Reference guide extracted from CONTRIBUTING.md and existing model implementations Created: 2025-11-05
- Focus on simplicity and clarity for end users
- Design the best possible API, simple by default
- Make it hard for users to make mistakes
- Better write clear code than fancy code
- Use TimeSeries as the main interface (users shouldn't worry about numpy/torch internals)
These principles prevail even if they mean more code inside the library.
- Keep logic in the model class itself
- Avoid helper utilities unless truly necessary
- Don't create abstraction layers for simple operations
- Use parent class methods (
_build_forecast_series(), etc.)
Examples:
- YES:
raise_if_not(condition, "message", logger)inline - NO: Separate
validation.pymodule with wrapper functions - YES: Device handling via
pl_trainer_kwargs(PyTorch Lightning) - NO: Custom
device_utils.pywith auto-detection
- Single model per file is typical
- Shared utilities only if used by multiple models
- Keep model files self-contained when possible
def __init__(self, param: int):
"""Short Title
Brief description in 1-3 paragraphs explaining what it does.
Parameters
----------
param
Description of parameter (no type - already in signature)
Examples
--------
>>> from darts.models import MyModel
>>> model = MyModel(param=10)
>>> model.fit(series)
>>> pred = model.predict(6)
References
----------
.. [1] Author. (Year). Paper title.
"""- Focus on clarity, not brevity - explain what users need to know
- Working examples are critical - show actual usage
- Parameters section should be complete but concise
- Line count is not a hard limit - 20-100 lines is fine if it serves users
- What the model does (conceptual explanation)
- Key parameters with clear descriptions
- Runnable examples (critical!)
- References to papers (if applicable)
- Important notes/caveats
- Implementation details (how it works internally)
- Excessive architecture explanations
- Tutorial content (belongs in notebooks)
def __init__(
self,
# Model-specific parameters first
context_length: int,
forecast_horizon: int,
# Standard Darts parameters
output_chunk_shift: int = 0,
**kwargs, # Pass to parent
):
super().__init__(**kwargs)
self.context_length = context_length
self.forecast_horizon = forecast_horizonKey points:
- Model-specific params first, Darts standard params after
- Use
**kwargsto pass parent class parameters - No need to store all kwargs - only what the model uses
def fit(
self,
series: Union[TimeSeries, Sequence[TimeSeries]],
past_covariates: Optional[Union[TimeSeries, Sequence[TimeSeries]]] = None,
future_covariates: Optional[Union[TimeSeries, Sequence[TimeSeries]]] = None,
**kwargs
) -> "MyModel":
"""Fit the model to data.
Parameters
----------
series
Training time series
past_covariates
Past covariates (optional)
future_covariates
Future covariates (optional)
Returns
-------
self
Fitted model
"""
super().fit(series)
# Validate inputs inline
raise_if_not(
condition,
"Clear error message",
logger,
)
# Model-specific fitting logic
...
return selfdef predict(
self,
n: int,
series: Optional[TimeSeries] = None,
past_covariates: Optional[TimeSeries] = None,
future_covariates: Optional[TimeSeries] = None,
num_samples: int = 1,
**kwargs
) -> TimeSeries:
"""Generate forecast.
Parameters
----------
n
Forecast horizon
series
Input series (optional if fitted)
num_samples
Number of samples for probabilistic forecasting
Returns
-------
TimeSeries
Forecasted values
"""
super().predict(n, num_samples)
# Prediction logic - direct implementation
forecast = ...
return self._build_forecast_series(forecast)from darts.logging import get_logger, raise_if, raise_if_not, raise_log
logger = get_logger(__name__)
# In code:
raise_if_not(
condition,
"Error message with context",
logger,
)
raise_if(
bad_condition,
"Why this is a problem",
logger,
)Pattern: Validate inline with raise_if/raise_if_not, not separate validation methods.
Device is NOT an __init__ parameter. Use PyTorch Lightning's trainer kwargs:
# User code
model = MyModel(
input_chunk_length=12,
pl_trainer_kwargs={"accelerator": "gpu", "devices": [0]}
)Don't create custom device detection/management - Lightning handles it.
- Capabilities:
supports_multivariate,supports_probabilistic_prediction - Metadata:
min_train_series_length,extreme_lags - Computed attributes that don't change:
model_name
@property
def supports_multivariate(self) -> bool:
return True- Actions with side effects
- Operations taking parameters
- Anything that does computation
# 1. Standard library
from typing import Optional, Union, Sequence
# 2. Third-party
import numpy as np
import torch
# 3. Darts
from darts import TimeSeries
from darts.logging import get_logger, raise_if_not
from darts.models.forecasting.forecasting_model import GlobalForecastingModel
logger = get_logger(__name__)def _load_pretrained_model(self):
try:
import optional_package
except ImportError:
raise ImportError(
"The 'optional_package' is required.\n"
"Install with: pip install 'darts[extra]'"
)Unnecessary abstraction layers
# Don't
def fit(self, ...):
if self.mode == "A":
return self._fit_mode_a(...)
else:
return self._fit_mode_b(...)
# Do
def fit(self, ...):
if self.mode == "A":
# Logic here directly
pass
else:
# Other logic here
passHelper modules for simple operations
# Don't: validation.py with validate_series(), validate_params(), etc.
# Do: Inline with raise_if_not()Registry/metadata systems for model info
# Don't: registry.yaml + get_model_spec()
# Do: @property methods in model classOver-documenting implementation details
# Don't: Explain architecture, encoder-decoder, attention mechanisms
# Do: "This model uses a transformer architecture [1]_" + reference- Implement logic directly in methods
- Use parent class utilities (
_build_forecast_series, etc.) - Validate inline with
raise_if_not
- Expose only what users need
- Keep internals private (
_method_name) - Use standard Darts parameter names
- Show how to use it (examples)
- Explain what it does (not how)
- Reference papers for details
For torch models:
- Device management via
pl_trainer_kwargs - Training loop via Lightning
- Don't reimplement what Lightning provides
Darts style = Simple, direct, user-focused
Write code that:
- Is easy for users to understand and use
- Validates clearly with inline checks
- Implements logic directly without unnecessary abstraction
- Uses parent class utilities
- Documents usage, not implementation