pyeve / cerberus

Lightweight, extensible data validation library for Python
http://python-cerberus.org
ISC License
3.16k stars 238 forks source link

Add DATE_FORMAT for datetime type / feature requests #396

Closed solinas3000 closed 6 years ago

solinas3000 commented 6 years ago

the field date coming from my front end are formatted like this : "%Y-%m-%dT%H:%M:%S.%fZ"

incoming payload : { "ID_RessourceStudio":-1, "RessourceStudio_CreationDate":"2018-05-24T15:26:47.019Z", "RessourceStudio_LastModificationDate":null, "RessourceStudio_Code":"lenn", "RessourceStudio_Name":"hcx", "RessourceStudio_Active":true } schema : {'ID_RessourceStudio': {'required': True, 'type': 'integer'}, 'RessourceStudio_CreationDate': {'nullable': True, 'default': None, 'type': 'datetime'}, 'RessourceStudio_LastModificationDate': {'nullable': True, 'default': None, 'type': 'datetime'}, 'RessourceStudio_Code': {'required': True, 'type': 'string'}, 'RessourceStudio_Name': {'required': True, 'type': 'string'}, 'RessourceStudio_Active': {'required': True, 'type': 'boolean'}} v.errors : {'RessourceStudio_CreationDate': ['must be of datetime type']}

Cerberus don't provide a way to format the 'datetime' type used in the schema validation.

This option is already available on python eve framework using cerberus validation like this : DATE_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ" in settings.py

For this particular case i'm outside the scope of python eve.

Could you please provide me with a workaround ?

Flargebla commented 6 years ago

I believe Cerberus does provide a mechanism for solving this problem via the coerce rule. You simply define the coercion function as something like this:

coerceDate = lambda d: datetime.strptime(d, "%Y-%m-%dT%H:%M:%S.%fZ")

And then add the rule:

'coerce': coerceDate

The final resulting schema would look like:

schema = {
          'ID_RessourceStudio': 
            {'required': True, 'type': 'integer'},
          'RessourceStudio_CreationDate':
            {'nullable': True, 'default': None, 'type': 'datetime', 'coerce': coerceDate},
          'RessourceStudio_LastModificationDate':
            {'nullable': True, 'default': None, 'type': 'datetime', 'coerce': coerceDate},
          'RessourceStudio_Code':
            {'required': True, 'type': 'string'}, 
          'RessourceStudio_Name':
            {'required': True, 'type': 'string'},
          'RessourceStudio_Active':
            {'required': True, 'type': 'boolean'}
}

I tested it using this document and got no errors or issues:

doc = {
    "ID_RessourceStudio": 1,
    "RessourceStudio_CreationDate": "2018-05-24T15:26:47.019Z",
    "RessourceStudio_LastModificationDate": None,
    "RessourceStudio_Code": "lenn",
    "RessourceStudio_Name": "hcx",
    "RessourceStudio_Active": True
}

Hope that helps!

funkyfuture commented 6 years ago

cool. btw: https://stackoverflow.com/questions/50133185/normalizing-string-to-date-in-cerbrus

sarjunwadkar commented 9 months ago

hi there thanks for providing the above solution. But is there a way to provide the date format externally? We are sourcing data from different source systems. some systems have different date formats. As the coerce function only gets a value argument, no way to select a format based on the field name. Is there a way around it?

The "validator" rule, which allows external functions to validate field values is useful. because it accepts (field, value, error) argument. so we can maintain an external dictionary with key = field name and value = date format and using dictionary lookup we can get the appropriate date format and do date conversion. but then the returned value is not in date time format. only value returned via coerce function is in python date format..

e.g.

dict = { 'field1' : '%Y%m%d', 'field2' : '%m%d%Y'}

def to_date(field, value,error): format = fict.get(field,'"%Y%m%d') return value.strptime(format)

schema = { 'dt' : { 'type' : 'date', 'validator' : to_date } from cerberus import validator data = { 'dt' : '20220312'}

v = Validator(schema) v.validate(data) print(v.document)

v.document is not printing date in DateTime.date format?

looks like 'coerce' and 'validator' can not be used at the same time.

please advise, on how to use date format while validating the date, return value should be in Python date format.