Python Mockito configuration for running test cases - python

I am writing unit tests for a Flask app using unittest and using mockito to mock the services which require the server to be up and running.
However I am unable to figure out how to mock the server. I am getting some error.
Here are the code snippets:
node.py
#app.route('/transaction', methods = ["POST"])
def transaction():
req = request.get_json()
print("\nreq")
i = bitcoin.addTransaction(req)
if req['purpose'] != 'redeem':
users = getColumn(sheet_u,0)
index = users.index(req['recipient'])
user = getRow(sheet_u,index)
hasPoints = int(user[labels_u.index("POINTS")])
hasPoints += req['amount']
setCell(sheet_u, index, labels_u.index("POINTS"), hasPoints)
wb.save("db.xlsx")
else:
users = getColumn(sheet_u,0)
index = users.index(req['sender'])
user = getRow(sheet_u,index)
hasPoints = int(user[labels_u.index("POINTS")])
hasPoints -= req['amount']
setCell(sheet_u, index, labels_u.index("POINTS"), hasPoints)
wb.save("db.xlsx")
r = requests.get(url = bitcoin.currentNodeUrl+"/save")
return jsonify({"note":"New transaction will be added to block "+str(i)})
#app.route('/transaction/broadcast', methods = ["POST"])
def transactionBroadcast():
check = True
failure = ""
req = request.get_json()
# Hiding some methods that change the value of check flag
if check:
newTransaction = bitcoin.createNewTransaction(req['amount'],req['sender'],req['recipient'],req['purpose'],time.time())
bitcoin.addTransaction(newTransaction)
promises = []
for node in bitcoin.networkNodes:
response = ""
try:
r = requests.post(url=node+"/transaction",json=newTransaction) #this line throws error
response = r.text #program control doesn't come here
print(newTransaction)
print("\n")
print(response)
except requests.exceptions.ConnectionError:
response = "{\"note\":\"The node is unavailable. It will sync itself later on.\"}"
if 'note' in json.loads(response):
promises.append(json.loads(response))
if len(promises) == len(bitcoin.networkNodes):
r = requests.get(url = bitcoin.currentNodeUrl+"/save")
return jsonify({"note":"Transaction broadcasted successfully"})
else:
return jsonify({"fail":"Invalid transaction. "+failure})
if __name__ == '__main__':
bitcoin = Blockchain(sys.argv[1])
app.run(port=sys.argv[1])
test_t2.py
from node import app
from flask import json
import unittest
import node
import requests
from mockito import when, mock, unstub
class TestSearch(unittest.TestCase):
print("inside TEST class")
def test_transactionBroadcast(self):
node.bitcoin = node.Blockchain('5000')
response = mock({"note": "New transaction will be added to block 5"})
when(requests).post('http://localhost:5001/transaction', strict = False ).thenReturn(response)
data1 = {
"sender" : "ph1000005",
"recipient" : "TIAA",
"amount" : 1,
"purpose" : "redeem"
}
response = app.test_client().post(
'/transaction/broadcast',
json = data1,
content_type='application/json',
)
print("running TransactionBroadcast test")
print(response)
self.assertEqual(response.get_json(), {
# 'fail': "Invalid transaction. This user doesn't exist. Check userid again."
"note": "Transaction broadcasted successfully"
})
unstub()
if __name__ == '__main__':
unittest.main()
error log
C:\POC>coverage run test_t2.py
inside TEST class
[2018-12-12 19:58:22,181] ERROR in app: Exception on /transaction/broadcast [POST]
Traceback (most recent call last):
File "c:\program files\python36\lib\site-packages\flask\app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "c:\program files\python36\lib\site-packages\flask\app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "c:\program files\python36\lib\site-packages\flask\app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "c:\program files\python36\lib\site-packages\flask\_compat.py", line 35, in reraise
raise value
File "c:\program files\python36\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "c:\program files\python36\lib\site-packages\flask\app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\POC\node.py", line 230, in transactionBroadcast
r = requests.post(url=node+"/transaction",json=newTransaction)
File "c:\program files\python36\lib\site-packages\mockito\mocking.py", line 89, in new_mocked_method
self, method_name, *args, **kwargs)
File "c:\program files\python36\lib\site-packages\mockito\mocking.py", line 44, in remembered_invocation_builder
return invoc(*args, **kwargs)
File "c:\program files\python36\lib\site-packages\mockito\invocation.py", line 103, in __call__
""" % (self, "\n ".join(str(invoc) for invoc in stubbed_invocations)))
mockito.invocation.InvocationError:
You called
post(url='http://localhost:5001/transaction', json={'amount': 1, 'purpose': 'redeem', 'recipient': 'TIAA', 'sender': 'ph1000005', 'timestamp': 1544624902.1440911, 'transactionId': 'd919ffb4080f47e890957f3f3edc97a1'}),
which is not expected. Stubbed invocations are:
post('http://localhost:5001/transaction', strict=False)
(Set strict to False to bypass this check.)
running TransactionBroadcast test
<Response streamed [500 INTERNAL SERVER ERROR]>
F
======================================================================
FAIL: test_transactionBroadcast (__main__.TestSearch)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_t2.py", line 49, in test_transactionBroadcast
"note": "Transaction broadcasted successfully"
AssertionError: None != {'note': 'Transaction broadcasted successfully'}
----------------------------------------------------------------------
Ran 1 test in 0.682s
FAILED (failures=1)
Now, I'm not sure what am I doing wrong. there is an internal route call to /transaction in the route /transaction/broadcast which is failing.
Since this is a unit testing, it doesn't require the server to be up and running. and the route is calling localhost
Any ideas on how to deal with it?

Basically, the stub error message tells you that your stubbing signature
when(requests).post('http://localhost:5001/transaction', strict = False ).thenReturn(response)
is wrong.
Note 1: when using strict it must go into when like so: when(requests, strict=False). But not being strict is usually not what you want.
Instead you fix your stubbing, e.g.:
when(requests).post(url='http://localhost:5001/transaction', ...).thenReturn(response)
# or for python2
from mockito import kwargs
when(requests).post(url='http://localhost:5001/transaction', **kwargs).thenReturn(response)

Related

Python Flask TypeError: Object of type NoSectionError is not JSON serializable

I'm developing an application with python and Flask to automate sending emails.
When I run this application locally, there is no problem, but after deploying the application in Azure, this error appears
TypeError: Object of type NoSectionError is not JSON serializable
The function that is bursting the error is this, when I try to return the dictionary variable
#app.route('/send_email', methods=['POST'])
def get_parameters():
"""
It receives a JSON object, prints it, and then calls another function that sends an email
:return: The result of the function send_email_to_customer
"""
user_input = request.json
print("Conteudo ", user_input)
try:
user = get_config_data(iten_title='EMAIL_LOGIN', iten='email')
psw = get_config_data(iten_title='EMAIL_LOGIN', iten='password')
id_meeting = user_input['id']
list_of_recipients = user_input['recipients']
creator_name = user_input['creator_name']
date_list = user_input['meeting_day']
subject = f'Melhor data para a reuniao {id_meeting}'
url = "https://easy-meeting.azurewebsites.net/external_url?meeting_day="+",".join(date_list)
email_server = create_email_server(user, psw)
for recipients_dict in list_of_recipients:
email_msg = create_email_body(user, recipients_dict, creator_name, subject, url)
run(email_server, email_msg)
dictionary = {"Status":"Sucesso ao enviar o email"}
except Exception as email_error:
dictionary = {"Status":"Erro ao enviar o email", "Error Message": email_error}
print(email_error)
dictionary = jsonify(dictionary)
return dictionary
full error code
2022-11-26T02:26:55.182403211Z [2022-11-26 02:26:55,162] ERROR in app: Exception on /send_email [POST]
2022-11-26T02:26:55.182438711Z Traceback (most recent call last):
2022-11-26T02:26:55.182445810Z File "/tmp/8dacf551bd5f657/antenv/lib/python3.10/site-packages/flask/app.py", line 2525, in wsgi_app
2022-11-26T02:26:55.182480710Z response = self.full_dispatch_request()
2022-11-26T02:26:55.182501610Z File "/tmp/8dacf551bd5f657/antenv/lib/python3.10/site-packages/flask/app.py", line 1822, in full_dispatch_request
2022-11-26T02:26:55.182505610Z rv = self.handle_user_exception(e)
2022-11-26T02:26:55.182509810Z File "/tmp/8dacf551bd5f657/antenv/lib/python3.10/site-packages/flask/app.py", line 1820, in full_dispatch_request
2022-11-26T02:26:55.182513410Z rv = self.dispatch_request()
2022-11-26T02:26:55.182516910Z File "/tmp/8dacf551bd5f657/antenv/lib/python3.10/site-packages/flask/app.py", line 1796, in dispatch_request
2022-11-26T02:26:55.182520410Z return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
2022-11-26T02:26:55.182524010Z File "/tmp/8dacf551bd5f657/api_run.py", line 55, in get_parameters
2022-11-26T02:26:55.182527510Z dictionary = jsonify(dictionary)
2022-11-26T02:26:55.182531010Z File "/tmp/8dacf551bd5f657/antenv/lib/python3.10/site-packages/flask/json/__init__.py", line 342, in jsonify
2022-11-26T02:26:55.182534510Z return current_app.json.response(*args, **kwargs)
2022-11-26T02:26:55.182538010Z File "/tmp/8dacf551bd5f657/antenv/lib/python3.10/site-packages/flask/json/provider.py", line 309, in response
2022-11-26T02:26:55.182541510Z f"{self.dumps(obj, **dump_args)}\n", mimetype=mimetype
2022-11-26T02:26:55.182545110Z File "/tmp/8dacf551bd5f657/antenv/lib/python3.10/site-packages/flask/json/provider.py", line 230, in dumps
2022-11-26T02:26:55.182548610Z return json.dumps(obj, **kwargs)
2022-11-26T02:26:55.182551910Z File "/opt/python/3.10.4/lib/python3.10/json/__init__.py", line 238, in dumps
2022-11-26T02:26:55.182555410Z **kw).encode(obj)
2022-11-26T02:26:55.182558710Z File "/opt/python/3.10.4/lib/python3.10/json/encoder.py", line 199, in encode
2022-11-26T02:26:55.182562210Z chunks = self.iterencode(o, _one_shot=True)
2022-11-26T02:26:55.182565610Z File "/opt/python/3.10.4/lib/python3.10/json/encoder.py", line 257, in iterencode
2022-11-26T02:26:55.182569210Z return _iterencode(o, 0)
2022-11-26T02:26:55.182572510Z File "/tmp/8dacf551bd5f657/antenv/lib/python3.10/site-packages/flask/json/provider.py", line 122, in _default
2022-11-26T02:26:55.182576010Z raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable")
2022-11-26T02:26:55.182579609Z TypeEr
I already tried to add the jsonify flask function, but it didn't work
The goal is to make the dictionary variable just like local
enter image description here

Locust with Python: No Locust Stats are showing on UI

I am new to Locust (and Python) and am trying to load test an API. My Locust UI shows no stats whatsoever - no users hatched, no API calls, etc. I need help figuring out how to get them to show up on the UI so I can get the stats.
Here is my locust.py file:
from locust import HttpUser, SequentialTaskSet, task, constant
import finops_service.locust_files.finops_fx_load_testing as load_test
class FXTransaction(SequentialTaskSet):
def __init__(self, parent):
super().__init__(parent)
self.comp_data = dict()
self.rate_lock_response = dict()
self.transaction_response = dict()
self.fx_providerID = '57638f08-e938-48d7-accf-325b6728a9ee'
self.headers = {"Content-Type": "application/json"}
def on_start(self):
load_test.login(self),
#task
def get_company_data(self):
# Get company data
self.comp_data = load_test.get_company_data(self)
print("Company is: ", self.comp_data['company'])
print("Vendor is: ", self.comp_data['vendor'])
print("Payment Method is: ", self.comp_data['payment_method'])
print("Funding Method is: ", self.comp_data['funding_method'])
# #task
# def rate_lock(self):
print("Starting rate lock")
load_test.rate_lock(self)
print("This is the returned rate lock response:")
print(self.rate_lock_response)
# #task
# def approve_transaction(self):
# print("Starting transaction")
# load_test.approve_transaction(self)
# print("This is the returned transaction response:")
# print(self.transaction_response)
class MyUser(HttpUser):
wait_time = constant(1)
# weight = 1
host = "http://localhost:8080/PaymentService/base/"
tasks = [FXTransaction]
And here are my functions:
import json
import random
import uuid
from utils import json_util as json_util
enter code here
def login(self):
try:
with self.client.post(
"security/login",
headers={'Content-Type': 'application/json',
'Authorization': 'BASIC 0ee89b88-5c4b-4922-b1f9-c1584ab26e7e:12345'},
name=login,
timeout=55.6,
catch_response=True) as response:
if response.status_code != 200:
response.failure("Login failed")
else:
response.success()
print("Login succeeded")
self.headers.update({'if-Match': "{}".format(response.headers["ETag"])})
except ConnectionRefusedError:
print("The test could not connect to {}".format("http://localhost:8080/PaymentService/security/login"))
raise
def get_company_data(self):
comp_index = random.randrange(0, 9)
print("Random company data index is: ", comp_index)
try:
body = json.load(open("finops_service/locust_files/load_testing_data.json", 'r'))
comp_data = body['fx']['multipleCompanies_10']['company_data'][comp_index]
except ConnectionRefusedError:
print("The test could not connect to {}".format("http://localhost:8080/PaymentService/security/login"))
raise
return comp_data
def rate_lock(self):
body = json_util.get_json_object(
"/finops_service/locust_files/rate_lock_load_testing.json",
'fx'.lower(),
'valid_multiple_20'.lower()
)
body["debtorCompanyProfileId"] = self.comp_data['company']
i = 0
# there are 20 rate locks so need to update each request
while i < 20:
body["rateRequestPayments"][i]["creditorProfileId"] = self.comp_data['vendor']
body["rateRequestPayments"][i]["debtorProfileId"] = self.comp_data['company']
body["rateRequestPayments"][i]["paymentMethodId"] = self.comp_data['payment_method']
random_float_no = round(random.uniform(1.11, 999.99), 2)
body['rateRequestPayments'][i]['amount'] = random_float_no
i += 1
try:
print("RIGHT BEFORE RATE LOCK CALL")
with self.client.post("services/transaction/fx/rate/lock",
data=json.dumps(body),
headers=self.headers,
name="rate lock",
timeout=55.6,
catch_response=True) as response:
if "GENERIC_FAILURE" in response.text:
response.failure("FAIL")
print("Rate lock call failed")
else:
response.success()
print("rate lock succeeded")
print("Rate lock response is:.........", response)
print("Rate lock response TEXT is:.........", response.text)
self.rate_lock_response = response.text
except ConnectionRefusedError:
print("The test could not connect to {}".format(
"http://localhost:8080/PaymentService/services/transaction/fx/rate/lock"))
raise
When I run this, I can see that the self.client.post("services/transaction/fx/rate/lock"... is happening and either succeeding or failing. However, in the Locust UI, I show 0 users hatched (console shows I hatched 5) and 0 tasks shown.
I get this error each time I run which it looks related to my stats not showing up but I don't know why it is happening:
Traceback (most recent call last):
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/gevent/pywsgi.py", line 999, in handle_one_response
self.run_application()
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/gevent/pywsgi.py", line 945, in run_application
self.result = self.application(self.environ, self.start_response)
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 2464, in __call__
return self.wsgi_app(environ, start_response)
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 2450, in wsgi_app
response = self.handle_exception(e)
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 1867, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/locust/web.py", line 319, in wrapper
return view_func(*args, **kwargs)
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/locust/util/cache.py", line 21, in wrapper
cache["result"] = func(*args, **kwargs)
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/locust/web.py", line 208, in request_stats
"safe_name": escape(s.name, quote=False),
File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/html/__init__.py", line 19, in escape
s = s.replace("&", "&") # Must be done first!
AttributeError: 'function' object has no attribute 'replace'
2021-03-18T16:44:29Z {'REMOTE_ADDR': '::1', 'REMOTE_PORT': '49242', 'HTTP_HOST': 'localhost:8089', (hidden keys: 25)} failed with AttributeError
Can someone please help me figure out how to make my stats show up?
Thank you!!!!
The stats not showing up in Locust is because of that Exception you posted. If you resolve that and get to where your code runs without issues, you should see stats in the Locust UI.
There are a number of issues with your code.
I'm not sure if it's just an issue with pasting your code into SO, but your on_start() and get_company_data() functions (and the #task decorator) need to be indented so they're part of FXTransaction.
Also, trying to use self.client in login() or get_company_data() isn't going to work because they aren't part of a class so there's no such thing as self. You'd probably want to change self in that function to just client and then pass in self.client when you call it from the on_start() function.
But what's possibly your main issue is here:
with self.client.post(
"security/login",
headers={'Content-Type': 'application/json',
'Authorization': 'BASIC 0ee89b88-5c4b-4922-b1f9-c1584ab26e7e:12345'},
name=login,
…
name here is the name of the endpoint (URL) you're hitting. This is supposed to be a string but you're giving it your function login. So when the Locust code tries to do some thing with your name value that it wants to do, expecting it to be a string, it's going to fail because it's trying to do those on a function instead. That's what AttributeError: 'function' object has no attribute 'replace' means.
I think if you fix all of those things, Locust should work.

How would I be able to connect to SQLAlchemy python to a server.py file

What I want to do is have a file called server.py that has the SQLAlchemy database in it and a web server file called webServer.py that has all the redirecting and button click events in it. I don't know how to connect the two. The database works when the server.py code in inside the webServer.py file, I have all the imports, just in case anyone needs the code, here it is:
webServer.py
from flask import Flask, render_template
from flask import redirect, url_for, request, session
from server import *
web_server = Flask(__name__)
web_server.secret_key = "SecretKey"
""" ROUTING """
#web_server.route("/")
#web_server.route("/home")
def index():
return render_template("index.html")
#web_server.route("/sign-in", methods=["POST", "GET"])
def signIn():
if request.method == "POST":
uip = request.form["UIP"]
pip = request.form["PIP"]
# START PF DATABASE TESTING
isAcct = checkForAccount(uip)
if isAcct:
isCorrect = checkUser(uip, pip)
if isCorrect:
print("CORRECT")
return redirect(url_for("index"))
else:
print("FALSE")
return render_template("signIn.html", incorrectPass="Wrong username or password.")
else:
createAccount(uip, pip)
return render_template("signIn.html")
# END OF DATABASE TESTING
else:
return render_template("signIn.html")
#web_server.route("/run<data>")
def run(data):
check = checkUser()
if check:
print(data)
return "none"
""" ERROR HANDLING """
#web_server.errorhandler(404)
def error404(error):
return render_template("error.html", EC="Error! Page Not Found!"), 404
#web_server.errorhandler(500)
def error500(error):
return render_template("error.html", EC="Error! Internal Server Issue!"), 500
print("Server Loaded..")
if __name__ == "__main__":
db.create_all()
# server.run(host="192.168.1.80", port="3000") #For running on IP address
web_server.run(port="3000")
server.py
from webServer import web_server
from flask_sqlalchemy import SQLAlchemy
web_server.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///dataBase.sqlite3"
web_server.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(web_server)
class dataBase(db.Model):
#_id = db.Column(db.Integer, primary_key=True)
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(100), unique=True, nullable=False)
password = db.Column(db.String(100), nullable=False)
def __init__(self, username, password):
self.username = username
self.password = password
def checkUser(username, password):
usernameQuery = dataBase.query.filter_by(username=username).first()
correctUser = usernameQuery.username
correctPass = usernameQuery.password
if username == correctUser and password == correctPass:
return True
else:
return False
def checkForAccount(uip):
found_user = dataBase.query.filter_by(username=uip).first()
return found_user
def createAccount(uip, pip):
accountStartupData = dataBase(uip, pip)
db.session.add(accountStartupData)
db.session.commit()
And here is the error:
[2020-05-18 17:59:48,172] ERROR in app: Exception on /sign-in [POST]
Traceback (most recent call last): File
"C:\Users\callu\Documents\Javo\venv\lib\site-packages\sqlalchemy\util_collections.py",
line 1020, in call
return self.registry[key] KeyError: 15864
During handling of the above exception, another exception occurred:
Traceback (most recent call last): File
"C:\Users\callu\Documents\Javo\venv\lib\site-packages\flask\app.py",
line 2447, in wsgi_app
response = self.full_dispatch_request() File "C:\Users\callu\Documents\Javo\venv\lib\site-packages\flask\app.py",
line 1952, in full_dispatch_request
rv = self.handle_user_exception(e) File "C:\Users\callu\Documents\Javo\venv\lib\site-packages\flask\app.py",
line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb) File "C:\Users\callu\Documents\Javo\venv\lib\site-packages\flask_compat.py",
line 39, in reraise
raise value File "C:\Users\callu\Documents\Javo\venv\lib\site-packages\flask\app.py",
line 1950, in full_dispatch_request
rv = self.dispatch_request() File "C:\Users\callu\Documents\Javo\venv\lib\site-packages\flask\app.py",
line 1936, in dispatch_request
return self.view_functionsrule.endpoint File "C:/Users/callu/Documents/Javo/webServer.py", line 25, in signIn
isAcct = checkForAccount(uip) File "C:\Users\callu\Documents\Javo\server.py", line 30, in checkForAccount
found_user = dataBase.query.filter_by(username=uip).first() File "C:\Users\callu\Documents\Javo\venv\lib\site-packages\flask_sqlalchemy__init__.py",
line 519, in get
return type.query_class(mapper, session=self.sa.session()) File "C:\Users\callu\Documents\Javo\venv\lib\site-packages\sqlalchemy\orm\scoping.py",
line 78, in call
return self.registry() File "C:\Users\callu\Documents\Javo\venv\lib\site-packages\sqlalchemy\util_collections.py",
line 1022, in call
return self.registry.setdefault(key, self.createfunc()) File "C:\Users\callu\Documents\Javo\venv\lib\site-packages\sqlalchemy\orm\session.py",
line 3286, in call
return self.class_(**local_kw) File "C:\Users\callu\Documents\Javo\venv\lib\site-packages\flask_sqlalchemy__init__.py",
line 137, in init
track_modifications = app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] KeyError: 'SQLALCHEMY_TRACK_MODIFICATIONS'

Unserializable value

I'm currently stuck with a serialization problem. The data seems ok in Nameko but not in Flask because an error occurred. I tried to serialise and unserialize, but it didn't work.
Here is an example of data from a MongoDB database :
{u'building': u'urk', u'idcapteur': 8, u'room': u'tyu', u'idpiece': 1, u'uri': u'urk/tyu/luminosity/yota1', u'idMesure': 458945, u'subId': u'yota1', u'datemesure2': datetime.datetime(2017, 6, 16, 12, 48, 19, 179000), u'datemesure': datetime.datetime(2017, 6, 16, 12, 48, 19, 179000), u'device': u'luminosity', u'_id': ObjectId('7825ahy'), u'data': {u'date': u'2017-06-16T14:48:19.179435', u'payload': {u'subID': u'yota1', u'input': 50, u'value_units': u'lux', u'value': 500, u'unitID': u'inside'}, u'uri': u'urk/tyu/luminosity/yota1'}, u'mesurevaleur': [{u'idlibv': 5, u'valeur': 500.0}]}
Here is my Nameko program :
# -*-coding:utf-8 -*
# neocampus.py
import json
from database import startMongoDbConnection, getRawDataCollection, mongoDbQuery
from nameko.rpc import rpc
#from database.py import startMongoDbConnection, getRawDataCollection, mongoDbQuery
mdbConnection = ''
mdbCollection = ''
# Send a request to the microservices system. It will call other microservices
class MsRequest:
name="msRequest"
# TODO
#rpc
def msRequest(self, value):
# Connect to MongoDB database and collection, if not already done
global mdbConnection, mdbCollection, queryResult
if mdbConnection == '':
mdbConnection = startMongoDbConnection()
if mdbCollection == '':
mdbCollection = getRawDataCollection(mdbConnection)
# Check the requested microservice
someData = GetData()
jsonData = someData.getData(value)
# It prints the proper data
for document in jsonData:
print(document)
print("FINISHED !!!")
# Don't forget : closeMongoDbConnection()
return jsonData
# Get data depending on sensor type
class GetData:
name="getData"
def getData(self, sensorType):
global mdbCollection
queryResult = mongoDbQuery(mdbCollection, "device", "$eq", sensorType)
return queryResult
# From database.py
def mongoDbQuery(someCollection, key, choice, value):
# Use MongoDB query dependeing on choices in parameters
docs = someCollection.find({key:{choice:value}}).limit(10)
#for document in docs:
#print(document)
return docs
# Start a MongoDB connection
def startMongoDbConnection():
connected = connectToMongoDb("mongodb")
return connected
# Start a MongoDB connection
def startMongoDbConnection():
connected = connectToMongoDb("mongodb")
return connected
# Choose the first collection available (for raw data)
def getRawDataCollection(connection):
currentCollection = chooseCollection(connection, mongollection)
return currentCollection
And now, my Flask program :
#app.route('/', methods=['GET', 'POST'])
def getData():
with ClusterRpcProxy(CONFIG) as rpc:
myData = rpc.msRequest.msRequest("luminosity")
#for document in myData:
#print myData
return flask.jsonify(**myData)
Finally, the error output :
ERROR in app: Exception on / [GET]
Traceback (most recent call last):
File "/home/oyo/.local/lib/python2.7/site-packages/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/home/oyo/.local/lib/python2.7/site-packages/flask/app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/oyo/.local/lib/python2.7/site-packages/flask/app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/oyo/.local/lib/python2.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "/home/oyo/.local/lib/python2.7/site-packages/flask/app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/oyo/flask_sandfox/sandfox.py", line 16, in getData
myData = rpc.msRequest.msRequest("luminosity")
File "/home/oyo/.local/lib/python2.7/site-packages/nameko/rpc.py", line 369, in __call__
return reply.result()
File "/home/oyo/.local/lib/python2.7/site-packages/nameko/rpc.py", line 327, in result
raise deserialize(error)
RemoteError: UnserializableValueError Unserializable value: `<pymongo.cursor.Cursor object at 0x7f3274612e50>`
With a print, data is correctly displayed in the terminal. But not in Flask, I get an error 500. I thought that with JSON data and Jsonify (found here, in this site), I could display something. But it's not the cas.
Any help, advice or hint would be gladly appreciated. Thank you.
For people who'll have this exact problem, it took me 5 days to find it. I was sure it was in JSON, because, when I copied/pasted the result, it was ok. In fact, it was in BSON (I didn't even know this format). So, just add this at the beginning of your file :
from bson.json_util import dumps
Then, add this :
# limit for the example
retrievedocs = someCollection.find({* something *}}, {'_id': 0}).limit(10)
docs = dumps(retrievedocs)
Then, the serialization between Nameko and Flask will work.

Cannot pass the form data to a method in order to validate form

I'm trying to create a custom validator for one field in the AddSongForm. I used the inline validator and it uses two methods from my Songs class. When I try running the code, I get the following trace back:
form = AddSongForm()
[2017-05-16 13:44:11,547] ERROR in app: Exception on /addsong [POST]
Traceback (most recent call last):
File "C:\Python36-32\lib\site-packages\flask\app.py", line 1982, in wsgi_app
response = self.full_dispatch_request()
File "C:\Python36-32\lib\site-packages\flask\app.py", line 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Python36-32\lib\site-packages\flask\app.py", line 1517, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\Python36-32\lib\site-packages\flask\_compat.py", line 33, in reraise
raise value
File "C:\Python36-32\lib\site-packages\flask\app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Python36-32\lib\site-packages\flask\app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Python36-32\lib\site-packages\flask_login\utils.py", line 228, in decorated_view
return func(*args, **kwargs)
File "C:/Users/Pellissari/Desktop/files/projects/Musical 9gag/view.py", line 40, in addsong
if form.validate_on_submit():
File "C:\Python36-32\lib\site-packages\flask_wtf\form.py", line 101, in validate_on_submit
return self.is_submitted() and self.validate()
File "C:\Python36-32\lib\site-packages\wtforms\form.py", line 310, in validate
return super(Form, self).validate(extra)
File "C:\Python36-32\lib\site-packages\wtforms\form.py", line 152, in validate
if not field.validate(self, extra):
File "C:\Python36-32\lib\site-packages\wtforms\fields\core.py", line 204, in validate
stop_validation = self._run_validation_chain(form, chain)
File "C:\Python36-32\lib\site-packages\wtforms\fields\core.py", line 224, in _run_validation_chain
validator(form, self)
File "C:\Users\Pellissari\Desktop\files\projects\app\forms.py", line 20, in validate_song_link
if Songs.get_provider(url) in valid_providers:
TypeError: get_provider() missing 1 required positional argument: 'url'
127.0.0.1 - - [16/May/2017 13:44:11] "POST /addsong HTTP/1.1" 500 -
This is my form class
class AddSongForm(Form):
song_title = StringField('song_title', validators=[DataRequired()])
song_artist = StringField('song_artist', validators=[DataRequired()])
song_genre = StringField('song_genre')
song_link = StringField('song_link', validators=[DataRequired()])
def validate_song_link(form, song_link):
valid_providers = ['youtube.com', 'www.youtube.com', 'soundcloud.com', 'www.soundcloud.com']
url = song_link.data
if Songs.get_provider(url) in valid_providers:
if Songs.get_embed_code(url) is not False:
return True
else:
print("couldn't get your content")
return False
else:
print("unsupported provider")
return False
And here is the class I used the methods
class Songs(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
title = db.Column(db.String(50))
artist = db.Column(db.String(30))
genre = db.Column(db.String(40))
author = db.Column(db.String(40))
timestamp = db.Column(db.DateTime)
likes_num = db.Column(db.Integer)
song_link = db.Column(db.String(120))
def get_provider(self, url):
return urllib.parse.urlsplit(url)[1]
def get_embed_code(self, url):
code = None
vars = {'url': url, 'format': 'json', 'iframe': 'true', 'maxwidth': '450', 'show_comments': 'false'}
provider = self.get_provider(url)
endpoint = "http://"+provider+"/oembed?"
source = endpoint+urllib.parse.urlencode(vars)
try:
request = urlopen(source)
code = json.load(request)['html']
return code
except:
print("impossible to get your content. Check the link")
return False
I'm quite new with Python and this is my first time writing OO code, so I have no idea what could be happening here. Besides the problem, I would be happy if you also could give me some feedback on the code and if there are room to improve in some sense.
I'm not convinced these should be methods on Songs. They don't refer to anything to do with the Song class.
However if you want to keep them as methods, but still want to call them from the class, they need to be classmethods, not instance methods.
#classmethod
def get_provider(cls, url):
return urllib.parse.urlsplit(url)[1]
#classmethod
def get_embed_code(cls, url):
...
provider = cls.get_provider(url)
First of all correct the indentation for the method validate_song_link. It should be like this:
def validate_song_link(form, song_link):
valid_providers = ['youtube.com', 'www.youtube.com', 'soundcloud.com', 'www.soundcloud.com']
url = song_link.data
if Songs.get_provider(url) in valid_providers:
if Songs.get_embed_code(url) is not False:
return True
else:
print("couldn't get your content")
return False
else:
print("unsupported provider")
return False
To solve your problem you can try to change the get_provider method to a class method like this:
#classmethod
def get_provider(cls, url):
return urllib.parse.urlsplit(url)[1]
And then you can call this way:
songs = Songs()
if Songs.get_provider(songs, url) in valid_providers:
if Songs.get_embed_code(url) is not False:
return True

Categories

Resources