Mock a part of function that calls get using Python - python

I have troubles to test my function using the mock. This function take an url as parameter then return an GeoDataFrame. At first I have to stimulate the response of get request (Json format).
Function to test
def download_stations_from_url(url):
response = requests.get(url)
data = response.json()
gdf = gpd.GeoDataFrame.from_features(data['features'])
gdf.crs = {'init': 'epsg:32188'}
return gdf.to_crs(epsg=4326)
Test using Mock
from py_process.app import download_stations_from_url
#patch('py_process.app.download_stations_from_url')
def test_download_stations_from_url(self, mock_requests_json):
mock_requests_json.return_value.status_code = 200
mock_requests_json.return_value.json.return_value = {
"features": [{
"geometry": {
"coordinates": [
299266.0160258789,
5039428.849663065
],
"type": "Point"
},
"type": "Feature",
"properties": {
"valide_a": 99999999,
"MUNIC": "Montreal",
"X": 299266.016026,
"xlong": -73.5708055439,
"Parking": 0,
"Y": 5039428.84966,
"NOM": "Gare Lucien-L'Allier",
"ylat": 45.4947606844
}
}]
}
response = download_stations_from_url('http://www.123.com')
assert response.status_code == 200

You need to mock requests.get, not the function you are actually testing.
from py_process.app import download_stations_from_url
#patch('py_process.app.requests.get')
def test_download_stations_from_url(self, mock_requests_json):
mock_requests_json.return_value.status_code = 200
mock_requests_json.return_value.json.return_value = {
"features": [{
"geometry": {
"coordinates": [
299266.0160258789,
5039428.849663065
],
"type": "Point"
},
"type": "Feature",
"properties": {
"valide_a": 99999999,
"MUNIC": "Montreal",
"X": 299266.016026,
"xlong": -73.5708055439,
"Parking": 0,
"Y": 5039428.84966,
"NOM": "Gare Lucien-L'Allier",
"ylat": 45.4947606844
}
}]
}
df = download_stations_from_url('http://www.123.com')
# Wrong:
# assert response.status_code == 200
# Right:
# Make assertions about the DataFrame you get back.

Related

Python request to get altitude from a GeoJSON file

I want to get the elevation of a segment (linestring) from a GeoJSON file.
I'm using this API:
Documentation: https://api3.geo.admin.ch/services/sdiservices.html#profile
request URL: https://api3.geo.admin.ch/rest/services/profile.csv
My problem is that I cannot get rid of an error saying the passed parameter 'geom' is not of GeoJSON type.
My geojson file:
{
"type": "FeatureCollection",
"name": "test",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "Name": null, "description": "", "altitudeMode": "clampToGround", "tessellate": 1, "type": "linepolygon" }, "geometry": { "type": "LineString", "coordinates": [ [ 7.349510580151255, 45.998132989830559 ], [ 7.346422156898689, 46.039529058312063 ], [ 7.287112064012824, 46.093617348068292 ], [ 7.236173542687846, 46.127135334945002 ] ] } }
]
}
My code:
import requests
import json
api_url = "https://api3.geo.admin.ch/rest/services/profile.csv"
file_path = "geojson.GEOJSON"
with open(file_path) as f:
geojson = json.load(f)
r = requests.get(api_url, params=dict(geom=geojson))
print(r.json())
Output:
{'error': {'code': 400, 'message': 'Invalid geom parameter, must be a GEOJSON'}, 'success': False}
Edit: Solution
import requests
import json
api_url = "https://api3.geo.admin.ch/rest/services/profile.csv"
file_path = "geojson.GEOJSON"
with open(file_path) as f:
geojson, = json.load(f)['features']
geom = json.dumps(geojson['geometry'])
r = requests.get(api_url, params=dict(geom=geom))
print(r.content)
Look at the example in the docs. The API wants a single geometry, something like {"type": "LineString", "coordinates": [[1,2], [3,4]]}; you are giving it an entire FeatureCollection.

Spotify API: Error parsing through JSON with Python

I have had trouble appending id's to a separate list as I parse through the JSON I receive from Spotify's "Users Saved Tracks" endpoint.
The JSON received looks like this:
{
"href": "https://api.spotify.com/v1/me/tracks?offset=0&limit=20",
"items": [
{
"added_at": "2021-11-16T13:56:51Z",
"track": {
"album": {
"album_type": "single",
"artists": [
{
"external_urls": {
"spotify": "https://open.spotify.com/artist/3iKDeO8yaOiWz7vkeljunk"
},
"href": "https://api.spotify.com/v1/artists/3iKDeO8yaOiWz7vkeljunk",
"id": "3iKDeO8yaOiWz7vkeljunk",
"name": "Heavenward",
"type": "artist",
"uri": "spotify:artist:3iKDeO8yaOiWz7vkeljunk"
}
],
"available_markets": [
],
"disc_number": 1,
"duration_ms": 224838,
"explicit": false,
"external_ids": {
"isrc": "QZK6P2040977"
},
"external_urls": {
"spotify": "https://open.spotify.com/track/6mJ1nbmQOm6iNClo71K5O6"
},
"href": "https://api.spotify.com/v1/tracks/6mJ1nbmQOm6iNClo71K5O6",
"id": "6mJ1nbmQOm6iNClo71K5O6",
"is_local": false,
"name": "Hole",
"popularity": 33,
"preview_url": "https://p.scdn.co/mp3-preview/c425dc91bdb19f1cddf2b35df08e30a03290c3c0?cid=8c9ee97b95854163a250399fda32d350",
"track_number": 1,
"type": "track",
"uri": "spotify:track:6mJ1nbmQOm6iNClo71K5O6"
}
}
Right now my code that I am using to parse looks like this:
def getLikedTrackIds(session):
url = 'https://api.spotify.com/v1/me/tracks'
payload = makeGetRequest(session, url)
if payload == None:
return None
liked_tracks_ids = []
for track in payload['items']:
for attribute in track['track']:
if (attribute == 'id'):
app.logger.info(f"\n\nTrack ID: {attribute}")
liked_tracks_ids.append(attribute)
return liked_tracks_ids
My liked_track_ids is filled with the string "id", for each song:
[ "id", "id", "id", "id"....]
Can anyone provide insight as to what I am doing wrong?
Already commented under the question but your code can be simplified by getting rid of the loop:
def getLikedTrackIds(session):
url = 'https://api.spotify.com/v1/me/tracks'
payload = makeGetRequest(session, url)
if payload == None:
return None
liked_tracks_ids = []
for track in payload['items']:
liked_id = track['track'].get('id', None)
if liked_id:
app.logger.info(f"\n\nTrack ID: {liked_id}")
liked_tracks_ids.append(liked_id)
return liked_tracks_ids

Python post request, problem with posting

I'm trying to write a typeform bot but I am a totally beginner so I have problems with request.post
I am trying to fill this typeform: https://typeformtutorial.typeform.com/to/aA7Vx9
by this code
import requests
token = requests.get("https://typeformtutorial.typeform.com/app/form/result/token/aA7Vx9/default")
data = {"42758279": "true",
"42758410": "text",
"token": token}
r = requests.post("https://typeformtutorial.typeform.com/app/form/submit/aA7Vx9", data)
print(r)
I think that something is wrong with "data" and I am not sure if I use token in a good way. Could you help me?
So, first of all, you need to get another field with the token. To do that, you should pass the header 'accept': 'application/json' in your first request. In the response, you'll get the json object with the token and landed_at parameters. You should use them in the next step.
Then, the post data shoud be different from what you're passing. See the network tab in the browser's developer tools to find out the actual template. It has a structure like that:
{
"signature": <YOUR_SIGNATURE>,
"form_id": "aA7Vx9",
"landed_at": <YOUR_LANDED_AT_TIME>,
"answers": [
{
"field": {
"id": "42758279",
"type": "yes_no"
},
"type": "boolean",
"boolean": True
},
{
"field": {
"id": "42758410",
"type": "short_text"
},
"type": "text",
"text": "1"
}
]
}
And finally, you should convert that json to text so the server would successfully parse it.
Working example:
import requests
import json
token = json.loads(requests.post(
"https://typeformtutorial.typeform.com/app/form/result/token/aA7Vx9/default",
headers={'accept': 'application/json'}
).text)
signature = token['token']
landed_at = int(token['landed_at'])
data = {
"signature": signature,
"form_id": "aA7Vx9",
"landed_at": landed_at,
"answers": [
{
"field": {
"id": "42758279",
"type": "yes_no"
},
"type": "boolean",
"boolean": True
},
{
"field": {
"id": "42758410",
"type": "short_text"
},
"type": "text",
"text": "1"
}
]
}
json_data = json.dumps(data)
r = requests.post("https://typeformtutorial.typeform.com/app/form/submit/aA7Vx9", data=json_data)
print(r.text)
Output:
{"message":"success"}

Python dictionary from schema

I need to check if all the keys declared in a schema file are present in a dictionary and if they are not, I need to fill them with a default value, of a given type. I need to do this dynamically because the structure can be even more complicated than the one below.
{
"type": "object",
"properties": {
"vid": {
"type": ["null", "integer"]
},
"merged-vids": {
"type": ["null", "array"],
"items": {
"type": ["null", "integer"]
}
},
"portal-id": {
"type": ["null", "integer"]
},
"is-contact": {
"type": ["null", "boolean"]
}
"form-submissions": {
"type": ["null", "array"],
"items": {
"type": ["null", "object"],
"properties": {
"conversion-id": {
"type": ["null", "string"]
},
"timestamp": {
"type": ["null", "string"],
"format": "date-time"
},
"form-id": {
"type": ["null", "string"]
},
"portal-id": {
"type": ["null", "integer"]
},
"page-url": {
"type": ["null", "string"]
},
"title": {
"type": ["null", "string"]
}
}
}
}
}
}
This is an example of dictionary:
{
"vid": 1000,
"portal-id": 2512,
"is-contact": true,
"profile-token": "dummy_profile_token",
"profile-url": "dummy_profile_url",
"form-submissions": [
{
"conversion-id": "127-798",
"timestamp": 1484080167266,
"form-id": "70fd-4b98-14796-777",
"page-url": "https://example.com/landing-page-url",
"title": "A new test form",
"meta-data": []
}
]
}
I am also new to python and this is a bit too much.
This is what I tried, but I cannot figure out what to do.
def get_default(type_object):
if type_object == 'object':
new_dict = {}
elif type_object == 'array':
return []
else:
return ''
def fill_fields_with_empty_str(record, schema):
if isinstance(schema['type'], list):
type_obj = schema['type'][len(schema['type'])-1]
elif isinstance(schema['type'], str):
type_obj = schema['type']
if type_obj == 'object':
new_dict = {}
for key in schema['properties'].keys():
if not record.get(key):
record[key] = get_default(schema['properties'][key]['type'])
new_dict[key] = fill_fields_with_empty_str(record[key], schema['properties'][key])
return new_dict
elif type_obj == 'array':
new_list = []
type_obj = schema["items"]['type']
if len(record) == 0:
record = get_default(type_obj)
for element in schema["items"]:
new_list.append(fill_fields_with_empty_str(record, schema['items']))
return new_list
else:
return ''

python rename field json with specific structure

i have a json with structure:
{
" features": [
{
"geometry": {
"type": "Polygon",
"coordinates": []
},
"type": "Feature",
"properties": {
"ADMIN_LEVE": "REGION",
"POPULTION": 4363916,
"GEO_CENTER": "7.923209152686669, 45.06052300898206",
"ID": "01",
"NAME": "PIEMONTE"
}
}
]
}
and i need to rename the field "ADMIN_LEVE".
I have write a code using pandas to rename but doesn't work
df = pd.DataFrame(data)
df.rename(columns={'ADMIN_LEVE':'ADMIN_LEVEL'}, inplace=True)
I can i do it?
i have also tryied with replace but doesn't work
json_data=open(path + ".json").read()
data = json.loads(json_data)
for d in data:
d.replace('"ADMIN_LEVE"', '"ADMIN_LEVEL"')
Thanks
Source JSON (as string):
In [325]: print(s)
{
" features": [
{
"geometry": {
"type": "Polygon",
"coordinates": []
},
"type": "Feature",
"properties": {
"ADMIN_LEVE": "REGION",
"POPULTION": 4363916,
"GEO_CENTER": "7.923209152686669, 45.06052300898206",
"ID": "01",
"NAME": "PIEMONTE"
}
}
]
}
Replaced:
In [327]: s = s.replace('"ADMIN_LEVE":', '"ADMIN_LEVEL":')
In [328]: print(s)
{
" features": [
{
"geometry": {
"type": "Polygon",
"coordinates": []
},
"type": "Feature",
"properties": {
"ADMIN_LEVEL": "REGION",
"POPULTION": 4363916,
"GEO_CENTER": "7.923209152686669, 45.06052300898206",
"ID": "01",
"NAME": "PIEMONTE"
}
}
]
}
UPDATE: helper function:
def replace_in_json_file(filename, from_str, to_str):
with open(filename) as f:
data = f.read()
with open(filename, 'w') as f:
f.write(data.replace(from_str, to_str))

Categories

Resources