
Security News
Software Engineering Daily Podcast: Feross on AI, Open Source, and Supply Chain Risk
Socket CEO Feross Aboukhadijeh joins Software Engineering Daily to discuss modern software supply chain attacks and rising AI-driven security risks.
mocksmith
Advanced tools
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.
name: Varchar(50)price: PositiveMoney(), age: Integer(ge=0, le=120)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
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:
# Standard installation (includes mock generation)
pip install mocksmith
# With Pydantic validation support (recommended)
pip install "mocksmith[pydantic]"
Requirements:
The standard installation includes Faker for mock data generation and custom validation logic. Adding Pydantic provides better performance and integration with Pydantic types.
The library organizes types into two categories:
Core database types are available through factory functions from the main package:
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: Direct class imports (VARCHAR, INTEGER, etc.) have been removed to prevent confusion. Use factory functions (Varchar, Integer, etc.) exclusively.
Specialized types for common use cases are available from the specialized submodule:
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:
pydantic.EmailStrpydantic.HttpUrl or pydantic.AnyUrlpydantic.IPvAnyAddress, pydantic.IPv4Address, or pydantic.IPv6AddressThis separation keeps the main namespace clean and makes it clear which types are fundamental database types versus application-specific types.
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 - Comprehensive Pydantic examples with all featuresexamples/dataclass_example.py - Comprehensive dataclass examples with all featuresexamples/pydantic_mock_example.py - Mock data generation with Pydantic modelsexamples/dataclass_mock_example.py - Mock data generation with dataclassesexamples/constrained_types_example.py - Constrained types with validation and mock generationE-commerce Product Model:
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:
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/ - All example files with detailed documentationexamples/pydantic_example.py - All features including constraintsexamples/dataclass_example.py - All features including constraintsGenerate realistic test data automatically with the @mockable decorator:
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:
field: Type() | None works seamlessly with mockingMockSmith fully supports Python 3.10+ pipe union syntax for optional fields:
from mocksmith import Varchar, Integer, BigInt, DateTime, Timestamp, mockable
from pydantic import BaseModel
@mockable
class User(BaseModel):
# Required fields
username: Varchar(50)
# Optional fields using pipe syntax - both work identically!
email: Varchar(100) | None # With Annotated
user_id: BigInt() | None # Simple type
age: Integer(ge=0, le=120) | None # With constraints
created_at: DateTime() | None # Temporal type
last_login: Timestamp() | None # With timezone
# Mock generation handles optional fields automatically
user = User.mock()
# Optional fields will randomly be None or have valid values (~20% None, ~80% value)
print(user.user_id) # Could be: 7786676712978416482 or None
print(user.last_login) # Could be: 2021-05-04 02:28:37+00:00 or None
Note: Both Optional[Type()] and Type() | None syntaxes work identically. Choose based on your Python version and style preference.
See mock examples:
examples/dataclass_mock_example.py - Complete mock examples with dataclasses including enum supportexamples/pydantic_mock_example.py - Complete mock examples with Pydantic including enum support and built-in typesexamples/pipe_syntax_example.py - Python 3.10+ pipe syntax examples with optional fieldsImportant: MockSmith uses factory functions exclusively. The old pattern of importing classes directly (VARCHAR, INTEGER, etc.) is no longer supported.
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()
# β OLD PATTERN (NO LONGER WORKS - REMOVED)
from mocksmith import VARCHAR # This import fails now
varchar_type = VARCHAR(30) # Would create instance "30" - WRONG!
# β
NEW PATTERN (THE ONLY WAY)
from mocksmith import Varchar # Factory function
UsernameType = Varchar(30) # Creates type class - CORRECT!
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 (traditional syntax)
optional_new: Varchar(50) | None = None # Can be None (Python 3.10+ pipe syntax)
with_default: Boolean() = True # Has default value
# All patterns can be mixed in the same model!
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!
)
β DO USE:
field: Varchar(50) - Factory functions for type creationfield: Integer(gt=0) - Factory functions with constraintsfield: Optional[Varchar(50)] = None - For nullable fields (traditional syntax)field: Varchar(50) | None - For nullable fields (Python 3.10+ pipe syntax)BaseModel when you need validationPositiveInteger() for common patternsβ DON'T USE (Removed):
from mocksmith import VARCHAR - Direct class imports removedVARCHAR(30) - Would create instance "30", not a type!All numeric types enforce SQL bounds and validate at instantiation:
Optional fields properly handle None values with both traditional and modern syntax:
from typing import Optional
class User(BaseModel):
name: Varchar(50) # Required
nickname: Optional[Varchar(30)] = None # Optional (traditional syntax)
bio: Varchar(200) | None = None # Optional (Python 3.10+ pipe syntax)
user = User(name="John", nickname=None, bio=None) # β Valid
# Both syntaxes work the same way - choose based on your Python version
# Python 3.10+ supports both, but pipe syntax is more concise
MockSmith types work seamlessly with Python's Literal type for strict value constraints:
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
The library provides a clean, Pythonic interface for defining database types:
String Types:
Varchar(length) β Variable-length stringChar(length) β Fixed-length stringText() β Large text fieldString β Alias for VarcharNumeric 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 decimalNumeric(precision, scale) β Alias for DecimalTypeMoney() β 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 precisionAll numeric types:
TinyInt(200) raises ValueError)TinyInt(gt=5) generates 6-127, not > 127)Constrained Numeric Types:
PositiveInteger() β Integer > 0NegativeInteger() β Integer < 0NonNegativeInteger() β Integer β₯ 0NonPositiveInteger() β Integer β€ 0ConstrainedInteger(ge=x, le=y, multiple_of=z) β Custom constraintsConstrainedBigInt(...) β Constrained 64-bit integerConstrainedSmallInt(...) β Constrained 16-bit integerConstrainedTinyInt(...) β Constrained 8-bit integerTemporal Types:
Date() β Date onlyTime() β Time onlyTimestamp() β Date and time with timezoneDateTime() β Date and time without timezoneOther Types:
Boolean() / Bool() β Boolean with flexible parsingBinary(length) β Fixed binaryVarBinary(max_length) β Variable binaryBlob() β Large binary objectMocksmith now supports automatic mock generation for Pydantic's built-in types:
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:
EmailStr instead of mocksmith.specialized.EmailHttpUrl or AnyUrl instead of mocksmith.specialized.URLIPvAnyAddress, IPv4Address, or IPv6Address for IP addressesWhile Pydantic types can be used as type annotations in dataclasses, there are important limitations:
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:
See the Pydantic types limitations section in examples/dataclass_example.py for a complete comparison.
The @mockable decorator supports automatic mock generation for the following Pydantic types:
HttpUrl - Generates valid HTTP/HTTPS URLsAnyHttpUrl - Generates any HTTP scheme URLsEmailStr - Generates valid email addressesIPvAnyAddress - Generates IPv4 or IPv6 addresses (80% IPv4, 20% IPv6)IPvAnyInterface - Generates IP addresses with CIDR notationIPvAnyNetwork - Generates IP network addressesPositiveInt - Integers > 0NegativeInt - Integers < 0NonNegativeInt - Integers >= 0NonPositiveInt - Integers <= 0PositiveFloat - Floats > 0NegativeFloat - Floats < 0NonNegativeFloat - Floats >= 0NonPositiveFloat - Floats <= 0UUID1, UUID3, UUID4, UUID5 - Generates UUIDs (currently all as UUID4)SecretStr - Generates password-like stringsJson - Generates valid JSON stringsFutureDate - Generates dates in the futurePastDate - Generates dates in the pastFutureDatetime - Generates datetimes in the futurePastDatetime - Generates datetimes in the pastconint(ge=1, le=100) - Integers with min/max constraintsconfloat(ge=0.0, le=1.0) - Floats with min/max constraintsconstr(min_length=1, max_length=50) - Strings with length constraintsconstr(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 constraintsfrom 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.
When @mockable encounters an unsupported type, it attempts to handle it intelligently:
(), None, "", or 0None with a warning to help identify gaps in type supportfrom 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!
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:
mock() with overrides: Example.mock(custom_required=CustomType('value'))Optional to avoid validation errorsPython's Optional type indicates fields that can be None:
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:
bio: Optional[Text()] = None # Clear and explicit
phone: Optional[Varchar(20)] = None # Optional field with no default
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
)
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
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()
For complete working examples, see the examples/ directory:
dataclass_example.py - Comprehensive dataclass examples including:
pydantic_example.py - Comprehensive Pydantic examples including:
dataclass_mock_example.py - Mock data generation examples:
@mockable decorator with dataclasses.mock()pydantic_mock_example.py - Mock data generation with Pydantic:
@mockable decorator with Pydantic modelsconstrained_types_example.py - Constrained types with validation:
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/ directory.
Plain dataclasses don't provide validation for mocksmith types. For validation, use Pydantic BaseModel:
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
from pydantic import BaseModel
class CustomProduct(BaseModel):
sku: Varchar(20) # Required field
name: Varchar(100) # Required field
description: Optional[Varchar(500)] = None # Optional field
# 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
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:
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 - All constraint examples with dataclassesexamples/pydantic_example.py - All constraint examples with PydanticAvailable Constraint Options:
# 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
)
mocksmith provides constrained versions of Money and Decimal types using Pydantic's constraint system:
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:
Example Usage:
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
This version introduces a critical breaking change to prevent confusion and subtle bugs:
from mocksmith import VARCHAR no longer worksVarchar(), not VARCHAR()In previous versions, importing and using VARCHAR(30) would create a type class. In the new 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.
# β 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 CODE (Clean and simple)
from mocksmith import Varchar, Integer, Boolean
class User(BaseModel):
username: Varchar(30) # Direct usage!
age: Integer()
active: Boolean()
| Old Pattern | New 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() |
DBTypeValidator or Annotated boilerplategit clone https://github.com/gurmeetsaran/mocksmith.git
cd mocksmith
curl -sSL https://install.python-poetry.org | python3 -
poetry install
poetry run pre-commit install
make test
make lint - Run linting (ruff + pyright)make format - Format code (black + isort + ruff fix)make test - Run testsmake test-cov - Run tests with coveragemake check-all - Run all checks (lint + format check + tests)make check-consistency - Verify pre-commit, Makefile, and CI are in syncTo ensure your development environment matches CI/CD:
# 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-config.yaml)MIT
FAQs
Type-safe data validation and mocking for Python dataclasses and Pydantic models
We found that mocksmith demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Β It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CEO Feross Aboukhadijeh joins Software Engineering Daily to discuss modern software supply chain attacks and rising AI-driven security risks.

Security News
GitHub has revoked npm classic tokens for publishing; maintainers must migrate, but OpenJS warns OIDC trusted publishing still has risky gaps for critical projects.

Security News
Rustβs crates.io team is advancing an RFC to add a Security tab that surfaces RustSec vulnerability and unsoundness advisories directly on crate pages.