Modules¶
Loading Modules¶
The Module class is used to register modules with the system, and provides attributes
used to define certain behaviour of the module.
An example of a module’s root file:
# file: my/module/__init__py
from superdesk.core.module import Module, SuperdeskAsyncApp
def init(app: SuperdeskAsyncApp):
...
module = Module(
name="my.module",
init=init,
frozen=True,
priority=100
)
Then you would add the following to your MODULES config:
# file: settings.py
MODULES = ["my.module"]
The system would then load this module when the application starts
Module Loading Sequence¶
The SuperdeskAsyncApp app is in charge of loading modules,
when the start function is run on the app.
Modules are loaded in the following 3 stages.
Import python module
Load module local configs
Run module init functions
The app will import ALL modules first, then ALL module configs are loaded, then ALL module init functions are run. This way we can ensure that all python modules and configs are loaded before initialising the modules themself.
Module Configuration¶
A module can optionally have a config loaded on app startup. This can be achieved by setting config options on the Module instance.:
# file: my/module/__init__py
from typing import Optional, Dict, Any
from superdesk.core.module import Module, SuperdeskAsyncApp
from superdesk.core.config import ConfigModel
# Create a new Config class that inherits from `ConfigModel`
class ModuleConfig(ConfigModel):
# Make sure to provide defaults for all fields
# otherwise validation would fail
uri: str = "localhost"
port: int = 27017
options: Optional[Dict[str, Any]] = None
# Create a module local instance of the class,
# to be used at runtime
config = ModuleConfig()
def init(app: SuperdeskAsyncApp):
# The module's config is loaded BEFORE executing the
# modules `init` function
if config.uri == "localhost":
print("Using a local instance")
else:
print("Using a remote instance")
# You can also import configs from other modules
# all configs are loaded BEFORE executing module's
# init function
from my import module_b
if module_b.config.enabled:
print("Secondary module is enabled")
else:
print("Secondary module is NOT enabled")
module = Module(
name="my.module",
init=init,
frozen=True,
priority=100,
# Tells the module loading system to load our config for us
config=config,
# Optionally use a prefix when loading config values
config_prefix="MONGO",
# Optionally tell the module loading system
# NOT to freeze our config so it can be changed at runtime
freeze=False,
)
When the app loads the module, it will populate the values in the config based on attributes from settings.py. For example, the following:
MONGO_URI = "remote_host.com"
MONGO_PORT = 37017
MONGO_OPTIONS = {"w": 3}
is the same as:
ModuleConfig(
uri="remote_host.com",
port=37017,
options=dict(w=3)
)
Validation will also occur when loading the module config, so if the value in settings.py is invalid with regards to the ConfigModel used, then the app will refuse to load and throw an error, such as:
pydantic_core._pydantic_core.ValidationError: 1 validation error for ModuleConfig
port
Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='val', input_type=str]
For further information visit https://errors.pydantic.dev/2.7/v/int_parsing
Module Reference¶
- class Module(name: str, init: Callable[[SuperdeskAsyncApp], None] | None = None, frozen: bool = False, priority: int = 0, path: str = '', config: ConfigModel | None = None, config_prefix: str | None = None, freeze_config: bool = True, resources: List[ResourceConfig] | None = None, endpoints: List[Endpoint | EndpointGroup] | None = None, privileges: list[Privilege] | None = None)[source]¶
Class used to register modules with the app
- name: str¶
The name of the module, used to identify the module as well as when overriding the module
- init: Callable[[SuperdeskAsyncApp], None] | None = None¶
Optional function to initialize the module
- frozen: bool = False¶
if
True, does not allow overriding the module
- priority: int = 0¶
loading priority for the module, loads in descending order
- path: str = ''¶
path to the loaded module, populated by the app on load
- config: ConfigModel | None = None¶
ConfigModel instance to be automatically populated by the app
- config_prefix: str | None = None¶
Config prefix to use when loading config from
settings.py
- freeze_config: bool = True¶
If
True, this modules config values cannot be changed once loaded
- resources: List[ResourceConfig] | None = None¶
Optional list of resources to automatically register
- endpoints: List[Endpoint | EndpointGroup] | None = None¶
Optional list of HTTP endpoints to register with the system