Lab is ready
This commit is contained in:
parent
05ed95fb65
commit
729b179d43
|
@ -0,0 +1,2 @@
|
|||
dist/*
|
||||
**/__pycache__/*
|
|
@ -0,0 +1,13 @@
|
|||
# This shell shell script adds `weather` to your global PATH, so that you'll be able to
|
||||
# run it from any Terminal session. If you want this, just run:
|
||||
#
|
||||
# source globalize_weather.sh
|
||||
|
||||
CHECK=$(which weather 2>&1)
|
||||
if [ $CHECK = "weather not found" ]; then
|
||||
echo "The weather script was not found. Make sure you are in a Poetry shell and that you have run poetry install."
|
||||
else
|
||||
echo "\n# Adding path for weather" >> ~/.mwc_rc
|
||||
echo "export PATH=\"$(dirname $(which weather)):\$PATH\"" >> ~/.mwc_rc
|
||||
source ~/.mwc_rc
|
||||
fi
|
|
@ -0,0 +1,180 @@
|
|||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2021.10.8"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "charset-normalizer"
|
||||
version = "2.0.12"
|
||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5.0"
|
||||
|
||||
[package.extras]
|
||||
unicode_backport = ["unicodedata2"]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.0.4"
|
||||
description = "Composable command line interface toolkit"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.4"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "decorator"
|
||||
version = "5.1.1"
|
||||
description = "Decorators for Humans"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "future"
|
||||
version = "0.18.2"
|
||||
description = "Clean single-source support for Python 3 and 2"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
|
||||
[[package]]
|
||||
name = "geocoder"
|
||||
version = "1.38.1"
|
||||
description = "Geocoder is a simple and consistent geocoding library."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
click = "*"
|
||||
future = "*"
|
||||
ratelim = "*"
|
||||
requests = "*"
|
||||
six = "*"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.3"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "ratelim"
|
||||
version = "0.1.6"
|
||||
description = "Makes it easy to respect rate limits."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
decorator = "*"
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.27.1"
|
||||
description = "Python HTTP for Humans."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2017.4.17"
|
||||
charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""}
|
||||
idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""}
|
||||
urllib3 = ">=1.21.1,<1.27"
|
||||
|
||||
[package.extras]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
|
||||
use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "1.26.8"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotlipy (>=0.6.0)"]
|
||||
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.9"
|
||||
content-hash = "8db6132dd735c9575de75a5b220e83f601f31e184320c37589cb255b78084b19"
|
||||
|
||||
[metadata.files]
|
||||
certifi = [
|
||||
{file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
|
||||
{file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
|
||||
]
|
||||
charset-normalizer = [
|
||||
{file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"},
|
||||
{file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"},
|
||||
]
|
||||
click = [
|
||||
{file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"},
|
||||
{file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"},
|
||||
]
|
||||
colorama = [
|
||||
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
|
||||
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
|
||||
]
|
||||
decorator = [
|
||||
{file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
|
||||
{file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
|
||||
]
|
||||
future = [
|
||||
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
|
||||
]
|
||||
geocoder = [
|
||||
{file = "geocoder-1.38.1-py2.py3-none-any.whl", hash = "sha256:a733e1dfbce3f4e1a526cac03aadcedb8ed1239cf55bd7f3a23c60075121a834"},
|
||||
{file = "geocoder-1.38.1.tar.gz", hash = "sha256:c9925374c961577d0aee403b09e6f8ea1971d913f011f00ca70c76beaf7a77e7"},
|
||||
]
|
||||
idna = [
|
||||
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
|
||||
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
|
||||
]
|
||||
ratelim = [
|
||||
{file = "ratelim-0.1.6-py2.py3-none-any.whl", hash = "sha256:e1a7dd39e6b552b7cc7f52169cd66cdb826a1a30198e355d7016012987c9ad08"},
|
||||
{file = "ratelim-0.1.6.tar.gz", hash = "sha256:826d32177e11f9a12831901c9fda6679fd5bbea3605910820167088f5acbb11d"},
|
||||
]
|
||||
requests = [
|
||||
{file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"},
|
||||
{file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"},
|
||||
]
|
||||
six = [
|
||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||
]
|
||||
urllib3 = [
|
||||
{file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"},
|
||||
{file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"},
|
||||
]
|
|
@ -1,5 +1,5 @@
|
|||
[tool.poetry]
|
||||
name = "mwc-pedprog-unit01-lab02"
|
||||
name = "weather"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["Chris <github.com@accounts.chrisproctor.net>"]
|
||||
|
@ -7,9 +7,14 @@ license = "MIT"
|
|||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
requests = "^2.27.1"
|
||||
geocoder = "^1.38.1"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
weather = "weather.weather_cli:weather_cli"
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
from weather.weather_apis import (
|
||||
geocode_location,
|
||||
geocode_ip_address,
|
||||
get_weather_office,
|
||||
get_forecast
|
||||
)
|
||||
|
||||
def print_weather(location=None, metric=False, verbose=False):
|
||||
"""Prints out a weather report using the provided location, or using
|
||||
the user's current location if no location was provided.
|
||||
When metric is True, prints out the weather in metric units.
|
||||
When verbose is True, prints out a more detailed report.
|
||||
"""
|
||||
print("Not finished...") # YOUR CODE HERE!
|
||||
|
||||
# This is a clunky way to check whether this module was called directly with `python weather.py`,
|
||||
# or whether it's being imported by another module. If the module is being called, then we
|
||||
# should actually run `print_weather`. But if this module is just being imported, we probably don't
|
||||
# want this module to call any functions. We'll leave that up whoever is doing the importing.
|
||||
if __name__ == "__main__":
|
||||
print_weather()
|
|
@ -0,0 +1,80 @@
|
|||
# Weather APIs
|
||||
|
||||
# This module contains functions which interact with external APIs related to weather.
|
||||
# The module relies on USA-specific services; it will need to be extended using local
|
||||
# services for other regions.
|
||||
|
||||
# The National Weather Service (NWS) provides weather forecasting services across US
|
||||
# states and territories. NWS divides the country into a grid of 2.5km squares, and
|
||||
# provides a forecast for each grid square.
|
||||
|
||||
import geocoder
|
||||
import requests
|
||||
|
||||
def geocode_location(location_string):
|
||||
"""Translates a location string into latitude and longitude coordinates.
|
||||
Uses the OpenStreetMap API. Returns a dict with keys 'lat' and 'lng'
|
||||
as shown below. When no result is found, returns None.
|
||||
|
||||
>>> geocode_location('11 Wall Street, New York')
|
||||
{"lat": -74.010865, "lng": 40.7071407}
|
||||
"""
|
||||
result = geocoder.osm(location_string)
|
||||
if result:
|
||||
lat, lng = result.latlng
|
||||
return {'lat': lat, 'lng': lng}
|
||||
|
||||
def geocode_ip_address(ip_address=None):
|
||||
"""Translates an IP address into latitude and longitude coodrdinates.
|
||||
When no IP address is provided, uses the user's current IP address.
|
||||
|
||||
>>> geocode_ip_address()
|
||||
{'lat': 23.6585116, 'lng': -102.0077097}
|
||||
"""
|
||||
result = geocoder.ip(ip_address or 'me')
|
||||
if result:
|
||||
lat, lng = result.latlng
|
||||
return {'lat': lat, 'lng': lng}
|
||||
|
||||
def get_weather_office(lat, lng):
|
||||
"""Looks up the NWS weather office for a pair of lat/lng coordinates.
|
||||
Returns a dict containing keys 'office', 'x', and 'y'.
|
||||
If no matching weather office is found, returns None.
|
||||
|
||||
>>> coords = geocode_ip_address()
|
||||
>>> get_weather_office(coords['lat'], coords['lng'])
|
||||
{'office': 'BUF', 'x': 39, 'y': 59}
|
||||
"""
|
||||
url = "https://api.weather.gov/points/{},{}".format(lat, lng)
|
||||
response = requests.get(url)
|
||||
if response.ok:
|
||||
result = response.json()
|
||||
return {
|
||||
"office": result['properties']['gridId'],
|
||||
"x": result['properties']['gridX'],
|
||||
'y': result['properties']['gridY']
|
||||
}
|
||||
|
||||
def get_forecast(office, x, y, metric=False):
|
||||
"""Fetches the weather forecast for the given NWS office, and (x, y) NWS grid tile.
|
||||
Returns a list of time periods, where each time period is a dict containing keys
|
||||
as shown below. If no forecast can be found, returns None.
|
||||
When metric is True, returns temperatures in Celcius and wind speeds in km/hr.
|
||||
|
||||
"""
|
||||
url = "https://api.weather.gov/gridpoints/{}/{},{}/forecast".format(office, x, y)
|
||||
if metric:
|
||||
url += "?units=si"
|
||||
response = requests.get(url)
|
||||
if response.ok:
|
||||
result = response.json()
|
||||
forecast = []
|
||||
for period in result['properties']['periods']:
|
||||
forecast.append({
|
||||
'name': period['name'],
|
||||
'temperature': period['temperature'],
|
||||
'wind_speed': period['windSpeed'],
|
||||
'wind_direction': period['windDirection'],
|
||||
'description': period['shortForecast'],
|
||||
})
|
||||
return forecast
|
|
@ -0,0 +1,15 @@
|
|||
from argparse import ArgumentParser
|
||||
from weather.weather import print_weather
|
||||
|
||||
def weather_cli():
|
||||
"""Provides a command-line interface for weather.
|
||||
This function creates an ArgumentParser, which parses command line arguments.
|
||||
Then it calls `print_weather` with the provided arguments.
|
||||
"""
|
||||
parser = ArgumentParser("weather", description="Prints out a weather report")
|
||||
parser.add_argument("-l", "--location", help="Location for weather forecast")
|
||||
parser.add_argument("-m", "--metric", action="store_true", help="Use metric units")
|
||||
parser.add_argument("-v", "--verbose", action="store_true", help="Verbose output")
|
||||
args = parser.parse_args()
|
||||
print_weather(location=args.location, metric=args.metric, verbose=args.verbose)
|
||||
|
Loading…
Reference in New Issue