From 413d038e9a9ee4dd693bb0c54aa6e0f49fc89be2 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Thu, 5 Feb 2026 08:45:43 +0000 Subject: [PATCH] Add utils, templates, config, interactive, and github modules --- src/auto_readme/config/__init__.py | 183 +++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 src/auto_readme/config/__init__.py diff --git a/src/auto_readme/config/__init__.py b/src/auto_readme/config/__init__.py new file mode 100644 index 0000000..17d92d8 --- /dev/null +++ b/src/auto_readme/config/__init__.py @@ -0,0 +1,183 @@ +"""Configuration file support for the Auto README Generator.""" + +from dataclasses import dataclass, field +from pathlib import Path +from typing import Optional +import yaml +import sys + +if sys.version_info >= (3, 11): + import tomllib +else: + try: + import tomli as tomllib + except ImportError: + tomllib = None + + +@dataclass +class ReadmeConfig: + """Configuration for README generation.""" + + project_name: Optional[str] = None + description: Optional[str] = None + template: str = "base" + interactive: bool = False + sections: dict = field(default_factory=dict) + output_filename: str = "README.md" + custom_fields: dict = field(default_factory=dict) + + +class ConfigLoader: + """Loads and validates configuration files.""" + + CONFIG_FILES = [".readmerc", ".readmerc.yaml", ".readmerc.yml", "readme.config.yaml"] + + @classmethod + def find_config(cls, directory: Path) -> Optional[Path]: + """Find a configuration file in the directory.""" + for config_name in cls.CONFIG_FILES: + config_path = directory / config_name + if config_path.exists(): + return config_path + return None + + @classmethod + def load(cls, path: Path) -> ReadmeConfig: + """Load configuration from a file.""" + if not path.exists(): + return ReadmeConfig() + + config = ReadmeConfig() + + if path.suffix in (".yaml", ".yml"): + config = cls._load_yaml(path, config) + elif path.suffix == ".toml": + config = cls._load_toml(path, config) + + return config + + @classmethod + def _load_yaml(cls, path: Path, config: ReadmeConfig) -> ReadmeConfig: + """Load configuration from YAML file.""" + try: + with open(path, "r", encoding="utf-8") as f: + data = yaml.safe_load(f) or {} + except yaml.YAMLError as e: + raise ValueError(f"Invalid YAML in config file: {e}") + + if not isinstance(data, dict): + raise ValueError("Config file must contain a dictionary") + + if "project_name" in data: + config.project_name = data["project_name"] + if "description" in data: + config.description = data["description"] + if "template" in data: + config.template = data["template"] + if "interactive" in data: + config.interactive = data["interactive"] + if "filename" in data: + config.output_filename = data["filename"] + if "sections" in data: + config.sections = data["sections"] + if "custom_fields" in data: + config.custom_fields = data["custom_fields"] + + return config + + @classmethod + def _load_toml(cls, path: Path, config: ReadmeConfig) -> ReadmeConfig: + """Load configuration from TOML file.""" + if tomllib is None: + raise ValueError("TOML support requires Python 3.11+ or tomli package") + try: + with open(path, "rb") as f: + data = tomllib.load(f) + except Exception as e: + raise ValueError(f"Invalid TOML in config file: {e}") + + if "auto-readme" in data: + auto_readme = data["auto-readme"] + if "filename" in auto_readme: + config.output_filename = auto_readme["filename"] + if "sections" in auto_readme: + config.sections = auto_readme["sections"] + + return config + + +class ConfigValidator: + """Validates configuration files.""" + + VALID_TEMPLATES = ["base", "minimal", "detailed"] + VALID_SECTIONS = [ + "title", + "description", + "badges", + "table_of_contents", + "overview", + "installation", + "usage", + "features", + "api", + "contributing", + "license", + ] + + @classmethod + def validate(cls, config: ReadmeConfig) -> list[str]: + """Validate a configuration and return any errors.""" + errors = [] + + if config.template and config.template not in cls.VALID_TEMPLATES: + errors.append(f"Invalid template: {config.template}. Valid options: {cls.VALID_TEMPLATES}") + + if config.sections: + if "order" in config.sections: + for section in config.sections["order"]: + if section not in cls.VALID_SECTIONS: + errors.append(f"Invalid section in order: {section}") + + return errors + + @classmethod + def generate_template(cls) -> str: + """Generate a template configuration file.""" + template = """# Auto README Configuration File +# https://github.com/yourusername/yourrepo + +# Project metadata +project_name: "My Project" +description: "A brief description of your project" + +# Template to use +template: "base" + +# Interactive mode +interactive: false + +# Output filename +filename: "README.md" + +# Section configuration +sections: + order: + - title + - description + - overview + - installation + - usage + - features + - api + - contributing + - license + optional: + Contributing: false + +# Custom fields to include +custom_fields: + author: "Your Name" + email: "your.email@example.com" +""" + return template