Metastatic.Semantic.Callbacks.PythonResolver (Metastatic v0.23.0)

View Source

Resolves Python callbacks via decorator patterns and class inheritance.

Python uses two main mechanisms that signal callback relationships:

  1. Decorators on functions/methods (e.g., @app.route, @celery.task, @abstractmethod) indicate the function serves as a callback for a framework or protocol.

  2. Base classes on class definitions (e.g., class MyView(View)) indicate the class implements a framework interface whose methods are callbacks.

Decorator Resolution

iex> PythonResolver.resolve_from_decorators(["app.route"])
{:ok, %{framework: :flask, domain: :http}}

iex> PythonResolver.resolve_from_decorators(["some_custom_decorator"])
:no_match

Base Class Resolution

iex> PythonResolver.resolve_base_class("View")
{:ok, "View"}

iex> PythonResolver.resolve_base_class("SomeRandomClass")
:no_match

Summary

Types

Callback specification from decorator resolution

Functions

Ensures that all known Python base class behaviours are registered in the Callbacks registry with their standard callbacks.

Resolves all callback specs from a list of decorators.

Checks whether a Python base class name is a known behaviour source.

Resolves all known behaviours from a list of base class names.

Resolves callback metadata from a list of Python decorator names.

Types

decorator_spec()

@type decorator_spec() :: %{framework: atom(), domain: atom() | nil}

Callback specification from decorator resolution

Functions

register_base_class_callbacks()

@spec register_base_class_callbacks() :: :ok

Ensures that all known Python base class behaviours are registered in the Callbacks registry with their standard callbacks.

Called during register_builtins/0 to populate the registry with Python class-based callback patterns.

resolve_all_decorators(decorators)

@spec resolve_all_decorators([String.t()]) :: [decorator_spec()]

Resolves all callback specs from a list of decorators.

Unlike resolve_from_decorators/1 which returns the first match, this returns all matching specs.

Examples

iex> specs = PythonResolver.resolve_all_decorators(["login_required", "app.route"])
iex> length(specs) >= 2
true

resolve_base_class(class_name)

@spec resolve_base_class(String.t()) :: {:ok, String.t()} | :no_match

Checks whether a Python base class name is a known behaviour source.

Returns {:ok, behaviour_name} if the base class maps to a known behaviour, or :no_match otherwise.

Examples

iex> PythonResolver.resolve_base_class("View")
{:ok, "View"}

iex> PythonResolver.resolve_base_class("object")
:no_match

resolve_base_classes(bases)

@spec resolve_base_classes([String.t()]) :: [String.t()]

Resolves all known behaviours from a list of base class names.

Returns the list of behaviour name strings that the enricher should use to annotate callbacks.

Examples

iex> PythonResolver.resolve_base_classes(["View", "object"])
["View"]

resolve_from_decorators(decorators)

@spec resolve_from_decorators([String.t()]) :: {:ok, decorator_spec()} | :no_match

Resolves callback metadata from a list of Python decorator names.

Checks each decorator against the known decorator patterns and returns the first matching callback spec.

Examples

iex> PythonResolver.resolve_from_decorators(["app.route"])
{:ok, %{framework: :flask, domain: :http}}

iex> PythonResolver.resolve_from_decorators(["login_required", "app.route"])
{:ok, %{framework: :django, domain: :auth}}

iex> PythonResolver.resolve_from_decorators(["my_custom_deco"])
:no_match