Embedded Mode
In Embedded Mode, ImportSpy is embedded directly into the module you want to protect.
When that module is imported, it inspects the runtime environment and the importing module.
If the context doesn't match the declared contract, the import fails with a structured error.
How it works
By using Spy().importspy(...)
, a protected module can validate:
- The runtime (OS, Python version, architecture…)
- The caller module’s structure (classes, methods, variables, annotations…)
If validation passes, the module returns a reference to the caller.
If not, the import is blocked and an exception is raised (e.g. ValueError
or custom error class).
Real-world example: plugin-based architecture
Let’s walk through a complete example.
This simulates a plugin framework that wants to validate the structure of external plugins at import time.
Project structure
external_module_compliance/
├── extensions.py # The plugin (caller)
├── package.py # The protected framework
├── plugin_interface.py # Base interface for plugins
└── spymodel.yml # The import contract
🧩 Source files
from importspy import (
Spy
)
import logging
__version__ = None
caller_module = Spy().importspy(filepath="./spymodel.yml", log_level=logging.WARN)
caller_module.Foo().get_bar()
import package
from plugin_interface import Plugin
author = "Luca Atella"
plugin_name = "plugin name"
plugin_description = "plugin description"
engine = "docker"
class Extension(Plugin):
extension_name = "extension_value"
def __init__(self) -> None:
self.extension_instance_name = "extension_instance_value"
def add_extension(self, msg:str) -> str:
print(msg)
return "Extension has added"
def remove_extension(self):
print("Extension has removed")
def http_get_request(self):
print("done")
class Foo:
def get_bar(self):
print("Foobar")
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
When to use Embedded Mode
Use this mode when:
- You want to protect a module from being imported incorrectly
- You’re building a plugin system and expect structural consistency from plugins
- You want to fail fast in invalid environments
- You need to enforce custom logic during
import
without modifying the caller