Assignment 07
Solutions to Assignment 07.
Nominatim OSM Search
Write a program nominatim.py to search for a place in Open Street Map using Nominatim API.
The API
$ curl 'https://nominatim.openstreetmap.org/search.php?q=bangalore&format=jsonv2'
[
{
"place_id": 216751017,
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright",
"osm_type": "relation",
"osm_id": 7902476,
"lat": "12.9767936",
"lon": "77.590082",
"category": "boundary",
"type": "administrative",
"place_rank": 16,
"importance": 0.6094348238975636,
"addresstype": "city",
"name": "Bengaluru",
"display_name": "Bengaluru, Bangalore North, Bengaluru Urban District, Karnataka, India",
"boundingbox": [
"12.8340125",
"13.1436649",
"77.4601025",
"77.7840515"
]
}
]
The Nominatum API returns the information about the matched locations. There could be zero, one, or more matches.
The Program
The program is expected to take the place name as a command-line argument and print the display_name, type, lat and lon for every match from the nominatum search for that place, as shown in the examples below.
$ python nominatum.py Bangalore
Bengaluru, Bangalore North, Bengaluru Urban District, Karnataka, India
Type: administrative
Latitude: 12.9767936
Longitude: 77.590082
When there are multiple matches, they are separated by a new line.
$ python nominatum.py "silk board"
Silk Board, Outer Ring Road, BTM 2nd Stage, BTM Layout Ward, South Zone, Bengaluru, Bangalore South, Bengaluru Urban District, Karnataka, 560034, India
Type: bus_stop
Latitude: 12.9170295
Longitude: 77.6223209
Silk Board, Srinagar - Kanyakumari Highway, HSR Layout Ward, Bommanahalli Zone, Bengaluru, Bangalore South, Bengaluru Urban District, Karnataka, 560034, India
Type: bus_stop
Latitude: 12.9167972
Longitude: 77.6235628
Sometimes there could be a lot of matches.
$ python nominatum.py Google
Google, 355, Main Street, East Cambridge, Cambridge, Middlesex County, Massachusetts, 02142, United States
Type: company
Latitude: 42.3627717
Longitude: -71.087257
Google, West Bluff Creek Drive, Playa Vista, Los Angeles, Los Angeles County, California, 90094, United States
Type: company
Latitude: 33.977092
Longitude: -118.4092133
Google, Mountain View, Santa Clara County, California, United States
Type: commercial
Latitude: 37.419000999999994
Longitude: -122.08237596053958
Google, 150, Broadway, East Cambridge, Cambridge, Middlesex County, Massachusetts, 02142, United States
Type: company
Latitude: 42.3642662
Longitude: -71.0887198
Googal, Devadurga taluk, Raichur District, Karnataka, India
Type: village
Latitude: 16.4693278
Longitude: 77.1442219
Google, Kirkland, King County, Washington, United States
Type: commercial
Latitude: 47.6705578
Longitude: -122.19707375045999
Solution
import requests
import sys
url = "https://nominatim.openstreetmap.org/search.php"
def search(q):
params = {"q": q, "format": "jsonv2"}
result = requests.get(url, params=params).json()
for entry in result:
print(entry['display_name'])
print("Type:", entry['type'])
print("Latitude:", entry['lat'])
print("Longitude:", entry['lon'])
print("")
name = sys.argv[1]
search(name)Client for Free Dictionary API
Write a program dict.py to find the meaning of a word using the Free Dictionary API.
Expected Usage
The program should take one word as argument and display the phonetics and meaning of that word using the Free Dictionary API.
$ python dict.py obscure
onscure /əbˈskjɔː(ɹ)/
VERB
To render obscure; to darken; to make dim; to keep in the dark; to hide; to make less visible, intelligible, legible, glorious, beautiful, or illustrious.
To hide, put out of sight etc.
To conceal oneself; to hide.
ADJECTIVE
Dark, faint or indistinct.
Hidden, out of sight or inconspicuous.
As you can see, The first line in the word and its phonetic. For each part of speech, the part of speech is shown in uppercase, followed by each of the meaning provided in the response. There will be exactly one new line after each meaning and part-of-speech line.
Solution
import sys
import requests
word = sys.argv[1]
url = f"https://api.dictionaryapi.dev/api/v2/entries/en/{word}"
d = requests.get(url).json()[0]
print(f"{d['word']} {d['phonetic']}")
print()
for m in d['meanings']:
print(m['partOfSpeech'].upper())
print()
for definition in m['definitions']:
print(definition['definition'])
print()
Frankfurter Exchange Rates
Write a program frankfurter.py to list the historical currency rate of a currency against a base currency using Frankfurter Exchange Rate API.
The program should take the following command-line arguments.
-c CURRENCY, --currency CURRENCY
target currency, default INR
-b BASE, --base BASE base currency, default USD
-d DATE, --date DATE First date to consider, default yesterday
-n DAYS, --days DAYS number of days to display
The program should display the curreny rate between the base currency and the target currency for n days starting from yesterday. Optionally, the start date could be provided as a command-line argument.
Please note that there convertion data is not available on weekends. So the number of rows of data shown may be less than n.
The Output Format
The output needs to be properly tabulated. Please use Python library tabulate for doing this.
Please refer to Printing Tables with Tabulate in the Python Cookbook to learn how to the the tabulate library.
Usage
$ python frankfurter.py
Date USD INR
---------- ----- -----
2023-10-18 1 83.25
2023-10-17 1 83.22
2023-10-16 1 83.25
2023-10-13 1 83.27
2023-10-12 1 83.24
2023-10-11 1 83.18
2023-10-10 1 83.24
2023-10-09 1 83.3
$ python frankfurter.py -n 2
Date USD INR
---------- ----- -----
2023-10-18 1 83.25
2023-10-17 1 83.22
$ python frankfurter.py -b GBP
Date GBP INR
---------- ----- ------
2023-10-18 1 101.55
2023-10-17 1 101.31
2023-10-16 1 101.37
2023-10-13 1 101.41
2023-10-12 1 102.47
2023-10-11 1 102.24
2023-10-10 1 101.96
2023-10-09 1 101.39
$ python frankfurter.py -b GBP -c USD
Date GBP USD
---------- ----- ------
2023-10-18 1 1.2198
2023-10-17 1 1.2173
2023-10-16 1 1.2176
2023-10-13 1 1.2178
2023-10-12 1 1.231
2023-10-11 1 1.2292
2023-10-10 1 1.2249
2023-10-09 1 1.2172
$ python frankfurter.py -d 2023-01-31
Date USD INR
---------- ----- -----
2023-01-31 1 81.82
2023-01-30 1 81.53
2023-01-27 1 81.61
2023-01-26 1 81.53
2023-01-25 1 81.57
2023-01-24 1 81.62
2023-01-23 1 81.36
Hints
- See Working with dates in the Python Cookbook.
- See Printing Tables with Tabulate in the Python Cookbook.
Solution
import argparse
import datetime
import requests
from tabulate import tabulate
p = argparse.ArgumentParser()
p.add_argument("-c", "--currency", help="currency to list, default INR", default="INR")
p.add_argument("-b", "--base", help="base currency, default USD", default="USD")
p.add_argument("-d", "--date", help="starting date, default yesterday", type=datetime.date.fromisoformat)
p.add_argument("-n", "--days", help="number of days to display", type=int, default=10)
args = p.parse_args()
yday = datetime.date.today() - datetime.timedelta(days=1)
start_date = args.date or yday
date2 = start_date - datetime.timedelta(days=args.days)
url = f"https://api.frankfurter.app/{date2}..{start_date}"
params = {"base": args.base, "to": args.currency}
result = requests.get(url, params=params).json()
headers = ["Date", args.base, args.currency]
data = [[date, 1.0, value[args.currency]] for date, value in result['rates'].items()][::-1]
print(tabulate(data, headers=headers))PyPI Releases
Overview
Python Package Index (PyPI) maintains an index of all the third-party python packages. It also provides an API to look at all the releases of a package.
Write a command line program `pypi-releases.py to list all the releases of a given package using the PyPI API.
The program should take the package name as argument and list all the releases along with the release time and filename uploaded for that release, in the reverse chronological order of the release time. By default, it should show the recent 5 releases.
The program should accept the following optional command-line arguments.
-n --count number of releases to show
-b --before only show release on or before this date
-a --after only show releases that are on or after this date
-r --reverse show the release in the reverse order - old releases first
You can use the upload_time as an approximation for the release time. Typically, there would multiple files uploaded for each release and all of them will be listed in the response of the API. Please use first entry where the packagetype is sdist. If a release does not have an entry with packagetype with value sdist, please ignore that release.
The PyPI API
The PYPI API documentation has two endpoints. The first one is to fecth the information about all releases of a project or a package. The second one is to get information about one particular release. We are only interested in the first one.
The following is the URL for getting information about releases of python package Flask. You can replace Flask with any package name to get information about that package.
https://pypi.org/pypi/Flask/json
You’ll have to explore the API response and figure out which part of the data that you need to take.
Hint: You just need to focus on the releases part of the response.
The Output Format
The output needs to be properly tabulated. Please use Python library tabulate for doing this.
Please refer to Printing Tables with Tabulate in the Python Cookbook to learn how to the the tabulate library.
Sample Usage
$ python pypi-releases.py Flask
Package Version Release Date Filename
--------- --------- ------------------- ------------------
Flask 3.0.0 2023-09-30T14:36:12 flask-3.0.0.tar.gz
Flask 2.3.3 2023-08-21T19:52:35 flask-2.3.3.tar.gz
Flask 2.2.5 2023-05-02T14:42:36 Flask-2.2.5.tar.gz
Flask 2.3.2 2023-05-01T15:42:12 Flask-2.3.2.tar.gz
Flask 2.3.1 2023-04-25T21:20:31 Flask-2.3.1.tar.gz
$ python pypi-releases.py Flask -b 2022-06
Package Version Release Date Filename
--------- --------- ------------------- ------------------
Flask 2.1.2 2022-04-28T17:47:40 Flask-2.1.2.tar.gz
Flask 2.1.1 2022-03-30T21:38:32 Flask-2.1.1.tar.gz
Flask 2.1.0 2022-03-28T19:15:15 Flask-2.1.0.tar.gz
Flask 2.0.3 2022-02-14T20:01:09 Flask-2.0.3.tar.gz
Flask 2.0.2 2021-10-04T14:34:54 Flask-2.0.2.tar.gz
$ python pypi-releases.py Flask -a 2022-06 -r
Package Version Release Date Filename
--------- --------- ------------------- ------------------
Flask 2.1.3 2022-07-13T20:56:00 Flask-2.1.3.tar.gz
Flask 2.2.0 2022-08-02T00:14:12 Flask-2.2.0.tar.gz
Flask 2.2.1 2022-08-03T23:52:25 Flask-2.2.1.tar.gz
Flask 2.2.2 2022-08-08T23:26:33 Flask-2.2.2.tar.gz
Flask 2.2.3 2023-02-15T22:43:57 Flask-2.2.3.tar.gz
Solution
Gist Lib
Write a python librart gist_lib.py to work with Github gists.
Github gists are quick way to save snippets of code. Here is a sample gist:
https://gist.github.com/PipalBot/a879fd2964b8afb2d7dac9034e656a71
The Interface
The python library should have the following functions.
get_gists(user)
Returns the ids of the recent 30 gists of the user.
>>> get_gists("PipalBot")
["afb5fef5669dddfd188c0ab403f8b096", "8648e51af65eae3317de7937e12a7ad2", ...]
get_files(gist_id)
Returns a dictionary with keys filename, contents for each file available in the gist.
>>> get_files("079c99c487c137bbb4b5e8a5fa134f49")
[{"filename": "README.md", "contents": "Hello World"}]
The API
Please look at Gists section in the Github API docs.
The two endpoints that you may need to understand are:
- https://docs.github.com/en/rest/gists/gists?apiVersion=2022-11-28#list-gists-for-a-user
- https://docs.github.com/en/rest/gists/gists?apiVersion=2022-11-28#get-a-gist
Quick summary of the API
List gists of a user
https://api.github.com/users/anandology/gists
(replace anandology with any github username)
The JSON response includes first 30 gists of that user. You just need to pick the IDs of the gists from response.
Get details of a gist
https://api.github.com/gists/a879fd2964b8afb2d7dac9034e656a71
The JSON response of the gist URL includes all the names of the files and their content.
Solution
import requests
def get_gists(username):
url = f"https://api.github.com/users/{username}/gists"
return [gist['id'] for gist in requests.get(url).json()]
def get_files(gist_id):
url = f"https://api.github.com/gists/{gist_id}"
d = requests.get(url).json()
return [{"filename": f['filename'], "content": f['content']} for f in d['files'].values()]