Coverage for audoma/drf/fields.py: 28%
65 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-08-12 12:52 +0000
« prev ^ index » next coverage.py v6.4.2, created at 2022-08-12 12:52 +0000
1"""
2This module is an override for default drf's field module.
3Most of those fields, are providing additional example functionality,
4and also has defined schema type.
5"""
7import sys
9import exrex
10import phonenumbers
11from djmoney.contrib.django_rest_framework import MoneyField
12from drf_spectacular.types import OpenApiTypes
13from drf_spectacular.utils import extend_schema_field
14from phonenumber_field import serializerfields
15from phonenumber_field.phonenumber import to_python
16from rest_framework import fields
17from rest_framework.fields import * # noqa: F403, F401
19from django.core import validators
21from audoma.example_generators import generate_lorem_ipsum
22from audoma.mixins import (
23 ExampleMixin,
24 NumericExampleMixin,
25 RegexExampleMixin,
26)
29field_names = [
30 "BooleanField",
31 "NullBooleanField",
32 "EmailField",
33 "SlugField",
34 "URLField",
35 "DateTimeField",
36 "DurationField",
37 "ChoiceField",
38 "MultipleChoiceField",
39 "FilePathField",
40 "FileField",
41 "ImageField",
42 "ListField",
43 "DictField",
44 "HStoreField",
45 "JSONField",
46 "ReadOnlyField",
47 "SerializerMethodField",
48] # pragma: no cover
51this = sys.modules[__name__]
54for field_name in field_names:
56 setattr(
57 this,
58 field_name,
59 type(field_name, (ExampleMixin, getattr(fields, field_name)), {}),
60 )
63class DecimalField(NumericExampleMixin, fields.DecimalField):
64 pass
67@extend_schema_field(OpenApiTypes.UUID)
68class UUIDField(ExampleMixin, fields.UUIDField):
69 pass
72class IntegerField(NumericExampleMixin, fields.IntegerField):
73 pass
76class FloatField(NumericExampleMixin, fields.FloatField):
77 pass
80class RegexField(RegexExampleMixin, fields.RegexField):
81 pass
84class MACAddressField(RegexExampleMixin, fields.CharField):
85 def __init__(self, **kwargs) -> None:
86 self.regex = "^([0-9A-F]{2}:){5}([0-9A-F]{2})|([0-9A-F]{2}-){5}([0-9A-F]{2})$"
87 self.validators = [validators.RegexValidator(self.regex)]
88 super().__init__(**kwargs)
91@extend_schema_field(OpenApiTypes.DATE)
92class DateField(ExampleMixin, fields.DateField):
93 pass
96@extend_schema_field(OpenApiTypes.TIME)
97class TimeField(ExampleMixin, fields.TimeField):
98 pass
101@extend_schema_field(
102 field={
103 "format": "ip-address",
104 "example": str(
105 exrex.getone(
106 r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
107 )
108 ),
109 }
110)
111class IPAddressField(ExampleMixin, fields.IPAddressField):
112 pass
115@extend_schema_field(field={"format": "tel"})
116class PhoneNumberField(ExampleMixin, serializerfields.PhoneNumberField):
117 def __init__(self, *args, **kwargs) -> None:
118 example = kwargs.pop("example", None)
119 if example is None:
120 number = phonenumbers.example_number(None)
121 example = str(to_python(number))
122 super().__init__(*args, example=example, **kwargs)
125class CharField(ExampleMixin, fields.CharField):
126 def __init__(self, *args, **kwargs) -> None:
127 example = kwargs.pop("example", None)
128 min_length = kwargs.get("min_length", 20)
129 max_length = kwargs.get("max_length", 80)
130 if not example:
131 example = generate_lorem_ipsum(min_length=min_length, max_length=max_length)
133 super().__init__(*args, example=example, **kwargs)
136class MoneyField(NumericExampleMixin, MoneyField):
137 pass
140class ChoiceField(ExampleMixin, fields.ChoiceField):
141 def __init__(self, choices, **kwargs):
142 if isinstance(choices, dict):
143 self.original_choices = list(choices.items())
144 else:
145 self.original_choices = choices
146 super().__init__(choices, **kwargs)