dddesign


Namedddesign JSON
Version 1.1.4 PyPI version JSON
download
home_pagehttps://github.com/davyddd/dddesign
SummaryDomain Driven Design Library
upload_time2025-01-09 14:31:31
maintainerNone
docs_urlNone
authordavyddd
requires_python<3.13,>=3.8
licenseMIT
keywords python ddd domain driven design ddd architecture ddd structure architecture structure dddesign
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # DDDesign

[![pypi](https://img.shields.io/pypi/v/dddesign.svg)](https://pypi.python.org/pypi/dddesign)
[![downloads](https://static.pepy.tech/badge/dddesign/month)](https://pepy.tech/project/dddesign)
[![versions](https://img.shields.io/pypi/pyversions/dddesign.svg)](https://github.com/davyddd/dddesign)
[![codecov](https://codecov.io/gh/davyddd/dddesign/branch/main/graph/badge.svg)](https://app.codecov.io/github/davyddd/dddesign)
[![license](https://img.shields.io/github/license/davyddd/dddesign.svg)](https://github.com/davyddd/dddesign/blob/main/LICENSE)

**DDDesign** is a Python library designed to implement Domain-Driven Design (DDD) principles in software projects. 
It provides a set of tools and structures to help developers apply DDD architecture. 
This library is built on top of [Pydantic](https://docs.pydantic.dev/latest/), 
ensuring data validation and settings management using Python type annotations.

## Installation

Install the library using pip:
```bash
pip install dddesign
```

## DDD Components

### Application

**Application** is a programmatic interface for accessing business logic. 
It serves as the primary entry point for all domain operations.

#### Entry points:
- **Ports**: HTTP interfaces, background tasks, CLI commands, and other interaction points.  
- **Other Applications**: Within the same **Context**, leading and subordinate **Applications** may coexist, creating a layered structure. Leading **Applications** manage core business logic, while subordinate **Applications** handle narrower delegated tasks.

This approach ensures clear separation of responsibilities and helps maintain a well-organized architecture.

### Adapter

**Adapter** is a component designed to retrieve data from external sources. 
Based on the **Adapter Pattern** described in "Gang of Four" (GoF), 
it bridges the interface of a system with the one expected by another.

#### Characteristics:
- Belongs to the infrastructure layer and isolates interactions with external interfaces.
- Divided into integration with internal (`InternalAdapter`) and third-party (`ExternalAdapter`) services.

By encapsulating external dependencies, **Adapter** keeps the core application logic decoupled and modular.

### Repository

**Repository**, a subtype of **Adapter**, is a specialized infrastructure layer component introduced in "Domain-Driven Design" by _Eric Evans_. 
It isolates interactions with data storage systems (e.g., PostgreSQL, ClickHouse, Redis, and others) 
and provides an abstraction for managing persistence.

#### Characteristics:
- **Single Responsibility**: Each **Repository** is typically designed to work with a single table (**Entity**).
- **Separation of Concerns**: Keeps domain logic independent of storage implementations.  
- **Application Usage**: If an **Application** uses more than one **Repository**, this indicates a design issue. In such cases, consider creating another **Application**.

This abstraction ensures that persistence logic is modular and aligns with DDD principles.

### Service

**Service** is used to handle business logic not tied to a specific domain object.  

#### Characteristics:
- **Purpose**: Used when a method spans multiple domain objects.
- **Clear Naming**: The name should clearly describe its purpose, as it always implements a single `handle` method.
- **Input / Output**: Can return a new object or modify an input object in place.  
- **Dependency Management**: Relies only on provided inputs, avoiding direct infrastructure dependencies, ensuring easy unit testing.

### Data Transfer Object (DTO)

**Data Transfer Object** is a simple, immutable data structure used for transferring data between application layers. 
Introduced by _Martin Fowler_ in "Patterns of Enterprise Application Architecture", it acts as a data contract.

#### Characteristics:
- **Data Contracts**: Defines clear structures for exchanging data between layers.  
- **Immutability**: DTOs cannot be modified after creation.  
- **Application Access**: Any additional data fetching required to fulfill a contract should be handled by the **Application**, as it has access to **Repositories** or subordinate **Applications**.

### Value Object

**Value Object** is an object defined solely by its properties and has no unique identifier. 
Originating in object-oriented programming, it was refined by _Eric Evans_ in "Domain-Driven Design" to reduce domain model complexity.

#### Characteristics:
- **No Identity**: Identified by attributes, not a unique identifier.  
- **Immutability**: Cannot be modified after creation, ensuring consistency.  
- **Equality**: Two **Value Objects** are equal if all their properties match.

#### Examples:
- **Address**: street, city, postal code, country.  
- **Money**: amount, currency.

### Entity

**Entity** is a domain object identified by a unique property (typically a primary key in the database). 
It represents a single record in a table and encapsulates related data and behavior.

#### Characteristics:
- **Unique Identity**: Ensures one-to-one correspondence with a database record.  
- **Field Consistency**: Fields in the **Entity** should align with the database schema.  

#### Notes:
- Fields such as `created_at` and `updated_at`, often managed by ORMs, can be omitted from the **Entity** if they are not required in the business logic. 
- Ideally, each **Entity** should have a dedicated **Repository** and possibly its own **Application**.

### Aggregate

**Aggregate** is a collection of related **Entity** objects that work together within a single bounded context.  
By exposing controlled methods for interaction, it ensures consistency and atomicity of operations under shared rules.

#### Characteristics:
- **Consistency**: Ensures domain rules are followed by exposing public methods for interaction, ensuring all internal **Entities** remain in valid states.
- **Atomicity**: Treats operations on the aggregate as a single unit, ensuring consistent changes across all entities.

#### Usage:
- **Ports** create a **DTO**, which is passed to the **Application**. The **Application** builds **Entities** and groups them into an **Aggregate**, validating rules and contracts.  
- **Aggregates** can also act as simple containers for related **Entities** within a single HTTP request, avoiding the need for multiple REST calls, thereby reducing network overhead.

### Component Interaction Flowchart

<img src="https://public-media.adapty.io/project-structure.png" alt="Component Interaction Flowchart" width="600">

## Factories

### ApplicationFactory

Facilitates creating application instances with specific dependencies.
Useful when multiple interfaces with different dependencies share the same application logic.

**Example**:
```python
from dddesign.structure.applications import Application, ApplicationDependencyMapper, ApplicationFactory

from app.account_context.applications.account import AccountApp, account_app_impl
from app.account_context.applications.social_account import SocialAccountApp, social_account_app_impl
from app.account_context.domains.constants import SocialDriver
from app.account_context.infrastructure.adapters.external import social


class AuthSocialApp(Application):
    account_app: AccountApp = account_app_impl
    social_account_app: SocialAccountApp = social_account_app_impl
    social_adapter: social.SocialAdapterInterface
    
    ...


auth_social_app_factory = ApplicationFactory[AuthSocialApp](
    application_class=AuthSocialApp,
    dependency_mappers=(
        ApplicationDependencyMapper(
            application_attribute_name='social_adapter',
            request_attribute_value_map={
                SocialDriver.APPLE: social.apple_id_adapter_impl,
                SocialDriver.GOOGLE: social.google_adapter_impl,
                SocialDriver.FACEBOOK: social.facebook_adapter_impl,
            },
        ),
    ),
)

# note: the argument name must match the lowercase version of the Enum class name
auth_apple_app_impl = auth_social_app_factory.get(social_driver=SocialDriver.APPLE)
```

### AggregateListFactory

Converts a list of **Entity** into **Aggregate** objects.

```python
from dddesign.structure.infrastructure.adapters.internal import InternalAdapter

from app.account_context.domains.dto.media import Media, MediaId
from app.media_context.applications.media import MediaApp, media_app_impl


class MediaAdapter(InternalAdapter):
    media_app: MediaApp = media_app_impl
    
    def get(self, media_id: MediaId | None) -> Media | None:
        if media_id is None:
            return None

        medias = self.get_map((media_id,))
        return next(iter(medias.values()), None)

    def get_map(self, media_ids: tuple[str, ...]) -> dict[str, Media]:
        if not media_ids:
            return {}

        medias = self.media_app.get_list(media_ids=media_ids)
        return {MediaId(media.media_id): Media(**media.model_dump()) for media in medias}


media_adapter_impl = MediaAdapter()
```

```python
from dddesign.structure.domains.aggregates import Aggregate
from pydantic import model_validator

from app.account_context.domains.dto.media import Media
from app.account_context.domains.entities.profile import Profile


class ProfileAggregate(Aggregate):
    profile: Profile
    icon: Media | None = None

    @model_validator(mode='after')
    def validate_consistency(self):
        if self.profile.icon_id:
            if self.icon is None:
                raise ValueError('`icon` field is required when `profile` has `icon_id`')
            if self.profile.icon_id != self.icon.media_id:
                raise ValueError('`profile.icon_id` is not equal to `icon.media_id`')
        elif self.icon is not None:
            raise ValueError('`icon` field is not allowed when `profile` has no `icon_id`')

        return self
```

**Example 1**: Retrieving multiple related objects
```python
from dddesign.structure.domains.aggregates import AggregateDependencyMapper, AggregateListFactory

from app.account_context.domains.aggregates.profile import ProfileAggregate
from app.account_context.infrastructure.adapters.internal.media import media_adapter_impl


aggregate_list_factory = AggregateListFactory[ProfileAggregate](
    aggregate_class=ProfileAggregate,
    aggregate_entity_attribute_name='profile',
    dependency_mappers=(
        AggregateDependencyMapper(
            method_getter=media_adapter_impl.get_map,
            entity_attribute_name='icon_id',
            aggregate_attribute_name='icon',
        ),
    ),
)

aggregates: list[ProfileAggregate] = aggregate_list_factory.create_list([...])  # list of Profile Entity
```

**Example 2**: Retrieving a single related object
```python
from dddesign.structure.domains.aggregates import AggregateDependencyMapper, AggregateListFactory

from app.account_context.domains.aggregates.profile import ProfileAggregate
from app.account_context.infrastructure.adapters.internal.media import media_adapter_impl


aggregate_list_factory = AggregateListFactory[ProfileAggregate](
    aggregate_class=ProfileAggregate,
    aggregate_entity_attribute_name='profile',
    dependency_mappers=(
        AggregateDependencyMapper(
            method_getter=media_adapter_impl.get,
            entity_attribute_name='icon_id',
            aggregate_attribute_name='icon',
        ),
    ),
)

aggregates: list[ProfileAggregate] = aggregate_list_factory.create_list([...])  # list of Profile Entity
```

## Enums

### BaseEnum

`BaseEnum` is a foundational enum class that should be used across the application. 
It extends the standard Python Enum and provides additional functionality:
- `__str__` method: Converts the enum’s value to a string representation, making it more readable in logs, responses, or debugging output.
- `has_value` class method: Allows you to check whether a specific value is defined in the enum. This is particularly useful for validation purposes.

### ChoiceEnum

`ChoiceEnum` is an extension of `BaseEnum` designed for scenarios where enumerations need both a machine-readable value 
and a human-readable title. It adds utility methods for creating user-friendly choices.

## Error Handling

### BaseError

`BaseError` is a foundational exception class that standardizes error handling by providing structured information for errors. 
It simplifies the creation of domain-specific exceptions and ensures consistency across the application.

### CollectionError

`CollectionError` is an exception class designed to aggregate multiple instances of `BaseError`. 
It simplifies error handling in scenarios where multiple errors need to be captured and processed together.

### Errors

`Errors` is a Data Transfer Object that transforms a `CollectionError` into a structured format for 4XX HTTP responses. 
It ensures domain-level errors are serialized and returned to the client in a meaningful way, avoiding 500 responses.

### wrap_error

`wrap_error` is a utility function designed to convert a Pydantic `ValidationError` into a `CollectionError`, 
enabling a standardized way of handling and aggregating validation errors. 
It ensures that detailed error information is preserved while providing a structured format for further processing.

### create_pydantic_error_instance

`create_pydantic_error_instance` is a utility function for dynamically creating custom `PydanticErrorMixin` instances, 
allowing to define detailed and context-aware Pydantic validation errors.

## Testing and State Management

### MagicMock

`MagicMock` is an enhanced version of `unittest.mock.MagicMock` that adds compatibility with `BaseModel`. 
It streamlines testing by handling Pydantic models more effectively in mocked environments.

### TrackChangesMixin

`TrackChangesMixin` is a mixin for `BaseModel` that tracks changes made to model fields. 
It allows to monitor field modifications, compare current and initial values, and manage the state of the model.


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/davyddd/dddesign",
    "name": "dddesign",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<3.13,>=3.8",
    "maintainer_email": null,
    "keywords": "python, ddd, domain driven design, ddd architecture, ddd structure, architecture, structure, dddesign",
    "author": "davyddd",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/5b/e0/bfe7591fcaf0ea6cf06832ce400e24c0da903a8c49e1ffa4fe1ce48b2a58/dddesign-1.1.4.tar.gz",
    "platform": null,
    "description": "# DDDesign\n\n[![pypi](https://img.shields.io/pypi/v/dddesign.svg)](https://pypi.python.org/pypi/dddesign)\n[![downloads](https://static.pepy.tech/badge/dddesign/month)](https://pepy.tech/project/dddesign)\n[![versions](https://img.shields.io/pypi/pyversions/dddesign.svg)](https://github.com/davyddd/dddesign)\n[![codecov](https://codecov.io/gh/davyddd/dddesign/branch/main/graph/badge.svg)](https://app.codecov.io/github/davyddd/dddesign)\n[![license](https://img.shields.io/github/license/davyddd/dddesign.svg)](https://github.com/davyddd/dddesign/blob/main/LICENSE)\n\n**DDDesign** is a Python library designed to implement Domain-Driven Design (DDD) principles in software projects. \nIt provides a set of tools and structures to help developers apply DDD architecture. \nThis library is built on top of [Pydantic](https://docs.pydantic.dev/latest/), \nensuring data validation and settings management using Python type annotations.\n\n## Installation\n\nInstall the library using pip:\n```bash\npip install dddesign\n```\n\n## DDD Components\n\n### Application\n\n**Application** is a programmatic interface for accessing business logic. \nIt serves as the primary entry point for all domain operations.\n\n#### Entry points:\n- **Ports**: HTTP interfaces, background tasks, CLI commands, and other interaction points.  \n- **Other Applications**: Within the same **Context**, leading and subordinate **Applications** may coexist, creating a layered structure. Leading **Applications** manage core business logic, while subordinate **Applications** handle narrower delegated tasks.\n\nThis approach ensures clear separation of responsibilities and helps maintain a well-organized architecture.\n\n### Adapter\n\n**Adapter** is a component designed to retrieve data from external sources. \nBased on the **Adapter Pattern** described in \"Gang of Four\" (GoF), \nit bridges the interface of a system with the one expected by another.\n\n#### Characteristics:\n- Belongs to the infrastructure layer and isolates interactions with external interfaces.\n- Divided into integration with internal (`InternalAdapter`) and third-party (`ExternalAdapter`) services.\n\nBy encapsulating external dependencies, **Adapter** keeps the core application logic decoupled and modular.\n\n### Repository\n\n**Repository**, a subtype of **Adapter**, is a specialized infrastructure layer component introduced in \"Domain-Driven Design\" by _Eric Evans_. \nIt isolates interactions with data storage systems (e.g., PostgreSQL, ClickHouse, Redis, and others) \nand provides an abstraction for managing persistence.\n\n#### Characteristics:\n- **Single Responsibility**: Each **Repository** is typically designed to work with a single table (**Entity**).\n- **Separation of Concerns**: Keeps domain logic independent of storage implementations.  \n- **Application Usage**: If an **Application** uses more than one **Repository**, this indicates a design issue. In such cases, consider creating another **Application**.\n\nThis abstraction ensures that persistence logic is modular and aligns with DDD principles.\n\n### Service\n\n**Service** is used to handle business logic not tied to a specific domain object.  \n\n#### Characteristics:\n- **Purpose**: Used when a method spans multiple domain objects.\n- **Clear Naming**: The name should clearly describe its purpose, as it always implements a single `handle` method.\n- **Input / Output**: Can return a new object or modify an input object in place.  \n- **Dependency Management**: Relies only on provided inputs, avoiding direct infrastructure dependencies, ensuring easy unit testing.\n\n### Data Transfer Object (DTO)\n\n**Data Transfer Object** is a simple, immutable data structure used for transferring data between application layers. \nIntroduced by _Martin Fowler_ in \"Patterns of Enterprise Application Architecture\", it acts as a data contract.\n\n#### Characteristics:\n- **Data Contracts**: Defines clear structures for exchanging data between layers.  \n- **Immutability**: DTOs cannot be modified after creation.  \n- **Application Access**: Any additional data fetching required to fulfill a contract should be handled by the **Application**, as it has access to **Repositories** or subordinate **Applications**.\n\n### Value Object\n\n**Value Object** is an object defined solely by its properties and has no unique identifier. \nOriginating in object-oriented programming, it was refined by _Eric Evans_ in \"Domain-Driven Design\" to reduce domain model complexity.\n\n#### Characteristics:\n- **No Identity**: Identified by attributes, not a unique identifier.  \n- **Immutability**: Cannot be modified after creation, ensuring consistency.  \n- **Equality**: Two **Value Objects** are equal if all their properties match.\n\n#### Examples:\n- **Address**: street, city, postal code, country.  \n- **Money**: amount, currency.\n\n### Entity\n\n**Entity** is a domain object identified by a unique property (typically a primary key in the database). \nIt represents a single record in a table and encapsulates related data and behavior.\n\n#### Characteristics:\n- **Unique Identity**: Ensures one-to-one correspondence with a database record.  \n- **Field Consistency**: Fields in the **Entity** should align with the database schema.  \n\n#### Notes:\n- Fields such as `created_at` and `updated_at`, often managed by ORMs, can be omitted from the **Entity** if they are not required in the business logic. \n- Ideally, each **Entity** should have a dedicated **Repository** and possibly its own **Application**.\n\n### Aggregate\n\n**Aggregate** is a collection of related **Entity** objects that work together within a single bounded context.  \nBy exposing controlled methods for interaction, it ensures consistency and atomicity of operations under shared rules.\n\n#### Characteristics:\n- **Consistency**: Ensures domain rules are followed by exposing public methods for interaction, ensuring all internal **Entities** remain in valid states.\n- **Atomicity**: Treats operations on the aggregate as a single unit, ensuring consistent changes across all entities.\n\n#### Usage:\n- **Ports** create a **DTO**, which is passed to the **Application**. The **Application** builds **Entities** and groups them into an **Aggregate**, validating rules and contracts.  \n- **Aggregates** can also act as simple containers for related **Entities** within a single HTTP request, avoiding the need for multiple REST calls, thereby reducing network overhead.\n\n### Component Interaction Flowchart\n\n<img src=\"https://public-media.adapty.io/project-structure.png\" alt=\"Component Interaction Flowchart\" width=\"600\">\n\n## Factories\n\n### ApplicationFactory\n\nFacilitates creating application instances with specific dependencies.\nUseful when multiple interfaces with different dependencies share the same application logic.\n\n**Example**:\n```python\nfrom dddesign.structure.applications import Application, ApplicationDependencyMapper, ApplicationFactory\n\nfrom app.account_context.applications.account import AccountApp, account_app_impl\nfrom app.account_context.applications.social_account import SocialAccountApp, social_account_app_impl\nfrom app.account_context.domains.constants import SocialDriver\nfrom app.account_context.infrastructure.adapters.external import social\n\n\nclass AuthSocialApp(Application):\n    account_app: AccountApp = account_app_impl\n    social_account_app: SocialAccountApp = social_account_app_impl\n    social_adapter: social.SocialAdapterInterface\n    \n    ...\n\n\nauth_social_app_factory = ApplicationFactory[AuthSocialApp](\n    application_class=AuthSocialApp,\n    dependency_mappers=(\n        ApplicationDependencyMapper(\n            application_attribute_name='social_adapter',\n            request_attribute_value_map={\n                SocialDriver.APPLE: social.apple_id_adapter_impl,\n                SocialDriver.GOOGLE: social.google_adapter_impl,\n                SocialDriver.FACEBOOK: social.facebook_adapter_impl,\n            },\n        ),\n    ),\n)\n\n# note: the argument name must match the lowercase version of the Enum class name\nauth_apple_app_impl = auth_social_app_factory.get(social_driver=SocialDriver.APPLE)\n```\n\n### AggregateListFactory\n\nConverts a list of **Entity** into **Aggregate** objects.\n\n```python\nfrom dddesign.structure.infrastructure.adapters.internal import InternalAdapter\n\nfrom app.account_context.domains.dto.media import Media, MediaId\nfrom app.media_context.applications.media import MediaApp, media_app_impl\n\n\nclass MediaAdapter(InternalAdapter):\n    media_app: MediaApp = media_app_impl\n    \n    def get(self, media_id: MediaId | None) -> Media | None:\n        if media_id is None:\n            return None\n\n        medias = self.get_map((media_id,))\n        return next(iter(medias.values()), None)\n\n    def get_map(self, media_ids: tuple[str, ...]) -> dict[str, Media]:\n        if not media_ids:\n            return {}\n\n        medias = self.media_app.get_list(media_ids=media_ids)\n        return {MediaId(media.media_id): Media(**media.model_dump()) for media in medias}\n\n\nmedia_adapter_impl = MediaAdapter()\n```\n\n```python\nfrom dddesign.structure.domains.aggregates import Aggregate\nfrom pydantic import model_validator\n\nfrom app.account_context.domains.dto.media import Media\nfrom app.account_context.domains.entities.profile import Profile\n\n\nclass ProfileAggregate(Aggregate):\n    profile: Profile\n    icon: Media | None = None\n\n    @model_validator(mode='after')\n    def validate_consistency(self):\n        if self.profile.icon_id:\n            if self.icon is None:\n                raise ValueError('`icon` field is required when `profile` has `icon_id`')\n            if self.profile.icon_id != self.icon.media_id:\n                raise ValueError('`profile.icon_id` is not equal to `icon.media_id`')\n        elif self.icon is not None:\n            raise ValueError('`icon` field is not allowed when `profile` has no `icon_id`')\n\n        return self\n```\n\n**Example 1**: Retrieving multiple related objects\n```python\nfrom dddesign.structure.domains.aggregates import AggregateDependencyMapper, AggregateListFactory\n\nfrom app.account_context.domains.aggregates.profile import ProfileAggregate\nfrom app.account_context.infrastructure.adapters.internal.media import media_adapter_impl\n\n\naggregate_list_factory = AggregateListFactory[ProfileAggregate](\n    aggregate_class=ProfileAggregate,\n    aggregate_entity_attribute_name='profile',\n    dependency_mappers=(\n        AggregateDependencyMapper(\n            method_getter=media_adapter_impl.get_map,\n            entity_attribute_name='icon_id',\n            aggregate_attribute_name='icon',\n        ),\n    ),\n)\n\naggregates: list[ProfileAggregate] = aggregate_list_factory.create_list([...])  # list of Profile Entity\n```\n\n**Example 2**: Retrieving a single related object\n```python\nfrom dddesign.structure.domains.aggregates import AggregateDependencyMapper, AggregateListFactory\n\nfrom app.account_context.domains.aggregates.profile import ProfileAggregate\nfrom app.account_context.infrastructure.adapters.internal.media import media_adapter_impl\n\n\naggregate_list_factory = AggregateListFactory[ProfileAggregate](\n    aggregate_class=ProfileAggregate,\n    aggregate_entity_attribute_name='profile',\n    dependency_mappers=(\n        AggregateDependencyMapper(\n            method_getter=media_adapter_impl.get,\n            entity_attribute_name='icon_id',\n            aggregate_attribute_name='icon',\n        ),\n    ),\n)\n\naggregates: list[ProfileAggregate] = aggregate_list_factory.create_list([...])  # list of Profile Entity\n```\n\n## Enums\n\n### BaseEnum\n\n`BaseEnum` is a foundational enum class that should be used across the application. \nIt extends the standard Python Enum and provides additional functionality:\n- `__str__` method: Converts the enum\u2019s value to a string representation, making it more readable in logs, responses, or debugging output.\n- `has_value` class method: Allows you to check whether a specific value is defined in the enum. This is particularly useful for validation purposes.\n\n### ChoiceEnum\n\n`ChoiceEnum` is an extension of `BaseEnum` designed for scenarios where enumerations need both a machine-readable value \nand a human-readable title. It adds utility methods for creating user-friendly choices.\n\n## Error Handling\n\n### BaseError\n\n`BaseError` is a foundational exception class that standardizes error handling by providing structured information for errors. \nIt simplifies the creation of domain-specific exceptions and ensures consistency across the application.\n\n### CollectionError\n\n`CollectionError` is an exception class designed to aggregate multiple instances of `BaseError`. \nIt simplifies error handling in scenarios where multiple errors need to be captured and processed together.\n\n### Errors\n\n`Errors` is a Data Transfer Object that transforms a `CollectionError` into a structured format for 4XX HTTP responses. \nIt ensures domain-level errors are serialized and returned to the client in a meaningful way, avoiding 500 responses.\n\n### wrap_error\n\n`wrap_error` is a utility function designed to convert a Pydantic `ValidationError` into a `CollectionError`, \nenabling a standardized way of handling and aggregating validation errors. \nIt ensures that detailed error information is preserved while providing a structured format for further processing.\n\n### create_pydantic_error_instance\n\n`create_pydantic_error_instance` is a utility function for dynamically creating custom `PydanticErrorMixin` instances, \nallowing to define detailed and context-aware Pydantic validation errors.\n\n## Testing and State Management\n\n### MagicMock\n\n`MagicMock` is an enhanced version of `unittest.mock.MagicMock` that adds compatibility with `BaseModel`. \nIt streamlines testing by handling Pydantic models more effectively in mocked environments.\n\n### TrackChangesMixin\n\n`TrackChangesMixin` is a mixin for `BaseModel` that tracks changes made to model fields. \nIt allows to monitor field modifications, compare current and initial values, and manage the state of the model.\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Domain Driven Design Library",
    "version": "1.1.4",
    "project_urls": {
        "Homepage": "https://github.com/davyddd/dddesign",
        "Repository": "https://github.com/davyddd/dddesign"
    },
    "split_keywords": [
        "python",
        " ddd",
        " domain driven design",
        " ddd architecture",
        " ddd structure",
        " architecture",
        " structure",
        " dddesign"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2da13261c935fa75ffb63334d9c858fd72864c885752cd0fa1fc30ec3860d8c4",
                "md5": "0476f24465fe38e7c3b752e7c0d01eba",
                "sha256": "ecc9aecc9cf9dc8d071c1cc128df59170c0391720aebf11e9b869008e8def25c"
            },
            "downloads": -1,
            "filename": "dddesign-1.1.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "0476f24465fe38e7c3b752e7c0d01eba",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<3.13,>=3.8",
            "size": 26486,
            "upload_time": "2025-01-09T14:31:29",
            "upload_time_iso_8601": "2025-01-09T14:31:29.965264Z",
            "url": "https://files.pythonhosted.org/packages/2d/a1/3261c935fa75ffb63334d9c858fd72864c885752cd0fa1fc30ec3860d8c4/dddesign-1.1.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "5be0bfe7591fcaf0ea6cf06832ce400e24c0da903a8c49e1ffa4fe1ce48b2a58",
                "md5": "8b5c726d545edf32497e5871849c84d7",
                "sha256": "d95864068b88fa28e59f6e1f64418982219dc76acb63e0a68bab93bb4fc4eb1d"
            },
            "downloads": -1,
            "filename": "dddesign-1.1.4.tar.gz",
            "has_sig": false,
            "md5_digest": "8b5c726d545edf32497e5871849c84d7",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<3.13,>=3.8",
            "size": 19469,
            "upload_time": "2025-01-09T14:31:31",
            "upload_time_iso_8601": "2025-01-09T14:31:31.851865Z",
            "url": "https://files.pythonhosted.org/packages/5b/e0/bfe7591fcaf0ea6cf06832ce400e24c0da903a8c49e1ffa4fe1ce48b2a58/dddesign-1.1.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-01-09 14:31:31",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "davyddd",
    "github_project": "dddesign",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "dddesign"
}
        
Elapsed time: 0.44486s