Skip to content

Commit

Permalink
Merge pull request #36 from ziima/use-validators
Browse files Browse the repository at this point in the history
Replace checkers with validators
  • Loading branch information
pawamoy authored Sep 25, 2018
2 parents e864c7c + d113db9 commit db5f50e
Show file tree
Hide file tree
Showing 10 changed files with 418 additions and 128 deletions.
1 change: 1 addition & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ Authors

* Timothee Mazzucotelli - http://pawamoy.github.io/
* Jan Musílek - http://stinovlas.org/
* Vlastimil Zíma
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Changelog
=========

- Add ``NestedSetting`` for easy management of nested settings.
- Deprecate setting checkers in favor of validators, similarly to Django form fields.

0.3.0 (2017-11-30)
==================
Expand Down
9 changes: 5 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -125,16 +125,17 @@ You can easily create your own Setting classes for more complex settings.
.. code:: python
import re
import appsettings
from django.core.exceptions import ValidationError
class RegexSetting(appsettings.Setting):
def checker(self, name, value):
def validate(self, value):
re_type = type(re.compile(r'^$'))
if not isinstance(value, (re_type, str)):
# raise whatever exception
raise ValueError('%s must be a a string or a compiled regex '
'(use re.compile)' % name)
# Raise ValidationError
raise ValidationError('Value must be a string or a compiled regex (use re.compile)')
def transform(self, value):
# ensure it always returns a compiled regex
Expand Down
50 changes: 24 additions & 26 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -222,40 +222,34 @@ cache each time.
def test_string_list(self):
assert 'bye' in self.settings.string_list
Writing your own setting class
------------------------------
Customize setting validation
----------------------------

At some point you may want to have more complex settings. You can customize
how the setting is checked, but also how the value is transformed before being
returned.
.. note:: New in version 0.4.

The first way to customize the check method is to pass a callable
in the ``checker`` parameter of the setting. This callable must accepts
two parameters: name and value.
You may need to customize the setting validation.
Individual ``Settings`` use validation similar to Django form fields.

The easiest way is to pass additional validators when defining a setting.

.. code:: python
import re
import appsettings
from django.core.validators import EmailValidator
def regex_checker(name, value):
re_type = type(re.compile(r'^$'))
if not isinstance(value, (re_type, str)):
# raise whatever exception
raise ValueError('%s must be a a string or a compiled regex '
'(use re.compile)' % name)
setting = appsettings.StringSetting(validators=(EmailValidator(), ))
A more robust method is to create a subclass and define a ``default_validators``.

setting = appsettings.Setting(checker=regex_checker)
.. code:: python
.. important::
import appsettings
from django.core.validators import EmailValidator
Note that only the ``appsettings.Setting`` class accepts the ``checker``
parameter! Other subclasses like ``appsettings.PositiveIntegerSetting``
already have a custom checker and therefore do not allow to change it.
class EmailSetting(StringSetting):
default_validators = (EmailValidator(), )
The second way is to subclass ``appsettings.Setting`` and write a custom
``checker`` method:
The finest-grained customization can be obtained by overriding the ``validate()`` method.

.. code:: python
Expand All @@ -264,19 +258,21 @@ The second way is to subclass ``appsettings.Setting`` and write a custom
class RegexSetting(appsettings.Setting):
def checker(name, value):
def validate(self, value):
re_type = type(re.compile(r'^$'))
if not isinstance(value, (re_type, str)):
# raise whatever exception
raise ValueError('%s must be a a string or a compiled regex '
'(use re.compile)' % name)
# Raise ValidationError
raise ValidationError('%(value)s is not a string or a compiled regex (use re.compile)',
params={'value': value})
setting = RegexSetting()
Writing your own type checker
'''''''''''''''''''''''''''''

.. warning:: Checkers are deprecated, use validators instead.

The third way to customize how the setting is checked is to create
a new ``TypeChecker`` class:

Expand Down Expand Up @@ -326,6 +322,8 @@ a new ``TypeChecker`` class:
Extending type checker and setting classes
''''''''''''''''''''''''''''''''''''''''''

.. warning:: Checkers are deprecated, use validators instead.

In the previous example, we combined our own type checker to our own setting
class. But we can extend it furthermore by adding parameters to the type
checker, or by inheriting from previous type checkers.
Expand Down
2 changes: 1 addition & 1 deletion requirements/test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ pytest-cov==2.5.1

pytest-django==3.1.2


mock
9 changes: 8 additions & 1 deletion src/appsettings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@
NestedSetting, ObjectSetting, ObjectTypeChecker, PositiveFloatSetting,
PositiveIntegerSetting, SetSetting, Setting, SetTypeChecker, StringSetting,
StringTypeChecker, TupleSetting, TupleTypeChecker, TypeChecker)
from .validators import (
DictKeysTypeValidator, DictValuesTypeValidator, TypeValidator,
ValuesTypeValidator)

__all__ = (
'BooleanSetting',
'BooleanTypeChecker',
'DictKeysTypeValidator',
'DictSetting',
'DictTypeChecker',
'DictValuesTypeValidator',
'FloatSetting',
'FloatTypeChecker',
'IntegerSetting',
Expand All @@ -40,7 +45,9 @@
'StringTypeChecker',
'TupleSetting',
'TupleTypeChecker',
'TypeChecker'
'TypeChecker',
'TypeValidator',
'ValuesTypeValidator',
)


Expand Down
Loading

0 comments on commit db5f50e

Please sign in to comment.