Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Converted from .format() to using requests.get params to build dictionary of url paramters #15

Merged
merged 10 commits into from
Jul 22, 2022
97 changes: 49 additions & 48 deletions monsoon.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ def precip_totals(self, start_date, end_date, networks):
# validate date input
self.__validate_date_input(start_date, end_date)

# after input validation, construct API request
query_string = MonsoonAPI.API_BASE_URL + \
"?startDate={}&endDate={}&network={}".format(
start_date, end_date, networks)

# send request
return self.__get_data(query_string)


# construct API request
# base monsoon url returns precipitation totals
url_string = ""
payload = {'startDate':start_date, 'endDate':end_date, 'network':networks}

# send request and return result
return self.__get_data(url_string, payload)
def sensor_readings(self, network, start_date, end_date="", sensor=""):
"""
Retrieves raw unprocessed sensor reading data from a given network or network sensor for a
Expand All @@ -56,29 +56,32 @@ def sensor_readings(self, network, start_date, end_date="", sensor=""):
self.__validate_date_input(start_date, end_date)

# construct API request
query_string = MonsoonAPI.API_BASE_URL + \
"/readings?network={}&startDate={}&endDate={}&sensor={}".format(
network, start_date, end_date, sensor)
url_string = "/readings"
payload = {'network':network, 'startDate':start_date, 'endDate':end_date, 'sensor':sensor}

# send request and return result
return self.__get_data(url_string, payload)

# send request
return self.__get_data(query_string)

def flood_data(self, network, start_date, end_date="", sensor=""):
"""
Flood data route makes an API call for data between the start date and end date
and optionally a sensor.
:param network (required): (string) - sensor network only pima and maricopa
:param start_date (required): (string) - format "YYYY-MM-DD"
:param end_date (optional): (string) - format "YYYY-MM-DD"
:param sensor (optional): (string) - specific sensor ID
:param network (required): (string) - sensor network only pima and maricopa
:param start_date (required): (string) - format "YYYY-MM-DD"
:param end_date: (string) - format "YYYY-MM-DD"
:param sensor: (string) - specific sensor ID
"""

# validate date input
self.__validate_date_input(start_date, end_date)

query_string = MonsoonAPI.API_BASE_URL + \
"/flood?network={}&startDate={}&endDate={}&sensor={}".format(
network, start_date, end_date, sensor)
# construct API request
url_string = "/flood"
payload = {'network':network, 'startDate':start_date, 'endDate':end_date, 'sensor':sensor}
reyg3 marked this conversation as resolved.
Show resolved Hide resolved

return self.__get_data(query_string)
# send request and return result
return self.__get_data(url_string, payload)


def monsoon_data(self, network, start_year, end_year="", sensor="", raw=""):
Expand All @@ -92,20 +95,20 @@ def monsoon_data(self, network, start_year, end_year="", sensor="", raw=""):
:param end_year: (string) - End year (inclusive) of monsoon data date range in "YYYY" format.
:param sensor: (string) - Specific sensor id monsoon data is being requested.
:param raw: (bool) - Default is False. If True the data will run through our delta calculation to return
totals for all sensors during the monsoon period. When used raw
adds datetime to return.
totals for all sensors during the monsoon period. When used raw
adds datetime to return.
:return JSON: - Returns monsoon data for given year(s).
"""

# validate year input
self.__validate_year_input(start_year, end_year)

# construct API request
query_string = MonsoonAPI.API_BASE_URL + \
"/monsoon?network={}&startYear={}&endYear={}&sensor={}&raw={}".format(
network, start_year, end_year, sensor, raw)
# send request
return self.__get_data(query_string)
# construct API request
url_string = "/monsoon"
payload = {'network':network, 'startYear':start_year, 'endYear':end_year, 'sensor':sensor, 'raw':raw}

# send request and return result
return self.__get_data(url_string, payload)


def sensor_metadata(self, network, sensor=""):
Expand All @@ -118,57 +121,55 @@ def sensor_metadata(self, network, sensor=""):
"""

# construct API request
query_string = MonsoonAPI.API_BASE_URL + \
"/sensors?network={}&sensor={}".format(network, sensor)
url_string = "/sensors"
payload = {'network':network, 'sensor':sensor}

# send request
return self.__get_data(query_string)
# send request and return result
return self.__get_data(url_string, payload)


"""
Helper functions
"""


def __login(self):
"""
login() makes a post request to /login to get your API session token.

:return: (string) - Session token.
"""
r = requests.post(MonsoonAPI.API_BASE_URL+"/login", {
req = requests.post(MonsoonAPI.API_BASE_URL+"/login", {
"username": self.__username,
"key": self.__api_key
})

# check for status code >= 400 indicating authentication error
if (r.status_code >= 400):
if (req.status_code >= 400):
sys.exit("Could not authenticate")

# else, load auth token
token = json.loads(r.text)
token = json.loads(req.text)
headers = {
"Authorization": "Bearer {}".format(token['accessToken'])
}
# setting headers
self.__headers = headers


def __get_data(self, url):
def __get_data(self, url_string, payload):
"""
Common set of instructions used to perform requests for all API functions/routes.
Common set of instructions used to perform requests for all API methods/routes.

:param url (required): (string) - Composed URL string for specific data API routes.
:return JSON: - Requested data.
:param url_string (required): (string) - String used for specific data API routes.
:param payload (required): (dictionary) - Dictionary of parameters.
:return JSON: - Requested data.
"""


# make request
r = requests.get(url, headers=self.__headers)
data = json.loads(r.text)

# build and make request
req = requests.get(MonsoonAPI.API_BASE_URL+url_string, payload, headers=self.__headers)

# return formatted data
return data
return json.loads(req.text)


def __validate_date_input(self, start_date, end_date=""):
Expand Down
112 changes: 112 additions & 0 deletions monsoon_cli/monsoon_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@

import click
import requests
from monsoon import MonsoonAPI
import json
import pandas as pd

'''
CLI tool for monsoon API
'''

''' authentication for the cli tool '''
@click.group()
@click.option('--username', prompt = True, required = True)
@click.password_option('--apikey', type = str, required = True)
@click.pass_context
def cli(ctx, username, apikey):
ctx.ensure_object(dict)
ctx.obj['API'] = MonsoonAPI(username, apikey)

''' commands for precip totals function, allows for json or csv data export '''
@cli.command()
@click.option('--startdate', required = True, prompt = True, help = "Enter as YYYY-MM-DD")
@click.option('--enddate', required = True, prompt = True, help = "Enter as YYYY-MM-DD" )
@click.option('--networks', required = True, prompt = True)
@click.option('--csvfile', required = True, prompt = True, default = False)
@click.pass_context
def precip_totals(ctx, startdate, enddate, networks, csvfile):
api = ctx.obj['API']
data = api.precip_totals(startdate, enddate, networks)
df = pd.DataFrame.from_records(data)
if csvfile is False:
click.echo(json.dumps(data, indent=4))
else:
df = pd.DataFrame.from_records(data)
click.echo(df.to_csv('precip_totals.csv'))


''' commands for sensor readings function, allows for json or csv data export '''
@cli.command()
@click.option('--network', prompt = True, required = True, type = str)
@click.option('--startdate', prompt = True, required = True)
@click.option('--enddate', prompt = True, default = "")
@click.option('--sensor', prompt = True, default = "")
@click.option('--csvfile', required = True, prompt = True, default = False)
@click.pass_context
def sensor_readings(ctx, network, startdate, enddate, sensor, csvfile):
api = ctx.obj['API']
data = api.sensor_readings(network, startdate, enddate, sensor)
df = pd.DataFrame.from_records(data)
if csvfile is False:
click.echo(json.dumps(data, indent= 4))
else:
df = pd.DataFrame.from_records(data)
click.echo(df.to_csv('sensor_readings.csv'))

''' commands for sensor readings function, allows for json or csv data export '''
@cli.command()
@click.pass_context
@click.option('--network', prompt = True, required = True)
@click.option('--startdate', prompt = True, required = True, help = "Enter as YYYY-MM-DD")
@click.option('--enddate', prompt = True, default = "")
@click.option('--sensor', prompt = True, default = "")
@click.option('--csvfile', required = True, prompt = True, default = False)
def flood_data(ctx, network, startdate, enddate, sensor, csvfile):
api = ctx.obj['API']
data = api.flood_data(network, startdate, enddate, sensor)
df = pd.DataFrame.from_records(data)
if csvfile is False:
click.echo(json.dumps(data, indent= 7))
else:
df = pd.DataFrame.from_records(data)
click.echo(df.to_csv('flood_data.csv'))

''' commands for monsoon data function, allows for json and csv data export '''
@cli.command()
@click.pass_context
@click.option('--network', prompt = True, required = True)
@click.option('--startyear', prompt = True, required = True)
@click.option('--endyear', prompt = True, required = True)
@click.option('--sensor', prompt = True, required = True)
@click.option('--raw', prompt = True, default = False)
@click.option('--csvfile', required = True, prompt = True, default = False)
def monsoon_data(ctx, network, startyear, endyear, sensor, raw, csvfile):
api = ctx.obj['API']
data = api.monsoon_data(network, startyear, endyear, sensor, raw)
df = pd.DataFrame.from_records(data)
if csvfile is False:
click.echo(json.dumps(data, indent= 6))
else:
df = pd.DataFrame.from_records(data)
click.echo(df.to_csv('monsoon_data.csv'))

''' commands for sensor metadata function, allows for json and csv data export '''
@cli.command()
@click.pass_context
@click.option('--network', prompt = True, required = True)
@click.option('--sensor', prompt = True, default = "")
@click.option('--csvfile', required = True, prompt = True, default = False)
def sensor_metadata(ctx, network, sensor, csvfile):
api = ctx.obj['API']
data = api.sensor_metadata(network, sensor)
df = pd.DataFrame.from_records(data)
if csvfile is False:
click.echo(json.dumps(data, indent = 6))
else:
df = pd.DataFrame.from_records(data)
click.echo(df.to_csv('sensor_metadata.csv'))


if __name__ == '__main__':
cli()