"""Module representation in the doc-forge documentation model. Module represents a Python module that can be documented. It serves as a container for all the documentation objects within that module, including classes, functions, attributes, and constants. Each Module corresponds to a Python import path and contains the module-level docstring along with all documented members. """ from __future__ import annotations from typing import Dict, List, Optional from .object import DocObject class Module: """Represents a Python module in the documentation model. A Module is the primary organizational unit in doc-forge. It corresponds to a Python module (identified by its import path) and contains all the documentation objects within that module. Attributes: path: The import path of the module (e.g., "package.submodule") docstring: Optional module-level docstring members: Dictionary of all documented objects in the module """ def __init__(self, path: str, docstring: Optional[str] = None) -> None: """Initialize a Module. Args: path: The import path of the module docstring: Optional module-level docstring Raises: ValueError: If path is empty """ if not path: raise ValueError("Module path cannot be empty") self.path: str = path self.docstring: Optional[str] = docstring self.members: Dict[str, DocObject] = {} def add_object(self, obj: DocObject) -> None: """Add a documentation object to this module. Args: obj: The documentation object to add Raises: ValueError: If object name conflicts with existing object """ if obj.name in self.members: raise ValueError(f"Object '{obj.name}' already exists in module '{self.path}'") self.members[obj.name] = obj def get_object(self, name: str) -> Optional[DocObject]: """Get a documentation object by name. Args: name: The name of the object to retrieve Returns: The DocObject if found, None otherwise """ return self.members.get(name) def get_public_objects(self) -> List[DocObject]: """Get all public (non-private) documentation objects. Returns: List of DocObjects that are not private """ return [obj for obj in self.members.values() if not obj.is_private()] def get_objects_by_kind(self, kind: str) -> List[DocObject]: """Get all documentation objects of a specific kind. Args: kind: The kind of objects to retrieve (e.g., "class", "function") Returns: List of DocObjects matching the specified kind """ return [obj for obj in self.members.values() if obj.kind == kind] def get_classes(self) -> List[DocObject]: """Get all class objects in this module. Returns: List of DocObjects with kind "class" """ return self.get_objects_by_kind("class") def get_functions(self) -> List[DocObject]: """Get all function objects in this module. Returns: List of DocObjects with kind "function" """ return self.get_objects_by_kind("function") def has_docstring(self) -> bool: """Check if this module has a docstring. Returns: True if docstring is not None and not empty, False otherwise """ return bool(self.docstring and self.docstring.strip()) def is_empty(self) -> bool: """Check if this module contains any documented objects. Returns: True if the module has no members, False otherwise """ return len(self.members) == 0 def __repr__(self) -> str: """Return a string representation of the Module. Returns: String representation showing path and member count """ return f"Module(path='{self.path}', members={len(self.members)})"