feat: Major directory reorganization and cleanup
Reorganized project structure for better maintainability and reduced disk usage by 95.9% (11 GB -> 451 MB). Directory Reorganization (85% reduction in root files): - Created docs/ with subdirectories (deployment, testing, database, etc.) - Created infrastructure/vpn-configs/ for VPN scripts - Moved 90+ files from root to organized locations - Archived obsolete documentation (context system, offline mode, zombie debugging) - Moved all test files to tests/ directory - Root directory: 119 files -> 18 files Disk Cleanup (10.55 GB recovered): - Deleted Rust build artifacts: 9.6 GB (target/ directories) - Deleted Python virtual environments: 161 MB (venv/ directories) - Deleted Python cache: 50 KB (__pycache__/) New Structure: - docs/ - All documentation organized by category - docs/archives/ - Obsolete but preserved documentation - infrastructure/ - VPN configs and SSH setup - tests/ - All test files consolidated - logs/ - Ready for future logs Benefits: - Cleaner root directory (18 vs 119 files) - Logical organization of documentation - 95.9% disk space reduction - Faster navigation and discovery - Better portability (build artifacts excluded) Build artifacts can be regenerated: - Rust: cargo build --release (5-15 min per project) - Python: pip install -r requirements.txt (2-3 min) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
207
tests/test_models_detailed.py
Normal file
207
tests/test_models_detailed.py
Normal file
@@ -0,0 +1,207 @@
|
||||
"""Detailed structure validation for all SQLAlchemy models."""
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Set UTF-8 encoding for Windows console
|
||||
if os.name == 'nt':
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||
|
||||
import api.models
|
||||
from sqlalchemy.orm import RelationshipProperty
|
||||
from sqlalchemy.schema import ForeignKeyConstraint, CheckConstraint, Index
|
||||
|
||||
|
||||
def get_table_models():
|
||||
"""Get all table model classes (excluding base classes)."""
|
||||
base_classes = {'Base', 'TimestampMixin', 'UUIDMixin'}
|
||||
all_classes = [attr for attr in dir(api.models) if not attr.startswith('_') and attr[0].isupper()]
|
||||
return sorted([m for m in all_classes if m not in base_classes])
|
||||
|
||||
|
||||
def analyze_model(model_name):
|
||||
"""Analyze a model's structure in detail."""
|
||||
model_cls = getattr(api.models, model_name)
|
||||
|
||||
result = {
|
||||
'name': model_name,
|
||||
'table': model_cls.__tablename__,
|
||||
'has_uuid_mixin': False,
|
||||
'has_timestamp_mixin': False,
|
||||
'foreign_keys': [],
|
||||
'relationships': [],
|
||||
'indexes': [],
|
||||
'check_constraints': [],
|
||||
'columns': []
|
||||
}
|
||||
|
||||
# Check mixins
|
||||
for base in model_cls.__mro__:
|
||||
if base.__name__ == 'UUIDMixin':
|
||||
result['has_uuid_mixin'] = True
|
||||
if base.__name__ == 'TimestampMixin':
|
||||
result['has_timestamp_mixin'] = True
|
||||
|
||||
# Get table object
|
||||
if hasattr(model_cls, '__table__'):
|
||||
table = model_cls.__table__
|
||||
|
||||
# Analyze columns
|
||||
for col in table.columns:
|
||||
col_info = {
|
||||
'name': col.name,
|
||||
'type': str(col.type),
|
||||
'nullable': col.nullable,
|
||||
'primary_key': col.primary_key
|
||||
}
|
||||
result['columns'].append(col_info)
|
||||
|
||||
# Analyze foreign keys
|
||||
for fk in table.foreign_keys:
|
||||
result['foreign_keys'].append({
|
||||
'parent_column': fk.parent.name,
|
||||
'target': str(fk.target_fullname)
|
||||
})
|
||||
|
||||
# Analyze indexes
|
||||
if hasattr(table, 'indexes'):
|
||||
for idx in table.indexes:
|
||||
result['indexes'].append({
|
||||
'name': idx.name,
|
||||
'columns': [col.name for col in idx.columns]
|
||||
})
|
||||
|
||||
# Analyze check constraints
|
||||
for constraint in table.constraints:
|
||||
if isinstance(constraint, CheckConstraint):
|
||||
result['check_constraints'].append({
|
||||
'sqltext': str(constraint.sqltext)
|
||||
})
|
||||
|
||||
# Analyze relationships
|
||||
for attr_name in dir(model_cls):
|
||||
try:
|
||||
attr = getattr(model_cls, attr_name)
|
||||
if hasattr(attr, 'property') and isinstance(attr.property, RelationshipProperty):
|
||||
rel = attr.property
|
||||
result['relationships'].append({
|
||||
'name': attr_name,
|
||||
'target': rel.mapper.class_.__name__,
|
||||
'uselist': rel.uselist
|
||||
})
|
||||
except (AttributeError, TypeError):
|
||||
continue
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def print_model_summary(result):
|
||||
"""Print a formatted summary of model structure."""
|
||||
print(f"\n{'='*70}")
|
||||
print(f"Model: {result['name']} (table: {result['table']})")
|
||||
print(f"{'='*70}")
|
||||
|
||||
# Mixins
|
||||
mixins = []
|
||||
if result['has_uuid_mixin']:
|
||||
mixins.append('UUIDMixin')
|
||||
if result['has_timestamp_mixin']:
|
||||
mixins.append('TimestampMixin')
|
||||
if mixins:
|
||||
print(f"Mixins: {', '.join(mixins)}")
|
||||
|
||||
# Columns
|
||||
print(f"\nColumns ({len(result['columns'])}):")
|
||||
for col in result['columns'][:10]: # Limit to first 10 for readability
|
||||
pk = " [PK]" if col['primary_key'] else ""
|
||||
nullable = "NULL" if col['nullable'] else "NOT NULL"
|
||||
print(f" - {col['name']}: {col['type']} {nullable}{pk}")
|
||||
if len(result['columns']) > 10:
|
||||
print(f" ... and {len(result['columns']) - 10} more columns")
|
||||
|
||||
# Foreign Keys
|
||||
if result['foreign_keys']:
|
||||
print(f"\nForeign Keys ({len(result['foreign_keys'])}):")
|
||||
for fk in result['foreign_keys']:
|
||||
print(f" - {fk['parent_column']} -> {fk['target']}")
|
||||
|
||||
# Relationships
|
||||
if result['relationships']:
|
||||
print(f"\nRelationships ({len(result['relationships'])}):")
|
||||
for rel in result['relationships']:
|
||||
rel_type = "many" if rel['uselist'] else "one"
|
||||
print(f" - {rel['name']} -> {rel['target']} ({rel_type})")
|
||||
|
||||
# Indexes
|
||||
if result['indexes']:
|
||||
print(f"\nIndexes ({len(result['indexes'])}):")
|
||||
for idx in result['indexes']:
|
||||
cols = ', '.join(idx['columns'])
|
||||
print(f" - {idx['name']}: ({cols})")
|
||||
|
||||
# Check Constraints
|
||||
if result['check_constraints']:
|
||||
print(f"\nCheck Constraints ({len(result['check_constraints'])}):")
|
||||
for check in result['check_constraints']:
|
||||
print(f" - {check['sqltext']}")
|
||||
|
||||
|
||||
def main():
|
||||
print("="*70)
|
||||
print("ClaudeTools - Detailed Model Structure Analysis")
|
||||
print("="*70)
|
||||
|
||||
models = get_table_models()
|
||||
print(f"\nAnalyzing {len(models)} table models...\n")
|
||||
|
||||
all_results = []
|
||||
for model_name in models:
|
||||
try:
|
||||
result = analyze_model(model_name)
|
||||
all_results.append(result)
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Error analyzing {model_name}: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
# Print summary statistics
|
||||
print("\n" + "="*70)
|
||||
print("SUMMARY STATISTICS")
|
||||
print("="*70)
|
||||
|
||||
total_models = len(all_results)
|
||||
models_with_uuid = sum(1 for r in all_results if r['has_uuid_mixin'])
|
||||
models_with_timestamp = sum(1 for r in all_results if r['has_timestamp_mixin'])
|
||||
models_with_fk = sum(1 for r in all_results if r['foreign_keys'])
|
||||
models_with_rel = sum(1 for r in all_results if r['relationships'])
|
||||
models_with_idx = sum(1 for r in all_results if r['indexes'])
|
||||
models_with_checks = sum(1 for r in all_results if r['check_constraints'])
|
||||
|
||||
total_fk = sum(len(r['foreign_keys']) for r in all_results)
|
||||
total_rel = sum(len(r['relationships']) for r in all_results)
|
||||
total_idx = sum(len(r['indexes']) for r in all_results)
|
||||
total_checks = sum(len(r['check_constraints']) for r in all_results)
|
||||
|
||||
print(f"\nTotal Models: {total_models}")
|
||||
print(f" - With UUIDMixin: {models_with_uuid}")
|
||||
print(f" - With TimestampMixin: {models_with_timestamp}")
|
||||
print(f" - With Foreign Keys: {models_with_fk} (total: {total_fk})")
|
||||
print(f" - With Relationships: {models_with_rel} (total: {total_rel})")
|
||||
print(f" - With Indexes: {models_with_idx} (total: {total_idx})")
|
||||
print(f" - With CHECK Constraints: {models_with_checks} (total: {total_checks})")
|
||||
|
||||
# Print detailed info for each model
|
||||
print("\n" + "="*70)
|
||||
print("DETAILED MODEL INFORMATION")
|
||||
print("="*70)
|
||||
|
||||
for result in all_results:
|
||||
print_model_summary(result)
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("[SUCCESS] Analysis complete!")
|
||||
print("="*70)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user