I'm having issues getting a class method to run in Flask.
In models/User.py:
from mongoengine import *
class User(Document):
first_name = StringField()
last_name = StringField()
...
def __init__(self, arg1, arg2, ...):
self.first_name = arg1
self.last_name = arg2
...
#classmethod
def create(self, arg1, arg2, ...):
#do some things like salting and hashing passwords...
user = self(arg1, arg2, ...)
user.save()
return user
In the main application python file:
from models import User
...
def func():
...
#Throws "AttributeError: type object 'User' has no attribute 'create'"
user = User.create(arg1, arg2, ...)
Shouldn't I be able to call create on the User class without instantiating a User object? I'm using Python 2.7.2, and I also tried the non-decorator syntax of using create = classmethod(create), but that didn't work. Thanks in advance!
EDIT: I found one issue: that the models folder did not contain an __init__.py file, so it wasn't a module, so from models import User was not actually importing the file I wanted it to. It did not give me an error from before because I used to have a models.py module in the same directory as the application python script, but after deleting it I never deleted the corresponding .pyc file. Now, I'm getting the error AttributeError: 'module' object has no attribute 'create' instead of what I had before, but I'm certain it is importing the correct file now.
EDIT2: Solved. I then changed the import to from models.User import User and It's hitting the method now.
The issue was twofold:
The User.py file was in the models/ folder, meaning that my import was actually looking for the User class in the models.py file, which no longer existed but still was being imported without error because the models.pyc file was still around
The import was incorrect for importing within a directory. it should have been from models.User import User, so long as the models/ folder is a module, so all I needed to do then was touch models/__init__.py.
>>> class foo(object):
... def __init__(self):
... pass
... #classmethod
... def classmethod(cls):
... return 0
...
>>> a = foo()
>>> a.classmethod()
0
>>>
Related
I'm trying to write a simple unit test to test an instance method of one of my models in Django. However my class initialises an external connection on __init__ which is not being patched even though I'm trying to target it.
Folder Structure:
- project/
- app1/
- tests/
- tests_models.py
- models.py
models.py:
from 3rdPartyPlugin import Bot
class MyClass:
def __init__(self, token):
self.bot = Bot(token)
def generate_buttons(self):
...
tests_models.py:
from django.test import TestCase
from unittest.mock import MagicMock, patch
from app1.models import MyClass
#patch('app1.models.3rdPartyPlugin.Bot')
class GenerateButtonsTestCase(TestCase):
def setUp(self):
self.tb = MyClass('', '', '')
def test_generates_button_correctly(self):
return True
I can't get past the setUp step because the initialisation of the class fails because it tries to reach out to that 3rdPartyPlugin module even though I patched it.
I've tried setting the patch to:
#patch('app1.models.3rdPartyPlugin.Bot')
#patch('app1.models.Bot')
#patch('app1.models.TB.Bot')
But all of the above still leads to the Bot being called. Any suggestions?
The problem is that Bot is already imported and read in models.py before you patch it.
Try to import the whole module instead:
import 3rdPartyPlugin
class MyClass:
def __init__(self, token):
self.bot = 3rdPartyPlugin.Bot(token)
def generate_buttons(self):
I eventually was able to solve this by moving the 3rdPartyPlugin code out of the initialiser and into an instance method on the class I was testing. This is how it looked in code:
models.py:
from 3rdPartyPlugin import Bot
class MyClass:
def __init__(self, token):
self.token = token
self.bot = self.bot()
def bot(self):
Bot(self.token)
tests_models.py:
from app1.models import MyClass
class GenerateButtonsTestCase(TestCase):
#patch('app1.models.MyClass.bot')
def setUp(self, _):
self.tb = MyClass('', '', '')
And after making the above changes, the patch correctly works and patches my use of Bot from the 3rdPartyPlugin. It's a bit messy but it works for me.
I have a django app where I want MyModel instances to be saved using an Enum choice, which I process in the save() method, such as:
# app/models.py
from django.db import models
from app.utils import translate_choice
from enum import Enum
class MyEnum(Enum):
CHOICE_A = 'Choice A'
CHOICE_B = 'Choice B'
class MyModel(models.Model):
...
choice = models.CharField(
max_length=10,
choices=[(tag.name, tag.value) for tag in MyEnum],
)
...
def save(self, *args, **kwargs):
self.choice = translate_choice(self.choice)
super().save(*args, **kwargs)
Whereas on the app/utils.py I have:
from app.models import MyEnum
def translate_choice(value):
...
return MyEnum.CHOICE_A # For example
I keep getting ImportError: cannot import name 'MyEnum' errors on the app/utils.py file when running the application. Is this due to a python circular import error, or am I missing something else? When moving the translate_choice() method to app/models.py it stops happening, but I would like to use this same method in other modules and it is kind of weird having a transforming feature within the models when used in another app.
Thank you in advance
It's probably due to the circular import, as you've guessed yourself. You can try putting the import statement not at the top of the file, but inside the function that uses the imported object:
def translate_choice(value):
from app.models import MyEnum
...
return MyEnum.CHOICE_A # For example
This is, admittedly, not the most elegant solution. See also the answers to this post, where you can find other approaches.
I have the following files:
# in models.py
class User(object):
def __init__(self, name):
self.name = name
# in util.py
def get_user():
return User(name="tom")
# in views.py
from util import get_user
get_user().name
I want to detect all Attribute usages for the name attribute on the User model. So get_user().name would be flagged as one such usage, since get_user returns a role User object.
Is there an easy way to do this using Astroid only preferably?
I am using Python 2.7, and have following code strucure
model
__init__.py
order.py
cart.py
That is, I define a package named model, and in this package, I define a module order, and I define a class in order.py
class MyOrder(object):
def __init__(self, name):
self.name = name
def getname(self):
return self.name
In the cart.py, the code is:
import model
x = model.order.MyOrder("Book")
print x.getname()
When I run it, it complains that AttributeError: 'module' object has no attribute 'order',
But the following is correct:
import model.order
x = model.order.MyOrder("Book")
print x.getname()
It looks that I can't import package (like import model) ?
If you want to have model automatically import order so it's available, you should do that in __init__.py. Simply put the following inside model/__init__.py:
from . import order
After that, you should be able to access model.order with just import model.
I want convert any string to my existing Entiy. Is it possible writing a convertToEntity() function as below?
class Personel(db.Model):
name=db.StringProperty()
class IsEntityExists(webapp.RequestHandler):
def get(self):
entity="Personal"
Entity=entity.convertToEntity()
Entity.all()
I wonder if the question is just asking to somehow look up the model class given its name, when it has already been imported. You can do this easily (but only when it has already been imported!), as follows:
cls = db.class_for_kind("Personel")
... cls.all() ...
The equivalent in NDB:
cls = ndb.Model._kind_map["Personel"]
... cls.query() ...
Good luck!
PS. No, it won't do spell correction. :-)
Only if you build loader for models... for example:
from app import model_loader
class IsEntityExists(webapp.RequestHandler):
def get(self):
Entity=model_loader("Personal")
Entity.all()
while the model_loader function would search the folder structure (python modules) for defined model.. for example you have folder structure:
models/
personal.py
other_model.py
user.py
So the model_loader("Personal") would import personal.py and extract "Personal" class from that module, allowing you to perform whatever you want with that class - if it finds it and loads it.
Of course you would have to code the loader.
However if the class (defined model) is in the same file as the code, you could search over locals() for "Personal"
def load_model(name):
local = locals()
try:
return local[name]
except KeyError:
return None