Files
claudetools/test_models_detailed.py
Mike Swanson fce1345a40 [Fix] Remove all emoji violations from code files
- Replaced emojis with ASCII text markers ([OK], [ERROR], [WARNING], etc.)
- Fixed 38+ violations across 20 files (7 Python, 6 shell scripts, 6 hooks, 1 API)
- All modified files pass syntax verification
- Conforms to CODING_GUIDELINES.md NO EMOJIS rule

Details:
- Python test files: check_record_counts.py, test_*.py (31 fixes)
- API utils: context_compression.py regex pattern updated
- Shell scripts: setup/test/install/upgrade scripts (64+ fixes)
- Hook scripts: task-complete, user-prompt-submit, sync-contexts (10 fixes)

Verification: All files pass syntax checks (python -m py_compile, bash -n)
Report: FIXES_APPLIED.md contains complete change log

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-17 13:06:33 -07:00

208 lines
6.9 KiB
Python

"""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()