Skip to content

Commit

Permalink
Merge pull request #198 from fyntex/develop
Browse files Browse the repository at this point in the history
Release v0.12.3
  • Loading branch information
ycouce-cdd committed Feb 26, 2021
2 parents 2d010fd + 355cae1 commit 0d54e13
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.12.2
current_version = 0.12.3
commit = True
tag = True

Expand Down
6 changes: 6 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
History
-------

0.12.3 (2021-02-26)
+++++++++++++++++++++++

* (PR #193, 2021-02-16) requirements: Update dependency graph of base requirements
* (PR #197, 2021-02-26) extras: add 'RutField' for Django forms

0.12.2 (2021-02-16)
+++++++++++++++++++++++

Expand Down
2 changes: 1 addition & 1 deletion cl_sii/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
"""


__version__ = '0.12.2'
__version__ = '0.12.3'
73 changes: 73 additions & 0 deletions cl_sii/extras/dj_form_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""
cl_sii "extras" / Django form fields.
"""
try:
import django
except ImportError as exc: # pragma: no cover
raise ImportError("Package 'Django' is required to use this module.") from exc

from typing import Any, Optional

import django.core.exceptions
import django.forms
from django.utils.translation import gettext_lazy as _

from cl_sii.rut import Rut


class RutField(django.forms.CharField):

"""
Django form field for RUT.
* Python data type: :class:`cl_sii.rut.Rut`
.. seealso::
:class:`.dj_model_fields.RutField`
"""

default_error_messages = {
'invalid': _('Enter a valid RUT.'),
'invalid_dv': _('RUT\'s "digito verificador" is incorrect.'),
}

def __init__(self, *, validate_dv: bool = False, **kwargs: Any) -> None:
"""
:param validate_dv: Boolean that specifies whether to validate that
the RUT's "digito verificador" is correct. False by default.
"""

self.validate_dv = validate_dv
super().__init__(strip=True, **kwargs)

def to_python(self, value: Optional[object]) -> Optional[Rut]:
"""
Validate that the input can be converted to a Python object (:class:`Rut`).
:raises django.core.exceptions.ValidationError:
if the input can't be converted
"""

if value in self.empty_values:
converted_value = None
elif isinstance(value, Rut):
converted_value = value
else:
try:
converted_value = Rut(value) # type: ignore[arg-type]
except (AttributeError, TypeError, ValueError):
raise django.core.exceptions.ValidationError(
self.error_messages['invalid'],
code='invalid',
)

if (converted_value is not None and self.validate_dv
and Rut.calc_dv(converted_value.digits) != converted_value.dv):
raise django.core.exceptions.ValidationError(
self.error_messages['invalid_dv'],
code='invalid_dv',
)

return converted_value
10 changes: 6 additions & 4 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,23 @@ signxml==2.8.1
# - cffi:
# - pycparser
# - six
# - jsonschema
# - jsonschema:
# - attrs
# - importlib-metadata (python_version<'3.8')
# - zipp
# - pyrsistent
# - setuptools
# - six
# - pyOpenSSL:
# - cryptography
# - six
# - signxml:
# - certifi
# - cryptography
# - eight
# - eight:
# - future
# - lxml
# - pyOpenSSL
# - six
attrs==20.3.0
certifi==2020.12.5
cffi==1.14.0
Expand All @@ -42,4 +44,4 @@ pycparser==2.20
pyrsistent==0.17.3
# setuptools
six==1.15.0
zipp==3.4.0
zipp==3.4.0 ; python_version < "3.8"
71 changes: 71 additions & 0 deletions tests/test_extras_dj_form_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import unittest

import django.core.exceptions

from cl_sii.extras.dj_form_fields import Rut, RutField


class RutFieldTest(unittest.TestCase):
valid_rut_canonical: str
valid_rut_instance: Rut
valid_rut_verbose_leading_zero_lowercase: str

@classmethod
def setUpClass(cls) -> None:
cls.invalid_rut_canonical = '60803000K'
cls.valid_rut_canonical = '60803000-K'
cls.valid_rut_instance = Rut(cls.valid_rut_canonical)
cls.valid_rut_canonical_with_invalid_dv = '60803000-0'
cls.valid_rut_canonical_instance_with_invalid_dv = Rut(
cls.valid_rut_canonical_with_invalid_dv
)
cls.valid_rut_verbose_leading_zero_lowercase = '060.803.000-k'

def test_clean_value_of_invalid_canonical_str(self) -> None:
rut_field = RutField()
with self.assertRaises(django.core.exceptions.ValidationError) as cm:
rut_field.clean(self.invalid_rut_canonical)
self.assertEqual(cm.exception.code, 'invalid')

def test_clean_value_of_canonical_str(self) -> None:
rut_field = RutField()
cleaned_value = rut_field.clean(self.valid_rut_canonical)
self.assertIsInstance(cleaned_value, Rut)
self.assertEqual(cleaned_value.canonical, self.valid_rut_canonical)

def test_clean_value_of_non_canonical_str(self) -> None:
rut_field = RutField()
cleaned_value = rut_field.clean(self.valid_rut_verbose_leading_zero_lowercase)
self.assertIsInstance(cleaned_value, Rut)
self.assertEqual(cleaned_value.canonical, self.valid_rut_canonical)

def test_clean_value_of_Rut(self) -> None:
rut_field = RutField()
cleaned_value = rut_field.clean(self.valid_rut_instance)
self.assertIsInstance(cleaned_value, Rut)
self.assertEqual(cleaned_value.canonical, self.valid_rut_canonical)

def test_clean_value_of_rut_str_with_invalid_dv_if_validated(self) -> None:
rut_field = RutField(validate_dv=True)
with self.assertRaises(django.core.exceptions.ValidationError) as cm:
rut_field.clean(self.valid_rut_canonical_with_invalid_dv)
self.assertEqual(cm.exception.code, 'invalid_dv')

def test_clean_value_of_rut_str_with_invalid_dv_if_not_validated(self) -> None:
rut_field = RutField(validate_dv=False)
cleaned_value = rut_field.clean(self.valid_rut_canonical_with_invalid_dv)
self.assertIsInstance(cleaned_value, Rut)
self.assertEqual(cleaned_value.canonical, self.valid_rut_canonical_with_invalid_dv)

def test_clean_of_empty_value_if_not_required(self) -> None:
rut_field = RutField(required=False)
for value in RutField.empty_values:
cleaned_value = rut_field.clean(value)
self.assertIsNone(cleaned_value)

def test_clean_of_empty_value_if_required(self) -> None:
rut_field = RutField()
for value in RutField.empty_values:
with self.assertRaises(django.core.exceptions.ValidationError) as cm:
rut_field.clean(value)
self.assertEqual(cm.exception.code, 'required')

0 comments on commit 0d54e13

Please sign in to comment.