Parse strings into Pydantic models using pattern matching
Project description
stringent
stringent is a powerful Python library that seamlessly parses strings into Pydantic models using flexible pattern matching. Whether you're working with pipe-separated values, space-separated data, JSON strings, or custom formats, stringent makes it easy to convert unstructured strings into validated, type-safe Python objects.
Features
✨ Flexible Pattern Matching - Parse strings using format-like patterns (e.g., {name} | {age} | {city})
🔗 Pattern Chaining - Chain multiple patterns using the | operator to try patterns in order until one matches
🔄 Automatic Input Handling - Seamlessly handles both dictionary and string inputs without code changes
🎯 Pydantic Integration - Built on Pydantic 2.0+ for robust validation and type safety
📦 JSON Support - Built-in JSON parsing with automatic fallback to pattern matching
🚀 JsonParsableModel - Automatic JSON string parsing for API integrations and message queues
🔀 Union Types - Organize parsing strategies using union types for maximum flexibility
🧬 Inheritance Support - Parse patterns are inherited and can be overridden in subclasses
Installation
pip install stringent
Quick Start
from pydantic import BaseModel, EmailStr
from typing import Literal
from stringent import parse, parse_json, ParsableModel
class Info(BaseModel):
name: str
age: int
city: str
class Record(ParsableModel):
id: int
info: Info = parse_json() | parse('{name} | {age} | {city}') | parse('{name} {age} {city}')
email: EmailStr
status: Literal['Active', 'Inactive']
# Parse the data - handles dicts, strings, and JSON automatically
data = [
{'id': 1, 'info': {'name': 'Alice', 'age': 30, 'city': 'New York'}, 'email': 'alice@example.com', 'status': 'Active'},
{'id': 3, 'info': 'Charlie | 27 | Chicago', 'email': 'charlie@example.com', 'status': 'Active'},
{'id': 5, 'info': 'Eve 35 Dallas', 'email': 'eve@example.com', 'status': 'Inactive'},
{'id': 8, 'info': '{"name": "Joe", "age": 55, "city": "Tampa"}', 'email': 'joe@example.com', 'status': 'Active'},
]
for item in data:
record = Record(**item)
print(record)
Output:
id=1 info=Info(name='Alice', age=30, city='New York') email='alice@example.com' status='Active'
id=3 info=Info(name='Charlie', age=27, city='Chicago') email='charlie@example.com' status='Active'
id=5 info=Info(name='Eve', age=35, city='Dallas') email='eve@example.com' status='Inactive'
id=8 info=Info(name='Joe', age=55, city='Tampa') email='joe@example.com' status='Active'
Why stringent?
Working with mixed data formats is a common challenge in data processing. You might receive:
- Dictionary objects from APIs
- Pipe-separated strings from legacy systems
- Space-separated values from log files
- JSON strings from message queues
stringent eliminates the need for manual parsing logic by automatically handling all these formats with a single, declarative definition.
Key Use Cases
- API Integration - Handle inconsistent data formats from different endpoints
- Data Migration - Parse legacy data formats while maintaining type safety
- Log Processing - Parse structured log entries into validated models
- ETL Pipelines - Transform unstructured strings into typed data structures
- Configuration Parsing - Support multiple configuration formats with fallback patterns
Documentation
Comprehensive documentation is available in the docs directory:
- Getting Started - Installation and basic concepts
- Basic Usage - Field-level parsing, pattern chaining, and common patterns
- JSON Parsing - Automatic JSON parsing with JsonParsableModel
- Regex Parsing - Parse strings using regular expressions with named groups
- Error Handling - Error recovery and partial parsing
- FastAPI Integration - Using stringent with FastAPI
- Advanced Patterns - Union types, inheritance, and complex scenarios
- API Reference - Complete API documentation
- Documentation Index - Overview and quick links
Requirements
- Python 3.10 or higher
- Pydantic 2.0 or higher
- parse 1.20 or higher
Dependencies
pydantic>=2.0.0- For Pydantic model integration and validationparse>=1.20.0- For string parsing functionality
Examples
Pattern Chaining
Try multiple patterns in order until one matches:
from stringent import parse, ParsableModel
from pydantic import BaseModel
class Info(BaseModel):
name: str
age: int
city: str
class Record(ParsableModel):
info: Info = parse('{name} | {age} | {city}') | parse('{name} {age} {city}')
# Both formats work automatically
record1 = Record(info="Alice | 30 | NYC")
record2 = Record(info="Bob 25 Chicago")
JSON Parsing
Automatically parse JSON strings with fallback to pattern matching:
from stringent import parse_json, parse, ParsableModel
from pydantic import BaseModel
class Info(BaseModel):
name: str
age: int
class Record(ParsableModel):
info: Info = parse_json() | parse('{name} | {age}')
# JSON string
record1 = Record(info='{"name": "Alice", "age": 30}')
# Pattern string (fallback)
record2 = Record(info="Bob | 25")
Union Types
Use union types to organize parsing strategies:
from typing import Union
from stringent import ParsableModel
from pydantic import BaseModel
class Info(ParsableModel):
name: str
age: int
class PipeInfo(Info):
_model_parse_pattern = '{name} | {age}'
class SpaceInfo(Info):
_model_parse_pattern = '{name} {age}'
class Record(ParsableModel):
info: Union[PipeInfo, SpaceInfo]
# Automatically selects the correct type
record1 = Record(info="Alice | 30") # Uses PipeInfo
record2 = Record(info="Bob 25") # Uses SpaceInfo
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Development
To set up a development environment:
# Clone the repository
git clone https://github.com/eddiethedean/stringent.git
cd stringent
# Create a virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run linting
ruff check .
ruff format .
# Run type checking
mypy stringent/
License
This project is licensed under the MIT License - see the LICENSE file for details.
Author
Odos Matthews
- GitHub: @eddiethedean
- Email: odosmatthews@gmail.com
Acknowledgments
Made with ❤️ for the Python community
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
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 stringent-0.3.0.tar.gz.
File metadata
- Download URL: stringent-0.3.0.tar.gz
- Upload date:
- Size: 29.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c0c37b6af4817d52fcc9c06b7791c63618354fee30ac4c2dc7259afdc1c87c05
|
|
| MD5 |
609febd01c9db09e76cde8a93ca1efdb
|
|
| BLAKE2b-256 |
9b4582f03c995a3f361c6092466c57867bf900c621d100a4e6f66a73bdb8c1d0
|
File details
Details for the file stringent-0.3.0-py3-none-any.whl.
File metadata
- Download URL: stringent-0.3.0-py3-none-any.whl
- Upload date:
- Size: 12.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8f34635ce58a593b1977c31b73a37c6f77b71278014f9424ee8d21a8fbd4f407
|
|
| MD5 |
8d706e58e2c5447012dde7878679405b
|
|
| BLAKE2b-256 |
13ac459516feb94f962aa75eb4f7efa8f58a464a6fb9573d2e5299a72815d8e8
|