pyeve / cerberus

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

Feature request: re-use a schema with extra params on validate() #447

Closed mararzu closed 5 years ago

mararzu commented 6 years ago

Feature request (first of all sorry for my english, hope you get the idea :) )

latest commit: 7d61ac3624d34d5dcb621089e48d91a3d1ee64a7 version: pypi v1.2

Use-case abstract

A simple entity like User which has: name, age, notes And 2 common CRUD use cases: Create and Update On creation: i want to check thet name and age EXISTS, and ARE NOT EMPTY On update: i want to check an ID field comes in the json AND name/age/notes are NOT MANDATORY, but if they come they CANT be empty

Feature request

From which i see (hope im wrong) i need to create 2 separate schemas, one for create and another for update. It would be nice if i can create 1 schema with all the fields (including the ID needed for update) and that the "validate" method could receive like another params like "not-mandatory" that could be a list of fields that if exists on the schema i want to override the "mandatory" property and set it to FALSE.

It has the benefit of no need to copy multiple times the same attributes on differents schemas

funkyfuture commented 5 years ago

sorry, i don't think i fully understand your request. and i have the impression that it's about more than one issue/feature; if that's the case, please open separate issues, code examples are always helpful.

mararzu commented 5 years ago

Hi funkyfuture! Thanks for the response! :)

Let me paste here the code of how i ended up solving my problem, it might give you an example of what i needed to do and maybe there is a better way

Introduction: I need to validate the same class with differentes validations, it depends if im creating the entity or updating it. And i dont want to have several schemas with repeated/"duplicated" atributes. So i ended up doing:

def makeRequieredAndNotEmpty(schema, fields):
    for field in fields:
        schema[field]["required"] = True
        schema[field]["empty"] = False
    return schema

def makeExcluded(schema, fields):
    for field in fields:
        del schema[field]
    return schema

class MoldeDS:
    id = 'id'
    name = 'name'
    description = 'description'
    photoUrl = 'photoUrl'
    code = 'code'
    dateModified = 'dateModified'

    schema = {
        name: {'type': 'string'},
        description: {'type': 'string'},
        photoUrl: {'type': 'string'},
        code: {'type': 'integer'}
    }

    def parseCreate(self, data):
        s = copy.deepcopy(self.schema)                            # Here im copying the schema to edit it
        s = makeRequieredAndNotEmpty(s, [self.name])  # Edit required fields
        s = makeExcluded(s, {self.code, self.id})                 # Make the code and id excluded during creation

        v = Validator()
        v.purge_unknown = True
        v.schema = s

        isValid = validator.validate(data)
        if isValid:
            return validator.document
        else:
            raise Excepton()

In this way i have 1 schema with all of the class atributes and i will need to create several methods (like "parseCreate") for differentes operations. For example for UPDATE the id would be a requiered field.

i might be doing things completly wrong. Im really new to python (and general programming too)

Thanks again for you time! :)

funkyfuture commented 5 years ago

this definitely looks like you can save code and time with the mentioned ChainMap. actually, i don't know what happens when you pass such as schema. it's one of the lesser known pearls in the stdlib. feedback how it works out would be cool, maybe even a usage example for the docs?