def get_aqi_data(response_data: Dict, query: str) -> List[Tuple[str, str]]: """ Grabs aqi data and station name from the response payload. Args: response_data: Response data from the API. query: search query from user. """ data_store: List[Tuple[str, str]] = [] AirData = namedtuple("AirData", ["station", "aqi"]) data_node: List[Dict[str, str]] = response_data.get("data") # Check for empty data_node: [] if not data_node: console.print( f"No air quality data found for search: [bold red]{query}[/bold red]" ) sys.exit() # Grab aqi value and station name from the response payload. for item in data_node: aqi = item["aqi"] station = item["station"]["name"] data_package = AirData(station, aqi) data_store.append(data_package) return data_store
def get_stations(data: Dict) -> List[NamedTuple]: """ Get stations from the response payload. """ Stations = namedtuple("Stations", ["uid", "station"]) help_message = "No stations found in the location.:x:" data_node: List = data["data"] if not data_node: console.print(help_message) sys.exit() data_store = [] for item in data_node: aqi = item["aqi"] uid = item["uid"] station = item["station"]["name"] data_store.append(Stations(uid, station)) # When aqi value for stations are "-" data_store will be empty. if not data_store: console.print(help_message) sys.exit() return data_store
def check_configs(): """ Checks if both the config directory and credential config are present. """ if not os.path.exists(_CONFIG_DIR) or not check_credential_file: console.print( "You have not initialized the app, [bold green]use `air init` to add token[/bold green]" ) sys.exit()
def init(): """ Initialize the CLI by prompting the user to enter API token. """ console.print(TOKEN_HELP_MSG) token = Prompt.get_input( console, ":key: Enter your API Token (hidden) ", password=True ) # Store credential to ~/.aqi/creds file. add_credential(token)
def remove_from_config_file( *, station_uid: List[int], location: str, station: str ): """ Remove station from config file. Args: * : all arguments after this should be keyword arguments. station_uid: unique identifier for the station. location: search query entered by user. station: name of the station. """ success_message = f"Successfully removed {station}!" empty_message = f"Config file empty. No stations saved to remove!" no_location_message = f"Location {location} isn't saved in config file." no_station_message = f"Station {station} isn't saved in config file." # Check for both config folder and credentials file. check_configs() # Remove uid from the config file. with open(CONFIG_FILE, "r+") as file: data = file.readline() if not data: console.print(empty_message) sys.exit() data_dict = json.loads(data) # If location doesnt exist, display message # If location exists but station doesnt, display message # If location exists as well as station, then remove the uid of the station if location not in data_dict: console.print(no_location_message) sys.exit() elif station_uid[0] not in data_dict[location]: console.print(station_uid[0]) console.print(no_station_message) sys.exit() else: data_dict[location].remove(station_uid[0]) with open(CONFIG_FILE, "w") as file: # Rewriting the config dictionary with config value file.seek(0) json.dump(data_dict, file) console.print(success_message)
def add_credential(credential: str): """ Store creds in .aqi/creds """ # Create a config directory if it doesn't exist. if not os.path.exists(_CONFIG_DIR): os.mkdir(_CONFIG_DIR) # @TODO add hashing to encrypt the keys. # Write credentials to the file. with open(f"{CREDS_FILE}", "w+") as cred: cred.write(credential.strip()) console.print( f"Credentials saved to [bold blue]{CREDS_FILE}[/bold blue]:white_check_mark:", style="bold green", )
def show_table(data: List[Tuple]): """ Show table to preview data. Args: data: Air Quality information. """ table = Table( *TABLE_HEADERS, header_style="bold", title="Air Quality Index", title_style="bold black on white", box=box.ROUNDED, show_lines=True, ) for row in data: table.add_row(*row) console.print(table)
def add_to_config_file(*, station_uid: List[int], location: str, station: str): """ Add station to config file. Args: * : all arguments after this should be keyword arguments. station_uid: unique identifier for the station. location: search query entered by user. station: name of the station. """ help_message = f"Successfully added {station}!" # Check for both config folder and credentials file. check_configs() # Create stations config file if it does not exist. if not os.path.exists(CONFIG_FILE): with open(CONFIG_FILE, "w+"): pass # Add search query and uid to config dictionary. with open(CONFIG_FILE, "r+") as file: data = file.readline() # If config file empty. if not data: value = {location: station_uid} json.dump(value, file) console.print(help_message) sys.exit() data_dict = json.loads(data) # If key for search location does not exist, add station based on it. # Else check if uid for the search query already exists. # Else assume the key for the search query exists; append uid to its value (List). if location not in data_dict: data_dict[location] = station_uid elif station_uid[0] in data_dict[location]: console.print(f"Station: {station} already exists.") sys.exit() else: data_dict[location].append(station_uid[0]) # Rewrite the config dictionary with updated value. file.seek(0) json.dump(data_dict, file) console.print(help_message)
def get_config_stations() -> Dict[str, List[int]]: """ Reads the config dictionary from the file. """ help_msg = "You have not saved any stations, use [bold green]`air add <location>`[/bold green] to save a station!" if not os.path.exists(_CONFIG_DIR): console.print( "App is not initialized. Use [bold green]`air init`[/bold green] to get started!" ) sys.exit() if not os.path.exists(CONFIG_FILE): console.print(help_msg) sys.exit() with open(CONFIG_FILE, "r") as file: data = json.loads(file.readline()) if not data: console.print(help_msg) sys.exit() return data
def make_request(query: str) -> Dict[str, str]: """ Make an API request. Args: query: search query from user input. """ token = check_credential_file() if not token: console.print( ":key: [bold red]No API token found, use [green]`air init`[/green] to enter API key.[/bold red]" ) sys.exit() try: response = requests.get( BASE_URL.format(query=query, API_KEY=token), timeout=10, ) response.raise_for_status() if response.json().get("status") == "error": raise requests.exceptions.HTTPError except requests.exceptions.HTTPError: error = response.json().get("data") console.print( f"Error: {error}.:x:", style="bold red", ) sys.exit() except requests.exceptions.ConnectionError: console.print("[bold red]No connection:x:[/bold red]") sys.exit() except requests.exceptions.RequestException: console.print( "An error has occcured. Please try again later or open an issue on GitHub.:x:", style="bold red", ) sys.exit() except requests.exceptions.ReadTimeout: console.print("Network connection timeout.:construction:", style="bold red") sys.exit() except Exception: error_base = response.json().get("errors")[0] console.print( f"Error: {error_base.get('message')}:x:", style="bold red", ) sys.exit() return response.json()