Dynamic Python utilities for class registration, creation, and type checking
Project description
Morphic
Dynamic Python utilities for class registration, creation, and type checking.
Features
- Registry: Dynamic class registration and factory pattern for building extensible architectures
- AutoEnum: Automatic enumeration creation from class hierarchies with type safety
- Typed: Enhanced data modeling with validation and serialization capabilities
Installation
From PyPI
pip install morphic
From Source
pip install git+https://github.com/adivekar-utexas/morphic.git
Development Installation
git clone https://github.com/adivekar-utexas/morphic.git
cd morphic
# Install with all dependencies (dev + docs)
pip install -e ".[all]"
# Or install specific dependency groups
pip install -e ".[dev]" # Development dependencies only
pip install -e ".[docs]" # Documentation dependencies only
pip install -e ".[dev,docs]" # Both dev and docs
Quick Start
Registry System: Inheritance-Based Class Registration
from morphic import Registry
from abc import ABC, abstractmethod
# Create base registry class
class NotificationService(Registry, ABC):
@abstractmethod
def send(self, to: str, message: str) -> bool:
pass
# Classes automatically register when inheriting
class EmailService(NotificationService):
aliases = ["email", "mail"] # Multiple aliases supported
def __init__(self, smtp_server: str = "localhost"):
self.smtp_server = smtp_server
def send(self, to: str, message: str) -> bool:
print(f"Sending email to {to} via {self.smtp_server}")
return True
class SMSService(NotificationService):
aliases = ["sms", "text"]
def send(self, to: str, message: str) -> bool:
print(f"Sending SMS to {to}")
return True
# Hierarchical factory pattern - create instances through base class
email_service = NotificationService.of("EmailService", smtp_server="mail.example.com")
sms_service = NotificationService.of("sms") # Works with aliases too!
# Direct instantiation works for concrete classes
email_direct = EmailService.of(smtp_server="direct.mail.com")
# Use the services
email_service.send("user@example.com", "Hello!")
sms_service.send("+1234567890", "Hello!")
AutoEnum: Ultra-Fast Fuzzy-Matching Enums
from morphic import AutoEnum, alias, auto
import json
# Create enum with fuzzy matching and aliases
class TaskStatus(AutoEnum):
PENDING = alias("waiting", "queued", "not_started")
RUNNING = alias("active", "in_progress", "executing")
COMPLETE = alias("done", "finished", "success")
FAILED = alias("error", "failure", "crashed")
# Fuzzy matching works with various formats
status1 = TaskStatus("pending") # Direct match
status2 = TaskStatus("IN PROGRESS") # Case insensitive + space handling
status3 = TaskStatus("not-started") # Alias with different formatting
status4 = TaskStatus("Done") # Alias with different case
# JSON compatibility (unlike standard enums!)
data = [TaskStatus.PENDING, TaskStatus.RUNNING]
json_str = json.dumps(data) # Works! -> '["PENDING", "RUNNING"]'
recovered = TaskStatus.convert_list(json.loads(json_str)) # Back to enums!
# Dynamic enum creation
Priority = AutoEnum.create("Priority", ["low", "medium", "high", "urgent"])
print(Priority.Low) # Low
print(Priority("MEDIUM")) # Medium (fuzzy matched)
# Perfect for configuration and user input
config_status = TaskStatus(user_input) # Handles "In Progress", "IN_PROGRESS", etc.
Typed
from morphic import Typed
from typing import Optional, List
class User(Typed):
name: str
email: str
age: int
is_active: bool = True
bio: Optional[str] = None
tags: List[str] = [] # Default empty list
def validate(self):
if self.age < 0:
raise ValueError("Age must be non-negative")
if "@" not in self.email:
raise ValueError("Invalid email format")
# Instantiate like any class with auto type-conversion:
user = User(
name="Alice Johnson",
email="alice@example.com",
age="30", # String automatically converts to int
is_active="true", # String automatically converts to bool
tags=("python", "ai", "data"), # Tuple of strings converted to list of strings.
)
print(f"User: {user.name}, Age: {user.age} ({type(user.age)}), Tags: {user.tags}")
# Output:
# User: Alice Johnson, Age: 30 (<class 'int'>), Tags: ['python', 'ai', 'data']
# Create from dict:
user = User.from_dict({
"name": "Alice Johnson",
"email": "alice@example.com",
"age": "30", # String automatically converts to int
"is_active": "true", # String automatically converts to bool
"tags": ["python", "ai", "data"] # List of strings
})
print(f"User: {user.name}, Age: {user.age} ({type(user.age)}), Tags: {user.tags}")
# Output:
# Same as above.
# Hierarchical field handling for nested data
class Company(Typed):
name: str
employees: List[User] # Automatically converts dicts to User instances
company_data = {
"name": "TechCorp",
"employees": [
{"name": "Alice", "email": "alice@tech.com", "age": "30"},
{"name": "Bob", "email": "bob@tech.com", "age": "25"}
]
}
company = Company.from_dict(company_data)
print(f"Company: {company.name}, Employees: {len(company.employees)}")
Documentation
Comprehensive documentation is available at https://adivekar-utexas.github.io/morphic/
Building Documentation Locally
To build and serve the documentation locally:
# Install documentation dependencies
pip install -e ".[docs]"
# Serve documentation locally
mkdocs serve
The documentation will be available at http://localhost:8000
Documentation Structure
- User Guide: Comprehensive tutorials and examples
- API Reference: Detailed API documentation generated from docstrings
- Examples: Real-world usage examples and patterns
- Contributing: Guidelines for contributors
Development
Setting Up Development Environment
-
Clone the repository:
git clone https://github.com/adivekar/morphic.git cd morphic
-
Create virtual environment:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install in development mode:
# Install all dependencies (recommended for contributors) pip install -e ".[all]" # Or install specific groups pip install -e ".[dev]" # Just development tools pip install -e ".[docs]" # Just documentation tools
Running Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=morphic --cov-report=html
# Run specific test file
pytest tests/test_registry.py
Code Quality
# Format code
black src/ tests/
# Lint code
ruff check src/ tests/
# Type checking
mypy src/
Documentation Deployment
Documentation is automatically deployed to GitHub Pages when changes are pushed to the main branch via GitHub Actions. The deployment workflow:
- Builds documentation using MkDocs with Material theme
- Generates API documentation automatically from docstrings using mkdocstrings
- Deploys to GitHub Pages at https://adivekar-utexas.github.io/morphic/
Performance
Morphic is optimized for production use:
- AutoEnum: 5.7M+ lookups/second with fuzzy matching
- Registry: O(1) class lookup with hierarchical inheritance
- Typed: Efficient type conversion with caching
Requirements
- Python 3.10.9 or higher
- typing-extensions >= 4.0.0
Contributing
We welcome contributions! Please see our Contributing Guide for details on:
- Setting up the development environment
- Running tests and quality checks
- Code style and documentation standards
- Pull request process
License
MIT License - see the LICENSE file for details.
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 morphic-0.1.3.tar.gz.
File metadata
- Download URL: morphic-0.1.3.tar.gz
- Upload date:
- Size: 124.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c02a2f1b34d7f45fbe77e3d09c7022cf1a45cab076caaf9f87dd30897f64708
|
|
| MD5 |
72908e585c62f7996766027da93be3cd
|
|
| BLAKE2b-256 |
15993207794a7b5224ced9dd108613a4065be1769506ac64536a21e7128af1ac
|
File details
Details for the file morphic-0.1.3-py3-none-any.whl.
File metadata
- Download URL: morphic-0.1.3-py3-none-any.whl
- Upload date:
- Size: 39.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a35fd1c550ff790f6d647f4a81e5472eb0c00b35240ab949c72c991f42b1a267
|
|
| MD5 |
44a6c84e2fa460ee2dfcbc4027a36488
|
|
| BLAKE2b-256 |
1aaeba7f77aa405d71027277e099554ab46d3b7413a29d67e0dd794dfe9021d2
|