How to save the header api at global - python

I have 2 functions which taking header of same. Can i save at global so that i no need to call every time
def funct1():
json_d = {"group_id": "uid"}
headers = {"account-id":"xxx","api-key":"xxx","Content-Type": "application/json"}
response = requests.post("https://example.com/docs",headers=headers,json=json_d)
def funct2():
json_d = {"group_id": "uid"}
headers = {"account-id":"xxx","api-key":"xxx","Content-Type": "application/json"}
response = requests.post("https://example.com/docs",headers=headers,json=json_d)
Can I do
headers = {"account-id":"xxx","api-key":"xxx","Content-Type": "application/json"}
global headers

i'd recommend making a function for a default http call.
In this case only the json_d is different per function. Maybe this will also be the URL or other things, you can easy move them up to the initial functions and parameterize them in the default_post() function.
Using **kwargs you can make it more generic, for example if you want to pass a timeout you can call default_post(..., timeout=3) which is passed automatically to the requests.post function.
Example
def funct1():
json_d_1 = {
"group_id": "uid_1"
}
default_post(json_d_1)
def funct2():
json_d_2 = {
"group_id": "uid_2"
}
default_post(json_d_2)
def default_post(json_d, ..., **kwargs):
headers = {"account-id":"xxx","api-key":"xxx","Content-Type": "application/json"}
response = requests.post(
"https://example.com/docs",
headers=headers,
json=json_d,
**kwargs
)
return response

I would suggest to create a function that will return the headers dictionary in order to "protect" it from changes:
def get_headers():
return {"account-id":"xxx","api-key":"xxx","Content-Type": "application/json"}
In this case at every call to the get_headers function new dictionary will be created so if you change it (the headers dictionary) in one function it does not effect the other function (unless what is that you are trying to achieve).

Related

Reuse methods from locust in different tests

I currently have this locust test:
import logging
from locust import HttpUser, TaskSet, task, constant
log = logging.getLogger("rest-api-performance-test")
def get_headers():
headers = {
"accept": "application/json",
"content-type": "application/json",
}
return headers
def headers_token(auth_token):
headers = {
"accept": "application/json",
"content-type": "application/json",
"auth-token": str(auth_token),
}
return headers
class LoginTasks(TaskSet):
def post_login(self):
headers = get_headers()
login_response = self.client.post("/api/auth",
json={"key": "cstrong#tconsumer.com", "secret": "cstrong"},
headers=headers, catch_response=False, name="Login")
login_data = login_response.json()
auth_token_value = login_data["results"][0]["auth-token"]
return auth_token_value
class UserTasks(UserTasks):
#task
def test_get_list_of_workers(self):
auth_token = self.post_login()
try:
with self.client.get("/api/client/workers",
headers=headers_token(auth_token), catch_response=True,
name="Get Worker Lists") as request_response:
if request_response.status_code == 200:
assert (
'"label": "Salena Mead S"' in request_response.text
)
request_response.success()
log.info("API call resulted in success.")
else:
request_response.failure(request_response.text)
log.error("API call resulted in failed.")
except Exception as e:
log.error(f"Exception occurred! details are {e}")
class WebsiteUser(HttpUser):
host = "https://test.com"
wait_time = constant(1)
tasks = [UserTasks]
the tests runs as expected but post_login is required by multiple tests since is the one who generates the authentication token used by most of the APIs that I'm testing, is there a way to avoid use inheritance from class LoginTasks and find a better solution? The reason I want to avoid it is post_login is not the only method that is going be used many times so I don't want to use multiple inheritance on my UserTasks class.
Any help is appreciated.
Move the function out of the class and pass in the client you want it to use.
def post_login(client):
headers = get_headers()
login_response = client.post("/api/auth",
…
You can then call it when you need it the same way you call get_headers().
auth_token = post_login(self.client)

Mocking variable and replacing it with object

I'd like to test this piece of code:
modify: UserModifyPort = _ports_.user_modify_port
#_app_.route(f"/user", methods=["POST"])
#headers_check({"Accept": "application/json", "Content-Type": "application/json"})
def create_user():
body_json = request.get_json()
body = UserCreateRequest(body_json["username"], body_json["password"])
cmd = UserCreateCmd(body.username, body.password)
# modify usage
user_id = modify.create_user(cmd)
response = UserCreateResponse(user_id)
return response.to_dict(), 201
In this test I need to mock a global variable modify and replace it with object. I've been trying to do this like that:
# TEST
#mock.patch("application.user.user_rest_adapter.modify")
def test_create_user_should_create(modify_mock, db_engine, client, user_config):
modify_mock.return_value = DatabaseUserModifyAdapter(db_engine, user_config)
response = client.post("/user", headers={"Accept": "application/json", "Content-Type": "application/json"},
json={"username": "GALJO", "password": "qwerty123"})
But it isn't executing modify.create_user() function, it just returns some weird object:
<MagicMock name='modify.create_user()' id='140375141136512'>
How can I make this function work?
I solved this issue with sort of workaround. Instead of mocking entire object I've mocked just function that I use. There is no need to use another function, because it is tested in other tests so I replaced it with constant value. I've only checked if given args are correct, everything else is other test task.
#mock.patch("application.user.user_rest_adapter.modify.create_user")
def test_create_user_should_create(create_user_mock, client):
# given
user_id = "a20d7a48-7235-489b-8552-5a081d069078"
create_user_mock.return_value = UUID(user_id)
# when
response = client.post("/user", headers={"Accept": "application/json", "Content-Type": "application/json"},
json={"username": "GALJO", "password": "qwerty123"})
# then
args = create_user_mock.call_args.args
assert args[0].username == "GALJO"
assert args[0].password == "qwerty123"
assert response.json["userID"] == user_id

Why json output so small?

This output should be way longer than it is in here.
I start with a GET request, I parse a JSON list and extract the id, which I then call on the second function, that will give me a second ID which then I will use to call on the 3rd function. But, I am only getting one entry whereas I should be getting way more entries.
The code is the following:
from requests.auth import HTTPBasicAuth
import requests
import json
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def countries():
data = requests.get("https://localhost:8543/api/netim/v1/countries/", verify=False, auth=HTTPBasicAuth("admin", "admin"))
rep = data.json()
return [elem.get("id","") for elem in rep['items']]
def regions():
for c in countries():
url = requests.get("https://localhost:8543/api/netim/v1/countries/{}/regions".format(c), verify=False, auth=HTTPBasicAuth("admin", "admin"))
response = url.json()
return [cid.get("id","") for cid in response['items']]
def city():
for r in regions():
api = requests.get("https://localhost:8543/api/netim/v1/regions/{}/cities".format(r), verify=False, auth=HTTPBasicAuth("admin", "admin"))
resolt = api.json()
return(json.dumps([{"name":r.get("name",""),"id":r.get("id", "")} for r in resolt['items']], indent=4))
city()
print(city())
The output is the following :
[
{
"name": "Herat",
"id": "AF~HER~Herat"
}
]
I should have a huge list, so I am not sure what am I missing?
You need to go through all the iterations of your loop and collect the results, then jsonify the and return them.
data = []
for r in regions():
api = requests.get("https://localhost:8543/api/netim/v1/regions/{}/cities".format(r), verify=False, auth=HTTPBasicAuth("admin", "admin"))
resolt = api.json()
data.extend([{"name":r.get("name",""),"id":r.get("id", "")} for r in resolt['items']])
return json.dumps(data, indent=4)
This would be a fix for city() but you have the same problem in all your functions. return immediately exits the function and does not do anything else, effectively all your for loops are doing 1 iteration.
I'll update my example here to give you a better idea what's occurring.
Your functions are basically this:
def test_fn():
for i in [1,2,3,4]:
return i
# output:
1
# We never see 2 or 3 or 4 because we return before looping on them.
What you want:
def test_fn():
results = []
for i in [1,2,3,4]:
results.append(i)
return results
# output
[1,2,3,4]
It seems like you understand that the for loop is going to take some action once for each element in the list. What you're not understanding is that return ends the function NOW. No more for loop, no more actions, and in your code, you immediately return inside the for loop, stopping any further action.

How can I post an image on Facebook using Python requests and Graph API?

1) I require a function which should publish a post with the given message and photo.
One can use the page ID and access tokens provided in self.page_id and self.page_access_token
def __init__(self):
self.page_id = Facebook.get_access_token('FACEBOOK_PAGE_ID')
self.page_access_token = Facebook.get_access_token('FACEBOOK_PAGE_ACCESS_TOKEN')
2) To find which API to hit, check out developer section of the Facebook API: https://developers.facebook.com/docs/graph-api/reference/page/photos/#example-2
3) The function should not return anything.
def publish_photo_msg(self, message, image_url):
#your code here
return
Please help.
python
params = (
('access_token', self.page_access_token),
)
Next, let us fix the data dictionary:
python
data = {
'url': image_url,
'caption': 'this is the caption'
}
Now, let’s proceed to the URL. There are many ways to set this. Here is one way:
python
url = 'https://graph.facebook.com/v5.0/' + self.page_id + '/photos?access_token=' + self.page_access_token
Since we have stored the access_token in the params tuple, let’s make use of it in the requests.post() call.
python
url = 'https://graph.facebook.com/v5.0/' + self.page_id + '/photos'
response = requests.post(url=url, params=params, data=data)
Lastly, you can also verify if your requests.post() call was successful by checking the value of the response variable:
python
print response.status_code, response.json()
For easy reference, here is the full implementation of the publish_photo_msg function with all the suggestions incorporated:
python
params = (
('access_token', self.page_access_token),
)
data = {
'url': image_url,
'caption': message
}
url = 'https://graph.facebook.com/v5.0/' + self.page_id + '/photos'
response = requests.post(url=url, params=params, data=data)
print(response.status_code, response.json())

Pass (optional) parameters to HTTP parameter (Python, requests)

I am currently working on an API Wrapper, and I have an issue with passing the parameters from a function, into the payload of requests. The parameters can be blockId, senderId, recipientId, limit, offset, orderBy. All parameters join by "OR". One possible solution could be having if statements for every combination, but I imagine that that is a terrible way to do it. (requests and constants are already imported)
def transactionsList(*args **kwargs):
if blockId not None:
payload = {'blockId': blockId}
if offset not None:
payload = {'offset': offset}
...
r = requests.get(constants.TRANSACTIONS_LIST, params=payload, timeout=constants.TIMEOUT)
return r
What is (or are) more elegant ways to achieve parameters of the function getting passed to the requests payload?
Shortest one:
PARAMS = ['blockid', 'senderid', 'recipientid', 'limit', 'offset', 'orderby']
payload = {name: eval(name) for name in PARAMS if eval(name) is not None}
After tinkering around with Pythonist answer (which didn't work because there was always a NameError), I have come up with this solution:
def transactionsList(*args, **kwargs):
payload = {name: kwargs[name] for name in kwargs if kwargs[name] is not None}
r = requests.get(constants.TRANSACTIONS_LIST, params=payload, timeout=constants.TIMEOUT)
# print(r.url)
return r
As you can see, the important part is the payload:
payload = {name: kwargs[name] for name in kwargs if kwargs[name] is not None}
As long as there is a parameter (name) in the kwargs array and if it's value isn't None, it'll be added to the payload.

Categories