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.7.1.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.7.1-py3-none-any.whl (16.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: ddd_value_objects-0.1.7.1.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.7.1.tar.gz
Algorithm Hash digest
SHA256 340ad685cfff73223c044e2345e2827f1f603157a42df59b61bca4ca000ec5cb
MD5 1aad06a469ad26ea0d98458c5beacd29
BLAKE2b-256 a526859c5fe252dbac6eb926735dd4ca5f1c9c60749e13d483e3590561773d25

See more details on using hashes here.

Provenance

The following attestation bundles were made for ddd_value_objects-0.1.7.1.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.7.1-py3-none-any.whl.

File metadata

File hashes

Hashes for ddd_value_objects-0.1.7.1-py3-none-any.whl
Algorithm Hash digest
SHA256 87453247c86f4d8e9a6882ca9c6baa2b966eea91afec85384648f8d105039b1c
MD5 49e851f6a278c31563453f8aa949fa12
BLAKE2b-256 c69abffb37bb0858b04d3366bf3dac2e2be02752903754730e7b2ed6da416273

See more details on using hashes here.

Provenance

The following attestation bundles were made for ddd_value_objects-0.1.7.1-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