zexus 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +0 -0
- package/README.md +2513 -0
- package/bin/zexus +2 -0
- package/bin/zpics +2 -0
- package/bin/zpm +2 -0
- package/bin/zx +2 -0
- package/bin/zx-deploy +2 -0
- package/bin/zx-dev +2 -0
- package/bin/zx-run +2 -0
- package/package.json +66 -0
- package/scripts/README.md +24 -0
- package/scripts/postinstall.js +44 -0
- package/shared_config.json +24 -0
- package/src/README.md +1525 -0
- package/src/tests/run_zexus_tests.py +117 -0
- package/src/tests/test_all_phases.zx +346 -0
- package/src/tests/test_blockchain_features.zx +306 -0
- package/src/tests/test_complexity_features.zx +321 -0
- package/src/tests/test_core_integration.py +185 -0
- package/src/tests/test_phase10_ecosystem.zx +177 -0
- package/src/tests/test_phase1_modifiers.zx +87 -0
- package/src/tests/test_phase2_plugins.zx +80 -0
- package/src/tests/test_phase3_security.zx +97 -0
- package/src/tests/test_phase4_vfs.zx +116 -0
- package/src/tests/test_phase5_types.zx +117 -0
- package/src/tests/test_phase6_metaprogramming.zx +125 -0
- package/src/tests/test_phase7_optimization.zx +132 -0
- package/src/tests/test_phase9_advanced_types.zx +157 -0
- package/src/tests/test_security_features.py +419 -0
- package/src/tests/test_security_features.zx +276 -0
- package/src/tests/test_simple_zx.zx +1 -0
- package/src/tests/test_verification_simple.zx +69 -0
- package/src/zexus/__init__.py +28 -0
- package/src/zexus/__main__.py +5 -0
- package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/advanced_types.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/builtin_modules.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/complexity_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/concurrency_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/config.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/dependency_injection.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/ecosystem.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/hybrid_orchestrator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/metaprogramming.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/optimization.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/plugin_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/policy_engine.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/stdlib_integration.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/strategy_recovery.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/type_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/virtual_filesystem.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
- package/src/zexus/advanced_types.py +401 -0
- package/src/zexus/blockchain/__init__.py +40 -0
- package/src/zexus/blockchain/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/crypto.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/ledger.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/transaction.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/crypto.py +463 -0
- package/src/zexus/blockchain/ledger.py +255 -0
- package/src/zexus/blockchain/transaction.py +267 -0
- package/src/zexus/builtin_modules.py +284 -0
- package/src/zexus/builtin_plugins.py +317 -0
- package/src/zexus/capability_system.py +372 -0
- package/src/zexus/cli/__init__.py +2 -0
- package/src/zexus/cli/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
- package/src/zexus/cli/main.py +707 -0
- package/src/zexus/cli/zpm.py +203 -0
- package/src/zexus/compare_interpreter_compiler.py +146 -0
- package/src/zexus/compiler/__init__.py +169 -0
- package/src/zexus/compiler/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/compiler/bytecode.py +266 -0
- package/src/zexus/compiler/compat_runtime.py +277 -0
- package/src/zexus/compiler/lexer.py +257 -0
- package/src/zexus/compiler/parser.py +779 -0
- package/src/zexus/compiler/semantic.py +118 -0
- package/src/zexus/compiler/zexus_ast.py +454 -0
- package/src/zexus/complexity_system.py +575 -0
- package/src/zexus/concurrency_system.py +493 -0
- package/src/zexus/config.py +201 -0
- package/src/zexus/crypto_bridge.py +19 -0
- package/src/zexus/dependency_injection.py +423 -0
- package/src/zexus/ecosystem.py +434 -0
- package/src/zexus/environment.py +101 -0
- package/src/zexus/environment_manager.py +119 -0
- package/src/zexus/error_reporter.py +314 -0
- package/src/zexus/evaluator/__init__.py +12 -0
- package/src/zexus/evaluator/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/integration.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/bytecode_compiler.py +700 -0
- package/src/zexus/evaluator/core.py +891 -0
- package/src/zexus/evaluator/expressions.py +827 -0
- package/src/zexus/evaluator/functions.py +3989 -0
- package/src/zexus/evaluator/integration.py +396 -0
- package/src/zexus/evaluator/statements.py +4303 -0
- package/src/zexus/evaluator/utils.py +126 -0
- package/src/zexus/evaluator_original.py +2041 -0
- package/src/zexus/external_bridge.py +16 -0
- package/src/zexus/find_affected_imports.sh +155 -0
- package/src/zexus/hybrid_orchestrator.py +152 -0
- package/src/zexus/input_validation.py +259 -0
- package/src/zexus/lexer.py +571 -0
- package/src/zexus/logging.py +89 -0
- package/src/zexus/lsp/__init__.py +9 -0
- package/src/zexus/lsp/completion_provider.py +207 -0
- package/src/zexus/lsp/definition_provider.py +22 -0
- package/src/zexus/lsp/hover_provider.py +71 -0
- package/src/zexus/lsp/server.py +269 -0
- package/src/zexus/lsp/symbol_provider.py +31 -0
- package/src/zexus/metaprogramming.py +321 -0
- package/src/zexus/module_cache.py +89 -0
- package/src/zexus/module_manager.py +107 -0
- package/src/zexus/object.py +973 -0
- package/src/zexus/optimization.py +424 -0
- package/src/zexus/parser/__init__.py +31 -0
- package/src/zexus/parser/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
- package/src/zexus/parser/integration.py +86 -0
- package/src/zexus/parser/parser.py +3977 -0
- package/src/zexus/parser/strategy_context.py +7254 -0
- package/src/zexus/parser/strategy_structural.py +1033 -0
- package/src/zexus/persistence.py +391 -0
- package/src/zexus/plugin_system.py +290 -0
- package/src/zexus/policy_engine.py +365 -0
- package/src/zexus/profiler/__init__.py +5 -0
- package/src/zexus/profiler/profiler.py +233 -0
- package/src/zexus/purity_system.py +398 -0
- package/src/zexus/runtime/__init__.py +20 -0
- package/src/zexus/runtime/async_runtime.py +324 -0
- package/src/zexus/search_old_imports.sh +65 -0
- package/src/zexus/security.py +1407 -0
- package/src/zexus/stack_trace.py +233 -0
- package/src/zexus/stdlib/__init__.py +27 -0
- package/src/zexus/stdlib/blockchain.py +341 -0
- package/src/zexus/stdlib/compression.py +167 -0
- package/src/zexus/stdlib/crypto.py +124 -0
- package/src/zexus/stdlib/datetime.py +163 -0
- package/src/zexus/stdlib/db_mongo.py +199 -0
- package/src/zexus/stdlib/db_mysql.py +162 -0
- package/src/zexus/stdlib/db_postgres.py +163 -0
- package/src/zexus/stdlib/db_sqlite.py +133 -0
- package/src/zexus/stdlib/encoding.py +230 -0
- package/src/zexus/stdlib/fs.py +195 -0
- package/src/zexus/stdlib/http.py +219 -0
- package/src/zexus/stdlib/http_server.py +248 -0
- package/src/zexus/stdlib/json_module.py +61 -0
- package/src/zexus/stdlib/math.py +360 -0
- package/src/zexus/stdlib/os_module.py +265 -0
- package/src/zexus/stdlib/regex.py +148 -0
- package/src/zexus/stdlib/sockets.py +253 -0
- package/src/zexus/stdlib/test_framework.zx +208 -0
- package/src/zexus/stdlib/test_runner.zx +119 -0
- package/src/zexus/stdlib_integration.py +341 -0
- package/src/zexus/strategy_recovery.py +256 -0
- package/src/zexus/syntax_validator.py +356 -0
- package/src/zexus/testing/zpics.py +407 -0
- package/src/zexus/testing/zpics_runtime.py +369 -0
- package/src/zexus/type_system.py +374 -0
- package/src/zexus/validation_system.py +569 -0
- package/src/zexus/virtual_filesystem.py +355 -0
- package/src/zexus/vm/__init__.py +8 -0
- package/src/zexus/vm/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/memory_manager.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/memory_pool.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/peephole_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/profiler.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/register_allocator.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/register_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/ssa_converter.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/async_optimizer.py +420 -0
- package/src/zexus/vm/bytecode.py +428 -0
- package/src/zexus/vm/bytecode_converter.py +297 -0
- package/src/zexus/vm/cache.py +532 -0
- package/src/zexus/vm/jit.py +720 -0
- package/src/zexus/vm/memory_manager.py +520 -0
- package/src/zexus/vm/memory_pool.py +511 -0
- package/src/zexus/vm/optimizer.py +478 -0
- package/src/zexus/vm/parallel_vm.py +899 -0
- package/src/zexus/vm/peephole_optimizer.py +452 -0
- package/src/zexus/vm/profiler.py +527 -0
- package/src/zexus/vm/register_allocator.py +462 -0
- package/src/zexus/vm/register_vm.py +520 -0
- package/src/zexus/vm/ssa_converter.py +757 -0
- package/src/zexus/vm/vm.py +1392 -0
- package/src/zexus/zexus_ast.py +1782 -0
- package/src/zexus/zexus_token.py +253 -0
- package/src/zexus/zpm/__init__.py +15 -0
- package/src/zexus/zpm/installer.py +116 -0
- package/src/zexus/zpm/package_manager.py +208 -0
- package/src/zexus/zpm/publisher.py +98 -0
- package/src/zexus/zpm/registry.py +110 -0
- package/src/zexus.egg-info/PKG-INFO +2235 -0
- package/src/zexus.egg-info/SOURCES.txt +876 -0
- package/src/zexus.egg-info/dependency_links.txt +1 -0
- package/src/zexus.egg-info/entry_points.txt +3 -0
- package/src/zexus.egg-info/not-zip-safe +1 -0
- package/src/zexus.egg-info/requires.txt +14 -0
- package/src/zexus.egg-info/top_level.txt +2 -0
- package/zexus.json +14 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
# src/zexus/dependency_injection.py
|
|
2
|
+
"""
|
|
3
|
+
Dependency Injection and Module Mocking System for Zexus
|
|
4
|
+
Implements IoC (Inversion of Control) with EXPORT/EXTERNAL keywords
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Dict, Any, Optional, Callable, List
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from .object import Object, String, Integer, NULL, EvaluationError, Builtin, Action
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# ===============================================
|
|
13
|
+
# EXECUTION MODES
|
|
14
|
+
# ===============================================
|
|
15
|
+
|
|
16
|
+
class ExecutionMode(Enum):
|
|
17
|
+
"""Execution modes for dependency injection"""
|
|
18
|
+
PRODUCTION = "production"
|
|
19
|
+
DEBUG = "debug"
|
|
20
|
+
TEST = "test"
|
|
21
|
+
SANDBOX = "sandbox"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Current execution mode (global state)
|
|
25
|
+
_current_mode = ExecutionMode.PRODUCTION
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def set_execution_mode(mode: ExecutionMode):
|
|
29
|
+
"""Set the current execution mode"""
|
|
30
|
+
global _current_mode
|
|
31
|
+
_current_mode = mode
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_execution_mode() -> ExecutionMode:
|
|
35
|
+
"""Get the current execution mode"""
|
|
36
|
+
return _current_mode
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# ===============================================
|
|
40
|
+
# DEPENDENCY CONTRACTS
|
|
41
|
+
# ===============================================
|
|
42
|
+
|
|
43
|
+
class DependencyContract:
|
|
44
|
+
"""Defines a required dependency"""
|
|
45
|
+
|
|
46
|
+
def __init__(self, name: str, dep_type: str = "any", required: bool = True, default_value: Any = None):
|
|
47
|
+
self.name = name
|
|
48
|
+
self.type = dep_type # Type hint: "function", "object", "const", "any"
|
|
49
|
+
self.required = required
|
|
50
|
+
self.default_value = default_value
|
|
51
|
+
self.description = ""
|
|
52
|
+
|
|
53
|
+
def validate(self, value: Any) -> tuple[bool, str]:
|
|
54
|
+
"""Validate that a provided value meets the contract"""
|
|
55
|
+
if value is None or value is NULL:
|
|
56
|
+
if self.required and self.default_value is None:
|
|
57
|
+
return False, f"Required dependency '{self.name}' not provided"
|
|
58
|
+
return True, ""
|
|
59
|
+
|
|
60
|
+
# Type validation
|
|
61
|
+
if self.type == "function":
|
|
62
|
+
if not isinstance(value, (Action, Builtin, Callable)):
|
|
63
|
+
return False, f"Dependency '{self.name}' must be a function, got {type(value)}"
|
|
64
|
+
elif self.type == "const":
|
|
65
|
+
# For const, we just check it's not mutable (no validation currently)
|
|
66
|
+
pass
|
|
67
|
+
elif self.type == "object":
|
|
68
|
+
if not isinstance(value, Object):
|
|
69
|
+
return False, f"Dependency '{self.name}' must be an object, got {type(value)}"
|
|
70
|
+
# "any" type accepts anything
|
|
71
|
+
|
|
72
|
+
return True, ""
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# ===============================================
|
|
76
|
+
# MODULE DEPENDENCY CONTAINER
|
|
77
|
+
# ===============================================
|
|
78
|
+
|
|
79
|
+
class DependencyContainer:
|
|
80
|
+
"""Container for a module's dependencies"""
|
|
81
|
+
|
|
82
|
+
def __init__(self, module_name: str):
|
|
83
|
+
self.module_name = module_name
|
|
84
|
+
self.contracts: Dict[str, DependencyContract] = {}
|
|
85
|
+
self.provided: Dict[str, Any] = {}
|
|
86
|
+
self.mocks: Dict[str, Any] = {} # For testing
|
|
87
|
+
|
|
88
|
+
def declare_dependency(self, name: str, dep_type: str = "any", required: bool = True, default_value: Any = None):
|
|
89
|
+
"""Declare a dependency contract"""
|
|
90
|
+
contract = DependencyContract(name, dep_type, required, default_value)
|
|
91
|
+
self.contracts[name] = contract
|
|
92
|
+
|
|
93
|
+
def provide(self, name: str, value: Any):
|
|
94
|
+
"""Provide a dependency value"""
|
|
95
|
+
if name not in self.contracts:
|
|
96
|
+
raise ValueError(f"No contract declared for dependency '{name}'")
|
|
97
|
+
|
|
98
|
+
# Validate against contract
|
|
99
|
+
contract = self.contracts[name]
|
|
100
|
+
valid, error_msg = contract.validate(value)
|
|
101
|
+
if not valid:
|
|
102
|
+
raise ValueError(f"Dependency validation failed: {error_msg}")
|
|
103
|
+
|
|
104
|
+
self.provided[name] = value
|
|
105
|
+
|
|
106
|
+
def mock(self, name: str, mock_value: Any):
|
|
107
|
+
"""Provide a mock for testing"""
|
|
108
|
+
if name not in self.contracts:
|
|
109
|
+
raise ValueError(f"No contract declared for dependency '{name}'")
|
|
110
|
+
|
|
111
|
+
self.mocks[name] = mock_value
|
|
112
|
+
|
|
113
|
+
def get(self, name: str) -> Any:
|
|
114
|
+
"""Get a dependency value (mock in TEST mode, real otherwise)"""
|
|
115
|
+
mode = get_execution_mode()
|
|
116
|
+
|
|
117
|
+
# In TEST/SANDBOX mode, prefer mocks
|
|
118
|
+
if mode in (ExecutionMode.TEST, ExecutionMode.SANDBOX):
|
|
119
|
+
if name in self.mocks:
|
|
120
|
+
return self.mocks[name]
|
|
121
|
+
|
|
122
|
+
# Check provided dependencies
|
|
123
|
+
if name in self.provided:
|
|
124
|
+
return self.provided[name]
|
|
125
|
+
|
|
126
|
+
# Check for default value
|
|
127
|
+
if name in self.contracts:
|
|
128
|
+
contract = self.contracts[name]
|
|
129
|
+
if contract.default_value is not None:
|
|
130
|
+
return contract.default_value
|
|
131
|
+
|
|
132
|
+
if not contract.required:
|
|
133
|
+
return NULL
|
|
134
|
+
|
|
135
|
+
# Dependency not satisfied
|
|
136
|
+
raise EvaluationError(f"Unsatisfied dependency: '{name}' in module '{self.module_name}'")
|
|
137
|
+
|
|
138
|
+
def validate_all(self) -> tuple[bool, List[str]]:
|
|
139
|
+
"""Validate that all required dependencies are satisfied"""
|
|
140
|
+
errors = []
|
|
141
|
+
|
|
142
|
+
for name, contract in self.contracts.items():
|
|
143
|
+
if contract.required:
|
|
144
|
+
try:
|
|
145
|
+
self.get(name)
|
|
146
|
+
except EvaluationError as e:
|
|
147
|
+
errors.append(str(e))
|
|
148
|
+
|
|
149
|
+
return len(errors) == 0, errors
|
|
150
|
+
|
|
151
|
+
def list_dependencies(self) -> List[Dict[str, Any]]:
|
|
152
|
+
"""List all declared dependencies"""
|
|
153
|
+
return [
|
|
154
|
+
{
|
|
155
|
+
'name': name,
|
|
156
|
+
'type': contract.type,
|
|
157
|
+
'required': contract.required,
|
|
158
|
+
'satisfied': name in self.provided or name in self.mocks or contract.default_value is not None
|
|
159
|
+
}
|
|
160
|
+
for name, contract in self.contracts.items()
|
|
161
|
+
]
|
|
162
|
+
|
|
163
|
+
def clear_mocks(self):
|
|
164
|
+
"""Clear all mocks"""
|
|
165
|
+
self.mocks.clear()
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# ===============================================
|
|
169
|
+
# DEPENDENCY INJECTION REGISTRY
|
|
170
|
+
# ===============================================
|
|
171
|
+
|
|
172
|
+
class DIRegistry:
|
|
173
|
+
"""Global registry for dependency injection containers"""
|
|
174
|
+
|
|
175
|
+
def __init__(self):
|
|
176
|
+
self.containers: Dict[str, DependencyContainer] = {}
|
|
177
|
+
self.module_factories: Dict[str, Callable] = {}
|
|
178
|
+
|
|
179
|
+
def register_module(self, module_name: str) -> DependencyContainer:
|
|
180
|
+
"""Register a module and return its dependency container"""
|
|
181
|
+
if module_name not in self.containers:
|
|
182
|
+
self.containers[module_name] = DependencyContainer(module_name)
|
|
183
|
+
return self.containers[module_name]
|
|
184
|
+
|
|
185
|
+
def get_container(self, module_name: str) -> Optional[DependencyContainer]:
|
|
186
|
+
"""Get dependency container for a module, creating it if it doesn't exist"""
|
|
187
|
+
if module_name not in self.containers:
|
|
188
|
+
self.containers[module_name] = DependencyContainer(module_name)
|
|
189
|
+
return self.containers[module_name]
|
|
190
|
+
|
|
191
|
+
def provide_dependency(self, module_name: str, dep_name: str, value: Any):
|
|
192
|
+
"""Provide a dependency to a module"""
|
|
193
|
+
container = self.get_container(module_name)
|
|
194
|
+
if not container:
|
|
195
|
+
raise ValueError(f"Module '{module_name}' not registered")
|
|
196
|
+
container.provide(dep_name, value)
|
|
197
|
+
|
|
198
|
+
def mock_dependency(self, module_name: str, dep_name: str, mock_value: Any):
|
|
199
|
+
"""Mock a dependency for testing"""
|
|
200
|
+
container = self.get_container(module_name)
|
|
201
|
+
if not container:
|
|
202
|
+
raise ValueError(f"Module '{module_name}' not registered")
|
|
203
|
+
container.mock(dep_name, mock_value)
|
|
204
|
+
|
|
205
|
+
def validate_module(self, module_name: str) -> tuple[bool, List[str]]:
|
|
206
|
+
"""Validate all dependencies for a module"""
|
|
207
|
+
container = self.get_container(module_name)
|
|
208
|
+
if not container:
|
|
209
|
+
return False, [f"Module '{module_name}' not registered"]
|
|
210
|
+
return container.validate_all()
|
|
211
|
+
|
|
212
|
+
def clear_all_mocks(self):
|
|
213
|
+
"""Clear all mocks from all modules"""
|
|
214
|
+
for container in self.containers.values():
|
|
215
|
+
container.clear_mocks()
|
|
216
|
+
|
|
217
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
218
|
+
"""Get DI statistics"""
|
|
219
|
+
total_deps = 0
|
|
220
|
+
satisfied_deps = 0
|
|
221
|
+
mocked_deps = 0
|
|
222
|
+
|
|
223
|
+
for container in self.containers.values():
|
|
224
|
+
deps = container.list_dependencies()
|
|
225
|
+
total_deps += len(deps)
|
|
226
|
+
satisfied_deps += sum(1 for d in deps if d['satisfied'])
|
|
227
|
+
mocked_deps += len(container.mocks)
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
'registered_modules': len(self.containers),
|
|
231
|
+
'total_dependencies': total_deps,
|
|
232
|
+
'satisfied_dependencies': satisfied_deps,
|
|
233
|
+
'mocked_dependencies': mocked_deps,
|
|
234
|
+
'execution_mode': get_execution_mode().value
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# Global DI registry
|
|
239
|
+
_di_registry = DIRegistry()
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def get_di_registry() -> DIRegistry:
|
|
243
|
+
"""Get the global DI registry"""
|
|
244
|
+
return _di_registry
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def get_dependency_manager() -> DIRegistry:
|
|
248
|
+
"""Get the dependency manager (alias for get_di_registry)"""
|
|
249
|
+
return _di_registry
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
# ===============================================
|
|
253
|
+
# MODULE BUILDER (For EXPORT blocks)
|
|
254
|
+
# ===============================================
|
|
255
|
+
|
|
256
|
+
class ModuleBuilder:
|
|
257
|
+
"""Builder for creating modules with dependency contracts"""
|
|
258
|
+
|
|
259
|
+
def __init__(self, module_name: str):
|
|
260
|
+
self.module_name = module_name
|
|
261
|
+
self.container = get_di_registry().register_module(module_name)
|
|
262
|
+
|
|
263
|
+
def require_external(self, name: str, dep_type: str = "any", required: bool = True):
|
|
264
|
+
"""Declare an EXTERNAL dependency"""
|
|
265
|
+
self.container.declare_dependency(name, dep_type, required)
|
|
266
|
+
return self
|
|
267
|
+
|
|
268
|
+
def require_const(self, name: str, default_value: Any = None):
|
|
269
|
+
"""Declare an EXTERNAL CONST dependency"""
|
|
270
|
+
self.container.declare_dependency(name, "const", required=(default_value is None), default_value=default_value)
|
|
271
|
+
return self
|
|
272
|
+
|
|
273
|
+
def provide(self, name: str, value: Any):
|
|
274
|
+
"""Provide a dependency (for setup/testing)"""
|
|
275
|
+
self.container.provide(name, value)
|
|
276
|
+
return self
|
|
277
|
+
|
|
278
|
+
def build(self) -> DependencyContainer:
|
|
279
|
+
"""Build and return the container"""
|
|
280
|
+
return self.container
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
# ===============================================
|
|
284
|
+
# MOCK FACTORY
|
|
285
|
+
# ===============================================
|
|
286
|
+
|
|
287
|
+
class MockFactory:
|
|
288
|
+
"""Factory for creating mock objects for testing"""
|
|
289
|
+
|
|
290
|
+
@staticmethod
|
|
291
|
+
def create_function_mock(name: str, return_value: Any = NULL) -> Builtin:
|
|
292
|
+
"""Create a mock function"""
|
|
293
|
+
def mock_fn(*args):
|
|
294
|
+
return return_value
|
|
295
|
+
return Builtin(mock_fn, name=f"mock_{name}")
|
|
296
|
+
|
|
297
|
+
@staticmethod
|
|
298
|
+
def create_object_mock(properties: Dict[str, Any]) -> Object:
|
|
299
|
+
"""Create a mock object with properties"""
|
|
300
|
+
from .object import Map
|
|
301
|
+
return Map(properties)
|
|
302
|
+
|
|
303
|
+
@staticmethod
|
|
304
|
+
def create_api_mock(endpoints: Dict[str, Any]) -> Object:
|
|
305
|
+
"""Create a mock API with endpoints"""
|
|
306
|
+
from .object import Map
|
|
307
|
+
|
|
308
|
+
mock_endpoints = {}
|
|
309
|
+
for endpoint, response in endpoints.items():
|
|
310
|
+
def make_endpoint_fn(resp):
|
|
311
|
+
def endpoint_fn(*args):
|
|
312
|
+
return resp
|
|
313
|
+
return endpoint_fn
|
|
314
|
+
mock_endpoints[endpoint] = Builtin(make_endpoint_fn(response), name=f"mock_{endpoint}")
|
|
315
|
+
|
|
316
|
+
return Map(mock_endpoints)
|
|
317
|
+
|
|
318
|
+
@staticmethod
|
|
319
|
+
def create_spy_function(name: str, original_fn: Optional[Callable] = None) -> tuple[Builtin, List]:
|
|
320
|
+
"""Create a spy function that records calls"""
|
|
321
|
+
call_log = []
|
|
322
|
+
|
|
323
|
+
def spy_fn(*args):
|
|
324
|
+
call_log.append({
|
|
325
|
+
'args': args,
|
|
326
|
+
'timestamp': __import__('time').time()
|
|
327
|
+
})
|
|
328
|
+
if original_fn:
|
|
329
|
+
return original_fn(*args)
|
|
330
|
+
return NULL
|
|
331
|
+
|
|
332
|
+
return Builtin(spy_fn, name=f"spy_{name}"), call_log
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
# ===============================================
|
|
336
|
+
# UTILITY FUNCTIONS
|
|
337
|
+
# ===============================================
|
|
338
|
+
|
|
339
|
+
def create_module(module_name: str) -> ModuleBuilder:
|
|
340
|
+
"""Create a new module with dependency injection"""
|
|
341
|
+
return ModuleBuilder(module_name)
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def inject_dependency(module_name: str, dep_name: str, value: Any):
|
|
345
|
+
"""Inject a dependency into a module"""
|
|
346
|
+
registry = get_di_registry()
|
|
347
|
+
registry.provide_dependency(module_name, dep_name, value)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def mock_dependency(module_name: str, dep_name: str, mock_value: Any):
|
|
351
|
+
"""Mock a dependency for testing"""
|
|
352
|
+
registry = get_di_registry()
|
|
353
|
+
registry.mock_dependency(module_name, dep_name, mock_value)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def get_dependency(module_name: str, dep_name: str) -> Any:
|
|
357
|
+
"""Get a dependency from a module"""
|
|
358
|
+
registry = get_di_registry()
|
|
359
|
+
container = registry.get_container(module_name)
|
|
360
|
+
if not container:
|
|
361
|
+
raise ValueError(f"Module '{module_name}' not registered")
|
|
362
|
+
return container.get(dep_name)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def validate_dependencies(module_name: str) -> tuple[bool, List[str]]:
|
|
366
|
+
"""Validate all dependencies for a module"""
|
|
367
|
+
registry = get_di_registry()
|
|
368
|
+
return registry.validate_module(module_name)
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def clear_all_mocks():
|
|
372
|
+
"""Clear all mocks"""
|
|
373
|
+
registry = get_di_registry()
|
|
374
|
+
registry.clear_all_mocks()
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def get_di_stats() -> Dict[str, Any]:
|
|
378
|
+
"""Get dependency injection statistics"""
|
|
379
|
+
registry = get_di_registry()
|
|
380
|
+
return registry.get_stats()
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
# ===============================================
|
|
384
|
+
# TESTING UTILITIES
|
|
385
|
+
# ===============================================
|
|
386
|
+
|
|
387
|
+
class TestContext:
|
|
388
|
+
"""Context manager for testing with mocks"""
|
|
389
|
+
|
|
390
|
+
def __init__(self, module_name: str, mocks: Dict[str, Any]):
|
|
391
|
+
self.module_name = module_name
|
|
392
|
+
self.mocks = mocks
|
|
393
|
+
self.original_mode = None
|
|
394
|
+
|
|
395
|
+
def __enter__(self):
|
|
396
|
+
"""Enter test context"""
|
|
397
|
+
self.original_mode = get_execution_mode()
|
|
398
|
+
set_execution_mode(ExecutionMode.TEST)
|
|
399
|
+
|
|
400
|
+
# Apply mocks
|
|
401
|
+
for dep_name, mock_value in self.mocks.items():
|
|
402
|
+
mock_dependency(self.module_name, dep_name, mock_value)
|
|
403
|
+
|
|
404
|
+
return self
|
|
405
|
+
|
|
406
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
407
|
+
"""Exit test context"""
|
|
408
|
+
# Restore original mode
|
|
409
|
+
if self.original_mode:
|
|
410
|
+
set_execution_mode(self.original_mode)
|
|
411
|
+
|
|
412
|
+
# Clear mocks
|
|
413
|
+
registry = get_di_registry()
|
|
414
|
+
container = registry.get_container(self.module_name)
|
|
415
|
+
if container:
|
|
416
|
+
container.clear_mocks()
|
|
417
|
+
|
|
418
|
+
return False
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def test_with_mocks(module_name: str, mocks: Dict[str, Any]) -> TestContext:
|
|
422
|
+
"""Create a test context with mocks"""
|
|
423
|
+
return TestContext(module_name, mocks)
|