diff --git a/.auxiliary/notes/todo.md b/.auxiliary/notes/todo.md new file mode 100644 index 0000000..f6adfed --- /dev/null +++ b/.auxiliary/notes/todo.md @@ -0,0 +1,10 @@ +# Development TODOs + +## Verification Tasks + +- [ ] **Verify pickle/copy support**: Test and verify that all immutable types properly support Python's pickle protocol and copy module operations. Update documentation and requirements once verified. + - Test pickling of Dictionary, ValidatorDictionary, Namespace + - Test pickling of classes created with metaclasses + - Test pickling of classes created with decorators + - Test copy.copy() and copy.deepcopy() operations + - Document any limitations or special considerations diff --git a/documentation/architecture/filesystem.rst b/documentation/architecture/filesystem.rst index 4b3f4c8..494faab 100644 --- a/documentation/architecture/filesystem.rst +++ b/documentation/architecture/filesystem.rst @@ -57,23 +57,171 @@ The main Python package follows the standard ``sources/`` directory pattern: .. code-block:: sources/ - ├── frigid/ # Main Python package - │ ├── __/ # Centralized import hub - │ │ ├── __init__.py # Re-exports core utilities - │ │ ├── imports.py # External library imports - │ │ └── nomina.py # python-frigid-specific naming constants - │ ├── __init__.py # Package entry point - │ ├── py.typed # Type checking marker - │ ├── exceptions.py # Package exception hierarchy - │ └── [modules].py # Feature-specific modules - + └── frigid/ # Main Python package + ├── __/ # Centralized import hub (internal) + │ ├── __init__.py # Re-exports core utilities + │ ├── imports.py # External library imports + │ ├── dictionaries.py # ImmutableDictionary implementation + │ ├── doctab.py # Documentation fragments table + │ ├── exceptions.py # Internal exception classes + │ └── nomina.py # Type aliases and naming utilities + ├── __init__.py # Package entry point (public API) + ├── py.typed # Type checking marker for mypy/pyright + ├── classes.py # Metaclasses and decorators for immutable classes + ├── dictionaries.py # Public immutable dictionary types + ├── exceptions.py # Public exception hierarchy + ├── installers.py # Utilities for installing into builtins + ├── modules.py # Immutable module types + ├── namespaces.py # Immutable namespace objects + └── sequences.py # Immutable sequence utilities All package modules use the standard ``__`` import pattern as documented in the common architecture guide. +Module Purposes +------------------------------------------------------------------------------- + +**Public API Modules** (directly under ``sources/frigid/``): + +``__init__.py`` + Package entry point that re-exports the public API. Imports and exposes: + + * Core classes (Dictionary, ValidatorDictionary, Namespace, Object, etc.) + * Metaclasses (Class, Dataclass, AbstractBaseClass, Protocol variants) + * Decorators (with_standard_behaviors, dataclass_with_standard_behaviors) + * Exception classes (AttributeImmutability, EntryImmutability, etc.) + * Utility functions (one, finalize_module) + +``classes.py`` + Metaclasses and decorators for creating immutable classes: + + * Metaclasses: Class, Dataclass, DataclassMutable, AbstractBaseClass, + ProtocolClass, ProtocolDataclass, ProtocolDataclassMutable + * Base classes: Object, ObjectMutable, DataclassObject, + DataclassObjectMutable, Protocol variants + * Decorators: with_standard_behaviors, dataclass_with_standard_behaviors + * All delegate to classcore.standard.class_factory with frigid configuration + +``dictionaries.py`` + Immutable dictionary implementations: + + * AbstractDictionary: Base class defining immutable dictionary interface + * Dictionary: Standard immutable dictionary (wraps ImmutableDictionary) + * ValidatorDictionary: Dictionary with validation on initialization + * Supports set operations (union ``|``, intersection ``&``) + +``exceptions.py`` + Public exception hierarchy: + + * Omniexception: Base exception for all frigid exceptions + * Omnierror: Base error (inherits from Omniexception) + * AttributeImmutability: Raised when modifying immutable attributes + * EntryImmutability: Raised when modifying immutable dictionary entries + * EntryInvalidity: Raised when dictionary validation fails + +``installers.py`` + Utilities for installing frigid functions into Python builtins: + + * install_into_builtins(): Adds frigid utilities to builtins module + * Opt-in mechanism for making frigid functions globally available + +``modules.py`` + Immutable module types and utilities: + + * Module: Immutable module class (extends types.ModuleType) + * finalize_module(): Combines dynadoc generation with module reclassification + * Prevents modification of module-level constants after finalization + +``namespaces.py`` + Immutable namespace objects: + + * Namespace: Similar to types.SimpleNamespace but immutable + * Initialization from iterables, mappings, and keyword arguments + * Uses ImmutableDictionary for __dict__ storage + +``sequences.py`` + Immutable sequence utilities: + + * one(): Creates single-item tuple more readably than ``(x,)`` syntax + * Minimal module focused on ergonomic tuple creation + +**Internal Implementation** (under ``sources/frigid/__/``): + +``__init__.py`` + Re-exports commonly used imports for internal use: + + * All imports from imports.py + * All type aliases from nomina.py + * Makes ``from . import __`` work consistently + +``imports.py`` + Centralized external library imports: + + * Standard library: abc, collections.abc, dataclasses, functools, types + * Third-party: classcore, dynadoc, absence, typing_extensions + * Provides consistent namespace for all frigid modules + * Reduces import duplication and eases dependency management + +``dictionaries.py`` + Core immutable dictionary implementation: + + * ImmutableDictionary: Subclasses dict with immutability enforcement + * Uses _behaviors_ set to track immutability state + * Allows modifications during __init__, blocks after initialization + * Foundation for all dictionary-based immutable structures + +``doctab.py`` + Documentation fragments for dynamic documentation: + + * Reusable documentation strings for classes and behaviors + * Used by dynadoc to generate comprehensive docstrings + * Organized by topic (classes, modules, behaviors, etc.) + +``exceptions.py`` + Internal exception classes: + + * EntryImmutability: Internal version for dictionary operations + * OperationInvalidity: Raised for invalid operations on immutable collections + * Used by implementation layer before being re-raised as public exceptions + +``nomina.py`` + Type aliases, type variables, and naming utilities: + + * Type variables: H (hashable), V (value), etc. + * Type aliases for common signatures + * calculate_attrname(): Generates package-specific attribute names + * Provides consistent naming across the package + Component Integration =============================================================================== +Import Pattern Implementation +------------------------------------------------------------------------------- + +All public modules follow the centralized import pattern: + +.. code-block:: python + + # In any public module (e.g., dictionaries.py, namespaces.py) + from . import __ + + # Usage throughout the module + class Dictionary( __.cabc.Mapping[ __.H, __.V ] ): + ''' Immutable dictionary implementation. ''' + def __init__( self, *args: __.typx.Any, **kwargs: __.typx.Any ): + self._data_ = __.ImmutableDictionary( *args, **kwargs ) + +This pattern provides: + +* Consistent access to external dependencies (classcore, dynadoc, absence) +* Type aliases (cabc for collections.abc, typx for typing extensions) +* Internal utilities (ImmutableDictionary, calculate_attrname) +* Reduced per-module import overhead + +The ``__`` package acts as a single source of truth for all dependencies, +making it easy to update dependencies or add new ones without modifying +individual modules. + Exception Organization ------------------------------------------------------------------------------- @@ -81,6 +229,176 @@ Package-wide exceptions are centralized in ``sources/frigid/exceptions.py`` following the standard hierarchy patterns documented in the `common practices guide `_. +The exception hierarchy follows this structure: + +.. code-block:: + + Omniexception (base for all frigid exceptions) + └── Omnierror (base for error conditions) + ├── AttributeImmutability (attribute modification violations) + ├── EntryImmutability (dictionary entry modification violations) + └── EntryInvalidity (validation failures) + +Each exception class inherits from both the frigid base and an appropriate +Python built-in exception: + +* ``AttributeImmutability`` → ``Omnierror`` + ``AttributeError`` +* ``EntryImmutability`` → ``Omnierror`` + ``TypeError`` +* ``EntryInvalidity`` → ``Omnierror`` + ``ValueError`` + +This dual inheritance ensures exceptions are catchable both through frigid's +hierarchy and through standard Python exception types. + +Documentation Integration +------------------------------------------------------------------------------- + +The package uses dynadoc for dynamic documentation generation: + +**Documentation Fragments** (``sources/frigid/__/doctab.py``): + +* Centralized table of reusable documentation strings +* Organized by category (classes, modules, behaviors) +* Enables consistent documentation across similar components + +**Fragment Usage**: + +.. code-block:: python + + class Dictionary: + _dynadoc_fragments_ = { + 'description': doctab.classes.Dictionary.description, + 'examples': doctab.classes.Dictionary.examples, + } + +**Benefits**: + +* Reduces documentation duplication +* Ensures consistency across similar classes +* Facilitates documentation updates +* Supports multiple documentation renderers + +Test Organization +=============================================================================== + +Tests mirror the source package structure and follow project naming conventions. +For detailed information about test structure, naming conventions, and coverage +targets, see ``architecture/testplans/index.rst``. + +Documentation Organization +=============================================================================== + +Documentation Structure +------------------------------------------------------------------------------- + +Project documentation resides in ``documentation/``: + +.. code-block:: + + documentation/ + ├── index.rst # Documentation home + ├── prd.rst # Product requirements document + ├── contribution.rst # Contribution guidelines + ├── architecture/ # Architecture documentation + │ ├── index.rst # Architecture overview + │ ├── summary.rst # System architecture summary + │ ├── filesystem.rst # This file + │ ├── decisions/ # Architectural decision records + │ ├── designs/ # Detailed design documents + │ └── testplans/ # Test planning documentation + └── examples/ # Usage examples for each module + +Documentation Types +------------------------------------------------------------------------------- + +**API Documentation**: + +* Generated from source code docstrings +* Uses Sphinx with autodoc extension +* Includes type hints and examples +* Available at package documentation site + +**Architecture Documentation**: + +* High-level system design +* Component relationships +* Architectural decision records +* Design patterns and rationale + +**Examples Documentation**: + +* Practical usage examples +* Common patterns and idioms +* Migration guides +* Tested via doctest + +**Requirements Documentation**: + +* Product requirements (prd.rst) +* Feature specifications +* Success criteria +* Constraints and assumptions + +Development Workspace +=============================================================================== + +Development-specific files are organized in ``.auxiliary/``: + +.. code-block:: + + .auxiliary/ + ├── notes/ # Development notes and session state + ├── scribbles/ # Temporary scratch files + └── instructions/ # Cached development guidelines + +Purpose and Usage +------------------------------------------------------------------------------- + +**Session Continuity**: + +* ``.auxiliary/notes/`` preserves development context across sessions +* Claude Code agents update notes during conversations +* TODO items track remaining work and emergent tasks +* Session notes capture decisions and context + +**Development Resources**: + +* ``.auxiliary/instructions/`` caches commonly-referenced guidelines +* Populated by agentsmgr tool from upstream repositories +* Provides offline access to development standards +* Ensures consistency with project templates + +**Scratch Space**: + +* ``.auxiliary/scribbles/`` for temporary experiments +* Preferred over ``/tmp/`` for project-specific scratch work +* Not committed to version control +* Cleaned up periodically + +Exclusion from Distribution +------------------------------------------------------------------------------- + +The ``.auxiliary/`` directory is excluded from package distributions: + +* Listed in ``.gitignore`` for local development files +* Excluded via ``tool.hatch.build`` configuration in ``pyproject.toml`` +* Not included in source distributions +* Development-specific only, not needed by users + +Configuration Files +=============================================================================== + +``pyproject.toml`` + Centralized project configuration following PEP 518/PEP 621 with package + metadata, dependencies, build system (hatch), and tool configurations + (pytest, coverage, ruff, pyright). + +``README.rst`` + Project overview with key features, installation instructions, basic + examples, and contribution guidelines. + +``LICENSE.txt`` + Apache License 2.0 with copyright and legal terms. + Architecture Evolution =============================================================================== diff --git a/documentation/architecture/summary.rst b/documentation/architecture/summary.rst index bab368a..827da76 100644 --- a/documentation/architecture/summary.rst +++ b/documentation/architecture/summary.rst @@ -21,4 +21,312 @@ System Overview ******************************************************************************* -.. todo:: Describe the high-level system architecture, major components, and their relationships. \ No newline at end of file +The package provides immutable data structures and class behaviors through a +layered architecture. The system enforces immutability at multiple levels - +from low-level dictionary implementations to high-level class decorators - +while maintaining compatibility with Python's standard library patterns and +third-party tools like dataclasses. + +Purpose and Scope +=============================================================================== + +The library addresses the need for immutable data structures in Python by: + +* Providing drop-in replacements for mutable built-in types (dict, namespace) +* Enabling conversion of arbitrary classes to immutable variants +* Supporting selective mutability for gradual adoption +* Maintaining type safety and comprehensive documentation + +The library does not attempt to make immutability completely unbreakable +(which is impossible in Python), but instead provides practical immutability +that integrates naturally with Python's idioms and existing code. + +Major Components +=============================================================================== + +The system is organized into distinct layers that build upon each other: + +**Public API Layer** + Modules that provide user-facing functionality: dictionaries, namespaces, + classes (metaclasses and decorators), modules, sequences, exceptions, and + installers. See ``architecture/filesystem.rst`` for detailed module + descriptions. + +**Core Implementation Layer** + Internal ``__`` subpackage containing ImmutableDictionary, centralized + imports, type aliases, documentation fragments, and internal exceptions. + See ``architecture/filesystem.rst`` for detailed module descriptions. + +**Foundation Dependencies** + External libraries providing core functionality: + + - **classcore**: Class factory mechanism and attribute protection system + - **dynadoc**: Dynamic documentation generation using reusable fragments + - **absence**: Sentinel value for distinguishing missing values from ``None`` + +Component Relationships +=============================================================================== + +Architecture Layers +------------------------------------------------------------------------------- + +The system follows a clear layered architecture: + +:: + + ┌─────────────────────────────────────────────────────────────┐ + │ Public API │ + │ (Dictionary, Namespace, Object, decorators) │ + └─────────────────────────────────────────────────────────────┘ + ↓ + ┌─────────────────────────────────────────────────────────────┐ + │ Core Implementation (__/) │ + │ (ImmutableDictionary, type aliases, doc fragments) │ + └─────────────────────────────────────────────────────────────┘ + ↓ + ┌─────────────────────────────────────────────────────────────┐ + │ Foundation Libraries │ + │ (classcore, dynadoc, absence) │ + └─────────────────────────────────────────────────────────────┘ + +Dependency Flow +------------------------------------------------------------------------------- + +All modules follow the ``__`` import pattern: + +1. Public modules import from ``. import __`` +2. The ``__`` package provides centralized access to external dependencies +3. Configuration flows from public API through to classcore via partial application +4. Runtime checks flow from classcore back through implementation to user code + +Key dependencies between components: + +* ``dictionaries.py`` → ``classes.py`` (uses AbstractBaseClass metaclass) +* ``namespaces.py`` → ``classes.py`` (uses Object base class) +* ``modules.py`` → ``classes.py`` (uses Module metaclass) +* All components → ``__`` (centralized imports and utilities) +* ``classes.py`` → ``classcore.standard`` (core class factory) + +Data Flow Patterns +=============================================================================== + +Initialization Flow +------------------------------------------------------------------------------- + +Immutable objects follow a consistent initialization pattern: + +1. Object creation begins with standard Python ``__new__`` +2. During ``__init__``, attributes/entries can be freely set +3. After ``__init__`` completes, protection is activated +4. Subsequent modification attempts raise immutability exceptions + +For ``ImmutableDictionary``: + +:: + + __init__ starts + ↓ + Set entries in dict (immutability not active) + ↓ + Add 'immutability' flag to _behaviors_ + ↓ + __init__ completes + ↓ + Future __setitem__/__delitem__ check flag and raise exceptions + +For classes using metaclasses: + +:: + + User class definition + ↓ + Metaclass __new__ with classcore.standard.class_factory + ↓ + Instance __init__ (attributes can be set) + ↓ + Protection activated via __setattr__/__delattr__ overrides + ↓ + Future modifications raise AttributeImmutability + +Operation Flow +------------------------------------------------------------------------------- + +Dictionary operations (union, intersection) maintain immutability: + +1. User invokes operation: ``dict1 | dict2`` +2. Operation method computes new data +3. Method calls ``with_data()`` to create new instance +4. New instance has same type and validator (if applicable) +5. Returns new immutable dictionary + +Class Creation Flow +------------------------------------------------------------------------------- + +When using decorators or metaclasses: + +:: + + User defines class with metaclass or decorator + ↓ + Metaclass or decorator invokes _class_factory (partial) + ↓ + classcore.standard.class_factory receives configuration: + - attributes_namer (calculate_attrname) + - dynadoc_configuration + - error_class_provider + - protection/concealment behaviors + ↓ + Returns configured class with immutability enforcement + ↓ + User creates instances with standard constructor + ↓ + classcore enforces attribute protection after __init__ + +Key Architectural Patterns +=============================================================================== + +Wrapper Pattern +------------------------------------------------------------------------------- + +Public classes wrap internal implementations: + +* ``Dictionary`` wraps ``ImmutableDictionary`` stored in ``_data_`` attribute +* ``ValidatorDictionary`` extends ``Dictionary`` with ``_validator_`` attribute +* ``Namespace`` uses ``ImmutableDictionary`` for ``__dict__`` + +This separation provides: + +* Clean public API distinct from implementation details +* Flexibility to change implementation without breaking API +* Support for subclassing and specialization + +Delegation Pattern +------------------------------------------------------------------------------- + +Frigid delegates core functionality to classcore rather than reimplementing +immutability mechanisms. This provides: + +* Reduced code duplication +* Leveraging battle-tested implementation +* Consistent behavior with other classcore-based packages +* Focus on user-facing API and documentation + +Configuration via Partial Application +------------------------------------------------------------------------------- + +Class factories use ``functools.partial`` to bind frigid-specific configuration: + +.. code-block:: python + + _class_factory = partial( + ccstd.class_factory, + attributes_namer=calculate_attrname, + dynadoc_configuration=DynadocConfiguration(...), + error_class_provider=_provide_error_class, + ) + +This pattern enables: + +* Reusable configuration across multiple metaclasses +* Clear separation of frigid customization from classcore mechanics +* Type-safe configuration that fails at import time, not runtime + +Centralized Import Hub Pattern +------------------------------------------------------------------------------- + +The ``__`` subpackage provides consistent access to dependencies: + +* All modules use ``from . import __`` +* Single source of truth for external dependencies +* Easy refactoring of dependencies +* Reduced import overhead through centralization + +Template Method Pattern +------------------------------------------------------------------------------- + +Abstract methods enable customization in subclasses: + +* ``Dictionary.with_data()`` - creates new instance with different data +* Subclasses override to maintain type and behavior +* Enables operations like union/intersection to return correct types + +Behavioral Flags Pattern +------------------------------------------------------------------------------- + +``ImmutableDictionary`` uses a ``_behaviors_`` set to track state: + +* During ``__init__``, 'immutability' not in set (modifications allowed) +* After ``__init__``, 'immutability' added to set (modifications blocked) +* Methods check flag before allowing operations +* Provides clear initialization window without complex state tracking + +Quality Attributes +=============================================================================== + +Maintainability +------------------------------------------------------------------------------- + +* Clear layered architecture separates concerns +* Delegation to classcore reduces maintenance burden +* Centralized imports simplify dependency management +* Comprehensive documentation via dynadoc + +Usability +------------------------------------------------------------------------------- + +* Familiar API similar to built-in types +* Multiple access patterns (metaclasses, decorators, direct instantiation) +* Clear exception messages for violations +* Gradual adoption via selective mutability + +Compatibility +------------------------------------------------------------------------------- + +* Works with dataclasses and other decorators +* Compatible with protocols and abstract base classes +* Supports standard Python introspection +* Respects existing Python conventions + +Performance +------------------------------------------------------------------------------- + +* Centralized imports reduce per-module import overhead +* Minimal runtime overhead beyond Python's standard attribute access +* No runtime code generation or bytecode manipulation +* Delegation to classcore for efficient attribute protection + +System Constraints +=============================================================================== + +Python Language Limitations +------------------------------------------------------------------------------- + +True immutability is impossible in Python: + +* Anyone with intermediate knowledge can circumvent protections +* ``object.__setattr__`` can bypass custom ``__setattr__`` +* Direct manipulation of ``__dict__`` possible in some cases +* Reflection and introspection expose internal state + +The library provides practical immutability for normal usage, not security +against determined circumvention. + +Initialization Window Requirement +------------------------------------------------------------------------------- + +Objects must support normal Python initialization: + +* ``__init__`` must be able to set attributes +* Dataclass initialization requires attribute assignment +* Protection activates only after ``__init__`` completes +* Brief window where object is technically mutable + +Compatibility with Third-Party Tools +------------------------------------------------------------------------------- + +Must work with existing Python ecosystem: + +* Dataclasses require specific initialization patterns +* Pickling requires certain attributes to be accessible +* Introspection tools expect standard Python semantics +* Documentation tools need readable docstrings and signatures \ No newline at end of file diff --git a/documentation/architecture/testplans/index.rst b/documentation/architecture/testplans/index.rst index 3db3d71..f7d326c 100644 --- a/documentation/architecture/testplans/index.rst +++ b/documentation/architecture/testplans/index.rst @@ -26,5 +26,39 @@ Test Plans summary +Test Structure +=============================================================================== -.. todo:: Add test plan documents to toctree. \ No newline at end of file +Tests mirror the source package structure: + +.. code-block:: + + tests/ + ├── test_000_modules/ # Module-level tests + │ ├── test_010_classes.py # Tests for classes.py + │ ├── test_020_dictionaries.py # Tests for dictionaries.py + │ ├── test_030_namespaces.py # Tests for namespaces.py + │ ├── test_040_sequences.py # Tests for sequences.py + │ └── test_050_modules.py # Tests for modules.py + ├── test_100_edge_cases/ # Edge case and integration tests + └── fixtures/ # Shared test fixtures + +Naming Conventions +------------------------------------------------------------------------------- + +**File naming**: ``test__.py`` + +* Priority indicates test execution order (000, 010, 020, etc.) +* Module name matches the source module being tested + +**Test function naming**: ``test__`` + +* Number indicates test execution order within file +* Description uses snake_case and clearly states what is tested + +Coverage Targets +------------------------------------------------------------------------------- + +* >95% line coverage for source code +* 100% coverage of public API surface +* All documented examples tested via doctest \ No newline at end of file diff --git a/documentation/prd.rst b/documentation/prd.rst index 85bf640..dbf4640 100644 --- a/documentation/prd.rst +++ b/documentation/prd.rst @@ -21,7 +21,442 @@ Product Requirements Document ******************************************************************************* -.. todo:: Define product requirements, user stories, and acceptance criteria. +Executive Summary +=============================================================================== -For PRD format and guidance, see the `requirements documentation guide -`_. \ No newline at end of file +Frigid is a Python library that provides practical immutability for Python +data structures and classes. The library addresses the gap between Python's +mutable-by-default design and the need for immutable objects in modern +software development practices. By offering familiar APIs similar to built-in +types (dict, namespace) and flexible integration mechanisms (metaclasses, +decorators), frigid enables developers to adopt immutability gradually and +pragmatically. + +The library targets Python developers who need immutable data structures for +configuration objects, value objects, thread-safe data sharing, and functional +programming patterns, while maintaining compatibility with the broader Python +ecosystem including dataclasses, protocols, and type checking tools. + +Problem Statement +=============================================================================== + +Python's built-in data structures (dict, list, set) and user-defined classes +are mutable by default. While Python provides some immutable types (tuple, +frozenset, str), it lacks comprehensive immutable alternatives for common +use cases: + +**Who experiences the problem:** + +* Python developers building concurrent or distributed systems +* Teams adopting functional programming patterns +* Developers creating configuration management systems +* Library authors providing public APIs with stability guarantees +* Engineers working with shared state across threads or processes + +**When and where it occurs:** + +* Configuration objects that should remain constant after initialization +* Value objects that represent immutable concepts (coordinates, timestamps) +* Shared data structures accessed by multiple threads +* API responses that should not be modified by consumers +* Cache keys that must maintain consistent hash values + +**Impact and consequences:** + +* Unintended mutations cause hard-to-debug errors +* Race conditions in concurrent code from shared mutable state +* Cache invalidation issues from objects changing after hashing +* Defensive copying proliferates throughout codebases +* Lack of compile-time guarantees about object immutability + +**Current workarounds and limitations:** + +* ``types.MappingProxyType`` - read-only view but lacks set operations and + creates indirection +* Manual ``__setattr__`` overrides - error-prone boilerplate for each class +* Converting to tuples - loses named access and type information +* Frozen dataclasses - limited to dataclasses and requires decorator +* Custom implementations - inconsistent behavior across projects + +None of these solutions provide a comprehensive, ergonomic, and consistent +approach to immutability across different Python constructs. + +Goals and Objectives +=============================================================================== + +Primary Objectives +------------------------------------------------------------------------------- + +**GOAL-001: Provide drop-in immutable replacements for common built-in types** + +* Success metric: Users can replace ``dict`` with ``Dictionary`` and + ``types.SimpleNamespace`` with ``Namespace`` with minimal code changes +* Success metric: Immutable versions support all read operations of their + mutable counterparts + +**GOAL-002: Enable conversion of arbitrary classes to immutable variants** + +* Success metric: Developers can make any class immutable using a decorator + or metaclass +* Success metric: Works with dataclasses, protocols, and abstract base classes + +**GOAL-003: Maintain compatibility with Python ecosystem** + +* Success metric: Compatible with type checkers (mypy, pyright) +* Success metric: Works with standard introspection tools +* Success metric: Integrates with dataclasses and other decorators + +**GOAL-004: Support gradual adoption** + +* Success metric: Selective mutability allows specific attributes to remain + mutable +* Success metric: Clear migration path from mutable to immutable code +* Success metric: Interoperability with mutable code without defensive copying + +Secondary Objectives +------------------------------------------------------------------------------- + +**GOAL-005: Provide clear error messages for immutability violations** + +* Success metric: Exceptions include attribute/entry names in error messages +* Success metric: Users can quickly identify and fix violations + +**GOAL-006: Minimize performance overhead** + +* Success metric: Immutable operations have comparable performance to mutable + equivalents +* Success metric: Import time and memory overhead remain minimal + +**GOAL-007: Comprehensive documentation and examples** + +* Success metric: All public APIs have complete documentation +* Success metric: Examples cover common use cases +* Success metric: Migration guides assist users transitioning from mutable code + +Functional Requirements +=============================================================================== + +Immutable Dictionary +------------------------------------------------------------------------------- + +**REQ-001: Standard Immutable Dictionary** (Priority: Critical) + +Provide an immutable dictionary type similar to dict that prevents +modifications after creation. + +Requirements: + +* Initialization from iterables, mappings, and keyword arguments +* All read operations (``__getitem__``, ``get``, ``keys``, ``values``, + ``items``, ``__len__``, ``__contains__``) +* Mutations (``__setitem__``, ``__delitem__``, ``clear``, ``pop``, + ``popitem``, ``update``) raise immutability exceptions +* Supports equality comparison and hashing +* Preserves dict-like repr and iteration order + +**REQ-002: Set Operations on Dictionaries** (Priority: High) + +Support set-like operations for combining immutable dictionaries. + +Requirements: + +* Union operation (``|``) creates new immutable dictionary +* Intersection operation (``&``) creates new immutable dictionary +* Operations return same type as operands (subclass-aware) +* Type signatures accept both mutable and immutable dictionaries + +**REQ-003: Dictionary with Validation** (Priority: High) + +Provide a dictionary variant that validates entries on initialization. + +Requirements: + +* Accepts validator function during initialization +* Validator receives all entries and raises exception on invalid data +* Validation occurs before immutability is enforced +* Clear error messages indicate which entries failed validation + +Immutable Namespace +------------------------------------------------------------------------------- + +**REQ-004: Immutable Namespace Object** (Priority: Critical) + +Provide an immutable namespace type similar to types.SimpleNamespace for +simple immutable objects with attribute access. + +Requirements: + +* Initialization from iterables, mappings, and keyword arguments +* Attribute read access (``__getattr__``) +* Attribute modifications (``__setattr__``, ``__delattr__``) raise exceptions +* Supports equality comparison +* Readable repr showing all attributes + +Immutable Classes +------------------------------------------------------------------------------- + +**REQ-005: Metaclass for Immutable Classes** (Priority: Critical) + +Provide metaclasses for creating immutable class hierarchies. + +Requirements: + +* Metaclass ``Class`` for standard immutable classes +* Metaclass ``Dataclass`` for immutable dataclasses +* Metaclass ``AbstractBaseClass`` compatible with abc.ABCMeta +* Protocol metaclasses for structural typing +* Attributes can be set during ``__init__`` +* Attribute protection activates after ``__init__`` completes + +**REQ-006: Decorator for Immutable Classes** (Priority: Critical) + +Provide decorators to make existing classes immutable without changing +inheritance. + +Requirements: + +* ``with_standard_behaviors`` decorator for any class +* ``dataclass_with_standard_behaviors`` combines dataclass and immutability +* Works with existing decorators (property, classmethod, staticmethod) +* Compatible with inheritance hierarchies +* Preserves type hints and docstrings + +**REQ-007: Selective Mutability** (Priority: High) + +Support marking specific attributes as mutable for gradual adoption. + +Requirements: + +* Metaclass parameter ``instances_mutables`` lists mutable attributes +* Decorator parameter ``instances_mutables`` lists mutable attributes +* Wildcard (``'*'``) allows all instance attributes to be mutable +* Class attributes remain protected by default +* Clear error messages distinguish protected vs. mutable attributes + +Immutable Modules +------------------------------------------------------------------------------- + +**REQ-008: Immutable Module Type** (Priority: Medium) + +Provide immutable module types to prevent modification of module-level +constants. + +Requirements: + +* ``Module`` class extends types.ModuleType +* Module attributes cannot be modified after ``finalize_module`` call +* Integration with dynadoc for documentation generation +* Compatible with standard module importing + +Utility Functions +------------------------------------------------------------------------------- + +**REQ-009: Sequence Utilities** (Priority: Medium) + +Provide readable utilities for creating immutable sequences. + +Requirements: + +* ``one(x)`` creates single-item tuple more readably than ``(x,)`` +* Compatible with type checkers +* Minimal performance overhead + +**REQ-010: Builtins Installation** (Priority: Low) + +Support optional installation of frigid functions into builtins. + +Requirements: + +* Installer function adds frigid utilities to builtins +* Opt-in mechanism (not automatic) +* Clear documentation about when to use + +Exception Handling +------------------------------------------------------------------------------- + +**REQ-011: Clear Exception Hierarchy** (Priority: Critical) + +Provide clear exception hierarchy for debugging immutability violations. + +Requirements: + +* ``AttributeImmutability`` for attribute violations (inherits AttributeError) +* ``EntryImmutability`` for dictionary entry violations (inherits TypeError) +* ``EntryInvalidity`` for validation failures (inherits ValueError) +* Exception messages include attribute/entry names +* Base exception classes (``Omniexception``, ``Omnierror``) for catching all + frigid exceptions + +Non-Functional Requirements +=============================================================================== + +Compatibility Requirements +------------------------------------------------------------------------------- + +**NFR-001: Python Version Support** + +* Support Python 3.10+ (latest stable versions) +* Follow Python's deprecation schedule for older versions +* Test against multiple Python implementations (CPython priority) + +**NFR-002: Type Checking Compatibility** + +* Full type hint coverage for public APIs +* Compatible with mypy, pyright, and other type checkers +* Proper generic type support for containers +* dataclass_transform decorator for dataclass metaclasses + +**NFR-003: Ecosystem Integration** + +* Works with standard introspection (inspect module) +* Compatible with other decorators and metaclasses + +Usability Requirements +------------------------------------------------------------------------------- + +**NFR-004: API Familiarity** + +* Immutable types mirror built-in type interfaces +* Method names follow Python naming conventions +* Consistent behavior with Python's data model +* Familiar initialization patterns + +**NFR-005: Error Messages** + +* Informative exception messages with context +* Clear indication of which attribute/entry caused violation +* Helpful suggestions for common mistakes +* Stack traces point to user code, not library internals + +**NFR-006: Documentation Quality** + +* Comprehensive API documentation for all public symbols +* Practical examples for each major feature +* Migration guides from common patterns +* Performance characteristics documented +* Type hints visible in documentation + +Maintainability Requirements +------------------------------------------------------------------------------- + +**NFR-007: Code Quality** + +* Type hints for all public and internal APIs +* Test coverage > 95% for all modules +* Automated testing on multiple Python versions +* Linting with ruff, type checking with pyright + +**NFR-008: Architectural Clarity** + +* Clear separation between public API and implementation +* Layered architecture documented +* Dependency on stable libraries (classcore, dynadoc) +* Minimal external dependencies + +Reliability Requirements +------------------------------------------------------------------------------- + +**NFR-009: Robustness** + +* Graceful handling of edge cases (empty collections, None values) +* No silent failures or data corruption +* Consistent behavior across Python versions +* Memory safety (no segmentation faults) + +Security Requirements +------------------------------------------------------------------------------- + +**NFR-010: Practical Immutability** + +* Immutability enforced for normal usage patterns +* Clear documentation that circumvention is possible +* Not intended as security boundary +* Protection against accidental modification, not malicious circumvention + +Constraints and Assumptions +=============================================================================== + +Technical Constraints +------------------------------------------------------------------------------- + +* Python language limitations make true immutability impossible +* Must allow attribute setting during ``__init__`` for compatibility +* Cannot prevent all circumvention methods (``object.__setattr__``, etc.) +* Delegation to classcore for core immutability mechanisms + +Dependency Constraints +------------------------------------------------------------------------------- + +* Depends on classcore for class factory and protection mechanisms +* Depends on dynadoc for documentation generation +* Depends on absence for sentinel values +* Depends on typing_extensions for backported type features + +Compatibility Constraints +------------------------------------------------------------------------------- + +* Must work with dataclasses decorator +* Must be compatible with metaclass conflicts resolution +* Must work with standard library introspection tools + +Assumptions +------------------------------------------------------------------------------- + +* Users understand Python's object model and attribute access +* Users accept that absolute immutability is impossible in Python +* Development environments support Python 3.10+ +* Type checkers are used as optional tools, not requirements +* Users willing to adopt new APIs for immutability benefits + +Out of Scope +=============================================================================== + +The following features are explicitly excluded from frigid's scope: + +**Security-Hardened Immutability** + +* Frigid does not prevent determined circumvention +* Not suitable as security boundary or sandbox +* Use Python's restricted execution or separate processes for security + +**Deep Freezing of Nested Structures** + +* Frigid does not recursively freeze nested mutable objects +* Users must explicitly create immutable nested structures +* No automatic conversion of mutable contents to immutable + +**Immutable Built-in Collections** + +* No immutable list (use tuple) +* No immutable set (use frozenset) +* Frigid focuses on types not provided by Python standard library + +**Runtime Performance Optimization** + +* No C extensions for performance optimization +* No JIT compilation or bytecode manipulation +* Relies on Python's standard attribute access mechanisms + +**Immutability Analysis Tools** + +* No static analysis for detecting mutations +* No linting rules for enforcing immutability +* Users should use type checkers for static guarantees + +**Automatic Migration Tools** + +* No automated refactoring from mutable to immutable code +* No codemod tools for converting existing code +* Users perform manual migration using documentation + +**Immutable I/O or External Resources** + +* No immutable file handles or network connections +* No immutable database connections +* Scope limited to in-memory data structures + +**Thread Synchronization Primitives** + +* No locks, semaphores, or other concurrency primitives +* Immutability aids thread safety but does not replace synchronization +* Users must still implement proper concurrent access patterns \ No newline at end of file