Unable to run an individual test with Django 1.8 - python

Having followed the advice in these two answers, I'm still unable to run only a single django test in the way it describes. I can run them all, but that takes a long time and makes debugging harder.
My project structure looks like this:
mainapp/mainapp/users/
├── __init__.py
├── tests
│ ├── __init__.py
│ ├── test_views.py
└── views.py
For example, when the whole test suite is run, one of the failing tests gives this output:
FAIL: test_changepassword (mainapp.users.tests.test_views.ChangePasswordTest)
But when I try to run that Django TestCase with either the Django...
~/mainapp$ python manage.py test mainapp.users.tests.test_views.ChangePasswordTest
File "/usr/lib/python2.7/unittest/loader.py", line 100, in loadTestsFromName
parent, obj = obj, getattr(obj, part)
AttributeError: 'module' object has no attribute 'test_views'
or django-nose syntax...
~/mainapp$ python manage.py test mainapp.users.tests.test_views:ChangePasswordTest
File "/usr/lib/python2.7/unittest/loader.py", line 100, in loadTestsFromName
parent, obj = obj, getattr(obj, part)
AttributeError: 'module' object has no attribute 'test_views:ChangePasswordTest'
When I run this in PyCharmCE debug mode it confirms that the module object has no attributes, but I don't know why.
I have django-nose (1.4.5) installed and it's in my INSTALLED_APPS, but I don't know if anything else is required to use it.
This works fine down to a certain level. For example this is OK:
~/mainapp$ python manage.py test mainapp.users.tests
What's going on?

Related

Django: __init__.py package breaks migrations

In my app, I have file structure:
myapp/
...
models.py
helpers/
__init__.py
RandomFileName.py
...
In RandomFileName.py I have helper class that generates random file names for my models:
class RandomFileName(object):
...
In models I want to treat helpers/ directory as a module:
from myapp.helpers import RandomFileName
class MyImage(models.Model):
...
image = models.ImageField(upload_to=RandomFileName('images/'))
...
Then, I run python3 manage.py makemigrations myapp
Looks good.
Then, I run python3 manage.py migrate and get an error:
in Migration
('image', models.ImageField(upload_to=myapp.helpers.RandomFileName.RandomFileName('images/'))),
AttributeError: type object 'RandomFileName' has no attribute 'RandomFileName'
Why is the RandomFileName doubled in migrations? Where did I go wrong?
Somehow your init.py file could have imported your object. Check. If not, then simply doing myapp.helpers.RandomFileName('images/') instead (based on the exception message) will fix the issue.

Python - Error importing class from another file

Can anyone guide on resolving the error ? The manager class method will need capability to create instance of User Class but it is not finding the module
Below is the folder structure and code and other details. init.py file is empty
Internal folder
->main.py
->__init__.py
->User Folder
-> user.py
-> models.py
-> usermanager.py
-> __init__.py
ModuleNotFoundError: No module named 'models'
at <module> (/home/vmagent/app/internal/user/usermanager.py:4)
at <module> (/home/vmagent/app/main.py:2)
at import_app (/env/lib/python3.6/site-packages/gunicorn/util.py:352)
at load_wsgiapp (/env/lib/python3.6/site-
packages/gunicorn/app/wsgiapp.py:52)
at load (/env/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py:65)
at wsgi (/env/lib/python3.6/site-packages/gunicorn/app/base.py:67)
at load_wsgi (/env/lib/python3.6/site-
packages/gunicorn/workers/base.py:135)
at init_process (/env/lib/python3.6/site-
packages/gunicorn/workers/base.py:126)
at spawn_worker (/env/lib/python3.6/site-
packages/gunicorn/arbiter.py:578)
main.py code
from internal.account import user,usermanager
def registerBlueprint(app, blueprint, manager):
blueprint.manager = manager
app.register_blueprint(blueprint)
registerBlueprint(app, user.request, usermanager)
user.py code
request = Blueprint('flex.user', __name__)
#request.route('/v1/user', methods=['POST'])
def CreateAccount():
test = request.manager.UserManager()
return test.CreateUser()
usermanager.py
from models import User
class UserManager:
def __init__(self):
pass
def CreateUser(self):
logger.log_text("AccountManger")
data = json.dumps(dict(
email="Hello#123.com",
password="Test124"
))
user = User(data)
user.create()
responseObject = dict(status='success', message='Successfully
registered.')
return make_response(jsonify(responseObject)), 201
Python paths can get kind of tricky. I don't claim that this is the best approach, but it's what I hacked together on my lunch. Perhaps it can get you where you need to go.
When you run main.py, you're in the internal/ directory. You need to go up a level and then access the user/ directory. That's what happens with sys.path.append('../'). The module usermanager.py is in the user/ directory, so to import from user.py, we want to point to the current directory. Hence the period in from .user import User.
Here's the directory structure I used. I believe it is the same as what you have.
C:.
├───internal
│ main.py
│ __init__.py
│
└───user
│ models.py
│ user.py
│ usermanager.py
└───__init__.py
__init__.py
The __init__.py files are empty. Their presence indicates to Python that the directories are modules1.
main.py
import sys
sys.path.append('../')
from user import user
from user import usermanager
from user import models
my_user = user.User()
my_user.message()
my_user_manager = usermanager.UserManager()
my_user_manager.message()
my_user_manager.CreateUser()
my_model = models.Model()
my_model.message()
models.py
class Model():
def message(self):
print("This is a Model!")
user.py
class User():
def message(self):
print("This is a User!")
usermanager.py
from .user import User
class UserManager():
def message(self):
print("This is a UserManager!")
def CreateUser(self):
new_user = User()
print("I created the user: ", new_user)
Now, when I call main.py I get:
c:\project\internal>python main.py
This is a User!
This is a UserManager!
I created the user: <user.user.User object at 0x0000000002A61EB8>
This is a Model!
Everyone is talking to everyone else. Hopefully you can extrapolate that to your use case! If not, Chris Yeh has an article "The Definitive Guide to Python import Statements" you may find helpful.
1 See What is __init__.py for? to learn more about how that works.
There is no models module in the standard library, and you do not have a file named models.py listed here, so python cannot find it. If models.py is in some subdirectory, that subdirectory needs to be in your python path, and you need to be sure that they contain an __init__.py file. That is the meaning of the error you're encountering here.

Python Import Dependency

I know this question has been asked many times, but even after I tried many SO suggestions, I still cannot get it right. So, posting here for your help.
I'm building a simple web server with Flask-Restful and Flask-SqlAlchemy. Basically, I think I'm getting an error because of a circular import. My Widget class is dependent on Visualization class and vice versa...
The error message:
Traceback (most recent call last):
File "server.py", line 1, in <module>
from app.resources.dashboard import Dashboards, Dashboard
File "app/__init__.py", line 14, in <module>
from models import *
File "app/models/__init__.py", line 1, in <module>
import visualization.Visualization as VisualizationModel
File "app/models/visualization.py", line 3, in <module>
from app.models import WidgetModel
ImportError: cannot import name WidgetModel
Directory structure:
├── app
│   ├── app/__init__.py
│   ├── app/models
│   │   ├── app/models/__init__.py
│   │   ├── app/models/dashboard.py
│   │   ├── app/models/visualization.py
│   │   ├── app/models/widget.py
│   └── app/resources
│   ├── app/resources/__init__.py
│   ├── app/resources/dashboard.py
│   ├── app/resources/visualization.py
│   ├── app/resources/widget.py
├── server.py
app/models/__init__.py:
from visualization import Visualization as VisualizationModel
from widget import Widget as WidgetModel
from dashboard import Dashboard as DashboardModel
app/models/visualization.py
from sqlalchemy import types
from app import db
from app.models import WidgetModel
class Visualization(db.Model):
__tablename__ = 'visualizations'
...
widget = db.relationship(WidgetModel, cascade="all, delete-orphan", backref="visualizations")
app/models/widget.py
from app import db
from app.models import VisualizationModel
class Widget(db.Model):
__tablename__ = 'widgets'
...
visualization = db.relationship(VisualizationModel, backref="widgets")
I tried changing my import to from app import models, and then use models.WidgetModel / models.VisualizationModel. However, still getting an ImportError.
Error message:
Traceback (most recent call last):
File "server.py", line 1, in <module>
from app.resources.dashboard import Dashboards, Dashboard
File "app/__init__.py", line 14, in <module>
from models import *
File "app/models/__init__.py", line 1, in <module>
from visualization import Visualization as VisualizationModel
File "app/models/visualization.py", line 3, in <module>
from app import models
ImportError: cannot import name models
I'm very new to Python. I would be grateful if you can help me out. Thanks for you help in advance!
Update
The intention of defining bi-directional relationship is that I want to attach the Visualization object in the fields of Widget object upon a return of GET request on a widget record.
In the app/resources/widget.py I have:
...
from flask_restful import fields, Resource, marshal_with, abort
from app.models import WidgetModel
import visualization as visualizationResource
widget_fields = {
'id': fields.String,
...
'dashboard_id': fields.String,
'visualization_id': fields.String,
'visualization': fields.Nested(visualizationResource.visualization_fields)
}
class Widgets(Resource):
#marshal_with(widget_fields)
def get(self):
return WidgetModel.query.all()
I also want to have the cascade delete feature because if a widget cannot exist without a visualization.
Change your import to look like this:
from app import models
And then use models.WidgetModel / models.VisualizationModel instead.
The problem is that you're creating a circular import dependency where both files require the other file to already have been processed before they can be processed. By moving to importing the entire models namespace rather than trying to import a specific model name at import time, you avoid making the import dependent on a fully processed file. That way, both files can be fully processed before either tries to invoke an object created by the other.
It may still not work in this case however because you're trying to immediately use the import in part of the class definition, which is evaluated at processing time.
It looks like you're trying to define bi-directional relationships - the backref parameter is intended to do this automatically without you having to specify the relationship on both models. (backref tells sqlalchemy what field to add to the other model to point back to the original models that link to it). So you may not need to be doing both of these imports in the first place.
For instance, the fact that Visualization.widget is defined with backref="visualizations" means that Widget.visualizations will already exist - you don't need to explicitly create it.
If what you specifically need is many:many relationships, then chances are what you actually want to do is define an association table for the many-to-many relationship.

Django Test Runner Not Finding Test Methods

I recently upgraded from Django 1.4 to 1.9 and realized something weird was going on with my tests. Here is the project structure:
project
manage.py
app/
__init__.py
tests/
__init__.py
test_MyTests.py
The test_MyTests.py file looks like this:
from django.test import TestCase
class MyTests(TestCase):
def test_math(self):
self.assertEqual(2, 2)
def test_math_again(self):
self.assertEqual(3, 3)
The test runner can find all of the tests when I run
./manage.py test app or ./manage.py test app.tests. However when I try running ./manage.py test app.tests.MyTests I get:
File "/usr/lib/python2.7/unittest/loader.py", line 100, in loadTestsFromName
parent, obj = obj, getattr(obj, part)
AttributeError: 'module' object has no attribute 'MyTests'
If I change the test class name to test_MyTests I can then run ./manage.py test app.tests.test_Mytests and it will find all tests. I was reading the Django docs though and it seems the file name and class name don't have to be the same. In either case that I showed above I still can't run individual tests like this, ./manage.py test app.tests.MyTests.test_math
I would like to be able to run individual tests and test classes, can someone help me here? Thanks.
In app.tests.test_MyTests part test_MyTests is module name, not class. To run test_math you should specify full path to this method:
python manage.py test app.tests.test_MyTests.MyTests.test_math
Y had the same problem and it was that I forgot to remove the default file tests.py that django create automatic when you create the app.

Python clean imports for models - SQL Alchemy

I have a flask app with the following directory structure:
myapp/
application.py
__init__.py
models/
__init__.py
user.py
The models use Flask-SQLAlchemy, and therefore, they need to have access to the db object (a SQLAlchemy instance) from application.py
user.py:
import sys,os
sys.path.append('/path/to/application/package')
from testapp import db
class User(db.Model):
id = db.Column(db.Integer,primary_key=True)
username = db.Column(db.String(255),unique=True)
age = db.Column(db.Integer)
def __init__(self,username,age):
self.username = username
self.age = age
def __repr__(self):
return '<User %r>' % self.username
Because any of the models need access to the application's SQLAlchemy instance, the db property, I have to throw this whole package on the path and then import from the main application module. For sanity's sake, I would like to keep the models in separate files. Will I need to put the path code on top of every model? Is there a better way? I'd rather not have the full path input like that, as they may be deployed to different hosts with different directory structures. Ideally there would be some way to internally handle the path so when it is used as another user via mod_wsgi I don't have to manually change the code.
1st approach:
I've ended up with the following structure:
project_root — also holds some configs, .gitignore file, etc
start.py
flask_root
__init__.py
application.py
module_1
__init__.py
models.py
module_2
__init__.py
models.py
Topmost start.py just runs the app:
#! /usr/bin/env python
from flask_root import applicaiton
if __name__ == '__main__':
application.manager.run()
Python searches for packages in the directory you script started from, so now you don't need add them to sys.path (as for me, modification of sys.path looks ugly).
Now you have full-working flask_root python package, and you can import everything from it, from any place of your application:
from flask_root.application import db
2nd approach:
If you start your Flask application from it's directory,
./application.py runserver
the directory you've started from is not be accessible as python package, even if it has __init__.py in it.
Though, with your directory layout you can do the following trick:
models/__init__.py:
from application import db
...
models/user.py:
from . import db
...
The first approach is more clean and universal. The second possibly can be useful when you need to share same blueprints between multiple Flask projects.

Categories

Resources