Skip to content

Commit 016f406

Browse files
authored
Merge pull request #64 from LeanderCS/py-typed
Add py.typed to improving type checking support and agents.md to help ai agents
2 parents ec71d0e + 4383506 commit 016f406

File tree

5 files changed

+241
-2
lines changed

5 files changed

+241
-2
lines changed

AGENTS.md

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
# Flask InputFilter - AI Agent Guide
2+
3+
A Flask extension for validating and filtering input data with comprehensive type support.
4+
5+
## Quick Overview
6+
7+
Flask InputFilter provides a declarative way to validate and filter incoming data in Flask applications. It supports both traditional method-based and modern decorator-based field definitions with full type hints and Cython optimization.
8+
9+
## Installation
10+
11+
```bash
12+
pip install flask-inputfilter
13+
# or
14+
uv add flask-inputfilter
15+
# or
16+
poetry add flask-inputfilter
17+
```
18+
19+
## Core Concepts
20+
21+
### 1. InputFilter Classes
22+
Create validation schemas by inheriting from `InputFilter`:
23+
24+
```python
25+
from flask_inputfilter import InputFilter, field
26+
from flask_inputfilter.filters import ToIntegerFilter, StringTrimFilter
27+
from flask_inputfilter.validators import IsIntegerValidator, LengthValidator
28+
29+
class UserInputFilter(InputFilter):
30+
# Modern decorator syntax (recommended)
31+
name: str = field(
32+
required=True,
33+
filters=[StringTrimFilter()],
34+
validators=[LengthValidator(min_length=2, max_length=50)]
35+
)
36+
37+
age: int = field(
38+
required=True,
39+
filters=[ToIntegerFilter()],
40+
validators=[IsIntegerValidator()]
41+
)
42+
43+
# Global filters/validators apply to all fields
44+
_global_filters = [StringTrimFilter()]
45+
_global_validators = []
46+
```
47+
48+
### 2. Usage in Flask Routes
49+
50+
```python
51+
from flask import Flask, request, jsonify
52+
53+
app = Flask(__name__)
54+
55+
@app.route('/users', methods=['POST'])
56+
def create_user():
57+
input_filter = UserInputFilter()
58+
input_filter.set_data(request.get_json())
59+
60+
if not input_filter.is_valid():
61+
return jsonify({'errors': input_filter.get_error_messages()}), 400
62+
63+
validated_data = input_filter.get_values()
64+
# Process validated_data...
65+
return jsonify(validated_data)
66+
```
67+
68+
## Available Components
69+
70+
### Filters (Data Transformation)
71+
- **String**: `ToUpperFilter`, `ToLowerFilter`, `StringTrimFilter`, `ToCamelCaseFilter`
72+
- **Type Conversion**: `ToIntegerFilter`, `ToFloatFilter`, `ToBooleanFilter`, `ToDateFilter`
73+
- **Data Structures**: `ToDataclassFilter`, `ToTypedDictFilter`, `ArrayExplodeFilter`
74+
- **Images**: `ToBase64ImageFilter`, `ToImageFilter`, `Base64ImageResizeFilter`
75+
- **Cleaning**: `ToAlphaNumericFilter`, `ToDigitsFilter`, `WhitelistFilter`, `BlacklistFilter`
76+
77+
### Validators (Data Validation)
78+
- **Type Checking**: `IsStringValidator`, `IsIntegerValidator`, `IsFloatValidator`, `IsBooleanValidator`
79+
- **Format**: `IsEmailValidator`, `IsUrlValidator`, `IsUuidValidator`, `IsJsonValidator`
80+
- **Ranges**: `LengthValidator`, `RangeValidator`, `ArrayLengthValidator`
81+
- **Dates**: `IsDateValidator`, `DateRangeValidator`, `IsFutureDateValidator`
82+
- **Images**: `IsImageValidator`, `IsHorizontalImageValidator`, `IsVerticalImageValidator`
83+
- **Logic**: `AndValidator`, `OrValidator`, `NotValidator`, `XorValidator`
84+
85+
### Conditions (Inter-field Validation)
86+
- **Requirement**: `RequiredIfCondition`, `ExactlyOneOfCondition`
87+
- **Logic**: `OneOfCondition`, `NOfCondition`, `ExactlyNOfCondition`
88+
- **Comparison**: `EqualCondition`, `NotEqualCondition`
89+
90+
## Project Structure
91+
92+
```
93+
flask_inputfilter/
94+
├── __init__.py # Main exports
95+
├── input_filter.py # Core InputFilter class
96+
├── py.typed # PEP 561 type support
97+
├── conditions/ # Inter-field validation logic
98+
├── filters/ # Data transformation components
99+
├── validators/ # Data validation components
100+
├── enums/ # Predefined enums
101+
├── exceptions/ # Custom exceptions
102+
├── models/ # Base classes and data models
103+
├── mixins/ # Reusable mixins
104+
└── declarative/ # Decorator-based field definition
105+
```
106+
107+
## Development Commands
108+
109+
```bash
110+
# Install dependencies
111+
pip install -e ".[dev]"
112+
113+
# Run tests
114+
pytest
115+
116+
# Lint code
117+
ruff check
118+
119+
# Format code
120+
ruff format
121+
122+
# Type checking
123+
mypy flask_inputfilter
124+
125+
# Build documentation
126+
cd docs && make html
127+
128+
# Build package
129+
python -m build
130+
```
131+
132+
## Advanced Features
133+
134+
### Custom Components
135+
```python
136+
from flask_inputfilter.models.base_filter import BaseFilter
137+
from flask_inputfilter.models.base_validator import BaseValidator
138+
139+
class CustomFilter(BaseFilter):
140+
def filter(self, value, context=None):
141+
# Your transformation logic
142+
return transformed_value
143+
144+
class CustomValidator(BaseValidator):
145+
def is_valid(self, value, context=None):
146+
# Your validation logic
147+
return True # or False
148+
```
149+
150+
### External API Integration
151+
```python
152+
from flask_inputfilter.models.external_api_config import ExternalApiConfig
153+
154+
class UserInputFilter(InputFilter):
155+
user_id: int = field(
156+
external_api=ExternalApiConfig(
157+
url="https://api.example.com/users/{user_id}",
158+
method="GET",
159+
headers={"Authorization": "Bearer token"}
160+
)
161+
)
162+
```
163+
164+
### Steps and Processing Order
165+
```python
166+
class ComplexInputFilter(InputFilter):
167+
data: dict = field(
168+
steps=[
169+
{'filters': [ToJsonFilter()]},
170+
{'validators': [IsJsonValidator()]},
171+
{'filters': [ToDataclassFilter(MyDataclass)]}
172+
]
173+
)
174+
```
175+
176+
## Type Support
177+
178+
- **Full PEP 561 compliance** with `py.typed` marker
179+
- **Comprehensive type hints** in all modules
180+
- **Stub files (.pyi)** for enhanced IDE support
181+
- **Cython extensions** with type declarations
182+
- **Compatible** with mypy, pyright, and other type checkers
183+
184+
## Performance
185+
186+
- **Cython optimization** available for performance-critical components
187+
- **Optional compilation** with `pip install flask-inputfilter[compile]`
188+
- **Fallback to Python** if compilation fails
189+
- **Benchmarked performance** improvements in validation-heavy scenarios
190+
191+
## Documentation
192+
193+
- **Full Documentation**: https://leandercs.github.io/flask-inputfilter
194+
- **API Reference**: Complete class and method documentation
195+
- **Guides**: Step-by-step tutorials and best practices
196+
- **Examples**: Real-world usage patterns
197+
198+
## Common Patterns
199+
200+
### API Endpoint Validation
201+
```python
202+
@app.route('/api/products', methods=['POST'])
203+
def create_product():
204+
class ProductFilter(InputFilter):
205+
name: str = field(required=True, validators=[LengthValidator(1, 100)])
206+
price: float = field(required=True, filters=[ToFloatFilter()], validators=[RangeValidator(0.01, 10000)])
207+
category: str = field(validators=[InArrayValidator(['electronics', 'clothing', 'books'])])
208+
209+
filter_instance = ProductFilter()
210+
filter_instance.set_data(request.get_json())
211+
212+
if not filter_instance.is_valid():
213+
return jsonify({'errors': filter_instance.get_error_messages()}), 400
214+
215+
return jsonify(filter_instance.get_values())
216+
```
217+
218+
### Form Data Processing
219+
```python
220+
@app.route('/contact', methods=['POST'])
221+
def contact_form():
222+
class ContactFilter(InputFilter):
223+
email: str = field(required=True, validators=[IsEmailValidator()])
224+
message: str = field(required=True, filters=[StringTrimFilter()], validators=[LengthValidator(10, 1000)])
225+
subscribe: bool = field(filters=[ToBooleanFilter()])
226+
227+
# Process form data...
228+
```
229+
230+
This guide provides AI agents with the essential context needed to effectively work with Flask InputFilter in any development scenario.

MANIFEST.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
include docs/source/index.rst
22
include LICENSE
33
include docs/source/changelog.rst
4-
recursive-include flask_inputfilter *.py *.pyi *.pyx *.pxd *.h
4+
recursive-include flask_inputfilter *.py *.pyi *.pyx *.pxd *.h py.typed
55

66
recursive-exclude flask_inputfilter *.cpp
77

docs/source/changelog.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ Changelog
44
All notable changes to this project will be documented in this file.
55

66

7+
[0.7.1] - 2025-09-27
8+
--------------------
9+
10+
Added
11+
^^^^^
12+
- Added comprehensive ``py.typed`` file for PEP 561 compliance, improving type checking support for mypy and other static type checkers.
13+
- Added ``AGENTS.md`` to document how to use this library for various ai agents.
14+
15+
716
[0.7.0] - 2025-09-25
817
--------------------
918

flask_inputfilter/py.typed

Whitespace-only changes.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "flask_inputfilter"
7-
version = "0.7.0"
7+
version = "0.7.1"
88
description = "A library to easily filter and validate input data in Flask applications"
99
readme = "README.md"
1010
keywords = [

0 commit comments

Comments
 (0)