Skip to main content

stringent

CI Python Version License: MIT Code style: ruff

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:

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 validation
  • parse>=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.

Getting Started

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Open Issues

Looking for something to work on? Check out our open issues! We have many enhancement ideas organized by priority:

Issues labeled with good first issue are great for newcomers. See the full list of enhancement issues for more ideas.

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

Acknowledgments

  • Built on Pydantic for robust data validation
  • Uses parse for flexible string parsing

Made with ❤️ for the Python community

Metadata

Release files for stringent 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for stringent 0.3.1
File Size Uploaded
stringent-0.3.1.tar.gz 30.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for stringent 0.3.1
File Interpreter ABI Platform
stringent-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 43.1 kB

Release files / stringent-0.3.1.tar.gz

Download URL stringent-0.3.1.tar.gz
Size 30.4 kB
Tags Source
SHA-256 checksum
How to use checksums
fe4dc6d7ec8a3ed5c456aae0deb8688ef4b38c390bb3941621b00ecafe71e453
BLAKE2b-256 checksum
How to use checksums
6303a05fb643887d1429f76fe315a0237ad0c62be28ee6c9ade3970b96763ffd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.19

Release files / stringent-0.3.1-py3-none-any.whl

Download URL stringent-0.3.1-py3-none-any.whl
Size 12.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b5167825321a5df584e62809d0fd7f5c081440ee97c29299141356cde74a82fb
BLAKE2b-256 checksum
How to use checksums
ec3d5b75bdb11fe7128392ce2f0f8a9d7a761f678e40d48c099825a5fdb1d821
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.19

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page