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.5.tar.gz (14.5 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.5-py3-none-any.whl (15.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: ddd_value_objects-0.1.5.tar.gz
  • Upload date:
  • Size: 14.5 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.5.tar.gz
Algorithm Hash digest
SHA256 1f235ab44c58cd764d6bd4c4252815be4263fc34b537009a032a4f984b1f5531
MD5 37a1b6e54b3981a67497af0552f6e54f
BLAKE2b-256 211fbbd80428a9fe809ebebd46e45dda9c1fdb159f7fe2e912477507ddcf9056

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ddd_value_objects-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 c32cb5995bd8321ac27ea71d55e2c7d7ab8fb5f1cd832d3767943d3e8c31c162
MD5 fa65f271b599d72071f805bb6f29927e
BLAKE2b-256 88300704c95e4de2e9f927397981bb7af2fad42635995e771146f70e6efef551

See more details on using hashes here.

Provenance

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