No project description provided
Project description
Classno
Classno is a lightweight and extensible Python library for data modeling, schema definition, and validation. It provides a clean and intuitive way to define data classes with various features like type validation, immutability, private fields, and automatic type casting.
Key Features
- Type hints validation - Runtime type checking for all fields
- Immutable objects - Create frozen, hashable instances
- Private fields - Write-once, read-only field access patterns
- Automatic type casting - Lossy autocast between compatible types
- Customizable comparison - Control equality, hashing, and ordering behavior
- Default values and factories - Safe handling of mutable defaults
- Nested object support - Deep validation and casting of complex structures
- Slots optimization - Reduced memory footprint
- Rich comparison methods - Full ordering support
- Union and Optional types - First-class support for
Optional[T]andUnion[T1, T2] - Extended collection types - Support for
frozenset,deque,defaultdict, and more
Installation
pip install classno
Basic Usage
Simple Data Class
from classno import Classno, field
class User(Classno):
name: str
age: int = 0
email: str = field(default="")
# Create an instance
user = User(name="John", age=30)
Features Configuration
Features can be enabled by setting the __features__ class attribute:
from classno import Classno, Features
class Config(Classno):
__features__ = Features.VALIDATION | Features.FROZEN
host: str
port: int = 8080
Available features:
Features.EQ- Enable equality comparisonFeatures.ORDER- Enable ordering operationsFeatures.HASH- Make instances hashableFeatures.SLOTS- Use slots for memory optimizationFeatures.FROZEN- Make instances immutableFeatures.PRIVATE- Enable private field accessFeatures.VALIDATION- Enable type validationFeatures.LOSSY_AUTOCAST- Enable automatic type casting
Field Configuration
Fields can be configured using the field() function:
from classno import Classno, field
from datetime import datetime
class Post(Classno):
title: str
content: str = ""
created_at: datetime = field(default_factory=datetime.now)
metadata: dict = field(default_factory=dict, metadata={"indexed": True})
Important: Always use default_factory for mutable defaults (list, dict, set) to avoid shared state issues:
# ❌ WRONG - This will raise an error
class Wrong(Classno):
tags: list = []
# ✅ CORRECT - Use default_factory
class Correct(Classno):
tags: list = field(default_factory=list)
Type Validation
class ValidatedModel(Classno):
__features__ = Features.VALIDATION
numbers: list[int]
mapping: dict[str, float]
# This will raise TypeError if types don't match
model = ValidatedModel(
numbers=[1, 2, 3],
mapping={"a": 1.0, "b": 2.0}
)
Optional and Union Types
Full support for Optional and Union types with proper validation:
from typing import Optional, Union
class FlexibleModel(Classno):
__features__ = Features.VALIDATION
# Optional field - can be None
optional_name: Optional[str] = None
# Union type - can be str or int
identifier: Union[str, int]
# Complex unions
data: Union[list[str], dict[str, int], None] = None
model = FlexibleModel(optional_name=None, identifier=42)
Extended Collection Types
Support for Python's extended collection types:
from collections import deque, defaultdict, Counter
from typing import Optional
class AdvancedCollections(Classno):
__features__ = Features.VALIDATION | Features.LOSSY_AUTOCAST
# Immutable set
unique_ids: frozenset[int] = field(default_factory=frozenset)
# Double-ended queue
history: deque[str] = field(default_factory=deque)
# Dict with default values
counters: defaultdict[str, int] = field(
default_factory=lambda: defaultdict(int)
)
# Counter for frequency tracking
word_counts: Counter[str] = field(default_factory=Counter)
Immutable Objects
class ImmutableConfig(Classno):
__features__ = Features.IMMUTABLE # Combines FROZEN, SLOTS, and HASH
host: str
port: int = 8080
config = ImmutableConfig(host="localhost")
# Attempting to modify will raise an exception
config.port = 9000 # Raises Exception
Private Fields
class PrivateFields(Classno):
__features__ = Features.PRIVATE
name: str
secret: str # Can only be accessed with _secret prefix for rw, secret for ro
obj = PrivateFields(name="public")
obj._secret = "hidden" # OK
obj.secret # OK
obj.secret = "hidden" # Raises Exception
Nested Objects
class Address(Classno):
street: str
city: str
class Person(Classno):
name: str
address: Address
# Create nested structure
person = Person(
name="John",
address=Address(street="123 Main St", city="Boston")
)
Automatic Type Casting
Enable automatic type conversion with LOSSY_AUTOCAST:
class AutoCastModel(Classno):
__features__ = Features.LOSSY_AUTOCAST
count: int
price: float
active: bool
# Automatic casting from compatible types
model = AutoCastModel(
count="42", # str → int
price="19.99", # str → float
active="true" # str → bool
)
# model.count == 42 (int)
# model.price == 19.99 (float)
# model.active == True (bool)
Combining Features
Features can be combined for powerful data modeling:
class RobustModel(Classno):
# First cast, then validate
__features__ = Features.LOSSY_AUTOCAST | Features.VALIDATION | Features.FROZEN
user_id: int
tags: list[str] = field(default_factory=list)
# This works: "42" is cast to 42, validated, then frozen
model = RobustModel(user_id="42", tags=["python", "classno"])
Feature execution order:
LOSSY_AUTOCAST- Values are automatically cast to target typesVALIDATION- Type validation is performed on cast valuesFROZEN- Object becomes immutable after validation
Customization
Custom Comparison Keys
Control which fields participate in equality, hashing, and ordering:
class CustomCompare(Classno):
__features__ = Features.EQ | Features.HASH | Features.ORDER
# Use tuples for ordered keys (order matters for comparison)
__hash_keys__ = ("id",) # Only id used for hashing
__eq_keys__ = ("id", "name") # id and name for equality
__order_keys__ = ("priority", "name") # Sort by priority, then name
id: int
name: str
priority: int = 0
description: str = ""
# Two objects are equal if id and name match
obj1 = CustomCompare(id=1, name="A", description="First")
obj2 = CustomCompare(id=1, name="A", description="Second")
assert obj1 == obj2 # True - description is ignored
# Ordering uses priority first, then name
items = [
CustomCompare(id=1, name="B", priority=2),
CustomCompare(id=2, name="A", priority=1),
]
sorted_items = sorted(items) # Sorted by priority, then name
Best Practices
- Use type hints for all fields - Enables validation and better IDE support
- Use
default_factoryfor mutable defaults - Always usefield(default_factory=list)instead offield(default=[]) - Enable appropriate features - Only enable features you need (e.g.,
VALIDATIONin development,FROZENfor config) - Use
Features.SLOTS- Reduces memory usage by ~40% for classes with many instances - Combine
LOSSY_AUTOCASTwithVALIDATION- Cast first, then validate for robust data handling - Use tuples for comparison keys -
__eq_keys__ = ("id", "name")not["id", "name"] - Leverage
OptionalandUnion- Use proper type hints for flexible APIs
Error Handling
Classno provides clear, actionable error messages:
# Validation error
class Model(Classno):
__features__ = Features.VALIDATION
age: int
try:
Model(age="not a number")
except ValidationError as e:
# "Validation error for field 'age': expected int, got 'not a number' of type str"
pass
# Mutable default error
try:
class Wrong(Classno):
tags: list = [] # ❌ Error at class definition time
except ValueError as e:
# "Mutable default values are not allowed. Found list [].
# Use default_factory=lambda: [] instead to avoid shared state issues."
pass
# Frozen modification error
class Frozen(Classno):
__features__ = Features.FROZEN
value: int
obj = Frozen(value=42)
try:
obj.value = 100
except AttributeError as e:
# "Cannot modify attributes of frozen class Frozen"
pass
The library raises appropriate exceptions for:
- ValidationError - Type validation failures
- TypeError - Type mismatch during casting or validation
- ValueError - Invalid field configurations (e.g., mutable defaults)
- AttributeError - Immutability violations (FROZEN), invalid field access (PRIVATE)
Advanced Usage
Inheritance
Features and fields are properly inherited:
class BaseModel(Classno):
__features__ = Features.VALIDATION
id: int
class UserModel(BaseModel):
# Inherits VALIDATION feature and id field
name: str
email: str
user = UserModel(id=1, name="John", email="john@example.com")
Serialization
Convert objects to dictionaries for JSON serialization:
class User(Classno):
name: str
age: int
user = User(name="John", age=30)
data = user.as_dict() # {"name": "John", "age": 30}
Copying
Objects support both shallow and deep copying:
import copy
original = User(name="John", age=30)
shallow = copy.copy(original)
deep = copy.deepcopy(original)
Testing
Run the comprehensive test suite:
# Install development dependencies
poetry install
# Run all tests
poetry run poe tests
# Run fast tests (skip slow tests)
poetry run poe test-fast
# Run with coverage
poetry run poe test-all
# Run specific test categories
poetry run poe test-unit # Unit tests
poetry run poe test-integration # Integration tests
poetry run poe test-edge-cases # Edge case tests
Authors
- Dmitriy Kudryavtsev - author - kuderr
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file classno-0.1.0.tar.gz.
File metadata
- Download URL: classno-0.1.0.tar.gz
- Upload date:
- Size: 18.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.3 CPython/3.13.3 Darwin/22.6.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d40279eb91235caa6b6196152b88af605fcd4ad64fe255b029d7a2705c76feaf
|
|
| MD5 |
63fd8ff1b90923a36da87195b3c118e5
|
|
| BLAKE2b-256 |
efb6b18828929de0f99bcf2a43e7bad5e4eff1473acc71087204853143f3a751
|
File details
Details for the file classno-0.1.0-py3-none-any.whl.
File metadata
- Download URL: classno-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.3 CPython/3.13.3 Darwin/22.6.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f76e6441a805d1d8451c7d6f8a20e5e8fa7d9bd6c7fe61f0ca05765f42522e7b
|
|
| MD5 |
81177782de2de91f0da4390b9f6112bd
|
|
| BLAKE2b-256 |
f420510ad4893a7b089c4157baeb16cabde11724711cbcdec13794adc5dd0a80
|