Skip to content

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

Learn more