Skip to content

Commit 273c15e

Browse files
authored
Merge pull request #53 from LeanderCS/45
45 | Move more static methods outside of InputFilter class
2 parents c5fc418 + c43aba7 commit 273c15e

File tree

13 files changed

+297
-228
lines changed

13 files changed

+297
-228
lines changed

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 *.pyx *.c *.cpp
4+
recursive-include flask_inputfilter *.py *.pyi *.pyx *.pxd *.c *.cpp
55
recursive-include flask_inputfilter/include *.h
66
prune tests
77
recursive-prune __pycache__

docs/source/changelog.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@ Changelog
33

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

6+
[0.5.2] - 2025-04-27
7+
--------------------
8+
9+
Changed
10+
^^^^^^^
11+
- Moved multiple internal methods to own ``FieldMixin``
12+
- ``applyFilters``
13+
- ``applySteps``
14+
- ``checkConditions``
15+
- ``checkForRequired``
16+
- ``validateField``
17+
18+
619
[0.5.1] - 2025-04-26
720
--------------------
821

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
project = "flask-inputfilter"
22
copyright = "2025, Leander Cain Slotosch"
33
author = "Leander Cain Slotosch"
4-
release = "0.5.1"
4+
release = "0.5.2"
55

66
extensions = ["sphinx_rtd_theme", "sphinx_design"]
77

flask_inputfilter/_input_filter.pyx

Lines changed: 15 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ from flask import Response, g, request
1313
from flask_inputfilter.conditions import BaseCondition
1414
from flask_inputfilter.exceptions import ValidationError
1515
from flask_inputfilter.filters import BaseFilter
16-
from flask_inputfilter.mixins import ExternalApiMixin
16+
from flask_inputfilter.mixins._external_api_mixin cimport ExternalApiMixin
17+
from flask_inputfilter.mixins._field_mixin cimport FieldMixin
1718
from flask_inputfilter.models import ExternalApiConfig, FieldModel
1819
from flask_inputfilter.validators import BaseValidator
1920

@@ -210,14 +211,14 @@ cdef class InputFilter:
210211
value = self.validated_data.get(copy)
211212

212213
if external_api:
213-
value = ExternalApiMixin().callExternalApi(
214+
value = ExternalApiMixin.callExternalApi(
214215
external_api, fallback, self.validated_data
215216
)
216217

217-
value = self.applyFilters(filters, value)
218-
value = self.validateField(validators, fallback, value) or value
219-
value = self.applySteps(steps, fallback, value) or value
220-
value = InputFilter.checkForRequired(
218+
value = FieldMixin.applyFilters(filters, value)
219+
value = FieldMixin.validateField(validators, fallback, value) or value
220+
value = FieldMixin.applySteps(steps, fallback, value) or value
221+
value = FieldMixin.checkForRequired(
221222
field_name, required, default, fallback, value
222223
)
223224

@@ -227,7 +228,7 @@ cdef class InputFilter:
227228
errors[field_name] = str(e)
228229

229230
try:
230-
self.checkConditions(self.conditions, self.validated_data)
231+
FieldMixin.checkConditions(self.conditions, self.validated_data)
231232
except ValidationError as e:
232233
errors["_condition"] = str(e)
233234

@@ -262,27 +263,6 @@ cdef class InputFilter:
262263
"""
263264
return self.conditions
264265

265-
cdef void checkConditions(self, conditions: List[BaseCondition], validated_data: Dict[str, Any]) except *:
266-
"""
267-
Checks if all conditions are met.
268-
269-
This method iterates through all registered conditions and checks
270-
if they are satisfied based on the provided validated data. If any
271-
condition is not met, a ValidationError is raised with an appropriate
272-
message indicating which condition failed.
273-
274-
Args:
275-
conditions (List[BaseCondition]):
276-
A list of conditions to be checked against the validated data.
277-
validated_data (Dict[str, Any]):
278-
The validated data to check against the conditions.
279-
"""
280-
for condition in conditions:
281-
if not condition.check(validated_data):
282-
raise ValidationError(
283-
f"Condition '{condition.__class__.__name__}' not met."
284-
)
285-
286266
cpdef void setData(self, data: Dict[str, Any]):
287267
"""
288268
Filters and sets the provided data into the object's internal
@@ -298,7 +278,7 @@ cdef class InputFilter:
298278
self.data = {}
299279
for field_name, field_value in data.items():
300280
if field_name in self.fields:
301-
field_value = self.applyFilters(
281+
field_value = FieldMixin.applyFilters(
302282
filters=self.fields[field_name].filters + self.global_filters,
303283
value=field_value,
304284
)
@@ -411,7 +391,7 @@ cdef class InputFilter:
411391
"""
412392
self.data = data
413393

414-
def hasUnknown(self) -> bool:
394+
cpdef bint hasUnknown(self):
415395
"""
416396
Checks whether any values in the current data do not have
417397
corresponding configurations in the defined fields.
@@ -422,10 +402,11 @@ cdef class InputFilter:
422402
if not self.data and self.fields:
423403
return True
424404

425-
return any(
426-
field_name not in self.fields.keys()
427-
for field_name in self.data.keys()
428-
)
405+
for field_name in self.data.keys():
406+
if field_name not in self.fields:
407+
return True
408+
409+
return False
429410

430411
cpdef str getErrorMessage(self, field_name: str):
431412
"""
@@ -641,94 +622,6 @@ cdef class InputFilter:
641622
copy=copy,
642623
)
643624

644-
cdef object applySteps(
645-
self,
646-
steps: List[Union[BaseFilter, BaseValidator]],
647-
fallback: Any,
648-
value: Any,
649-
):
650-
"""
651-
Apply multiple filters and validators in a specific order.
652-
653-
This method processes a given value by sequentially applying a list of
654-
filters and validators. Filters modify the value, while validators
655-
ensure the value meets specific criteria. If a validation error occurs
656-
and a fallback value is provided, the fallback is returned. Otherwise,
657-
the validation error is raised.
658-
659-
Args:
660-
steps (List[Union[BaseFilter, BaseValidator]]):
661-
A list of filters and validators to be applied in order.
662-
fallback (Any):
663-
A fallback value to return if validation fails.
664-
value (Any):
665-
The initial value to be processed.
666-
667-
Returns:
668-
Any: The processed value after applying all filters and validators.
669-
If a validation error occurs and a fallback is provided, the
670-
fallback value is returned.
671-
672-
Raises:
673-
ValidationError: If validation fails and no fallback value is
674-
provided.
675-
"""
676-
if value is None:
677-
return
678-
679-
try:
680-
for step in steps:
681-
if isinstance(step, BaseFilter):
682-
value = step.apply(value)
683-
elif isinstance(step, BaseValidator):
684-
step.validate(value)
685-
except ValidationError:
686-
if fallback is None:
687-
raise
688-
return fallback
689-
return value
690-
691-
@staticmethod
692-
cdef object checkForRequired(
693-
field_name: str,
694-
required: bool,
695-
default: Any,
696-
fallback: Any,
697-
value: Any,
698-
):
699-
"""
700-
Determine the value of the field, considering the required and
701-
fallback attributes.
702-
703-
If the field is not required and no value is provided, the default
704-
value is returned. If the field is required and no value is provided,
705-
the fallback value is returned. If no of the above conditions are met,
706-
a ValidationError is raised.
707-
708-
Args:
709-
field_name (str): The name of the field being processed.
710-
required (bool): Indicates whether the field is required.
711-
default (Any): The default value to use if the field is not provided and not required.
712-
fallback (Any): The fallback value to use if the field is required but not provided.
713-
value (Any): The current value of the field being processed.
714-
715-
Returns:
716-
Any: The determined value of the field after considering required, default, and fallback attributes.
717-
718-
Raises:
719-
ValidationError: If the field is required and no value or fallback is provided.
720-
"""
721-
if value is not None:
722-
return value
723-
724-
if not required:
725-
return default
726-
727-
if fallback is not None:
728-
return fallback
729-
730-
raise ValidationError(f"Field '{field_name}' is required.")
731-
732625
cpdef void addGlobalFilter(self, filter: BaseFilter):
733626
"""
734627
Add a global filter to be applied to all fields.
@@ -751,27 +644,6 @@ cdef class InputFilter:
751644
"""
752645
return self.global_filters
753646

754-
cdef object applyFilters(self, filters: List[BaseFilter], value: Any):
755-
"""
756-
Apply filters to the field value.
757-
758-
Args:
759-
filters (List[BaseFilter]): A list of filters to apply to the
760-
value.
761-
value (Any): The value to be processed by the filters.
762-
763-
Returns:
764-
Any: The processed value after applying all filters.
765-
If the value is None, None is returned.
766-
"""
767-
if value is None:
768-
return
769-
770-
for filter in filters:
771-
value = filter.apply(value)
772-
773-
return value
774-
775647
cpdef void clear(self):
776648
"""
777649
Resets all fields of the InputFilter instance to
@@ -877,32 +749,3 @@ cdef class InputFilter:
877749
List[BaseValidator]: A list of global validators.
878750
"""
879751
return self.global_validators
880-
881-
cdef object validateField(
882-
self, validators: List[BaseValidator], fallback: Any, value: Any
883-
):
884-
"""
885-
Validate the field value.
886-
887-
Args:
888-
validators (List[BaseValidator]): A list of validators to apply
889-
to the field value.
890-
fallback (Any): A fallback value to return if validation fails.
891-
value (Any): The value to be validated.
892-
893-
Returns:
894-
Any: The validated value if all validators pass. If validation
895-
fails and a fallback is provided, the fallback value is
896-
returned.
897-
"""
898-
if value is None:
899-
return
900-
901-
try:
902-
for validator in validators:
903-
validator.validate(value)
904-
except ValidationError:
905-
if fallback is None:
906-
raise
907-
908-
return fallback

flask_inputfilter/input_filter.pyi

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
from collections.abc import Callable
4-
from typing import Any, Dict, List, Optional, Type, TypeVar, Union
4+
from typing import Any, Dict, List, Optional, Tuple, Type, TypeVar, Union
55

66
from flask import Response
77

@@ -31,8 +31,8 @@ class InputFilter:
3131
) -> Callable[
3232
[Any],
3333
Callable[
34-
[tuple[Any, ...], Dict[str, Any]],
35-
Union[Response, tuple[Any, Dict[str, Any]]],
34+
[Tuple[Any, ...], Dict[str, Any]],
35+
Union[Response, Tuple[Any, Dict[str, Any]]],
3636
],
3737
]: ...
3838
def validateData(

flask_inputfilter/mixins/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
if shutil.which("g++") is not None:
44
from ._external_api_mixin import ExternalApiMixin
5+
from ._field_mixin import FieldMixin
56

67
else:
78
from .external_api_mixin import ExternalApiMixin
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from typing import Any, Dict
2+
3+
from flask_inputfilter.models import ExternalApiConfig
4+
5+
6+
cdef class ExternalApiMixin:
7+
@staticmethod
8+
cdef str replacePlaceholders(
9+
value: str,
10+
validated_data: Dict[str, Any]
11+
)
12+
@staticmethod
13+
cdef dict replacePlaceholdersInParams(
14+
params: dict, validated_data: Dict[str, Any]
15+
)
16+
@staticmethod
17+
cdef object callExternalApi(config: ExternalApiConfig, fallback: Any, validated_data: Dict[str, Any])

0 commit comments

Comments
 (0)