Skip to content

Commit b680e83

Browse files
authored
Merge pull request #666 from cordada/deploy/v0.31.0
Deploy release v0.31.0
2 parents 5ee3799 + 78db45b commit b680e83

13 files changed

+373
-2
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 0.30.0
2+
current_version = 0.31.0
33
commit = True
44
tag = False
55
message = chore: Bump version from {current_version} to {new_version}

HISTORY.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# History
22

3+
## 0.31.0 (2024-07-17)
4+
5+
- (PR #661, 2024-07-17) extras: Add `RutFilter` for Django views and DRF views
6+
- (PR #662, 2024-07-17) extras: Add Django URL path converter for RUT and Tipo DTE
7+
- (PR #663, 2024-07-17) extras: Add mapping of Django model fields to DRF serializer fields
8+
- (PR #664, 2024-07-17) extras: Reformat source code of `.dj_filters`
9+
310
## 0.30.0 (2024-07-11)
411

512
- (PR #640, 2024-05-20) chore: Bump the production-dependencies group across 1 directory with 5 updates

mypy.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ ignore_missing_imports = True
2929
[mypy-django.*]
3030
ignore_missing_imports = True
3131

32+
[mypy-django_filters.*]
33+
ignore_missing_imports = True
34+
3235
[mypy-lxml.*]
3336
ignore_missing_imports = True
3437

requirements.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
backports-zoneinfo==0.2.1 ; python_version < "3.9" # Used by `djangorestframework`.
99
cryptography==42.0.8
1010
defusedxml==0.7.1
11+
django-filter>=24.2
1112
Django>=2.2.24
1213
djangorestframework>=3.10.3,<3.16
1314
importlib-metadata==7.1.0

requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ defusedxml==0.7.1
3131
django==4.2.14
3232
# via
3333
# -r requirements.in
34+
# django-filter
3435
# djangorestframework
36+
django-filter==24.2
37+
# via -r requirements.in
3538
djangorestframework==3.15.2
3639
# via -r requirements.in
3740
importlib-metadata==7.1.0

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def get_version(*file_paths: str) -> str:
3434

3535
extras_requirements = {
3636
'django': ['Django>=2.2.24'],
37+
'django-filter': ['django-filter>=24.2'],
3738
'djangorestframework': ['djangorestframework>=3.10.3,<3.16'],
3839
}
3940

src/cl_sii/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
55
"""
66

7-
__version__ = '0.30.0'
7+
__version__ = '0.31.0'

src/cl_sii/extras/dj_filters.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
"""
2+
cl_sii "extras" / Django-Filter.
3+
4+
(for Django views and DRF views)
5+
"""
6+
7+
from __future__ import annotations
8+
9+
10+
try:
11+
import django_filters
12+
except ImportError as exc: # pragma: no cover
13+
raise ImportError("Package 'django-filter' is required to use this module.") from exc
14+
15+
from copy import deepcopy
16+
from typing import ClassVar, Mapping, Tuple, Type
17+
18+
import django.db.models
19+
import django.forms
20+
21+
import cl_sii.extras.dj_form_fields
22+
import cl_sii.extras.dj_model_fields
23+
24+
25+
FILTER_FOR_DBFIELD_DEFAULTS: Mapping[Type[django.db.models.Field], Mapping[str, object]]
26+
FILTER_FOR_DBFIELD_DEFAULTS = deepcopy(django_filters.filterset.FILTER_FOR_DBFIELD_DEFAULTS)
27+
28+
29+
class RutFilter(django_filters.filters.CharFilter):
30+
"""
31+
Matches on a RUT.
32+
33+
Used with :class:`cl_sii.extras.dj_form_fields.RutField` by default.
34+
35+
.. seealso::
36+
- https://django-filter.readthedocs.io/en/stable/ref/filters.html
37+
- https://github.com/carltongibson/django-filter/blob/24.2/docs/ref/filters.txt
38+
"""
39+
40+
field_class: ClassVar[Type[django.forms.Field]]
41+
field_class = cl_sii.extras.dj_form_fields.RutField
42+
43+
44+
FILTER_FOR_DBFIELD_DEFAULTS = {
45+
**FILTER_FOR_DBFIELD_DEFAULTS,
46+
cl_sii.extras.dj_model_fields.RutField: {'filter_class': RutFilter},
47+
}
48+
49+
50+
class SiiFilterSet(django_filters.filterset.FilterSet):
51+
"""
52+
Custom filterset with extra database field mappings.
53+
54+
This class serves as a base class for filtersets that additionally need to
55+
support filtering one of the following database fields:
56+
- :class:`cl_sii.extras.dj_model_fields.RutField`
57+
58+
.. seealso::
59+
- https://django-filter.readthedocs.io/en/main/ref/filterset.html
60+
- https://github.com/carltongibson/django-filter/blob/24.2/docs/ref/filterset.txt
61+
"""
62+
63+
FILTER_DEFAULTS: ClassVar[Mapping[Type[django.db.models.Field], Mapping[str, object]]]
64+
FILTER_DEFAULTS = FILTER_FOR_DBFIELD_DEFAULTS
65+
66+
@classmethod
67+
def filter_for_lookup(
68+
cls, field: django.db.models.Field, lookup_type: str
69+
) -> Tuple[Type[django_filters.filters.Filter], Mapping[str, object]]:
70+
filter_class, params = super().filter_for_lookup(field, lookup_type)
71+
72+
# Override RUT containment lookups.
73+
if isinstance(field, cl_sii.extras.dj_model_fields.RutField) and lookup_type in (
74+
'contains',
75+
'icontains',
76+
):
77+
filter_class, params = django_filters.filters.CharFilter, {}
78+
79+
return filter_class, params
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""
2+
cl_sii "extras" / Django URL converters.
3+
"""
4+
5+
from __future__ import annotations
6+
7+
from typing import ClassVar
8+
9+
import cl_sii.dte.constants
10+
import cl_sii.rut
11+
12+
13+
class RutConverter:
14+
"""
15+
Django URL path converter for Chilean RUT.
16+
17+
Thousands separators are not supported.
18+
19+
Example:
20+
21+
>>> from django.urls import path, register_converter
22+
>>> register_converter(RutConverter, 'cl_sii_rut')
23+
>>> urlpatterns = [path('example/<cl_sii_rut:emisor_rut>/', ...)]
24+
25+
.. seealso::
26+
https://docs.djangoproject.com/en/4.2/topics/http/urls/#registering-custom-path-converters
27+
"""
28+
29+
regex: ClassVar[str] = r'\d{1,8}-[\dKk]'
30+
31+
def to_python(self, value: str) -> cl_sii.rut.Rut:
32+
return cl_sii.rut.Rut(value)
33+
34+
def to_url(self, value: cl_sii.rut.Rut) -> str:
35+
return str(value)
36+
37+
38+
class TipoDteConverter:
39+
"""
40+
Django URL path converter for `Tipo DTE` object.
41+
42+
Example:
43+
44+
>>> from django.urls import path, register_converter
45+
>>> register_converter(TipoDteConverter, 'cl_sii_tipo_dte')
46+
>>> urlpatterns = [path('example/<cl_sii_tipo_dte:tipo_dte>/', ...)]
47+
48+
.. seealso::
49+
https://docs.djangoproject.com/en/4.2/topics/http/urls/#registering-custom-path-converters
50+
"""
51+
52+
regex: ClassVar[str] = r'\d{2,3}'
53+
54+
def to_python(self, value: str) -> cl_sii.dte.constants.TipoDte:
55+
return cl_sii.dte.constants.TipoDte(int(value))
56+
57+
def to_url(self, value: cl_sii.dte.constants.TipoDte) -> str:
58+
return str(value.value)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from __future__ import annotations
2+
3+
4+
try:
5+
import rest_framework
6+
except ImportError as exc: # pragma: no cover
7+
raise ImportError("Package 'djangorestframework' is required to use this module.") from exc
8+
try:
9+
import django
10+
except ImportError as exc: # pragma: no cover
11+
raise ImportError("Package 'Django' is required to use this module.") from exc
12+
13+
from typing import Mapping, Type
14+
15+
import django.db.models
16+
import rest_framework.serializers
17+
18+
import cl_sii.extras.dj_model_fields
19+
import cl_sii.extras.drf_fields
20+
21+
22+
model_serializer_field_mapping: Mapping[
23+
Type[django.db.models.Field], Type[rest_framework.serializers.Field]
24+
]
25+
"""
26+
Mapping of Django model fields to DRF serializer fields.
27+
28+
Use this to extend DRF serializers that inherit from :class:`ModelSerializer` so
29+
that Django model fields from :mod:`cl_sii.extras.dj_model_fields` do not have
30+
to be explicitly defined in the serializer.
31+
32+
Usage example:
33+
34+
>>> class ExampleSerializer(rest_framework.serializers.ModelSerializer):
35+
... serializer_field_mapping = {
36+
... **rest_framework.serializers.ModelSerializer.serializer_field_mapping,
37+
... **model_serializer_field_mapping,
38+
... }
39+
"""
40+
model_serializer_field_mapping = {
41+
cl_sii.extras.dj_model_fields.RutField: cl_sii.extras.drf_fields.RutField,
42+
}

0 commit comments

Comments
 (0)