apywire can generate standalone Python code from your wiring spec using the WiringCompiler class and its compile() method. This is useful for production deployments and performance optimization.
The compile() method generates Python code that behaves identically to the runtime Wiring container:
from apywire import WiringCompiler
spec = {
"datetime.datetime now": {"year": 2025, "month": 1, "day": 1},
}
compiler = WiringCompiler(spec)
code = compiler.compile()
print(code)This generates a Python class with the same lazy loading, caching, and dependency resolution behavior.
from apywire import WiringCompiler
spec = {
"datetime.datetime start": {"year": 2025, "month": 1, "day": 1},
"datetime.timedelta delta": {"days": 7},
}
compiler = WiringCompiler(spec)
code = compiler.compile()
# Save to file
with open("compiled_wiring.py", "w") as f:
f.write(code)The generated code can be imported and used like the runtime container:
from compiled_wiring import Compiled
wired = Compiled()
start = wired.start()
delta = wired.delta()Include async accessors in the generated code:
code = compiler.compile(aio=True)Generated code will support both sync and async access:
from compiled_wiring import Compiled
wired = Compiled()
# Sync access
obj = wired.my_object()
# Async access
import asyncio
obj = asyncio.run(wired.aio.my_object())Include thread-safe instantiation in the generated code:
code = compiler.compile(thread_safe=True)Generated code will use the same optimistic locking mechanism as runtime Wiring.
code = compiler.compile(aio=True, thread_safe=True)Generates code with both async support and thread safety.
The compiled code contains:
All necessary imports for the wired classes:
import datetime
import pathlib
# ... other importsA class that mirrors your wiring spec:
class Compiled:
def __init__(self):
self._values = {}
# Thread-safe: locks initialization
# Constants initializationMethods for each wired object:
def start(self):
if "start" not in self._values:
# Instantiation logic
self._values["start"] = datetime.datetime(year=2025, month=1, day=1)
return self._values["start"]Async versions of accessor methods:
class AioAccessors:
async def start(self):
loop = asyncio.get_running_loop()
return await loop.run_in_executor(None, lambda: self._wired.start())
@property
def aio(self):
return self._aio_accessorsLocking mechanisms and thread-local state.
- Performance: Slightly faster than runtime
Wiring(no dynamic__getattr__lookup) - Deployment: No need to include spec dictionary in production code
- Type Checking: Generated code can be type-checked by mypy
- Inspection: Easier to understand dependency graph by reading generated code
- Cython: Can be compiled with Cython for additional performance
- Static: Can't modify spec at runtime
- Code Size: Generated code can be large for complex specs
- Maintenance: Need to regenerate if spec changes
apywire itself uses Cython for performance. You can compile the generated code with Cython:
compiler = WiringCompiler(spec)
code = compiler.compile()
with open("wiring.py", "w") as f:
f.write(code)from setuptools import setup
from Cython.Build import cythonize
setup(
ext_modules=cythonize("wiring.py"),
)uv run python setup.py build_ext --inplaceThis generates wiring.c and wiring.so (compiled extension).
# config.py
from apywire import Wiring
def get_spec():
return {
"database_url": "postgresql://localhost/mydb",
"psycopg2.connect db": {"dsn": "{database_url}"},
"MyRepository repo": {"db": "{db}"},
}
wired = Wiring(get_spec())# generate_wiring.py
from apywire import WiringCompiler
from config import get_spec
compiler = WiringCompiler(get_spec())
code = compiler.compile(aio=True, thread_safe=True)
with open("compiled_wiring.py", "w") as f:
f.write(code)
print("Compiled wiring generated!")Run once during deployment:
python generate_wiring.pyUse in production:
# app.py
from compiled_wiring import Compiled
wired = Compiled()
repo = wired.repo()The generated code is readable Python. You can inspect it to understand dependencies:
spec = {
"MyDatabase db": {},
"MyCache cache": {"db": "{db}"},
"MyService service": {"cache": "{cache}"},
}
compiler = WiringCompiler(spec)
code = compiler.compile()
# Save and inspect
with open("wiring.py", "w") as f:
f.write(code)
# Look at wiring.py to see:
# - service() method calls cache()
# - cache() method calls db()
# - Dependency chain is explicitThe generated code doesn't include SPDX headers by default. Add them manually if needed:
header = """# SPDX-FileCopyrightText: 2025 Your Name <your@email.com>
#
# SPDX-License-Identifier: ISC
"""
compiler = WiringCompiler(spec)
code = compiler.compile()
full_code = header + code
with open("wiring.py", "w") as f:
f.write(full_code)Test that compiled code behaves identically to runtime:
from apywire import Wiring
spec = {
"datetime.datetime now": {"year": 2025, "month": 1, "day": 1},
}
# Runtime
wired_runtime = Wiring(spec)
# Compiled
compiler = WiringCompiler(spec)
code = compiler.compile()
exec(code) # Defines Compiled class
wired_compiled = Compiled()
# Both should produce same results
assert wired_runtime.now() == wired_compiled.now()# In your CI/CD pipeline
python scripts/generate_wiring.py
uv run python setup.py build_ext --inplace # Optional: Cython compileOption A: Don't commit generated code (regenerate on deploy)
# .gitignore
compiled_wiring.pyOption B: Commit generated code (easier for others to use)
Pros: Others can use without regenerating Cons: Diffs in PRs, risk of forgetting to regenerate
# In your tests
def test_compiled_code_valid():
from apywire import WiringCompiler
compiler = WiringCompiler(spec)
code = compiler.compile()
# Check code compiles
compile(code, "wiring.py", "exec")
# Check code executes
exec(code)If you use thread_safe=True in runtime, compile with it too:
# Development
wired = Wiring(spec, thread_safe=True)
# Production
compiler = WiringCompiler(spec)
code = compiler.compile(thread_safe=True) # Match!If generated code has issues:
code = compiler.compile()
with open("debug_wiring.py", "w") as f:
f.write(code)
# Open debug_wiring.py in your editortry:
compile(code, "wiring.py", "exec")
except SyntaxError as e:
print(f"Syntax error in generated code: {e}")Make sure all modules in your spec can be imported:
spec = {
"my.custom.module.Class obj": {},
}
# Make sure my.custom.module is importable!
import my.custom.moduleCompilation is static. If your spec changes at runtime, you can't use compilation:
# This won't work with compilation
spec = {}
if os.getenv("PRODUCTION"):
spec["db"] = {...}
else:
spec["db"] = {...} # Different spec!Specs with lambdas can't be compiled:
spec = {
"MyClass obj": {"callback": lambda x: x * 2}, # Can't compile!
}Some Python objects can't be represented as code literals:
import re
spec = {
"regex": re.compile(r"\d+"), # Can't compile!
}For these cases, use constants in the compiled code or factory functions.
- Basic Usage - Understand runtime wiring first
- Thread Safety - Learn about thread-safe compilation
- Async Support - Learn about async compilation
- Advanced Features - Advanced patterns and edge cases