diff --git a/.gitignore b/.gitignore index b928aa0..23bacdb 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,5 @@ dist/ test.py .coverage htmlcov/ -benchmarks/cases.json +benchmarks/*.json docs/_build/ diff --git a/benchmarks/run.py b/benchmarks/run.py index 73f1f43..6f90f4b 100644 --- a/benchmarks/run.py +++ b/benchmarks/run.py @@ -78,13 +78,13 @@ def generate_case(): id=random.randrange(1, 2000), client_name=null_missing_string(10, 280, null_chance=0.05, missing_chance=0.05), sort_index=random.random() * 200, - client_email=null_missing_email(), # email checks differ with different frameworks + # client_email=null_missing_email(), # email checks differ with different frameworks client_phone=null_missing_string(5, 15), location=dict( latitude=random.random() * 180 - 90, longitude=random.random() * 180, ), - contractor=str(random.randrange(50, 2000)), + contractor=str(random.randrange(-100, 2000)), upstream_http_referrer=null_missing_string(10, 1050), grecaptcha_response=null_missing_string(10, 1050, null_chance=0.05, missing_chance=0.05), last_updated=rand_date(), @@ -132,7 +132,7 @@ def main(): for i in range(repeats): count, pass_count = 0, 0 start = datetime.now() - test = test_class(False) + test = test_class(True) for i in range(3): for case in cases: passed, result = test.validate(case) @@ -153,5 +153,30 @@ def main(): print(r) +def diff(): + json_path = THIS_DIR / 'cases.json' + with json_path.open() as f: + cases = json.load(f) + + allow_extra = True + pydantic = TestPydantic(allow_extra) + others = [TestTrafaret(allow_extra), TestDRF(allow_extra)] + + for case in cases: + pydantic_passed, pydantic_result = pydantic.validate(case) + for other in others: + other_passed, other_result = other.validate(case) + if other_passed != pydantic_passed: + print(f'⨯ pydantic {pydantic_passed} != {other.package} {other_passed}') + print(json.dumps(case, indent=2)) + print(f'pydantic result: {pydantic_result}') + print(f'{other.package} result: {other_result}') + return + print('✓ data passes match for all packages') + + if __name__ == '__main__': - main() + if 'diff' in sys.argv: + diff() + else: + main() diff --git a/benchmarks/test_drf.py b/benchmarks/test_drf.py index d05499a..a377ef3 100644 --- a/benchmarks/test_drf.py +++ b/benchmarks/test_drf.py @@ -15,28 +15,18 @@ class TestDRF: id = serializers.IntegerField() client_name = serializers.CharField(max_length=255) sort_index = serializers.FloatField() - client_email = serializers.EmailField(required=False, - allow_null=True) - client_phone = serializers.CharField(max_length=255, - required=False, - allow_null=True) + # client_email = serializers.EmailField(required=False, allow_null=True) + client_phone = serializers.CharField(max_length=255, required=False, allow_null=True) class Location(serializers.Serializer): - latitude = serializers.FloatField(allow_null=True) - longitude = serializers.FloatField(allow_null=True) + latitude = serializers.FloatField(required=False, allow_null=True) + longitude = serializers.FloatField(required=False, allow_null=True) location = Location(required=False, allow_null=True) - contractor = serializers.IntegerField(required=False, - allow_null=True, - min_value=0) - upstream_http_referrer = serializers.CharField(max_length=1023, - required=False, - allow_null=True) - grecaptcha_response = serializers.CharField(min_length=20, - max_length=1000, - allow_null=True) - last_updated = serializers.DateTimeField(required=False, - allow_null=True) + contractor = serializers.IntegerField(required=False, allow_null=True, min_value=0) + upstream_http_referrer = serializers.CharField(max_length=1023, required=False, allow_null=True) + grecaptcha_response = serializers.CharField(min_length=20, max_length=1000) + last_updated = serializers.DateTimeField(required=False, allow_null=True) class Skill(serializers.Serializer): subject = serializers.CharField() diff --git a/benchmarks/test_pydantic.py b/benchmarks/test_pydantic.py index 76bc8c7..5e3dc21 100644 --- a/benchmarks/test_pydantic.py +++ b/benchmarks/test_pydantic.py @@ -1,7 +1,7 @@ from datetime import datetime from typing import List -from pydantic import BaseModel, constr, EmailStr +from pydantic import BaseModel, constr, EmailStr, PositiveInt, ValidationError class TestPydantic: @@ -13,7 +13,7 @@ class TestPydantic: id: int = ... client_name: constr(max_length=255) = ... sort_index: float = ... - client_email: EmailStr = None + # client_email: EmailStr = None client_phone: constr(max_length=255) = None class Location(BaseModel): @@ -21,7 +21,7 @@ class TestPydantic: longitude: float = None location: Location = None - contractor: int = None + contractor: PositiveInt = None upstream_http_referrer: constr(max_length=1023) = None grecaptcha_response: constr(min_length=20, max_length=1000) = ... last_updated: datetime = None @@ -43,5 +43,5 @@ class TestPydantic: def validate(self, data): try: return True, self.model(**data) - except ValueError: - return False, None + except ValidationError as e: + return False, str(e) diff --git a/benchmarks/test_trafaret.py b/benchmarks/test_trafaret.py index 31eac10..9f6fc28 100644 --- a/benchmarks/test_trafaret.py +++ b/benchmarks/test_trafaret.py @@ -10,7 +10,7 @@ class TestTrafaret: 'id': t.Int(), 'client_name': t.String(max_length=255), 'sort_index': t.Float, - t.Key('client_email', optional=True): t.Or(t.Null | t.Email()), + # t.Key('client_email', optional=True): t.Or(t.Null | t.Email()), t.Key('client_phone', optional=True): t.Or(t.Null | t.String(max_length=255)), t.Key('location', optional=True): t.Or(t.Null | t.Dict({