diff --git a/requirements.txt b/requirements.txt index c3dccde..01ceeeb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,7 @@ pandas==1.4.1 numpy==1.22.2 requests==2.27.1 openpyxl -ratelimit==2.2.1 \ No newline at end of file +ratelimit==2.2.1 +mypy +flake8 +black \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 6a8c289..58e447e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = ozon3 -version = 1.4.2 +version = 1.4.3 author = Milind Sharma author_email = milindsharma8@gmail.com description = A package to get air quality data using the WAQI API diff --git a/setup.py b/setup.py index d5fe52e..ab027eb 100644 --- a/setup.py +++ b/setup.py @@ -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.4.2", - download_url="https://github.com/Milind220/Ozone/archive/refs/tags/v1.4.2.tar.gz", + version="1.4.3", + download_url="https://github.com/Milind220/Ozone/archive/refs/tags/v1.4.3.tar.gz", packages=setuptools.find_packages(), install_requires=[ "numpy; python_version>='3'", diff --git a/src/ozone/ozone.py b/src/ozone/ozone.py index 582a5ff..ad62ca0 100644 --- a/src/ozone/ozone.py +++ b/src/ozone/ozone.py @@ -16,6 +16,7 @@ import requests import json import itertools +import warnings from ratelimit import limits, sleep_and_retry from .urls import URLs @@ -73,7 +74,7 @@ def _check_token_validity(self) -> None: if self._check_status_code(r): if json.loads(r.content)["status"] != "ok": - print("Warning: Token may be invalid!") + warnings.warn("Token may be invalid!") @sleep_and_retry @limits(calls=CALLS, period=RATE_LIMIT) @@ -111,9 +112,7 @@ def reset_token(self, token: str) -> None: self._check_token_validity() def _format_output( - self, - data_format: str = "df", - df: pandas.DataFrame = pandas.DataFrame(), + self, data_format: str = "df", df: pandas.DataFrame = pandas.DataFrame(), ) -> pandas.DataFrame: """Format output data @@ -134,12 +133,12 @@ def _format_output( df.to_json("air_quality_data.json") print("File saved to disk as air_quality_data.json") elif data_format == "xlsx": - df.to_excel( - "air_quality_data.xlsx", - ) + df.to_excel("air_quality_data.xlsx",) print("File saved to disk as air_quality_data.xlsx") else: - print("Invalid file format. Use any of: csv, json, xlsx, df") + raise Exception( + f"Invalid file format {data_format}. Use any of: csv, json, xlsx, df" + ) return pandas.DataFrame() def _parse_data( @@ -187,7 +186,7 @@ def _parse_data( return [row] def _AQI_meaning(self, aqi: float) -> Tuple[str, str]: - """Retrieve API Meaning and health implications + """Retrieve AQI meaning and health implications Args: row["aqi"] (float): parsed AQI data. @@ -196,7 +195,7 @@ def _AQI_meaning(self, aqi: float) -> Tuple[str, str]: str: The meaning and health implication of the AQI data. """ - if aqi <= 50: + if 0 <= aqi <= 50: AQI_meaning = "Good" AQI_health_implications = "Air quality is considered satisfactory, and air pollution poses little or no risk" elif 51 <= aqi <= 100: @@ -211,11 +210,15 @@ def _AQI_meaning(self, aqi: float) -> Tuple[str, str]: elif 201 <= aqi <= 300: AQI_meaning = "Very Unhealthy" AQI_health_implications = "Health warnings of emergency conditions. The entire population is more likely to be affected." - else: + elif 301 <= aqi <= 500: AQI_meaning = "Hazardous" AQI_health_implications = ( "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." + ) return AQI_meaning, AQI_health_implications @@ -314,7 +317,18 @@ def get_city_air( r = self._make_api_request(f"{self._search_aqi_url}/{city}/?token={self.token}") if self._check_status_code(r): # Get all the data. - data_obj = json.loads(r.content)["data"] + response_content = json.loads(r.content) + status, data_obj = response_content["status"], response_content["data"] + if status != "ok": + if data_obj == "Unknown station": + raise Exception( + f'There is no known AQI station for the city "{city}"' + ) + + raise Exception( + f'There is a problem with city "{city}", the returned data: {data_obj}' + ) + row = self._parse_data(data_obj, city, params) df = pandas.concat([df, pandas.DataFrame(row)], ignore_index=True) @@ -405,11 +419,7 @@ def get_multiple_city_air( df.reset_index(inplace=True, drop=True) return self._format_output(data_format, df) - def get_specific_parameter( - self, - city: str, - air_param: str = "", - ) -> float: + def get_specific_parameter(self, city: str, air_param: str = "",) -> float: """Get specific parameter as a float Args: @@ -420,20 +430,14 @@ def get_specific_parameter( Returns: float: Value of the specified parameter for the given city. """ - result: float = 0.0 - try: - r = self._make_api_request( - f"{self._search_aqi_url}/{city}/?token={self.token}" - ) - if self._check_status_code(r): - data_obj = json.loads(r.content)["data"] - row = self._parse_data(data_obj, city, [air_param])[0] - result = float(row[air_param]) + row = self.get_city_air(city, params=[air_param]) + try: + result = float(row[air_param]) except KeyError: - print( - "Missing air quality parameter!\n" - + "Try: get_specific_parameter(`city name`, `aqi` or `no2` or `co`)" + raise Exception( + f'Missing air quality parameter "{air_param}"\n' + + 'Try another air quality parameters: "aqi", "no2", or "co"' ) return result diff --git a/updateVersion.sh b/updateVersion.sh new file mode 100644 index 0000000..359d276 --- /dev/null +++ b/updateVersion.sh @@ -0,0 +1,61 @@ +#!/usr/bin/bash + +# This script is used for automating the process of updating patch numbers. +# Specifically, it updates the version number in setup.cfg (Line 3) and setup.py (Line 12 & 13) +# You can provide the script with either major, minor or patch (Case sensitive) +# Example usage: +# If the current version is 1.4.0, running './updateVersion.sh major' will change +# the current version to 2.0.0 + +if [ "$1" = "" ]; then +echo "You must provide an argument for this script" +echo "Your argument must be either major, minor or patch" +echo "See version semantics for more" +exit +fi + +if [ "$1" != "major" ] && [ "$1" != "minor" ] && [ "$1" != "patch" ]; then +echo "Incorrect argument provided" +echo "Your argument must be either major, minor or patch (Case sensitive)" +exit +fi + +VERSION_STRING=$(cat setup.cfg | grep "version") + +IFS=' ' +read -ra VERSION_STRING_ARR <<< $VERSION_STRING + +VERSION="${VERSION_STRING_ARR[@]:2:2}" + +echo "Current Version: $VERSION" + +IFS='.' + +read -ra VERSION_NUMBERS <<< $VERSION + +MAJOR=${VERSION_NUMBERS[@]::1} +MINOR=${VERSION_NUMBERS[@]:1:1} +PATCH=${VERSION_NUMBERS[@]:2:2} + +if [ "$1" = "major" ]; then +PATCH="0" +MINOR="0" +MAJOR=$(( $MAJOR + 1)) +fi + +if [ "$1" = "minor" ]; then +PATCH="0" +MINOR=$(( $MINOR + 1)) +fi + +if [ "$1" = "patch" ]; then +PATCH=$(( $PATCH + 1)) +fi + +UPDATED_VERSION="${MAJOR}.${MINOR}.${PATCH}" + +echo "Updated Version: $UPDATED_VERSION" + +sed -i "s/version = ${VERSION}/version = ${UPDATED_VERSION}/" setup.cfg +sed -i "s/^ version=\"${VERSION}\",/ version=\"${UPDATED_VERSION}\",/" setup.py +sed -i "s/^ download_url=\"https:\/\/github.com\/Milind220\/Ozone\/archive\/refs\/tags\/v${VERSION}.tar.gz\",/ download_url=\"https:\/\/github.com\/Milind220\/Ozone\/archive\/refs\/tags\/v${UPDATED_VERSION}.tar.gz\",/" setup.py