Skip to main content

Python 2/3 兼容的 DataClass 库,支持完整的数据校验功能和自定义错误消息

Project description

Schemas DataClass

Python Version License CI Coverage

A lightweight, Python 2/3 compatible data validation library that brings powerful schema validation to Python classes with a clean decorator-based API. Schemas DataClass combines the simplicity of Python dataclasses with robust validation capabilities, making it ideal for data processing, API validation, and configuration management.

🚀 Why Choose Schemas DataClass?

  • Seamless Python 2/3 Compatibility: Works flawlessly across Python 2.7+ and 3.4+
  • Type-Safe Data Validation: Comprehensive validation for strings, numbers, lists, and nested objects
  • Clean, Pythonic API: Use standard class syntax with decorator-based validation
  • Customizable Error Messages: Internationalization-ready with template formatting
  • Zero Dependencies: Pure Python implementation using only standard libraries
  • Efficient Performance: Lightweight design with minimal overhead
  • Recursive Validation Protection: Safely handles nested and circular references

📦 Installation

From PyPI (Recommended)

pip install schemas-dataclass

From Source

git clone https://github.com/b40yd/schema_dataclass.git
cd dataclass
python setup.py install

For Development

git clone https://github.com/b40yd/schema_dataclass.git
cd dataclass
pip install -e .
pip install -r requirements-dev.txt

🚀 Quick Start

Basic Usage

from schema_dataclass import StringField, NumberField, dataclass, ValidationError

@dataclass
class User(object):
    name = StringField(min_length=2, max_length=50)
    age = NumberField(minvalue=0, maxvalue=120)
    email = StringField(
        regex=r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    )

# Create a user
user = User(name="Alice", age=25, email="alice@example.com")
print(user.to_dict())  # {'name': 'Alice', 'age': 25, 'email': 'alice@example.com'}

Custom Error Messages

@dataclass
class User(object):
    name = StringField(
        min_length=2,
        error_messages={
            'required': 'Name is required',
            'min_length': 'Name must be at least {min_length} characters long'
        }
    )

try:
    user = User(name="A")  # Too short
except ValidationError as e:
    print(e.message)  # Output: Name must be at least 2 characters long

📚 Documentation Index

Installation and Usage

Basic Usage Guide

from schema_dataclass import StringField, NumberField, ListField, dataclass

@dataclass
class User(object):
    name = StringField(min_length=2, max_length=50)
    age = NumberField(minvalue=0, maxvalue=120)
    email = StringField(
        regex=r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    )
    tags = ListField(item_type=str, required=False)

# Create and use
user = User(
    name="Alice",
    age=25,
    email="alice@example.com",
    tags=["developer", "python"]
)

print(user.name)        # Alice
print(user['age'])      # 25
print(user.get('email')) # alice@example.com
print(user.to_dict())   # Convert to dictionary

Core Features

🔧 Field Types Support

  • StringField: String validation

    • Length constraints (min_length, max_length)
    • Regular expression validation (regex)
    • Enumeration validation (choices)
    • Custom error messages with template formatting
  • NumberField: Numeric validation (int, float, long)

    • Range validation (minvalue, maxvalue)
    • Enumeration validation (choices)
    • Type validation with automatic coercion
    • Custom error messages with template formatting
  • ListField: List validation

    • Length constraints (min_length, max_length)
    • Item type validation (item_type)
    • Supports nested types including strings, numbers, and dataclass models
    • Custom error messages with template formatting

🌍 Custom Error Messages

  • Multi-language Ready: Supports internationalization with locale-aware messages
  • Template Formatting: Use {parameter} style formatting for dynamic messages
  • Complete Coverage: Customize error messages for all validation types
  • Backward Compatible: Optional feature that doesn't affect existing code
# Custom error messages example
@dataclass
class User(object):
    name = StringField(
        min_length=3,
        max_length=20,
        error_messages={
            'required': 'Username is required',
            'min_length': 'Username must be at least {min_length} characters long',
            'max_length': 'Username cannot exceed {max_length} characters'
        }
    )

🎯 Decorator Syntax

@dataclass
class User(object):
    name = StringField(min_length=1, max_length=100)
    age = NumberField(minvalue=0, maxvalue=150)

🔍 Custom Validation Decorator

@dataclass
class Product(object):
    name = StringField()
    price = NumberField()
    
    @validate("name")
    def validate_name_custom(self, name):
        if not name.isalnum():
            raise ValidationError("Name must be alphanumeric")
    
    @validate("price")
    def validate_price_custom(self, price):
        if price <= 0:
            raise ValidationError("Price must be positive")

🔧 Custom Get Methods

@dataclass
class BlogPost(object):
    title = StringField()
    status = StringField(default='draft')
    
    def get_title(self):
        """Custom method to get formatted title"""
        title = self.__dict__.get('title', '')
        status = self.__dict__.get('status', 'draft')
        return "[{0}] {1}".format(status.upper(), title)

🌐 Nested DataClass Support

@dataclass
class Address(object):
    street = StringField()
    city = StringField()
    zip_code = StringField()

@dataclass
class User(object):
    name = StringField()
    address = Address  # Class reference (auto-instantiated)
    addresses = ListField(item_type=Address)  # List of nested objects

Complete Examples

📁 Example Files

The project provides rich examples in the examples/ directory:

🚀 Running Examples

# Basic usage example
python examples/basic_usage.py

# Custom error messages example
python examples/custom_error_messages.py

# Advanced features example
python examples/advanced_features.py

# Real world examples
python examples/real_world_examples.py

💡 Quick Example

User Management System

from schema_dataclass import StringField, NumberField, ListField, dataclass, validate

@dataclass
class User(object):
    username = StringField(
        min_length=3,
        max_length=20,
        regex=r'^[a-zA-Z][a-zA-Z0-9_]*$',
        error_messages={
            'required': 'Username is required',
            'min_length': 'Username must be at least {min_length} characters long',
            'regex': 'Username must start with a letter and contain only letters, numbers, and underscores'
        }
    )
    
    email = StringField(
        regex=r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
        error_messages={
            'required': 'Email address is required',
            'regex': 'Please enter a valid email address'
        }
    )
    
    age = NumberField(
        minvalue=13,
        maxvalue=120,
        error_messages={
            'minvalue': 'Age cannot be less than {minvalue}',
            'maxvalue': 'Age cannot be greater than {maxvalue}'
        }
    )
    
    tags = ListField(
        item_type=str,
        required=False,
        max_length=10,
        error_messages={
            'max_length': 'Cannot have more than {max_length} tags'
        }
    )
    
    @validate("username")
    def validate_username_not_reserved(self, username):
        """Check if username is a reserved word"""
        reserved = ['admin', 'root', 'system']
        if username.lower() in reserved:
            raise ValidationError(f"Username '{username}' is a reserved word")

# Usage example
user = User(
    username="alice_dev",
    email="alice@example.com",
    age=28,
    tags=["developer", "python"]
)

print("User: {}".format(user.username))
print("Email: {}".format(user.email))
print("Age: {}".format(user.age))
print("Tags: {}".format(user.tags))

API Reference

Important Change Notice: Starting from version 2.0, all fields are optional by default (required=False). For required fields, explicitly set required=True.

Field Types

StringField

StringField(
    default=None,           # Default value
    alias=None,            # Field alias
    required=False,        # Whether the field is required (default: False)
    min_length=None,       # Minimum length
    max_length=None,       # Maximum length
    regex=None,            # Regular expression pattern
    choices=None,          # Enumeration options
    error_messages=None    # Custom error messages
)

NumberField

NumberField(
    default=None,           # Default value
    alias=None,            # Field alias
    required=False,        # Whether the field is required (default: False)
    minvalue=None,         # Minimum value
    maxvalue=None,         # Maximum value
    choices=None,          # Enumeration options
    error_messages=None    # Custom error messages
)

ListField

ListField(
    default=None,           # Default value
    alias=None,            # Field alias
    required=False,        # Whether the field is required (default: False)
    min_length=None,       # Minimum length
    max_length=None,       # Maximum length
    item_type=None,        # Type of list items
    error_messages=None    # Custom error messages
)

Decorators

@dataclass

@dataclass
class MyClass(object):
    field1 = StringField()
    field2 = NumberField()

@validate

@dataclass
class MyClass(object):
    field1 = StringField()

    @validate("field1")
    def validate_field1(self, value):
        # Custom validation logic
        if not condition:
            raise ValidationError("Custom validation failed")

Error Message Keys

Common Error Message Keys

  • required: Required field is empty
  • invalid_type: Type mismatch

StringField Error Message Keys

  • min_length: Length below minimum
  • max_length: Length above maximum
  • regex: Regular expression mismatch
  • choices: Value not in enumeration options

NumberField Error Message Keys

  • minvalue: Value below minimum
  • maxvalue: Value above maximum
  • choices: Value not in enumeration options

ListField Error Message Keys

  • min_length: List length below minimum
  • max_length: List length above maximum
  • invalid_list_item: List item type mismatch

Validation Features

String Validation

  • Length validation: min_length, max_length
  • Regular expression validation: regex
  • Enumeration validation: choices
  • Custom error messages for all validation types

Number Validation

  • Range validation: minvalue, maxvalue
  • Enumeration validation: choices
  • Type validation: automatic support for int, float, long (Python 2)
  • Custom error messages for all validation types

List Validation

  • Length validation: min_length, max_length
  • Item type validation: item_type
  • Supports nesting: strings, numbers, dataclass models
  • Custom error messages for list item type errors

DataClass Field Support

  • Support dataclass as field types
  • Automatic instantiation and validation
  • Re-creation of objects on reassignment
  • Support nested to_dict() conversion
  • Validation on reassignment

Custom Validation

  • Use @validate("field_name") decorator
  • Executed after basic validation
  • Support multiple custom validation functions

Custom Error Messages Features

  • Multi-language Support: Full support for Chinese, English, and other languages
  • Template Formatting: Support {parameter} style parameter replacement
  • Complete Coverage: Support custom error messages for all validation types
  • Backward Compatibility: Doesn't affect existing code, optional usage
  • Robustness: Graceful degradation when formatting fails, returns original template
  • Zero Performance Impact: Same performance as original version when not using custom messages

Supported Error Message Types

  • Common: required, invalid_type
  • StringField: min_length, max_length, regex, choices
  • NumberField: minvalue, maxvalue, choices
  • ListField: min_length, max_length, invalid_list_item

Testing

Running Tests

# Run all tests
pytest

# Run specific test file
pytest tests/test_fields.py

# Run tests with coverage
pytest --cov=schema_dataclass

# Run tests with specific markers
pytest -m "unit"
pytest -m "integration"
pytest -m "error_messages"

Test Structure

tests/
├── conftest.py                    # pytest configuration and fixtures
├── test_fields.py                 # Field type tests
├── test_custom_error_messages.py  # Custom error messages tests
├── test_dataclass.py             # dataclass functionality tests
└── test_integration.py           # Integration tests

Test Coverage

  • 25+ test cases covering all functionality
  • 100% test pass rate
  • Backward compatibility verification
  • Multi-language error message tests
  • Complex scenario boundary testing

Compatibility

  • Python 2.7+: Fully supported
  • Python 3.4+: Fully supported
  • PyPy: Supported
  • Jython: Theoretically supported (untested)

Performance

  • Zero Dependencies: Uses only Python standard library
  • Lightweight: Core code under 1000 lines
  • High Performance: Fast validation with low memory usage
  • Extensible: Easy to add new field types and validation rules

Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the project
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Add test cases
  4. Ensure all tests pass (pytest)
  5. Update relevant documentation
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Create a Pull Request

Development Environment Setup

git clone https://github.com/b40yd/schema_dataclass.git
cd dataclass
pip install -e .
pip install -r requirements-dev.txt

Code Guidelines

  • Follow PEP 8 coding style
  • Add appropriate docstrings
  • Add test cases for new features
  • Maintain Python 2/3 compatibility

License

This project is licensed under the GNU General Public License v3.0. See the LICENSE file for details.

Changelog

Check CHANGELOG.md for detailed version history and updates.


Note: This library is fully compatible with Python 2.7 and Python 3.x. Custom error messages are an optional feature that doesn't affect the usage of existing code.

Project details


Download files

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

Source Distribution

schema_dataclass-0.0.3.tar.gz (55.4 kB view details)

Uploaded Source

Built Distribution

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

schema_dataclass-0.0.3-py3-none-any.whl (26.6 kB view details)

Uploaded Python 3

File details

Details for the file schema_dataclass-0.0.3.tar.gz.

File metadata

  • Download URL: schema_dataclass-0.0.3.tar.gz
  • Upload date:
  • Size: 55.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.3

File hashes

Hashes for schema_dataclass-0.0.3.tar.gz
Algorithm Hash digest
SHA256 6a3098dcfa289200aeb9947bb0355f321a9fbbab71cc7c87c507a26c247488da
MD5 d6708319094e3f69ce1a8ba536db0786
BLAKE2b-256 aac5f682bb8841a10db20a38b6768731a85e7caa12b79b6325c8e3b82e14caa2

See more details on using hashes here.

File details

Details for the file schema_dataclass-0.0.3-py3-none-any.whl.

File metadata

File hashes

Hashes for schema_dataclass-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 ad3a47889a6191de611c46b57026faa57061538ee86c232040d4c1aa70269065
MD5 9aba3f54d660cb36a6f1944d17600ce2
BLAKE2b-256 57f24e7e8a1f023d2554bb26eefcfc08f0ac7872582d6a0db3999a71f8456efb

See more details on using hashes here.

Supported by

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