Dependency Management Architecture#
MolSysMT uses a sophisticated Decorator-based Lazy Loading architecture to handle external dependencies. This ensures fast startup times, robustness against missing optional libraries, and introspection capabilities.
1. Core Principles#
Zero-Cost Startup: Importing
molsysmtnever triggers the import of a soft dependency (likeopenmm,mdtraj).Single Source of Truth: All dependency metadata is centralized in
molsysmt/_depdigest.py.Runtime Validation: The
@dep_digestdecorator enforces availability just-in-time.Lazy Discovery: Form modules are only scanned and imported when accessed, allowing for dynamic capability filtering.
2. Configuration & Mapping#
Dependency Definitions (molsysmt/_depdigest.py)#
This file defines which libraries are hard (required) and soft (optional).
LIBRARIES = {
'numpy': {'type': 'hard', 'pypi': 'numpy'},
'mdtraj': {'type': 'soft', 'pypi': 'mdtraj'},
# ...
}
Form Directory Mapping#
Crucially, this file also maps Form Directories to their required libraries. This enables the Lazy Loader to know that mdtraj_Trajectory needs mdtraj without opening the folder.
MAPPING = {
'mdtraj_Trajectory': 'mdtraj',
'openmm_Topology': 'openmm',
# ...
}
Developer Rule: If you add a new form that depends on an external library, you MUST add it to this map.
3. The @dep_digest Decorator#
This decorator is provided by the depdigest package and configured by
molsysmt/_depdigest.py.
Usage:
from depdigest import dep_digest
@dep_digest('mdtraj')
def to_mdtraj(item):
import mdtraj # Safe lazy import
...
Features:
Validation: Checks if the library is installed. Raises
LibraryNotFoundErrorwith a clear message if not.Metadata: Tags the function with
_dependenciesfor introspection and tooling.Caching: Optimizes checks to have negligible runtime overhead.
4. The Lazy Form Loader (molsysmt.form)#
The __init__.py in molsysmt/form implements a custom dictionary (_FormsDictionary) that:
Does not import anything at startup.
When a form is requested (e.g.,
convert(..., to_form='mdtraj.Trajectory')):Checks
MAPPING.Checks
msm.configure.show_all_capabilities.Checks if the required library is installed.
If all checks pass, it imports the module.
If filtering is active and lib is missing, the form remains “invisible”.
5. Validation Script#
We provide a script to enforce architectural rules:
devtools/scripts/validate_dependencies.py
What it checks:
No top-level imports of soft dependencies (e.g.,
import openmmat module level).Scans the entire codebase (AST analysis).
Exempt Zones: Some directories are exempt from the “Zero Soft Dependency” rule because they are dev tools or tests:
molsysmt/data/_make/tests/molsysmt/docs/generate_static_views/sandbox/
6. Integration Testing#
To verify the runtime behavior of the dependency system (filtering, mocking), use:
pytest tests/test_dependencies_architecture.py
7. User Introspection#
Users can check the status of the MolSysMT ecosystem at any time using:
import molsysmt as msm
msm.supported.dependencies()
This returns a Pandas-formatted table showing which libraries are installed, whether they are hard or soft dependencies, and the commands to install them if missing.
8. How to Add a New Dependency#
Register it: Add it to
LIBRARIESinmolsysmt/_depdigest.py.Map it: If it has associated forms, add them to
MAPPING.Use it: Use
@dep_digest('new_lib')in your functions.Import it: Always import it inside the function/method.
7. Troubleshooting#
“ModuleNotFoundError” vs “LibraryNotFoundError”:
LibraryNotFoundErrormeans the system works: it detected the missing lib and warned you.ModuleNotFoundError(for a soft dep) usually means a Top-Level Import leaked into the code. Run the validation script!
Form not showing up:
Check if
show_all_capabilitiesis False.Check if it’s mapped in
MAPPING.Check the logs (debug level) for skipped forms.