134 lines
4.4 KiB
Python
134 lines
4.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Add missing aliases to refactored slot files.
|
|
|
|
For files like:
|
|
- has_X.yaml -> add alias "has_or_had_X"
|
|
- X.yaml (non-has_) -> add alias "is_or_was_X"
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
import yaml
|
|
from pathlib import Path
|
|
|
|
SLOTS_DIR = Path("/Users/kempersc/apps/glam/schemas/20251121/linkml/modules/slots/20260202_matang")
|
|
|
|
def add_alias_to_file(filepath: Path, old_name: str) -> bool:
|
|
"""Add old_name as an alias to the slot file if not already present."""
|
|
with open(filepath, 'r') as f:
|
|
content = f.read()
|
|
|
|
# Check if alias already exists
|
|
if old_name in content:
|
|
return False
|
|
|
|
# Parse YAML
|
|
try:
|
|
data = yaml.safe_load(content)
|
|
except Exception as e:
|
|
print(f"ERROR parsing {filepath}: {e}")
|
|
return False
|
|
|
|
if not data or 'slots' not in data:
|
|
print(f"SKIP (no slots): {filepath}")
|
|
return False
|
|
|
|
# Get the slot name (first key in slots)
|
|
slot_name = list(data['slots'].keys())[0]
|
|
slot_data = data['slots'][slot_name]
|
|
|
|
# Add or update aliases
|
|
if 'aliases' not in slot_data:
|
|
slot_data['aliases'] = []
|
|
|
|
if old_name not in slot_data['aliases']:
|
|
slot_data['aliases'].append(old_name)
|
|
|
|
# Write back
|
|
# Preserve comments by using regex replacement instead of full rewrite
|
|
if 'aliases:' in content:
|
|
# Find aliases section and add to it
|
|
pattern = r'(aliases:\s*\n)((?:\s*-\s*[^\n]+\n)*)'
|
|
def add_alias(match):
|
|
aliases_header = match.group(1)
|
|
existing_aliases = match.group(2)
|
|
indent = ' ' # Standard indent for aliases
|
|
return f"{aliases_header}{existing_aliases}{indent}- {old_name}\n"
|
|
|
|
new_content = re.sub(pattern, add_alias, content)
|
|
else:
|
|
# Add aliases section after range or description
|
|
# Find a good insertion point - after 'range:' line or before 'annotations:'
|
|
lines = content.split('\n')
|
|
new_lines = []
|
|
inserted = False
|
|
|
|
for i, line in enumerate(lines):
|
|
new_lines.append(line)
|
|
# Insert after range, multivalued, or slot_uri lines at the slot level
|
|
if not inserted and re.match(r'\s{4}(range|multivalued|slot_uri):', line):
|
|
# Check next lines to find the right spot
|
|
# Insert aliases after the last property before annotations/examples/comments
|
|
next_line = lines[i+1] if i+1 < len(lines) else ''
|
|
if not re.match(r'\s{4}(range|multivalued|slot_uri|description):', next_line):
|
|
new_lines.append(' aliases:')
|
|
new_lines.append(f' - {old_name}')
|
|
inserted = True
|
|
|
|
if not inserted:
|
|
# Fallback: insert before annotations if present
|
|
new_lines = []
|
|
for line in lines:
|
|
if 'annotations:' in line and not inserted:
|
|
new_lines.append(' aliases:')
|
|
new_lines.append(f' - {old_name}')
|
|
inserted = True
|
|
new_lines.append(line)
|
|
|
|
new_content = '\n'.join(new_lines)
|
|
|
|
with open(filepath, 'w') as f:
|
|
f.write(new_content)
|
|
|
|
return True
|
|
|
|
def process_slots():
|
|
"""Process all slot files and add missing aliases."""
|
|
updated = 0
|
|
skipped = 0
|
|
|
|
for filepath in SLOTS_DIR.glob('*.yaml'):
|
|
name = filepath.stem
|
|
|
|
# Determine the old name based on current name
|
|
if name.startswith('has_'):
|
|
# has_X -> has_or_had_X
|
|
old_name = 'has_or_had_' + name[4:]
|
|
elif name.startswith('contains_'):
|
|
# contains_X -> contains_or_contained_X
|
|
old_name = 'contains_or_contained_' + name[9:]
|
|
else:
|
|
# X -> is_or_was_X
|
|
old_name = 'is_or_was_' + name
|
|
|
|
# Check if alias already exists in file
|
|
with open(filepath, 'r') as f:
|
|
content = f.read()
|
|
|
|
if old_name in content:
|
|
skipped += 1
|
|
continue
|
|
|
|
# Add alias
|
|
if add_alias_to_file(filepath, old_name):
|
|
print(f"UPDATED: {name} -> added alias '{old_name}'")
|
|
updated += 1
|
|
else:
|
|
skipped += 1
|
|
|
|
print(f"\nSummary: Updated {updated}, Skipped {skipped}")
|
|
return updated, skipped
|
|
|
|
if __name__ == '__main__':
|
|
process_slots()
|