Skip to main content

A collection of base classes for Domain-Driven Design (DDD) value objects and entities in Python

Project description

DDD Value Objects for Python

A comprehensive collection of base classes and specialized types for implementing Domain-Driven Design (DDD) patterns in Python. This library provides a robust foundation for building maintainable, type-safe, and self-validating domain models using Value Objects and Entities.

License: MIT Python 3.10+ Coverage

Key Features

  • Base Classes: Robust base classes for both Primitive and Composite Value Objects.
  • Immutability: Designed to be immutable, ensuring domain integrity.
  • Structural Equality: Value Objects are compared by their attributes, not by identity.
  • Self-Validation: Built-in validation for common domain types (Emails, UUIDs, URLs, etc.).
  • Strong Typing: Leverages Python generics for type safety and better IDE support.
  • Entity Support: Base class for Entities with identity-based equality.

Installation

Install using pip:

pip install ddd-value-objects

Or using uv:

uv add ddd-value-objects

Core Concepts

Value Objects

In DDD, a Value Object is an object that represents a descriptive aspect of the domain with no conceptual identity. They are defined by their attributes and are immutable. Two value objects are considered equal if all their attributes are equal.

Primitive Value Objects

Wrap single primitive types (str, int, float, bool) to give them domain meaning.

Composite Value Objects

Combine multiple values into a single domain concept (e.g., Money which consists of an amount and a currency).

Entities

Entities have a unique identity that persists over time, regardless of changes to their attributes.


Usage Examples

1. Primitive Value Objects

You can extend base classes to create domain-specific types:

from ddd_value_objects import StringValueObject, PositiveIntValueObject, InvalidArgumentError

class UserName(StringValueObject):
    pass

class UserAge(PositiveIntValueObject):
    def __init__(self, value: int):
        super().__init__(value)
        if value > 150:
            raise InvalidArgumentError(f"Age {value} is out of valid range (max 150)")

# Usage
name1 = UserName("Alice")
name2 = UserName("Alice")
age = UserAge(30)

print(name1 == name2)  # True (Structural equality)
print(name1.value)     # "Alice"

2. Specialized Value Objects

The library includes many pre-built, self-validating types:

from ddd_value_objects import (
    EmailValueObject, 
    UuidValueObject, 
    UrlValueObject, 
    PhoneNumberValueObject,
    CurrencyValueObject
)

email = EmailValueObject("user@example.com")
user_id = UuidValueObject("550e8400-e29b-41d4-a716-446655440000")
website = UrlValueObject("https://github.com")
currency = CurrencyValueObject("USD") # Validates ISO 4217 code

3. Composite Value Objects (e.g., Money)

Handle complex types that group multiple values:

from ddd_value_objects import MoneyValueObject

price = MoneyValueObject(99.99, "USD")
tax = MoneyValueObject(10.00, "USD")

# Arithmetic operations (if supported by implementation)
total = price.add(tax)

print(total.amount)   # 109.99
print(total.currency) # "USD"

4. Enum Value Objects

Restrict values to a specific set using an Enum:

from enum import Enum
from ddd_value_objects import EnumValueObject, StringValueObject, InvalidArgumentError

class UserRole(Enum):
    ADMIN = "admin"
    USER = "user"

class RoleValueObject(EnumValueObject):
    def __init__(self, value: str):
        # Define the valid options
        valid_roles = [StringValueObject(r.value) for r in UserRole]
        
        # Pass the current value as a ValueObject and the list of valid options
        super().__init__(
            StringValueObject(value), 
            valid_roles
        )

# Usage
try:
    role = RoleValueObject("admin")
    print(role.value)  # "admin"
    
    invalid_role = RoleValueObject("guest") # Raises InvalidArgumentError
except InvalidArgumentError as e:
    print(e)

5. Entities

Use the Entity base class for objects with identity:

from ddd_value_objects import Entity, UuidValueObject

class Product(Entity):
    def __init__(self, product_id: str, name: str):
        # Entity expects a string ID which it wraps in a UuidValueObject
        super().__init__(product_id)
        self.name = name

product1 = Product("550e8400-e29b-41d4-a716-446655440000", "Laptop")
product2 = Product("550e8400-e29b-41d4-a716-446655440000", "Updated Laptop Name")

print(product1 == product2) # True (Same identity/ID)

Available Value Objects

Category Classes
Primitives StringValueObject, IntValueObject, FloatValueObject, BoolValueObject
Numeric PositiveIntValueObject, PositiveFloatValueObject
Identity UuidValueObject
Network EmailValueObject, UrlValueObject, IpAddressValueObject
Communication PhoneNumberValueObject, CountryCodeValueObject (ISO 3166-1 alpha-2)
Temporal DateTimeValueObject, DateValueObject (Unix timestamps)
Financial CurrencyValueObject (ISO 4217), MoneyValueObject
Others EnumValueObject, CompositeValueObject

Development and Testing

We use uv for dependency management and pytest for testing.

Setup

# Clone the repository
git clone https://github.com/youruser/ddd-value-objects.git
cd ddd-value-objects

# Install dependencies
uv sync

Running Tests

uv run pytest

Coverage Threshold

This project maintains a minimum coverage threshold of 90%. The CI workflow will automatically fail if coverage falls below this level.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ddd_value_objects-0.1.6.tar.gz (14.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ddd_value_objects-0.1.6-py3-none-any.whl (16.0 kB view details)

Uploaded Python 3

File details

Details for the file ddd_value_objects-0.1.6.tar.gz.

File metadata

  • Download URL: ddd_value_objects-0.1.6.tar.gz
  • Upload date:
  • Size: 14.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ddd_value_objects-0.1.6.tar.gz
Algorithm Hash digest
SHA256 ff3b38d45a9d099496eff041be0f708f8ef5a23fa1545b46ef9089c26faa4157
MD5 a1139b69421d38da7f49cd74d9401977
BLAKE2b-256 222badd1575a47010c06de2b676f1fbe4c7335018f6967f2c7fb8bf2523e0315

See more details on using hashes here.

Provenance

The following attestation bundles were made for ddd_value_objects-0.1.6.tar.gz:

Publisher: code.yml on josedejesuschavez/ddd-value-objects

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ddd_value_objects-0.1.6-py3-none-any.whl.

File metadata

File hashes

Hashes for ddd_value_objects-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 b93a082709934a21b16f5dab883ca5238abf5bf35a664390e83f83f3604f7875
MD5 160dfd568c7b06df0afa36f12d504a1d
BLAKE2b-256 8fedc96ccbf0b03752b91b089fe1dbe0e48e2895dc2d81b5c8139da3b0859a0f

See more details on using hashes here.

Provenance

The following attestation bundles were made for ddd_value_objects-0.1.6-py3-none-any.whl:

Publisher: code.yml on josedejesuschavez/ddd-value-objects

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page