Python mocking requests.get content and iter_lines() - python

I am trying to mock the streamed requests.get function for one object that uses it internally.
I particularly need to test following methods:
class MyObject(object)
def __iter__(self):
payload = {"op": "OPEN"}
response = requests.get("http://" + self.parsed_uri.uri_path, params=payload, stream=True)
return response.iter_lines()
def read(self, size=None):
if not size or size < 0:
payload = {"op": "OPEN", "offset": self.offset}
self.offset = 0
else:
payload = {"op": "OPEN", "offset": self.offset, "length": size}
self.offset = self.offset + size
response = requests.get("http://" + self.parsed_uri.uri_path, params=payload, stream=True)
return response.content
I need requests.get to return me something like "abc\n123"
And then my test method should look like:
#mock.patch('requests.get', mock.Mock(side_effect=mocked_requests_get))
def test_iter(self, mock_get):
object = MyObject(ParseUri("http://host/path"))
self.assertEqual(object.next(), "abc")
self.assertEqual(object.next(), "123")
#mock.patch('requests.get', mock.Mock(side_effect=mocked_requests_get))
def test_read(self, mock_get):
object = MyObject(ParseUri("http://host/path"))
self.assertEqual(object.read, "abc\n123")
I am trying to implement the mocked_requests_get, but unfortunately I can't make it work. Is it possible to use mock library this way? How should the mocked_requests_get look like?

UPD. Can't say what's really wrong with your code without full example. How I solves this with responses module:
import requests
import unittest
import responses
class Foo(object):
def __init__(self, uri):
self.uri = uri
def __iter__(self):
payload = {"op": "OPEN"}
response = requests.get("http://" + self.uri, params=payload,
stream=True)
return response.iter_lines()
class TestFoo(unittest.TestCase):
#responses.activate
def test_iter_lines(self):
responses.add(responses.GET, "http://local.host/", body='abc\n123')
r = iter(Foo("local.host"))
self.assertEqual(r.next(), "abc")
self.assertEqual(r.next(), "123")
if __name__ == '__main__':
unittest.main()
P.S. Maybe you want to return iterator before call this?
self.assertEqual(object.next(), "123")

Related

How to Mock a Flask Cloud Run service that is called by another Flask Cloud Run service for Testing [duplicate]

I am trying to use Pythons mock package to mock Pythons requests module. What are the basic calls to get me working in below scenario?
In my views.py, I have a function that makes variety of requests.get() calls with different response each time
def myview(request):
res1 = requests.get('aurl')
res2 = request.get('burl')
res3 = request.get('curl')
In my test class I want to do something like this but cannot figure out exact method calls
Step 1:
# Mock the requests module
# when mockedRequests.get('aurl') is called then return 'a response'
# when mockedRequests.get('burl') is called then return 'b response'
# when mockedRequests.get('curl') is called then return 'c response'
Step 2:
Call my view
Step 3:
verify response contains 'a response', 'b response' , 'c response'
How can I complete Step 1 (mocking the requests module)?
This is how you can do it (you can run this file as-is):
import requests
import unittest
from unittest import mock
# This is the class we want to test
class MyGreatClass:
def fetch_json(self, url):
response = requests.get(url)
return response.json()
# This method will be used by the mock to replace requests.get
def mocked_requests_get(*args, **kwargs):
class MockResponse:
def __init__(self, json_data, status_code):
self.json_data = json_data
self.status_code = status_code
def json(self):
return self.json_data
if args[0] == 'http://someurl.com/test.json':
return MockResponse({"key1": "value1"}, 200)
elif args[0] == 'http://someotherurl.com/anothertest.json':
return MockResponse({"key2": "value2"}, 200)
return MockResponse(None, 404)
# Our test case class
class MyGreatClassTestCase(unittest.TestCase):
# We patch 'requests.get' with our own method. The mock object is passed in to our test case method.
#mock.patch('requests.get', side_effect=mocked_requests_get)
def test_fetch(self, mock_get):
# Assert requests.get calls
mgc = MyGreatClass()
json_data = mgc.fetch_json('http://someurl.com/test.json')
self.assertEqual(json_data, {"key1": "value1"})
json_data = mgc.fetch_json('http://someotherurl.com/anothertest.json')
self.assertEqual(json_data, {"key2": "value2"})
json_data = mgc.fetch_json('http://nonexistenturl.com/cantfindme.json')
self.assertIsNone(json_data)
# We can even assert that our mocked method was called with the right parameters
self.assertIn(mock.call('http://someurl.com/test.json'), mock_get.call_args_list)
self.assertIn(mock.call('http://someotherurl.com/anothertest.json'), mock_get.call_args_list)
self.assertEqual(len(mock_get.call_args_list), 3)
if __name__ == '__main__':
unittest.main()
Important Note: If your MyGreatClass class lives in a different package, say my.great.package, you have to mock my.great.package.requests.get instead of just 'request.get'. In that case your test case would look like this:
import unittest
from unittest import mock
from my.great.package import MyGreatClass
# This method will be used by the mock to replace requests.get
def mocked_requests_get(*args, **kwargs):
# Same as above
class MyGreatClassTestCase(unittest.TestCase):
# Now we must patch 'my.great.package.requests.get'
#mock.patch('my.great.package.requests.get', side_effect=mocked_requests_get)
def test_fetch(self, mock_get):
# Same as above
if __name__ == '__main__':
unittest.main()
Enjoy!
Try using the responses library. Here is an example from their documentation:
import responses
import requests
#responses.activate
def test_simple():
responses.add(responses.GET, 'http://twitter.com/api/1/foobar',
json={'error': 'not found'}, status=404)
resp = requests.get('http://twitter.com/api/1/foobar')
assert resp.json() == {"error": "not found"}
assert len(responses.calls) == 1
assert responses.calls[0].request.url == 'http://twitter.com/api/1/foobar'
assert responses.calls[0].response.text == '{"error": "not found"}'
It provides quite a nice convenience over setting up all the mocking yourself.
There's also HTTPretty:
It's not specific to requests library, more powerful in some ways though I found it doesn't lend itself so well to inspecting the requests that it intercepted, which responses does quite easily
There's also httmock.
A new library gaining popularity recently over the venerable requests is httpx, which adds first-class support for async. A mocking library for httpx is: https://github.com/lundberg/respx
Here is what worked for me:
import mock
#mock.patch('requests.get', mock.Mock(side_effect = lambda k:{'aurl': 'a response', 'burl' : 'b response'}.get(k, 'unhandled request %s'%k)))
I used requests-mock for writing tests for separate module:
# module.py
import requests
class A():
def get_response(self, url):
response = requests.get(url)
return response.text
And the tests:
# tests.py
import requests_mock
import unittest
from module import A
class TestAPI(unittest.TestCase):
#requests_mock.mock()
def test_get_response(self, m):
a = A()
m.get('http://aurl.com', text='a response')
self.assertEqual(a.get_response('http://aurl.com'), 'a response')
m.get('http://burl.com', text='b response')
self.assertEqual(a.get_response('http://burl.com'), 'b response')
m.get('http://curl.com', text='c response')
self.assertEqual(a.get_response('http://curl.com'), 'c response')
if __name__ == '__main__':
unittest.main()
this is how you mock requests.post, change it to your http method
#patch.object(requests, 'post')
def your_test_method(self, mockpost):
mockresponse = Mock()
mockpost.return_value = mockresponse
mockresponse.text = 'mock return'
#call your target method now
Here is a solution with requests Response class. It is cleaner IMHO.
import json
from unittest.mock import patch
from requests.models import Response
def mocked_requests_get(*args, **kwargs):
response_content = None
request_url = kwargs.get('url', None)
if request_url == 'aurl':
response_content = json.dumps('a response')
elif request_url == 'burl':
response_content = json.dumps('b response')
elif request_url == 'curl':
response_content = json.dumps('c response')
response = Response()
response.status_code = 200
response._content = str.encode(response_content)
return response
#mock.patch('requests.get', side_effect=mocked_requests_get)
def test_fetch(self, mock_get):
response = requests.get(url='aurl')
assert ...
If you want to mock a fake response, another way to do it is to simply instantiate an instance of the base HttpResponse class, like so:
from django.http.response import HttpResponseBase
self.fake_response = HttpResponseBase()
I started out with Johannes Farhenkrug's answer here and it worked great for me. I needed to mock the requests library because my goal is to isolate my application and not test any 3rd party resources.
Then I read up some more about python's Mock library and I realized that I can replace the MockResponse class, which you might call a 'Test Double' or a 'Fake', with a python Mock class.
The advantage of doing so is access to things like assert_called_with, call_args and so on. No extra libraries are needed. Additional benefits such as 'readability' or 'its more pythonic' are subjective, so they may or may not play a role for you.
Here is my version, updated with using python's Mock instead of a test double:
import json
import requests
from unittest import mock
# defube stubs
AUTH_TOKEN = '{"prop": "value"}'
LIST_OF_WIDGETS = '{"widgets": ["widget1", "widget2"]}'
PURCHASED_WIDGETS = '{"widgets": ["purchased_widget"]}'
# exception class when an unknown URL is mocked
class MockNotSupported(Exception):
pass
# factory method that cranks out the Mocks
def mock_requests_factory(response_stub: str, status_code: int = 200):
return mock.Mock(**{
'json.return_value': json.loads(response_stub),
'text.return_value': response_stub,
'status_code': status_code,
'ok': status_code == 200
})
# side effect mock function
def mock_requests_post(*args, **kwargs):
if args[0].endswith('/api/v1/get_auth_token'):
return mock_requests_factory(AUTH_TOKEN)
elif args[0].endswith('/api/v1/get_widgets'):
return mock_requests_factory(LIST_OF_WIDGETS)
elif args[0].endswith('/api/v1/purchased_widgets'):
return mock_requests_factory(PURCHASED_WIDGETS)
raise MockNotSupported
# patch requests.post and run tests
with mock.patch('requests.post') as requests_post_mock:
requests_post_mock.side_effect = mock_requests_post
response = requests.post('https://myserver/api/v1/get_widgets')
assert response.ok is True
assert response.status_code == 200
assert 'widgets' in response.json()
# now I can also do this
requests_post_mock.assert_called_with('https://myserver/api/v1/get_widgets')
Repl.it links:
https://repl.it/#abkonsta/Using-unittestMock-for-requestspost#main.py
https://repl.it/#abkonsta/Using-test-double-for-requestspost#main.py
This worked for me, although I haven't done much complicated testing yet.
import json
from requests import Response
class MockResponse(Response):
def __init__(self,
url='http://example.com',
headers={'Content-Type':'text/html; charset=UTF-8'},
status_code=200,
reason = 'Success',
_content = 'Some html goes here',
json_ = None,
encoding='UTF-8'
):
self.url = url
self.headers = headers
if json_ and headers['Content-Type'] == 'application/json':
self._content = json.dumps(json_).encode(encoding)
else:
self._content = _content.encode(encoding)
self.status_code = status_code
self.reason = reason
self.encoding = encoding
Then you can create responses :
mock_response = MockResponse(
headers={'Content-Type' :'application/json'},
status_code=401,
json_={'success': False},
reason='Unauthorized'
)
mock_response.raise_for_status()
gives
requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: http://example.com
One possible way to work around requests is using the library betamax, it records all requests and after that if you make a request in the same url with the same parameters the betamax will use the recorded request, I have been using it to test web crawler and it save me a lot time.
import os
import requests
from betamax import Betamax
from betamax_serializers import pretty_json
WORKERS_DIR = os.path.dirname(os.path.abspath(__file__))
CASSETTES_DIR = os.path.join(WORKERS_DIR, u'resources', u'cassettes')
MATCH_REQUESTS_ON = [u'method', u'uri', u'path', u'query']
Betamax.register_serializer(pretty_json.PrettyJSONSerializer)
with Betamax.configure() as config:
config.cassette_library_dir = CASSETTES_DIR
config.default_cassette_options[u'serialize_with'] = u'prettyjson'
config.default_cassette_options[u'match_requests_on'] = MATCH_REQUESTS_ON
config.default_cassette_options[u'preserve_exact_body_bytes'] = True
class WorkerCertidaoTRT2:
session = requests.session()
def make_request(self, input_json):
with Betamax(self.session) as vcr:
vcr.use_cassette(u'google')
response = session.get('http://www.google.com')
https://betamax.readthedocs.io/en/latest/
Can you use requests-mock instead?
Suppose your myview function instead takes a requests.Session object, makes requests with it, and does something to the output:
# mypackage.py
def myview(session):
res1 = session.get("http://aurl")
res2 = session.get("http://burl")
res3 = session.get("http://curl")
return f"{res1.text}, {res2.text}, {res3.text}"
# test_myview.py
from mypackage import myview
import requests
def test_myview(requests_mock):
# set up requests
a_req = requests_mock.get("http://aurl", text="a response")
b_req = requests_mock.get("http://burl", text="b response")
c_req = requests_mock.get("http://curl", text="c response")
# test myview behaviour
session = requests.Session()
assert myview(session) == "a response, b response, c response"
# check that requests weren't called repeatedly
assert a_req.called_once
assert b_req.called_once
assert c_req.called_once
assert requests_mock.call_count == 3
You can also use requests_mock with frameworks other than Pytest - the documentation is great.
I will add this information since I had a hard time figuring how to mock an async api call.
Here is what I did to mock an async call.
Here is the function I wanted to test
async def get_user_info(headers, payload):
return await httpx.AsyncClient().post(URI, json=payload, headers=headers)
You still need the MockResponse class
class MockResponse:
def __init__(self, json_data, status_code):
self.json_data = json_data
self.status_code = status_code
def json(self):
return self.json_data
You add the MockResponseAsync class
class MockResponseAsync:
def __init__(self, json_data, status_code):
self.response = MockResponse(json_data, status_code)
async def getResponse(self):
return self.response
Here is the test. The important thing here is I create the response before since init function can't be async and the call to getResponse is async so it all checked out.
#pytest.mark.asyncio
#patch('httpx.AsyncClient')
async def test_get_user_info_valid(self, mock_post):
"""test_get_user_info_valid"""
# Given
token_bd = "abc"
username = "bob"
payload = {
'USERNAME': username,
'DBNAME': 'TEST'
}
headers = {
'Authorization': 'Bearer ' + token_bd,
'Content-Type': 'application/json'
}
async_response = MockResponseAsync("", 200)
mock_post.return_value.post.return_value = async_response.getResponse()
# When
await api_bd.get_user_info(headers, payload)
# Then
mock_post.return_value.post.assert_called_once_with(
URI, json=payload, headers=headers)
If you have a better way of doing that tell me but I think it's pretty clean like that.
The simplest way so far:
from unittest import TestCase
from unittest.mock import Mock, patch
from .utils import method_foo
class TestFoo(TestCase):
#patch.object(utils_requests, "post") # change to desired method here
def test_foo(self, mock_requests_post):
# EXPLANATION: mocked 'post' method above will return some built-in mock,
# and its method 'json' will return mock 'mock_data',
# which got argument 'return_value' with our data to be returned
mock_data = Mock(return_value=[{"id": 1}, {"id": 2}])
mock_requests_post.return_value.json = mock_data
method_foo()
# TODO: asserts here
"""
Example of method that you can test in utils.py
"""
def method_foo():
response = requests.post("http://example.com")
records = response.json()
for record in records:
print(record.get("id"))
# do other stuff here
For those, who don't want to install additional libs for pytest, there is an example. I will duplicate it here with some extension, based on examples above:
import datetime
import requests
class MockResponse:
def __init__(self, json_data, status_code):
self.json_data = json_data
self.status_code = status_code
self.elapsed = datetime.timedelta(seconds=1)
# mock json() method always returns a specific testing dictionary
def json(self):
return self.json_data
def test_get_json(monkeypatch):
# Any arguments may be passed and mock_get() will always return our
# mocked object, which only has the .json() method.
def mock_get(*args, **kwargs):
return MockResponse({'mock_key': 'mock_value'}, 418)
# apply the monkeypatch for requests.get to mock_get
monkeypatch.setattr(requests, 'get', mock_get)
# app.get_json, which contains requests.get, uses the monkeypatch
response = requests.get('https://fakeurl')
response_json = response.json()
assert response_json['mock_key'] == 'mock_value'
assert response.status_code == 418
assert response.elapsed.total_seconds() == 1
============================= test session starts ==============================
collecting ... collected 1 item
test_so.py::test_get_json PASSED [100%]
============================== 1 passed in 0.07s ===============================
Using requests_mock is easy to patch any requests
pip install requests-mock
from unittest import TestCase
import requests_mock
from <yourmodule> import <method> (auth)
class TestApi(TestCase):
#requests_mock.Mocker()
def test_01_authentication(self, m):
"""Successful authentication using username password"""
token = 'token'
m.post(f'http://localhost/auth', json= {'token': token})
act_token =auth("user", "pass")
self.assertEqual(act_token, token)
To avoid installing other dependencies you should create a fake response. This FakeResponse could be a child of Response (I think this is a good approach because it's more realistic) or just a simple class with the attributes you need.
Simple Fake class
class FakeResponse:
status_code = None
def __init__(self, *args, **kwargs):
self.status_code = 500
self.text = ""
Child of Response
class FakeResponse(Response):
encoding = False
_content = None
def __init__(*args, **kwargs):
super(FakeResponse).__thisclass__.status_code = 500
# Requests requires to be not be None, if not throws an exception
# For reference: https://github.com/psf/requests/issues/3698#issuecomment-261115119
super(FakeResponse).__thisclass__.raw = io.BytesIO()
Just a helpful hint to those that are still struggling, converting from urllib or urllib2/urllib3 to requests AND trying to mock a response- I was getting a slightly confusing error when implementing my mock:
with requests.get(path, auth=HTTPBasicAuth('user', 'pass'), verify=False) as url:
AttributeError: __enter__
Well, of course, if I knew anything about how with works (I didn't), I'd know it was a vestigial, unnecessary context (from PEP 343). Unnecessary when using the requests library because it does basically the same thing for you under the hood. Just remove the with and use bare requests.get(...) and Bob's your uncle.
For pytest users there is a convinient fixture from https://pypi.org/project/pytest-responsemock/
For example to mock GET to http://some.domain you can:
def test_me(response_mock):
with response_mock('GET http://some.domain -> 200 :Nice'):
response = send_request()
assert result.ok
assert result.content == b'Nice'
I will demonstrate how to detach your programming logic from the actual external library by swapping the real request with a fake one that returns the same data. In your view if external api call then this process is best
import pytest
from unittest.mock import patch
from django.test import RequestFactory
#patch("path(projectname.appname.filename).requests.post")
def test_mock_response(self, mock_get, rf: RequestFactory):
mock_get.return_value.ok = Mock(ok=True)
mock_get.return_value.status_code = 400
mock_get.return_value.json.return_value = {you can define here dummy response}
request = rf.post("test/", data=self.payload)
response = view_name_view(request)
expected_response = {
"success": False,
"status": "unsuccessful",
}
assert response.data == expected_response
assert response.status_code == 400
If using pytest:
>>> import pytest
>>> import requests
>>> def test_url(requests_mock):
... requests_mock.get('http://test.com', text='data')
... assert 'data' == requests.get('http://test.com').text
Taken from the official documentation

How to unit test a function whose output can vary?

I have a function that fetches latest data from a URL based on given inputs. How do I write a unit test for this function given that the output is not fixed and might change every day?
def get_data_from_url(param1, param2):
url = f"https://some-service/get_data/param1={param1}&param2={param2}"
resp = requests.get(url, headers={"Content-Type": "application/json"})
something = resp.json()['something']
if something.match(pattern):
...
return some_value
elif something.match(some_other_pattern):
...
return some_other_value
else:
return something
I'm using pytest for my unit tests.
You should use mock. Either a standard mock or a requests_mock:
class Test(unittest.TestCase):
def test_with_simple_mock(self):
fake_result = collections.namedtuple("Response", ("status_code", "json"))(
200, lambda: {"something": "somevalue"}
)
with mock.patch("requests.get", return_value=fake_result):
self.assertEquals(
requests.get("https://some-service/get_data/").json()["something"],
"somevalue",
)
def test_with_requests_mock(self):
with requests_mock.Mocker() as m:
m.get("https://some-service/get_data/", text='{"something": "somevalue"}')
self.assertEquals(
requests.get("https://some-service/get_data/").json()["something"],
"somevalue",
)

How do I use the functions within this Python script?

I have this Python script to control a PfSense router via FauxAPI. The problem is that when i call a function it gives an error. I think i'm calling the function wrong. Does anyone know how to call them?
Here is a link to the API i'm using: https://github.com/ndejong/pfsense_fauxapi
I have tried calling config_get(self, section=none) but that does not seem to work.
import os
import json
import base64
import urllib
import requests
import datetime
import hashlib
class PfsenseFauxapiException(Exception):
pass
class PfsenseFauxapi:
host = '172.16.1.1'
proto = None
debug = None
version = None
apikey = 'key'
apisecret = 'secret'
use_verified_https = None
def __init__(self, host, apikey, apisecret, use_verified_https=False, debug=False):
self.proto = 'https'
self.base_url = 'fauxapi/v1'
self.version = __version__
self.host = host
self.apikey = apikey
self.apisecret = apisecret
self.use_verified_https = use_verified_https
self.debug = debug
if self.use_verified_https is False:
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
def config_get(self, section=None):
config = self._api_request('GET', 'config_get')
if section is None:
return config['data']['config']
elif section in config['data']['config']:
return config['data']['config'][section]
raise PfsenseFauxapiException('Unable to complete config_get request, section is unknown', section)
def config_set(self, config, section=None):
if section is None:
config_new = config
else:
config_new = self.config_get(section=None)
config_new[section] = config
return self._api_request('POST', 'config_set', data=config_new)
def config_patch(self, config):
return self._api_request('POST', 'config_patch', data=config)
def config_reload(self):
return self._api_request('GET', 'config_reload')
def config_backup(self):
return self._api_request('GET', 'config_backup')
def config_backup_list(self):
return self._api_request('GET', 'config_backup_list')
def config_restore(self, config_file):
return self._api_request('GET', 'config_restore', params={'config_file': config_file})
def send_event(self, command):
return self._api_request('POST', 'send_event', data=[command])
def system_reboot(self):
return self._api_request('GET', 'system_reboot')
def system_stats(self):
return self._api_request('GET', 'system_stats')
def interface_stats(self, interface):
return self._api_request('GET', 'interface_stats', params={'interface': interface})
def gateway_status(self):
return self._api_request('GET', 'gateway_status')
def rule_get(self, rule_number=None):
return self._api_request('GET', 'rule_get', params={'rule_number': rule_number})
def alias_update_urltables(self, table=None):
if table is not None:
return self._api_request('GET', 'alias_update_urltables', params={'table': table})
return self._api_request('GET', 'alias_update_urltables')
def function_call(self, data):
return self._api_request('POST', 'function_call', data=data)
def system_info(self):
return self._api_request('GET', 'system_info')
def _api_request(self, method, action, params=None, data=None):
if params is None:
params = {}
if self.debug:
params['__debug'] = 'true'
url = '{proto}://{host}/{base_url}/?action={action}&{params}'.format(
proto=self.proto, host=self.host, base_url=self.base_url, action=action, params=urllib.parse.urlencode(params))
if method.upper() == 'GET':
res = requests.get(
url,
headers={'fauxapi-auth': self._generate_auth()},
verify=self.use_verified_https
)
elif method.upper() == 'POST':
res = requests.post(
url,
headers={'fauxapi-auth': self._generate_auth()},
verify=self.use_verified_https,
data=json.dumps(data)
)
else:
raise PfsenseFauxapiException('Request method not supported!', method)
if res.status_code == 404:
raise PfsenseFauxapiException('Unable to find FauxAPI on target host, is it installed?')
elif res.status_code != 200:
raise PfsenseFauxapiException('Unable to complete {}() request'.format(action), json.loads(res.text))
return self._json_parse(res.text)
def _generate_auth(self):
# auth = apikey:timestamp:nonce:HASH(apisecret:timestamp:nonce)
nonce = base64.b64encode(os.urandom(40)).decode('utf-8').replace('=', '').replace('/', '').replace('+', '')[0:8]
timestamp = datetime.datetime.utcnow().strftime('%Y%m%dZ%H%M%S')
hash = hashlib.sha256('{}{}{}'.format(self.apisecret, timestamp, nonce).encode('utf-8')).hexdigest()
return '{}:{}:{}:{}'.format(self.apikey, timestamp, nonce, hash)
def _json_parse(self, data):
try:
return json.loads(data)
except json.JSONDecodeError:
pass
raise PfsenseFauxapiException('Unable to parse response data!', data)
Without having tested the above script myself, I can conclude that yes you are calling the function wrong. The above script is rather a class that must be instantiated before any function inside can be used.
For example you could first create an object with:
pfsense = PfsenseFauxapi(host='<host>', apikey='<API key>', apisecret='<API secret>')
replacing <host>, <API key> and <API secret> with the required values
Then call the function with:
pfsense.config_get() # self is not passed
where config_get can be replaced with any function
Also note
As soon as you call pfsense = PfsenseFauxapi(...), all the code in
the __init__ function is also run as it is the constructor (which
is used to initialize all the attributes of the class).
When a function has a parameter which is parameter=something, that something is the default value when nothing is passed for that parameter. Hence why use_verified_https, debug and section do not need to be passed (unless you want to change them of course)
Here is some more information on classes if you need.
You need to create an object of the class in order to call the functions of the class. For example
x = PfsenseFauxapi() (the init method is called during contructing the object)
and then go by x.'any function'. Maybe name the variable not x for a good naming quality.

Calling regular functions from inside a class?

I'm new to Python and I have factory class that takes in API arguments and with my setup i get a NameError: 'self' is not defined. I understand that my functions calls are wrong. How would I refactor this to have the same logic
import requests
import json
class Call:
results = []
__response = None
__methods= dict(post=self.__post(), get=self.__get())
def __init__(self, root, endpoint, payload, header):
self.__root = root
self.__endpoint = endpoint
self.__payload = payload
self.__header = header
def __post(self):
self.__response = requests.post(
self.__root + self.__endpoint,
data = json.dumps(self.__payload),
headers = self.__header
)
self.__get_results()
def __get(self):
self.__response = requests.get(
self.__root + self.__endpoint,
data = json.dumps(self.__payload),
headers = self.__header
)
self.__get_results()
def __get_results(self):
if (self.__response.ok):
data = json.loads(self.__response.content)
results.append(
{
'result':data['result'],
'endpoint': self.__endpoint,
'status' : response.status_code
}
)
else:
results.append(
{
'result':'FAILED',
'endpoint': self.__endpoint,
'status' : response.status_code
}
)
def method(self, method):
return self.__methods[method]
login = Call(
Url.V1_PROD,
DriverEndpoint.LOGIN,
DriverPayload.LOGIN,
Request.HEADER
)
login.method('post')
You shouldn't use variable names starting with a __double __underscore, they are used to invoke name mangling, which you probably don't want.
Use a _single _underscore.
It's easier to declare your dictionary on the instance, in the __init__ method.
A common alternative would be to store the names of the methods you want to call, as strings, and use getattr to access the methods (see Call a Python method by name).
import requests
import json
class Call:
results = []
_response = None
def __init__(self, root, endpoint, payload, header):
self._root = root
self._endpoint = endpoint
self._payload = payload
self._header = header
# NO () after self._post, otherwise it would call the
# method and insert the return value in the dict
self._methods= dict(post=self._post, get=self._get)
def _post(self):
self._response = requests.post(
self._root + self._endpoint,
data = json.dumps(self._payload),
headers = self._header
)
self._get_results()
def _get(self):
self._response = requests.get(
self._root + self._endpoint,
data = json.dumps(self._payload),
headers = self._header
)
self._get_results()
def _get_results(self):
if (self.__response.ok):
data = json.loads(self.__response.content)
results.append(
{
'result':data['result'],
'endpoint': self._endpoint,
'status' : response.status_code
}
)
else:
results.append(
{
'result':'FAILED',
'endpoint': self._endpoint,
'status' : response.status_code
}
)
def method(self, method):
# Here, we have to effectively call the selected method,
# hence the () at the end
self._methods[method]()
login = Call(
Url.V1_PROD,
DriverEndpoint.LOGIN,
DriverPayload.LOGIN,
Request.HEADER
)
login.method('post')
__methods= dict(post=self.__post(), get=self.__get())
Your __methods variable is class variable, self is used to refer to an instance of Call, self cannot access to the class variable scope.
You can declare __method as an instance variable:
def __init__(self):
self.__methods= dict(post=self.__post(), get=self.__get())
def get_mothods(self):
return self.__methods

How do I use urllib2 to post data to a sever?

I am making a python twitch.tv API Wrapper for python and so far I have :
import urllib2
import json
import time
waittime = 1
baseurl = 'https://api.twitch.tv/kraken/'
secret = '(CLASSIFIED)'
class twitchchannelinfo(): #Ignore me ;D I'm Here for reference's sake
def __init__ (self,channel):
self.channel = channel
time.sleep(waittime)
self.dict1 = json.loads(urllib2.urlopen(baseurl + 'channels/' + channel).read())
def getstatus(self):
return self.dict1 ['status']
def getdisplay_name(self):
return self.dict1 ['display_name']
def getmature(self):
return self.dict1 ['mature']
def getchanurl(self):
return self.dict1 ['url']
def getcreated_at(self):
return self.dict1 ['created_at']
def getteams(self):
return self.dict1 ['teams']
def getgame(self):
return self.dict1 ['game']
def getupdated_at(self):
return self.dict1 ['updated_at']
class twichtvwrapper():
def __init__(self,username,password):
self.username = username
self.password = password
self.dict1 = json.loads(urllib2.urlopen(baseurl + 'oauth2/token',\
"client_id=<3kfp6al05voejvv7ofmpc94g4jga0tb>&\
client_secret=<" + secret + ">&\
username=<" + self.username + ">&\
password=<" + self.password + ">&\
scope=user_read&\
grant_type=password"))
print self.dict1
me = twichtvwrapper('martincharles07','(CLASSIFIED)')
(The secret is an API identifier and the password has been retracted for obvious reasons ;D).
The server should return a JSON response like this:
{
"scope":["user_read"],
"access_token":"df4yofxyn2s7240ojfrh9chz8"
}
Here is the API reference.
The program crashes with the exception urllib2.HTTPError: HTTP Error 400: Bad Request. I don't know what I am doing wrong, is it the line splits or incorrect usage of urllib2? How can I fix it?
Instead of concatenating your string together try something like
body={'username':'someusername','password':'somepassword', ...}
txdata = urllib.urlencode(body)
You'll have to use urllib instead of urllib2 to use that method.
Here's an untested snippet.
import json
import urllib
import urllib2
def wrapper(user, password, secret):
data = {"client_id":"<3kfp6al05voejvv7ofmpc94g4jga0tb>",
"client_secret":secret,
"username":username,
"password":password,
"scope":"user_read",
"grant_type":"password",
}
txdata = urllib.urlencode(data)
response = urllib2.urlopen(baseurl + 'oauth2/token', txdata)
return_data = json.loads(response.read())
return return_data

Categories

Resources