BREAKING CHANGES: - Removed orphaned dqn.rs monolithic trainer (4,975 lines) - Removed orphaned dqn_ensemble.rs module (816 lines) - Removed orphaned tft.rs and tft_complete_int8_integration_test.rs - TFT trainer split into modular directory structure DQN Module Refactoring: - Split trainers/dqn.rs into modular structure (config.rs, statistics.rs, trainer.rs) - Fixed hyperopt 39D search space (continuous params only) - Boolean flags (use_dueling, use_double_dqn, use_per, use_noisy_nets) are now FIXED architectural decisions - use_distributional defaults to false (Candle BUG #36 - scatter_add gradient issues) Clean Module Structure: - ml/src/trainers/dqn/ directory with proper mod.rs exports - ml/src/trainers/tft/ directory with config.rs, types.rs, model.rs, trainer.rs, tests.rs - All P0 features validated: TD-error clamping, batch diversity, LR scheduler, priority staleness Documentation: - Added comprehensive docs in docs/codebase-cleanup/ - ADR-001 for DQN refactoring decisions - Rainbow DQN component matrix and quick reference guides Build Status: Compiles with zero errors 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
155 lines
5.0 KiB
Python
Executable File
155 lines
5.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Analyze Rust workspace for unused dependencies.
|
|
Checks if dependencies in Cargo.toml are actually used in source code.
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
import subprocess
|
|
from pathlib import Path
|
|
from collections import defaultdict
|
|
|
|
def parse_cargo_toml(path):
|
|
"""Parse dependencies from Cargo.toml"""
|
|
deps = []
|
|
try:
|
|
with open(path, 'r') as f:
|
|
content = f.read()
|
|
|
|
# Extract dependencies section
|
|
in_deps = False
|
|
in_dev_deps = False
|
|
for line in content.split('\n'):
|
|
if line.strip().startswith('[dependencies]'):
|
|
in_deps = True
|
|
in_dev_deps = False
|
|
continue
|
|
elif line.strip().startswith('[dev-dependencies]'):
|
|
in_deps = False
|
|
in_dev_deps = True
|
|
continue
|
|
elif line.strip().startswith('['):
|
|
in_deps = False
|
|
in_dev_deps = False
|
|
continue
|
|
|
|
if in_deps and line.strip() and not line.strip().startswith('#'):
|
|
# Extract dependency name
|
|
match = re.match(r'^([a-zA-Z0-9_-]+)\s*=', line)
|
|
if match:
|
|
dep_name = match.group(1).replace('-', '_')
|
|
deps.append((dep_name, 'normal'))
|
|
elif in_dev_deps and line.strip() and not line.strip().startswith('#'):
|
|
match = re.match(r'^([a-zA-Z0-9_-]+)\s*=', line)
|
|
if match:
|
|
dep_name = match.group(1).replace('-', '_')
|
|
deps.append((dep_name, 'dev'))
|
|
except Exception as e:
|
|
print(f"Error parsing {path}: {e}")
|
|
|
|
return deps
|
|
|
|
def check_dep_usage(crate_path, dep_name):
|
|
"""Check if dependency is used in Rust source files"""
|
|
src_path = os.path.join(crate_path, 'src')
|
|
tests_path = os.path.join(crate_path, 'tests')
|
|
benches_path = os.path.join(crate_path, 'benches')
|
|
examples_path = os.path.join(crate_path, 'examples')
|
|
|
|
patterns = [
|
|
f'use {dep_name}',
|
|
f'use {dep_name}::',
|
|
f'extern crate {dep_name}',
|
|
f'{dep_name}::',
|
|
]
|
|
|
|
for base_path in [src_path, tests_path, benches_path, examples_path]:
|
|
if not os.path.exists(base_path):
|
|
continue
|
|
|
|
for root, dirs, files in os.walk(base_path):
|
|
# Skip target directory
|
|
if 'target' in dirs:
|
|
dirs.remove('target')
|
|
|
|
for file in files:
|
|
if not file.endswith('.rs'):
|
|
continue
|
|
|
|
file_path = os.path.join(root, file)
|
|
try:
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
for pattern in patterns:
|
|
if pattern in content:
|
|
return True
|
|
except Exception:
|
|
continue
|
|
|
|
return False
|
|
|
|
def analyze_workspace():
|
|
"""Analyze all crates in workspace"""
|
|
workspace_root = '/home/jgrusewski/Work/foxhunt'
|
|
|
|
# Find all Cargo.toml files (excluding target directories)
|
|
cargo_tomls = []
|
|
for root, dirs, files in os.walk(workspace_root):
|
|
# Skip target and vendor directories
|
|
if 'target' in dirs:
|
|
dirs.remove('target')
|
|
if '.git' in dirs:
|
|
dirs.remove('.git')
|
|
|
|
if 'Cargo.toml' in files:
|
|
cargo_path = os.path.join(root, 'Cargo.toml')
|
|
# Skip if it's a workspace-only Cargo.toml
|
|
with open(cargo_path, 'r') as f:
|
|
content = f.read()
|
|
if '[package]' in content:
|
|
cargo_tomls.append(cargo_path)
|
|
|
|
results = {}
|
|
|
|
for cargo_toml in cargo_tomls[:15]: # Limit to first 15 for performance
|
|
crate_path = os.path.dirname(cargo_toml)
|
|
crate_name = os.path.basename(crate_path)
|
|
|
|
print(f"\nAnalyzing {crate_name}...")
|
|
|
|
deps = parse_cargo_toml(cargo_toml)
|
|
unused = []
|
|
|
|
for dep_name, dep_type in deps:
|
|
# Skip workspace crates
|
|
if dep_name in ['trading_engine', 'risk', 'data', 'backtesting',
|
|
'common', 'storage', 'ml', 'config', 'database',
|
|
'market_data', 'tli', 'risk_data', 'trading_data',
|
|
'adaptive_strategy', 'model_loader']:
|
|
continue
|
|
|
|
# Check if dependency is used
|
|
if not check_dep_usage(crate_path, dep_name):
|
|
unused.append((dep_name, dep_type))
|
|
|
|
if unused:
|
|
results[crate_name] = unused
|
|
|
|
return results
|
|
|
|
if __name__ == '__main__':
|
|
print("=== UNUSED DEPENDENCY ANALYSIS ===\n")
|
|
results = analyze_workspace()
|
|
|
|
if not results:
|
|
print("\n✅ No obvious unused dependencies found!")
|
|
else:
|
|
print("\n⚠️ POTENTIALLY UNUSED DEPENDENCIES:\n")
|
|
for crate, unused in results.items():
|
|
print(f"\n{crate}:")
|
|
for dep, dep_type in unused:
|
|
print(f" - {dep} ({dep_type})")
|
|
|
|
print("\n=== ANALYSIS COMPLETE ===")
|