Error while testing flask application with unittest - python

I have
ModuleNotFoundError: No module named 'project'
while trying to run test_req.py
My project structure is:
├── instance/
│ ├── flask.cfg
├── project/
│ ├── __init__.py
│ ├── base_processing.py
│ ├── models.py
| ├── views.py
│ ├── templates/
│ │ ├── base.html
│ │ ├── login.html
│ │ ├── note.html
│ │ ├── notes.html
│ └── static/
│ │
│ └── tests/
│ ├── test_req.html
├── run.py
My UnitTest file is:
# project/test_req.py
import unittest
import os
from project import app
from project.models import db, User, Note
from project.views import *
TEST_DB = 'test.db'
class RequestTests(unittest.TestCase):
#classmethod
def setUpClass(cls):
app.config['TESTING'] = True
app.config['WTF_CSRF_ENABLED'] = False
app.config['DEBUG'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + \
os.path.join(app.config['BASEDIR'], TEST_DB)
app.secret_key = 'staytrue'
cls.app = app.test_client()
def setUp(self):
db.create_all()
def tearDown(self):
db.drop_all()
def test_main_page(self):
response = self.app.get('/', follow_redirects=True)
self.assertEqual(response.status_code, 200)
def test_auth(self):
u = User(username='testname1', password='1234567', email='cyber#mail.com')
db.session.add(u)
db.session.commit()
response = self.app.post('/login', data=dict(username='testname1', password='1234567'), follow_redirects=True)
with self.app.session_transaction() as sess:
self.assertEqual(sess['username'], 'testname1')
if __name__ == "__main__":
unittest.main()
Also my test work just fine with nose2, when I run it from my root directory. Also this is the first time I'm organizing my project layout this way.

Module is not a folder, it should be a .py file. As you don't have project.py file, you should not specify from project import app.
Specifying from project import app means that there is project.py file and you want to import class app from this file.
if your test_req.py and app.py files are located in the same folder, then just use: import app in your test_req.py
Also replace:
from project.models import db, User, Note
from project.views import *
to
from models import db, User, Note
from views import *
Further reading:
Python
modules
Importing
Also, I would recommend to use PyCharm Community Edition, it is free, multilpatform and open source, and will help you to solve such tasks just via two mouse clicks.
Assume we have the following project structure in the root folder of our project:
/folder1/MyPythonFile1.py
/folder1/folder11/MyPythonFile2.py
/folder2/MyApp.py
/folder1/MyPythonFile1.py file looks like that:
class Class1:
def __init__(self):
pass
class Class2:
def __init__(self):
pass
And /folder1/folder11/MyPythonFile2.py file looks like that:
class Class3:
def __init__(self):
pass
File /folder2/MyApp.py uses classes from aforecited files and looks like that:
from folder1.MyPythonFile1 import Class1
from folder1.folder11.MyPythonFile2 import Class3
obj1 = Class1()
obj3 = Class3()
Apply this example to your particular case and update your imports accordingly.

Related

Register Tortoise signals in fast API

I just created a signal to generate a token when the user is created, I use tortoise.signals to generate it in a separate file, my project structure is like this
├── Makefile
├── README.md
├── core
│ ├── __init__.py
│ ├── authentication.py
│ ├── email.py
│ ├── models.py
│ ├── router.py
│ ├── schema.py
│ ├── signals.py
│ └── views.py
├── main.py
├── requirements.txt
├── static
└── templates
└── verification.html
And here is my signal file
# signals.py
from tortoise.signals import post_save
from tortoise import BaseDBAsyncClient
from typing import Type, List, Optional
from .models import UserModel, business_pydantic
from .email import send_email
#post_save(sender=UserModel)
async def create_business(
sender: "Type[UserModel]",
instance: UserModel,
created: bool,
using_db: Optional[BaseDBAsyncClient],
update_fields: List[str],
) -> None:
if created:
business_objects: UserModel = await UserModel.create(
business_name = instance.username, owner_id = instance
)
await business_pydantic.from_tortoise_orm(business_objects)
# send email
await send_email([instance.email], instance)
and I import the module in function create_app
from dotenv import dotenv_values
from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise
from fastapi.staticfiles import StaticFiles
from .router import router
def create_app():
app = FastAPI()
# mount static files
app.mount("/static", StaticFiles(directory="static"), name="static")
import signals # <- import my signal file here
register_tortoise(
app=app,
db_url="postgres://postgres:1234#localhost:5432/ecommerce_db",
modules={"models": ["core.models"]},
generate_schemas=True,
add_exception_handlers=True,
)
# add routes
app.include_router(router)
return app
My problem is that the signal that I created in the signals.py file is not read/executed, how do I make the functions that I make executed properly if I make them in a separate file, is there a way to register so that the signal is read in fast API?
Thanks!

How to use data obtained from DB as values in add_argument() when the Flask app starts?

I have the following project structure for a Flask app using flask-restx
.
├── app
│   ├── extensions.py
│   ├── __init__.py
│   └── pv_dimensioning
│   ├── controller.py
│   ├── __init__.py
│   ├── models
│   │   ├── dto.py
│   │   ├── __init__.py
│   │   └── vendor_models.py
│   ├── services
│   │   ├── calculator.py
│   │   ├── database.py
│   │   ├── data.py
│   │   ├── db_crud.py
│   │   ├── __init__.py
│   │   └── processor.py
│   └── utils
│   ├── decode_verify_jwt.py
│   ├── decorator.py
│   └── __init__.py
├── config.py
├── main.py
├── package.json
├── package-lock.json
├── Pipfile
├── Pipfile.lock
├── README.md
├── serverless.yml
└── tests
├── __init__.py
├── test_calculator.py
├── test_config.py
└── test_processor.py
In controller.py, I am adding the add_argument() statements and parsing them in the api routes. In one of the add_argument() statement, I would like to add choices for the user. For getting the choices, I am querying from the database and getting a list of values available. I then convert this list to a tuple, assign it to a variable, and pass it as choices parameter in the add_argument()
My codes:
data.py
from ..models.vendor_models import AdminVendor
def data(app):
values = AdminVendor.query.all()
v = [value.name for value in values]
return {'v': tuple(v)}
controller.py
from flask_restx import Resource, reqparse
parser = reqparse.RequestParser()
parser.add_argument(
"vendor",
choices=vendors, # <--- The values of v should be added here
help="Select the vendor"
)
#ns.route("/")
class UserOutput(Resource):
#ns.doc(
"Get calculated response",
responses={
200: "Values returned",
400: "Validation Error",
403: "Not authorized"
},
)
#ns.expect(parser, validation=True)
def get(self):
args = parser.parse_args()
return DimensionCalculator.inputs(**args), 200
where ns is the namespace.
My __init__.py file in the app folder is as follows:
from flask import Flask
from .extensions import cors, db, ma
def create_app(app_config):
app = Flask(__name__)
app.config.from_object(app_config)
register_blueprints(app)
register_extensions(app)
return app
def register_extensions(app):
cors.init_app(app)
db.init_app(app)
ma.init_app(app)
def register_blueprints(app):
from .pv_dimensioning import dimensioning_blueprint
app.register_blueprint(dimensioning_blueprint)
and the entry point to the app is main.py
import os
from app import create_app
from app.extensions import db
from app.pv_dimensioning.services.data import data
from config import config_by_name
config_name = os.getenv("FLASK_CONFIG") or "default"
app_config = config_by_name[config_name]
app = create_app(app_config)
db.create_all(app=app)
with app.app_context():
v = data(app)
print(v)
The output of print(v) is as follows:
{'v': ('Solarmodul Canadian Solar HiKu CS3L-370MS 370Wp', 'Solarmodul Longi LR4-60HIH-370M, 370Wp', 'Solarmodul Solar Fabrik mono S3 - Halfcut 360Wp', 'Solarmodul Energetica e.Classic M HC black - 360Wp', 'Solarmodul Yingli YL280P-29b-YGE 60 Cell Series 2 - poly, 280Wp', 'Solarmodul Suntech Power STP370S-B60/Wnh, 370Wp', 'Solarmodul AXITEC AXIworldpremium X HC AC-340MH/120S, 340Wp', 'Solarmodul Longi LR4-72HIH-440M, 440Wp', 'Solarmodul Seraphim SRP-330-BMB-DG 330Wp', 'Solarmodul Sharp NU-JD 440Wp')}
I want these values of v to be used in controller.py in the 'vendor' argument.
I have tried getting the values of v from main.py by adding from main import v in the controller.py, but it shows the following error
ImportError: cannot import name 'v' from 'main'
What is the mistake that I am doing?
I'm not an expert on flask_restx, but from my understanding, the choices argument takes an iterable so you should simply be able to pass in the return value of your data function.
data.py
from ..models.vendor_models import AdminVendor
def data():
values = AdminVendor.query.all()
v = [value.name for value in values]
return {'v': tuple(v)}
controller.py
from flask_restx import Resource, reqparse
from .services.data import data
parser = reqparse.RequestParser()
parser.add_argument(
"vendor",
choices=data()['v'],
help="Select the vendor")
Regarding the import error, as Mindslave points out that is most likely a circular import error see this question for a bit more detail. Generally these can be avoided by moving the import from the top of the module to within a function/class, e.g:
from flask_restx import Resource, reqparse
def load_parser():
from .services.data import data # avoid circular import
parser = reqparse.RequestParser()
parser.add_argument(
"vendor",
choices=data()['v'],
help="Select the vendor")
return parser
parse = load_parser()
As a side note, be aware that reqparse is scheduled to be removed from flask_restx, so might be worth considering a different option before you get too embedded with it:
Warning The whole request parser part of Flask-RESTX is slated for
removal and will be replaced by documentation on how to integrate with
other packages that do the input/output stuff better (such as
marshmallow). This means that it will be maintained until 2.0 but
consider it deprecated. Don’t worry, if you have code using that now
and wish to continue doing so, it’s not going to go away any time too
soon.
source: https://flask-restx.readthedocs.io/en/latest/parsing.html

import class from another/folder into views, django

I am making a scraper function with tidy folder structure. But when I try to import scraper class into views.py it's giving an error:
'module' object is not callable
This is the Tree:
├── api_services
│   ├── spiders
│   │   ├── spiderAtom.py
│   │   └── spiderEbis.py
│   └── views
│   └── viewApi.py
In spiders folder I have this class:
class spiderAtom:
def atom():
string = "return this method"
return string
and trying import it in viewApi
from ..spiders import spiderAtom
def atomApi(request):
spider = spiderAtom()
response = spider.atom()
return HttpResponse(response)
But with the the way I am doing is not working.
Just add __init__.py file to api_services and then call from api_services.spiders.spiderAtom import spiderAtom.

Why does admin's template cover over main's one in Flask?

This is my structure.
│ run.py
│
├─admin
│ │ views.py
│ │ views.pyc
│ │ __init__.py
│ │ __init__.pyc
│ │
│ └─templates
│ hello.html
│ index.html
│
└─main
│ views.py
│ views.pyc
│ __init__.py
│ __init__.pyc
│
└─templates
index.html
I try to build two apps in flask project. My purpose is when I browse http://127.0.0.1:5000/main/ it will returns main/templates/index.html, when I browse http://127.0.0.1:5000/admin/ it will returns main/templates/index.html.
I find I browse http://127.0.0.1:5000/main/ it will return main/templates/index.html. WTF?
If I rename html of different directory when changing main/templates/index.html to main/templates/index2.html, I am valid to get main/templates/index2.html in my expectation
admin/views.py:
from flask import Blueprint, render_template
admin = Blueprint("admin", __name__, template_folder="templates")
#admin.route('/')
def index():
return render_template('index.html')
main/views.py:
from flask import Blueprint, render_template
main = Blueprint("main", __name__, template_folder="templates")
#main.route('/')
def index():
return render_template('index.html')
run.py
import os
from flask import Flask
from main.views import main
from admin.views import admin
app = Flask(__name__)
app.register_blueprint(main, url_prefix='/main')
app.register_blueprint(admin, url_prefix='/admin')
print app.url_map
app.run(debug=True)
The issue is same in django. The document has recommended your template directory should set: app_name/templates/app_name.

django: cant import model to a .py on the same path as models

I have read everything on SO and all the django docs looking for a solution to this. My models work absolutely fine but i cant import them to my 'getnews.py' file in the same directory as models.py, i can to the views.py and there is absolutely no circular imports!
models.py:
from django.db import models
import datetime
from django.utils import timezone
class newsurls(models.Model):
title = models.CharField(max_length=200)
def __unicode__(self):
return unicode(self.title)
pub_date = models.DateTimeField("date published")
class newsblock(models.Model):
news = models.ForeignKey(newsurls)
url = models.URLField(max_length=2000)
def __unicode__(self):
return unicode(self.url)
image = models.URLField(max_length=2000)
favi = models.URLField(max_length=2000)
bgcolor = models.CharField(max_length=20)
tcolor = models.CharField(max_length=20)
genre = models.CharField(max_length=200)
in views.py: (works)
from news.models import newsurls, newsblock
getnews.py: (dont work)
from news.models import newsurls, newsblock
traceback:
Traceback (most recent call last):
File "/home/skru/newsshuffle/news/getnews.py", line 3, in <module>
from news.models import newsurls, newsblock
ImportError: No module named news.models
views.py:
from django.shortcuts import render_to_response
from news.models import newsurls, newsblock
try:
import cPickle as pickle
except:
import pickle
import random
def news(request):
newsDatabase = open('/home/skru/newsshuffle/news/storyDb.p', 'r+')
openData = newsDatabase.read()
dstory = pickle.loads(openData)
count = dstory['count']['links']
story = []
outstorys = []
keys = dstory.keys()
for key in keys:
if key != 'count':
story.append(dstory[key]['genre'])
story.append(dstory[key]['title'])
story.append(dstory[key]['url'])
story.append(dstory[key]['image'])
story.append(dstory[key]['bgcolor'])
story.append(dstory[key]['via'])
story.append(dstory[key]['tcolor'])
outstorys.append(story)
story = []
random.shuffle(outstorys)
lists = newsurls.objects.order_by('-pub_date')[:100]
return render_to_response('news/news.html',
{
'story_list':outstorys,
'count':count,
'lists':lists,
})
filepath:
├── db.sqlite3
├── manage.py
├── news
│ ├── static
│ │ └── news
│ │ ├── news.css
│ │ └── ...
│ ├── templates
│ │ └── news
│ │ ├── allnews.html
│ │ └── ...
│ ├── __init__.py
│ ├── admin.py
│ ├── dd.py
│ ├── getPrevDate.py
│ ├── getnews.py
│ ├── models.py
│ ├── storyDb.p
│ ├── tests.py
│ ├── urls.py
│ ├── views.py
└── newsshuffle
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
i have tried every sort of different import 'newsshuffle.news.models' etc..,
added the system path to the system path manually as suggested in other feeds please help!!
manage.py:
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "newsshuffle.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
added this because most other posts on SO point to setting DJANGO_SETTINGS_MODULE having to be set manually bur as you can see it already is
Given that directory structure, your import should be working.
How about trying a relative import instead? In both views.py and getnews.py this should work:
from models import ...
have You tried that?
from .models import newsurls, newsblock
Please also read about PEP8 http://legacy.python.org/dev/peps/pep-0008/ cause Your code is not formatted correctly.
EDITED: I see that You trying to do that but without '.' sign. Please note that before models is '.' like that .models

Categories