Dynamic Import Patterns in Victor¶
This guide explains dynamic import patterns used in Victor verticals and how to properly analyze code for dependencies.
Overview¶
Traditional static analysis (grep, AST) often misses Python's dynamic import patterns. Victor verticals use several dynamic loading mechanisms that must be accounted for when analyzing "dead code" or module dependencies.
Common Dynamic Import Patterns¶
1. init.py Export Mappings¶
Pattern: Modules are re-exported through lazy import mappings.
# victor_coding/__init__.py
_EXPORTS = {
"CodingSafetyRules": ("victor_coding.safety_enhanced", "CodingSafetyRules"),
"EnhancedCodingConversationManager": (
"victor_coding.conversation_enhanced",
"EnhancedCodingConversationManager",
),
}
def __getattr__(name: str) -> Any:
target = _EXPORTS.get(name)
if target:
module = import_module(module_name)
return getattr(module, attribute_name)
Detection: Check for:
- _EXPORTS dictionary
- __getattr__ implementations
- Lazy import patterns
Tools:
2. String-Based importlib.import_module()¶
Pattern: Module paths are strings loaded at runtime.
# victor_coding/workflows/provider.py
class WorkflowProvider:
def _get_escape_hatches_module(self) -> str:
return "victor_coding.escape_hatches"
def load_workflow(self, name: str):
module_path = self._get_escape_hatches_module()
escape_hatches = importlib.import_module(module_path)
Detection: Check for:
- importlib.import_module()
- __import__()
- Methods returning module path strings
Tools:
3. Hook Methods¶
Pattern: Methods that return module/function paths for dynamic registration.
Examples:
- _get_escape_hatches_module()
- _get_capability_provider_module()
- _get_extension_provider_module()
Detection: Check for methods with these naming patterns in:
- Provider classes
- Registry classes
- Factory classes
4. Plugin Registration¶
Pattern: Classes/functions register themselves via decorators or explicit calls.
Detection: Check for:
- Decorator-based registration (@register, @plugin)
- Explicit registration calls
- Plugin manifests
5. YAML Workflow Conditions¶
Pattern: Functions referenced by string in YAML config files.
# workflow.yaml
- id: check_quality
type: condition
condition: "retrieval_quality" # References function in escape_hatches.py
Detection: Check for:
- YAML files with condition references
- Corresponding Python functions
- Workflow provider classes
Analyzing Module Dependencies¶
Static Analysis¶
For direct imports, static analysis works:
# Find direct imports
grep -rn "from victor_xxx import" victor_xxx/
grep -rn "import victor_xxx" victor_xxx/
Dynamic Analysis¶
For dynamic imports, use the DynamicImportTracker:
from victor.tools.graph_dynamic_import_tracker import DynamicImportTracker
tracker = DynamicImportTracker(root_path="/path/to/project")
# Scan all dynamic imports
imports = tracker.scan_all()
# Check if a module is used
analysis = tracker.augment_graph_analysis(
static_callers=set(), # From static analysis
symbol_name="escape_hatches"
)
# Returns: {
# "static_callers": [...],
# "dynamic_importers": ["workflows/provider.py"],
# "exported_from": [...],
# "total_references": 1
# }
Dead Code Detection Checklist¶
Before marking code as "dead", verify:
- Not in
__init__.py_EXPORTSmapping - Not loaded via
importlib.import_module() - Not a hook method (returns module path string)
- Not referenced in YAML/config files
- Not decorated with
@registeror similar - No test imports/usage
- Not in public API (
__all__)
Examples¶
Example 1: escape_hatches.py¶
Static analysis shows: 0 direct imports
Dynamic analysis shows:
# workflows/provider.py
def _get_escape_hatches_module(self) -> str:
return "victor_rag.escape_hatches"
# Later...
escape_hatches = importlib.import_module(self._get_escape_hatches_module())
Conclusion: NOT dead - dynamically loaded
Example 2: safety_enhanced.py¶
Static analysis shows: 0 direct imports in victor_coding/
Dynamic analysis shows:
# __init__.py
_EXPORTS = {
"CodingSafetyRules": ("victor_coding.safety_enhanced", "CodingSafetyRules"),
}
Conclusion: NOT dead - exported as public API
Tools¶
DynamicImportTracker¶
Located in: victor/tools/graph_dynamic_import_tracker.py
from victor.tools.graph_dynamic_import_tracker import DynamicImportTracker
tracker = DynamicImportTracker(root_path=".")
# Get all dynamic imports
imports = tracker.scan_all()
# Check reverse dependencies
importers = tracker.get_reverse_dynamic_dependencies("my_module")
# Check if file is a dynamic entrypoint
is_entrypoint, reason = tracker.is_dynamic_entrypoint("my_file.py")
# Augment graph analysis
analysis = tracker.augment_graph_analysis(
static_callers={"main.py"},
symbol_name="my_function"
)
Best Practices¶
For Code Authors¶
- Document dynamic imports: Add comments explaining dynamic loading
- Use consistent patterns: Follow Victor's conventions for dynamic imports
- Add type hints: Help tools understand return types
- Register exports: Always add to
__init__.pyfor public APIs
For Code Reviewers¶
- Check dynamic patterns: Use this guide to verify "dead code"
- Ask for context: When unsure, ask about intended usage
- Run tests: Check if tests use the module
- Check init.py: Look for export mappings