Skip to content

Rename predict to run#2925

Open
markphelps wants to merge 19 commits intomainfrom
predict-rename
Open

Rename predict to run#2925
markphelps wants to merge 19 commits intomainfrom
predict-rename

Conversation

@markphelps
Copy link
Copy Markdown
Contributor

@markphelps markphelps commented Apr 9, 2026

Summary

Renames the user-facing "predict" concept to "run" across CLI, Python SDK, cog.yaml, Rust coglet, Go schema parser, docs, and tests. Full backwards compatibility -- old names keep working with deprecation warnings.

Scope: user-facing changes only. Internal Go packages (pkg/predict/), Rust types, COG_PREDICT_TYPE_STUB, predict_time metrics, /predictions HTTP endpoints, and IPC wire format are all unchanged.

What changed

  • CLI: cog run is the new primary command for predictions. cog predict is hidden + deprecated. cog run <cmd> [args...] (2+ args) forwards to cog exec with deprecation warning.
  • cog.yaml: run: key supported alongside predict:. Both cannot be set simultaneously. run: resolves into Config.Predict at parse time.
  • Python SDK: BaseRunner is the single real class. BasePredictor = BaseRunner is a backwards-compatible alias. run() is the primary method; predict() is a bridge that calls run(). No duplicated logic between the two names.
  • Rust coglet: Detects run() vs predict() at predictor load time via class __dict__ MRO walk. Stored method name used for all subsequent calls.
  • Go schema parser: Tree-sitter parser tries run() first, falls back to predict().
  • cog init: Generates run.py with BaseRunner/Runner/def run().
  • Docs: All examples updated. Backwards-compat notes in yaml.md and python.md.
  • Integration tests: ~110 txtar files renamed + 5 new backwards-compat tests.

Backwards compatibility

Old usage Still works? Behavior
predict: in cog.yaml Yes Resolves to same internal field
BasePredictor / def predict() Yes BasePredictor is an alias for BaseRunner; inspector detects predict() via MRO
cog predict Yes (hidden) Prints deprecation warning
cog run <shell-command> (2+ args) Yes Forwards to cog exec with warning

- Create new 'cog run' command that runs predictions (replaces 'cog predict')
- 'cog predict' is hidden and prints deprecation warning
- 'cog run <cmd> [args...]' (2+ args) forwards to 'cog exec' with deprecation warning
- Remove 'run' alias from exec command
- Add Run field to configFile struct
- Resolve run: vs predict: at parse time into Config.Predict
- Validate that both cannot be set simultaneously
- Update JSON schema with run property
- Produce field-appropriate error messages (run.py:Runner vs predict.py:Predictor)
- Add BaseRunner class alongside BasePredictor
- Inspector detects run() vs predict() via class __dict__
- load_predictor_from_ref tries Runner before Predictor as default
- Export BaseRunner from cog package
- Add predict_method_name field to PythonPredictor
- Detect method via class __dict__ at load time
- Error if both run() and predict() are defined, or neither
- Use stored method name for all getattr/call_method calls
- Dynamic log messages and error messages use detected method name
Tree-sitter parser now looks for run() method first, falls back
to predict() for backwards compatibility.
- Rename predict.py template to run.py
- Template uses BaseRunner/Runner/def run()
- cog.yaml template uses run: key
Mechanical find-and-replace across ~143 files:
- cog predict -> cog run
- predict.py:Predictor -> run.py:Runner
- BasePredictor -> BaseRunner
- class Predictor -> class Runner
- def predict -> def run
- predict: -> run: in cog.yaml
- Updated comments and variable names

Edge cases preserved:
- predict_time metric name (unchanged)
- /predictions API path (unchanged)
- prediction as a noun in comments (unchanged)
- OpenAPI schema assertions with server-generated content (unchanged)
- Source: comments referencing original test file names (unchanged)
Verify old names still work:
- predict: key in cog.yaml with Runner/run()
- BasePredictor/predict() with run: key
- Full legacy setup (predict: key + BasePredictor/predict())
- cog predict CLI command deprecation warning
- cog run <command> forwarding to exec with deprecation warning
- All examples now use cog run, run:, BaseRunner, def run()
- Backwards compatibility notes for predict:/BasePredictor/cog predict
- Training examples: removed unused BasePredictor imports
- AGENTS.md: fixed incorrect base_predictor.py references to predictor.py
…s class

- Inspector walks MRO (skipping base stubs) to support multi-level inheritance
- load_predictor_from_ref return type changed to Any
- Warn when module has both Runner and Predictor without explicit class name
- legacy_sdk_schema.txtar: revert to BasePredictor/predict() (SDK 0.16.12 compat)
- predictor.rs: predict_method_name changed from String to &'static str
- docs/wsl2/wsl2.md: cog predict -> cog run
…walk in Rust

- Skip duplicate validation when both run: and predict: set
- Fix train description in JSON schema
- Clarify cog.yaml template comment
- Fix fragile no_predictor.txtar assertion
- Walk MRO in Rust coglet for multi-level inheritance support
@michaeldwan
Copy link
Copy Markdown
Member

michaeldwan commented Apr 9, 2026

Is there a benefit to having a full implementation of BasePredictor and BaseRunner with fallback logic? I think we can do this by renaming BasePredictor to BaseRunner, then making an alias to BasePredictor. And we can rename more of the internals in isolation later.

Edit: We'd also need to add an override for both run and predict methods. eg run is abstract and raises NotImplemented when called, predict calls run. I think that covers the bases and won't require duplicating and maintaining a ton of logic across 2 classes.

BaseRunner is now the single real class. BasePredictor = BaseRunner is
a backwards-compatible alias. predict() is a bridge method that calls
run(), eliminating duplicated setup/scope/record_metric logic.

The runtime still detects which method the user overrode (run vs predict)
via MRO walk and calls it directly.
Copy link
Copy Markdown

@ask-bonk ask-bonk bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm Bonk, and I've done a quick review of your PR.

This PR renames 'predict' to 'run' across CLI, Python SDK, cog.yaml, and Rust coglet while maintaining full backwards compatibility. The implementation looks solid with proper MRO walking for method detection in both Python and Rust.

I found one issue worth addressing:

}
if cfg.Predict != nil {
// Resolve run: vs predict: -- run: takes precedence, conflict is caught by validation
switch {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check duplicates validation logic that already exists in validateRunPredictConflict in validate.go:110-118. The validation there produces a better error message and runs before this code path. Consider removing this redundant check and relying on the validation layer to catch this case.

@ask-bonk
Copy link
Copy Markdown

ask-bonk bot commented Apr 10, 2026

I loaded the relevant review skills, read through the key files changed in this PR (Python SDK predictor changes, Rust coglet predictor detection, Go config parsing, CLI commands), and analyzed the backwards compatibility mechanisms. I found one issue where validation logic is duplicated between pkg/config/parse.go and pkg/config/validate.go, and posted a review to PR #2925 with a comment about removing that redundancy.

github run

…tfmt

- test_default_predict_raises: predict() now bridges to run(), so the
  NotImplementedError message says 'run' not 'predict'
- no_predictor.txtar: match actual error output ('predict' from SDK internals)
- predictor.rs: apply cargo fmt
Copy link
Copy Markdown

@ask-bonk ask-bonk bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm Bonk, and I've done a quick review of your PR.

This PR renames 'predict' to 'run' across CLI, Python SDK, cog.yaml, and Rust coglet while maintaining full backwards compatibility. The implementation looks solid with proper MRO walking for method detection in both Python and Rust.

I found one issue worth addressing:

}
if cfg.Predict != nil {
// Resolve run: vs predict: -- run: takes precedence, conflict is caught by validation
switch {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check duplicates validation logic that already exists in validateRunPredictConflict in validate.go:110-118. The validation there produces a better error message and runs before this code path. Consider removing this redundant check and relying on the validation layer to catch this case.

Suggested change
switch {
// Resolve run: vs predict: -- run: takes precedence, conflict is caught by validation
switch {
case cfg.Run != nil:
config.Predict = *cfg.Run
case cfg.Predict != nil:
config.Predict = *cfg.Predict
}

@ask-bonk
Copy link
Copy Markdown

ask-bonk bot commented Apr 10, 2026

I'm Bonk, and I've done a quick review of your PR.

This PR renames 'predict' to 'run' across CLI, Python SDK, cog.yaml, and Rust coglet while maintaining full backwards compatibility. The implementation looks solid with proper MRO walking for method detection in both Python and Rust.

I found one issue worth addressing:

Issue: The check at pkg/config/parse.go:152-154 duplicates validation logic that already exists in validateRunPredictConflict at validate.go:110-118. The validation layer produces a better error message and runs before this code path. Consider removing the redundant check in parse.go and relying solely on the validation layer to catch this case.

github run

@markphelps markphelps marked this pull request as ready for review April 10, 2026 16:21
@markphelps markphelps requested a review from a team as a code owner April 10, 2026 16:21
Medium:
- Consolidate conflict error messages between parse.go and validate.go
- Add inspect.isclass() guard in load_predictor_from_ref class resolution

Low:
- Update __init__.py docstring to show BaseRunner/run() as primary
- Add alias comments in Rust MRO walk and Python _inspector
- Add sentinel comment for empty predict_method_name on standalone functions
- Add 2 mixed-combo backwards-compat integration tests (BaseRunner+predict, BasePredictor+run)
@markphelps markphelps requested a review from michaeldwan April 10, 2026 16:33
@ask-bonk
Copy link
Copy Markdown

ask-bonk bot commented Apr 10, 2026

The author already addressed my previous feedback in commit 6728a5a. The error messages are now consistent between parse.go and validate.go, and the comment explains why the check exists (defensive programming for the FromYAML path which skips validation).

I don't see any other actionable issues in this PR. The backwards compatibility mechanisms are well-implemented, the integration tests cover the key scenarios, and the documentation is updated appropriately.

LGTM

github run

@ask-bonk
Copy link
Copy Markdown

ask-bonk bot commented Apr 10, 2026

LGTM

github run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants