I'm trying to patch a testing framework built in python for javascript called mootools-test-runner (i'm a front end developer by day, so my python skills are pretty weak... really weak.)
The use case is we want to be able to make a json request to the server and have it delay x amount of time before it returns -- originally it was written to use a sleep method, but that prevented multiple simultaneous requests. Sooo... after poking around for about a day i arrived at the code below. The problem i'm seeing (although there could well be many problems with my code) is:
The view test_runner.views.echo_json didn't return an HttpResponse object.
if anyone could offer any advice or point me in the right direction I would be super grateful -- thanks!
def echo_json(req, wasDelayed=False):
if req.REQUEST.get('delay') and wasDelayed == False:
sleeper(req, echo_jsonp)
else:
response = {}
callback = req.REQUEST.get('callback', False)
noresponse_eys = ['callback', 'delay']
for key, value in req.REQUEST.items():
if key not in noresponse_keys:
response.update({key: value})
response = simplejson.dumps(response)
if callback:
response = '%s(%s);' % (callback, response)
return HttpResponse(response, mimetype='application/javascript')
def sleeper(req, callback)
delay = float(req.REQUEST.get('delay'))
t = threading.Timer(delay, functools.partial(callback, req, true))
t.start()
Are you sure you want the return statement inside the for key, value loop? You're only allowing a single iteration, and returning.
Also, check the flow of the function. There are cases in which it will return None. Easiest way to do this is printing out your request object and examining it in the cases in which the function doesn't return an HttpResponse object.
See that your function will return None if:
req.request contains the key 'delay' and wasDelayed is True
req.REQUEST.items() is empty
I can't be sure, but I think the 2 problems are the else: and the return there. Shouldn't the code below the else: be executing whether the response is delayed or not? And shouldn't the return statement be outside the for loop?
Related
I hope everything is going well.
I'm working in a project really big and it wasn't set up by me. The project is buils using flask and cors.
I'm trying to create a query to update a row with SQLAlchemy follow the structure that the project has. so basically is like that:
#app.route("/update-topic", methods=['PATCH'])
async def update_by_id():
input_data = request.get_json()
await update_record(input_data)
return ApplicationTopicSchema(many=True).dump(data)
As you see in the code above is just a simple endpoint with PATCH method that get the input data and pass it to a function update_record(), that function is in charge to update the record like you can see in the next code:
from sqlalchemy import and_, update
class AppTopics(Base):
__tablename__ = AppTopics.__table__
async def update_record(self, data):
id_data = data['id']
query = self.__tablename__.update().\
where(self.__tablename__.c.id == id_data).values(**data).returning(self.__tablename__)
await super().fetch_one(query=query)
return 'updated'
Basically is something like that, and when I try to use the endpoint I get the next message error:
TypeError: The response value returned by the view function cannot be None
Executing <Handle <TaskWakeupMethWrapper object at 0x000001CAD3970F10>(<Future f
inis...events.py:418>) created at C:\Python\Python380\lib\asyncio\tasks.py:881>
Also, I'm trying to structure the query in another like this:
from sqlalchemy import and_, update
class AppTopics(Base):
__tablename__ = AppTopics.__table__
async def update_record(self, data):
u = update(self.__tablename__)
u = u.values({"topic": data['topic']})
u = u.where(self.__tablename__.c.id == data['id'])
await super().fetch_one(query=u)
return 'updated'
However I got the same error.
May you guys knows what is happening and what means this error:
TypeError: The response value returned by the view function cannot be None
Executing <Handle <TaskWakeupMethWrapper object at 0x000001B1B4861100>(<Future f
inis...events.py:418>) created at C:\Python\Python380\lib\asyncio\tasks.py:881>
Thanks in advance for your help and time.
Have a good day, evening, afternoon :)
The error message "TypeError: The response value returned by the view function cannot be None" is indicating that the view function (in this case, the update_by_id function) is not returning a value.
It seems that the function update_record does not return anything. If you want to return the string "updated" after updating the record, you should use a return statement like this:
async def update_record(self, data):
# update code here
return 'updated'
And on the update_by_id function you should call the return value of await update_record(input_data) to return it.
async def update_by_id():
input_data = request.get_json()
result = await update_record(input_data)
return result
Another point is that in the second example, you are not returning anything either, you should add a return statement before the end of the function.
Also, you are returning 'ApplicationTopicSchema(many=True).dump(data)' but the input data data is not being defined in the function, you should use the 'result' variable returned by update_record function instead.
async def update_by_id():
input_data = request.get_json()
result = await update_record(input_data)
return ApplicationTopicSchema(many=True).dump(result)
It's important to note that in the first example, the update_record function seems to be missing the self parameter, and could be causing some issues with the class.
It's also important to check if the fetch_one function from super() is waiting for the query with await keyword, and also if the fetch_one is returning something, otherwise it could be the cause of the None return value.
My understanding and knowledge is limited, but I hope this helps. Feel free to shoot me any further questions.
I have an object that is used for fetching information from another service which is very simple. Since the object is simple and the initialization method could be easily patched I thought I would try to write my code to be super reusable and extendable. But alas, I cannot figure out how to make it work. The code below is pretty well sudo code and is super simplified but it should get the point across.
class SimpleClient:
def __init__(self):
pass
def read(self, key, path='some/path'):
return value_from_get_on_another_service
I then have a request handler object that initializes a client via get_client() (seen below)
def get_client():
return SimpleClient()
Then a method on the request handler uses the client.read() method a few times with different parameters (2nd dependent upon the 1st).
For my tests, I thought I could "patch" the get_client method to return my own simple object that could then be used "regularly" and eliminate the dependence on the third party service and actually use the values retrieved from the method execution. I was disappointed to find it was not that easy and clean. The test pattern is seen below.
class MockClient:
def __init__(self, addr='someAddr', token='someToken'):
pass
def read(self, value, prefix):
data = {}
if prefix == 'path/1':
data = self.p1_lookup(value)
elif prefix == 'path/2':
data = self.p2_lookup(value)
return self.response_wrapper(data)
def p2_lookup(self, key):
data = {
'key1': {
'sub_key': {"55B3FE7D-9F43-4DD4-9090-9D89330C918A": "Dev2",
"7A1C2F4B-E91C-4659-A33E-1B18B0BEE2B3": "Dev"}
}
}
return data.get(key, {})
#mock.patch('a.module.get_client')
def test_authorize_valid_request_no_body(mock_get_client):
request = RequestMock()
request.body = None
handler = RequestHandler(Application(), request=request, logging_level='INFO')
mock_get_client.return_value = MockClient()
handler.authorize_request()
assert handler.verified_headers is None
assert handler.verified_body is None
assert handler.user_authenticated is False
I have seen where I can mock the responses for the actual client.read() to return multiple values with a list. But this just seems like I will be doing lots of copy and paste and have to do the same thing over and over for each little test. Forgive me if this is simple, sadly I am just learning the art of testing. Is there a way to accomplish what I am trying to do? Maybe there is something super simple I am missing. Or maybe I am just totally on the wrong track for no good reason. Help?!
After a sleep, with fresh eyes I was able to figure this out relatively quickly thanks to a couple other similar questions/answers that I had not found before. Primarily this one, Python Mock Object with Method called Multiple Times.
Rather than needing to rebuild the module object completely I need to let mock do that for me and then override the specific method on it with the side_effect attribute. So below is what sanitized version of the code looks like.
def read_override(value, prefix):
lookup_data1 = {"lookup1": {'key1': 'value1'}}
lookup_data2 = {'some_id': {'akey': {'12345678': 'DEV'}}
data = {}
if prefix == 'path1/1a':
data = lookup_data1.get(value, {})
elif prefix == 'path2/2a':
data = lookup_data2.get(value, {})
return {'data': data}
# Create a true Mock of the entire LookupClient Object
VAULT_MOCK = mock.Mock(spec=LookupClient)
# make the read method work the way I want it to with an "override" of sorts
VAULT_MOCK.read.side_effect = vault_read_override
Then the test simply looked like this...
#mock.patch('a.module.get_client')
def test_authorize_valid_request_no_body(get_client):
get_client.return_value = VAULT_MOCK
request = RequestMock()
request.body = None
handler = RequestHandler(Application(), request=request, logging_level='INFO')
handler.authorize_request()
assert handler.verified_headers is None
assert handler.verified_body is None
assert handler.user_authenticated is False
Is there a more Pythonic (2.7) way to check the server for a good status_code (200) that doesn't include using while True? My code snippet is as follows - and it's called many times:
import time
import json
from datetime import datetime
import requests
while True:
response = requests.get('http://example.com')
if response.status_code != 200:
print 'sleeping:',str(datetime.now()),response.status_code
print 'sleeping:',str(datetime.now()),response.headers
time.sleep(5.0)
else: break
if "x-mashery-error-code" in response.headers:
return None
return response.json()
edit: I included the 'if' loop with the header errors.
You can use Event Hooks
requests.get('http://example.com', hooks=dict(response=check_status))
def check_status(response):
if response.status_code != 200:
print 'not yet'
I would like this solution:
response = requests.get('http://example.com')
while response.status_code != 200:
print 'sleeping:',str(datetime.now()),response.status_code
print 'sleeping:',str(datetime.now()),response.headers
time.sleep(5.0)
response = requests.get('http://example.com')
Because:
>>> import this
...
Explicit is better than implicit.
Simple is better than complex.
...
Flat is better than nested.
...
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
...
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
...
Because I read it and understand it right away. With event hooks this is not the case. Do they open a thread to retrieve bytes in parallel? When are they called? Do I need to retrieve the data myself?
I'm using aspect-oriented programming by applying decorators for things like doing retries. If my function for getting the value I want looks like this:
def getValue():
return requests.get('http://example.com')
Then I'm decorating this function to apply the retry mechanism without interfering with the original (naive) code:
def retryUntilCondition(condition):
def decorate(function):
def f(*args, **kwargs):
while True:
result = function(*args, **kwargs)
if condition(result):
return result
time.sleep(5.0)
return f
return decorate
def responseIs200(response):
return response.status_code == 200
The above is the preparation (part of a utility library), below follows the usage:
#retryUntilCondition(responseIs200)
def getValue():
return requests.get('http://example.com')
This way the while loop is completely hidden from the application code and does not complicate reading it. The aspect of retrying is added by prepending a simple decorator which can even be reused in other situations.
If later you decide that you only want to retry for a specific number of times, have different delays etc., all this can be implemented in the retry decorator alone.
In flask, I can do this:
render_template("foo.html", messages={'main':'hello'})
And if foo.html contains {{ messages['main'] }}, the page will show hello. But what if there's a route that leads to foo:
#app.route("/foo")
def do_foo():
# do some logic here
return render_template("foo.html")
In this case, the only way to get to foo.html, if I want that logic to happen anyway, is through a redirect:
#app.route("/baz")
def do_baz():
if some_condition:
return render_template("baz.html")
else:
return redirect("/foo", messages={"main":"Condition failed on page baz"})
# above produces TypeError: redirect() got an unexpected keyword argument 'messages'
So, how can I get that messages variable to be passed to the foo route, so that I don't have to just rewrite the same logic code that that route computes before loading it up?
You could pass the messages as explicit URL parameter (appropriately encoded), or store the messages into session (cookie) variable before redirecting and then get the variable before rendering the template. For example:
from flask import session, url_for
def do_baz():
messages = json.dumps({"main":"Condition failed on page baz"})
session['messages'] = messages
return redirect(url_for('.do_foo', messages=messages))
#app.route('/foo')
def do_foo():
messages = request.args['messages'] # counterpart for url_for()
messages = session['messages'] # counterpart for session
return render_template("foo.html", messages=json.loads(messages))
(encoding the session variable might not be necessary, flask may be handling it for you, but can't recall the details)
Or you could probably just use Flask Message Flashing if you just need to show simple messages.
I found that none of the answers here applied to my specific use case, so I thought I would share my solution.
I was looking to redirect an unauthentciated user to public version of an app page with any possible URL params. Example:
/app/4903294/my-great-car?email=coolguy%40gmail.com to
/public/4903294/my-great-car?email=coolguy%40gmail.com
Here's the solution that worked for me.
return redirect(url_for('app.vehicle', vid=vid, year_make_model=year_make_model, **request.args))
Hope this helps someone!
I'm a little confused. "foo.html" is just the name of your template. There's no inherent relationship between the route name "foo" and the template name "foo.html".
To achieve the goal of not rewriting logic code for two different routes, I would just define a function and call that for both routes. I wouldn't use redirect because that actually redirects the client/browser which requires them to load two pages instead of one just to save you some coding time - which seems mean :-P
So maybe:
def super_cool_logic():
# execute common code here
#app.route("/foo")
def do_foo():
# do some logic here
super_cool_logic()
return render_template("foo.html")
#app.route("/baz")
def do_baz():
if some_condition:
return render_template("baz.html")
else:
super_cool_logic()
return render_template("foo.html", messages={"main":"Condition failed on page baz"})
I feel like I'm missing something though and there's a better way to achieve what you're trying to do (I'm not really sure what you're trying to do)
You can however maintain your code and simply pass the variables in it separated by a comma: if you're passing arguments, you should rather use render_template:
#app.route("/baz")
def do_baz():
if some_condition:
return render_template("baz.html")
else:
return render_template("/foo", messages={"main":"Condition failed on page baz"})
Excuse the vague title, I didn't know how else to state this.
I have a task worker request handler that fetches data from a URL and writes it to blobstore and saves the data's blob_key to a ListProperty in datastore. I've tried to simplifly the code for clarity here:
class Fetch(webapp2.RequestHandler):
def get(self):
url = self.request.get('url')
itemKey = self.request.get('itemKey')
item = MyModel.get(itemKey)
try:
result = urlfetch.fetch(url=url)
if result.status_code == 200:
saveDataResult = save_data(result.content, itemKey)
if saveDataResult is False:
raise Exception('error saving data')
else:
raise Exception('error fetching data: %s' % result.status_code)
item.status = 'success'
except Exception:
item.status = 'failed'
finally:
item.put()
def save_data(data, itemKey)
try:
#write data to blobstore and get its blob_key...
blob_key = files.blobstore.get_blob_key(file_name)
item = MyModel.get(itemKey)
item.blobKey.append(blob_key)
item.put()
return True
except:
return False
Now the problem I'm having is, when saveDataResult returns True, its status is set to 'success' but its blobKey property contains no value, even though a blob_key was generated and the data successfully written. I can't see what's causing this to save my life, please help.
Without much more information it is very difficult to determine what's happening. Here's my educated guess:
MyModel.get(itemKey) is called both in get() and save_data(). I surmise that it's returning two different objects representing the item. When the blobKey gets updated in save_data, the update is occurring only in the object fetched in save_data. When you later examine it outside that scope, you're looking at a different object.
Whether this is correct or not will depend on the implementation of MyModel.get().
Also, you do realize that you're calling item.put() twice, right?
The problem is here
finally:
item.put()
this single call overrides the data saved by save_data() because it references an older object of item.
My suggestion would be you do the status updates from save_data() i.e item.status = 'success'
or move item = MyModel.get(itemKey) to come after save_data() so you can fetch the updated object.
The problem is that when you call save_data() with item = MyModel.get(itemKey)
which is again called from the class Fetch you end up having two different objects and therefore overwriting the one in save_data() and hence when you go to your model datastore no data for blobkey is stored as its overwritten.
Try doing everything in the class or you do not use item = MyModel.get(itemKey) twice.