Here is my Python method:
for time in (timedelta(hours=3), timedelta(minutes=30)):
delay = (datetime.now() + time).strftime('%Y-%m-%dT%H:%M:%S')
payload = json.dumps({
"channels": [
"accountID-{acct_id}".format(acct_id=account_id)
],
"push_time": delay,
"data": {
"alert": "Test Push",
"m": "12345"
},
})
try:
requests.post(
"https://api.parse.com/1/push",
data=payload,
headers={
"X-Parse-Application-Id": settings.PARSE_APPLICATION_ID,
"X-Parse-REST-API-Key": settings.PARSE_REST_API_KEY,
"Content-Type": "application/json"
}
)
except requests.exceptions.RequestException as e:
logging.getLogger().setLevel(logging.ERROR)
Here is my test:
#patch("requests.post")
def test_send_push_notifications_to_parse(self, post_mock):
post_mock.return_value = {"status": 200}
mailing = Mock()
mailing.name = "Foo Name"
mailing.account_id = 12345
mailing.mailing_id = 45
payload = json.dumps({
"channels": [
"accountID-12345"
],
"push_time": "2014-03-04T15:00:00",
"data": {
"alert": "Test Push",
"m": "12345"
},
})
send_push_notification_to_parse(mailing.account_id, mailing.mailing_id, mailing.name)
post_mock.assert_called_with(
"https://api.parse.com/1/push",
data=payload,
headers={
"X-Parse-Application-Id": settings.PARSE_APPLICATION_ID,
"X-Parse-REST-API-Key": settings.PARSE_REST_API_KEY,
"Content-Type": "application/json"
}
)
The test fails because the POST request is inside of a loop where the datetimeobject changes. How can I patch the datetime object to make my test pass?
Just mock datetime in your module:
#patch("your.module.datetime")
#patch("requests.post")
def test_send_push_notifications_to_parse(self, post_mock, dt_mock):
# set datetime.now() to a fixed value
dt_mock.now.return_value = datetime.datetime(2013, 2, 1, 10, 9, 8)
You bound datetime in your module with an import, and the above #patch decorator will replace that object with a mock.
If you need to test against multiple values, you can set the dt_mock.now.side_effect attribute instead; a list will cause the mock to return values one by one from that list on sequential calls, a method lets you produce a new value each time datetime.now() is called as needed.
Anyone stumbling on this old question like me can use freezegun that Lets your Python tests travel through time(like Interstellar:))
Related
I have the following code
import requests
import json
import sys
credentials_User=sys.argv[1]
credentials_Password=sys.argv[2]
email=sys.argv[3]
def auth_api(login_User,login_Password,):
gooddata_user=login_User
gooddata_password=login_Password
body = json.dumps({
"postUserLogin":{
"login": gooddata_user,
"password": gooddata_password,
"remember":1,
"verify_level":0
}
})
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
url="https://reports.domain.com/gdc/account/login"
response = requests.request(
"POST",
url,
headers=headers,
data=body
)
sst=response.headers.get('Set-Cookie')
return sst
def query_api(cookie,email):
url="https://reports.domain.com/gdc/account/domains/domain/users?login="+email
body={}
headers={
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cookie': cookie
}
response = requests.request(
"GET",
url,
headers=headers,
data=body
)
jsonContent=[]
jsonContent.append({response.text})
accountSettings=jsonContent[0]
print(accountSettings)
cookie=auth_api(credentials_User,credentials_Password)
profilehash=query_api(cookie,email)
The code itself works and sends a request to the Gooddata API.
The query_api() function returns JSON similar to below
{
"accountSettings": {
"items": [
{
"accountSetting": {
"login": "user#example.com",
"email": "user#example.com",
"firstName": "First Name",
"lastName": "Last Name",
"companyName": "Company Name",
"position": "Data Analyst",
"created": "2020-01-08 15:44:23",
"updated": "2020-01-08 15:44:23",
"timezone": null,
"country": "United States",
"phoneNumber": "(425) 555-1111",
"old_password": "secret$123",
"password": "secret$234",
"verifyPassword": "secret$234",
"authenticationModes": [
"SSO"
],
"ssoProvider": "sso-domain.com",
"language": "en-US",
"ipWhitelist": [
"127.0.0.1"
],
"links": {
"projects": "/gdc/account/profile/{profile_id}/projects",
"self": "/gdc/account/profile/{profile_id}",
"domain": "/gdc/domains/default",
"auditEvents": "/gdc/account/profile/{profile_id}/auditEvents"
},
"effectiveIpWhitelist": "[ 127.0.0.1 ]"
}
}
],
"paging": {
"offset": 20,
"count": 100,
"next": "/gdc/uri?offset=100"
}
}
}
The issue I am having is reading specific keys from this JSON Dict, I can use accountSettings=jsonContent[0] but that just returns the same JSON.
What I want to do is read the value of the project key within links
How would I do this with a dict?
Thanks
Based on your description, uyou have your value inside a list, (not a set. Foergt about set: sets are not used with JSON). Inside your list, you either your content as a single string, which then you'd have to parse with json.loads, or it is simply a well behaved nested data structure already extracted from JSON, but which is inside a single element list. This seems the most likely.
So, you should be able to do:
accountlink = jsonContent[0]["items"][0]["accountSetting"]["login"]
otherwise, if it is encoded as a a json string, you have to parse it first:
import json
accountlink = json.loads(jsonContent[0])["items"][0]["accountSetting"]["login"]
Now, given your question, I'd say your are on a begginer level as a programmer, or a casual user, just using Python to automatize something either way, I'd recommend you do try some exercising before proceeding: it will save you time (a lot of time). I am not trying to bully or mock anything here: this is the best advice I can offer you. Seek for tutorials that play around on the interactive mode, rather than trying entire programs at once that you'd just copy and paste.
Using the below code fixed the issue
jsonContent=json.loads(response.text)
print(type(jsonContent))
test=jsonContent["accountSettings"]["items"][0]
test2=test["accountSetting"]["links"]["self"]
print(test)
print(test2)
I believe this works because for some reason I didn't notice I was using .append for my jsonContent. This resulted in the data type being something other than it should have been.
Thanks to everyone who tried helping me.
I've got a little utility function built like this to grab data from another applications API:
# app/utils.py
import json
import requests
from django.conf import settings
def get_future_assignments(user_id):
"""gets a users future assignments list from the API
Arguments:
user_id {int} -- user_id for a User
"""
headers = {
"User-Agent": "Mozilla/5.0",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With": "XMLHttpRequest",
}
api_app = settings.ASSIGNMENTS_API_ROOT_URL # http://project.org/appname/
api_model = "futureassignments/"
api_query = "?user_id=" + str(user_id)
json_response = requests.get(
api_app + api_model + api_query, headers=headers, verify=False
)
return json.loads(json_response.content)
It basically builds the API call and returns the response data - I'd like to test this.
# tests/test_utils.py
import mock
from unittest.mock import patch, Mock
from django.test import TestCase
from app.utils import get_future_assignments
class UtilsTest(TestCase):
def setUp(self):
self.futureassignments = [
{
"id": 342,
"user_id": 18888,
"job": 361,
"location": "1234",
"building": "Building One",
"confirmed_at": None,
"returning": None,
"signature": None,
},
{
"id": 342,
"user_id": 18888,
"job": 361,
"location": "1235",
"building": "Building Two",
"confirmed_at": None,
"returning": None,
"signature": None,
},
]
#patch("app.utils.get_future_assignments")
def test_get_future_assignments_with_multi_assignments(self, mock_gfa):
"""
Test for getting future assignments for a user with mocked API
"""
mock_gfa.return_value = Mock()
# set the json response to what we're expecting
mock_gfa.return_value.json.return_value = self.futureassignments
assignments = get_future_assignments(18888)
self.assertEqual(len(assignments), 2)
It keeps giving me an error that it can't reach the API to get a response (which is expected at the moment - since I'm running it locally and it cannot hit the API)
I'm new to using Mock - so maybe I'm way, way off base here.
Any ideas?
Like you, I am also new to using mock. I believe it's intended to work like this:
#patch("requests.get")
def test_get_future_assignments_with_multi_assignments(self, mock_requests_get):
"""
Test for getting future assignments for a user with mocked API
"""
mock_requests_get.return_value = json.dumps(self.futureassignments)
assignments = get_future_assignments(18888)
self.assertEqual(len(assignments), 2)
Please correct me if I'm wrong!
I would like to pass two parameters to my url(status code & parent id). The json response of the url request is such :
{
"page": 1,
"per_page": 10,
"total": 35,
"total_pages": 4,
"data": [
{
"id": 11,
"timestamp": 1565193225660,
"status": "RUNNING",
"operatingParams": {
"rotorSpeed": 2363,
"slack": 63.07,
"rootThreshold": 0
},
"asset": {
"id": 4,
"alias": "Secondary Rotor"
},
"parent": {
"id": 2,
"alias": "Main Rotor Shaft"
}
}]
I would like to know how to pass the two parameters in the url. Passing ?status=RUNNING gives the response of all the devices which have running as status (thats pretty straightforward).
For now I have tried this:
import requests
resp = requests.get('https://jsonmock.hackerrank.com/api/iot_devices/search?status=RUNNING')
q = resp.json()
print(q)
How should I pass in parentid=2, so it returns a response with devices which have their parent id=2.Thank you.
It's plainly documented under "Passing Parameters in URLs" in the Requests docs.
resp = requests.get(
'https://jsonmock.hackerrank.com/api/iot_devices/search',
params={
'status': 'RUNNING',
'parentid': 2,
},
)
To add a second get parameter, use the & separator :
import requests
resp = requests.get('https://jsonmock.hackerrank.com/api/iot_devices/search?status=RUNNING&parentid=2')
q = resp.json()
print(q)
If you want to send data via get request the process is straight forward note how different values are seperated with '&'.
url?name1=value1&name2=value2
If you are using Flask for backend then you can access these parameters like.
para1=request.args.get("name1")
para2=request.args.get("name2")
On the front end you can use ajax to send the request
var xhttp=new XMLHttpRequest();
var url="url?name1=value1&name2=value2"
xhttp.open("GET",url,true)
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200)
{
console.log(this.responseText);
}
};
xhttp.send();
In a whole context of trying to combine 2 APIs, I need to "combine" two functions results so that everything is more organized.
def descr():
return 88
def name():
return 'Account',descr()
When I print name(), I get this ('Account', 88). Problem with that format is that I can't use this result later in my script.
Here is the whole script :
import requests
import json
url = "https://proxy6.net/api/xxx/getproxy"
def descr():
return 88
def name():
return 'Account',descr()
querystring = {"descr":descr()}
headers = {
'Cache-Control': "no-cache",
'Postman-Token': "xxxx"
}
response = requests.request("GET", url, headers=headers, params=querystring)
data = response.json()
for value in data['list'].values():
host = value['host']
port = value['port']
url = "https://api.multiloginapp.com/v1/profile/create"
querystring = {"token":"xxx"}
payloadobj = {
"generateZeroFingerprintsData": True,
"name": name(),
"OS": "MacOS",
"platform": "MacIntel",
"browserType": "mimic",
"proxyHost": host,
"proxyPort": port,
"proxyIpValidation": False,
"proxyType": "socks5",
"maskFonts": True,
"disablePlugins": True,
"disableWebrtcPlugin": True,
"disableFlashPlugin": True,
"canvasDefType": "noise",
"hardwareConcurrency": 2,
"langHdr": "en-US,en;q=0.8",
"timeZone": "US/Eastern",
"audio": {
"noise": True
},
"geolocation": {
"permitType": "block"
},
"mediaDevices": {
"audioInputs": 1,
"audioOutputs": 1,
"videoInputs": 1
},
"webgl": {
"noise": True
},
"webRtc": {
"type": "block"
},
"shared": False
}
payload = json.dumps(payloadobj)
headers = {
'Content-Type': "application/json",
'Cache-Control': "no-cache",
'Postman-Token': "xxx"
}
response = requests.request("POST", url, data=payload, headers=headers, params=querystring)
print(response.text)
I want the name value in the JSON query above to be the result of name + descr, but it won't work with that returned format.
Looks like you need.
def descr():
return 88
def name():
return '{} {}'.format('Account', descr())
print(name())
Output:
Account 88
name() is returning a tuple object not a string. To return a string you could change it to:
def name():
return "Account {}".format(descr())
If you are using python3.6 or later you can:
def descr():
return 88
def name():
return f"Account {descr()}"
I have this python code below and it works for creating a event in Outlook Calendar. The example below has Start and End time from 3pm to 4pm (I think UTC timezone)
We have users from different regions (Pacific, Mountain, Central... times). What I try to accomplish is the time always be local time. No matter where the user account from it should also default to 3pm to 4pm in their Outlook.
Thanks in advance and please let me know if I need to clarify any of this.
# Set the request parameters
url = 'https://outlook.office365.com/api/v1.0/me/events?$Select=Start,End'
user = 'user1#domain.com'
pwd = getpass.getpass('Please enter your AD password: ')
# Create JSON payload
data = {
"Subject": "Testing Outlock Event",
"Body": {
"ContentType": "HTML",
"Content": "Test Content"
},
"Start": "2016-05-23T15:00:00.000Z",
"End": "2016-05-23T16:00:00.000Z",
"Attendees": [
{
"EmailAddress": {
"Address": "user1#domain.com",
"Name": "User1"
},
"Type": "Required" },
{
"EmailAddress": {
"Address": "user2#domain.com",
"Name": "User2"
},
"Type": "Optional" }
]
}
json_payload = json.dumps(data)
# Build the HTTP request
opener = urllib2.build_opener(urllib2.HTTPHandler)
request = urllib2.Request(url, data=json_payload)
auth = base64.encodestring('%s:%s' % (user, pwd)).replace('\n', '')
request.add_header('Authorization', 'Basic %s' % auth)
request.add_header('Content-Type', 'application/json')
request.add_header('Accept', 'application/json')
request.get_method = lambda: 'POST'
# Perform the request
result = opener.open(request)
First of all, there's no point of creating a meeting on the same time at different timezones.
If you really want to do so, you'll need to create separate meeting requests per the timezone of the attendees, the JSON format would be something like below,
var body = new JObject
{
{"Subject", "Testing Outlock Event"},
{"Start", new JObject { { "DateTime", "2016-03-24T15:00:00"}, { "TimeZone", "Pacific Standard Time" } } },
{"End", new JObject { { "DateTime", "2016-03-24T16:00:00"}, { "TimeZone", "Pacific Standard Time" } } }
};
Note you need to remove the capital 'Z' from the time, so that it'll be shown in the local time tone specified by the "TimeZone" attribute.
The workaround above needs to know the timezone of all the attendees, I'm not sure if this can be done pragmatically. If not, it might not make much sense if you have tones of attendees.
The "ideal" way of achieving your requirement is giving the time without specifying the timezone, so that it'll be shown at the same time with different timezone.
However, it's not supported yet, but you can vote here https://officespdev.uservoice.com/forums/224641-general/suggestions/12866364-microsoft-graph-o365-unified-api-create-events-w