CLI Mode
ImportSpy can also be used outside of runtime to validate a Python module against a contract from the command line.
This is useful in CI/CD pipelines, pre-commit hooks, or manual validations β whenever you want to enforce import contracts without modifying the target module.
How it works
In CLI Mode, you invoke the importspy
command and provide:
- The path to the module to validate
- The path to the YAML contract
- (Optional) a log level for output verbosity
ImportSpy loads the module dynamically, builds its SpyModel, and compares it against the .yml
contract.
If the module is non-compliant, the command will:
- Exit with a non-zero status
- Print a structured error explaining the violation
Basic usage
importspy extensions.py -s spymodel.yml -l WARNING
CLI options
+-----------------------------------------------------------------------------+
| Flag | Description |
|--------------------|--------------------------------------------------------|
| -s, --spymodel
| Path to the import contract .yml
file |
| -l, --log-level
| Logging verbosity: DEBUG
, INFO
, WARNING
, ERROR
|
| -v, --version
| Show ImportSpy version |
| --help
| Show help message and exit |
+-----------------------------------------------------------------------------+
Example project
Letβs look at a full CLI-mode validation example.
Project structure
pipeline_validation/
βββ extensions.py
βββ spymodel.yml
π Source files
filename: extension.py
variables:
- name: engine
value: docker
- name: plugin_name
value: plugin name
- name: plugin_description
value: plugin description
classes:
- name: Extension
attributes:
- type: instance
name: extension_instance_name
value: extension_instance_value
- type: class
name: extension_name
value: extension_value
methods:
- name: __init__
arguments:
- name: self
return_annotation:
- name: add_extension
arguments:
- name: self
- name: msg
annotation: str
return_annotation: str
- name: remove_extension
arguments:
- name: self
return_annotation:
- name: http_get_request
arguments:
- name: self
superclasses:
- name: Plugin
- name: Foo
attributes:
methods:
- name: get_bar
arguments:
- name: self
deployments:
- arch: x86_64
systems:
- os: linux
pythons:
- version: 3.12.9
interpreter: CPython
modules:
- filename: extension.py
version:
variables:
- name: author
value: Luca Atella
functions:
classes:
- version: 3.12.4
interpreter:
modules:
- filename: addons.py
- interpreter: IronPython
modules:
- filename: addons.py
- os: windows
pythons:
- version: 3.12.9
interpreter: CPython
modules:
- filename: extension.py
version:
variables:
- name: author
value: Luca Atella
π Run validation
cd examples/plugin_based_architecture/pipeline_validation
importspy extensions.py -s spymodel.yml -l WARNING
If the module matches the contract, the command exits silently with 0
.
If it doesn't, youβll see a structured error like:
[Structure Violation] Missing required method 'get_bar' in class 'Foo'.
When to use CLI Mode
Use CLI Mode for automation
CLI Mode is ideal when you want to:
- Validate modules without changing their code
- Integrate checks in CI/CD pipelines
- Enforce contracts in external packages
- Run batch validations over multiple files
Import Contract Syntax
An ImportSpy contract is a YAML file that describes:
- The structure expected in the calling module (classes, methods, variablesβ¦)
- The runtime and system environment where the module is allowed to run
- The required environment variables and optional secrets
This contract is parsed into a SpyModel
, which is then compared against the actual runtime and importing module.
β Overview
Hereβs a minimal but complete contract:
filename: extension.py
variables:
- name: engine
value: docker
classes:
- name: Plugin
methods:
- name: run
arguments:
- name: self
deployments:
- arch: x86_64
systems:
- os: linux
pythons:
- version: 3.12
interpreter: CPython
π filename
filename: extension.py
- Optional.
- Declares the filename of the module being validated.
- Used for reference and filtering in multi-module declarations.
π£ variables
variables:
- name: engine
value: docker
- Declares top-level variables that must be present in the importing module.
- Supports optional
annotation
(type hint).
- name: debug
annotation: bool
value: true
π§ functions
functions:
- name: run
arguments:
- name: self
- name: config
annotation: dict
return_annotation: bool
- Declares standalone functions expected in the importing module.
- Use
arguments
andreturn_annotation
for stricter typing.
π§± classes
classes:
- name: Plugin
attributes:
- type: class
name: plugin_name
value: my_plugin
methods:
- name: run
arguments:
- name: self
superclasses:
- name: BasePlugin
Each class can declare:
attributes
: divided bytype
(class
orinstance
)methods
: each witharguments
and optionalreturn_annotation
superclasses
: flat list of required superclass names
π§ deployments
This section defines where the module is allowed to run.
deployments:
- arch: x86_64
systems:
- os: linux
pythons:
- version: 3.12.9
interpreter: CPython
modules:
- filename: extension.py
version: 1.0.0
variables:
- name: author
value: Luca Atella
β³οΈ Fields
Field | Type | Description |
---|---|---|
arch |
Enum | e.g. x86_64 , arm64 |
os |
Enum | linux , windows , darwin |
version |
str | Python version string (3.12.4 ) |
interpreter |
Enum | CPython , PyPy , IronPython , etc. |
modules |
list | Repeats the structure declaration per module |
This structure allows fine-grained targeting of supported environments.
π± environment
Environment variables and secrets expected on the system.
environment:
variables:
- name: LOG_LEVEL
value: INFO
- name: DEBUG
annotation: bool
value: true
secrets:
- MY_SECRET_KEY
- DATABASE_PASSWORD
variables
: can define name, value, and annotationsecrets
: only their presence is verified β values are never exposed
Notes
- All fields are optional β contracts can be partial
- Field order does not matter
- Unknown fields are ignored with a warning (not an error)