Loading...
No commits yet
Not committed History
Blame
_verify_tree_structure.py • 4.1 KB
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File: src/scitex_writer/_utils/_verify_tree_structure.py

"""Project structure validation for writer module.

Leverages dataclass verify_structure() methods for validation."""

from __future__ import annotations

from logging import getLogger
from pathlib import Path

from .._dataclasses import (
    ConfigTree,
    ManuscriptTree,
    RevisionTree,
    ScriptsTree,
    SharedTree,
    SupplementaryTree,
)

logger = getLogger(__name__)

# Parameters
TREE_VALIDATORS = {
    "config": {"dir_name": "config", "tree_class": ConfigTree},
    "00_shared": {"dir_name": "00_shared", "tree_class": SharedTree},
    "01_manuscript": {
        "dir_name": "01_manuscript",
        "tree_class": ManuscriptTree,
    },
    "02_supplementary": {
        "dir_name": "02_supplementary",
        "tree_class": SupplementaryTree,
    },
    "03_revision": {"dir_name": "03_revision", "tree_class": RevisionTree},
    "scripts": {"dir_name": "scripts", "tree_class": ScriptsTree},
}


# Exception classes
class ProjectValidationError(Exception):
    """Raised when project structure is invalid."""

    pass


# 2. Public validation functions
def verify_tree_structure(
    project_dir: Path, func_name="validate_tree_structures"
) -> None:
    """Validates all tree structures in the project directory."""
    logger.info(
        f"{func_name}: Validating tree structures: {Path(project_dir).absolute()}..."
    )
    project_dir = Path(project_dir)
    for dir_name in TREE_VALIDATORS.keys():
        validator_func_name = f"_validate_{dir_name}_structure"
        eval(validator_func_name)(project_dir)
    logger.info(
        f"{func_name}: Validated tree structures: {Path(project_dir).absolute()}"
    )
    return True


# 3. Internal validation functions
def _validate_01_manuscript_structure(project_dir: Path) -> bool:
    """Validates manuscript structure."""
    return _validate_tree_structure_base(
        project_dir, **TREE_VALIDATORS["01_manuscript"]
    )


def _validate_02_supplementary_structure(project_dir: Path) -> bool:
    """Validates supplementary structure."""
    return _validate_tree_structure_base(
        project_dir, **TREE_VALIDATORS["02_supplementary"]
    )


def _validate_03_revision_structure(project_dir: Path) -> bool:
    """Validates revision structure."""
    return _validate_tree_structure_base(project_dir, **TREE_VALIDATORS["03_revision"])


def _validate_config_structure(project_dir: Path) -> bool:
    """Validates config structure."""
    return _validate_tree_structure_base(project_dir, **TREE_VALIDATORS["config"])


def _validate_scripts_structure(project_dir: Path) -> bool:
    """Validates scripts structure."""
    return _validate_tree_structure_base(project_dir, **TREE_VALIDATORS["scripts"])


def _validate_00_shared_structure(project_dir: Path) -> bool:
    """Validates shared structure."""
    return _validate_tree_structure_base(project_dir, **TREE_VALIDATORS["00_shared"])


# 4. Helper functions
def _validate_tree_structure_base(
    project_dir: Path, dir_name: str, tree_class: type = None
) -> bool:
    """Base validation function that checks directory existence and verifies structure using tree class.

    Args:
        project_dir: Root project directory
        dir_name: Name of directory to validate
        tree_class: Tree class with verify_structure method

    Returns
    -------
        True if structure is valid

    Raises
    ------
        ProjectValidationError: If directory missing or structure invalid
    """
    project_dir = Path(project_dir)
    target_dir = project_dir / dir_name
    if not target_dir.exists():
        raise ProjectValidationError(f"Required directory missing: {target_dir}")
    if tree_class is not None:
        doc = tree_class(target_dir, git_root=project_dir)
        is_valid, issues = doc.verify_structure()
        if not is_valid:
            raise ProjectValidationError(
                f"{dir_name} structure invalid:\n"
                + "\n".join(f"  - {issue}" for issue in issues)
            )
    logger.debug(f"{dir_name} structure valid: {project_dir}")
    return True


__all__ = ["verify_tree_structure", "ProjectValidationError"]

# EOF