Skip to content
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

Self parameter is None in mutate method #810

Open
symstu opened this issue Aug 14, 2018 · 27 comments
Open

Self parameter is None in mutate method #810

symstu opened this issue Aug 14, 2018 · 27 comments

Comments

@symstu
Copy link

symstu commented Aug 14, 2018

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 symstu changed the title Self attribute is None in mutate method Self parameter is None in mutate method Aug 14, 2018
@shifqu
Copy link

shifqu commented Aug 28, 2018

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
Copy link

shifqu commented Aug 29, 2018

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

@a-musing-moose
Copy link

a-musing-moose commented Sep 26, 2018

This also seems to apply to resolve_* methods too.

@vladcalin
Copy link

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?

@woodpav
Copy link

woodpav commented Nov 20, 2018

What is the rationale for unbinding mutate @syrusakbary ?

resolver = get_unbound_function(mutate)

Edit: the commit that unbounded mutate: 999bca8

@reverie
Copy link

reverie commented Jan 13, 2019

Any explanation here?

@woodpav
Copy link

woodpav commented Jan 13, 2019

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. 🤷🏻‍♂️

@stale
Copy link

stale bot commented Jul 29, 2019

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 stale bot added the wontfix label Jul 29, 2019
@riverfr0zen
Copy link

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

@stale stale bot removed the wontfix label Aug 1, 2019
@stale
Copy link

stale bot commented Sep 30, 2019

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 stale bot added the wontfix label Sep 30, 2019
@jkimbo jkimbo removed the wontfix label Sep 30, 2019
@reverie
Copy link

reverie commented Sep 30, 2019

Still a valid issue

@novelview9
Copy link

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

@reverie
Copy link

reverie commented Oct 25, 2019

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.

@henryfjordan
Copy link

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

@stale
Copy link

stale bot commented Feb 16, 2020

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 stale bot added the wontfix label Feb 16, 2020
@stale stale bot closed this as completed Mar 1, 2020
@johnfrancisgit
Copy link

This is still a valid open issue.

@smitty42
Copy link

smitty42 commented Apr 1, 2020

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

@syrusakbary syrusakbary reopened this Apr 1, 2020
@stale stale bot removed the wontfix label Apr 1, 2020
@poppops
Copy link

poppops commented Apr 21, 2020

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

@jkimbo
Copy link
Member

jkimbo commented Jul 12, 2020

I've created a proposal for an alternative API for mutations that should solve this issue: #1226

Feedback welcome!

@benlei
Copy link

benlei commented Sep 7, 2020

still seeing this

@m3talstorm
Copy link

Just got hit by this, wasted 15 minutes.

@Sher-V
Copy link

Sher-V commented Oct 11, 2020

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

@paultop6
Copy link

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.

@CyanCode
Copy link

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.

@hkievet
Copy link

hkievet commented Mar 19, 2021

This is still an issue.

@vteran93
Copy link

vteran93 commented Mar 25, 2022

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"

@calummackervoy
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests