Skip to content

Exceptions

Every exception py-beacon raises, all derived from BeaconError.

exceptions

Custom exceptions for the beacon package. This helps in categorizing errors originating from the beacon package.

BeaconError

BeaconError(message: str)

Bases: Exception

Base exception class for all custom exceptions in the beacon package.

DataNotFoundError

DataNotFoundError(
    data_description: str, source: str = "N/A"
)

Bases: BeaconError

Raised when specific financial data cannot be found or is unavailable.

InvalidRuleError

InvalidRuleError(rule_description: str, reason: str)

Bases: BeaconError

Raised when an index methodology rule or backtest rule is invalid or improperly configured.

ExpressionError

ExpressionError(message: str)

Bases: BeaconError

Raised when an expression is built or used in a way that cannot work.

Most often bool(expression). Python evaluates and, or and not by calling __bool__, and an expression has no truth value until it is resolved against an instrument and a date. Returning True there would make (a == 1) and (b > 2) silently discard half the expression, so it raises instead. Combine expressions with &, | and ~.

UnknownDatasetError

UnknownDatasetError(message: str)

Bases: ExpressionError, AttributeError

Raised when an expression names a dataset that does not exist.

Also an AttributeError, because it is raised from __getattr__ and the language builds on that: hasattr and getattr(..., default) catch AttributeError and nothing else, so raising only a BeaconError would make hasattr(data, "typo") blow up instead of answering False.

DataSourceError

DataSourceError(message: str)

Bases: BeaconError

Raised when a read needs a data source and the process has none.

The message always names both fixes, beacon.use(fetcher) and generating the default store, because "no data" discovered deep inside a price lookup is useless without being told what to do about it.

InvalidIdentifierError

InvalidIdentifierError(identifier: str, reason: str)

Bases: BeaconError, ValueError

Raised when a caller supplies an identifier that cannot be used.

Subclasses ValueError as well as BeaconError, on the same principle as MissingDependencyError: a caller already writing except ValueError around a store operation keeps working, because a rejected identifier is a value error. The API still answers 422 rather than using the generic argument handler, because BeaconError precedes ValueError in the MRO and the handler lookup walks it in order.

Distinct from DataNotFoundError, which means the identifier was fine and nothing was stored under it. This means the identifier itself is unusable (empty, or containing path separators), so there is nothing to look for.

The distinction decides the status code. A document id arrives from a URL path parameter, so rejecting one is a statement about the request, not a server fault.

The identifier is truncated to 40 characters in the message and in the identifier attribute.

ConfigurationError

ConfigurationError(config_param: str, details: str)

Bases: BeaconError

Raised for errors related to package or module configuration.

NoDataLoadedError

NoDataLoadedError(purpose: str)

Bases: BeaconError

Raised when something needs market data and none is loaded.

The engine can run with no data: it starts empty until a data store is loaded, and everything that does not read data keeps working. This is the answer for everything that does. It is a state the caller can change by loading a store, not a server fault, so it maps to 409, not 500.

Parameters:

Name Type Description Default
purpose str

What could not be done, completing "No data is loaded, so ...", e.g. "a backtest cannot be run".

required

DocumentFromNewerBuildError

DocumentFromNewerBuildError(
    config_param: str, details: str
)

Bases: ConfigurationError

A stored document written by a newer py-beacon than this one.

A ConfigurationError, so every handler for that still catches it, and a subclass, so a listing can tell it apart from a damaged file. The two call for opposite responses: nothing is wrong with this file, and the remedy is to upgrade the engine reading it. Two installs reach this state when the engine and the app are updated on different machines.

ReportingError

ReportingError(details: str)

Bases: BeaconError

Raised when a report cannot be generated or written.

A BeaconError rather than a bare Exception so it reaches a client through the API's error envelope with a stable code, like every other library failure, instead of as an unlabelled 500.

MissingDependencyError

MissingDependencyError(
    module_name: str, feature: str, extra: str
)

Bases: BeaconError, ImportError

Raised when a feature is used without its optional dependency installed.

Subclasses ImportError as well as BeaconError so that callers already handling a missing import keep working.

FrozenPortfolioError

FrozenPortfolioError(portfolio_id: str, operation: str)

Bases: BeaconError

Raised when something tries to write to a portfolio that is closed.

A finished backtest freezes its portfolio, because that portfolio is the record of the run: applying another trade to it would quietly restate a result someone has already read. Continuing a strategy means seeding a new run from the old end state, not mutating the record.

Frozen is a state, not a subclass: a hand-built portfolio is never frozen unless its owner freezes it.

CalculationError

CalculationError(calculation_name: str, details: str)

Bases: BeaconError

Raised during financial calculations if an error occurs (e.g., division by zero, bad inputs).

UnexpectedCalculationError

UnexpectedCalculationError(
    calculation_name: str, cause: BaseException
)

Bases: CalculationError

Raised when a calculation crashed, as opposed to refusing.

Every other CalculationError is a deliberate refusal: a guard that names what was missing and what to do about it. This one is the opposite: an exception nobody anticipated, caught at a boundary and re-raised so it still reaches a client inside the error envelope, with its own published code, instead of as an unlabelled 500. It means there is nothing in the request to change, and the failure is worth reporting.

A subclass rather than a sibling, because a crash during a calculation genuinely is a calculation error: anything already written as except CalculationError keeps catching it.

original_type carries the class name of the exception that actually failed, so a reader can tell a ZeroDivisionError from a KeyError without a server log. Like every other attribute of a BeaconError, it reaches the client in the envelope's detail.