# mocksmith
[](https://github.com/gurmeetsaran/mocksmith/actions/workflows/ci.yml)
[](https://codecov.io/gh/gurmeetsaran/mocksmith)
[](https://badge.fury.io/py/mocksmith)
[](https://pypi.org/project/mocksmith/)
[](https://opensource.org/licenses/MIT)
Type-safe data validation with automatic mock generation for Python dataclasses and Pydantic models. Build robust data models with database-aware validation and generate realistic test data with a single decorator.
## Features
- **Type-safe database columns**: Define database columns with proper validation
- **SQL-compliant validation**: All numeric types strictly enforce SQL bounds (TINYINT: -128 to 127, etc.)
- **Instantiation validation**: Types validate at creation time, preventing invalid data from being created
- **Serialization/Deserialization**: Automatic conversion between Python and SQL types
- **Dataclass Integration**: Full support for Python dataclasses with validation
- **Pydantic Integration**: First-class Pydantic support with automatic validation
- **Clean API**: Simple, intuitive interface for both Pydantic AND dataclasses - just `name: Varchar(50)`
- **Comprehensive Types**: STRING (VARCHAR, CHAR, TEXT), NUMERIC (INTEGER, DECIMAL, FLOAT), TEMPORAL (DATE, TIME, TIMESTAMP), and more
- **Mock Data Generation**: Built-in mock/fake data generation that respects all SQL bounds and constraints
- **Constrained Types**: Support for min/max constraints on numeric types - `price: PositiveMoney()`, `age: Integer(ge=0, le=120)`
## Why mocksmith?
### Before (Traditional Approach)
```python
from typing import Annotated
from pydantic import BaseModel, Field, validator
from decimal import Decimal
class Product(BaseModel):
name: Annotated[str, Field(max_length=100)]
price: Annotated[Decimal, Field(decimal_places=2, max_digits=10)]
in_stock: bool = True
@validator('price')
def validate_price(cls, v):
if v < 0:
raise ValueError('Price must be non-negative')
return v
```
### After (With mocksmith)
```python
from pydantic import BaseModel
from mocksmith import Varchar, Money, Boolean
class Product(BaseModel):
name: Varchar(100) # Enforces VARCHAR(100) constraint
price: Money() # Decimal(19,4) - use PositiveMoney() for price > 0
in_stock: Boolean() = True # Flexible boolean parsing
```
✨ **Benefits:**
- Same clean syntax for both Pydantic and dataclasses
- Automatic SQL constraint validation
- Type conversion (string "99.99" → Decimal)
- Better IDE support and type hints
- Write once, use with either framework
## Installation
```bash
# Standard installation (includes mock generation)
pip install mocksmith
# With Pydantic validation support (recommended)
pip install "mocksmith[pydantic]"
```
The standard installation includes Faker for mock data generation and custom validation logic. Adding Pydantic provides better performance and integration with Pydantic types.
## Import Structure
The library organizes types into two categories:
### Core Database Types (V3 Pattern)
Core database types are available through factory functions from the main package:
```python
from mocksmith import (
# String types - Factory functions only
Varchar, Char, Text,
# Numeric types - Factory functions only
Integer, DecimalType, Float,
BigInt, SmallInt, TinyInt,
Double, Real, Numeric,
# Temporal types - Factory functions only
Date, Time, DateTime, Timestamp,
# Other types - Factory functions only
Boolean, Binary, VarBinary, Blob,
# Constrained types
PositiveInteger, NonNegativeInteger, NegativeInteger, NonPositiveInteger,
Money, PositiveMoney, NonNegativeMoney, ConstrainedMoney,
ConstrainedDecimal, ConstrainedFloat
)
```
**⚠️ Breaking Change in V3:** Direct class imports (VARCHAR, INTEGER, etc.) have been removed to prevent confusion. Use factory functions (Varchar, Integer, etc.) exclusively.
### Specialized Types
Specialized types for common use cases are available from the `specialized` submodule:
```python
from mocksmith.specialized import (
# Geographic types
CountryCode, # ISO 3166-1 alpha-2 country codes
City, # City names
State, # State/province names
ZipCode, # Postal codes
# Contact types
PhoneNumber, # Phone numbers
)
```
**Note**: For email and web types, use Pydantic's built-in types instead:
- Email → Use `pydantic.EmailStr`
- URL → Use `pydantic.HttpUrl` or `pydantic.AnyUrl`
- IP addresses → Use `pydantic.IPvAnyAddress`, `pydantic.IPv4Address`, or `pydantic.IPv6Address`
This separation keeps the main namespace clean and makes it clear which types are fundamental database types versus application-specific types.
## Quick Start
### Clean V3 Interface (Works with both Pydantic and Dataclasses!) ✨
```python
from pydantic import BaseModel
from mocksmith import Varchar, Integer, Boolean, Money
class User(BaseModel):
id: Integer()
username: Varchar(50) # Creates a type class with length 50
email: Varchar(255)
is_active: Boolean() = True
balance: Money() = "0.00"
# Automatic validation and type conversion
user = User(
id=1,
username="john_doe",
email="john@example.com",
is_active="yes", # Converts to True
balance="1234.56" # Converts to Decimal('1234.56')
)
```
The same syntax works with dataclasses! See full examples:
- [`examples/pydantic_example.py`](examples/pydantic_example.py) - Comprehensive Pydantic examples with all features
- [`examples/dataclass_example.py`](examples/dataclass_example.py) - Comprehensive dataclass examples with all features
- [`examples/pydantic_mock_example.py`](examples/pydantic_mock_example.py) - Mock data generation with Pydantic models
- [`examples/dataclass_mock_example.py`](examples/dataclass_mock_example.py) - Mock data generation with dataclasses
- [`examples/constrained_types_example.py`](examples/constrained_types_example.py) - Constrained types with validation and mock generation
### Common Use Cases
**E-commerce Product Model:**
```python
from pydantic import BaseModel
from mocksmith import Varchar, Text, Money, Boolean, Timestamp
class Product(BaseModel):
sku: Varchar(20)
name: Varchar(100)
description: Text()
price: Money()
in_stock: Boolean() = True
created_at: Timestamp()
```
**User Account with Constraints:**
```python
from mocksmith import Integer, PositiveInteger, NonNegativeInteger
class UserAccount(BaseModel):
user_id: PositiveInteger()
age: Integer(ge=13, le=120)
balance_cents: NonNegativeInteger()
```
See complete working examples:
- [`examples/`](examples/) - All example files with detailed documentation
- [`examples/pydantic_example.py`](examples/pydantic_example.py) - All features including constraints
- [`examples/dataclass_example.py`](examples/dataclass_example.py) - All features including constraints
## Mock Data Generation
Generate realistic test data automatically with the `@mockable` decorator:
```python
from dataclasses import dataclass
from mocksmith import Varchar, Integer, Date, mockable
from mocksmith.specialized import PhoneNumber, CountryCode
@mockable
@dataclass
class Address:
street: Varchar(100)
city: Varchar(50)
zip_code: Integer(ge=10000, le=99999)
@mockable
@dataclass
class User:
id: Integer()
username: Varchar(50)
phone: PhoneNumber()
country: CountryCode()
birth_date: Date()
address: Address # Nested dataclass!
# Generate mock instances
user = User.mock()
print(user.username) # "Christina Wells"
print(user.phone) # "(555) 123-4567"
print(user.country) # "US"
print(user.address.city) # "New York" # Nested fields are mocked too!
# With overrides
user = User.mock(username="test_user", country="GB")
# Using builder pattern
user = (User.mock_builder()
.with_username("john_doe")
.with_country("CA")
.build())
```
The same `@mockable` decorator works with Pydantic models! Mock generation:
- Respects all field constraints (length, format, etc.)
- Generates appropriate mock data for each type
- Supports specialized types with realistic data
- Works with both dataclasses and Pydantic models
- Automatically handles Python Enum types with random value selection
- Supports nested dataclasses - automatically generates mock data for nested structures
See mock examples:
- [`examples/dataclass_mock_example.py`](examples/dataclass_mock_example.py) - Complete mock examples with dataclasses including enum support
- [`examples/pydantic_mock_example.py`](examples/pydantic_mock_example.py) - Complete mock examples with Pydantic including enum support and built-in types
## V3 Type Usage Patterns
**Important:** MockSmith V3 uses factory functions exclusively. The old pattern of importing classes directly (VARCHAR, INTEGER, etc.) is no longer supported.
### Correct V3 Pattern
```python
from mocksmith import Varchar, Integer, Boolean # Factory functions
# Factory functions create type classes for use in annotations
UsernameType = Varchar(30, min_length=3) # Returns a type class
class User(BaseModel):
username: UsernameType # Use the type class
# Or inline:
email: Varchar(100, to_lower=True) # Factory function inline
age: Integer(gt=0, le=120)
active: Boolean()
```
### What Changed from V2
```python
# ❌ OLD PATTERN (NO LONGER WORKS - REMOVED IN V3)
from mocksmith import VARCHAR # This import fails now
varchar_type = VARCHAR(30) # Would create instance "30" - WRONG!
# ✅ NEW V3 PATTERN (THE ONLY WAY)
from mocksmith import Varchar # Factory function
UsernameType = Varchar(30) # Creates type class - CORRECT!
```
### With Pydantic (Full Validation)
```python
from typing import Optional
from pydantic import BaseModel
from mocksmith import Integer, Varchar, Money, Boolean, PositiveInteger, NonNegativeInteger
from decimal import Decimal
# Pattern 1: Direct usage (Recommended - cleanest syntax)
class Product(BaseModel):
id: Integer()
name: Varchar(100)
price: Money()
in_stock: Boolean() = True
# Pattern 2: With constraints
class ConstrainedModel(BaseModel):
age: Integer(ge=0, le=120) # Age between 0-120
quantity: Integer(gt=0) # Positive quantity
discount: Integer(ge=0, le=100, multiple_of=5) # 0-100%, multiples of 5
# Pattern 3: Factory functions with constraints
class ConstrainedProduct(BaseModel):
sku: Varchar(20, to_upper=True) # Auto uppercase
name: Varchar(100, min_length=3)
price: DecimalType(10, 2, gt=0) # precision=10, scale=2, >0
# Pattern 4: Constrained types (common patterns)
class UserAccount(BaseModel):
user_id: PositiveInteger() # > 0
balance: NonNegativeInteger() # >= 0
# Pattern 5: Optional fields
class OptionalModel(BaseModel):
required_field: Varchar(50)
optional_field: Optional[Varchar(50)] = None # Can be None
with_default: Boolean() = True # Has default value
# All patterns can be mixed in the same model!
```
### With Dataclasses (Type Hints Only, No Validation)
```python
from dataclasses import dataclass
from typing import Optional
from decimal import Decimal
from mocksmith import Integer, Varchar, Money, Text
@dataclass
class Product:
# Same syntax works, but NO validation occurs!
id: Integer()
name: Varchar(100)
price: Money() = Decimal("0.00")
optional_field: Optional[Text()] = None
# WARNING: Dataclasses don't validate!
product = Product(
id=999999999999, # Accepts invalid values!
name="x" * 1000, # No length check!
price="invalid" # No type check!
)
```
### Important V3 Notes
✅ **DO USE (V3 Pattern):**
- `field: Varchar(50)` - Factory functions for type creation
- `field: Integer(gt=0)` - Factory functions with constraints
- `field: Optional[Varchar(50)] = None` - For nullable fields
- Pydantic `BaseModel` when you need validation
- Constrained types like `PositiveInteger()` for common patterns
❌ **DON'T USE (Removed in V3):**
- `from mocksmith import VARCHAR` - Direct class imports removed
- `VARCHAR(30)` - Would create instance "30", not a type!
- Plain dataclasses if you need validation (use Pydantic instead)
### Type Validation Features
All numeric types enforce SQL bounds and validate at instantiation:
- **TinyInt**: -128 to 127 (8-bit)
- **SmallInt**: -32,768 to 32,767 (16-bit)
- **Integer**: -2,147,483,648 to 2,147,483,647 (32-bit)
- **BigInt**: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 (64-bit)
Optional fields properly handle None values:
```python
class User(BaseModel):
name: Varchar(50) # Required
nickname: Optional[Varchar(30)] = None # Optional, can be None
user = User(name="John", nickname=None) # ✓ Valid
```
### Literal Type Support
MockSmith types work seamlessly with Python's `Literal` type for strict value constraints:
```python
from typing import Literal
from pydantic import BaseModel
from mocksmith import Varchar, Integer, mockable
@mockable
class ServerConfig(BaseModel):
environment: Literal["dev", "staging", "prod"]
status_code: Literal[200, 301, 404, 500]
port: Integer(ge=1024, le=65535)
log_level: Literal[0, 1, 2, 3, 4, 5] # 0=OFF, 5=TRACE
# Validation enforces Literal constraints
config = ServerConfig(
environment="prod", # ✓ Valid
status_code=200, # ✓ Valid
port=8080, # ✓ Valid (within range)
log_level=2 # ✓ Valid
)
# Mock generation respects Literal values
mock = ServerConfig.mock()
# mock.environment will be one of: "dev", "staging", "prod"
# mock.status_code will be one of: 200, 301, 404, 500
```
## Clean Annotation Interface
The library provides a clean, Pythonic interface for defining database types:
### Available Clean Types:
**String Types:**
- `Varchar(length)` → Variable-length string
- `Char(length)` → Fixed-length string
- `Text()` → Large text field
- `String` → Alias for Varchar
**Numeric Types:**
- `Integer()` → 32-bit integer (-2,147,483,648 to 2,147,483,647)
- `BigInt()` → 64-bit integer (-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807)
- `SmallInt()` → 16-bit integer (-32,768 to 32,767)
- `TinyInt()` → 8-bit integer (-128 to 127)
- `DecimalType(precision, scale)` → Fixed-point decimal
- `Numeric(precision, scale)` → Alias for DecimalType
- `Money()` → Alias for Decimal(19, 4)
- `Float()` → Floating point (generates FLOAT SQL type)
- `Real()` → Floating point (generates REAL SQL type, typically single precision in SQL)
- `Double()` → Double precision
All numeric types:
- Enforce SQL bounds at instantiation (e.g., `TinyInt(200)` raises ValueError)
- Generate mock data within valid ranges (e.g., `TinyInt(gt=5)` generates 6-127, not > 127)
- Support constraints (gt, ge, lt, le, multiple_of)
**Constrained Numeric Types:**
- `PositiveInteger()` → Integer > 0
- `NegativeInteger()` → Integer < 0
- `NonNegativeInteger()` → Integer ≥ 0
- `NonPositiveInteger()` → Integer ≤ 0
- `ConstrainedInteger(ge=x, le=y, multiple_of=z)` → Custom constraints
- `ConstrainedBigInt(...)` → Constrained 64-bit integer
- `ConstrainedSmallInt(...)` → Constrained 16-bit integer
- `ConstrainedTinyInt(...)` → Constrained 8-bit integer
**Temporal Types:**
- `Date()` → Date only
- `Time()` → Time only
- `Timestamp()` → Date and time with timezone
- `DateTime()` → Date and time without timezone
**Other Types:**
- `Boolean()` / `Bool()` → Boolean with flexible parsing
- `Binary(length)` → Fixed binary
- `VarBinary(max_length)` → Variable binary
- `Blob()` → Large binary object
## Pydantic Integration Features
### Pydantic Built-in Types Support
Mocksmith now supports automatic mock generation for Pydantic's built-in types:
```python
from pydantic import BaseModel, EmailStr, HttpUrl, IPvAnyAddress, conint, constr
from mocksmith import mockable
@mockable
class ServerConfig(BaseModel):
hostname: constr(min_length=1, max_length=253)
ip_address: IPvAnyAddress
port: conint(ge=1, le=65535)
api_url: HttpUrl
admin_email: EmailStr
# Generate mock with Pydantic types
config = ServerConfig.mock()
print(config.ip_address) # IPv4Address('192.168.1.100')
print(config.api_url) # https://example.com
print(config.admin_email) # user@example.com
```
**Tip**: For types that have Pydantic equivalents, prefer using Pydantic's built-in types:
- Use `EmailStr` instead of `mocksmith.specialized.Email`
- Use `HttpUrl` or `AnyUrl` instead of `mocksmith.specialized.URL`
- Use `IPvAnyAddress`, `IPv4Address`, or `IPv6Address` for IP addresses
### Using Pydantic Types in Dataclasses
While Pydantic types can be used as type annotations in dataclasses, there are important limitations:
```python
from dataclasses import dataclass
from pydantic import EmailStr, HttpUrl, conint
@dataclass
class ServerConfig:
hostname: str
email: EmailStr # Works as type hint only
port: conint(ge=1, le=65535) # No validation!
# This creates an instance WITHOUT validation
server = ServerConfig(
hostname="api.example.com",
email="invalid-email", # Not validated!
port=99999 # Out of range but accepted!
)
```
**Key Points**:
- Pydantic types in dataclasses serve as type hints only
- No automatic validation occurs
- Mock generation works but produces regular Python types (str, int, etc.)
- For validation, use Pydantic's BaseModel instead
See the Pydantic types limitations section in [`examples/dataclass_example.py`](examples/dataclass_example.py) for a complete comparison.
### Supported Pydantic Types for Mock Generation
The `@mockable` decorator supports automatic mock generation for the following Pydantic types:
#### Network Types
- `HttpUrl` - Generates valid HTTP/HTTPS URLs
- `AnyHttpUrl` - Generates any HTTP scheme URLs
- `EmailStr` - Generates valid email addresses
- `IPvAnyAddress` - Generates IPv4 or IPv6 addresses (80% IPv4, 20% IPv6)
- `IPvAnyInterface` - Generates IP addresses with CIDR notation
- `IPvAnyNetwork` - Generates IP network addresses
#### Numeric Types
- `PositiveInt` - Integers > 0
- `NegativeInt` - Integers < 0
- `NonNegativeInt` - Integers >= 0
- `NonPositiveInt` - Integers <= 0
- `PositiveFloat` - Floats > 0
- `NegativeFloat` - Floats < 0
- `NonNegativeFloat` - Floats >= 0
- `NonPositiveFloat` - Floats <= 0
#### String/Identifier Types
- `UUID1`, `UUID3`, `UUID4`, `UUID5` - Generates UUIDs (currently all as UUID4)
- `SecretStr` - Generates password-like strings
- `Json` - Generates valid JSON strings
#### Date/Time Types
- `FutureDate` - Generates dates in the future
- `PastDate` - Generates dates in the past
- `FutureDatetime` - Generates datetimes in the future
- `PastDatetime` - Generates datetimes in the past
#### Constraint Types
- `conint(ge=1, le=100)` - Integers with min/max constraints
- `confloat(ge=0.0, le=1.0)` - Floats with min/max constraints
- `constr(min_length=1, max_length=50)` - Strings with length constraints
- `constr(pattern=r"^[A-Z]{3}[0-9]{3}$")` - Strings matching regex patterns (limited support)
- `conlist(item_type, min_length=1, max_length=10)` - Lists with constraints
#### Example Usage
```python
from pydantic import BaseModel, EmailStr, HttpUrl, conint, PositiveInt
from mocksmith import mockable
@mockable
class UserProfile(BaseModel):
user_id: PositiveInt
email: EmailStr
website: HttpUrl
age: conint(ge=18, le=120)
# Generate mock data
user = UserProfile.mock()
print(user.email) # "john.doe@example.com"
print(user.website) # "https://example.com"
print(user.age) # 42 (between 18-120)
```
**Note**: When using Pydantic types in dataclasses (not BaseModel), the types work as annotations only without validation. The mock generation still works but produces regular Python types.
### Handling Unsupported Types
When `@mockable` encounters an unsupported type, it attempts to handle it intelligently:
1. **Common types** (Path, Set, FrozenSet) - Now supported with appropriate mock values
2. **Auto-instantiable types** - Tries to create instances with `()`, `None`, `""`, or `0`
3. **Truly unsupported types** - Returns `None` with a warning to help identify gaps in type support
#### Newly Supported Types
```python
from dataclasses import dataclass
from pathlib import Path
from typing import Set, FrozenSet
from mocksmith import mockable
@mockable
@dataclass
class Config:
config_path: Path # ✓ Generates Path('/tmp/mock_file.txt')
data_dir: Path # ✓ Smart naming: Path('/tmp/mock_directory')
tags: Set[str] # ✓ Generates {'tag1', 'tag2', ...}
frozen_tags: FrozenSet[int] # ✓ Generates frozenset({1, 2, 3})
config = Config.mock()
# All fields get appropriate mock values!
```
#### Warning System
```python
class CustomType:
def __init__(self, required_arg):
# Cannot be auto-instantiated
pass
@mockable
@dataclass
class Example:
name: str # ✓ Supported
custom_required: CustomType # ⚠️ Warning issued, returns None
custom_optional: Optional[CustomType] = None # ⚠️ Warning issued (if attempted), returns None
# Console output:
# UserWarning: mocksmith: Unsupported type 'CustomType' for field 'custom_required'.
# Returning None. Consider making this field Optional or providing a mock override.
```
**Important Notes**:
- **All unsupported types trigger warnings** - This helps identify gaps in mocksmith's type support
- **Warnings help improve mocksmith** - If you encounter warnings, please file an issue on GitHub
- **Optional fields** - May show warnings ~80% of the time (when generation is attempted)
- **Override unsupported types** - Use `mock()` with overrides: `Example.mock(custom_required=CustomType('value'))`
- **Pydantic models** - Make unsupported fields `Optional` to avoid validation errors
### Optional Fields Pattern
Python's `Optional` type indicates fields that can be None:
```python
from typing import Optional
from pydantic import BaseModel
from mocksmith import Varchar, Integer, Text
class Example(BaseModel):
# Required field
required_field: Varchar(50)
# Optional field (can be None)
optional_field: Optional[Varchar(50)] = None
# Field with default value
status: Varchar(20) = "active"
```
**Best Practice**: For optional fields, use `Optional[Type]` with `= None`:
```python
bio: Optional[Text()] = None # Clear and explicit
phone: Optional[Varchar(20)] = None # Optional field with no default
```
### Automatic Type Conversion
```python
from pydantic import BaseModel
from mocksmith import Money, Boolean, Date, Timestamp
class Order(BaseModel):
# String to Decimal conversion
total: Money()
# Flexible boolean parsing
is_paid: Boolean()
# String to date conversion
order_date: Date()
# String to datetime conversion
created_at: Timestamp(with_timezone=False)
# All these string values are automatically converted
order = Order(
total="99.99", # → Decimal('99.99')
is_paid="yes", # → True
order_date="2023-12-15", # → date(2023, 12, 15)
created_at="2023-12-15T10:30:00" # → datetime
)
```
### Field Validation with Pydantic
```python
from pydantic import BaseModel, field_validator
from mocksmith import Varchar, Integer, Money
class Product(BaseModel):
name: Varchar(50)
price: Money()
quantity: Integer()
@field_validator('price')
def price_must_be_positive(cls, v):
if v <= 0:
raise ValueError('Price must be positive')
return v
@field_validator('quantity')
def quantity_non_negative(cls, v):
if v < 0:
raise ValueError('Quantity cannot be negative')
return v
```
### Model Configuration
```python
from pydantic import BaseModel, ConfigDict
from mocksmith import Varchar, Money, Timestamp
class StrictModel(BaseModel):
model_config = ConfigDict(
# Validate on assignment
validate_assignment=True,
# Use Enum values
use_enum_values=True,
# Custom JSON encoders
json_encoders={
Decimal: str,
datetime: lambda v: v.isoformat()
}
)
name: Varchar(100)
price: Money()
updated_at: Timestamp()
```
## Working Examples
For complete working examples, see the [`examples/`](examples/) directory:
- [`dataclass_example.py`](examples/dataclass_example.py) - Comprehensive dataclass examples including:
- All data types (String, Numeric, Date/Time, Binary, Boolean)
- Constrained numeric types (PositiveInteger, NonNegativeInteger, etc.)
- Custom constraints (min_value, max_value, multiple_of)
- TINYINT usage for small bounded values
- REAL vs FLOAT distinction
- SQL serialization
- Validation and error handling
- [`pydantic_example.py`](examples/pydantic_example.py) - Comprehensive Pydantic examples including:
- All data types with automatic validation
- Field validators and computed properties
- Constrained types with complex business logic
- JSON serialization with custom encoders
- [`dataclass_mock_example.py`](examples/dataclass_mock_example.py) - Mock data generation examples:
- Using `@mockable` decorator with dataclasses
- Generating mock instances with `.mock()`
- Override specific fields
- Type-safe builder pattern
- Specialized types (Email, CountryCode, etc.)
- [`pydantic_mock_example.py`](examples/pydantic_mock_example.py) - Mock data generation with Pydantic:
- Using `@mockable` decorator with Pydantic models
- Same mock API as dataclasses
- Automatic validation of generated data
- Specialized types with DBTypeValidator
- Model configuration and validation on assignment
- TINYINT and REAL type usage
- Boolean type conversions
- [`constrained_types_example.py`](examples/constrained_types_example.py) - Constrained types with validation:
- PositiveMoney, NonNegativeMoney, ConstrainedMoney usage
- ConstrainedDecimal with precision and range constraints
- ConstrainedFloat for percentages and probabilities
- Mock generation respecting all constraints
- Validation examples showing error handling
- Builder pattern with constrained types
### Example: E-commerce Order System
```python
from dataclasses import dataclass
from typing import Optional
from datetime import datetime, date
from decimal import Decimal
from mocksmith import Varchar, Integer, Date, DecimalType, Text, BigInt, Timestamp
@dataclass
class Customer:
customer_id: Integer()
first_name: Varchar(50)
last_name: Varchar(50)
email: Varchar(100)
phone: Optional[Varchar(20)]
date_of_birth: Optional[Date()]
@dataclass
class Order:
order_id: BigInt()
customer_id: Integer()
order_date: Timestamp(with_timezone=False)
total_amount: DecimalType(12, 2)
status: Varchar(20)
notes: Optional[Text()]
# Create instances
customer = Customer(
customer_id=1,
first_name="Jane",
last_name="Smith",
email="jane.smith@email.com",
phone="+1-555-0123",
date_of_birth=date(1990, 5, 15)
)
order = Order(
order_id=1001,
customer_id=1,
order_date=datetime(2023, 12, 15, 14, 30, 0),
total_amount=Decimal("299.99"),
status="pending",
notes="Rush delivery requested"
)
# Convert to SQL-ready format
print(order.to_sql_dict())
```
For more complete examples including financial systems, authentication, and SQL testing integration,
see the [`examples/`](examples/) directory.
### Validation in Dataclasses
Plain dataclasses don't provide validation for mocksmith types. For validation, use Pydantic BaseModel:
```python
from pydantic import BaseModel
from mocksmith import SmallInt
class Config(BaseModel): # Use BaseModel for validation
hour: SmallInt(ge=0, le=23)
# Validation happens automatically
try:
config = Config(hour=24) # Raises ValidationError
except ValidationError as e:
print(f"Validation error: {e}")
config = Config(hour=12) # Works fine
```
## Advanced Features
### Custom Validation with Pydantic
```python
from pydantic import BaseModel
class CustomProduct(BaseModel):
sku: Varchar(20) # Required field
name: Varchar(100) # Required field
description: Optional[Varchar(500)] = None # Optional field
```
### Working with Different Types
```python
# Integer types with range validation
small_value = SMALLINT()
small_value.validate(32767) # OK
# small_value.validate(32768) # Raises ValueError - out of range
# Decimal with precision
money = DECIMAL(19, 4)
money.validate("12345.6789") # OK
# money.validate("12345.67890") # Raises ValueError - too many decimal places
# Time with precision
timestamp = TIMESTAMP(precision=0) # No fractional seconds
timestamp.validate("2023-12-15T10:30:45.123456") # Microseconds will be truncated
# Boolean accepts various formats
bool_type = BOOLEAN()
bool_type.deserialize("yes") # True
bool_type.deserialize("1") # True
bool_type.deserialize("false") # False
bool_type.deserialize(0) # False
```
### Constrained Numeric Types
**Important:** All numeric types in mocksmith strictly enforce SQL bounds and validate at instantiation time. For example, `TinyInt` enforces the TINYINT range of -128 to 127, preventing invalid data from being created or generated.
The library provides specialized numeric types with built-in constraints for common validation scenarios:
```python
from mocksmith import Integer, PositiveInteger, NonNegativeInteger
# Enhanced Integer functions - no constraints = standard type
id: Integer() # Standard 32-bit integer
quantity: Integer(ge=0) # With constraints (same as NonNegativeInteger)
discount: Integer(ge=0, le=100) # Percentage 0-100
price: Integer(gt=0) # Same as PositiveInteger()
# Specialized constraint types
id: PositiveInteger() # > 0
quantity: NonNegativeInteger() # >= 0
```
For complete examples with both dataclasses and Pydantic, see:
- [`examples/dataclass_example.py`](examples/dataclass_example.py) - All constraint examples with dataclasses
- [`examples/pydantic_example.py`](examples/pydantic_example.py) - All constraint examples with Pydantic
**Available Constraint Options:**
```python
# Enhanced Integer functions - no constraints = standard type
Integer() # Standard 32-bit integer
Integer(ge=0) # With constraints
Integer(gt=0) # Shortcut for > 0
BigInt() # Standard 64-bit integer
BigInt(ge=0, le=1000000) # With constraints
SmallInt() # Standard 16-bit integer
SmallInt(multiple_of=10) # With constraints
# Specialized constraint types
PositiveInteger() # > 0
NegativeInteger() # < 0
NonNegativeInteger() # >= 0
NonPositiveInteger() # <= 0
# Full constraint options
Integer(
gt=10, # Value must be greater than 10
ge=10, # Value must be greater than or equal to 10
lt=100, # Value must be less than 100
le=100, # Value must be less than or equal to 100
multiple_of=5, # Must be divisible by this
)
```
### Constrained Money and Decimal Types
mocksmith provides constrained versions of Money and Decimal types using Pydantic's constraint system:
```python
from mocksmith import (
ConstrainedMoney, PositiveMoney, NonNegativeMoney,
ConstrainedDecimal, ConstrainedFloat
)
# Money with constraints
price: PositiveMoney() # > 0
balance: NonNegativeMoney() # >= 0
discount: ConstrainedMoney(ge=0, le=100) # 0-100 range
payment: ConstrainedMoney(gt=0, le=10000) # 0 < payment <= 10000
# Decimal with precision and constraints
weight: ConstrainedDecimal(10, 2, gt=0) # Positive weight, max 10 digits, 2 decimal places
temperature: ConstrainedDecimal(5, 2, ge=-273.15) # Above absolute zero
# Float with constraints
percentage: ConstrainedFloat(ge=0.0, le=1.0) # 0-1 range
rate: ConstrainedFloat(gt=0, lt=0.5) # 0 < rate < 0.5
```
These constrained types:
- Work seamlessly with Pydantic validation
- Generate appropriate mock data respecting constraints
- Provide the same clean API as other mocksmith types
- Fall back gracefully if Pydantic is not available
**Example Usage:**
```python
from pydantic import BaseModel
from mocksmith import mockable, PositiveMoney, NonNegativeMoney, ConstrainedMoney, ConstrainedFloat
@mockable
class Order(BaseModel):
subtotal: PositiveMoney() # Must be > 0
discount: ConstrainedMoney(ge=0, le=50) # 0-50 range
tax: NonNegativeMoney() # >= 0
discount_rate: ConstrainedFloat(ge=0, le=0.3) # 0-30%
# Validation works
order = Order(
subtotal="100.00", # ✓ Converts to Decimal
discount="25.00", # ✓ Within 0-50 range
tax="8.50", # ✓ Non-negative
discount_rate=0.15 # ✓ 15% is within 0-30%
)
# Mock generation respects constraints
mock_order = Order.mock()
assert mock_order.subtotal > 0
assert 0 <= mock_order.discount <= 50
assert mock_order.tax >= 0
assert 0 <= mock_order.discount_rate <= 0.3
```
## Migration Guide from V2 to V3
### Breaking Changes
V3 introduces a critical breaking change to prevent confusion and subtle bugs:
1. **Direct class imports are removed** - `from mocksmith import VARCHAR` no longer works
2. **Only factory functions are available** - Use `Varchar()`, not `VARCHAR()`
3. **DBTypeValidator is removed** - Types work directly with Pydantic
### Why This Change?
In V2, importing and using `VARCHAR(30)` would create a type class. In V3's simplified pattern, this would create a string instance with value "30" - highly confusing! To prevent this dangerous ambiguity, direct class access has been removed entirely.
### Migration Steps
```python
# ❌ OLD V2 CODE (No longer works)
from mocksmith import VARCHAR, INTEGER, BOOLEAN
from mocksmith.pydantic_integration import DBTypeValidator
from typing import Annotated
class User(BaseModel):
username: Annotated[str, DBTypeValidator(VARCHAR(30))]
age: Annotated[int, DBTypeValidator(INTEGER())]
active: Annotated[bool, DBTypeValidator(BOOLEAN())]
# ✅ NEW V3 CODE (Clean and simple)
from mocksmith import Varchar, Integer, Boolean
class User(BaseModel):
username: Varchar(30) # Direct usage!
age: Integer()
active: Boolean()
```
### Common Migration Patterns
| Old V2 Pattern | New V3 Pattern |
|----------------|----------------|
| `from mocksmith import VARCHAR` | `from mocksmith import Varchar` |
| `from mocksmith.types.string import VARCHAR` | Not available - use factory functions |
| `Annotated[str, DBTypeValidator(VARCHAR(30))]` | `Varchar(30)` |
| `VARCHAR(30)` (creates type) | `Varchar(30)` (creates type) |
| `INTEGER()` | `Integer()` |
| `DECIMAL(10, 2)` | `DecimalType(10, 2)` |
| `BOOLEAN()` | `Boolean()` |
| `DATE()` | `Date()` |
| `TIMESTAMP()` | `Timestamp()` |
### Benefits of V3
1. **Cleaner API** - No more `DBTypeValidator` or `Annotated` boilerplate
2. **Type safety** - Factory functions always return type classes
3. **No confusion** - Can't accidentally create instances when you mean types
4. **Better IDE support** - Direct type usage improves autocomplete
5. **Simpler codebase** - Less complexity, easier to maintain
## Development
1. Clone the repository:
```bash
git clone https://github.com/gurmeetsaran/mocksmith.git
cd mocksmith
```
2. Install Poetry (if not already installed):
```bash
curl -sSL https://install.python-poetry.org | python3 -
```
3. Install dependencies:
```bash
poetry install
```
4. Set up pre-commit hooks:
```bash
poetry run pre-commit install
```
5. Run tests:
```bash
make test
```
### Development Commands
- `make lint` - Run linting (ruff + pyright)
- `make format` - Format code (black + isort + ruff fix)
- `make test` - Run tests
- `make test-cov` - Run tests with coverage
- `make check-all` - Run all checks (lint + format check + tests)
- `make check-consistency` - Verify pre-commit, Makefile, and CI are in sync
### Ensuring Consistency
To ensure your development environment matches CI/CD:
```bash
# Check that pre-commit hooks match Makefile and GitHub Actions
make check-consistency
```
This will verify that all tools (black, isort, ruff, pyright) are configured consistently across:
- Pre-commit hooks (`.pre-commit-config.yaml`)
- Makefile commands
- GitHub Actions workflows
## License
MIT
Raw data
{
"_id": null,
"home_page": null,
"name": "mocksmith",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "mock, validation, dataclass, pydantic, testing, faker, types, sql",
"author": "Gurmeet Saran",
"author_email": "gurmeetx@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/c2/72/18d9c52e62785e724a40250e6ee2883a5fefc6a517cb483415c3b3451b6b/mocksmith-6.0.1.tar.gz",
"platform": null,
"description": "# mocksmith\n\n[](https://github.com/gurmeetsaran/mocksmith/actions/workflows/ci.yml)\n[](https://codecov.io/gh/gurmeetsaran/mocksmith)\n[](https://badge.fury.io/py/mocksmith)\n[](https://pypi.org/project/mocksmith/)\n[](https://opensource.org/licenses/MIT)\n\nType-safe data validation with automatic mock generation for Python dataclasses and Pydantic models. Build robust data models with database-aware validation and generate realistic test data with a single decorator.\n\n## Features\n\n- **Type-safe database columns**: Define database columns with proper validation\n- **SQL-compliant validation**: All numeric types strictly enforce SQL bounds (TINYINT: -128 to 127, etc.)\n- **Instantiation validation**: Types validate at creation time, preventing invalid data from being created\n- **Serialization/Deserialization**: Automatic conversion between Python and SQL types\n- **Dataclass Integration**: Full support for Python dataclasses with validation\n- **Pydantic Integration**: First-class Pydantic support with automatic validation\n- **Clean API**: Simple, intuitive interface for both Pydantic AND dataclasses - just `name: Varchar(50)`\n- **Comprehensive Types**: STRING (VARCHAR, CHAR, TEXT), NUMERIC (INTEGER, DECIMAL, FLOAT), TEMPORAL (DATE, TIME, TIMESTAMP), and more\n- **Mock Data Generation**: Built-in mock/fake data generation that respects all SQL bounds and constraints\n- **Constrained Types**: Support for min/max constraints on numeric types - `price: PositiveMoney()`, `age: Integer(ge=0, le=120)`\n\n## Why mocksmith?\n\n### Before (Traditional Approach)\n```python\nfrom typing import Annotated\nfrom pydantic import BaseModel, Field, validator\nfrom decimal import Decimal\n\nclass Product(BaseModel):\n name: Annotated[str, Field(max_length=100)]\n price: Annotated[Decimal, Field(decimal_places=2, max_digits=10)]\n in_stock: bool = True\n\n @validator('price')\n def validate_price(cls, v):\n if v < 0:\n raise ValueError('Price must be non-negative')\n return v\n```\n\n### After (With mocksmith)\n```python\nfrom pydantic import BaseModel\nfrom mocksmith import Varchar, Money, Boolean\n\nclass Product(BaseModel):\n name: Varchar(100) # Enforces VARCHAR(100) constraint\n price: Money() # Decimal(19,4) - use PositiveMoney() for price > 0\n in_stock: Boolean() = True # Flexible boolean parsing\n```\n\n\u2728 **Benefits:**\n- Same clean syntax for both Pydantic and dataclasses\n- Automatic SQL constraint validation\n- Type conversion (string \"99.99\" \u2192 Decimal)\n- Better IDE support and type hints\n- Write once, use with either framework\n\n## Installation\n\n```bash\n# Standard installation (includes mock generation)\npip install mocksmith\n\n# With Pydantic validation support (recommended)\npip install \"mocksmith[pydantic]\"\n```\n\nThe standard installation includes Faker for mock data generation and custom validation logic. Adding Pydantic provides better performance and integration with Pydantic types.\n\n## Import Structure\n\nThe library organizes types into two categories:\n\n### Core Database Types (V3 Pattern)\nCore database types are available through factory functions from the main package:\n\n```python\nfrom mocksmith import (\n # String types - Factory functions only\n Varchar, Char, Text,\n # Numeric types - Factory functions only\n Integer, DecimalType, Float,\n BigInt, SmallInt, TinyInt,\n Double, Real, Numeric,\n # Temporal types - Factory functions only\n Date, Time, DateTime, Timestamp,\n # Other types - Factory functions only\n Boolean, Binary, VarBinary, Blob,\n # Constrained types\n PositiveInteger, NonNegativeInteger, NegativeInteger, NonPositiveInteger,\n Money, PositiveMoney, NonNegativeMoney, ConstrainedMoney,\n ConstrainedDecimal, ConstrainedFloat\n)\n```\n\n**\u26a0\ufe0f Breaking Change in V3:** Direct class imports (VARCHAR, INTEGER, etc.) have been removed to prevent confusion. Use factory functions (Varchar, Integer, etc.) exclusively.\n\n### Specialized Types\nSpecialized types for common use cases are available from the `specialized` submodule:\n\n```python\nfrom mocksmith.specialized import (\n # Geographic types\n CountryCode, # ISO 3166-1 alpha-2 country codes\n City, # City names\n State, # State/province names\n ZipCode, # Postal codes\n\n # Contact types\n PhoneNumber, # Phone numbers\n)\n```\n\n**Note**: For email and web types, use Pydantic's built-in types instead:\n- Email \u2192 Use `pydantic.EmailStr`\n- URL \u2192 Use `pydantic.HttpUrl` or `pydantic.AnyUrl`\n- IP addresses \u2192 Use `pydantic.IPvAnyAddress`, `pydantic.IPv4Address`, or `pydantic.IPv6Address`\n\nThis separation keeps the main namespace clean and makes it clear which types are fundamental database types versus application-specific types.\n\n## Quick Start\n\n### Clean V3 Interface (Works with both Pydantic and Dataclasses!) \u2728\n\n```python\nfrom pydantic import BaseModel\nfrom mocksmith import Varchar, Integer, Boolean, Money\n\nclass User(BaseModel):\n id: Integer()\n username: Varchar(50) # Creates a type class with length 50\n email: Varchar(255)\n is_active: Boolean() = True\n balance: Money() = \"0.00\"\n\n# Automatic validation and type conversion\nuser = User(\n id=1,\n username=\"john_doe\",\n email=\"john@example.com\",\n is_active=\"yes\", # Converts to True\n balance=\"1234.56\" # Converts to Decimal('1234.56')\n)\n```\n\nThe same syntax works with dataclasses! See full examples:\n- [`examples/pydantic_example.py`](examples/pydantic_example.py) - Comprehensive Pydantic examples with all features\n- [`examples/dataclass_example.py`](examples/dataclass_example.py) - Comprehensive dataclass examples with all features\n- [`examples/pydantic_mock_example.py`](examples/pydantic_mock_example.py) - Mock data generation with Pydantic models\n- [`examples/dataclass_mock_example.py`](examples/dataclass_mock_example.py) - Mock data generation with dataclasses\n- [`examples/constrained_types_example.py`](examples/constrained_types_example.py) - Constrained types with validation and mock generation\n\n### Common Use Cases\n\n**E-commerce Product Model:**\n\n```python\nfrom pydantic import BaseModel\nfrom mocksmith import Varchar, Text, Money, Boolean, Timestamp\n\nclass Product(BaseModel):\n sku: Varchar(20)\n name: Varchar(100)\n description: Text()\n price: Money()\n in_stock: Boolean() = True\n created_at: Timestamp()\n```\n\n**User Account with Constraints:**\n\n```python\nfrom mocksmith import Integer, PositiveInteger, NonNegativeInteger\n\nclass UserAccount(BaseModel):\n user_id: PositiveInteger()\n age: Integer(ge=13, le=120)\n balance_cents: NonNegativeInteger()\n```\n\nSee complete working examples:\n- [`examples/`](examples/) - All example files with detailed documentation\n- [`examples/pydantic_example.py`](examples/pydantic_example.py) - All features including constraints\n- [`examples/dataclass_example.py`](examples/dataclass_example.py) - All features including constraints\n\n## Mock Data Generation\n\nGenerate realistic test data automatically with the `@mockable` decorator:\n\n```python\nfrom dataclasses import dataclass\nfrom mocksmith import Varchar, Integer, Date, mockable\nfrom mocksmith.specialized import PhoneNumber, CountryCode\n\n@mockable\n@dataclass\nclass Address:\n street: Varchar(100)\n city: Varchar(50)\n zip_code: Integer(ge=10000, le=99999)\n\n@mockable\n@dataclass\nclass User:\n id: Integer()\n username: Varchar(50)\n phone: PhoneNumber()\n country: CountryCode()\n birth_date: Date()\n address: Address # Nested dataclass!\n\n# Generate mock instances\nuser = User.mock()\nprint(user.username) # \"Christina Wells\"\nprint(user.phone) # \"(555) 123-4567\"\nprint(user.country) # \"US\"\nprint(user.address.city) # \"New York\" # Nested fields are mocked too!\n\n# With overrides\nuser = User.mock(username=\"test_user\", country=\"GB\")\n\n# Using builder pattern\nuser = (User.mock_builder()\n .with_username(\"john_doe\")\n .with_country(\"CA\")\n .build())\n```\n\nThe same `@mockable` decorator works with Pydantic models! Mock generation:\n- Respects all field constraints (length, format, etc.)\n- Generates appropriate mock data for each type\n- Supports specialized types with realistic data\n- Works with both dataclasses and Pydantic models\n- Automatically handles Python Enum types with random value selection\n- Supports nested dataclasses - automatically generates mock data for nested structures\n\nSee mock examples:\n- [`examples/dataclass_mock_example.py`](examples/dataclass_mock_example.py) - Complete mock examples with dataclasses including enum support\n- [`examples/pydantic_mock_example.py`](examples/pydantic_mock_example.py) - Complete mock examples with Pydantic including enum support and built-in types\n\n## V3 Type Usage Patterns\n\n**Important:** MockSmith V3 uses factory functions exclusively. The old pattern of importing classes directly (VARCHAR, INTEGER, etc.) is no longer supported.\n\n### Correct V3 Pattern\n\n```python\nfrom mocksmith import Varchar, Integer, Boolean # Factory functions\n\n# Factory functions create type classes for use in annotations\nUsernameType = Varchar(30, min_length=3) # Returns a type class\n\nclass User(BaseModel):\n username: UsernameType # Use the type class\n # Or inline:\n email: Varchar(100, to_lower=True) # Factory function inline\n age: Integer(gt=0, le=120)\n active: Boolean()\n```\n\n### What Changed from V2\n\n```python\n# \u274c OLD PATTERN (NO LONGER WORKS - REMOVED IN V3)\nfrom mocksmith import VARCHAR # This import fails now\nvarchar_type = VARCHAR(30) # Would create instance \"30\" - WRONG!\n\n# \u2705 NEW V3 PATTERN (THE ONLY WAY)\nfrom mocksmith import Varchar # Factory function\nUsernameType = Varchar(30) # Creates type class - CORRECT!\n```\n\n### With Pydantic (Full Validation)\n\n```python\nfrom typing import Optional\nfrom pydantic import BaseModel\nfrom mocksmith import Integer, Varchar, Money, Boolean, PositiveInteger, NonNegativeInteger\nfrom decimal import Decimal\n\n# Pattern 1: Direct usage (Recommended - cleanest syntax)\nclass Product(BaseModel):\n id: Integer()\n name: Varchar(100)\n price: Money()\n in_stock: Boolean() = True\n\n# Pattern 2: With constraints\nclass ConstrainedModel(BaseModel):\n age: Integer(ge=0, le=120) # Age between 0-120\n quantity: Integer(gt=0) # Positive quantity\n discount: Integer(ge=0, le=100, multiple_of=5) # 0-100%, multiples of 5\n\n# Pattern 3: Factory functions with constraints\nclass ConstrainedProduct(BaseModel):\n sku: Varchar(20, to_upper=True) # Auto uppercase\n name: Varchar(100, min_length=3)\n price: DecimalType(10, 2, gt=0) # precision=10, scale=2, >0\n\n# Pattern 4: Constrained types (common patterns)\nclass UserAccount(BaseModel):\n user_id: PositiveInteger() # > 0\n balance: NonNegativeInteger() # >= 0\n\n# Pattern 5: Optional fields\nclass OptionalModel(BaseModel):\n required_field: Varchar(50)\n optional_field: Optional[Varchar(50)] = None # Can be None\n with_default: Boolean() = True # Has default value\n\n# All patterns can be mixed in the same model!\n```\n\n### With Dataclasses (Type Hints Only, No Validation)\n\n```python\nfrom dataclasses import dataclass\nfrom typing import Optional\nfrom decimal import Decimal\nfrom mocksmith import Integer, Varchar, Money, Text\n\n@dataclass\nclass Product:\n # Same syntax works, but NO validation occurs!\n id: Integer()\n name: Varchar(100)\n price: Money() = Decimal(\"0.00\")\n optional_field: Optional[Text()] = None\n\n# WARNING: Dataclasses don't validate!\nproduct = Product(\n id=999999999999, # Accepts invalid values!\n name=\"x\" * 1000, # No length check!\n price=\"invalid\" # No type check!\n)\n```\n\n### Important V3 Notes\n\n\u2705 **DO USE (V3 Pattern):**\n- `field: Varchar(50)` - Factory functions for type creation\n- `field: Integer(gt=0)` - Factory functions with constraints\n- `field: Optional[Varchar(50)] = None` - For nullable fields\n- Pydantic `BaseModel` when you need validation\n- Constrained types like `PositiveInteger()` for common patterns\n\n\u274c **DON'T USE (Removed in V3):**\n- `from mocksmith import VARCHAR` - Direct class imports removed\n- `VARCHAR(30)` - Would create instance \"30\", not a type!\n- Plain dataclasses if you need validation (use Pydantic instead)\n\n### Type Validation Features\n\nAll numeric types enforce SQL bounds and validate at instantiation:\n- **TinyInt**: -128 to 127 (8-bit)\n- **SmallInt**: -32,768 to 32,767 (16-bit)\n- **Integer**: -2,147,483,648 to 2,147,483,647 (32-bit)\n- **BigInt**: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 (64-bit)\n\nOptional fields properly handle None values:\n```python\nclass User(BaseModel):\n name: Varchar(50) # Required\n nickname: Optional[Varchar(30)] = None # Optional, can be None\n\nuser = User(name=\"John\", nickname=None) # \u2713 Valid\n```\n\n### Literal Type Support\n\nMockSmith types work seamlessly with Python's `Literal` type for strict value constraints:\n\n```python\nfrom typing import Literal\nfrom pydantic import BaseModel\nfrom mocksmith import Varchar, Integer, mockable\n\n@mockable\nclass ServerConfig(BaseModel):\n environment: Literal[\"dev\", \"staging\", \"prod\"]\n status_code: Literal[200, 301, 404, 500]\n port: Integer(ge=1024, le=65535)\n log_level: Literal[0, 1, 2, 3, 4, 5] # 0=OFF, 5=TRACE\n\n# Validation enforces Literal constraints\nconfig = ServerConfig(\n environment=\"prod\", # \u2713 Valid\n status_code=200, # \u2713 Valid\n port=8080, # \u2713 Valid (within range)\n log_level=2 # \u2713 Valid\n)\n\n# Mock generation respects Literal values\nmock = ServerConfig.mock()\n# mock.environment will be one of: \"dev\", \"staging\", \"prod\"\n# mock.status_code will be one of: 200, 301, 404, 500\n```\n\n## Clean Annotation Interface\n\nThe library provides a clean, Pythonic interface for defining database types:\n\n### Available Clean Types:\n\n**String Types:**\n- `Varchar(length)` \u2192 Variable-length string\n- `Char(length)` \u2192 Fixed-length string\n- `Text()` \u2192 Large text field\n- `String` \u2192 Alias for Varchar\n\n**Numeric Types:**\n- `Integer()` \u2192 32-bit integer (-2,147,483,648 to 2,147,483,647)\n- `BigInt()` \u2192 64-bit integer (-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807)\n- `SmallInt()` \u2192 16-bit integer (-32,768 to 32,767)\n- `TinyInt()` \u2192 8-bit integer (-128 to 127)\n- `DecimalType(precision, scale)` \u2192 Fixed-point decimal\n- `Numeric(precision, scale)` \u2192 Alias for DecimalType\n- `Money()` \u2192 Alias for Decimal(19, 4)\n- `Float()` \u2192 Floating point (generates FLOAT SQL type)\n- `Real()` \u2192 Floating point (generates REAL SQL type, typically single precision in SQL)\n- `Double()` \u2192 Double precision\n\nAll numeric types:\n- Enforce SQL bounds at instantiation (e.g., `TinyInt(200)` raises ValueError)\n- Generate mock data within valid ranges (e.g., `TinyInt(gt=5)` generates 6-127, not > 127)\n- Support constraints (gt, ge, lt, le, multiple_of)\n\n**Constrained Numeric Types:**\n- `PositiveInteger()` \u2192 Integer > 0\n- `NegativeInteger()` \u2192 Integer < 0\n- `NonNegativeInteger()` \u2192 Integer \u2265 0\n- `NonPositiveInteger()` \u2192 Integer \u2264 0\n- `ConstrainedInteger(ge=x, le=y, multiple_of=z)` \u2192 Custom constraints\n- `ConstrainedBigInt(...)` \u2192 Constrained 64-bit integer\n- `ConstrainedSmallInt(...)` \u2192 Constrained 16-bit integer\n- `ConstrainedTinyInt(...)` \u2192 Constrained 8-bit integer\n\n**Temporal Types:**\n- `Date()` \u2192 Date only\n- `Time()` \u2192 Time only\n- `Timestamp()` \u2192 Date and time with timezone\n- `DateTime()` \u2192 Date and time without timezone\n\n**Other Types:**\n- `Boolean()` / `Bool()` \u2192 Boolean with flexible parsing\n- `Binary(length)` \u2192 Fixed binary\n- `VarBinary(max_length)` \u2192 Variable binary\n- `Blob()` \u2192 Large binary object\n\n## Pydantic Integration Features\n\n### Pydantic Built-in Types Support\n\nMocksmith now supports automatic mock generation for Pydantic's built-in types:\n\n```python\nfrom pydantic import BaseModel, EmailStr, HttpUrl, IPvAnyAddress, conint, constr\nfrom mocksmith import mockable\n\n@mockable\nclass ServerConfig(BaseModel):\n hostname: constr(min_length=1, max_length=253)\n ip_address: IPvAnyAddress\n port: conint(ge=1, le=65535)\n api_url: HttpUrl\n admin_email: EmailStr\n\n# Generate mock with Pydantic types\nconfig = ServerConfig.mock()\nprint(config.ip_address) # IPv4Address('192.168.1.100')\nprint(config.api_url) # https://example.com\nprint(config.admin_email) # user@example.com\n```\n\n**Tip**: For types that have Pydantic equivalents, prefer using Pydantic's built-in types:\n- Use `EmailStr` instead of `mocksmith.specialized.Email`\n- Use `HttpUrl` or `AnyUrl` instead of `mocksmith.specialized.URL`\n- Use `IPvAnyAddress`, `IPv4Address`, or `IPv6Address` for IP addresses\n\n### Using Pydantic Types in Dataclasses\n\nWhile Pydantic types can be used as type annotations in dataclasses, there are important limitations:\n\n```python\nfrom dataclasses import dataclass\nfrom pydantic import EmailStr, HttpUrl, conint\n\n@dataclass\nclass ServerConfig:\n hostname: str\n email: EmailStr # Works as type hint only\n port: conint(ge=1, le=65535) # No validation!\n\n# This creates an instance WITHOUT validation\nserver = ServerConfig(\n hostname=\"api.example.com\",\n email=\"invalid-email\", # Not validated!\n port=99999 # Out of range but accepted!\n)\n```\n\n**Key Points**:\n- Pydantic types in dataclasses serve as type hints only\n- No automatic validation occurs\n- Mock generation works but produces regular Python types (str, int, etc.)\n- For validation, use Pydantic's BaseModel instead\n\nSee the Pydantic types limitations section in [`examples/dataclass_example.py`](examples/dataclass_example.py) for a complete comparison.\n\n### Supported Pydantic Types for Mock Generation\n\nThe `@mockable` decorator supports automatic mock generation for the following Pydantic types:\n\n#### Network Types\n- `HttpUrl` - Generates valid HTTP/HTTPS URLs\n- `AnyHttpUrl` - Generates any HTTP scheme URLs\n- `EmailStr` - Generates valid email addresses\n- `IPvAnyAddress` - Generates IPv4 or IPv6 addresses (80% IPv4, 20% IPv6)\n- `IPvAnyInterface` - Generates IP addresses with CIDR notation\n- `IPvAnyNetwork` - Generates IP network addresses\n\n#### Numeric Types\n- `PositiveInt` - Integers > 0\n- `NegativeInt` - Integers < 0\n- `NonNegativeInt` - Integers >= 0\n- `NonPositiveInt` - Integers <= 0\n- `PositiveFloat` - Floats > 0\n- `NegativeFloat` - Floats < 0\n- `NonNegativeFloat` - Floats >= 0\n- `NonPositiveFloat` - Floats <= 0\n\n#### String/Identifier Types\n- `UUID1`, `UUID3`, `UUID4`, `UUID5` - Generates UUIDs (currently all as UUID4)\n- `SecretStr` - Generates password-like strings\n- `Json` - Generates valid JSON strings\n\n#### Date/Time Types\n- `FutureDate` - Generates dates in the future\n- `PastDate` - Generates dates in the past\n- `FutureDatetime` - Generates datetimes in the future\n- `PastDatetime` - Generates datetimes in the past\n\n#### Constraint Types\n- `conint(ge=1, le=100)` - Integers with min/max constraints\n- `confloat(ge=0.0, le=1.0)` - Floats with min/max constraints\n- `constr(min_length=1, max_length=50)` - Strings with length constraints\n- `constr(pattern=r\"^[A-Z]{3}[0-9]{3}$\")` - Strings matching regex patterns (limited support)\n- `conlist(item_type, min_length=1, max_length=10)` - Lists with constraints\n\n#### Example Usage\n\n```python\nfrom pydantic import BaseModel, EmailStr, HttpUrl, conint, PositiveInt\nfrom mocksmith import mockable\n\n@mockable\nclass UserProfile(BaseModel):\n user_id: PositiveInt\n email: EmailStr\n website: HttpUrl\n age: conint(ge=18, le=120)\n\n# Generate mock data\nuser = UserProfile.mock()\nprint(user.email) # \"john.doe@example.com\"\nprint(user.website) # \"https://example.com\"\nprint(user.age) # 42 (between 18-120)\n```\n\n**Note**: When using Pydantic types in dataclasses (not BaseModel), the types work as annotations only without validation. The mock generation still works but produces regular Python types.\n\n### Handling Unsupported Types\n\nWhen `@mockable` encounters an unsupported type, it attempts to handle it intelligently:\n\n1. **Common types** (Path, Set, FrozenSet) - Now supported with appropriate mock values\n2. **Auto-instantiable types** - Tries to create instances with `()`, `None`, `\"\"`, or `0`\n3. **Truly unsupported types** - Returns `None` with a warning to help identify gaps in type support\n\n#### Newly Supported Types\n```python\nfrom dataclasses import dataclass\nfrom pathlib import Path\nfrom typing import Set, FrozenSet\nfrom mocksmith import mockable\n\n@mockable\n@dataclass\nclass Config:\n config_path: Path # \u2713 Generates Path('/tmp/mock_file.txt')\n data_dir: Path # \u2713 Smart naming: Path('/tmp/mock_directory')\n tags: Set[str] # \u2713 Generates {'tag1', 'tag2', ...}\n frozen_tags: FrozenSet[int] # \u2713 Generates frozenset({1, 2, 3})\n\nconfig = Config.mock()\n# All fields get appropriate mock values!\n```\n\n#### Warning System\n```python\nclass CustomType:\n def __init__(self, required_arg):\n # Cannot be auto-instantiated\n pass\n\n@mockable\n@dataclass\nclass Example:\n name: str # \u2713 Supported\n custom_required: CustomType # \u26a0\ufe0f Warning issued, returns None\n custom_optional: Optional[CustomType] = None # \u26a0\ufe0f Warning issued (if attempted), returns None\n\n# Console output:\n# UserWarning: mocksmith: Unsupported type 'CustomType' for field 'custom_required'.\n# Returning None. Consider making this field Optional or providing a mock override.\n```\n\n**Important Notes**:\n- **All unsupported types trigger warnings** - This helps identify gaps in mocksmith's type support\n- **Warnings help improve mocksmith** - If you encounter warnings, please file an issue on GitHub\n- **Optional fields** - May show warnings ~80% of the time (when generation is attempted)\n- **Override unsupported types** - Use `mock()` with overrides: `Example.mock(custom_required=CustomType('value'))`\n- **Pydantic models** - Make unsupported fields `Optional` to avoid validation errors\n\n### Optional Fields Pattern\n\nPython's `Optional` type indicates fields that can be None:\n\n```python\nfrom typing import Optional\nfrom pydantic import BaseModel\nfrom mocksmith import Varchar, Integer, Text\n\nclass Example(BaseModel):\n # Required field\n required_field: Varchar(50)\n\n # Optional field (can be None)\n optional_field: Optional[Varchar(50)] = None\n\n # Field with default value\n status: Varchar(20) = \"active\"\n```\n\n**Best Practice**: For optional fields, use `Optional[Type]` with `= None`:\n```python\nbio: Optional[Text()] = None # Clear and explicit\nphone: Optional[Varchar(20)] = None # Optional field with no default\n```\n\n### Automatic Type Conversion\n\n```python\nfrom pydantic import BaseModel\nfrom mocksmith import Money, Boolean, Date, Timestamp\n\nclass Order(BaseModel):\n # String to Decimal conversion\n total: Money()\n\n # Flexible boolean parsing\n is_paid: Boolean()\n\n # String to date conversion\n order_date: Date()\n\n # String to datetime conversion\n created_at: Timestamp(with_timezone=False)\n\n# All these string values are automatically converted\norder = Order(\n total=\"99.99\", # \u2192 Decimal('99.99')\n is_paid=\"yes\", # \u2192 True\n order_date=\"2023-12-15\", # \u2192 date(2023, 12, 15)\n created_at=\"2023-12-15T10:30:00\" # \u2192 datetime\n)\n```\n\n### Field Validation with Pydantic\n\n```python\nfrom pydantic import BaseModel, field_validator\nfrom mocksmith import Varchar, Integer, Money\n\nclass Product(BaseModel):\n name: Varchar(50)\n price: Money()\n quantity: Integer()\n\n @field_validator('price')\n def price_must_be_positive(cls, v):\n if v <= 0:\n raise ValueError('Price must be positive')\n return v\n\n @field_validator('quantity')\n def quantity_non_negative(cls, v):\n if v < 0:\n raise ValueError('Quantity cannot be negative')\n return v\n```\n\n### Model Configuration\n\n```python\nfrom pydantic import BaseModel, ConfigDict\nfrom mocksmith import Varchar, Money, Timestamp\n\nclass StrictModel(BaseModel):\n model_config = ConfigDict(\n # Validate on assignment\n validate_assignment=True,\n # Use Enum values\n use_enum_values=True,\n # Custom JSON encoders\n json_encoders={\n Decimal: str,\n datetime: lambda v: v.isoformat()\n }\n )\n\n name: Varchar(100)\n price: Money()\n updated_at: Timestamp()\n```\n\n## Working Examples\n\nFor complete working examples, see the [`examples/`](examples/) directory:\n\n- [`dataclass_example.py`](examples/dataclass_example.py) - Comprehensive dataclass examples including:\n - All data types (String, Numeric, Date/Time, Binary, Boolean)\n - Constrained numeric types (PositiveInteger, NonNegativeInteger, etc.)\n - Custom constraints (min_value, max_value, multiple_of)\n - TINYINT usage for small bounded values\n - REAL vs FLOAT distinction\n - SQL serialization\n - Validation and error handling\n\n- [`pydantic_example.py`](examples/pydantic_example.py) - Comprehensive Pydantic examples including:\n - All data types with automatic validation\n - Field validators and computed properties\n - Constrained types with complex business logic\n - JSON serialization with custom encoders\n\n- [`dataclass_mock_example.py`](examples/dataclass_mock_example.py) - Mock data generation examples:\n - Using `@mockable` decorator with dataclasses\n - Generating mock instances with `.mock()`\n - Override specific fields\n - Type-safe builder pattern\n - Specialized types (Email, CountryCode, etc.)\n\n- [`pydantic_mock_example.py`](examples/pydantic_mock_example.py) - Mock data generation with Pydantic:\n - Using `@mockable` decorator with Pydantic models\n - Same mock API as dataclasses\n - Automatic validation of generated data\n - Specialized types with DBTypeValidator\n - Model configuration and validation on assignment\n - TINYINT and REAL type usage\n - Boolean type conversions\n\n- [`constrained_types_example.py`](examples/constrained_types_example.py) - Constrained types with validation:\n - PositiveMoney, NonNegativeMoney, ConstrainedMoney usage\n - ConstrainedDecimal with precision and range constraints\n - ConstrainedFloat for percentages and probabilities\n - Mock generation respecting all constraints\n - Validation examples showing error handling\n - Builder pattern with constrained types\n\n### Example: E-commerce Order System\n\n```python\nfrom dataclasses import dataclass\nfrom typing import Optional\nfrom datetime import datetime, date\nfrom decimal import Decimal\n\nfrom mocksmith import Varchar, Integer, Date, DecimalType, Text, BigInt, Timestamp\n@dataclass\nclass Customer:\n customer_id: Integer()\n first_name: Varchar(50)\n last_name: Varchar(50)\n email: Varchar(100)\n phone: Optional[Varchar(20)]\n date_of_birth: Optional[Date()]\n\n@dataclass\nclass Order:\n order_id: BigInt()\n customer_id: Integer()\n order_date: Timestamp(with_timezone=False)\n total_amount: DecimalType(12, 2)\n status: Varchar(20)\n notes: Optional[Text()]\n\n# Create instances\ncustomer = Customer(\n customer_id=1,\n first_name=\"Jane\",\n last_name=\"Smith\",\n email=\"jane.smith@email.com\",\n phone=\"+1-555-0123\",\n date_of_birth=date(1990, 5, 15)\n)\n\norder = Order(\n order_id=1001,\n customer_id=1,\n order_date=datetime(2023, 12, 15, 14, 30, 0),\n total_amount=Decimal(\"299.99\"),\n status=\"pending\",\n notes=\"Rush delivery requested\"\n)\n\n# Convert to SQL-ready format\nprint(order.to_sql_dict())\n```\n\nFor more complete examples including financial systems, authentication, and SQL testing integration,\nsee the [`examples/`](examples/) directory.\n\n### Validation in Dataclasses\n\nPlain dataclasses don't provide validation for mocksmith types. For validation, use Pydantic BaseModel:\n\n```python\nfrom pydantic import BaseModel\nfrom mocksmith import SmallInt\n\nclass Config(BaseModel): # Use BaseModel for validation\n hour: SmallInt(ge=0, le=23)\n\n# Validation happens automatically\ntry:\n config = Config(hour=24) # Raises ValidationError\nexcept ValidationError as e:\n print(f\"Validation error: {e}\")\n\nconfig = Config(hour=12) # Works fine\n```\n\n## Advanced Features\n\n### Custom Validation with Pydantic\n\n```python\nfrom pydantic import BaseModel\n\nclass CustomProduct(BaseModel):\n sku: Varchar(20) # Required field\n name: Varchar(100) # Required field\n description: Optional[Varchar(500)] = None # Optional field\n```\n\n### Working with Different Types\n\n```python\n# Integer types with range validation\nsmall_value = SMALLINT()\nsmall_value.validate(32767) # OK\n# small_value.validate(32768) # Raises ValueError - out of range\n\n# Decimal with precision\nmoney = DECIMAL(19, 4)\nmoney.validate(\"12345.6789\") # OK\n# money.validate(\"12345.67890\") # Raises ValueError - too many decimal places\n\n# Time with precision\ntimestamp = TIMESTAMP(precision=0) # No fractional seconds\ntimestamp.validate(\"2023-12-15T10:30:45.123456\") # Microseconds will be truncated\n\n# Boolean accepts various formats\nbool_type = BOOLEAN()\nbool_type.deserialize(\"yes\") # True\nbool_type.deserialize(\"1\") # True\nbool_type.deserialize(\"false\") # False\nbool_type.deserialize(0) # False\n```\n\n### Constrained Numeric Types\n\n**Important:** All numeric types in mocksmith strictly enforce SQL bounds and validate at instantiation time. For example, `TinyInt` enforces the TINYINT range of -128 to 127, preventing invalid data from being created or generated.\n\nThe library provides specialized numeric types with built-in constraints for common validation scenarios:\n\n```python\nfrom mocksmith import Integer, PositiveInteger, NonNegativeInteger\n\n# Enhanced Integer functions - no constraints = standard type\nid: Integer() # Standard 32-bit integer\nquantity: Integer(ge=0) # With constraints (same as NonNegativeInteger)\ndiscount: Integer(ge=0, le=100) # Percentage 0-100\nprice: Integer(gt=0) # Same as PositiveInteger()\n\n# Specialized constraint types\nid: PositiveInteger() # > 0\nquantity: NonNegativeInteger() # >= 0\n```\n\nFor complete examples with both dataclasses and Pydantic, see:\n- [`examples/dataclass_example.py`](examples/dataclass_example.py) - All constraint examples with dataclasses\n- [`examples/pydantic_example.py`](examples/pydantic_example.py) - All constraint examples with Pydantic\n\n**Available Constraint Options:**\n\n```python\n# Enhanced Integer functions - no constraints = standard type\nInteger() # Standard 32-bit integer\nInteger(ge=0) # With constraints\nInteger(gt=0) # Shortcut for > 0\nBigInt() # Standard 64-bit integer\nBigInt(ge=0, le=1000000) # With constraints\nSmallInt() # Standard 16-bit integer\nSmallInt(multiple_of=10) # With constraints\n\n# Specialized constraint types\nPositiveInteger() # > 0\nNegativeInteger() # < 0\nNonNegativeInteger() # >= 0\nNonPositiveInteger() # <= 0\n\n# Full constraint options\nInteger(\n gt=10, # Value must be greater than 10\n ge=10, # Value must be greater than or equal to 10\n lt=100, # Value must be less than 100\n le=100, # Value must be less than or equal to 100\n multiple_of=5, # Must be divisible by this\n)\n```\n\n### Constrained Money and Decimal Types\n\nmocksmith provides constrained versions of Money and Decimal types using Pydantic's constraint system:\n\n```python\nfrom mocksmith import (\n ConstrainedMoney, PositiveMoney, NonNegativeMoney,\n ConstrainedDecimal, ConstrainedFloat\n)\n\n# Money with constraints\nprice: PositiveMoney() # > 0\nbalance: NonNegativeMoney() # >= 0\ndiscount: ConstrainedMoney(ge=0, le=100) # 0-100 range\npayment: ConstrainedMoney(gt=0, le=10000) # 0 < payment <= 10000\n\n# Decimal with precision and constraints\nweight: ConstrainedDecimal(10, 2, gt=0) # Positive weight, max 10 digits, 2 decimal places\ntemperature: ConstrainedDecimal(5, 2, ge=-273.15) # Above absolute zero\n\n# Float with constraints\npercentage: ConstrainedFloat(ge=0.0, le=1.0) # 0-1 range\nrate: ConstrainedFloat(gt=0, lt=0.5) # 0 < rate < 0.5\n```\n\nThese constrained types:\n- Work seamlessly with Pydantic validation\n- Generate appropriate mock data respecting constraints\n- Provide the same clean API as other mocksmith types\n- Fall back gracefully if Pydantic is not available\n\n**Example Usage:**\n\n```python\nfrom pydantic import BaseModel\nfrom mocksmith import mockable, PositiveMoney, NonNegativeMoney, ConstrainedMoney, ConstrainedFloat\n\n@mockable\nclass Order(BaseModel):\n subtotal: PositiveMoney() # Must be > 0\n discount: ConstrainedMoney(ge=0, le=50) # 0-50 range\n tax: NonNegativeMoney() # >= 0\n discount_rate: ConstrainedFloat(ge=0, le=0.3) # 0-30%\n\n# Validation works\norder = Order(\n subtotal=\"100.00\", # \u2713 Converts to Decimal\n discount=\"25.00\", # \u2713 Within 0-50 range\n tax=\"8.50\", # \u2713 Non-negative\n discount_rate=0.15 # \u2713 15% is within 0-30%\n)\n\n# Mock generation respects constraints\nmock_order = Order.mock()\nassert mock_order.subtotal > 0\nassert 0 <= mock_order.discount <= 50\nassert mock_order.tax >= 0\nassert 0 <= mock_order.discount_rate <= 0.3\n```\n\n## Migration Guide from V2 to V3\n\n### Breaking Changes\n\nV3 introduces a critical breaking change to prevent confusion and subtle bugs:\n\n1. **Direct class imports are removed** - `from mocksmith import VARCHAR` no longer works\n2. **Only factory functions are available** - Use `Varchar()`, not `VARCHAR()`\n3. **DBTypeValidator is removed** - Types work directly with Pydantic\n\n### Why This Change?\n\nIn V2, importing and using `VARCHAR(30)` would create a type class. In V3's simplified pattern, this would create a string instance with value \"30\" - highly confusing! To prevent this dangerous ambiguity, direct class access has been removed entirely.\n\n### Migration Steps\n\n```python\n# \u274c OLD V2 CODE (No longer works)\nfrom mocksmith import VARCHAR, INTEGER, BOOLEAN\nfrom mocksmith.pydantic_integration import DBTypeValidator\nfrom typing import Annotated\n\nclass User(BaseModel):\n username: Annotated[str, DBTypeValidator(VARCHAR(30))]\n age: Annotated[int, DBTypeValidator(INTEGER())]\n active: Annotated[bool, DBTypeValidator(BOOLEAN())]\n\n# \u2705 NEW V3 CODE (Clean and simple)\nfrom mocksmith import Varchar, Integer, Boolean\n\nclass User(BaseModel):\n username: Varchar(30) # Direct usage!\n age: Integer()\n active: Boolean()\n```\n\n### Common Migration Patterns\n\n| Old V2 Pattern | New V3 Pattern |\n|----------------|----------------|\n| `from mocksmith import VARCHAR` | `from mocksmith import Varchar` |\n| `from mocksmith.types.string import VARCHAR` | Not available - use factory functions |\n| `Annotated[str, DBTypeValidator(VARCHAR(30))]` | `Varchar(30)` |\n| `VARCHAR(30)` (creates type) | `Varchar(30)` (creates type) |\n| `INTEGER()` | `Integer()` |\n| `DECIMAL(10, 2)` | `DecimalType(10, 2)` |\n| `BOOLEAN()` | `Boolean()` |\n| `DATE()` | `Date()` |\n| `TIMESTAMP()` | `Timestamp()` |\n\n### Benefits of V3\n\n1. **Cleaner API** - No more `DBTypeValidator` or `Annotated` boilerplate\n2. **Type safety** - Factory functions always return type classes\n3. **No confusion** - Can't accidentally create instances when you mean types\n4. **Better IDE support** - Direct type usage improves autocomplete\n5. **Simpler codebase** - Less complexity, easier to maintain\n\n## Development\n\n1. Clone the repository:\n```bash\ngit clone https://github.com/gurmeetsaran/mocksmith.git\ncd mocksmith\n```\n\n2. Install Poetry (if not already installed):\n```bash\ncurl -sSL https://install.python-poetry.org | python3 -\n```\n\n3. Install dependencies:\n```bash\npoetry install\n```\n\n4. Set up pre-commit hooks:\n```bash\npoetry run pre-commit install\n```\n\n5. Run tests:\n```bash\nmake test\n```\n\n### Development Commands\n\n- `make lint` - Run linting (ruff + pyright)\n- `make format` - Format code (black + isort + ruff fix)\n- `make test` - Run tests\n- `make test-cov` - Run tests with coverage\n- `make check-all` - Run all checks (lint + format check + tests)\n- `make check-consistency` - Verify pre-commit, Makefile, and CI are in sync\n\n### Ensuring Consistency\n\nTo ensure your development environment matches CI/CD:\n\n```bash\n# Check that pre-commit hooks match Makefile and GitHub Actions\nmake check-consistency\n```\n\nThis will verify that all tools (black, isort, ruff, pyright) are configured consistently across:\n- Pre-commit hooks (`.pre-commit-config.yaml`)\n- Makefile commands\n- GitHub Actions workflows\n\n## License\n\nMIT\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Type-safe data validation and mocking for Python dataclasses and Pydantic models",
"version": "6.0.1",
"project_urls": {
"Bug Tracker": "https://github.com/gurmeetsaran/mocksmith/issues",
"Homepage": "https://github.com/gurmeetsaran/mocksmith",
"Repository": "https://github.com/gurmeetsaran/mocksmith"
},
"split_keywords": [
"mock",
" validation",
" dataclass",
" pydantic",
" testing",
" faker",
" types",
" sql"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "d1ea6d7e4425c97d77b9057da8295603db171914761ef13c391e84aeb19996e5",
"md5": "e4f1f8d641565af8ef59ad6ce5f097c5",
"sha256": "dc3d70d586b2b33e1bd2eefed73b9cc1265615157bdf3b52aef563974fb49da6"
},
"downloads": -1,
"filename": "mocksmith-6.0.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "e4f1f8d641565af8ef59ad6ce5f097c5",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 47191,
"upload_time": "2025-08-11T05:24:03",
"upload_time_iso_8601": "2025-08-11T05:24:03.248272Z",
"url": "https://files.pythonhosted.org/packages/d1/ea/6d7e4425c97d77b9057da8295603db171914761ef13c391e84aeb19996e5/mocksmith-6.0.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "c27218d9c52e62785e724a40250e6ee2883a5fefc6a517cb483415c3b3451b6b",
"md5": "24fc8e818a3f9eb1961a9ffac7679ca0",
"sha256": "5820932ed715a26ebce7b782b55a1a9c758b41ae0e9bb848edcae7afa391bc79"
},
"downloads": -1,
"filename": "mocksmith-6.0.1.tar.gz",
"has_sig": false,
"md5_digest": "24fc8e818a3f9eb1961a9ffac7679ca0",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 49507,
"upload_time": "2025-08-11T05:24:04",
"upload_time_iso_8601": "2025-08-11T05:24:04.788594Z",
"url": "https://files.pythonhosted.org/packages/c2/72/18d9c52e62785e724a40250e6ee2883a5fefc6a517cb483415c3b3451b6b/mocksmith-6.0.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-11 05:24:04",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "gurmeetsaran",
"github_project": "mocksmith",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "mocksmith"
}