pip install portafilter
from portafilter import Validator
validator = Validator(
{
'name': 'espresso',
'description': 'Espresso is both a coffee beverage and a brewing method.',
},
{
'name': 'required',
'description': 'required|max:255',
}
)
Next, check the validation state and get the error messages:
if validator.fails():
# The data is not valid
print(validator.errors())
# The data is valid
Or use the "validate" method directly:
from portafilter.exceptions import ValidationError
try:
validator.validate()
# The data is valid
except ValidationError as e:
# The data is not valid
print(validator.errors())
from portafilter import Validator
validator = Validator(
{
'name': 10,
'description': 'Espresso is both a coffee beverage and a brewing method.',
'ingredients': [
{
'name': 'Robusta',
},
{
'price': 2,
},
'Microfoam',
],
},
{
'name': 'required|string|min:5',
'description': 'required|max:255',
'ingredients.*': 'required|dict',
'ingredients.*.name': 'required|string',
}
)
if validator.fails():
print(validator.errors())
And, the error messages are:
{
"ingredients.1.name":
[
"The ingredients.1.name field is required.",
"The ingredients.1.name must be a string."
],
"ingredients.2":
[
"The ingredients.2 must be a dictionary."
],
"ingredients.2.name":
[
"The ingredients.2.name field is required.",
"The ingredients.2.name must be a string."
],
"name":
[
"The name must be a string.",
"The name must be at least 5 characters."
]
}
Note that nested error keys are flattened into "dot" notation format.
from portafilter import Validator
validator = Validator(
{
'menu': ['Espresso', 'Mocha', 'Latte'],
},
{
'coffee': 'list', # 'coffee': 'list:string',
}
)
print(validator.fails()) # It returns False
The acceptable types are: dict, string, integer, numeric, boolean.
from portafilter import Validator
validator = Validator(
{
'coffee': {
'name': 'Frappe',
'description': 'A Frappe coffee is a Greek iced coffee drink made from instant coffee.',
'available': True,
},
},
{
'coffee': 'dict:name,description',
}
)
if validator.fails():
print(validator.errors())
// Validate that a string is exactly 12 characters long
'title': 'size:12'
// Validate that a provided integer equals 10
'count': 'integer|size:10'
// Validate that a provided numeric equals 10
'weight': 'numeric|size:10.2'
// Validate that an list has exactly 5 elements
'menu': 'list|size:5'
from portafilter import Validator
validator = Validator(
{
'date': '2023-01-06',
},
{
'date': 'date|between:2023-01-04,2023-01-10',
}
)
print(validator.fails()) # It returns False
from portafilter import Validator
validator = Validator(
{
'weight': 10.2,
},
{
'weight': 'numeric|in:0,10,10.1,10.5,11',
}
)
print(validator.fails()) # It returns False
However, you can use the "InRule" class directly to include any specific type:
from portafilter import Validator
from portafilter.rules import InRule
validator = Validator(
{
'date': 10.1,
},
{
'date': ['numeric', InRule(0, 10, 10.1, 10.5, 11)],
}
)
print(validator.fails()) # It returns False
from portafilter import Validator
validator = Validator(
{
'ingredients': ['water', 'microfoam', 'robusta', 100],
},
{
'ingredients': 'required|contains:water,microfoam,100',
}
)
validator.fails() # It returns True
To detect the item types in lists, you can use the "ContainRule" directly:
from portafilter import Validator
from portafilter.rules import ContainsRule
validator = Validator(
{
'ingredients': ['water', 'microfoam', 'robusta', 100],
},
{
'ingredients': ['required', ContainsRule('water', 'microfoam', 100)],
}
)
print(validator.fails()) # It returns False
from portafilter import Validator
validator = Validator(
{
'date': '2023-01-06 12:00:00',
},
{
'date': 'date:%Y-%m-%d %H:%M:%S',
}
)
print(validator.fails()) # It returns False
from portafilter import Validator
validator = Validator(
{
'date': '2023-01-05',
},
{
'date': 'required|date|before:today',
}
)
print(validator.fails()) # It returns False
Instead of passing a date string, you may specify another field to compare against the date:
from portafilter import Validator
validator = Validator(
{
'start_date': '2023-01-05',
'end_date': '2023-01-06',
},
{
'start_date': 'required|before:end_date',
'end_date': 'required|date',
}
)
print(validator.fails()) # It returns False
from portafilter import Validator
validator = Validator(
{
'coffee': {
'name': 'Doppio',
},
},
{
'coffee.name': 'required|string|in:Doppio,Espresso,Lungo',
}
)
print(validator.fails()) # It returns False
You may also validate each element of a list:
from portafilter import Validator
validator = Validator(
{
'menu': [
{
'id': 1,
'name': 'Espresso',
},
{
'id': 2,
'name': None,
},
{
'name': 'Flat white',
},
],
},
{
'menu.*.id': 'required|integer',
'menu.*.name': 'required|string',
}
)
if validator.fails():
print(validator.errors())
And the errors are:
{
"menu.1.name":
[
"The menu.1.name field is required.",
"The menu.1.name must be a string."
],
"menu.2.id":
[
"The menu.2.id field is required.",
"The menu.2.id must be an integer."
]
}
from portafilter import Rule
class AgeVerificationRule(Rule):
def passes(self, attribute, value, params) -> bool:
"""Determine if the validation rule passes.
Arguments:
attribute {str}
value {Any}
params {List[str]}
Returns:
bool
"""
age_check = self.get_params()[0] if self.get_params() else 18
return isinstance(value, int) and value >= age_check
def message(self, attribute, value, params) -> str:
"""The validation error message.
Arguments:
attribute {str}
value {Any}
params {List[str]}
Returns:
str
"""
return f'The {attribute} must be greater than {params[0]}.'
Now, assign the custom rule to the attributes. You can create an instance of the rule with the proper additional parameters or just pass the reference of it:
from portafilter import Validator
validator = Validator(
{
'age': 18,
},
{
'age': ['required', 'integer', AgeVerificationRule],
}
)
print(validator.fails()) # It returns False
The additional parameters must pass as the arguments: CustomRule(foo, bar, ...)
'age': ['required', 'integer', AgeVerificationRule(18)]
from portafilter import Ruleset
class EmailRuleset(Ruleset):
rules = 'string|email'
class CustomEmailRuleset(Ruleset):
rules = [EmailRuleset, EmailDomainRule]
Now, you are able to assign a ruleset or multiple rulesets to an attribute:
from portafilter import Validator
validator = Validator(
{
'admin_email': 'espresso@portafilter.dev',
'customer_email': 'aryan.arabshahi.programmer@gmail.com',
},
{
'admin_email': ['required', EmailRuleset, CustomEmailRuleset],
'customer_email': EmailRuleset,
}
)
from portafilter import validate
from portafilter.exceptions import ValidationError
class EspressoMachine:
@validate(name='required|string', microfoam='required|boolean', chocolate='required|numeric', sugar='boolean')
def make_coffee(self, name, microfoam, chocolate, sugar = False) -> None:
pass
try:
EspressoMachine().make_coffee('Espresso', True, chocolate=10, sugar=None)
except ValidationError as e:
print(e.get_errors())