Skip to content

Commit

Permalink
Merge branch 'release-1.7.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
Milind220 committed Apr 24, 2022
2 parents 1347d1b + d543cd9 commit a3aafe9
Show file tree
Hide file tree
Showing 9 changed files with 598 additions and 42 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: Bug report
about: 'Create a report to help Ozone improve. Treat this template more as a guide
to filling a good issue, rather than a rulebook '
to filing a good issue, rather than something you have to fill completely every time.'
title: "[BUG]"
labels: bug
assignees: ''
Expand Down
6 changes: 3 additions & 3 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
about: Suggest an idea for a feature/enhancement for Ozone.
title: '[FEAT]'
labels: 'enhancement'
assignees: ''

---
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = ozon3
version = 1.7.3
version = 1.7.4
author = Milind Sharma
author_email = milindsharma8@gmail.com
description = A package to get air quality data using the WAQI API
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
description="A package to get air quality data using the WAQI API",
license="GPLv3+",
url="https://github.com/Milind220/Ozone",
version="1.7.3",
download_url="https://github.com/Milind220/Ozone/archive/refs/tags/v1.7.3.tar.gz",
version="1.7.4",
download_url="https://github.com/Milind220/Ozone/archive/refs/tags/v1.7.4.tar.gz",
packages=setuptools.find_packages(),
install_requires=[
"numpy; python_version>='3'",
Expand Down
79 changes: 56 additions & 23 deletions src/ozone/ozone.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@
RATE_LIMIT: int = 1


def _as_float(x: Any) -> float:
"""Convert x into a float. If unable, convert into numpy.nan instead.
Naming and functionality inspired by R function as.numeric()"""
try:
return float(x)
except (TypeError, ValueError):
return numpy.nan


class Ozone:
"""Primary class for Ozone API
Expand Down Expand Up @@ -62,18 +72,27 @@ class Ozone:
"wg",
]

def __init__(self, token: str = "", output_path: str = "."):
def __init__(
self, token: str = "", output_path: str = ".", file_name: str = "air_quality"
):
"""Initialises the class instance and sets the API token value
Args:
token (str): The users private API token for the WAQI API.
output_path (str): The path to the location where
file_name (str): Name of output file
any output artifacts will be created
"""
self.token: str = token
self._check_token_validity()

self.output_dir_path: Path = Path(output_path, "ozone_output")
self.file_name = file_name

if self.file_name == "air_quality":
warnings.warn(
"You have not specified a custom save file name. Existing files with the same name may be overwritten!"
)

def _check_token_validity(self) -> None:
"""Check if the token is valid"""
Expand Down Expand Up @@ -144,19 +163,21 @@ def _format_output(
self.output_dir_path.mkdir(exist_ok=True)

if data_format == "csv":
df.to_csv(Path(self.output_dir_path, "air_quality.csv"), index=False)
print(f"File saved to disk at {self.output_dir_path} as air_quality.csv")
df.to_csv(Path(self.output_dir_path, f"{self.file_name}.csv"), index=False)
print(
f"File saved to disk at {self.output_dir_path} as {self.file_name}.csv"
)
elif data_format == "json":
df.to_json(Path(self.output_dir_path, "air_quality_data.json"))
df.to_json(Path(self.output_dir_path, f"{self.file_name}.json"))
print(
f"File saved to disk at {self.output_dir_path} as air_quality_data.json"
f"File saved to disk at {self.output_dir_path} as {self.file_name}.json"
)
elif data_format == "xlsx":
df.to_excel(
Path(self.output_dir_path, "air_quality_data.xlsx"),
Path(self.output_dir_path, f"{self.file_name}.xlsx"),
)
print(
f"File saved to disk at {self.output_dir_path} as air_quality_data.xlsx"
f"File saved to disk at {self.output_dir_path} as {self.file_name}.xlsx"
)
else:
raise Exception(
Expand Down Expand Up @@ -196,14 +217,14 @@ def _extract_live_data(
try:
if param == "aqi":
# This is in different part of JSON object.
row["aqi"] = float(data_obj["aqi"])
row["aqi"] = _as_float(data_obj["aqi"])
# This adds AQI_meaning and AQI_health_implications data
(
row["AQI_meaning"],
row["AQI_health_implications"],
) = self._AQI_meaning(float(data_obj["aqi"]))
) = self._AQI_meaning(_as_float(data_obj["aqi"]))
else:
row[param] = float(data_obj["iaqi"][param]["v"])
row[param] = _as_float(data_obj["iaqi"][param]["v"])
except KeyError:
# Gets triggered if the parameter is not provided by station.
row[param] = numpy.nan
Expand Down Expand Up @@ -336,10 +357,8 @@ def _AQI_meaning(self, aqi: float) -> Tuple[str, str]:
"Health alert: everyone may experience more serious health effects."
)
else:
raise Exception(
f"{aqi} is not valid air quality index value. "
"Should be between 0 to 500."
)
AQI_meaning = "Invalid AQI value"
AQI_health_implications = "Invalid AQI value"

return AQI_meaning, AQI_health_implications

Expand Down Expand Up @@ -474,11 +493,18 @@ def get_multiple_coordinate_air(
selected another data format, this dataframe will be empty)
"""
for loc in locations:
# This just makes sure that it's always a returns a pandas.DataFrame.
# Makes mypy happy.
df = pandas.DataFrame(
self.get_coordinate_air(loc[0], loc[1], df=df, params=params)
)
try:
# This just makes sure that it's always a returns a pandas.DataFrame.
# Makes mypy happy.
df = pandas.DataFrame(
self.get_coordinate_air(loc[0], loc[1], df=df, params=params)
)
except Exception:
# NOTE: If we have custom exception we can catch it instead.
empty_row = pandas.DataFrame(
{"latitude": [_as_float(loc[0])], "longitude": [_as_float(loc[1])]}
)
df = pandas.concat([df, empty_row], ignore_index=True)

df.reset_index(inplace=True, drop=True)
return self._format_output(data_format, df)
Expand Down Expand Up @@ -543,9 +569,16 @@ def get_multiple_city_air(
selected another data format, this dataframe will be empty)
"""
for city in cities:
# This just makes sure that it's always a returns a pandas.DataFrame.
# Makes mypy happy.
df = pandas.DataFrame(self.get_city_air(city=city, df=df, params=params))
try:
# This just makes sure that it's always a returns a pandas.DataFrame.
# Makes mypy happy.
df = pandas.DataFrame(
self.get_city_air(city=city, df=df, params=params)
)
except Exception:
# NOTE: If we have custom exception we can catch it instead.
empty_row = pandas.DataFrame({"city": [city]})
df = pandas.concat([df, empty_row], ignore_index=True)

df.reset_index(inplace=True, drop=True)
return self._format_output(data_format, df)
Expand Down Expand Up @@ -574,7 +607,7 @@ def get_specific_parameter(
row = self._extract_live_data(data_obj, [air_param])

try:
result = float(row[air_param])
result = _as_float(row[air_param])
except KeyError:
raise Exception(
f'Missing air quality parameter "{air_param}"\n'
Expand Down
74 changes: 70 additions & 4 deletions tests/cassettes/test_get_multiple_city_air/test_bad_city.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ interactions:
- Fri, 22 Apr 2022 01:26:13 GMT
Server:
- nginx
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
X-Gen-Time:
Expand Down Expand Up @@ -134,8 +132,6 @@ interactions:
- Fri, 22 Apr 2022 01:26:15 GMT
Server:
- nginx
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
X-Gen-Time:
Expand All @@ -147,4 +143,74 @@ interactions:
status:
code: 200
message: OK
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
User-Agent:
- python-requests/2.27.1
method: GET
uri: https://api.waqi.info/feed//a%20definitely%20nonexistent%20city/?token=DUMMY_TOKEN
response:
body:
string: ''
headers:
Connection:
- keep-alive
Content-Length:
- '0'
Date:
- Sat, 23 Apr 2022 14:41:19 GMT
Location:
- /feed/a%20definitely%20nonexistent%20city/?token=DUMMY_TOKEN
Server:
- nginx
status:
code: 301
message: Moved Permanently
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
User-Agent:
- python-requests/2.27.1
method: GET
uri: https://api.waqi.info/feed/a%20definitely%20nonexistent%20city/?token=DUMMY_TOKEN
response:
body:
string: '{"status":"error","data":"Unknown station"}'
headers:
Access-Control-Allow-Origin:
- '*'
Connection:
- keep-alive
Content-Type:
- application/json; charset=UTF-8
Date:
- Sat, 23 Apr 2022 14:41:19 GMT
Server:
- nginx
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
X-Gen-Time:
- "188.033\xC2\xB5s"
X-Powered-By:
- rxstreamer-waqi/1.3
content-length:
- '43'
status:
code: 200
message: OK
version: 1
Loading

0 comments on commit a3aafe9

Please sign in to comment.