I am not sure why following decorator[validate_request] doesn't work. What is correct way to write such validation decorator?
def validate_request(req_type):
if req_type is 'json' and not request.json:
abort(400)
def decorator(func):
#functools.wraps(func)
def wrapped_func(*args, **kwargs):
return func(*args, **kwargs)
return wrapped_func
return decorator
#app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['PUT'])
#validate_request('json')
#json
def update_task(task_id):
# task = filter(lambda t: t['id'] == task_id, tasks)
task = [task for task in tasks if task['id'] == task_id]
if len(task) == 0:
abort(404)
#update task
for field in ['title', 'description', 'done']:
task[0][field] = request.json.get(field, task[0][field])
Error :-
Traceback (most recent call last):
File "C:\AGR\Programming\LearningPython\FlaskLearning\flask_rest\app.py", line 156, in <module>
#validate_request('json')
File "C:\AGR\Programming\LearningPython\FlaskLearning\flask_rest\app.py", line 144, in validate_request
if req_type is 'json' and not request.json:
File "C:\Anaconda\lib\site-packages\werkzeug\local.py", line 338, in __getattr__
return getattr(self._get_current_object(), name)
File "C:\Anaconda\lib\site-packages\werkzeug\local.py", line 297, in _get_current_object
return self.__local()
File "C:\Anaconda\lib\site-packages\flask\globals.py", line 20, in _lookup_req_object
raise RuntimeError('working outside of request context')
RuntimeError: working outside of request context
How should this be done in a more idiomatic way???
This is how your decorator should look like
def validate_request(f):
#functools.wraps(f)
def decorated_function(*args, **kwargs):
# Do something with your request here
data = flask.request.get_json()
if not data:
flask.abort(404)
return f(*args, **kwargs)
return decorated_function
and you will call it like this
#app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['PUT'])
#validate_request
def update_task(task_id):
# The rest of your code..
It's kind of an old post, but I think that it may benefit from a little correction:
decorated_function needs to return f(*args, **kws)
def validate_request(f):
#functools.wraps(f)
def decorated_function(*args, **kws):
# Do something with your request here
data = flask.request.get_json()
if not data:
flask.abort(404)
return f(*args, **kws)
return decorated_function
Otherwise you will encounter TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement.
Related
My question is pretty strange i know, but i have to do something like this:
def on_update(self, context):
self.possibleContext=[r"\/file\/",r"\/anyFile\/"]
def inner(function, *args, **kwargs):
self.handlers.append(function)
#i define result, is the dictionary returned by telegram request
function(result, *args, **kwargs)
return update
return inner
There is the decorator, under the polling function that should call every decorator
def polling(self, timeout: int = 0, *args, **kwargs):
print(f"Started {self.bot['first_name']} on TeleLib V.{self.version}")
try:
update_id = self.getUpdates()[0]['update_id']
except IndexError:
update_id = None
while True:
try:
for funct in self.handlers:
#Here i should call the decorator, not the function, because the decorator call the function giving it an argument
except Error1:
#here some telegram errors exceptions
except Error2:
#ecc
for update in self.getUpdates(offset=update_id, timeout=timeout):
update_id = update['update_id'] + 1
self.polling()
return update
and here a sample function:
#client.on_update('ciikk')
def funzione(update):
client.sendMessage(update['message']['chat']['id'],update['message']['text'])
I wrote two decorators, verbose controls whether or not the defined function prints it's output, announcer will announce when the function is called.
import os
import sys
def verbose(func):
'''Sets verbose mode on function'''
#functools.wraps(func)
def wrapper_func(verbboo=True, *args, **kwargs):
# disabling print
if not verbboo:
sys.stdout = open(os.devnull, 'w')
# running func
ret = func(*args, **kwargs)
# enabling print again
if not verbboo:
sys.stdout = sys.__stdout__
return ret
return wrapper_func
def announcer(func, endboo=True):
'''anounces when function is called and when it finishes; if specified'''
#functools.wraps(func)
def wrapper_func(*args, **kwargs):
print('run {}.{}#{:%Y%m%d%H%M}'.format(
func.__module__, func.__name__,
dt.datetime.now())
)
ret = func(*args, **kwargs)
if endboo:
print('end {}.{}#{:%Y%m%d%H%M}'.format(
func.__module__, func.__name__,
dt.datetime.now())
)
return ret
return wrapper_func
I then nest the following function with the decorators
#verbose
#announcer
def f(boo, opboo=True):
if boo:
print('This is True')
if opboo:
print('This is also True')
return f
# testing
f(True)
But I receive the following error
run __main__.f#202006021152
Traceback (most recent call last):
File "/home/user/anaconda3/envs/mpl/lib/python3.8/runpy.py", line 193, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/home/user/anaconda3/envs/mpl/lib/python3.8/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/user/project/test.py", line 17, in <module>
f(True)
File "/home/user/project/decorators.py", line 18, in wrapper_func
ret = func(*args, **kwargs)
File "/home/user/project/decorators.py", line 47, in wrapper_func
ret = func(*args, **kwargs)
TypeError: f() missing 1 required positional argument: 'boo'
The error only occurs when I nest verbose on top of announcer. announcer by itself works fine. What is going on?
I think the problem is in this line:
def wrapper_func(verbboo=True, *args, **kwargs):
A function definition has to have all of the positional arguments before any of the keyword arguments. Probably the keyword argument verbboo interfered with the positional argument boo getting passed through.
When I put the verbboo parameter at the end, it still didn't run, but when I put it between *args and **kwargs, it did run.
I have implemented the following retry decorator.
def retry(delay=10, retries=4):
def retry_decorator(f):
#wraps(f)
def f_retry(*args, **kwargs):
while retries > 1:
try:
return f(*args, **kwargs)
except Exception as e:
msg = "Exception: {}, Retrying in {} seconds...'.format(e, delay)"
print(msg)
time.sleep(delay)
retries -= 1
return f(*args, **kwargs)
return f_retry
return retry_decorator
I get the error that retries is not defined. However, retries is mentioned in the function definition. I am unable to figure out what went wrong here. Any help will be appreciated.
I made it work by collecting the variables retry and delay in a dictionary and then using that inside the function.
def retry(delay=10, retries=4):
def retry_decorator(f):
#wraps(f)
def f_retry(*args, **kwargs):
opt_dict = {'retries': retries, 'delay': delay}
while opt_dict['retries'] > 1:
try:
return f(*args, **kwargs)
except Exception as e:
msg = "Exception: {}, Retrying in {} seconds...".format(e, delay)
print(msg)
time.sleep(opt_dict['delay'])
opt_dict['retries'] -= 1
return f(*args, **kwargs)
return f_retry
return retry_decorator
I have a function that returns a future. I want to create a decorator to the function which waits for the future to complete and then return the result essentially converting the async function to blocking function (which I will use in my REST API). Is there a way to do that?
def sync(fn):
def wrapped(*args, **kwargs):
return IOLoop.instance().run_sync(lambda: fn(*args, **kwargs))
return wrapped
#gen.coroutine
def my_coro():
# ...
sync_fn = sync(my_coro)
result = sync_fn()
To resolve a future you need to yield it. Something like this might work:
from tornado import gen
def blocking(func):
def new_func(*args, **kwargs):
result = yield func(*args, **kwargs)
return result
return gen.coroutine(new_func)
The title simply described my problem. I would like to mock "_func_inner_1" with specific return value. Thanks for any advises :)
code under test:
from tornado.gen import coroutine, Return
from tornado.testing import gen_test
from tornado.testing import AsyncTestCase
import mock
#coroutine
def _func_inner_1():
raise Return(1)
#coroutine
def _func_under_test_1():
temp = yield _func_inner_1()
raise Return(temp + 1)
But, this intuitive solution not work
class Test123(AsyncTestCase):
#gen_test
#mock.patch(__name__ + '._func_inner_1')
def test_1(self, mock_func_inner_1):
mock_func_inner_1.side_effect = Return(9)
result_1 = yield _func_inner_1()
print 'result_1', result_1
result = yield _func_under_test_1()
self.assertEqual(10, result, result)
With below error, seems _func_inner_1 is not patched due to it's coroutine nature
AssertionError: 2
if I add coroutine to patch returned mock function
#gen_test
#mock.patch(__name__ + '._func_inner_1')
def test_1(self, mock_func_inner_1):
mock_func_inner_1.side_effect = Return(9)
mock_func_inner_1 = coroutine(mock_func_inner_1)
result_1 = yield _func_inner_1()
print 'result_1', result_1
result = yield _func_under_test_1()
self.assertEqual(10, result, result)
the error becomes:
Traceback (most recent call last):
File "tornado/testing.py", line 118, in __call__
result = self.orig_method(*args, **kwargs)
File "tornado/testing.py", line 494, in post_coroutine
timeout=timeout)
File "tornado/ioloop.py", line 418, in run_sync
return future_cell[0].result()
File "tornado/concurrent.py", line 109, in result
raise_exc_info(self._exc_info)
File "tornado/gen.py", line 175, in wrapper
yielded = next(result)
File "coroutine_unit_test.py", line 39, in test_1
mock_func_inner_1 = coroutine(mock_func_inner_1)
File "tornado/gen.py", line 140, in coroutine
return _make_coroutine_wrapper(func, replace_callback=True)
File "tornado/gen.py", line 150, in _make_coroutine_wrapper
#functools.wraps(func)
File "functools.py", line 33, in update_wrapper
setattr(wrapper, attr, getattr(wrapped, attr))
File "mock.py", line 660, in __getattr__
raise AttributeError(name)
AttributeError: __name__
This is the closest solution I can find, but the mocking function will NOT be reset after test case execution, unlike what patch does
#gen_test
def test_4(self):
global _func_inner_1
mock_func_inner_1 = mock.create_autospec(_func_inner_1)
mock_func_inner_1.side_effect = Return(100)
mock_func_inner_1 = coroutine(mock_func_inner_1)
_func_inner_1 = mock_func_inner_1
result = yield _func_under_test_1()
self.assertEqual(101, result, result)
There are two issues here:
First is the interaction between #mock.patch and #gen_test. gen_test works by converting a generator into a "normal" function; mock.patch only works on normal functions (as far as the decorator can tell, the generator returns as soon as it reaches the first yield, so mock.patch undoes all its work). To avoid this problem, you can either reorder the decorators (always put #mock.patch before #gen_test, or use the with form of mock.patch instead of the decorator form.
Second, coroutines should never raise an exception. Instead, they return a Future which will contain a result or an exception. The special Return exception is encapsulated by the coroutine system; you would never raise it from a Future. When you create your mocks, you must create the appropriate Future and set it as the return value instead of using side_effect to raise on exception.
The complete solution is:
from tornado.concurrent import Future
from tornado.gen import coroutine, Return
from tornado.testing import gen_test
from tornado.testing import AsyncTestCase
import mock
#coroutine
def _func_inner_1():
raise Return(1)
#coroutine
def _func_under_test_1():
temp = yield _func_inner_1()
raise Return(temp + 1)
class Test123(AsyncTestCase):
#mock.patch(__name__ + '._func_inner_1')
#gen_test
def test_1(self, mock_func_inner_1):
future_1 = Future()
future_1.set_result(9)
mock_func_inner_1.return_value = future_1
result_1 = yield _func_inner_1()
print 'result_1', result_1
result = yield _func_under_test_1()
self.assertEqual(10, result, result)
import unittest
unittest.main()