"""Check syntax, imported local modules, file types and public package hashes.""" import ast import hashlib import importlib.util import json from pathlib import Path root = Path(__file__).resolve().parents[1] allowed = {'.py', '.sh', '.json', '.md', '.yaml', '.yml', '.txt', '.cff', '.sha256'} files = [p for p in root.rglob('*') if p.is_file() and '__pycache__' not in p.parts] modules = {} for path in (root / 'src').rglob('*.py'): parts = list(path.relative_to(root / 'src').with_suffix('').parts) if parts[-1] == '__init__': parts.pop() modules['.'.join(parts)] = path errors = [] for path in files: rel = path.relative_to(root).as_posix() if path.is_symlink() or path.suffix not in allowed or path.stat().st_size > 2 * 1024 * 1024: errors.append(f'Unexpected file: {rel}') continue text = path.read_text(encoding='utf-8') if path.suffix == '.py': ast.parse(text, filename=rel) if path.suffix == '.json': json.loads(text) for module, path in modules.items(): package = module if path.name == '__init__.py' else module.rpartition('.')[0] for node in ast.walk(ast.parse(path.read_text())): targets = [] if isinstance(node, ast.Import): targets = [alias.name for alias in node.names] elif isinstance(node, ast.ImportFrom): targets = [importlib.util.resolve_name('.' * node.level + (node.module or ''), package) if node.level else node.module or ''] for target in targets: if target.startswith('llamafactory') and target not in modules: errors.append(f'Missing local import: {module} -> {target}') manifest = root / 'MANIFEST.sha256' expected_paths = set() for line in manifest.read_text().splitlines(): digest, relative = line.split(' ', 1) expected_paths.add(relative) path = root / relative if not path.is_file() or hashlib.sha256(path.read_bytes()).hexdigest() != digest: errors.append(f'Checksum mismatch: {relative}') if expected_paths != {p.relative_to(root).as_posix() for p in files if p != manifest}: errors.append('Checksum manifest and package file set differ') if errors: raise SystemExit('\n'.join(errors)) print(f'Passed: {len(files)} package files, {len(modules)} source modules, syntax, imports and hashes.')