merge: рабочий генератор из rewrite + тест пройден

This commit is contained in:
2026-07-31 00:35:52 +04:00
commit 66753f6607
16 changed files with 3514 additions and 0 deletions
+199
View File
@@ -0,0 +1,199 @@
#!/usr/bin/env python3
"""DokoGen — test: verify generator with nested loops"""
import sys, os, json, tempfile, zipfile, shutil, re
from datetime import datetime
# Add to path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from dokogen.models import Company, CommissionMember, InformationSystem
from dokogen.variables import build_replacements
from dokogen.generator import process_template, expand_loops_in_zip
def create_test_template():
"""Creates a test .docx with nested loops for verification."""
from docx import Document
from docx.shared import Pt
doc = Document()
# Title
doc.add_heading('Test Document with Nested Loops', 0)
# Simple variable
doc.add_paragraph('Company: {{company_full_name}}')
doc.add_paragraph('Date: {{date}}')
doc.add_paragraph('')
# Outer loop: information_systems
doc.add_paragraph('<!-- loop:information_systems -->')
doc.add_paragraph('=== IS: {{item.name}} ===')
doc.add_paragraph('Category: {{item.category}}')
doc.add_paragraph('Threat type: {{item.threat_type}}')
doc.add_paragraph('Defence level: {{item.defence_level}}')
doc.add_paragraph('')
# Inner loop: commission
doc.add_paragraph('Commission members:')
doc.add_paragraph('<!-- loop:commission -->')
doc.add_paragraph(' - {{item.role}}: {{item.position}} {{item.fio}}')
doc.add_paragraph('<!-- loop_end -->')
doc.add_paragraph('')
doc.add_paragraph('--- end of IS ---')
doc.add_paragraph('')
doc.add_paragraph('<!-- loop_end -->')
doc.add_paragraph('')
doc.add_paragraph('Footer: Generated automatically')
path = '/tmp/test_template_nested.docx'
doc.save(path)
print(f'✅ Test template created: {path}')
return path
def test_zip_loop_expansion():
"""Test ZIP-level loop expansion with mock data."""
print('\n' + '='*60)
print('TEST: ZIP-level loop expansion')
print('='*60)
# Create test data
company = Company(
full_name='ООО "Ромашка"',
short_name='Ромашка',
inn='7701234567',
chief_fio='Иванов Иван Иванович',
chief_position='Генеральный директор',
commission=[
CommissionMember(role='Председатель', position='Директор', fio='Иванов И.И.'),
CommissionMember(role='Секретарь', position='Секретарь', fio='Петров П.П.'),
CommissionMember(role='Член комиссии', position='Бухгалтер', fio='Сидорова А.А.'),
],
information_systems=[
InformationSystem(name='ИС-1 "Бухгалтерия"', category='специальные',
pd_count='менее 100 000', threat_type='1', defence_level='2'),
InformationSystem(name='ИС-2 "Кадры"', category='иные',
pd_count='более 100 000', threat_type='3', defence_level='4'),
InformationSystem(name='ИС-3 "Склад"', category='общедоступные',
pd_count='менее 100 000', threat_type='2', defence_level='3'),
]
)
# Build replacements
replacements = build_replacements(
company=company,
is_list=company.information_systems,
doc_number='001',
doc_date='31.07.2026',
direction='152fz'
)
loops = replacements.get('_loops', {})
print(f'\nLoops found: {list(loops.keys())}')
print(f'IS items: {len(loops.get("information_systems", []))}')
print(f'Commission items: {len(loops.get("commission", []))}')
# Create test template
template_path = create_test_template()
# Verify template has markers
with zipfile.ZipFile(template_path, 'r') as z:
doc_xml = z.read('word/document.xml').decode('utf-8')
start_count = doc_xml.count('loop:')
end_count = doc_xml.count('loop_end')
print(f'\nMarkers in template: {start_count} starts, {end_count} ends')
# Process with ZIP-level loop expansion
print('\nProcessing loops via ZIP...')
result_path = expand_loops_in_zip(template_path, loops)
# Verify result
with zipfile.ZipFile(result_path, 'r') as z:
result_xml = z.read('word/document.xml').decode('utf-8')
remaining_starts = len(re.findall(r'loop:(\w+)', result_xml))
remaining_ends = result_xml.count('loop_end')
print(f'Markers after expansion: {remaining_starts} starts, {remaining_ends} ends')
if remaining_starts == 0 and remaining_ends == 0:
print('✅ ALL LOOPS EXPANDED SUCCESSFULLY')
else:
print(f'⚠️ {remaining_starts} loop markers remaining')
# Now test full process_template
print('\n' + '='*60)
print('TEST: Full process_template with all replacements')
print('='*60)
# Rebuild replacements (they were consumed)
replacements2 = build_replacements(
company=company,
is_list=company.information_systems,
doc_number='001',
doc_date='31.07.2026',
direction='152fz'
)
try:
output_path = process_template(
template_path=template_path,
replacements=replacements2,
output_path='/tmp/test_output.docx',
log_func=print
)
print(f'\n✅ Output generated: {output_path}')
# Verify output
with zipfile.ZipFile(output_path, 'r') as z:
out_xml = z.read('word/document.xml').decode('utf-8')
# Check no remaining variables
remaining_vars = re.findall(r'\{\{[^}]+\}\}', out_xml)
remaining_old = re.findall(r'<[A-Za-z_]+>', out_xml)
if remaining_vars:
print(f'⚠️ Remaining {{...}} vars: {remaining_vars[:5]}')
else:
print('✅ No remaining {{...}} variables')
if remaining_old:
print(f'⚠️ Remaining <...> vars: {remaining_old[:5]}')
else:
print('✅ No remaining <...> variables')
# Check IS names appear
for isys in company.information_systems:
if isys.name in out_xml:
print(f'✅ Found IS name: {isys.name}')
else:
print(f'⚠️ MISSING IS name: {isys.name}')
# Check commission members appear
for m in company.commission:
if m.fio in out_xml:
print(f'✅ Found commission: {m.fio}')
else:
print(f'⚠️ MISSING commission: {m.fio}')
except Exception as e:
print(f'❌ Error: {e}')
import traceback
traceback.print_exc()
# Cleanup
os.unlink(template_path)
if os.path.exists(result_path):
os.unlink(result_path)
if os.path.exists('/tmp/test_output.docx'):
os.unlink('/tmp/test_output.docx')
print('\n' + '='*60)
print('TEST COMPLETE')
print('='*60)
if __name__ == '__main__':
test_zip_loop_expansion()