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.
Related
I'm not sure if I used the right terms in the title. This maybe a known way to program interface functions for a subsystem or module but because I don't know the keywords, I'm not finding the results in my search queries.
I want to create a function whose intention can be clearly described in the functions name but the parameters are flexible. I want to write the function to be generic enough so that the function can complete the intention with whatever parameters it receives from whichever caller.
Let's take a function do_foo.
do_foo can take in some_obj whose attributes allows do_foo to do its work. Additionally, do_foo can just take in the individual attributes it cares about like obj_attr0 or obj_attr1 and perform the same work. In both cases, the expected result is the same as well.
So this would look something like this:
Class SomeObj():
def __init__(self, obj_attr0, obj_attr1, obj_attrN):
self.obj_attr0 = None
self.obj_attr1 = None
self.obj_attrN = None # denotes an N number of attributes
def do_foo(params)
# unpack params. do_foo requires obj_attr0 and obj_attr1 and so its searching it in the params iterable
# determine which data is passed in
# execute the work the same way regardless of what form the data is passed in
pass
obj_attr0 = None
obj_attr1 = None
obj_attrN = None
some_obj = SomeObj(obj_attr0, obj_attr1, obj_attrN)
# One can either call with a subset of attributes that would make up SomeObj or SomeObj itself if all the information is there. E.g.:
params = (some_obj)
do_foo(params)
# OR
params = (obj_att0, obj_attr1)
do_foo(params)
I know python offers *args and **kwargs facilities that offer the flexibility above. I'm looking for some examples of where the implementation lends itself to reducing pitfalls. What is a good way to implement the above? And if there are any resources out there what are examples/articles/or terms that describe the above style of programming? Clearly, I'm trying to write my interface functions to be generic and usable in multiple logic paths where the users has its data in different forms where sticking to a specific parameter list is limiting.
Short answer:
You can use function decorators to do this
Long answer:
I have a concrete example for you. It might not be the prettiest code but it does something similar to what you are asking for.
Mini HTTP Testing library
I made a mini HTTP testing library because I make my REST http tests in python, and I realized that I always write the same code again and again. So I made a more general setup
The core
The core is kind of ugly and this is the part I don't want to write again and again.
Just skip this part quick and check how it is used in the interface section.
Then if you like it you can go back and try to understand how it is all tied together.
# base.py
import json, requests, inspect
# This function drops invallid parameters
def request(*args, **kwargs):
allowed = inspect.signature(requests.Session.request).parameters
return {k:v for (k,v) in kwargs.items() if k in allowed}
def response(r, code):
if r.status_code != code:
print(r.text)
return
data = r.json()
if data:
print(json.dumps(data, indent=2, ensure_ascii=False))
return data
# This is the core function it is not pretty but it creates all the abstaction in multiple levels of decorations.
def HTTP(base_url):
def outer(func_one):
def over(*args_one, **kwargs_one):
req, url, code = func_one(*args_one, **kwargs_one)
url = base_url + url
def inner(func_two):
def under(*args_two, **kwargs_two):
allowed = inspect.signature(func_two).parameters
kwparams = {k:v for (k,v) in kwargs_two.items() if k in allowed}
from_inner = func_two(*args_two, **kwparams)
u = url.format(id=kwargs_two.pop('_id')) if '{id}' in url else url
r = req(u, **request(**kwargs_two, **from_inner))
return response(r, code)
return under
return inner
return over
return outer
The interface
The interface functions are all each decorated by the HTTP function which makes them a HTTP caller function, it is still abstract since it will return a function.
Note: interface is just what I call it but it is really just functions which returns functions based on the HTTP decorator
BASE_URL = "https://example.com"
#HTTP(BASE_URL)
def POST(url, code=200): return requests.post, url, code
#HTTP(BASE_URL)
def PUT(url, code=200): return requests.put, url, code
#HTTP(BASE_URL)
def DELETE(url, code=200): return requests.delete, url, code
#HTTP(BASE_URL)
def GET(url, code=200): return requests.get, url, code
A middleware function
When one of the interface functions are decorated with this one then they need a token.
def AUTH(func):
def inner(token, *args, **kwargs):
headers = {'Authorization': f'bearer {token}'}
return func(*args, **kwargs, headers=headers)
return inner
The implementation
The interface can be used for many implementations.
Here I use the interface of POST, PUT, GET and DELETE for the user model.
This is the final decoration, and the functions returned will actually return content instead of other functions.
# users.py
from httplib.base import (
POST,
GET,
DELETE,
PUT,
AUTH,
request
)
#POST('/users',200)
def insert(user):
return request(json=user)
#AUTH
#GET('/users')
def find(_filter={}):
return request(params=_filter)
#AUTH
#GET('/users/{id}')
def find_one(_id):
return request()
#AUTH
#DELETE('/users/{id}')
def delete(_id):
return request()
#AUTH
#PUT('/users/{id}')
def update(_id, updates={}):
return request(json=updates)
Operation
Here you can see how the users delete insert and find functions work.
from httplib import users
def create_and_delete_users(token, n): return [
users.delete(token, _id=x['user']['id'])
for x in [
users.insert(user={
'username' : f'useruser{str(i).zfill(2)}',
'password' : 'secretpassword',
'email' : f'useruser{str(i).zfill(2)}#mail.com',
'gender' : 'male',
}) for i in range(n)]
]
def find_all_and_then_find_each(token): return [
users.find_one(token, _id=x['id'])
for x in users.find(token)['data']
]
I hope this was helpful.
I am writing tests that involve HTTP requests. There are some requests I have to make in a certain order, but I want to check the response from each step. So I thought a generator would be appropriate to enforce the sequence:
# Main code
def sequence_of_requests(arg1, arg2):
yield request_a(arg1)
yield request_b(arg1, arg2)
yield request_c(arg1, arg2)
Then in my test code I can write:
# Test code
generator_responses = sequence_of_requests()
r = next(generator_responses)
assert r.status_code == 200
r = next(generator_responses)
assert r.status_code == 204
r = next(generator_responses)
assert r.status_code == 404
The problem is that request_c() does not always receive the correct status on the first try, so I have been wrapping this function with a decorator in the test code so it repeatedly tries until success or timeout.
I'm wondering if there's some way I can do this wrapping on the generator, so I still get the enforced sequence of events. So I'm basically wondering if there's some way to repeatedly call one yield step of a generator.
Note: I don't want to put the code to wait for a response directly in the sequence_of_requests function, because it's not test code. The sequence_of_requests function is just used to ensure those steps are completed in the right order.
Instead of yielding the response values themselves, you can yield the functions, which can then be called repeatedly. The parameters to the functions can be applied with functools.partial.
from functools import partial
def sequence_of_requests(arg1, arg2):
yield partial(request_a, arg1)
yield partial(request_b, arg1, arg2)
yield partial(request_c, arg1, arg2)
Now the steps can be tested:
generator_functions = sequence_of_requests()
r = next(generator_functions)()
assert r.status_code == 200
r = next(generator_functions)()
assert r.status_code == 204
# Repeatedly make the request until the expected status code is returned.
func_slow_request = next(generator_functions)
wait_for_status(404)(func_slow_request)
You weren't very specific about timeout and number of retries, or condition for success... But, for simplicity, let's assume you want to retry up to 5 times, with 1s in between retries and you're expecting an error code other than 500 (or 5xx) to proceed.
Then you could use something like:
import time
def sequence_of_requests(arg1, arg2):
yield request_a(arg1)
yield request_b(arg1, arg2)
for retries in range(5):
result = request_c(arg1, arg2)
if result.status_code < 500:
break
time.sleep(1)
yield result
If you get to the maximum number of retries, you'll simply return the last received response. If you get a valid response, you break out of the loop and return the good response.
There's a small inefficiency in that if you reach the total number of retries, you still sleep for 1s before returning the value. You can fix that by managing the retries variable explicitly and checking for the limit inside the loop. But you might have other ideas on how to manage giving up (e.g. a timeout, rather than a fixed number of retries), so you should adapt that part of the code to follow the logic that makes sense to you.
I want to write a method to parse a site with requests library, the method should take a part of url having base_url in it and perform the get request on this, the main problem is that I do not know how to make it better;
What I have in mind now is:
import requests
class Response:
# ...
def site_parser(self, atom):
base_url="https://example.com/"
def category1(self):
return requests.get(base_url + category1/ + atom).text
def category2(self):
return requests.get(base_url + category2/ + atom).text
if __name == "__main__":
def main():
result = Response()
result.site_parser.category1("atom")
result.site_parser.category2("atom")
so needed data has the same base url but different dirs to get into, and I need to gen each dir if only the method was called afterwards. is there a way of doing this properly? I wouuld like to avoid making base url global variable
It seems to me that what you need is another class.
class Response:
# ... Some dark magic here ...
def site_parser(self, atom):
return ResponseParser(self, atom)
class ResponseParser:
def __init__(self, res, atom):
self.atom = atom
self.res = res
self.base_url = "https://example.com/"
def category1(self):
# ... Do stuff ...
def category2(self):
# ... Do stuff ...
Then you call it with
result = Response()
result.site_parser("atom").category1()
If you really insist on getting rid of the parentheses on the site_parser call, you could move the "atom" bit to the categoryN methods and turn site_parser into a property, but IMO that would probably just confuse people more than anything.
As a functional programmer, I love nested functions and closures as much as the next guy, but it seems to me that, based on the limited example you've given, having a second helper class is probably going to be the more readable way to go about this in this case.
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
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?