Skip to content

Commit ac63c9c

Browse files
authored
Merge pull request #26 from LeanderCS/25
25 | Add more filters and validators
2 parents 3049777 + 76d92a5 commit ac63c9c

26 files changed

+530
-67
lines changed

.coveragerc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
source = flask_inputfilter
33

44
[report]
5-
omit = __init__.py, setup.py, */test/*
5+
omit = __init__.py, setup.py, */test/*

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FROM python:3.7-slim
22

33
WORKDIR /app
44

5-
RUN apt-get update && apt-get install -y gcc python3-dev git
5+
RUN apt-get update && apt-get install -y gcc python3-dev
66

77
RUN pip install --upgrade pip
88

README.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ For information about the usage you can view the documentation `here <https://le
3636

3737
.. image:: https://img.shields.io/pypi/dm/flask-inputfilter?style=flat-square&label=PyPI
3838
:target: https://pypi.org/project/flask-inputfilter/
39+
.. image:: https://static.pepy.tech/badge/flask-inputfilter
40+
:target: https://pypi.org/project/flask-inputfilter/
3941

4042
Installation
4143
============
@@ -127,7 +129,7 @@ If the data is invalid, a 400 response with an error message will be returned.
127129
See also
128130
========
129131

130-
For further instructions please view the documentary `here <https://leandercs.github.io/flask-inputfilter>`__.
132+
For further instructions please view the `documentary <https://leandercs.github.io/flask-inputfilter>`__.
131133

132-
For ideas, suggestions or questions, please open an issue on GitHub `here <https://github.com/LeanderCS/flask-inputfilter>`__.
134+
For ideas, suggestions or questions, please open an issue on `GitHub <https://github.com/LeanderCS/flask-inputfilter>`__.
133135

docs/changelog.rst

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,90 +3,109 @@ Changelog
33

44
All notable changes to this project will be documented in this file.
55

6-
[0.0.8] - 2025-01-20
6+
[0.0.9] - 2025-01-29
77
--------------------
88

99
Added
1010
^^^^^
11+
- New ``copy`` functionality to copy the value of another field. `Check it out <options/copy>`_
12+
13+
Filter
14+
""""""
15+
- New ``ToDataclassFilter`` to convert a dictionary to a dataclass.
16+
- New ``ToTypedDictFilter`` to convert a dictionary to a TypedDict.
17+
18+
Validator
19+
"""""""""
20+
- New ``CustomJsonValidator`` to check if a value is the format of a specific json.
21+
- New ``IsDataclassValidator`` to check if a value is a dataclass.
22+
- New ``IsTypedDictValidator`` to check if a value is a TypedDict.
23+
24+
Changed
25+
^^^^^^^
26+
- Moved external API call before the filter and validation process.
27+
Before, filters and validators the the external API field where useless,
28+
because the value of the field where replaced by the API result.
29+
- Updated ``SlugifyFilter`` to remove accents and other special characters.
30+
31+
32+
[0.0.8] - 2025-01-20
33+
--------------------
1134

35+
Added
36+
^^^^^
1237
- New functionality to define steps for a field to have more control over the
1338
order of the validation and filtering process.
1439
- Documentary
1540

1641
Filter
1742
""""""
18-
19-
- New `Base64ImageDownscaleFilter` to reduce the size of an image.
20-
- New `Base64ImageResizeFilter` to reduce the file size of an image.
43+
- New ``Base64ImageDownscaleFilter`` to reduce the size of an image.
44+
- New ``Base64ImageResizeFilter`` to reduce the file size of an image.
2145

2246
Validator
2347
"""""""""
24-
25-
- New `IsHorizontalImageValidator` to check if an image is horizontal.
26-
- New `IsVerticalImageValidator` to check if an image is vertical.
48+
- New ``IsHorizontalImageValidator`` to check if an image is horizontal.
49+
- New ``IsVerticalImageValidator`` to check if an image is vertical.
2750

2851
Changed
2952
^^^^^^^
30-
31-
- Added `UnicodeFormEnum` to show possible config values for `ToNormalizedUnicodeFilter`.
53+
- Added ``UnicodeFormEnum`` to show possible config values for ``ToNormalizedUnicodeFilter``.
3254
Old config is still supported, but will be removed in a later version.
3355

56+
3457
[0.0.7.1] - 2025-01-16
3558
----------------------
3659

3760
Changed
3861
^^^^^^^
62+
- Updated ``setup.py`` to fix the issue with the missing subfolders.
3963

40-
- Updated `setup.py` to fix the issue with the missing subfolders.
4164

4265
[0.0.7] - 2025-01-14
4366
--------------------
4467

4568
Added
4669
^^^^^
47-
48-
- Workflow to run tests on all supported Python versions. [Check it out](.github/workflows/test_env.yaml)
70+
- Workflow to run tests on all supported Python versions.
4971
- Added more test coverage for validators and filters.
5072
- Added tracking of coverage in tests. `Check it out <https://coveralls.io/github/LeanderCS/flask-inputfilter>`_
51-
- New functionality for global filters and validators in `InputFilters`.
73+
- New functionality for global filters and validators in ``InputFilters``.
5274
- New functionality to define custom supported methods.
5375

5476
Validator
5577
"""""""""
78+
- New ``NotInArrayValidator`` to check if a value is not in a list.
79+
- New ``NotValidator`` to invert the result of another validator.
5680

57-
- New `NotInArrayValidator` to check if a value is not in a list.
58-
- New `NotValidator` to invert the result of another validator.
5981

6082
[0.0.6] - 2025-01-12
6183
--------------------
6284

6385
Added
6486
^^^^^
65-
6687
- New date validators and filters.
6788

6889
Removed
6990
^^^^^^^
70-
7191
- Dropped support for Python 3.6.
7292

93+
7394
[0.0.5] - 2025-01-12
7495
--------------------
7596

7697
Added
7798
^^^^^
78-
79-
- New condition functionality between fields. [Check it out](flask_inputfilter/Condition/README.md)
99+
- New ``condition`` functionality between fields. `Check it out <options/condition>`_
80100

81101
Changed
82102
^^^^^^^
103+
- Switched ``external_api`` config from dict to class. `Check it out <options/external_api#Configuration>`_
83104

84-
- Switched `external_api` config from dict to class. [Check it out](flask_inputfilter/Model/ExternalApiConfig.py)
85105

86106
[0.0.4] - 2025-01-09
87107
--------------------
88108

89109
Added
90110
^^^^^
91-
92-
- New external API functionality. [Check it out](docs/EXTERNAL_API.md)
111+
- New external API functionality. `Check it out <options/external_api>`_

docs/index.rst

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,12 @@ Available functions:
3232
</p>
3333
<p style="margin:0;">
3434
Thank you for using <code>flask-inputfilter</code>!<br>
35-
If you have any questions or suggestions, please feel free to open an issue on GitHub <a href="https://github.com/LeanderCS/flask-inputfilter">here</a>.<br>
35+
If you have any questions or suggestions, please feel free to open an issue on <a href="https://github.com/LeanderCS/flask-inputfilter">GitHub</a>.<br>
3636
If you don't want to miss any updates, please star the repository.<br>
3737
This will help me to understand how many people are interested in this project.<br>
3838
</p>
3939
</div>
4040

41-
<div style="border:1px solid #86989B;padding:1rem;border-radius:3px;margin:20px 0 40px;">
42-
<p style="background-color:hsl(150, 36.7%, 90%);margin:-1rem -1rem 0.8rem -1rem;padding:0.3rem 1rem 0.3rem 2.5rem;position:relative;border-radius:3px 3px 0 0;">
43-
<span style="content:'';position:absolute;top:.25rem;left:.5rem;width:1.5rem;height:1.5rem;background-color:hsl(150, 36.7%, 50%);mask-image:url('data:image/svg+xml;charset=utf-8,<svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 24 24&quot;><path d=&quot;M15.07 11.25l-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 00-2-2 2 2 0 00-2 2H8a4 4 0 014-4 4 4 0 014 4 3.2 3.2 0 01-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 002 12a10 10 0 0010 10 10 10 0 0010-10c0-5.53-4.5-10-10-10z&quot;/></svg>');"></span>
44-
Hint
45-
</p>
46-
<p style="margin:0;">
47-
For information about the usage you can view the documentation <a href="https://leandercs.github.io/flask-inputfilter">here</a>.
48-
</p>
49-
</div>
50-
5141
Installation
5242
------------
5343

docs/options/copy.rst

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
Copy functionality
2+
==================
3+
4+
5+
Overview
6+
--------
7+
8+
The copy functionality is configured via the ``copy`` parameter in the ``add`` method.
9+
This parameter accepts a string with the name the value should be copied from.
10+
11+
.. note::
12+
13+
The copy functionality runs **before** all filters and validators have been executed.
14+
This means the copied data can be validated and/or filtered.
15+
16+
Examples
17+
--------
18+
19+
Basic Copy Integration
20+
21+
.. code-block:: python
22+
23+
from flask_inputfilter import InputFilter
24+
from flask_inputfilter.Filter import SlugifyFilter
25+
26+
class MyInputFilter(InputFilter):
27+
def __init__(self):
28+
super().__init__()
29+
30+
self.add(
31+
"username"
32+
)
33+
34+
self.add(
35+
"escapedUsername",
36+
copy="username"
37+
filters=[SlugifyFilter()]
38+
)
39+
40+
# Example usage
41+
# Body: {"username": "Very Important User"}
42+
43+
@app.route("/test", methods=["GET"])
44+
@MyInputFilter.validate()
45+
def test_route():
46+
validated_data = g.validated_data
47+
48+
# Cotains the same value as username but escaped eg. "very-important-user"
49+
print(validated_data["escapedUsername"])

docs/options/external_api.rst

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
External API
22
============
33

4-
This documentation provides a comprehensive overview of the external API functionality available in the `InputFilter` class. It covers the configuration, core methods, and examples of usage for interacting with external APIs.
4+
This documentation provides a comprehensive overview of the external API functionality available in the `InputFilter` class.
5+
It covers the configuration, core methods, and examples of usage for interacting with external APIs.
56

67
Overview
78
--------
@@ -11,8 +12,8 @@ This feature allows dynamic data retrieval based on user inputs, such as validat
1112

1213
.. note::
1314

14-
The external API functionality runs **after** all other filters and validators have been executed.
15-
This means the data fetched from the external API will not be validated or filtered.
15+
The external API functionality runs **before** all filters and validators have been executed.
16+
This means the data fetched from the external API can be validated and/or filtered as normal.
1617

1718
Configuration
1819
-------------
@@ -52,7 +53,7 @@ Basic External API Integration
5253

5354
.. code-block:: python
5455
55-
from flask_inputfilter.InputFilter import InputFilter
56+
from flask_inputfilter import InputFilter
5657
5758
class MyInputFilter(InputFilter):
5859
def __init__(self):
@@ -72,9 +73,13 @@ Basic External API Integration
7273
)
7374
7475
# Example usage
75-
filter_instance = MyInputFilter()
76-
validated_data = filter_instance.validateData({"user_id": 123})
77-
print(validated_data["is_active"]) # True or False based on API response
76+
# Body: {"user_id": 123}
77+
78+
@app.route("/test", methods=["GET"])
79+
@MyInputFilter.validate()
80+
def test_route():
81+
validated_data = g.validated_data
82+
print(validated_data["is_active"]) # True or False based on API response
7883
7984
Using Query Parameters
8085
^^^^^^^^^^^^^^^^^^^^^^
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
from abc import ABC, abstractmethod
12
from typing import Any, Dict
23

34

4-
class BaseCondition:
5+
class BaseCondition(ABC):
56
"""
67
Base class for defining conditions.
78
Each condition should implement the `check` method.
89
"""
910

11+
@abstractmethod
1012
def check(self, data: Dict[str, Any]) -> bool:
11-
raise NotImplementedError("Condition must implement 'check' method.")
13+
pass
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
from abc import ABC, abstractmethod
12
from typing import Any
23

34

4-
class BaseFilter:
5+
class BaseFilter(ABC):
56
"""
67
BaseFilter-Class. Every filter should inherit from it.
78
"""
89

10+
@abstractmethod
911
def apply(self, value: Any) -> Any:
10-
raise NotImplementedError("Filter apply method must be implemented")
12+
pass

flask_inputfilter/Filter/SlugifyFilter.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import re
2+
import unicodedata
23
from typing import Any, Optional, Union
34

5+
from flask_inputfilter.Enum import UnicodeFormEnum
46
from flask_inputfilter.Filter import BaseFilter
57

68

@@ -13,6 +15,17 @@ def apply(self, value: Any) -> Union[Optional[str], Any]:
1315
if not isinstance(value, str):
1416
return value
1517

18+
value_without_accents = "".join(
19+
char
20+
for char in unicodedata.normalize(UnicodeFormEnum.NFD.value, value)
21+
if unicodedata.category(char) != "Mn"
22+
)
23+
24+
value = unicodedata.normalize(
25+
UnicodeFormEnum.NFKD.value, value_without_accents
26+
)
27+
value = value.encode("ascii", "ignore").decode("ascii")
28+
1629
value = value.lower()
1730

1831
value = re.sub(r"[^\w\s-]", "", value)

0 commit comments

Comments
 (0)