I was wondering how does a module really work in Python.For example I have this code
import requests
r = requests.get("http://www.google.com")
print r.status_code
Now according to my understanding, the requests module should have a python file which would be containing a class called "get" and within the "get" class there must be a member variable called "status_code"
So when I create the object "r", I get the variable status_code for it.
However, when I looked at all the files that come in the package, I could not find any class named "get".
I could however find a function called "get", under a class called "response". But since we did not create the object as an instance of the "response" class, how can we access the "get" function inside it?
I think I am missing a key concept here, can someone point it out for me please?
Thanks
When you import requests file __init__.pyis executed, if you examine that file in your case, you will find this line:
from .api import request, get, head, post, patch, put, delete, options
Which means that from api.py you are importing get() function:
def get(url, **kwargs):
kwargs.setdefault('allow_redirects', True)
return request('get', url, **kwargs)
And as you can see it calls request function from api.py that looks like:
def request(method, url, **kwargs):
session = sessions.Session()
return session.request(method=method, url=url, **kwargs)
That creates an object Session defined inside session.py, then calls its method request. This method will call method send() which returns a Responseobject which is defined in the class Response inside models.py (I copy the first lines):
class Response(object):
def __init__(self):
super(Response, self).__init__()
self._content = False
self._content_consumed = False
#: Integer Code of responded HTTP Status.
self.status_code = None
...
Here is where status_code is defined, so when you invoke r = requests.get("http://www.google.com") you are retrieving this object and then you can access to status_code
Your understanding is not entirely correct.
The requests module is an object; .get is then an attribute lookup on that object; it has to be a callable object because you try to call it with the (...) syntax. That means it can be a class, or a function or any other object with a __call__ method.
That callable returns something; all callables do. For a class, generally an instance is returned, but for a function that can be any Python object. Whatever .get() does, it returns an object that has a .status_code attribute, or has a .__getattr__ method that returns something when called with the name status_code.
In this specific case, get() is a function, which has been imported into the requests/__init__.py package initializer module. This function, indirectly, creates a Session() instance, and calls the .request() method on that instance. That method, eventually, returns a Response instance, which does have a .status_code attribute.
Related
I'm trying to set up a base class that contains common REST methods, to be used by more specific methods in a later testing framework. I decided that instead of creating different request.post methods that correspond to to the user passing in data, json, or files parameters, I would make one method that has the set parameters of url and header and let the user pass in whatever else they want within **kwargs. However, I'm not sure I can even use *kwargs in this context, as it seems the requests module expects a positional argument. This is what I have so far:
class Action:
def __init__(self, url, requestHeaders, **kwargs):
self.url = url
self.requestHeaders = requestHeaders
self.kwargs = kwargs
def postAction(self):
response = requests.post(self.url, headers=self.requestHeaders, self.kwargs)
resultCode = response.status_code
resultMessage = response.text
print(resultCode)
print(resultMessage)
return resultCode,resultMessage
For example, kwargs might contain files={'csv': ('/path/to/csv.csv', open('csv.csv, 'rb'), 'text/csv')} and verify=false. In another request, files might be replaced with data. However, when I try to test, I end up with this:
Traceback (most recent call last):
File "/home/user1/test/action.py", line 24
response = requests.post(self.url, headers=self.requestHeaders, self.kwargs)
SyntaxError: positional argument follows keyword argument
Is what I'm trying to do possible? If not, are there any alternatives?
If you want the kwargs to be treated as keyword arguments given to post, you need to use ** to apply them:
response = requests.post(self.url, headers=self.requestHeaders, **self.kwargs)
This, similar to sequence unpacking (*seq), will cause the data to be "expanded" into the argument list of the call.
I am writing unit tests. I would like to mock the result of a function called on a mock object.
I have a class called OwnerAnalyzer which accepts an object called client in its constructor. Using this client, I can get owner details.
In my unit test, I want to pass a mock for this client and mock results from its get_owners method.
Here is what I have so far:
def test_get_owner_details(mock_datetime, monkeypatch):
mock_datetime.now.return_value.isoformat.return_value = MOCK_NOW
mock_client = mock.MagicMock()
mock_client.return_value.get_owners.return_value = ListOwnerDetails(
main_owner=OwnerDetails(name='test_owner', type='User'), secondary_owners=[])
owner_analyzer = OwnerAnalyzer(OWNER_NAME, client=mock_client)
owner_analyzer.analyze_owner(OWNER_NAME)
assert classUnderTest.owner_name == 'test_owner'
I don't think the mock value is being returned in the get_owners call because I get something like for main_owner
owner is : <MagicMock name='mock.get_owners().main_owner' id='140420863948896'>.
Thanks to #jonrsharpe for pointing me in the right direction.
I was able to get this working by updating my mock setup to -
mock_client.get_owners.return_value = ListOwnerDetails(
main_owner=OwnerDetails(name='test_owner', type='User'), secondary_owners=[])
I've seen a lot of examples of mock tests but none that show how one could mock something like <graphql.execution.base.ResolveInfo object at 0x106f002a8>
For instance, if I wanted to test that the two methods in this class were working properly, how would I mock the values that are being passed in?
class mySearch(graphene.ObjectType):
my_search = graphene.Field(
MySearchWrapper,
query = graphene.String(description="Search query")
)
def __init__(self, args, context, info):
super(mySearch, self).__init__()
def resolve_my_search(self, args, context, info):
return promisify(MySearchWrapper, args, context, info)
The __init__ method returns:
args: {}, context: <Request 'http://localhost:8080/graphql' [POST]>, info: <graphql.execution.base.ResolveInfo object at 0x106f000c8>
And the resolve_my_search method returns:
args: {'page_type': [u'MyCorgi', u'YourCorgi'], 'query': u'Corgi family', 'domain': u'corgidata.com'}, context: <Request 'http://localhost:8080/graphql' [POST]>, info: <graphql.execution.base.ResolveInfo object at 0x106f002a8>
I know I can mock the dictionary value with mock_args.json.return_value but... not sure about the Request and object. Any ideas? Guidance? I've already spent a week on this and have found no way out.
Use unittest.mock python package. Here is an example:
from unittest import mock
info = mock.create_autospec(graphql.execution.base.ResolveInfo)
info.context.user = AnonymousUser()
Here is how I did it. You can tweak it to mock the GraphQLResolveInfo but for this use case I only needed to mock the Request object.
from requests import Requests
from unittest.mock import patch
from starlette.authentication import AuthenticationError
#patch("grapql.type.definition.GraphQLResolveInfo.context")
def test_func(context_mock):
with pytest.raises(AuthenticationError):
context_mock.side_effect = Request()
func_to_be_tested(resolver("fake_source", info_mock, data_inputs))
I'm trying to patch a public method for my flask application but it doesn't seem to work.
Here's my code in mrss.feed_burner
def get_feed(env=os.environ):
return 'something'
And this is how I use it
#app.route("/feed")
def feed():
mrss_feed = get_feed(env=os.environ)
response = make_response(mrss_feed)
response.headers["Content-Type"] = "application/xml"
return response
And this is my test which it's not parsing.
def test_feed(self):
with patch('mrss.feed_burner.get_feed', new=lambda: '<xml></xml>'):
response = self.app.get('/feed')
self.assertEquals('<xml></xml>', response.data)
I believe your problem is that you're not patching in the right namespace. See where_to_patch documentation for unittest.mock.patch.
Essentially, you're patching the definition of get_feed() in mrss.feed_burner but your view handler feed() already has a reference to the original mrss.feed_burner.get_feed(). To solve this problem, you need to patch the reference in your view file.
Based on your usage of get_feed in your view function, I assume you're importing get_feed like so
view_file.py
from mrss.feed_burner import get_feed
If so, you should be patching view_file.get_feed like so:
def test_feed(self):
with patch('view_file.get_feed', new=lambda: '<xml></xml>'):
...
I came across the __getattr__ built-in and was wondering when it would be used. I had a hard time thinking of a practical use from the documentation
http://docs.python.org/reference/datamodel.html#. What would be an actual example of how it could be used and useful in code?
One example is to use object notation with dictionaries. For example, consider a dictionary
myDict = {'value': 1}
Typically in Python one accesses the 'value' variable as
myDict['value']
which will print 1 at the Python interpreter. However, one may wish to use the myDict.value notation. This may be achieved by using the following class:
class DictAsMember(dict):
def __getattr__(self, name):
value = self[name]
if isinstance(value, dict):
value = DictAsMember(value)
return value
my_dict = DictAsMember()
my_dict['property'] = {'sub_property': 1}
print(my_dict.property.sub_property) # 1 will be printed
An example usage would be to create a simple wrapper around some object. In order, for example, to log the calls, or modify its behavior without inheriting from it, and without having to implement the whole interface of the object.
There is several good documented examples out there, like, for example, http://western-skies.blogspot.fr/2008/02/complete-example-of-getattr-in-python.html.
Since __getattr__ is only called when an attribute is not found, it can be a useful way to define an alternate place to look up an attribute, or to give default values, similar to a defaultdict.
You could also emulate a base class higher than all the others in an object's MRO, by delegating all the lookups here to another object (though doing this you could potentially have an infinite loop if the other object is delegating the attribute back).
There is also __getattribute__, which is related in that it is called anytime any attribute is looked up on the object.
Edit: This is about the built-in function getattr, not the __getattr__ method.
I needed to do this for a REST client using bearer tokens. I wrapped Requests's Session object into my own interface so I could always send the auth header, and (more relevantly) make HTTP requests to the same site, just using the URL's path.
class RequestsWrapper():
def __init__(self, base_url):
self.client = requests.Session(
headers={'Authorization':'myauthtoken'}
)
self.base_url = base_url
def _make_path_request(self, http_method, path, **kwargs):
"""
Use the http_method string to find the requests.Session instance's
method.
"""
method_to_call = getattr(self.client, http_method.lower())
return method_to_call(self.base_url + path, **kwargs)
def path_get(self, path, **kwargs):
"""
Sends a GET request to base_url + path.
"""
return self._make_path_request('get', path, **kwargs)
def path_post(self, path, **kwargs):
"""
Sends a POST request to base_url + path.
"""
return self._make_path_request('post', path, **kwargs)
def path_put(self, path, **kwargs):
"""
Sends a PUT request to base_url + path.
"""
return self._make_path_request('put', path, **kwargs)
def path_delete(self, path, **kwargs):
"""
Sends a DELETE request to base_url + path.
"""
return self._make_path_request('delete', path, **kwargs)
Then, I could just make a request based on the path:
# Initialize
myclient = RequestsWrapper("http://www.example.com")
# Make a get request to http://www.example.com/api/spam/eggs
response = myclient.path_get("/api/spam/eggs")
# Print the response JSON data
if response.ok:
print response.json