In Python, I'm trying to create a few global objects that are available anywhere in a program if a module has been imported (similar to the logging module).
For example:
module: databaseinterface.py
import sqlite3
DATABASE = None
class Database:
def init(self, location): ...
def ViewQuery(self, query, params): ...
def ModifyQuery(self, query, params): ...
def create_database(location):
if not DATABASE:
DATABASE = Database(location)
module: main.py
import databaseinterface
databaseinterface.create_database("test.sqlite")
results = databaseinterface.DATABASE.ViewQuery("SELECT * from users")
But I get the error "ViewQuery" does not exist. Is there a neat way to have global instances available from an import?
cheers,
Brad
What you want is a singleton class structure. It is a common code Design Pattern.
There are a lot of resources. e.g. This Blog post Or just use: https://duckduckgo.com/?q=python+singleton
example code piece:
class SingletonGovt:
__instance__ = None
def __init__(self):
""" Constructor.
"""
if SingletonGovt.__instance__ is None:
SingletonGovt.__instance__ = self
else:
raise Exception("You cannot create another SingletonGovt class")
#staticmethod
def get_instance():
""" Static method to fetch the current instance.
"""
if not SingletonGovt.__instance__:
SingletonGovt()
return SingletonGovt.__instance__
Is it possible to have base classes that define tests in tornado that are themselves not run as tests?
Let's say I have the following minimal example as a base class:
from tornado.testing import AsyncTestCase, gen_test
from tornado.httpclient import HTTPRequest
class AbstractTestCase(AsyncTestCase):
def set_parameters(self):
#Set some parameter value here: self.uri = ...
raise NotImplementedError
#gen_test
def test_common_functionality(self):
req = HTTPRequest(self.uri, method = "GET")
response = yield self.client.fetch(req, raise_error=False)
self.assertEqual(200, response.code)
Now, I would like to make several test cases that inherit from this, define their own value for self.uri...and have some specific tests of their own. Like this:
class ConcreteTestCase(AbstractTestCase):
def set_parameters(self):
self.uri = "www.stackoverflow.com"
#gen_test
def test_some_other_thing(self):
self.assertEqual(2, 1+1)
However, when I try to run this, the AbstractTestCase is also run on its own, giving an error (the NotImplementedError). This happens even when I only try to run the inheriting tests.
Is there any way around this issue, or do I have to duplicate the functionality in each test case?
One way to do this is with multiple inheritance. The abstract class doesn't need to extend AsyncTestCase as long as that class is in the inheritance hierarchy at runtime.
class AbstractTestCase(object):
def set_parameters(self):
#Set some parameter value here: self.uri = ...
raise NotImplementedError
#gen_test
def test_common_functionality(self):
req = HTTPRequest(self.uri, method = "GET")
response = yield self.client.fetch(req, raise_error=False)
self.assertEqual(200, response.code)
class ConcreteTestCase(AbstractTestCase, AsyncTestCase):
def set_parameters(self):
self.uri = "www.stackoverflow.com"
#gen_test
def test_some_other_thing(self):
self.assertEqual(2, 1+1)
This is admittedly a little weird and mypy type checking doesn't like it. But it's simple and it works, and I haven't found a mypy-friendly alternative that I like.
CLI
python3 -m tornado.testing ConcreteTestCase.ConcreteTestCase
testmain.py
#!/usr/bin/env python3
import unittest
from tornado.testing import main
def all():
cases = ['ConcreteTestCase.ConcreteTestCase']
return unittest.defaultTestLoader.loadTestsFromNames(cases)
main()
test/runtests.py is a good example.
I have an application with many threads. One of them is flask, which is used to implement (auxiliary) API. It's used with low load and never exposed to the Internet, so build-in flask web server is perfectly fine.
My current code looks like this:
class API:
# ... all other stuff here, skipped
def run():
app = flask.Flask('API')
#app.route('/cmd1')
def cmd1():
self.cmd1()
#app.route('/cmd2')
def cmd2()
self.cmd2()
app.run()
I feel I done it wrong, because all docs says 'create flask app at module level'. But I don't want to do this - it messes up with my tests, and API is a small part of the larger application, which has own structure and conventions (each 'application' is a separate class running in one or more threads).
How can I use Flask inside class?
Although this works it doesn't feel compliant with the Flask style guide. If you need to wrap a Flask application inside your project, create a separate class to your needs and add functions that should be executed
from flask import Flask, Response
class EndpointAction(object):
def __init__(self, action):
self.action = action
self.response = Response(status=200, headers={})
def __call__(self, *args):
self.action()
return self.response
class FlaskAppWrapper(object):
app = None
def __init__(self, name):
self.app = Flask(name)
def run(self):
self.app.run()
def add_endpoint(self, endpoint=None, endpoint_name=None, handler=None):
self.app.add_url_rule(endpoint, endpoint_name, EndpointAction(handler))
def action():
# Execute anything
a = FlaskAppWrapper('wrap')
a.add_endpoint(endpoint='/ad', endpoint_name='ad', handler=action)
a.run()
Some things to note here:
EndpointAction is supposed to be a wrapper that will execute your function and generate an empty 200 response. If you want you can edit the functionality
The endpoint handler can be anything that has a __call__ method defined
The endpoint name should be unique as it represents a view name
Adding endpoints after the application is not possible as the thread will block once the application starts. You can enable it by running the application on a separate thread but changing the URL map on the fly is not advised, neither thread safe
So I just came across the library Flask-Classful
which was really simple comparatively
To create a simple web app inside a class is this:
from flask import Flask
from flask_classful import FlaskView
app = Flask(__name__)
class TestView(FlaskView):
def index(self):
# http://localhost:5000/
return "<h1>This is my indexpage</h1>"
TestView.register(app,route_base = '/')
if __name__ == '__main__':
app.run(debug=True)
Handling multiple route and dynamic route is also simple
class TestView(FlaskView):
def index(self):
# http://localhost:5000/
return "<h1>This is my indexpage</h1>"
def secondpage(self):
# http://localhost:5000/secondpage
return "<h1>This is my second</h1>"
def thirdpage(self,name):
# dynamic route
# http://localhost:5000/thirdpage/sometext
return "<h1>This is my third page <br> welcome"+name+"</h1>"
TestView.register(app,route_base = '/')
Adding own route name with a different method that is also possible
from flask_classful import FlaskView,route
class TestView(FlaskView):
def index(self):
# http://localhost:5000/
return "<h1>This is my indexpage</h1>"
#route('/diffrentname')
def bsicname(self):
# customized route
# http://localhost:5000/diffrentname
return "<h1>This is my custom route</h1>"
TestView.register(app,route_base = '/')
This gives the potential to create separate class and handlers for a separate dependent and independent process and just import them as a package to run on the main file or wrapper file
from package import Classname
Classname.register(app,route_base = '/')
which is really simple and object-oriented
To complete Kostas Pelelis's answer, because I had some difficulty to find the why the Response wasn't directly using the Action returned value.
Here is another version of FLASK class without decorators :
class EndpointAction(object):
def __init__(self, action):
self.action = action
def __call__(self, *args):
# Perform the action
answer = self.action()
# Create the answer (bundle it in a correctly formatted HTTP answer)
self.response = flask.Response(answer, status=200, headers={})
# Send it
return self.response
class FlaskAppWrapper(object):
def add_all_endpoints(self):
# Add root endpoint
self.add_endpoint(endpoint="/", endpoint_name="/", handler=self.action)
# Add action endpoints
self.add_endpoint(endpoint="/add_X", endpoint_name="/add_X", handler=self.add_X)
# you can add more ...
def add_endpoint(self, endpoint=None, endpoint_name=None, handler=None):
self.app.add_url_rule(endpoint, endpoint_name, EndpointAction(handler))
# You can also add options here : "... , methods=['POST'], ... "
# ==================== ------ API Calls ------- ====================
def action(self):
# Dummy action
return "action" # String that will be returned and display on the webpage
# Test it with curl 127.0.0.1:5000
def add_X(self):
# Dummy action
return "add_X"
# Test it with curl 127.0.0.1:5000/add_X
Here is an example of mixing class and routing that seems reasonable to me. See also https://github.com/WolfgangFahl/pyFlaskBootstrap4/issues/2 (where i am a committer)
This design has been criticized so in the project there are some improvements to this code.
'''
Created on 27.07.2020
#author: wf
'''
from flask import Flask
from frontend.WikiCMS import Frontend
from flask import render_template
import os
class AppWrap:
def __init__(self, host='0.0.0.0',port=8251,debug=False):
self.debug=debug
self.port=port
self.host=host
scriptdir=os.path.dirname(os.path.abspath(__file__))
self.app = Flask(__name__,template_folder=scriptdir+'/../templates')
self.frontend=None
def wrap(self,route):
if self.frontend is None:
raise Exception("frontend is not initialized")
content,error=self.frontend.getContent(route);
return render_template('index.html',content=content,error=error)
def run(self):
self.app.run(debug=self.debug,port=self.port,host=self.host)
pass
def initFrontend(self,wikiId):
frontend=Frontend(wikiId)
frontend.open()
appWrap=AppWrap()
app=appWrap.app
#app.route('/', defaults={'path': ''})
#app.route('/<path:route>')
def wrap(route):
return appWrap.wrap(route)
if __name__ == '__main__':
appWrap.run()
A sidenote/addition to #Kostas Pelelis Answer (Sorry can't comment yet):
For all of you who wonder how to integrate the methods of the endpoint route: have a look at the function description for app.add_url_rule.
As stated there you can use the "methods" parameter to change the default "GET" method.
Kostas Pelelis code changed to a "POST" type method would look like this:
(Example with methods integrated + Endpoint-class that returns whatever your action-function returns [a html for example]
from flask import Flask, Response, render_template
class EndpointAction(object):
def __init__(self, action):
self.action = action
self.response = Response(status=200, headers={})
def __call__(self, *args):
response = self.action()
if response != None:
return response
else
return self.response
class FlaskAppWrapper(object):
app = None
def __init__(self, name):
self.app = Flask(name)
def run(self):
self.app.run()
def add_endpoint(self, endpoint=None, endpoint_name=None, handler=None, t_methods=None):
self.app.add_url_rule(endpoint, endpoint_name, EndpointAction(handler), methods=t_methods)
def action():
# Execute anything
print('i did something')
def returning_action():
# Returning for example an index hello world page
return render_template('index.html')
a = FlaskAppWrapper('wrap')
a.add_endpoint(endpoint='/ad', endpoint_name='ad', handler=action, req_methods=['POST'])
#just a little addition for handling of a returning actionhandler method
#-> i added another endpoint but for a returning method
a.add_endpoint(endpoint='/', endpoint_name='index_page', handler=returning_action, req_methods=['GET']
a.run()
While the templates/index.html could look like this (note render_templates expects a templates-folder in the same location as your py-file with specified htmls in it):
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index Page</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
This index page addition is called when the index route 'ip-address-of-the-webapp/' is visited (via usual browser visit -> GET request).
*Edit: to show how it would look like if your action-methods had params (for example from a route param) here an updated version of the endpoint class and the action class
class EndpointAction(object):
def __init__(self, action):
self.action = action
self.response = Response(status=200, headers={})
def __call__(self, *args, **kwargs):
response = self.action(**kwargs)
if response != None:
return response
else
return self.response
def param_action(param):
# Execute something (print param)
print(f'i did {param}')
[...]
a.add_endpoint(endpoint='/<param>', endpoint_name='parametric_action', handler=param_action, req_methods=['GET']
[...]
i want to move functions because of lot of files, into separate python files.
But if i do it, it dont work.
I tried:
File: server.py:
import os, cherrypy, json
from customers.py import *
class application(object):
def get_webpage(self):
....
def get_data(self):
....
File: customers.py:
import os, cherrypy, json
def get_customer_data(self):
....
I use the python as server,
the data in the function: get_customer_data is in this case not processed, get a 404 Not Found,
means the function is not included in main file (server.py)
I removed the self from get_webpages() because it was not indented, which means it was not part of the class.
application.py:
class application(object):
def __init__(self):
pass
def get_webpage():
print('From application')
customers.py:
from application import *
get_webpage() # From application
You could indent get_webpages() and make it part of the class. The way you call it would change. (I put the self back and capitalized the name of the class.)
application.py:
class Application(object):
def __init__(self):
pass
def get_webpage(self):
print('From application')
customers.py:
from application import *
a = Application()
a.get_webpage() # From application
I'm trying to patch an API for unit testing purposes. I have a class like this:
# project/lib/twilioclient.py
from os import environ
from django.conf import settings
from twilio.rest import TwilioRestClient
def __init__(self):
return super(Client, self).__init__(
settings.TWILIO_ACCOUNT_SID,
settings.TWILIO_AUTH_TOKEN,
)
client = Client()
and this method:
# project/apps/phone/models.py
from project.lib.twilioclient import Client
# snip imports
class ClientCall(models.Model):
'call from Twilio'
# snip model definition
def dequeue(self, url, method='GET'):
'''"dequeue" this call (take off hold)'''
site = Site.objects.get_current()
Client().calls.route(
sid=self.sid,
method=method,
url=urljoin('http://' + site.domain, url)
)
and then the following test:
# project/apps/phone/tests/models_tests.py
class ClientCallTests(BaseTest):
#patch('project.apps.phone.models.Client', autospec=True)
def test_dequeued(self, mock_client):
cc = ClientCall()
cc.dequeue('test', 'TEST')
mock_client.calls.route.assert_called_with(
sid=cc.sid,
method='TEST',
url='http://example.com/test',
)
When I run the test, it fails because the real client is called instead of the mock client.
Looks like it should work to me, and I've been able to make this type of thing work before. I've tried the usual suspects (removing *.pyc) and things don't seem to be changing. Is there a new behavior here that I'm missing somehow?