chpmrc / graphene-validator

A Python micro library to ease field validation in Graphene
MIT License
21 stars 5 forks source link

@validated decorator is incompatible with Relay mutations #10

Open akikoskinen opened 3 years ago

akikoskinen commented 3 years ago

Relay mutations are those inherited from graphene.relay.ClientIDMutation. To reproduce, add this code to tests.py and try to run tests:

@validated
class RelayMutation(graphene.relay.ClientIDMutation):
    @classmethod
    def mutate_and_get_payload(cls, root, info, **_inpt):
        return RelayMutation()

An error is produced already in the import phase. Output could look something like this:

tests.py:117: in <module>
    class RelayMutation(graphene.relay.ClientIDMutation):
graphene_validator/decorators.py:143: in validated
    class Wrapper(cls):
.venv/lib64/python3.7/site-packages/graphene/utils/subclass_with_meta.py:52: in __init_subclass__
    super_class.__init_subclass_with_meta__(**options)
.venv/lib64/python3.7/site-packages/graphene/relay/mutation.py:34: in __init_subclass_with_meta__
    input_fields, client_mutation_id=String(name="clientMutationId")
E   TypeError: Cannot create a consistent method resolution
E   order (MRO) for bases InputObjectType, RelayMutationInput

Graphene's Relay code does some meta class magic and dynamically produces various classes and at some point it manages to create a cyclic dependency chain between classes and thus Python can't create an MRO.

I have no idea how to solve this. The meta class magic in Graphene looks too complex to me.

chpmrc commented 3 years ago

Yeah Graphene's metaclass system is a mess, I don't understand why they had to rely on such a complex abstraction (although I'm sure there are reasons). I'll try to take a look in the weekend. Thanks!

akikoskinen commented 3 years ago

Not directly related to this, but it could work as a solution. I have come to the conclusion that the @validated class decorator can't be used in every use case. With the class decorator solution validation is always run before mutate is entered. But there are use cases where the Mutation's mutate method is entered, something is first done (for example related to authorisation), and only after that validation should be run.

My current idea is to provide a validation function from graphene-validator. Basically the current _do_validation can almost work as is. That function can then be called from inside the mutate method at any point that is fit for the purpose.

This solution could also be used to circumvent the MRO problem mentioned in this issue, if the meta class magic proves too problematic to be solved otherwise.

akikoskinen commented 3 years ago

My current idea is to provide a validation function from graphene-validator.

@chpmrc PR #11 now contains this kind of validation function. Can you check it out?