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
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[flake8]
exclude = __init__.py, venv, *.md, .*
max-line-length = 90
8 changes: 4 additions & 4 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

### Build docker image
```bash
docker build -t jtrfaker .
docker build -t flask-inputfilter .
```

### Run docker container in interactive mode
Expand All @@ -11,15 +11,15 @@ docker compose up -d
```

```bash
docker exec -it jtrfaker bash
docker exec -it flask-inputfilter /bin/bash
```

### Run tests
```bash
docker exec -it jtrfaker pytest
docker exec -it flask-inputfilter pytest
```

### Run linting
```bash
docker exec -it jtrfaker flake8
docker exec -it flask-inputfilter black .
```
35 changes: 30 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ It provides a modular way to clean and ensure that incoming data meets expected
pip install flask-inputfilter
```

## Usage
## 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.
Expand All @@ -19,8 +19,8 @@ There are lots of different filters and validators available to use, and you can
```python
from flask_inputfilter import InputFilter
from flask_inputfilter.Enum import RegexEnum
from flask_inputfilter.Filter import ToIntegerFilter, ToNullFilter, StringTrimFilter
from flask_inputfilter.Validator import RegexValidator
from flask_inputfilter.Filter import StringTrimFilter, ToIntegerFilter, ToNullFilter
from flask_inputfilter.Validator import IsIntegerValidator, RegexValidator


class UpdateZipcodeInputFilter(InputFilter):
Expand All @@ -31,7 +31,10 @@ class UpdateZipcodeInputFilter(InputFilter):
self.add(
'id',
required=True,
filters=[ToIntegerFilter(), ToNullFilter()]
filters=[ToIntegerFilter(), ToNullFilter()],
validators=[
IsIntegerValidator()
]
)

self.add(
Expand All @@ -41,7 +44,7 @@ class UpdateZipcodeInputFilter(InputFilter):
validators=[
RegexValidator(
RegexEnum.POSTAL_CODE.value,
'The email is not in the format of an email.'
'The zipcode is not in the correct format.'
)
]
)
Expand Down Expand Up @@ -69,3 +72,25 @@ def updateZipcode():
zipcode = data.get('zipcode')
```

## Options

The `add` method takes the following options:

- [`Required`](#required)
- [`Filter`](src/flask_inputfilter/Filter/README.md)
- [`Validator`](src/flask_inputfilter/Validator/README.md)
- [`Default`](#default)
- [`Fallback`](#fallback)

### Required

The `required` option is used to specify if the field is required or not.
If the field is required and not present in the input data, the `validate` method will return a 400 response with the error message.

### Default

The `default` option is used to specify a default value to use if the field is not present in the input data.

### Fallback

The `fallback` option is used to specify a fallback value to use if the field is not present in the input data, although it is required or the validation fails.
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

[tool.black]
line-length = 90
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ pillow==2.0.0
pytest
setuptools
twine
black
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
version="0.0.3",
author="Leander Cain Slotosch",
author_email="[email protected]",
description="A library to filter and validate input data in"
"Flask applications",
description="A library to filter and validate input data in" "Flask applications",
long_description=open("README.md").read(),
long_description_content_type="text/markdown",
url="https://github.com/LeanderCS/flask-inputfilter",
Expand Down
19 changes: 10 additions & 9 deletions src/flask_inputfilter/Enum/RegexEnum.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ class RegexEnum(Enum):
Enum for regex patterns.
"""

EMAIL = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
EMAIL = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"

IPV4_ADDRESS = r'^(?:\d{1,3}\.){3}\d{1,3}$'
IPV6_ADDRESS = r'^\[?([a-fA-F0-9:]+:+)+[a-fA-F0-9]+\]?$'
IPV4_ADDRESS = r"^(?:\d{1,3}\.){3}\d{1,3}$"
IPV6_ADDRESS = r"^\[?([a-fA-F0-9:]+:+)+[a-fA-F0-9]+\]?$"

ISO_DATE = r'^\d{4}-\d{2}-\d{2}$'
ISO_DATETIME = (r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}'
r'(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?$')
ISO_DATE = r"^\d{4}-\d{2}-\d{2}$"
ISO_DATETIME = (
r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}" r"(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?$"
)

PHONE_NUMBER = r'^\+?[\d\s\-()]{7,}$'
PHONE_NUMBER = r"^\+?[\d\s\-()]{7,}$"

POSTAL_CODE = r'^\d{4,10}$'
POSTAL_CODE = r"^\d{4,10}$"

URL = r'^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$'
URL = r"^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$"
1 change: 0 additions & 1 deletion src/flask_inputfilter/Exception/ValidationError.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

class ValidationError(Exception):
"""
This class is used to raise an exception when a validation error occurs.
Expand Down
20 changes: 20 additions & 0 deletions src/flask_inputfilter/Filter/ArrayExplodeFilter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import Any, List, Optional

from ..Filter.BaseFilter import BaseFilter


class ArrayExplodeFilter(BaseFilter):
"""
Filter that splits a string into an array based on a specified delimiter.
"""

def __init__(self, delimiter: str = ",") -> None:

self.delimiter = delimiter

def apply(self, value: Any) -> Optional[List[str]]:

if not isinstance(value, str):
return None

return value.split(self.delimiter)
21 changes: 21 additions & 0 deletions src/flask_inputfilter/Filter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Filter

The `Filter` module contains the filters that can be used to filter the input data.

## Available filters

The following filters are available in the `Filter` module:

1. [`ArrayExplodeFilter`](src/flask_inputfilter/Filter/ArrayExplodeFilter.py) - Explodes the input string into an array.
2. [`StringTrimFilter`](src/flask_inputfilter/Filter/StringTrimFilter.py) - Trims the whitespace from the beginning and end of the string.
3. [`ToBooleanFilter`](src/flask_inputfilter/Filter/ToBooleanFilter.py) - Converts the string to a boolean value.
4. [`ToCamelCaseFilter`](src/flask_inputfilter/Filter/ToCamelCaseFilter.py) - Converts the string to camel case.
5. [`ToFloatFilter`](src/flask_inputfilter/Filter/ToFloatFilter.py) - Converts the string to a float value.
5. [`ToIntegerFilter`](src/flask_inputfilter/Filter/ToIntegerFilter.py) - Converts the string to an integer value.
6. [`ToLowerFilter`](src/flask_inputfilter/Filter/ToLowerFilter.py) - Converts the string to lowercase.
7. [`ToNullFilter`](src/flask_inputfilter/Filter/ToNullFilter.py) - Converts the string to `None` if it is already `None` or `''` (empty string).
8. [`ToPascaleCaseFilter`](src/flask_inputfilter/Filter/ToPascaleCaseFilter.py) - Converts the string to pascal case.
9. [`ToSnakeCaseFilter`](src/flask_inputfilter/Filter/ToSnakeCaseFilter.py) - Converts the string to snake case.
9. [`ToStringFilter`](src/flask_inputfilter/Filter/ToStringFilter.py) - Converts the input to a string value.
9. [`ToUpperFilter`](src/flask_inputfilter/Filter/ToUpperFilter.py) - Converts the string to uppercase.
10. [`WhitespaceCollapseFilter`](src/flask_inputfilter/Filter/WhitespaceCollapseFilter.py) - Collapses the whitespace in the string.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from ..Filter import BaseFilter


class ToBoolFilter(BaseFilter):
class ToBooleanFilter(BaseFilter):
"""
Filter, that transforms the value to a boolean.
"""
Expand Down
21 changes: 21 additions & 0 deletions src/flask_inputfilter/Filter/ToCamelCaseFilter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import re
from typing import Any, Optional

from ..Filter import BaseFilter


class ToCamelCaseFilter(BaseFilter):
"""
Filter that converts a string to camelCase.
"""

def apply(self, value: Any) -> Optional[str]:

if not isinstance(value, str):
return None

value = re.sub(r"[\s-_]+", " ", value).strip()

value = "".join(word.capitalize() for word in value.split())

return value[0].lower() + value[1:] if value else value
2 changes: 1 addition & 1 deletion src/flask_inputfilter/Filter/ToNullFilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ class ToNullFilter(BaseFilter):

def apply(self, value: Any) -> Optional[Any]:

return None if value in ('', None) else value
return None if value in ("", None) else value
21 changes: 21 additions & 0 deletions src/flask_inputfilter/Filter/ToPascaleCaseFilter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import re
from typing import Any, Optional

from ..Filter.BaseFilter import BaseFilter


class ToPascaleCaseFilter(BaseFilter):
"""
Filter that converts a string to PascalCase.
"""

def apply(self, value: Any) -> Optional[str]:

if not isinstance(value, str):
return None

value = re.sub(r"[\s\-_]+", " ", value).strip()

value = "".join(word.capitalize() for word in value.split())

return value
21 changes: 21 additions & 0 deletions src/flask_inputfilter/Filter/ToSnakeCaseFilter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import re
from typing import Any, Optional

from ..Filter.BaseFilter import BaseFilter


class ToSnakeCaseFilter(BaseFilter):
"""
Filter that converts a string to snake_case.
"""

def apply(self, value: Any) -> Optional[str]:

if not isinstance(value, str):
return None

value = re.sub(r"(?<!^)(?=[A-Z])", "_", value).lower()

value = re.sub(r"[\s-]+", "_", value)

return value
19 changes: 19 additions & 0 deletions src/flask_inputfilter/Filter/WhitespaceCollapseFilter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import re
from typing import Any, Optional

from ..Filter.BaseFilter import BaseFilter


class WhitespaceCollapseFilter(BaseFilter):
"""
Filter that collapses multiple consecutive whitespace characters into a single space.
"""

def apply(self, value: Any) -> Optional[str]:

if not isinstance(value, str):
return None

value = re.sub(r"\s+", " ", value).strip()

return value
7 changes: 6 additions & 1 deletion src/flask_inputfilter/Filter/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
from .ArrayExplodeFilter import ArrayExplodeFilter
from .BaseFilter import BaseFilter
from .StringTrimFilter import StringTrimFilter
from .ToBoolFilter import ToBoolFilter
from .ToBooleanFilter import ToBooleanFilter
from .ToCamelCaseFilter import ToCamelCaseFilter
from .ToFloatFilter import ToFloatFilter
from .ToIntegerFilter import ToIntegerFilter
from .ToLowerFilter import ToLowerFilter
from .ToNullFilter import ToNullFilter
from .ToPascaleCaseFilter import ToPascaleCaseFilter
from .ToSnakeCaseFilter import ToSnakeCaseFilter
from .ToStringFilter import ToStringFilter
from .ToUpperFilter import ToUpperFilter
from .WhitespaceCollapseFilter import WhitespaceCollapseFilter
Loading
Loading