Skip to content

Contract Syntax

ImportSpy contracts are written in YAML and describe the structure and runtime expectations of a Python module. These contracts can be embedded or validated externally (e.g., in CI/CD), and act as import-time filters for enforcing compatibility and intent.

A contract defines: - What variables, classes, and functions a module must expose - What runtime conditions are required (OS, architecture, Python version, etc.) - How strict or flexible the structure must be

This document explains the full syntax supported in .yml contract files.


Top-Level Structure

Every .yml contract is structured as follows:

filename: plugin.py
version: "1.2.3"

variables:
  - name: MODE
    value: production
    annotation: str

functions:
  - name: initialize
    arguments:
      - name: self
      - name: config
        annotation: dict
    return_annotation: None

classes:
  - name: Plugin
    attributes:
      - name: settings
        value: default
        annotation: dict
        type: instance
    methods:
      - name: run
        arguments:
          - name: self
        return_annotation: None
    superclasses:
      - BasePlugin

deployments:
  - arch: x86_64
    systems:
      - os: linux
        environment:
          variables:
            - name: IMPORTSPY_ENABLED
              value: true
              annotation: bool
        pythons:
          - version: "3.11"
            interpreter: CPython
            modules:
              - filename: plugin.py
                version: "1.2.3"

Fields Explained

filename

The name of the target Python file or module this contract applies to.

version

Optional string that defines the expected version of the module. Can be used to pin specific builds or releases.


variables

Declares global or module-level variables the importer must provide.

variables:
  - name: DEBUG
    value: true
    annotation: bool

Each variable entry supports: - name (required): Variable name - value (optional): Expected value - annotation (optional): Expected type annotation as string (e.g., "str", "dict")


functions

Specifies required functions in the importing module.

functions:
  - name: load_config
    arguments:
      - name: path
        annotation: str
    return_annotation: dict

Each function supports: - name: The function's name - arguments: List of required arguments (each with optional annotation) - return_annotation: Expected return type (as string)


classes

Defines required class structures.

classes:
  - name: Plugin
    attributes:
      - name: config
        annotation: dict
        value: {}
        type: instance
    methods:
      - name: execute
        arguments:
          - name: self
    superclasses:
      - BasePlugin

A class may include: - name: Class name - attributes: A list of attributes exposed by the class - type: Can be "instance" or "class" to indicate attribute level - methods: Required method declarations (same format as top-level functions) - superclasses: Optional list of superclass names expected

Attributes are matched on name, annotation, and (if provided) value.


deployments

This section defines runtime constraints in which the import is valid. It allows validation based on:

  • Architecture
  • Operating system
  • Environment variables
  • Python version and interpreter
  • Declared modules
deployments:
  - arch: x86_64
    systems:
      - os: linux
        environment:
          variables:
            - name: MODE
              value: prod
              annotation: str
        pythons:
          - version: "3.10"
            interpreter: CPython
            modules:
              - filename: plugin.py

Deployment fields:

Field Description
arch CPU architecture (e.g. x86_64, arm64)
systems.os Operating system (e.g. linux, windows)
environment.variables Required runtime env variables
pythons.version Required Python version (string)
pythons.interpreter Interpreter (e.g., CPython)
modules Specific modules to check (with filename/version)

Note: all conditions are AND-combined within a deployment block.


Matching Rules

ImportSpy uses a strict structural validator. Here are some notes:

  • Variables, functions, and methods are matched by name.
  • Annotations are matched as plain strings – no semantic typing or runtime evaluation.
  • If an annotation is omitted, it is not enforced.
  • Superclasses are checked only by name, not by inheritance tree resolution.

Best Practices

  • Use consistent annotations: "str", "dict", "list", etc.
  • Prefer matching exact function signatures for critical plugins
  • Define environment constraints only when needed (e.g., IMPORTSPY_MODE=prod)
  • Use modules.filename to enforce versioning in multi-plugin systems