Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHAGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.


# [0.0.8] - 2025-01-16

## Added

- New functionality to define steps for a field to have more control over the
order of the validation and filtering process.


# [0.0.7.1] - 2025-01-16

## Changed
Expand Down
37 changes: 32 additions & 5 deletions flask_inputfilter/InputFilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ def add(
or field None, although it is required .
:param filters: The filters to apply to the field value.
:param validators: The validators to apply to the field value.
:param steps:
:param steps: Allows to apply multiple filters and validators
in a specific order.
:param external_api: Configuration for an external API call.
"""

Expand Down Expand Up @@ -89,12 +90,14 @@ def __applyFilters(self, field_name: str, value: Any) -> Any:

field = self.fields.get(field_name)

for filter_ in field["filters"]:
for filter_ in field.get("filters"):
value = filter_.apply(value)

return value

def __validateField(self, field_name: str, field_info, value: Any) -> None:
def __validateField(
self, field_name: str, field_info: Any, value: Any
) -> None:
"""
Validate the field value.
"""
Expand All @@ -108,16 +111,38 @@ def __validateField(self, field_name: str, field_info, value: Any) -> None:

field = self.fields.get(field_name)

for validator in field["validators"]:
for validator in field.get("validators"):
validator.validate(value)
except ValidationError:
if field_info.get("fallback") is None:
raise

return field_info.get("fallback")

def __applySteps(
self, field_name: str, field_info: Any, value: Any
) -> Any:
"""
Apply multiple filters and validators in a specific order.
"""

field = self.fields.get(field_name)

try:
for step in field.get("steps"):
if isinstance(step, BaseFilter):
value = step.apply(value)
elif isinstance(step, BaseValidator):
step.validate(value)
except ValidationError:
if field_info.get("fallback") is None:
raise
return field_info.get("fallback")

return value

def __callExternalApi(
self, field_info, validated_data: dict
self, field_info: Any, validated_data: dict
) -> Optional[Any]:
"""
Führt den API-Aufruf durch und gibt den Wert zurück,
Expand Down Expand Up @@ -255,6 +280,8 @@ def validateData(
self.__validateField(field_name, field_info, value) or value
)

value = self.__applySteps(field_name, field_info, value)

if field_info.get("external_api"):
value = self.__callExternalApi(field_info, validated_data)

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name="flask_inputfilter",
version="0.0.7.2",
version="0.0.8",
author="Leander Cain Slotosch",
author_email="[email protected]",
description="A library to filter and validate input data in"
Expand Down
27 changes: 26 additions & 1 deletion test/test_input_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from flask_inputfilter import InputFilter
from flask_inputfilter.Condition import BaseCondition
from flask_inputfilter.Exception import ValidationError
from flask_inputfilter.Filter import ToUpperFilter
from flask_inputfilter.Filter import ToLowerFilter, ToUpperFilter
from flask_inputfilter.Model import ExternalApiConfig
from flask_inputfilter.Validator import (
InArrayValidator,
Expand Down Expand Up @@ -242,6 +242,31 @@ def test_fallback_with_default(self) -> None:
with self.assertRaises(ValidationError):
self.inputFilter.validateData({})

def test_steps(self) -> None:
"""
Test that custom steps works.
"""

self.inputFilter.add(
"name_upper",
steps=[
ToUpperFilter(),
InArrayValidator(["MAURICE"]),
ToLowerFilter(),
],
)

validated_data = self.inputFilter.validateData(
{"name_upper": "Maurice"}
)
self.assertEqual(validated_data["name_upper"], "maurice")

with self.assertRaises(ValidationError):
validated_data = self.inputFilter.validateData(
{"name_upper": "Alice"}
)
self.assertEqual(validated_data["name_upper"], "ALICE")

@patch("requests.request")
def test_external_api(self, mock_request: Mock) -> None:
"""
Expand Down
Loading