graphene icon indicating copy to clipboard operation
graphene copied to clipboard

Self parameter is None in mutate method

Open symstu opened this issue 7 years ago • 27 comments
trafficstars

I don't know, maybe it's not a bug and problem caused by rx, but i have this mutation

class ExtendedMutation(graphene.Mutation):

    ok = graphene.Boolean()
    code = graphene.Int()
    message = graphene.String()

    def mutate(self, *_, **__):
        return ExtendedMutation()

class UserLogin(ExtendedMutation):
    class Arguments:
        access_token = graphene.String()

    access_token = graphene.String()

    @login_required
    def mutate(self, info, access_token):
        response = client.login(access_token)
        access_token = response.get('data', dict()).get('access_token', None)

        return UserLogin(
            access_token=access_token,
            ok=response.get('ok'),
            code=response.get('code'),
            message=response.get('message')
        )

and wrote such decorator


def login_required(mutation):
    @wraps(mutation)
    def inner(obj, info, **kwargs):
        access_token = request.headers.get('access_token', None)

        print('obj: {}, info; {}, kwargs: {} '.format(obj, info, kwargs))
        if not access_token:
            return obj(
                ok=False, code=401, message='You must login first'
            )
        return mutation(obj, info, **kwargs)
    return inner

I wait for UserLogin object in self argument of mutation method, but it's equal None. Info is equal ResolveObject. When i wraps mutate method with @classmethod decorator, i got UserLogin login class, info is None and appears third position required argument which is actually is info.

Any ideas?

symstu avatar Aug 14 '18 10:08 symstu

I bet we are doing something wrong here, @symstu . But I have the same issue. I try to call a method I defined in my Mutation object, it's called validate. When I try to call this method from my mutate method, the self param is empty. I think the usage will have changed when they removed the @classmethod

shifqu avatar Aug 28 '18 22:08 shifqu

First off, I am using graphene-django, so this might be totally unrelated. As a current work around I keep mutate as a @classmethod. I also changed the signature from self, info, **kwargs to cls, root, info, **kwargs

shifqu avatar Aug 29 '18 23:08 shifqu

This also seems to apply to resolve_* methods too.

a-musing-moose avatar Sep 26 '18 22:09 a-musing-moose

I also experience some frustrations with this and I think this is intended. I remember I saw a discussion in another issue related on this and the conclusion was that this design was deliberately implemented like this but I don't remember the justification and I can't seem to find the issue right now.

I think this is a very poor design choice as it doesn't allow any OOP principle to be applied for mutations and queries as I can't access any method or member. What's the point of using classes if you can't use OOP principles anyway?

vladcalin avatar Oct 04 '18 08:10 vladcalin

What is the rationale for unbinding mutate @syrusakbary ?

https://github.com/graphql-python/graphene/blob/08c86f3def71b1cb8aebc13026dae11982fc1ef7/graphene/types/mutation.py#L66

Edit: the commit that unbounded mutate: https://github.com/graphql-python/graphene/commit/999bca84c98d452634dd530e374ea6b649167c64

woodpav avatar Nov 20 '18 02:11 woodpav

Any explanation here?

reverie avatar Jan 13 '19 16:01 reverie

I think the rationale is that the Mutation class is not a traditional class. Instead serves only as a description of a mutation. I also think the unbounded mutate was to fix a bug. 🤷🏻‍♂️

woodpav avatar Jan 13 '19 18:01 woodpav

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jul 29 '19 21:07 stale[bot]

Commenting to unstale. This design should be improved, or strongly documented with workarounds/suggestions (and workaround implications).

riverfr0zen avatar Aug 01 '19 17:08 riverfr0zen

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Sep 30 '19 17:09 stale[bot]

Still a valid issue

reverie avatar Sep 30 '19 19:09 reverie

It's not a issue. it is intended, for make it simplify to access parent schema, first argument on resolver is "parent schema". I'm agree with @vladcalin's opinion(it is wired with OOP principle).

grahpene documents help me to understand how it works. https://docs.graphene-python.org/en/latest/types/objecttypes/#resolver-parameters

novelview9 avatar Oct 25 '19 06:10 novelview9

Whether it's intended is not the issue, the issue is what's right. :) This behavior breaks convention, reduces functionality, and smells like over-engineering.

reverie avatar Oct 25 '19 14:10 reverie

The intended behavior here makes no sense. The point of a library like graphene is fit some abstraction like graphql into the domain of python. When you ignore the conventions of the target domain (namely python's use of self on methods in classes), you have failed to make a good library.

If I wanted the function signatures to be exactly the same as Apollo, I'd use Apollo.

Please reinstate self on resolve_... methods and Mutation classes

henryfjordan avatar Nov 01 '19 19:11 henryfjordan

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Feb 16 '20 18:02 stale[bot]

This is still a valid open issue.

johnfrancisgit avatar Mar 19 '20 19:03 johnfrancisgit

This has bitten me now as well. This is an unpython and confusing design choice.

smitty42 avatar Apr 01 '20 00:04 smitty42

This is still a valid issue. Has there been any justification for the design?

poppops avatar Apr 21 '20 20:04 poppops

I've created a proposal for an alternative API for mutations that should solve this issue: https://github.com/graphql-python/graphene/issues/1226

Feedback welcome!

jkimbo avatar Jul 12 '20 12:07 jkimbo

still seeing this

benlei avatar Sep 07 '20 03:09 benlei

Just got hit by this, wasted 15 minutes.

m3talstorm avatar Oct 07 '20 17:10 m3talstorm

So, what`s the solution? How to get a self variable?

Sher-V avatar Oct 11 '20 09:10 Sher-V

This is nothing short of a poor design choice. I have been working around this on the resolver side for a sizable graphql api, now hit by the same issue with mutations. Cant even do something a simply OO as get an inherited variable from a base class.

paultop6 avatar Oct 15 '20 20:10 paultop6

Just ran into this issue and found this thread via Google search. I'd be interested in learning more about the design decisions around this as its causing some awkward workarounds in my project.

CyanCode avatar Oct 18 '20 04:10 CyanCode

This is still an issue.

hkievet avatar Mar 19 '21 21:03 hkievet

Same here, I want to put a method in my Mutation class that is not allowed, so, my mutation will be really a long one,

def mutate(self, info, id, input):
        foovar=do_something()
        self._do_something_else() # self is None
        return SomeResponse(foo=foovar)

def _do_something_else((self):
        return "Hi world"

vteran93 avatar Mar 25 '22 17:03 vteran93

In terms of OOP in my class I'm able to workaround this by using @classmethod and calling it with the name of the class. Works for me because there aren't any members of self which I need to access, but it's not ideal. I think those of you who tried to use cls could work on the same basis

I'm wondering if perhaps root or info have a reference to self somewhere? I haven't investigated that though

calummackervoy avatar Feb 23 '23 15:02 calummackervoy