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
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[flake8]
exclude = __init__.py, venv, *.md, .*
max-line-length = 90
max-line-length = 79
13 changes: 13 additions & 0 deletions CHAGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Changelog

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

## [0.0.5] - 2025-01-12

### Added

- New condition functionality between fields. [Check it out](src/flask_inputfilter/Condition/README.md)

### Changed

- Switched external_api config from dict to class. [Check it out](src/flask_inputfilter/Model/ExternalApiConfig.py)
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 Leander Cain Slotosch
Copyright (c) 2025 Leander Cain Slotosch

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
27 changes: 23 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from src.flask_inputfilter.Validator import IsStringValidator

# flask-inputfilter

The `InputFilter` class is used to validate and filter input data in Flask applications.
Expand All @@ -16,15 +18,18 @@ pip install flask-inputfilter
## Quickstart

To use the `InputFilter` class, you need to create a new class that inherits from it and define the fields you want to validate and filter.
There are lots of different filters and validators available to use, and you can also create your own custom filters and validators.

There are lots of different filters and validators available to use, but it is also possible to create your own.

### Definition

```python

from flask_inputfilter import InputFilter
from flask_inputfilter.Condition import ExactlyOneOfCondition
from flask_inputfilter.Enum import RegexEnum
from flask_inputfilter.Filter import StringTrimFilter, ToIntegerFilter, ToNullFilter
from flask_inputfilter.Validator import IsIntegerValidator, RegexValidator
from flask_inputfilter.Validator import IsIntegerValidator, IsStringValidator, RegexValidator


class UpdateZipcodeInputFilter(InputFilter):
Expand All @@ -35,15 +40,14 @@ class UpdateZipcodeInputFilter(InputFilter):
self.add(
'id',
required=True,
filters=[ToIntegerFilter(), ToNullFilter()],
filters=[ToNullFilter()],
validators=[
IsIntegerValidator()
]
)

self.add(
'zipcode',
required=True,
filters=[StringTrimFilter()],
validators=[
RegexValidator(
Expand All @@ -52,6 +56,19 @@ class UpdateZipcodeInputFilter(InputFilter):
)
]
)

self.add(
'city',
filters=[StringTrimFilter()],
validators=[
IsStringValidator()
]
)

self.addCondition(
ExactlyOneOfCondition(['zipcode', 'city'])
)

```

### Usage
Expand All @@ -61,6 +78,7 @@ After calling the `validate` method, the validated data will be available in the
If the data is not valid, the `validate` method will return a 400 response with the error message.

```python

from flask import Flask, g
from your-path import UpdateZipcodeInputFilter

Expand All @@ -74,6 +92,7 @@ def updateZipcode():
# Do something with validatedData
id = data.get('id')
zipcode = data.get('zipcode')

```

---
Expand Down
3 changes: 2 additions & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
services:
app:

flask-inputfilter:
build:
context: .
dockerfile: Dockerfile
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.4",
version="0.0.5",
author="Leander Cain Slotosch",
author_email="[email protected]",
description="A library to filter and validate input data in"
Expand Down
20 changes: 20 additions & 0 deletions src/flask_inputfilter/Condition/ArrayLengthEqualCondition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import Any, Dict

from .BaseCondition import BaseCondition


class ArrayLengthEqualCondition(BaseCondition):
"""
Condition that checks if the array is of the specified length.
"""

def __init__(self, first_field: str, second_field: str) -> None:

self.first_field = first_field
self.second_field = second_field

def check(self, data: Dict[str, Any]) -> bool:

return len(data.get(self.first_field) or []) == len(
data.get(self.second_field) or []
)
20 changes: 20 additions & 0 deletions src/flask_inputfilter/Condition/ArrayLongerThanCondition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import Any, Dict

from .BaseCondition import BaseCondition


class ArrayLongerThanCondition(BaseCondition):
"""
Condition that checks if the array is longer than the specified length.
"""

def __init__(self, longer_field: str, shorter_field: str) -> None:

self.longer_field = longer_field
self.shorter_field = shorter_field

def check(self, data: Dict[str, Any]) -> bool:

return len(data.get(self.longer_field) or []) > len(
data.get(self.shorter_field) or []
)
12 changes: 12 additions & 0 deletions src/flask_inputfilter/Condition/BaseCondition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from typing import Any, Dict


class BaseCondition:
"""
Base class for defining conditions.
Each condition should implement the `check` method.
"""

def check(self, data: Dict[str, Any]) -> bool:

raise NotImplementedError("Condition must implement 'check' method.")
17 changes: 17 additions & 0 deletions src/flask_inputfilter/Condition/CustomCondition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from typing import Any, Callable, Dict

from .BaseCondition import BaseCondition


class CustomCondition(BaseCondition):
"""
Allows users to define their own condition as a callable.
"""

def __init__(self, condition: Callable[[Dict[str, Any]], bool]) -> None:

self.condition = condition

def check(self, data: Dict[str, Any]) -> bool:

return self.condition(data)
18 changes: 18 additions & 0 deletions src/flask_inputfilter/Condition/EqualCondition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from typing import Any, Dict

from .BaseCondition import BaseCondition


class EqualCondition(BaseCondition):
"""
Condition that checks if two fields are equal.
"""

def __init__(self, first_field: str, second_field: str) -> None:

self.first_field = first_field
self.second_field = second_field

def check(self, data: Dict[str, Any]) -> bool:

return data.get(self.first_field) == data.get(self.second_field)
22 changes: 22 additions & 0 deletions src/flask_inputfilter/Condition/ExactlyNOfCondition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from typing import Any, Dict, List

from .BaseCondition import BaseCondition


class ExactlyNOfCondition(BaseCondition):
"""
Condition that checks if exactly n of the given
fields are present in the data.
"""

def __init__(self, fields: List[str], n: int) -> None:

self.fields = fields
self.n = n

def check(self, data: Dict[str, Any]) -> bool:

return (
sum(1 for field in self.fields if data.get(field) is not None)
== self.n
)
22 changes: 22 additions & 0 deletions src/flask_inputfilter/Condition/ExactlyNOfMatchesCondition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from typing import Any, Dict, List

from .BaseCondition import BaseCondition


class ExactlyNOfMatchesCondition(BaseCondition):
"""
Condition that checks if exactly n of the given fields
match with the value.
"""

def __init__(self, fields: List[str], n: int, value: Any) -> None:
self.fields = fields
self.n = n
self.value = value

def check(self, data: Dict[str, Any]) -> bool:

return (
sum(1 for field in self.fields if data.get(field) == self.value)
== self.n
)
19 changes: 19 additions & 0 deletions src/flask_inputfilter/Condition/ExactlyOneOfCondition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from typing import Any, Dict, List

from .BaseCondition import BaseCondition


class ExactlyOneOfCondition(BaseCondition):
"""
Condition that ensures exactly one of the specified fields is present.
"""

def __init__(self, fields: List[str]) -> None:

self.fields = fields

def check(self, data: Dict[str, Any]) -> bool:

return (
sum(1 for field in self.fields if data.get(field) is not None) == 1
)
22 changes: 22 additions & 0 deletions src/flask_inputfilter/Condition/ExactlyOneOfMatchesCondition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from typing import Any, Dict, List

from .BaseCondition import BaseCondition


class ExactlyOneOfMatchesCondition(BaseCondition):
"""
Condition that ensures exactly one of the specified
fields matches the value.
"""

def __init__(self, fields: List[str], value: Any) -> None:

self.fields = fields
self.value = value

def check(self, data: Dict[str, Any]) -> bool:

return (
sum(1 for field in self.fields if data.get(field) == self.value)
== 1
)
24 changes: 24 additions & 0 deletions src/flask_inputfilter/Condition/IntegerBiggerThanCondition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from typing import Dict

from .BaseCondition import BaseCondition


class IntegerBiggerThanCondition(BaseCondition):
"""
Condition that ensures an integer is bigger than the specified value.
"""

def __init__(self, bigger_field: str, smaller_field: str) -> None:

self.bigger_field = bigger_field
self.smaller_field = smaller_field

def check(self, data: Dict[str, int]) -> bool:

if (
data.get(self.bigger_field) is None
or data.get(self.smaller_field) is None
):
return False

return data.get(self.bigger_field) > data.get(self.smaller_field)
21 changes: 21 additions & 0 deletions src/flask_inputfilter/Condition/NOfCondition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from typing import Any, List

from .BaseCondition import BaseCondition


class NOfCondition(BaseCondition):
"""
Condition that ensures at least N of the specified fields are present.
"""

def __init__(self, fields: List[str], n: int) -> None:

self.fields = fields
self.n = n

def check(self, data: Any) -> bool:

return (
sum(1 for field in self.fields if data.get(field) is not None)
>= self.n
)
23 changes: 23 additions & 0 deletions src/flask_inputfilter/Condition/NOfMatchesCondition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from typing import Any, Dict, List

from src.flask_inputfilter.Condition import BaseCondition


class NOfMatchesCondition(BaseCondition):
"""
Condition that ensures at least N of the specified
fields matches the value.
"""

def __init__(self, fields: List[str], n: int, value: Any) -> None:

self.fields = fields
self.n = n
self.value = value

def check(self, data: Dict[str, Any]) -> bool:

return (
sum(1 for field in self.fields if data.get(field) == self.value)
== self.n
)
18 changes: 18 additions & 0 deletions src/flask_inputfilter/Condition/NotEqualCondition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from typing import Any, Dict

from .BaseCondition import BaseCondition


class NotEqualCondition(BaseCondition):
"""
Condition that checks if two fields are not equal.
"""

def __init__(self, first_field: str, second_field: str) -> None:

self.first_field = first_field
self.second_field = second_field

def check(self, data: Dict[str, Any]) -> bool:

return data.get(self.first_field) != data.get(self.second_field)
Loading
Loading