Skip to content

Allow StatsForecastModel to accept model as string or class#3058

Merged
dennisbader merged 5 commits intounit8co:masterfrom
tmchow:feat/3055-statsforecast-model-string
Apr 10, 2026
Merged

Allow StatsForecastModel to accept model as string or class#3058
dennisbader merged 5 commits intounit8co:masterfrom
tmchow:feat/3055-statsforecast-model-string

Conversation

@tmchow
Copy link
Copy Markdown
Contributor

@tmchow tmchow commented Apr 2, 2026

Summary

StatsForecastModel now accepts model as a string name, a class, or an instance. This follows the same pattern already used by NeuralForecastModel and makes it much easier to define models via config files or without importing every statsforecast model class.

Changes

Updated darts/models/forecasting/sf_model.py:

  • model parameter now accepts str | type[_TS] | _TS (was _TS only)
  • Added model_kwargs parameter for passing constructor arguments when using string or class form
  • Added _import_sf_model_class() static method that imports models from statsforecast.models by name
  • Existing code passing model instances still works (backwards compatible)
  • If model_kwargs is passed with an instance, a UserWarning is raised

Three usage patterns now work:

# String (new)
model = StatsForecastModel(model="AutoARIMA", model_kwargs={"season_length": 12})

# Class (new)
from statsforecast.models import AutoARIMA
model = StatsForecastModel(model=AutoARIMA, model_kwargs={"season_length": 12})

# Instance (existing, backwards compatible)
model = StatsForecastModel(model=AutoARIMA(season_length=12))

Testing

The change is backwards compatible with existing tests. The string and class resolution paths follow the same pattern as NeuralForecastModel._import_nf_model_class() which is already tested.

Fixes #3055

This contribution was developed with AI assistance (Claude Code).

@tmchow tmchow requested a review from dennisbader as a code owner April 2, 2026 11:14
Copy link
Copy Markdown
Collaborator

@jakubchlapek jakubchlapek left a comment

Choose a reason for hiding this comment

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

Hey @tmchow, thanks a lot for your first contribution :)

The first draft looks nice, but I have left some comments, regarding your changes.

I think that regarding this update we should for the time being keep the option of passing in model instances, while giving an explicit warning to the user that the option is deprecated. The biggest thing I can see currently is that the new str | class paths aren't tested. While all the tests still pass (because we still accept instances so the logic hasn't changed) we don't check the new functionality yet. Since it will be the default I think it would be nice to change the existing tests to leverage the str path instead, while also adding new tests that verify the model class and instance model creation work. Maybe @dennisbader has some other thoughts on how we want to approach the migration?

@@ -110,8 +118,8 @@ def encode_year(idx):
>>> series = AirPassengersDataset().load()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

the AutoARIMA import is no longer necessary

>>> future_cov = datetime_attribute_timeseries(series, "month", cyclic=True, add_length=6)
>>> # define AutoARIMA parameters
>>> model = StatsForecastModel(model=AutoARIMA(season_length=12))
>>> # define AutoARIMA parameters (using string and model_kwargs)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

we can get rid of the clarification in () since it will be the default

Comment on lines +175 to +181
if not (isinstance(model_class, type) and issubclass(model_class, _TS)):
raise_log(
ValueError(
f"`{model}` is not a valid StatsForecast model class."
),
logger,
)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

i'd suggest extracting this code into _validate_sf_model_class, as per the NF implementation. while this would work, I'd like to keep the implementations as close to each other as possible :)

Comment on lines +133 to +142
if isinstance(model, _TS):
# backwards compatibility: model passed as an instance
if model_kwargs:
warnings.warn(
"`model_kwargs` is ignored when `model` is an instance. "
"Pass `model` as a string or class to use `model_kwargs`.",
UserWarning,
stacklevel=2,
)
self.model = model
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

i generally agree that for now the SFModel instances should be accepted at least until some further release, but the error should be more clear this path is now deprecated and will be removed (e.g. "DEPRECATED: <xyz>, not just if the user passes in model_kwargs).

additionally, instead of warnings.warn() use logger.warning() for it.

tmchow and others added 5 commits April 10, 2026 10:52
Adapted the NeuralForecastModel pattern so StatsForecastModel now
accepts model as a string name (e.g., "AutoARIMA"), a class, or an
instance (backwards compatible). Added model_kwargs parameter for
passing constructor arguments when using string or class form.

This makes it easier to define models via config files without
importing all statsforecast model classes.

Fixes unit8co#3055
- Remove unused AutoARIMA import from docstring example
- Remove redundant (using string and model_kwargs) clarification
- Extract validation into _validate_sf_model_class (matches NF pattern)
- Use logger.warning() with DEPRECATED prefix instead of warnings.warn()
 especially if it merges an updated upstream into a topic branch.
@dennisbader dennisbader force-pushed the feat/3055-statsforecast-model-string branch from 1d86c95 to 3cb2637 Compare April 10, 2026 10:33
Copy link
Copy Markdown
Collaborator

@dennisbader dennisbader left a comment

Choose a reason for hiding this comment

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

Thanks @tmchow for this PR and your first contribution 🚀
The PR looked like a good start, I have already applied some updates to make it ready to be merged.

After the tests have passed, I'll merge 💯

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 10, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.73%. Comparing base (5711b61) to head (3cb2637).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3058      +/-   ##
==========================================
- Coverage   95.79%   95.73%   -0.06%     
==========================================
  Files         158      158              
  Lines       17303    17315      +12     
==========================================
+ Hits        16575    16577       +2     
- Misses        728      738      +10     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dennisbader dennisbader merged commit 447c7d3 into unit8co:master Apr 10, 2026
9 checks passed
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.

Make StatsForecastModel accept model as string or class with model_kwargs.

3 participants