I'm using Pytest to test connection to database which hangs
when I run it:
def test_db():
db.create_all()
new_comment = Comments(comment='python rocks')
db.session.add(new_comment)
db.session.commit()
entry = Comments.query.all()
assert len(entry) == 1
db.drop_all()
The table is created successfully but I can't run select * from Comments; as it hangs too. I have to kill both windows.
How can I fix this ?
This code did the trick:
from sqlalchemy.engine.reflection import Inspector
from sqlalchemy import create_engine
engine = create_engine('mysql://user:password#localhost/table')
inspector = Inspector.from_engine(engine)
def test_db():
db.create_all()
assert inspector.get_table_names()[0] == 'comments'
db.drop_all()
Related
In pytest-django there is a builtin fixture live_server though it seems like this server (that is actually based on LiveServerTestCase) can't handle web-sockets or at least won't interact with my asgi.py module.
How can one mimic that fixture in order to use ChannelsLiveServerTestCase instead? Or anything else that will run a test-database and will be able to serve an ASGI application?
My goal eventually is to have as close to production environment as possible, for testing and being able to test interaction between different Consumers.
P.S: I know I can run manage.py testserver <Fixture> on another thread / process by overriding django_db_setup though I seek for a better solution.
You can implement a channels_live_server fixture based on the implementations of:
live_server fixture, which instantiates
LiveServer helper, which starts LiveServerThread, and
ChannelsLiveServerTestCase, which starts DaphneProcess.
#medihack implemented it at https://github.com/pytest-dev/pytest-django/issues/1027:
from functools import partial
from channels.routing import get_default_application
from daphne.testing import DaphneProcess
from django.contrib.staticfiles.handlers import ASGIStaticFilesHandler
from django.core.exceptions import ImproperlyConfigured
from django.db import connections
from django.test.utils import modify_settings
def make_application(*, static_wrapper):
# Module-level function for pickle-ability
application = get_default_application()
if static_wrapper is not None:
application = static_wrapper(application)
return application
class ChannelsLiveServer:
host = "localhost"
ProtocolServerProcess = DaphneProcess
static_wrapper = ASGIStaticFilesHandler
serve_static = True
def __init__(self) -> None:
for connection in connections.all():
if connection.vendor == "sqlite" and connection.is_in_memory_db():
raise ImproperlyConfigured(
"ChannelsLiveServer can not be used with in memory databases"
)
self._live_server_modified_settings = modify_settings(ALLOWED_HOSTS={"append": self.host})
self._live_server_modified_settings.enable()
get_application = partial(
make_application,
static_wrapper=self.static_wrapper if self.serve_static else None,
)
self._server_process = self.ProtocolServerProcess(self.host, get_application)
self._server_process.start()
self._server_process.ready.wait()
self._port = self._server_process.port.value
def stop(self) -> None:
self._server_process.terminate()
self._server_process.join()
self._live_server_modified_settings.disable()
#property
def url(self) -> str:
return f"http://{self.host}:{self._port}"
#pytest.fixture
def channels_live_server(request):
server = ChannelsLiveServer()
request.addfinalizer(server.stop)
return server
#aaron's solution can't work, due to pytest-django conservative approach for database access.
another proccess wouldn't be aware that your test has database access permissions therefore you won't have database access. (here is a POC)
Using a scoped fixture of daphne Server suffice for now.
import threading
import time
from functools import partial
from django.contrib.staticfiles.handlers import ASGIStaticFilesHandler
from django.core.exceptions import ImproperlyConfigured
from django.db import connections
from django.test.utils import modify_settings
from daphne.server import Server as DaphneServer
from daphne.endpoints import build_endpoint_description_strings
def get_open_port() -> int:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("", 0))
s.listen(1)
port = s.getsockname()[1]
s.close()
return port
def make_application(*, static_wrapper):
# Module-level function for pickle-ability
if static_wrapper is not None:
application = static_wrapper(your_asgi_app)
return application
class ChannelsLiveServer:
port = get_open_port()
host = "localhost"
static_wrapper = ASGIStaticFilesHandler
serve_static = True
def __init__(self) -> None:
for connection in connections.all():
if connection.vendor == "sqlite" and connection.is_in_memory_db():
raise ImproperlyConfigured(
"ChannelsLiveServer can not be used with in memory databases"
)
self._live_server_modified_settings = modify_settings(ALLOWED_HOSTS={"append": self.host})
self._live_server_modified_settings.enable()
get_application = partial(
make_application,
static_wrapper=self.static_wrapper if self.serve_static else None,
)
endpoints = build_endpoint_description_strings(
host=self.host, port=self.port
)
self._server = DaphneServer(
application=get_application(),
endpoints=endpoints
)
t = threading.Thread(target=self._server.run)
t.start()
for i in range(10):
time.sleep(0.10)
if self._server.listening_addresses:
break
assert self._server.listening_addresses[0]
def stop(self) -> None:
self._server.stop()
self._live_server_modified_settings.disable()
#property
def url(self) -> str:
return f"ws://{self.host}:{self.port}"
#property
def http_url(self):
return f"http://{self.host}:{self.port}"
#pytest.fixture(scope='session')
def channels_live_server(request, live_server):
server = ChannelsLiveServer()
request.addfinalizer(server.stop)
return server
I am new to REST API and starting building first REST API app using Flask, SQLAlchemy & Marshmallow. This is my app.py file:
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import os
# Initialize App
app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))
# Database Setup
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'db.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# Init db
db = SQLAlchemy(app)
# Init marshmallow
ma = Marshmallow(app)
# Product Class/Model
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True)
description = db.Column(db.String(200))
price = db.Column(db.Float)
qty = db.Column(db.Integer)
def __init__(self, name, description, price, qty):
self.name = name
self.description = description
self.price = price
self.qty = qty
# Product Schema
class ProductSchema(ma.Schema):
class Meta:
fields = ('id', 'name', 'description', 'price', 'qty')
# Init Schema
product_schema = ProductSchema()
products_schema = ProductSchema(many=True)
# Create Product
#app.route('/product', methods=['POST'])
def add_product():
name = request.json['name']
description = request.json['description']
price = request.json['price']
qty = request.json['qty']
new_product = Product(name, description, price, qty)
db.session.add(new_product)
db.session.commit()
return product_schema.jsonify(new_product)
# Get All Products
#app.route('/receive', methods=['GET'])
def get_products():
all_products = Product.query.all()
result = products_schema.dump(all_products)
return jsonify(result)
# Run the Server
if __name__ == '__main__':
app.run(debug=True)
For generating SQLite database, I have to open python interactive shell and then there I have to do this:
from app import db
db.create_all()
But I have to genreate database from app.py itself so I am inserting the same commands inside app.py, but it's giving me error:
OperationalError: (sqlite3.OperationalError) no such table: product
How do I generate a database from app.py?
Where are you placing your db.create_all()? The error may simply be a result of placement. When I copy and paste your code into PyCharm (running Python 3.7) it creates the DB fine when I place
db.create_all()
immediately before
# Run the Server
if __name__ == '__main__':
app.run(debug=True)
If you try to run db.create_all() before you instantiate the db object it will throw an error because db does not exist yet.
You should not need to use "from app import db" at all because the db object is declared up top.
please; can someone tell me what's wrong with this code?, i tried to connect to my postgre sql database with flask sqlalchemy but i keep having an error that db is not defined. NB: all modules are installed and loaded successfully.
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:....'
db = SQLAlchemy(app)
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text)
age = db.Column(db.Integer)
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return "Name:{}\tAge:{}".format(self.name, self.age)
def create_database():
db.create_all()
print('Database created....')
if __name__ == "__main__":
create_database()
First do a pip for sqlalchemy_utils i.e. pip install sqlalchemy_utils
and then,
You need to use engine for creating the DB:
from sqlalchemy import create_engine
from sqlalchemy_utils import database_exists, create_database
engine = create_engine("postgres://localhost/somedb")
if not database_exists(engine.url):
create_database(engine.url)
print(database_exists(engine.url))
I have an application with Blueprints and Celery
the code is here:
config.py
import os
from celery.schedules import crontab
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY') or ''
SQLALCHEMY_COMMIT_ON_TEARDOWN = True
RECORDS_PER_PAGE = 40
SQLALCHEMY_DATABASE_URI = ''
CELERY_BROKER_URL = ''
CELERY_RESULT_BACKEND = ''
CELERY_RESULT_DBURI = ''
CELERY_TIMEZONE = 'Europe/Kiev'
CELERY_ENABLE_UTC = False
CELERYBEAT_SCHEDULE = {}
#staticmethod
def init_app(app):
pass
class DevelopmentConfig(Config):
DEBUG = True
WTF_CSRF_ENABLED = True
APP_HOME = ''
SQLALCHEMY_DATABASE_URI = 'mysql+mysqldb://...'
CELERY_BROKER_URL = 'sqla+mysql://...'
CELERY_RESULT_BACKEND = "database"
CELERY_RESULT_DBURI = 'mysql://...'
CELERY_TIMEZONE = 'Europe/Kiev'
CELERY_ENABLE_UTC = False
CELERYBEAT_SCHEDULE = {
'send-email-every-morning': {
'task': 'app.workers.tasks.send_email_task',
'schedule': crontab(hour=6, minute=15),
},
}
class TestConfig(Config):
DEBUG = True
WTF_CSRF_ENABLED = False
TESTING = True
SQLALCHEMY_DATABASE_URI = 'mysql+mysqldb://...'
class ProdConfig(Config):
DEBUG = False
WTF_CSRF_ENABLED = True
SQLALCHEMY_DATABASE_URI = 'mysql+mysqldb://...'
CELERY_BROKER_URL = 'sqla+mysql://...celery'
CELERY_RESULT_BACKEND = "database"
CELERY_RESULT_DBURI = 'mysql://.../celery'
CELERY_TIMEZONE = 'Europe/Kiev'
CELERY_ENABLE_UTC = False
CELERYBEAT_SCHEDULE = {
'send-email-every-morning': {
'task': 'app.workers.tasks.send_email_task',
'schedule': crontab(hour=6, minute=15),
},
}
config = {
'development': DevelopmentConfig,
'default': ProdConfig,
'production': ProdConfig,
'testing': TestConfig,
}
class AppConf:
"""
Class to store current config even out of context
"""
def __init__(self):
self.app = None
self.config = {}
def init_app(self, app):
if hasattr(app, 'config'):
self.app = app
self.config = app.config.copy()
else:
raise TypeError
init.py:
import os
from flask import Flask
from celery import Celery
from config import config, AppConf
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
app_conf.init_app(app)
# Connect to Staging view
from staging.views import staging as staging_blueprint
app.register_blueprint(staging_blueprint)
return app
def make_celery(app=None):
app = app or create_app(os.getenv('FLASK_CONFIG') or 'default')
celery = Celery(__name__, broker=app.config.CELERY_BROKER_URL)
celery.conf.update(app.conf)
TaskBase = celery.Task
class ContextTask(TaskBase):
abstract = True
def __call__(self, *args, **kwargs):
with app.app_context():
return TaskBase.__call__(self, *args, **kwargs)
celery.Task = ContextTask
return celery
tasks.py:
from app import make_celery, app_conf
cel = make_celery(app_conf.app)
#cel.task
def send_realm_to_fabricdb(realm, form):
some actions...
and here is the problem:
The Blueprint "staging" uses task send_realm_to_fabricdb, so it makes: from tasks import send_realm_to_fabricdb
than, when I just run application, everything goes ok
BUT, when I'm trying to run celery: celery -A app.tasks worker -l info --beat, it goes to cel = make_celery(app_conf.app) in tasks.py, got app=None and trying to create application again: registering a blueprint... so I've got cycle import here.
Could you tell me how to break this cycle?
Thanks in advance.
I don't have the code to try this out, but I think things would work better if you move the creation of the Celery instance out of tasks.py and into the create_app function, so that it happens at the same time the app instance is created.
The argument you give to the Celery worker in the -A option does not need to have the tasks, Celery just needs the celery object, so for example, you could create a separate starter script, say celery_worker.py that calls create_app to create app and cel and then give it to the worker as -A celery_worker.cel, without involving the blueprint at all.
Hope this helps.
What I do to solve this error is that I create two Flask instance which one is for Web app, and another is for initial Celery instance.
Like #Miguel said, I have
celery_app.py for celery instance
manager.py for Flask instance
And in these two files, each module has it's own Flask instance.
So I can use celery.task in Views. And I can start celery worker separately.
Thanks Bob Jordan, you can find the answer from https://stackoverflow.com/a/50665633/2794539,
Key points:
1. make_celery do two things at the same time: create celery app and run celery with flask content, so you can create two functions to do make_celery job
2. celery app must init before blueprint register
Having the same problem, I ended up solving it very easily using shared_task (docs), keeping a single app.py file and not having to instantiate the flask app multiple times.
The original situation that led to the circular import:
from src.app import celery # src.app is ALSO importing the blueprints which are importing this file which causes the circular import.
#celery.task(bind=True)
def celery_test(self):
sleep(5)
logger.info("Task processed by Celery.")
The current code that works fine and avoids the circular import:
# from src.app import celery <- not needed anymore!
#shared_task(bind=True)
def celery_test(self):
sleep(5)
logger.info("Task processed by Celery.")
Please mind that I'm pretty new to Celery so I might be overseeing important stuff, it would be great if someone more experienced can give their opinion.
I am using selenium and i have properly installed the selenium module on redhat linux 6.
Below is my script:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
import unittest, time, re
import zlib
class Sele1(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "https://bugzilla.example.com/"
self.verificationErrors = []
def test_sele1(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("Bugzilla_login").clear()
driver.find_element_by_id("Bugzilla_login").send_keys("username")
driver.find_element_by_id("Bugzilla_password").clear()
driver.find_element_by_id("Bugzilla_password").send_keys("password")
driver.find_element_by_id("log_in").click()
driver.find_element_by_id("quicksearch").clear()
driver.find_element_by_id("quicksearch").send_keys("new bugs is bugzilla tool")
driver.find_element_by_xpath("//input[#value='Find Bugs']").click()
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException, e: return False
return True
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
unittest.main()
When i am running this script it is showing errors:
ERROR: test_sele1 (main.Sele1)
Traceback (most recent call last):
File "sele1.py", line 19, in test_sele1
driver.find_element_by_id("Bugzilla_login").clear()
AttributeError: 'NoneType' object has no attribute 'clear'
Ran 1 test in 2.018s
FAILED (errors=1)
Plateform: Redhat
Python Version: 2.6
Note: while running the same script in windows7, it is running fine but not running in linux with python2.6
Please help me for this...
Thanks in advance!
Simple: Selenium can't find an element called "Bugzilla_login".
There could be hundreds of reasons this may be happening. I'd start with checking whether you're loading the correct page.