app.services.strategy_service module¶
- app.services.strategy_service.is_custom_strategy_id(strategy_id)[source]¶
Return True when
strategy_idaddresses a DB-stored strategy.- Parameters:
strategy_id (str | None)
- Return type:
bool
- app.services.strategy_service.parse_custom_strategy_id(strategy_id)[source]¶
Strip the
custom:prefix and return the underlying uuid.- Parameters:
strategy_id (str)
- Return type:
str
- app.services.strategy_service.resolve_realm_id(*, api_key=None, oauth_user_id=None)[source]¶
Tenant-boundary resolver shared by call sites that don’t have an
AuthContexthandy (e.g.UserPointsService).Same convention as
_resolve_realm_idinapp/api/v1/endpoints/strategies_custom.py:API key present → its value is the realm.
OAuth admin → falls back to
configs.KEYCLOAK_REALM.Neither →
None(legacy unauthenticated path; any attempt to load acustom:strategy will then 404, which is the desired tenant-isolation behaviour).
- Parameters:
api_key (str | None)
oauth_user_id (str | None)
- Return type:
str | None
- class app.services.strategy_service.StrategyService(strategy_definition_service=None, *, dsl_interpreter=None, analytics_service=None, execution_observer=None)[source]¶
Bases:
BaseServiceService class for managing strategies.
Resolution is a two-step routing:
built-in strategies (registry-discovered
BaseStrategysubclasses) keep their bare id, e.g."default".persistent strategies authored from the dashboard live in the
strategydefinitiontable and are addressed as"custom:<uuid>". The resolver returns a thin descriptor for them; the DSL interpreter that runs the AST plugs into this same method.
- Parameters:
strategy_definition_service (StrategyDefinitionService | None)
dsl_interpreter (DslInterpreter | None)
analytics_service (Any | None)
execution_observer (Any | None)
- __init__(strategy_definition_service=None, *, dsl_interpreter=None, analytics_service=None, execution_observer=None)[source]¶
Initializes the StrategyService.
strategy_definition_serviceis optional so legacy call sites that only need built-ins still work after the custom-strategy wiring. When it’s omitted, attempting to resolve acustom:id raisesNotFoundErrorwith a clear message rather than silently crashing.dsl_interpreterandanalytics_serviceare required to instantiateDslStrategyforcustom:ids. They are optional kwargs to preserve the legacyStrategyService()no-arg call style still in use by tests and byUserPointsService.__init__until the container injection lands; when missing,get_strategy_instanceraises a preciseInternalServerErrorinstead of crashing withAttributeError.- Parameters:
strategy_definition_service (StrategyDefinitionService | None)
dsl_interpreter (DslInterpreter | None)
analytics_service (Any | None)
execution_observer (Any | None)
- Return type:
None
- list_all_strategies()[source]¶
Lists all available built-in strategies.
Custom DB-stored strategies are returned through the dedicated
/v1/strategies/customendpoints rather than mixed in here, so the legacy contract of this endpoint stays stable.- Return type:
list[dict[str, Any]]
- get_strategy_by_id(id)[source]¶
Retrieves a built-in strategy by its ID.
- Return type:
dict[str, Any]
- get_Class_by_id(id)[source]¶
Retrieves the instance of a built-in strategy by its ID.
Only handles the registry path; custom DSL strategies need a DB round-trip and use the async
resolve()instead.- Return type:
Any
- async resolve(strategy_id, *, realmId=None)[source]¶
Single resolution entrypoint for both code paths.
Returns a small descriptor. For built-ins:
{"kind": "BUILT_IN", "id": "default", "instance": <obj>}
For custom strategies:
{"kind": "DSL_FULL" | "DSL_EXTEND", "id": "custom:<uuid>", "definition": <StrategyDefinitionRead>}
Execution (
BaseStrategy.calculate_pointsdelegating to the DSL interpreter when the descriptor is a DSL one) plugs into this same method.- Parameters:
strategy_id (str) – A built-in id (e.g.
"default") or a"custom:<uuid>"id.realmId (str, optional) – Tenant boundary used to scope custom strategy lookups.
- Returns:
dict – The resolution descriptor described above.
- Raises:
NotFoundError – If a
custom:id is given but custom-strategy resolution is not wired, or the definition is not found.- Return type:
dict[str, Any]
- async get_strategy_instance(strategy_id, *, realmId=None)[source]¶
Single async entrypoint that returns something with
calculate_points(...)- either a built-in registry singleton or a freshly-constructedDslStrategywrapping a DB-persisted AST.For non-
custom:ids this delegates to the syncget_Class_by_idso existing test patches on that method keep intercepting. Forcustom:<uuid>it fetches the definition scoped byrealmId(multi-tenant isolation is enforced at the repository layer inStrategyDefinitionService.get_strategy) and wires the same sharedDslInterpreter+ analytics service injected at construction.Raises
InternalServerErrorif the DSL collaborators were not wired - a clearer signal thanAttributeErrorfor ops.- Parameters:
strategy_id (str)
realmId (str | None)
- Return type: