How do you unit test a file post with webapp2? - python

I am unit testing a webapp2 application and would like to write a test that simulates a file post. How can I create a request object in my unit test that contains the simulated contents of a file?
import unittest
import webapp2
import main
file_contents = """id, first, last
1, Bruce, Banner
2, Tony, Stark
"""
class TestHandlers(unittest.TestCase):
def test_hello(self):
request = webapp2.Request.blank('/')
request.method = 'POST'
# Magic needed here.
#Put file_contents into a form parameter
response = request.get_response(main.app)
#Test that the returned text contains something from the posted file
self.assertEqual(True, "Bruce" in response.body)

Looks to me like the blank method includes a named POST parameter. It says in the docs http://webapp-improved.appspot.com/guide/testing.html#request-blank that by using it, the request method is automatically set to POST and the CONTENT_TYPE is set to ‘application/x-www-form-urlencoded’.
So in the above it could just be:
post_contents = {'someVar':file_contents}
request = webapp2.Request.blank('/', POST=post_contents)
response = request.get_response(main.app)

Related

How to write unit testing script using unittest

I want to write a unit test cases using unittest where my input is set of images and output is set of images with boundary box in the text, also it generate co-ordinate of the boundary boxes. How can I write test script for that using unittest pyunit framework.
So I have written unittest script to test api is working or not, response should be json / and list format and response of image file format should be png,jpg format, which is working now. I have below test case scenario need to test but how I will check? I don't know.
If optional keys are not passed to API, it should not throw an error. (opposite for compulsory ones) 8) The implemented route should throw/return error if GET request is passed instead of POST. 9) If valid path but invalid file name is provided, you should see respective error. 10) In case of invalid path, you should see respective error message. 11) There is specified set of keys which are compulsory to be passed to APIs, if not it returns an error 12) verify for session time out.
Here is my code:
import requests
import json
import sshtunnel
import unittest
class TestSequentialExecutions(unittest.TestCase):
def setUp(self) -> None:
a=10
def test_API(self):
self.resp_list = []
# API url
url = ['dummy url','dummyurl']
# Additional headers.
headers = {'Content-Type': 'application/json'}
# Body
payload = [{'input': 'dummy path'},
{"path": "dummy"}]
# Test case-1 checking valid API is routed or not
# convert dict to json by json.dumps() for body data.
for i in range(len(url)):
resp = requests.post(url[i], headers=headers, data=json.dumps(payload[i], indent=4))
self.assertEqual(resp.status_code, 200)
self.resp_list.append(resp.json())
#Test case-2 to check input file is in JPG ,PNG format or not
def test_fileformat(self):
n = len(self.resp_list[1])
my_list = [1]*n
empty_list=[]
extensions = ['png','v']
for filename in self.resp_list[0]:
if filename.lower().endswith(('.png', '.jpg')):
empty_list.append(1)
else:
empty_list.append(0)
self.assertEqual(my,empy_list)
if __name__ == '__main__':
unittest.main()
Actually I am trying to write test script for below github code: https://github.com/eragonruan/text-detection-ctpn

Flask: How to use url_for() outside the app context?

I'm writing a script to collect the emails of those users that didn't receive an email confirmation email and resend it to them. The script works obviously outside of flask app context. I would like to use url_for() but can't get it right.
def resend(self, csv_path):
self.ctx.push()
with open(csv_path) as csv_file:
csv_reader = csv.reader(csv_file)
for row in csv_reader:
email = row[0]
url_token = AccountAdmin.generate_confirmation_token(email)
confirm_url = url_for('confirm_email', token=url_token, _external=True)
...
self.ctx.pop()
The first thing I had to do was to set SERVER_NAME in config. But then I get this error message:
werkzeug.routing.BuildError: Could not build url for endpoint
'confirm_email' with values ['token']. Did you mean 'static' instead?
This is how it's defined, but I don't think it can even find this, because it's not registered when ran as script:
app.add_url_rule('/v5/confirm_email/<token>', view_func=ConfirmEmailV5.as_view('confirm_email'))
Is there a way to salvage url_for() or do I have to build my own url?
Thanks
It is much easier and proper to get the URL from the application context.
You can either import the application and manually push context with app_context
https://flask.palletsprojects.com/en/2.0.x/appcontext/#manually-push-a-context
from flask import url_for
from whereyoudefineapp import application
application.config['SERVER_NAME'] = 'example.org'
with application.app_context():
url_for('yourblueprint.yourpage')
Or you can redefine your application and register the wanted blueprint.
from flask import Flask, url_for
from whereyoudefineyourblueprint import myblueprint
application = Flask(__name__)
application.config['SERVER_NAME'] = 'example.org'
application.register_blueprint(myblueprint)
with application.app_context():
url_for('myblueprint.mypage')
We can also imagine different ways to do it without the application, but I don't see any adequate / proper solution.
Despite everything, I will still suggest this dirty solution.
Let's say you have the following blueprint with the following routes inside routes.py.
from flask import Blueprint
frontend = Blueprint('frontend', __name__)
#frontend.route('/mypage')
def mypage():
return 'Hello'
#frontend.route('/some/other/page')
def someotherpage():
return 'Hi'
#frontend.route('/wow/<a>')
def wow(a):
return f'Hi {a}'
You could use the library inspect to get the source code and then parse it in order to build the URL.
import inspect
import re
BASE_URL = "https://example.org"
class FailToGetUrlException(Exception):
pass
def get_url(function, complete_url=True):
source = inspect.getsource(function)
lines = source.split("\n")
for line in lines:
r = re.match(r'^\#[a-zA-Z]+\.route\((["\'])([^\'"]+)\1', line)
if r:
if complete_url:
return BASE_URL + r.group(2)
else:
return r.group(2)
raise FailToGetUrlException
from routes import *
print(get_url(mypage))
print(get_url(someotherpage))
print(get_url(wow).replace('<a>', '456'))
Output:
https://example.org/mypage
https://example.org/some/other/page
https://example.org/wow/456

send data to html dashboard in python flask while having dictionary in a function parameter

I want to send data to html in flask framework, i have a function which receives dictionary as a parameter, then there are several functions applied on dictionary. after that final result i want to render in to html page. Its been 48 hours i am trying from different blogs but didn't get precise solution.
imports ...
from other file import other_functions
from other file import other_functions_2
from other file import other_functions_3
app = Flask(__name__, template_folder='templates/')
#app.route("/dashboard")
def calculate_full_eva_web(input:dict):
calculate_gap = other_functions(input)
calculate_matrix = other_functions_2(input)
average = other_functions_3(input)
data = dict{'calculate_gap':calculate_gap, 'calculate_matrix':calculate_matrix,'average':average}
return render_template('pages/dashboard.html', data = data)
if __name__ == "__main__":
app.run(debug=True)
TRACEBACK
Methods that Flask can route to don't take dictionaries as inputs, and the arguments they do take need to be matches by a pattern in the route. (See https://flask.palletsprojects.com/en/1.1.x/api/#url-route-registrations)
You'd get the same error if you changed
#app.route("/dashboard")
def calculate_full_eva_web(input:dict):
to
#app.route("/dashboard")
def calculate_full_eva_web(input):
Your path forward depends on how you want to pass data when you make the request. You can pass key/value pairs via URL parameters and retrieve them via the request.args object. That might be close enough to what you want. (You'll need to remove the argument declaration from calculate_full_eva_web())
Something like
from flask import request
#app.route('/dashboard')
def calculate_full_eva_web():
input = request.args
...

Optimise python function fetching multi-level json attributes

I have a 3 level json file. I am fetching the values of some of the attributes from each of the 3 levels of json. At the moment, the execution time of my code is pathetic as it is taking about 2-3 minutes to get the results on my web page. I will be having a much larger json file to deal with in production.
I am new to python and flask and haven't done much of web programming. Please suggest me ways I could optimise my below code! Thanks for help, much appreciated.
import json
import urllib2
import flask
from flask import request
def Backend():
url = 'http://localhost:8080/surveillance/api/v1/cameras/'
response = urllib2.urlopen(url).read()
response = json.loads(response)
components = list(response['children'])
urlComponentChild = []
for component in components:
urlComponent = str(url + component + '/')
responseChild = urllib2.urlopen(urlComponent).read()
responseChild = json.loads(responseChild)
camID = str(responseChild['id'])
camName = str(responseChild['name'])
compChildren = responseChild['children']
compChildrenName = list(compChildren)
for compChild in compChildrenName:
href = str(compChildren[compChild]['href'])
ID = str(compChildren[compChild]['id'])
urlComponentChild.append([href,ID])
myList = []
for each in urlComponentChild:
response = urllib2.urlopen(each[0]).read()
response = json.loads(response)
url = each[0] + '/recorder'
responseRecorder = urllib2.urlopen(url).read()
responseRecorder = json.loads(responseRecorder)
username = str(response['subItems']['surveillance:config']['properties']['username'])
password = str(response['subItems']['surveillance:config']['properties']['password'])
manufacturer = str(response['properties']['Manufacturer'])
model = str(response['properties']['Model'])
status = responseRecorder['recording']
myList.append([each[1],username,password,manufacturer,model,status])
return myList
APP = flask.Flask(__name__)
#APP.route('/', methods=['GET', 'POST'])
def index():
""" Displays the index page accessible at '/'
"""
if request.method == 'GET':
return flask.render_template('index.html', response = Backend())
if __name__ == '__main__':
APP.debug=True
APP.run(port=62000)
Ok, caching. So what we're going to do is start returning values to the user instantly based on data we already have, rather than generating new data every time. This means that the user might get slightly less up to date data than is theoretically possible to get, but it means that the data they do receive they receive as quickly as is possible given the system you're using.
So we'll keep your backend function as it is. Like I said, you could certainly speed it up with multithreading (If you're still interested in that, the 10 second version is that I would use grequests to asynchronously get data from a list of urls).
But, rather than call it in response to the user every time a user requests data, we'll just call it routinely every once in a while. This is almost certainly something you'd want to do eventually anyway, because it means you don't have to generate brand new data for each user, which is extremely wasteful. We'll just keep some data on hand in a variable, update that variable as often as we can, and return whatever's in that variable every time we get a new request.
from threading import Thread
from time import sleep
data = None
def Backend():
.....
def main_loop():
while True:
sleep(LOOP_DELAY_TIME_SECONDS)
global data
data = Backend()
APP = flask.Flask(__name__)
#APP.route('/', methods=['GET', 'POST'])
def index():
""" Displays the index page accessible at '/'
"""
if request.method == 'GET':
# Return whatever data we currently have cached
return flask.render_template('index.html', response = data)
if __name__ == '__main__':
data = Backend() # Need to make sure we grab data before we start the server so we never return None to the user
Thread(target=main_loop).start() #Loop and grab new data at every loop
APP.debug=True
APP.run(port=62000)
DISCLAIMER: I've used Flask and threading before for a few projects, but I am by no means an expert on it or web development, at all. Test this code before using it for anything important (or better yet, find someone who knows that they're doing before using it for anything important)
Edit: data will have to be a global, sorry about that - hence the disclaimer

How can I test "uploading a file" using Tornado unit tests?

I'm want to test my web service (built on Tornado) using tornado.testing.AsyncHTTPTestCase. It says here that using POST for AsyncHttpClients should look like the following.
from tornado.testing import AsyncHTTPTestCase
from urllib import urlencode
class ApplicationTestCase(AsyncHTTPTestCase):
def get_app(self):
return app.Application()
def test_file_uploading(self):
url = '/'
filepath = 'uploading_file.zip' # Binary file
data = ??????? # Read from "filepath" and put the generated something into "data"
self.http_client.fetch(self.get_url(url),
self.stop,
method="POST",
data=urlencode(data))
response = self.wait()
self.assertEqual(response.code, 302) # Do assertion
if __name__ == '__main__':
unittest.main()
The problem is that I've no idea what to write at ???????. Are there any utility functions built in Tornado, or is it better to use alternative libraries like Requests?
P.S.
... actually, I've tried using Requests, but my test stopped working because probably I didn't do good for asynchronous tasking
def test_file_uploading(self):
url = '/'
filepath = 'uploading_file.zip' # Binary file
files = {'file':open(filepath,'rb')}
r = requests.post(self.get_url(url),files=files) # Freezes here
self.assertEqual(response.code, 302) # Do assertion
You need to construct a multipart/form-data request body. This is officially defined in the HTML spec. Tornado does not currently have any helper functions for generating a multipart body. However, you can use the MultipartEncoder class from the requests_toolbelt package. Just use the to_string() method instead of passing the encoder object directly to fetch().

Categories

Resources