How can I test the functions in this Flask app- write unittests? - python

POOL = redis.ConnectionPool(host='localhost', port=6379, db=0)
app = Flask(__name__)
#app.route('/get_cohort_curve/', methods=['GET'])```
def get_cohort_curve():
curve = str(request.args.get('curve'))
cohort = str(request.args.get('cohort'))
key = curve+cohort
return get_from_redis(key)
def get_from_redis(key):
try:
my_server = redis.Redis(connection_pool=POOL)
return json.dumps(my_server.get(key))
except Exception, e:
logging.error(e)
app.run()
I need to write unit-tests for this.
How do I test just the route, i.e. a get request goes to the right place?
Do I need to create and destroy instances of the app in the test for each function?
Do I need to create a mock redis connection?

If you are interested in running something in Flask, you could create a virtual environment and test the whole shebang, but in my opinion that is THE HARDEST way to do it.
When I built my site installing Redis locally, setting the port and then depositing some data inside it with an appropriate key was essential. I did all of my development in iPython (jupyter) notebooks so that I could test the functions and interactions with Redis before adding the confounding layer of Flask.
Then you set up a flawless template, solid HTML around it and CSS to style the site. If it works without data as an html page, then you move on to the python part of Flask.
Solidify the Flask directories. Make sure that you house them in a virtual environment so that you can call them from your browser and it will treat your virtual environment as a server.
You create your app.py application. I created each one of the page functions one at a time. tested to see that it was properly pushing the variables to post on the page and calling the right template. After you get on up and running right, with photos and data, then at the next page's template, using #app.route
Take if very slow, one piece at a time with debugging on so that you can see where when and how you are going wrong. You will only get the site to run with redis server on and your virtual environment running.
Then you will have to shut down the VE to edit and reboot to test. At first it is awful, but over time it becomes rote.
EDIT :
If you really want to test just the route, then make an app.py with just the #app.route definition and return just the page (the template you are calling). You can break testing into pieces as small as you like, but you have to be sure that the quanta you pick are executable as either a python script in a notebook or commandline execution or as a compact functional self-contained website....unless you use the package I mentioned in the comment: Flask Unit Testing Applications
And you need to create REAL Redis connections or you will error out.

Related

How to run flask along side my tests in PyTest?

The usual flags: I'm new to Python, I'm new to PyTest, I'm new to Flask.
I need to create some server independent tests to test an api which calls a third-party.
I cannot access that api directly, but I can tell it what url to use for each third-party.
So what I want to do is to have a fake api running on the side (localhost) while I'm running my tests, so when the api that I'm testing needs to consume the third-parties, it uses my fake-api instead.
So I created the following app.py:
from flask import Flask
from src.fakeapi.routes import configure_routes
app = Flask(__name__)
configure_routes(app)
def start_fake_api():
app.run(debug=True)
And my_test.py:
from src.fakeapi.app import start_fake_api
#start_fake_api()
def test_slack_call():
send_request_to_api_to_configure_which_url_to_use_to_call_third_party("http://127.0.0.1:5000/")
send_request_to_api_to_populate_table_using_third_party()
Now, this might be an oversimplified example, but that's the idea. My problem obviously is that once I run Flask the process just stays in stand by and doesn't continue with the tests.
I want to avoid having to depend on manually running the server before running the tests, and I want to avoid running my tests in parallel.
What's the best way to do this?
Can I somehow execute app.py when I execute pytest? Maybe by altering pytest.ini somehow?
Can I force a new thread just for the server to run?
Thanks in advance!
I don't see a good reason to run a fake server, when you can instead use mock libraries such as requests-mock or responses to respond.
That said, if you really do need to run a real server, you could set up a session scoped fixture with a cleanup.
Adding autouse will make the tests automagically start the server, but you can leave that out and just invoke the fixture in your test, á la test_foo(fake_api)
Implementing the TODOed bit can be a little tricky; you'd probably need to set up the Werkzeug server in a way that you can signal it to stop; e.g. by having it wait on a threading.Event you can then raise.
#pytest.mark.fixture(scope="session", autouse=True)
def fake_api():
app = ...
port = random.randint(1025, 65535) # here's hoping no one is on that port
t = threading.Thread(target=lambda: app.run(debug=True, port=port))
t.start()
yield port
# TODO: implement cleanly terminating the thread here :)

Any way to run an internal python script from a webpage?

I finally made a project that I wanted to make since a long time :
I'm using an Arduino Uno to replace my PC power button (with a simple relay) and that Arduino Board is connected to a Raspi 3 for network connection purposes
My wish is to do a webpage (or a API-Like request) that at a touch of a button (preferably in a password-protected page) It'll power the PC on
I know how to code in Python, and my script to control the Arduino is already done but I can't find a way to run, only server-side, a Python Script from a button in a webpage
I found that CherryPy framework but I don't think it'll suit my needs
Can someone give me any ideas about that please?
As already mentioned by #ForceBru, you need a python webserver.
If this can be useful to you, this is a possible unsecure implementation using flask:
from flask import Flask
from flask import request
app = Flask(__name__)
#app.route('/turnOn')
def hello_world():
k = request.args.get('key')
if k == "superSecretKey":
# Do something ..
return 'Ok'
else:
return 'Nope'
If you put this in an app.py name file and, after having installed flask (pip install flask), you run flask run you should be able to see Ok if visiting the url http://localhost:5000/turnOn?key=superSecretKey .
You could write a brief html gui with a button and a key field in a form but I leaves that to you (you need to have fun too!).
To avoid potential security issues you could use a POST method and https.
Look at the flask documentation for more infos.

Django Hostname in Testing

I am wondering if there is a way to obtain the hostname of a Django application when running tests. That is, I would like the tests to pass both locally and when run at the staging server. Hence a need to know http://localhost:<port> vs. http://staging.example.com is needed because some tests query particular URLs.
I found answers on how to do it inside templates, but that does not help since there is no response object to check the hostname.
How can one find out the hostname outside the views/templates? Is it stored in Django settings somewhere?
Why do you need to know the hostname? Tests can run just fine without it, if you use the test client. You do not need to know anything about the system they're running on.
You can also mark tests with a tag and then have the CI system run the tests including that tag.
And finally there is the LiveServerTestCase:
LiveServerTestCase does basically the same as TransactionTestCase with one extra feature: it launches a live Django server in the background on setup, and shuts it down on teardown. This allows the use of automated test clients other than the Django dummy client such as, for example, the Selenium client, to execute a series of functional tests inside a browser and simulate a real user’s actions.
The live server listens on localhost and binds to port 0 which uses a free port assigned by the operating system. The server’s URL can be accessed with self.live_server_url during the tests.
Additional information from comments:
You can test if the URL of an image file is present in your response by testing for the MEDIA_URL:
self.assertContains(response, f'{settings.MEDIA_URL}/default-avatar.svg')
You can test for the existence of an upload in various ways, but the easiest one is to check if there's a file object associated with the FileField. It will throw ValueError if there is not.

Dynamically displaying a Python variable in a Flask application

I am working on a little personal project with the aim of using Python to obtain and process data from a running game and use HTML/CSS to output this data using Flask.
I am very new to Python, but have some basic exposure to HTML/CSS and JavaScript.
Using example code from the web and various tutorials I have been able to get two distinct sections of this working to a proof of concept stage:
My python code runs in an interuptible loop and will output a variable every X seconds to the console.
I have setup a Flask application that I can pass a variable to in a Python script and display in a browser.
My problem is I am stumped with how I go about joining these two together. In the Python script that runs the Flask app nothing else happens while the Flask app is running, I assume because it is executing synchronously. This means that I can't start the Flask app and then have my loop run after that, how can I get both to work simultaneously?
EDIT:
After more thinking about this and some further research I think I have framed the problem incorrectly due to the way I have setup my local environment.
My original thinking was that the Python script which runs the Flask server could also be used to recieve/process and output my game logic*. I now believe this to be incorrect because in typical usage Flask would be running on a web server somewhere serving the website while the data from the game would have to be collected and processed by an application local to the running of the game.
So, given the above the question could be better posed as:
How to dynamically display (say with a maximum refresh interval of 1s) a Python variable that is constantly changing using a Flask server? How do I get these two separate parts of my project to communicate with one-another?
*If this were possible (and I don't know its not) it would actually accomplish what I want from this project but is not likely to be a particularly useful skill so I would like to figure out how to do this the correct way in case this becomes something I would like to make available to others.

How to convert the django web application into the desktop application

How to convert the web site develpoed in django, python into desktop application.
I am new to python and django can you please help me out
Thanks in Advance
I think you should just create an application that connects to the webserver. There is a good answer to getting RESTful API calls into your django application. This means you'd basically just be creating a new front-end for your server.
Using django-rest-interface
It doesn't make sense to rewrite the entire django application as a desktop application. I mean, where do you want to store the data?
For starters, you'll have to replace the web UI with a desktop technology like Tk/Tcl.
If you do that, you may not want to use HTTP as the protocol between the client and the services.
Django is a web framework. If you're switching to a desktop, you'll have to forego Django.
I would try to replicate the Django application functionality with the PyQt toolkit.
You can in fact embed web content in PyQt applications, with the help of QtWebKit. I would post some potentially useful links, but apparently I have too low a reputation to post more than one :)
There are two places you can go to try to decouple the view and put it into a new desktop app. First you can use the existing controller and model and adapt a new view to that. Second, you can use only the existing model and build a new view and controller.
If you haven't adhered closely enough to the MVC principles that you can detach the model from the rest of the application, you can simply rewrite the entire thing. if you are forced to go this route, bail on django and http entirely (as duffymo suggests above).
You have to also evaluate these solutions based upon performance requirements and "heaviness" of the services. If you have stringent performance requirements then relying on the HTTP layer just gets in the way, and providing a simple API into your model is the way to go.
There are clearly a lot of possibly solutions but this is the approach I would take to deciding what the appropriate one is...
It is possible to convert a django application to a desktop app with pywebview with some line of codes. Frist create a python file gui.py in directory where manage.py exists. install pywebview through pip, the write the code in gui.py
import os
import sys
import time
from threading import Thread
import webview
def start_webview():
window = webview.create_window('Hello world', 'http://localhost:8000/', confirm_close=True, width=900, height=600)
webview.start()
window.closed = os._exit(0)
def start_startdjango():
if sys.platform in ['win32', 'win64']:
os.system("python manage.py runserver {}:{}".format('127.0.0.1', '8000'))
# time.sleep(10)
else:
os.system("python3 manage.py runserver {}:{}".format('127.0.0.1', '8000'))
# time.sleep(10)
if __name__ == '__main__':
Thread(target=start_startdjango).start()
start_webview()
then run gui.py with the command python gui.py. IT will create a window like desktop app
There's a project called Camelot which seems to try to combine Django-like features on the desktop using PyQt. Haven't tried it though.
I am thinking about a similar Problem.
Would it be enough to habe a minimal PyQt Gui that enables you to present the djando-website from localhost (get rid of TCP/HTTPS on loop interface somehow) via QtWebkit?
All you seem to need is to have a minimal Python-Broser, that surfs the build in Webserver (and i guess you could even call Django directly for the html-payload without going over the HTTP/TCP layers).
I have django manage.py runserver in .bat file and a localhost bookmark bar in a browser and whola a django-desktop-app. Or make your own browser that opens localhost. Creating a web-browser with Python and PyQT

Categories