Calling a custom method in a Graphene python resolver - python

Hello I simply want to avoid repeating code for each query, and I was wondering if I could call a method from inside a resolver a such:
# pseudo code
class Query(graphene.ObjectType):
field = graphene.Field(SomeType)
def do_boring_task(parent, info, arg):
return "I did something"
def resolve_field(parent, info):
did_something = parent.do_boring_task(arg) # <-- is this possible ?
# do something here
return resolved_fields
I always get a "graphql.error.located_error.GraphQLLocatedError: 'NoneType' object has no attribute 'do_boring_task'" error
Is it possible to do that the way I described it, or is this something that should be done using middleware?
Thanks

Classes inheriting from graphene.ObjectType are different than a normal class, resolve_field and do_boring_task are by default static methods.
Note that first argument of resolve_field is parent and not self, do_boring_task is a classmethod (static method in other languages) of Query class and does not exist in parent schema, that explains your error.
A quick fix for your problem is as shown below, define the function, outside of the class.
def do_boring_task(args):
return "I did something"
class Query(graphene.ObjectType):
field = graphene.Field(SomeType)
def resolve_field(parent, info):
did_something = do_boring_task(arg)
# do something here
return resolved_fields
Refer these in the blog for more details
Implicit Static Method
Resolvers Outside the class

Related

Django model class can't be serialized due to `default=` field parameter poiting to class method [duplicate]

I have a very basic class that looks something like the following:
class Car(Model):
name = CharField(max_length=255, unique=True)
#classmethod
def create_simple_examples(cls):
for c in ['Sedan', 'Coupe', 'Van', 'SUV']:
cls.objects.get_or_create(name=c)
#classmethod
def get_default(cls):
c, _ = cls.objects.get_or_create(name='Sedan')
return c
def __unicode__(self):
return self.name
I am trying to add it to a django app. I have the two class methods to 1. a function to populate the table quickly, and 2. to grab a default one which will be used often.
When I run
python manage.py makemigrations myapp
I get the following error
ValueError: Cannot serialize: <bound method ModelBase.get_default of <class 'crunch.django.myapp.models.Car'>>
I am not quite sure why it's trying to serialize my get_default function as that's not really part of the migration of the table itself. Any help would be greatly appreciated
UPDATE I think I may have found the source of the problem (still not sure how to fix it though...)
I have other classes that are FKing to my new class, and the default uses my default above...something like this
class OtherClass(Model):
car = ForeignKey(Car, default=Car.get_default)
It looks like the migration is trying to serialize the function because of this. Any tips on how to get around this?
Add the #deconstructible decorator to the classes which have a classmethod
from django.utils.deconstruct import deconstructible
#deconstructible
class Car(Model):
...
More documentation on deconstructible can be found here
As explained in Django's migrations docs, Django can serialize function and method references, (in Python 3) unbound methods used from within the class body, and a bunch of other stuff, but it can't serialize everything.
In this case, because you've made get_default a #classmethod, Car.get_default is a bound method (i.e., it takes an implicit reference to Car as its first parameter), rather than a plain function or method reference, and Django doesn't know what to do with that.
Try making get_default a #staticmethod instead, or make a free function (top-level function) that calls Car.get_default.

Python - Using classes as default values of another class' attribute - NameError

I'm creating a structure of classes for a wrapper of an API I'm currently writing.
I have multiple classes defined inside my models file. I want to assign the default value of some attributes of classes to other classes. When I do this, I get a NameError because sometimes I try to use classes that are defined below the current class, thus Python does not know these classes yet. I've tried multiple solutions but none of them seem to work. Does anybody know an alternative or has experience with this?
my classes I've defined:
class RateResponse(BaseModel):
def __init__(self,
provider=Provider()
):
self.provider = provider
class Provider(ObjectListModel):
def __init__(self):
super(Provider, self).__init__(list=[], listObject=ProviderItem)
#property
def providerItems(self):
return self.list
class ProviderItem(BaseModel):
def __init__(self,
code=None,
notification=Notification(),
service=Service()
):
self.code = code
self.notification = notification
self.service = service
As you can see above, I'm initialising the attribute 'provider' on the class RateResponse with the an empty object of the class Provider, which is defined below it. I'm getting a NameError on this line because it's defined below RateResponse.
provider=Provider()
NameError: name 'Provider' is not defined
The simple solution to above would be to shift the places of the classes. However, this is only a snippet of my file that is currently 400 lines long, all with these types of classes and initializations. It would be impossible to order them all correctly.
I've looked up some solutions where I thought I could return an empty object of a class by a string. I thought the function would only evaluate after all the classes were defined, but I was wrong. This is what I tried:
def getInstanceByString(classStr):
return globals()[classStr]()
class RateResponse(BaseModel):
def __init__(self,
provider=getInstanceByString('Provider')
):
self.provider = provider
But to no avail. Does anybody have experience with this? Is this even possible within Python? Is my structure just wrong? Any help is appreciated. Thanks.
This code might not mean what you want it to mean:
class RateResponse(BaseModel):
def __init__(self,
provider=Provider()
):
...
This code is saying that when this class is declared you want to make an instance of Provider which will be the default value for the provider parameter.
You may have meant that the default argument should be a new instance of Provider for each client that makes an instance of RateResponse.
You can use the Mutable Default Argument pattern to get the latter:
class RateResponse(BaseModel):
def __init__(self, provider=None):
if provider is None:
provider = Provider()
...
However, if you really do want a single instance when the client wants the default you could add a single instance below the Provider definition:
class Provider(ObjectListModel):
...
Singleton_Provider = Provider()
Then the RateResponse class could still use the current pattern, but instead perform this assignment inside the if:
if provider is None:
provider = Singleton_Provider
At the time that the assignment is performed, the Singleton_Provider will have been created.

Django - NameError when trying to call model method in views

I have a method in my model that I would like to call in my views. However, I get a NameError that this function is not defined (I have imported all models in my views and all migrations are up to date). It has worked for other functions in the past.
Here is my model:
class Song(models.Model):
"""
fields
"""
def lyrics_as_list(self):
return self.lyrics_ru.split()
def sorted_strings(self, strings, locale=None):
if locale is None:
return sorted(strings)
collator = icu.Collator.createInstance(icu.Locale(locale))
return sorted(strings, key=collator.getSortKey)
And in my views the relevant part where I want to use it:
lyrics_list = models.Song.objects.get(pk=self.kwargs['pk']).lyrics_as_list() #this is also a method on my model, and it does work
lyrics_sorted = sorted_strings(set(lyrics_list, "ru_RU.UTF8")) #but this one gives me an error
The error: name 'sorted_strings' is not defined
When I move the method to my views, it works. But I have to use this in several views, so I am trying to follow the DRY principle, and so it would be great to get it to work.
Edit - What the sorted_strings function is for:
My Song model contains lyrics. I am displaying all words in the lyrics in a table, but I want to show it alphabetically. In order to be able to sort Russian words, I needed to add this function.
The method sorted strings as defined in the class Song:
class Song(models.Model):
"""
fields
"""
def sorted_strings(self, strings, locale=None):
if locale is None:
return sorted(strings)
collator = icu.Collator.createInstance(icu.Locale(locale))
return sorted(strings, key=collator.getSortKey)
cannot be called like this:
sorted_strings(strings, locale)
This obviously leads to a NameError. It is a method, so you need to call it on an object as instance of that class.
You might get tempted to try this:
Song.sorted_strigns(strings, locale)
but it won't work. It will result in missing 1 required positional argument. That is you have to provide self. You can't call it directly on the class.
If you introspect this method well, it doesn't perform any action on an object. The argument self is not used. You'd like to call it without instantiating an object, but directly on the class. Therefore you can use the decorator #staticmethod:
#staticmethod
def sorted_strings(strings, locale=None):
if locale is None:
return sorted(strings)
collator = icu.Collator.createInstance(icu.Locale(locale))
return sorted(strings, key=collator.getSortKey)
Please notice how the static method doesn't need to be passed the argument self.
Now your code should work like this:
lyrics_list = Song.objects.get(pk=self.kwargs['pk']).lyrics_as_list()
lyrics_sorted = Song.sorted_strings(set(lyrics_list), "ru_RU.UTF8")
Also in your code example you have an error with the parentheses in the second line.
Besides static methods, there are also class methods, defined using the decorator #classmethod. For this purpose here I'd go with the static method, but if someone has an objection, I'm ready to learn.
Static methods are not very common in Python and frowned upon by many.
Nevertheless it's good to know they exist and how they work.
lyrics_list = models.Song.objects.get(pk=self.kwargs['pk']).lyrics_as_list()
lyrics_sorted = models.Song.objects.sorted_strings(set(lyrics_list), "ru_RU.UTF8")
Manager's method can only be called with Model.objects

Python - how do I force the use of a factory method to instantiate an object?

I have a set of related classes that all inherit from one base class. I would like to use a factory method to instantiate objects for these classes. I want to do this because then I can store the objects in a dictionary keyed by the class name before returning the object to the caller. Then if there is a request for an object of a particular class, I can check to see whether one already exists in my dictionary. If not, I'll instantiate it and add it to the dictionary. If so, then I'll return the existing object from the dictionary. This will essentially turn all the classes in my module into singletons.
I want to do this because the base class that they all inherit from does some automatic wrapping of the functions in the subclasses, and I don't want to the functions to get wrapped more than once, which is what happens currently if two objects of the same class are created.
The only way I can think of doing this is to check the stacktrace in the __init__() method of the base class, which will always be called, and to throw an exception if the stacktrace does not show that the request to make the object is coming from the factory function.
Is this a good idea?
Edit: Here is the source code for my base class. I've been told that I need to figure out metaclasses to accomplish this more elegantly, but this is what I have for now. All Page objects use the same Selenium Webdriver instance, which is in the driver module imported at the top. This driver is very expensive to initialize -- it is initialized the first time a LoginPage is created. After it is initialized the initialize() method will return the existing driver instead of creating a new one. The idea is that the user must begin by creating a LoginPage. There will eventually be dozens of Page classes defined and they will be used by unit testing code to verify that the behavior of a website is correct.
from driver import get_driver, urlpath, initialize
from settings import urlpaths
class DriverPageMismatchException(Exception):
pass
class URLVerifyingPage(object):
# we add logic in __init__() to check the expected urlpath for the page
# against the urlpath that the driver is showing - we only want the page's
# methods to be invokable if the driver is actualy at the appropriate page.
# If the driver shows a different urlpath than the page is supposed to
# have, the method should throw a DriverPageMismatchException
def __init__(self):
self.driver = get_driver()
self._adjust_methods(self.__class__)
def _adjust_methods(self, cls):
for attr, val in cls.__dict__.iteritems():
if callable(val) and not attr.startswith("_"):
print "adjusting:"+str(attr)+" - "+str(val)
setattr(
cls,
attr,
self._add_wrapper_to_confirm_page_matches_driver(val)
)
for base in cls.__bases__:
if base.__name__ == 'URLVerifyingPage': break
self._adjust_methods(base)
def _add_wrapper_to_confirm_page_matches_driver(self, page_method):
def _wrapper(self, *args, **kwargs):
if urlpath() != urlpaths[self.__class__.__name__]:
raise DriverPageMismatchException(
"path is '"+urlpath()+
"' but '"+urlpaths[self.__class.__name__]+"' expected "+
"for "+self.__class.__name__
)
return page_method(self, *args, **kwargs)
return _wrapper
class LoginPage(URLVerifyingPage):
def __init__(self, username=username, password=password, baseurl="http://example.com/"):
self.username = username
self.password = password
self.driver = initialize(baseurl)
super(LoginPage, self).__init__()
def login(self):
driver.find_element_by_id("username").clear()
driver.find_element_by_id("username").send_keys(self.username)
driver.find_element_by_id("password").clear()
driver.find_element_by_id("password").send_keys(self.password)
driver.find_element_by_id("login_button").click()
return HomePage()
class HomePage(URLVerifyingPage):
def some_method(self):
...
return SomePage()
def many_more_methods(self):
...
return ManyMorePages()
It's no big deal if a page gets instantiated a handful of times -- the methods will just get wrapped a handful of times and a handful of unnecessary checks will take place, but everything will still work. But it would be bad if a page was instantiated dozens or hundreds or tens of thousands of times. I could just put a flag in the class definition for each page and check to see if the methods have already been wrapped, but I like the idea of keeping the class definitions pure and clean and shoving all the hocus-pocus into a deep corner of my system where no one can see it and it just works.
In Python, it's almost never worth trying to "force" anything. Whatever you come up with, someone can get around it by monkeypatching your class, copying and editing the source, fooling around with bytecode, etc.
So, just write your factory, and document that as the right way to get an instance of your class, and expect anyone who writes code using your classes to understand TOOWTDI, and not violate it unless she really knows what she's doing and is willing to figure out and deal with the consequences.
If you're just trying to prevent accidents, rather than intentional "misuse", that's a different story. In fact, it's just standard design-by-contract: check the invariant. Of course at this point, SillyBaseClass is already screwed up, and it's too late to repair it, and all you can do is assert, raise, log, or whatever else is appropriate. But that's what you want: it's a logic error in the application, and the only thing to do is get the programmer to fix it, so assert is probably exactly what you want.
So:
class SillyBaseClass:
singletons = {}
class Foo(SillyBaseClass):
def __init__(self):
assert self.__class__ not in SillyBaseClass.singletons
def get_foo():
if Foo not in SillyBaseClass.singletons:
SillyBaseClass.singletons[Foo] = Foo()
return SillyBaseClass.singletons[Foo]
If you really do want to stop things from getting this far, you can check the invariant earlier, in the __new__ method, but unless "SillyBaseClass got screwed up" is equivalent to "launch the nukes", why bother?
it sounds like you want to provide a __new__ implementation: Something like:
class MySingledtonBase(object):
instance_cache = {}
def __new__(cls, arg1, arg2):
if cls in MySingletonBase.instance_cache:
return MySingletonBase.instance_cache[cls]
self = super(MySingletonBase, cls).__new__(arg1, arg2)
MySingletonBase.instance_cache[cls] = self
return self
Rather than adding complex code to catch mistakes at runtime, I'd first try to use convention to guide users of your module to do the right thing on their own.
Give your classes "private" names (prefixed by an underscore), give them names that suggest they shouldn't be instantiated (eg _Internal...) and make your factory function "public".
That is, something like this:
class _InternalSubClassOne(_BaseClass):
...
class _InternalSubClassTwo(_BaseClass):
...
# An example factory function.
def new_object(arg):
return _InternalSubClassOne() if arg == 'one' else _InternalSubClassTwo()
I'd also add docstrings or comments to each class, like "Don't instantiate this class by hand, use the factory method new_object."
You can also just nest classes in factory method, as described here:
https://python-3-patterns-idioms-test.readthedocs.io/en/latest/Factory.html#preventing-direct-creation
Working example from mentioned source:
# Factory/shapefact1/NestedShapeFactory.py
import random
class Shape(object):
types = []
def factory(type):
class Circle(Shape):
def draw(self): print("Circle.draw")
def erase(self): print("Circle.erase")
class Square(Shape):
def draw(self): print("Square.draw")
def erase(self): print("Square.erase")
if type == "Circle": return Circle()
if type == "Square": return Square()
assert 0, "Bad shape creation: " + type
def shapeNameGen(n):
for i in range(n):
yield factory(random.choice(["Circle", "Square"]))
# Circle() # Not defined
for shape in shapeNameGen(7):
shape.draw()
shape.erase()
I'm not fan of this solution, just want to add this as one more option.

Why does "self" outside a function's parameters give a "not defined" error?

Look at this code:
class MyClass():
# Why does this give me "NameError: name 'self' is not defined":
mySelf = self
# But this does not?
def myFunction(self):
mySelf2 = self
Basically I want a way for a class to refer to itself without needing to name itself specifically, hence I want self to work for the class, not just methods/functions. How can I achieve this?
EDIT: The point of this is that I'm trying to refer to the class name from inside the class itself with something like self.class._name_ so that the class name isn't hardcoded anywhere in the class's code, and thus it's easier to re-use the code.
EDIT 2: From what I've learned from the answers below, what I'm trying to do is impossible. I'll have to find a different way. Mission abandoned.
EDIT 3: Here is specifically what I'm trying to do:
class simpleObject(object):
def __init__(self, request):
self.request = request
#view_defaults(renderer='string')
class Test(simpleObject):
# this line throws an error because of self
myClassName = self.__class__.__name__
#view_config(route_name=myClassName)
def activateTheView(self):
db = self.request.db
foo = 'bar'
return foo
Note that self is not defined at the time when you want the class to refer to itself for the assignment to work. This is because (in addition to being named arbitrarily), self refers to instances and not classes. At the time that the suspect line of code attempts to run, there is as of yet no class for it to refer to. Not that it would refer to the class if there was.
In a method, you can always use type(self). That will get the subclass of MyClass that created the current instance. If you want to hard-code to MyClass, that name will be available in the global scope of the methods. This will allow you to do everything that your example would allow if it actually worked. E.g, you can just do MyClass.some_attribute inside your methods.
You probably want to modify the class attributes after class creation. This can be done with decorators or on an ad-hoc basis. Metaclasses may be a better fit. Without knowing what you actually want to do though, it's impossible to say.
UPDATE:
Here's some code to do what you want. It uses a metaclass AutoViewConfigMeta and a new decorator to mark the methods that you want view_config applied to. I spoofed the view_config decorator. It prints out the class name when it's called though to prove that it has access to it. The metaclass __new__ just loops through the class dictionary and looks for methods that were marked by the auto_view_config decorator. It cleans off the mark and applies the view_config decorator with the appropriate class name.
Here's the code.
# This just spoofs the view_config decorator.
def view_config(route=''):
def dec(f):
def wrapper(*args, **kwargs):
print "route={0}".format(route)
return f(*args, **kwargs)
return wrapper
return dec
# Apply this decorator to methods for which you want to call view_config with
# the class name. It will tag them. The metaclass will apply view_config once it
# has the class name.
def auto_view_config(f):
f.auto_view_config = True
return f
class AutoViewConfigMeta(type):
def __new__(mcls, name, bases, dict_):
#This is called during class creation. _dict is the namespace of the class and
# name is it's name. So the idea is to pull out the methods that need
# view_config applied to them and manually apply them with the class name.
# We'll recognize them because they will have the auto_view_config attribute
# set on them by the `auto_view_config` decorator. Then use type to create
# the class and return it.
for item in dict_:
if hasattr(dict_[item], 'auto_view_config'):
method = dict_[item]
del method.auto_view_config # Clean up after ourselves.
# The next line is the manual form of applying a decorator.
dict_[item] = view_config(route=name)(method)
# Call out to type to actually create the class with the modified dict.
return type.__new__(mcls, name, bases, dict_)
class simpleObject(object):
__metaclass__ = AutoViewConfigMeta
class Test(simpleObject):
#auto_view_config
def activateTheView(self):
foo = 'bar'
print foo
if __name__=='__main__':
t = Test()
t.activateTheView()
Let me know if you have any questions.
Python has an "explict is better than implicit" design philosophy.
Many languages have an implicit pointer or variable in the scope of a method that (e.g. this in C++) that refers to the object through which the method was invoked. Python does not have this. Here, all bound methods will have an extra first argument that is the object through which the method was invoked. You can call it anything you want (self is not a keyword like this in C++). The name self is convention rather than a syntactic rule.
Your method myFunction defines the variable self as a parameter so it works. There's no such variable at the class level so it's erroring out.
So much for the explanation. I'm not aware of a straightforward way for you to do what you want and I've never seen such requirement in Python. Can you detail why you want to do such a thing? Perhaps there's an assumption that you're making which can be handled in another way using Python.
self is just a name, your self in this case is a class variable and not this for the object using which it is called,
self is treated as a normal variable and it is not defined, where as the self in the function comes from the object used for calling.
you want to treat the object reference in self as a class variable which is not possible.
self isn't a keyword, it's just a convention. The methods are attributes of the class object (not the instance), but they receive the instance as their first argument. You could rename the argument to xyzzy if you wanted and it would still work the same way.
But (as should be obvious) you can't refer to a method argument outside the body of the method. Inside a class block but outside of any method, self is undefined. And the concept wouldn't even make sense -- at the time the class block is being evaluated, no instance of the class can possibly exist yet.
Because the name self is explicitly defined as part of the arguments to myFunction. The first argument to a method is the instance that the method was called on; in the class body, there isn't an "instance we're dealing with", because the class body deals with every possible instance of the class (including ones that don't necessarily exist yet) - so, there isn't a particular object that could be called self.
If you want to refer to the class itself, rather than some instance of it, this is spelled self.__class__ (or, for new-style classes in Py2 and all classes in Py3, type(self)) anywhere self exists. If you want to be able to deal with this in situations where self doesn't exist, then you may want to look at class methods which aren't associated with any particular instance, and so take the class itself in place of self. If you really need to do this in the class body (and, you probably don't), you'll just have to call it by name.
You can't refer to the class itself within the class body because the class doesn't exist at the time that the class body is executed. (If the previous sentence is confusing, reading up about metaclasses will either clear this up or make you more confused.)
Within an instance method, you can refer to the class of the instance with self.__class__, but be careful here. This will be the instance's actual class, which through the power of inheritance might not be the class in which the method was defined.
Within a class method, the class is passed in as the first argument, much like instances are the first argument to instance methods:
class MyClass(object):
#classmethod
def foo(cls):
print cls.__name__
MyClass.foo() # Should print "MyClass"
As with instance methods, the actual class might differ due to inheritance.
class OtherClass(MyClass):
pass
OtherClass.foo() # Should print "OtherClass"
If you really need to refer to MyClass within a method of MyClass, you're pretty much going to have to refer to it as MyClass unless you use magic. This sort of magic is more trouble than it is worth.

Categories

Resources