New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding support for Decimal type (Decimal module) #332
Conversation
i'm not sure whether that makes sense. in opposite to other possible constraints, this test doesn't relate to an actual Python type. it tests whether a value can be used to initialize a in the not-so-fundamental-points category:
now, some more fundamental stuff again:
i tend to recommend you to use it custom validators. |
Hi! decimal module is native in python since version 2.4, therefore all python version has it. Regarding your question, I understand your point, but it is used a lot to provide support for prices and everywhere you want to keep the decimal part without approximation. Regards, |
27b11c4
to
7f90311
Compare
@nicolaiarocci I did the PR to start to add the decimal data type to Cerberus in order to have it available in pyeve/eve as well. Regards, Note: python 3.5 is failing for everybody for some problem in the documentation which i was not able to understand. |
it'd make sense to test for |
I do not really understand what it is not clear for you: how would you implement this behavior? For my point of view, the Decimal module can be considered as a different way to represent numbers. Regards, |
i have no doubt that
yes, but then do exactly that. validate the type of a symbol, not what a value could be coerced to. if you want to use it as
just for my understanding, does the Python client have a strict concorance with the Python type of the same name? |
Just for your understanding of the issue, look at this: pyeve/eve#1045 App which uses mongodb needs to format the data type accordingly. "yes, but then do exactly that. validate the type of a symbol, not what a value could be coerced to. if you want to use it as Decimal, you'd have to convert it in the normalization phase anyway." --> not able to follow you of how to do it: can you give me an example? |
decimal128 is a sub-class of the decimal module. The only difference is that it accepts only string as an input of the module, but I do not think we should enforce it in the json validator as it is a specificity of mongoDb. For coerce, unfortunately, I need to use the type field in order to be able to implement it in Eve. For this point, I would prefer to wait for @nicolaiarocci feedback if you are ok with that so that we design together how to add the support in both Cerberus and Eve. Thank you for your feedback Regards, |
Since |
there is no dissent in this regard. though it becomes critical when more and more types from the standard library are supported and the footprint (import execution time, memory) of an application that uses cerberus increases with each imported module. so far only builtin types and some from
my critique is still that the implementation makes no sense considering how Cerberus' type validations operate. it's understandable that the following inconsistency would alienate users: >>> schema = {'a_bool': {'type': 'boolean'},
... 'a_date': {'type': 'date'},
... 'a_decimal': {'type': 'decimal'},
... 'another_decimal': {'type': 'decimal'}}
...
>>> document = {'a_bool': True,
... 'a_date': datetime.date(1945, 5, 9),
... 'a_decimal': 10,
... 'another_decimal': '100'}
...
>>> validator(document, schema)
True
>>> isinstance(document['a_bool'], bool)
True
>>> isinstance(document['a_date'], datetime.date)
True
>>> isinstance(document['a_decimal'], decimal.Decimal)
False
>>> isinstance(document['another_decimal'], decimal.Decimal)
False
maybe a bad allegory, but who would trust a lying validator? i'd appreciate feedback regarding the particular points i raise by anyone from the user community. |
I understand youf point. What if we automatically convert the input to decimal in case it is parsable? After all, we are talking about number: I think it makes sense! Let me know your opinion. :) Regards, |
that is why i pointed to the value coercion. once a value is coerced it will pass a proper type test. |
I did not really get that until now! Ok, I will update |
normalization is applied before validation. as documented.
|
Ok, I did the update in order to make it work as you requested. Regards, |
propably the cleanest and safest way is to put this in the DECIMAL_TYPES = (decimal.Decimal,)
try:
from bson import Decimal128
except ImportError:
pass
else:
DECIMAL_TYPES += Decimal128 and then use that constant as second argument for |
would it suffice to test that particular type in Eve as it already has that dependency? |
cerberus/tests/test_validation.py
Outdated
@@ -393,6 +404,22 @@ def test_integer(): | |||
assert_success({'an_integer': 50}) | |||
|
|||
|
|||
def test_decimal(): | |||
# Module decimal does not accept integer or float for version 2.6 | |||
if int(sys.version_info[0]) > 2 and int(sys.version_info[1]) > 6: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there's the PYTHON_VERSION
constant in platform
for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
cerberus/tests/test_validation.py
Outdated
@@ -1270,8 +1297,20 @@ def test_oneof_schema(): | |||
|
|||
|
|||
def test_nested_oneof_type(): | |||
schema = {'nested_oneof_type': | |||
{'valueschema': {'oneof_type': ['string', 'integer']}}} | |||
schema = \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i appreciate the other reformattings, but this is unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
put it back (I change it as I had a problem with the flake8 validation...but now it is working fine)
cerberus/validator.py
Outdated
@@ -11,6 +11,7 @@ | |||
from __future__ import absolute_import | |||
|
|||
from ast import literal_eval | |||
import decimal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please keep imports sorted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updating! Thanks
cerberus/validator.py
Outdated
@@ -1240,6 +1241,14 @@ def _validate_type_integer(self, value): | |||
if isinstance(value, _int_types): | |||
return True | |||
|
|||
def _validate_type_decimal(self, value): | |||
if isinstance(value, decimal.Decimal): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'd prefer this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updating
docs/validation-rules.rst
Outdated
- :class:`py2:decimal.Decimal()` | ||
- :class:`py3:decimal.Decimal() or bson.decimal128.Decimal128()` | ||
|
||
.. versionchanged:: 1.1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these comments are below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updating
761580a
to
9e0829a
Compare
@funkyfuture I did the updated following your code review! :) Thanks, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry if some remarks seem cynical, they are.
i'm under the impression you don't care much a clean code or take hints as impulse for own investigations. when contributing to a new project it is advisable to study its code and get familar with it. also, sleeping a night over one's own changes and then self-reviewing them makes a difference in the result's quality.
cerberus/validator.py
Outdated
@@ -1240,6 +1249,11 @@ def _validate_type_integer(self, value): | |||
if isinstance(value, _int_types): | |||
return True | |||
|
|||
def _validate_type_decimal(self, value): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please keep methods sorted. maintainability is must.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are already not sorted!! But ok, I will move mine
cerberus/validator.py
Outdated
@@ -1240,6 +1249,11 @@ def _validate_type_integer(self, value): | |||
if isinstance(value, _int_types): | |||
return True | |||
|
|||
def _validate_type_decimal(self, value): | |||
for decimal_type in DECIMAL_TYPES: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please re-read the last sentence here. it's always advisable to study the function's documentation one uses. and the docs of the library one uses. ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops! Sorry, I have it in my local! I will push now
docs/validation-rules.rst
Outdated
@@ -691,6 +695,9 @@ A list of types can be used to allow different values: | |||
fields. This allows to safely assume that field type is correct when other | |||
(standard or custom) rules are invoked. | |||
|
|||
.. versionchanged:: 1.1 | |||
From this version, a new data type to support decimal module has been introduced. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indentation is off. a formulation and formatting like for other types seems appropriate. 1.1 is already released.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I am updating the version and indentation :)
@@ -648,6 +648,10 @@ Data type allowed for the key value. Can be one of the following names: | |||
* - ``string`` | |||
- :func:`py2:basestring` | |||
- :class:`py3:str` | |||
* - ``decimal`` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add '(if available)' as annotation for the latter Python type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type is always available as decimal module. Only decimal128 might be not available as part of bson module (which exist for all python version)
cerberus/tests/conftest.py
Outdated
'a_decimal': { | ||
'type': 'decimal', | ||
}, | ||
'a_decimal_coercing': { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this schema is only used for validation so far. it stems back from a time when Cerberus was far less complex. putting more complex stuff here has a chance to break a lot of tests.
there's a test module for normalizations you propably have noticed when you studied the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I will find another place for it.
import re | ||
import sys | ||
|
||
from bson import decimal128 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to repeat myself: would it suffice to test that in Eve? i'd rather avoid extra dependencies, even for testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I did not get this point before (too many comments): since it is a functionality offered by Cerberus, I think it should be tested within it. But I let you take the decision over it
@funkyfuture I do not really see why you are cynical in the first place..... |
eb280c5
to
6138a9f
Compare
Decimal type support is going to be implemented in Eve's own custom validator instead. |
This PR has the goal to provide support to validate decimal data type.
This way allows checking whether the number in the request is parsable by the decimal module. Note: this is to provide support for the new decimal type in mongodb.