A tool for managing dependencies in a modular python project by tracking which dependencies are needed by which sub-modules
—
Comprehensive module dependency analysis using bytecode inspection to discover all imports and their relationships within Python projects.
Tracks dependencies of Python modules by analyzing bytecode to discover all import statements, supporting both direct analysis and recursive submodule tracking.
def track_module(
module_name: str,
package_name: Optional[str] = None,
submodules: Union[List[str], bool] = False,
track_import_stack: bool = False,
full_depth: bool = False,
detect_transitive: bool = False,
show_optional: bool = False,
) -> Union[Dict[str, List[str]], Dict[str, Dict[str, Any]]]:
"""
Track the dependencies of a single python module
Args:
module_name: The name of the module to track (may be relative if package_name provided)
package_name: The parent package name of the module if the module name is relative
submodules: If True, all submodules of the given module will also be tracked.
If given as a list of strings, only those submodules will be tracked.
If False, only the named module will be tracked.
track_import_stack: Store the stacks of modules causing each dependency for debugging
full_depth: Include transitive dependencies of third party dependencies
detect_transitive: Detect whether each dependency is 'direct' or 'transitive'
show_optional: Show whether each requirement is optional (behind a try/except) or not
Returns:
import_mapping: The mapping from fully-qualified module name to the set of imports
needed by the given module. If tracking import stacks or detecting
direct vs transitive dependencies, returns Dict[str, Dict[str, Any]]
with nested dicts containing "stack" and/or "type" keys.
Otherwise returns Dict[str, List[str]].
"""Simple module dependency analysis returning a mapping of modules to their required dependencies:
import import_tracker
# Track a single module
deps = import_tracker.track_module('requests')
print(deps)
# {'requests': ['urllib3', 'certifi', 'charset_normalizer', 'idna']}
# Track a module with package context
deps = import_tracker.track_module('.widgets', package_name='my_package')
print(deps)
# {'my_package.widgets': ['matplotlib', 'pillow']}Track dependencies across all submodules within a package:
# Track all submodules
deps = import_tracker.track_module('my_package', submodules=True)
print(deps)
# {
# 'my_package': ['requests'],
# 'my_package.utils': ['numpy', 'pandas'],
# 'my_package.widgets': ['matplotlib']
# }
# Track specific submodules only
deps = import_tracker.track_module(
'my_package',
submodules=['my_package.core', 'my_package.utils']
)Detailed analysis with transitive dependency detection and import stack tracing:
# Detect direct vs transitive dependencies
deps = import_tracker.track_module(
'my_package',
submodules=True,
detect_transitive=True,
show_optional=True
)
print(deps)
# {
# 'my_package': {
# 'requests': {'type': 'direct', 'optional': False},
# 'urllib3': {'type': 'transitive', 'optional': False}
# }
# }
# Track import stacks for debugging
deps = import_tracker.track_module(
'my_package',
track_import_stack=True,
full_depth=True
)
print(deps)
# {
# 'my_package': {
# 'requests': {'stack': [['my_package']]},
# 'urllib3': {'stack': [['my_package', 'requests']]}
# }
# }Identifies dependencies that are wrapped in try/except blocks, indicating they are optional:
# Show which dependencies are optional
deps = import_tracker.track_module('my_package', show_optional=True)
print(deps)
# {
# 'my_package': {
# 'requests': {'optional': False}, # Required dependency
# 'matplotlib': {'optional': True} # Optional dependency (in try/except)
# }
# }The dependency tracking functionality is available via command line:
# Basic tracking
python -m import_tracker --name my_package
# Track all submodules with pretty printing
python -m import_tracker --name my_package --submodules --indent 2
# Comprehensive analysis
python -m import_tracker \
--name my_package \
--submodules \
--track_import_stack \
--detect_transitive \
--show_optional \
--full_depth \
--indent 2# Available CLI arguments
--name/-n # Module name to track (required)
--package/-p # Package for relative imports
--submodules/-s # List of submodules to include (all if no value given)
--track_import_stack/-t # Store import stack traces
--detect_transitive/-d # Detect direct vs transitive dependencies
--show_optional/-o # Show optional vs required dependencies
--full_depth/-f # Include transitive third-party dependencies
--indent/-i # JSON output indentation
--log_level/-l # Set logging levelWhen detect_transitive=False, track_import_stack=False, and show_optional=False:
{
'module_name': ['dep1', 'dep2', 'dep3']
}When any of the advanced options are enabled:
{
'module_name': {
'dependency_name': {
'type': 'direct', # When detect_transitive=True
'stack': [['module_path']], # When track_import_stack=True
'optional': False # When show_optional=True
}
}
}# Core function types
from typing import Any, Dict, List, Optional, Union
ModuleName = str
DependencyName = str
ImportStack = List[List[str]]
# Simple return format
SimpleDependencyMap = Dict[ModuleName, List[DependencyName]]
# Extended return format
ExtendedDependencyInfo = Dict[str, Any] # Contains 'type', 'stack', 'optional' keys
ExtendedDependencyMap = Dict[ModuleName, Dict[DependencyName, ExtendedDependencyInfo]]
# Function return type
TrackModuleReturn = Union[SimpleDependencyMap, ExtendedDependencyMap]Install with Tessl CLI
npx tessl i tessl/pypi-import-tracker