From 795a439dd61c04bba356481c22051e62022cabef Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Wed, 20 Dec 2017 15:20:41 -0600 Subject: [PATCH 01/15] Adds acis.py, which provides a function for connecting to ACIS Web Services --- siphon/acis.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 siphon/acis.py diff --git a/siphon/acis.py b/siphon/acis.py new file mode 100644 index 000000000..b648cda79 --- /dev/null +++ b/siphon/acis.py @@ -0,0 +1,52 @@ +import json +import urllib.request +import urllib.parse +import json +import socket + +def acisRequest(method, params): + """ + + + This function will make a request to the ACIS Web Services API for data + based on the given method (StnMeta,StnData,MultiStnData,GridData,General) + and parameters string. Information about the parameters can be obtained at: + http://www.rcc-acis.org/docs_webservices.html + + If a connection to the API fails, then it returns False. A failed request + will have an error text in the return data produced by the remote API. + + Parameters + ---------- + method - The Web Services request method (MultiStn,StnMeta,etc) + params - A JSON array of parameters (See Web Services API) + + Returns + ---------- + Connection Success: A dictionary that is derived from JSON data from the remote API + Connection Failure: False + + """ + params = json.dumps(params).encode('utf8') + + base_url = 'http://data.rcc-acis.org/' # ACIS Web API URL + + req = urllib.request.Request(base_url+method, + params, {'Content-Type': 'application/json'}) + if method == 'MultiStnData': + timeout=300 + else: + timeout=60 + + try: + response = urllib.request.urlopen(req, timeout=timeout) # 10-Minute Timeout + return json.loads(response.read()) + except urllib.request.HTTPError as error: + if error.code == 400: + print(error.msg) + print(error) + return False + + except socket.timeout: + print("Connection Timeout") + return False # Failed This Time From e5df7d1051eada8ad2247fa261df80b523b72229 Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Tue, 9 Jan 2018 09:26:48 -0600 Subject: [PATCH 02/15] Update acis.py Updates docstring text to better reflect parameters --- siphon/acis.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/siphon/acis.py b/siphon/acis.py index b648cda79..799caabaa 100644 --- a/siphon/acis.py +++ b/siphon/acis.py @@ -6,8 +6,7 @@ def acisRequest(method, params): """ - - + This function will make a request to the ACIS Web Services API for data based on the given method (StnMeta,StnData,MultiStnData,GridData,General) and parameters string. Information about the parameters can be obtained at: @@ -18,8 +17,8 @@ def acisRequest(method, params): Parameters ---------- - method - The Web Services request method (MultiStn,StnMeta,etc) - params - A JSON array of parameters (See Web Services API) + method - The Web Services request method (StnMeta, StnData, MultiStnData, etc) + params - A dictionary of parameters (see API documentation) Returns ---------- From 90d52dd4d71ad312877a0f6da9498bbcff7be5c3 Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Wed, 17 Jan 2018 15:06:31 -0600 Subject: [PATCH 03/15] - Moves acis.py to the simplewebservice directory. - Updates acis_request to use the requests library. --- siphon/acis.py | 52 --------------------------- siphon/simplewebservice/acis.py | 62 +++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 52 deletions(-) delete mode 100644 siphon/acis.py create mode 100644 siphon/simplewebservice/acis.py diff --git a/siphon/acis.py b/siphon/acis.py deleted file mode 100644 index b648cda79..000000000 --- a/siphon/acis.py +++ /dev/null @@ -1,52 +0,0 @@ -import json -import urllib.request -import urllib.parse -import json -import socket - -def acisRequest(method, params): - """ - - - This function will make a request to the ACIS Web Services API for data - based on the given method (StnMeta,StnData,MultiStnData,GridData,General) - and parameters string. Information about the parameters can be obtained at: - http://www.rcc-acis.org/docs_webservices.html - - If a connection to the API fails, then it returns False. A failed request - will have an error text in the return data produced by the remote API. - - Parameters - ---------- - method - The Web Services request method (MultiStn,StnMeta,etc) - params - A JSON array of parameters (See Web Services API) - - Returns - ---------- - Connection Success: A dictionary that is derived from JSON data from the remote API - Connection Failure: False - - """ - params = json.dumps(params).encode('utf8') - - base_url = 'http://data.rcc-acis.org/' # ACIS Web API URL - - req = urllib.request.Request(base_url+method, - params, {'Content-Type': 'application/json'}) - if method == 'MultiStnData': - timeout=300 - else: - timeout=60 - - try: - response = urllib.request.urlopen(req, timeout=timeout) # 10-Minute Timeout - return json.loads(response.read()) - except urllib.request.HTTPError as error: - if error.code == 400: - print(error.msg) - print(error) - return False - - except socket.timeout: - print("Connection Timeout") - return False # Failed This Time diff --git a/siphon/simplewebservice/acis.py b/siphon/simplewebservice/acis.py new file mode 100644 index 000000000..ae98da820 --- /dev/null +++ b/siphon/simplewebservice/acis.py @@ -0,0 +1,62 @@ +import json +import urllib.request +import urllib.parse +import requests +import json +import socket + +def acis_request(method, params): + """ + + This function will make a request to the ACIS Web Services API for data + based on the given method (StnMeta,StnData,MultiStnData,GridData,General) + and parameters string. Information about the parameters can be obtained at: + http://www.rcc-acis.org/docs_webservices.html + + If a connection to the API fails, then it will raise an exception. Some bad + calls will also return empty dictionaries. + + Parameters + ---------- + method : str + The Web Services request method (MultiStn,StnMeta,etc) + params : dict + A JSON array of parameters (See Web Services API) + + Returns + ------- + A dictionary of data based on the JSON parameters + + Raises + ------ + :class: `ACIS_API_Exception` + When the API is unable to establish a connection or returns + unparsable data. + + """ + #params = json.dumps(params).encode('utf8') + + base_url = 'http://data.rcc-acis.org/' # ACIS Web API URL + + if method == 'MultiStnData': + timeout=300 + else: + timeout=60 + + try: + response = requests.post(base_url+method, data=params, timeout=timeout) + return response.json() + except requests.exceptions.Timeout: + raise ACIS_API_Exception("Connection Timeout") + except requests.exceptions.TooManyRedirects: + raise ACIS_API_Exception("Bad URL. Check your ACIS connection method string.") + except ValueError: + raise ACIS_API_Exception("No data returned! The ACIS parameter dictionary may + be incorrectly formatted") + +class ACIS_API_Exception(Exception): + """ + + This class handles exceptions raised by the acis_request function. + """ + pass From 5ef7f3a83d4c6ccc3540f1466e21d08af6fc23ef Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Wed, 17 Jan 2018 15:15:29 -0600 Subject: [PATCH 04/15] Fixes syntax error in acis_request --- siphon/simplewebservice/acis.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/siphon/simplewebservice/acis.py b/siphon/simplewebservice/acis.py index ae98da820..3a51e1bec 100644 --- a/siphon/simplewebservice/acis.py +++ b/siphon/simplewebservice/acis.py @@ -51,8 +51,7 @@ def acis_request(method, params): except requests.exceptions.TooManyRedirects: raise ACIS_API_Exception("Bad URL. Check your ACIS connection method string.") except ValueError: - raise ACIS_API_Exception("No data returned! The ACIS parameter dictionary may - be incorrectly formatted") + raise ACIS_API_Exception("No data returned! The ACIS parameter dictionary may be incorrectly formatted") class ACIS_API_Exception(Exception): """ From bea518c87ee8727d93c6c6c3220a7f8d3dd3929a Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Thu, 18 Jan 2018 11:14:53 -0600 Subject: [PATCH 05/15] - Finalizes acis_request function with requests - Adds examples and resources for Siphon documentation --- examples/acis/Basic_Overview.py | 93 +++++++++++++++++++ examples/acis/Mapping_Example.py | 149 +++++++++++++++++++++++++++++++ examples/acis/readme.txt | 27 ++++++ siphon/simplewebservice/acis.py | 12 ++- 4 files changed, 279 insertions(+), 2 deletions(-) create mode 100644 examples/acis/Basic_Overview.py create mode 100644 examples/acis/Mapping_Example.py create mode 100644 examples/acis/readme.txt diff --git a/examples/acis/Basic_Overview.py b/examples/acis/Basic_Overview.py new file mode 100644 index 000000000..dafb5eaa6 --- /dev/null +++ b/examples/acis/Basic_Overview.py @@ -0,0 +1,93 @@ +""" +============================= +Basic ACIS Web Services Usage +============================= + +Siphon's simplewebservice support also includes the ability to query the +Regional Climate Centers' ACIS data servers. ACIS data provides daily records +for most station networks in the U.S. and is updated hourly. + +In this example we will be querying the service for 20 years of temperature data +from Denver International Airport. +""" + +from siphon.simplewebservice.acis import acis_request +import matplotlib.pyplot as plt + +########################################### +# First, we need to assemble a dictionary containing the information we want. +# For this example we want the average temperature at Denver International (KDEN) +# from January 1, 1997 to December 1, 2017. While we could get the daily data, +# we will instead request the monthly averages, which the remote service will +# find for us. +parameters = {"sid":"KDEN", "sdate":"19970101", "edate":"20171231","elems":[{"name":"avgt","interval":"mly","duration":"mly","reduce":"mean"}]} + +########################################### +# These parameters are used to specify what kind of data we want. We are +# formatting this as a dictionary, the acis_request function will handle the +# conversion of this into a JSON string for us! +# +# As we explain how this dictionary is formatted, feel free to follow along +# using the API documentation here :http://www.rcc-acis.org/docs_webservices.html +# +# The first section of the parameters dictionary is focused on the station and +# period of interest. We have a 'sid' element where the airport identifier is, +# and sdate/edate which correspond to the starting and ending dates of the +# period of interest. +# +# The 'elems' list contains individual dictionaries of elements (variables) of +# interest. In this example we are requesting the average monthly temperature. +# If we also wanted the minimum temperature, we would simply add an additional +# dictionary to the 'elems' list. +# +# Now that we have assembled our dictionary, we need to decide what type of +# request we are making. You can request meta data (information about the +# station), station data (data from an individual station), data from multiple +# stations, or even images of pre-prepared data. +# +# In this case we are interested in a single station, so we will be using the +# method set aside for this called, 'StnData'. + +method = "StnData" + +########################################### +# Now that we have our request information ready, we can call the acis_request +# function and recieve our data! + +myData = acis_request(method,parameters) + +########################################### +# The data is also returned in a dictionary format, decoded from a JSON string. + +print(myData) + +########################################### +# We can see there are two parts to this data: The metadata, and the data. The +# metadata can be useful in mapping the observations (We'll do this in a later +# example). +# +# To wrap this example up, we are going to do a simple line graph of this 30 +# year temperature data using MatPlotLib! Notice that the data is decoded as +# a string, so you should convert those back into numbers before use. +# +# *Note: Missing data is recorded as M! + +stnName = myData['meta']['name'] + +avgt = [] +dates = [] +for obs in myData['data']: + if obs[0][-2:] == '01': + dates.append(obs[0]) + else: + dates.append('') + avgt.append(float(obs[1])) + +X = list(range(len(avgt))) + +plt.title(stnName) +plt.ylabel("Average Temperature (F)") +plt.plot(X,avgt) +plt.xticks(X,dates,rotation=45) + +plt.show() diff --git a/examples/acis/Mapping_Example.py b/examples/acis/Mapping_Example.py new file mode 100644 index 000000000..b6a51448e --- /dev/null +++ b/examples/acis/Mapping_Example.py @@ -0,0 +1,149 @@ +""" +=============================== +Multi Station Calls and Mapping +=============================== + +In this example we will be using Siphon's simplewebservice support to query +ACIS Web Services for multiple stations. We will plot precipitation +values recorded in Colorado and Wyoming during the 2013 flooding event. +""" +from siphon.simplewebservice.acis import acis_request +import matplotlib.pyplot as plt +import cartopy.crs as ccrs +import cartopy.feature as feat +import matplotlib.pyplot as plt +import numpy as np + +########################################### +# First, we need to assemble a dictionary containing the information we want. +# In this example we want multiple station information, which indicates we +# need a MultiStnData call. Our event period spans from September 9 through +# September 12, 2013. We know we are interested in precipitation totals, +# but we are also going to take advantage of the long-term record in ACIS +# and ask it to return what the departure from normal precipitation was on +# this day. + +parameters = {"state":"co","sdate":"20130909","edate":"20130912","elems":[ + {"name":"pcpn","interval":"dly"}, + {"name":"pcpn","interval":"dly","normal":"departure"}]} + +method = "MultiStnData" +########################################### +# In this case, rather than using station ID's, we are able to specify a new +# parameter called 'state'. If we were interested in other states, we could just +# add another to the list like this: "co,wy". Also notice how we are getting +# both the precipitation and departure from normal within one variable. We'll +# see how this changes the final data dictionary. Now let's make our call and +# review our data. + +myData = acis_request(method,parameters) + +print(myData) + +########################################### +# MultiStnData calls take longer to return than single stations, especially when +# you request multiple states. We can see the data is divided by station, with +# each station having it's own meta and data components. This time we also have +# multiple values in each data list. Each value corresponds to the variable we +# requested, in the order we requested it. So in this case, we have the +# precipitation value, followed by the departure from normal value. Before we +# plot this information, we need to add up the precipitation sums. But rather +# than doing it in Python, let's make another ACIS call that prepares this for +# us. + +parameters = {"state":"co","sdate":"20130909","edate":"20130912","elems":[ + {"name":"pcpn","interval":"dly","smry":"sum","smry_only":1}, + {"name":"pcpn","interval":"dly","smry":"sum","smry_only":1,"normal":"departure"}]} + +myData = acis_request(method,parameters) + +print(myData) + +########################################### +# First of all, we have two new components to our elements: 'smry' and 'smry_only'. +# 'smry' allows us to summarize the data over our time period. There are a few +# options for this, including being able to count the number of records exceeding +# a threshold (something we will explore in the next example). The other parameter, +# 'smry_only', allows us to only return the summary value and not the intermediate +# data. +# +# Now let's look at how our data has changed. Rather than having a just a 'meta' +# and 'data' component, we have a new one called 'smry'. As you've guessed, +# this contains our summary information (also in the order we requested it). +# By specifying 'smry_only', there is no 'data' component. If we also wanted +# all 4 days of data, we would simply remove that parameter. +# +# To wrap up this example, we will finally plot our precipitation sums and +# departures onto a map using CartoPy and MetPy. To do this we will utilize +# the meta data that is provided with each station's data. Within the metadata +# is a 'll' element that contains the latitude and longitude, which is perfect +# for plotting! +# +# One final thing to note is that not all stations have location information. +# Stations from the ThreadEx network cover general areas, and thus aren't +# packaged with precise latitudes and longitudes. We will skip them by +# identifying their network ID of 9 in the ACIS metadata. Don't worry about +# lost information though! These summarize stations that already exist within +# their areas! + +lat = [] +lon = [] +pcpn = [] +pcpn_dep = [] + +for stn in myData['data']: + # Skip threaded stations! They have no lat/lons + if stn['meta']['sids'][-1][-1] == '9': + continue + # Skip stations with missing data + if stn['smry'][0] == 'M' or stn['smry'][1] == 'M': + continue + + lat.append(stn['meta']['ll'][1]) + lon.append(stn['meta']['ll'][0]) + pcpn.append(float(stn['smry'][0])) + pcpn_dep.append(float(stn['smry'][1])) +########################################### +# Now we setup our map and plot the data! We are going to plot the station +# locations with a '+' symbol and label them with the precipitation value. +# We will use the departures to set the departure from normal values where: +# * Departure < 0 is Red +# * Departure > 0 is Green +# * Departure > 2 is Magenta +# +# This should help us visualize where the precipitation event was strongest! + +proj = ccrs.LambertConformal(central_longitude=-105, central_latitude=0, + standard_parallels=[35]) + +fig = plt.figure(figsize=(20, 10)) +ax = fig.add_subplot(1, 1, 1, projection=proj) + +state_boundaries = feat.NaturalEarthFeature(category='cultural', + name='admin_1_states_provinces_lines', + scale='110m', facecolor='none') + +ax.add_feature(feat.LAND, zorder=-1) +ax.add_feature(feat.OCEAN, zorder=-1) +ax.add_feature(feat.LAKES, zorder=-1) +ax.coastlines(resolution='110m', zorder=2, color='black') +ax.add_feature(state_boundaries, edgecolor='black') +ax.add_feature(feat.BORDERS, linewidth=2, edgecolor='black') + +# Set plot bounds +ax.set_extent((-109.9, -101.8, 36.5, 41.3)) + +# Plot each station, labeling based on departure +for stn in range(len(pcpn)): + if pcpn_dep[stn] >= 0 and pcpn_dep[stn] < 2: + ax.plot(lon[stn],lat[stn],'g+', markersize=7, transform=ccrs.Geodetic()) + ax.text(lon[stn],lat[stn], pcpn[stn], transform=ccrs.Geodetic()) + elif pcpn_dep[stn] >= 2: + ax.plot(lon[stn],lat[stn],'m+', markersize=7, transform=ccrs.Geodetic()) + ax.text(lon[stn],lat[stn], pcpn[stn], transform=ccrs.Geodetic()) + elif pcpn_dep[stn] < 0: + ax.plot(lon[stn],lat[stn],'r+', markersize=7, transform=ccrs.Geodetic()) + ax.text(lon[stn],lat[stn], pcpn[stn], transform=ccrs.Geodetic()) +ax.plot(pcpn) + +plt.show() diff --git a/examples/acis/readme.txt b/examples/acis/readme.txt new file mode 100644 index 000000000..bf110757e --- /dev/null +++ b/examples/acis/readme.txt @@ -0,0 +1,27 @@ +.. _acis_examples: + +ACIS Web Services +----------------- + +Examples of using Siphon's simplewebservice support to access and use data from +the Applied Climate Information System (ACIS) Web Services API provided by the +Regional Climate Centers. + +The ACIS Web Service API provides daily records for stations from the following +networks: +* WBAN +* COOP +* FAA +* WMO +* ICAO +* GHCN +* NWSLI/SHEF +* ThreadEx +* CoCoRahs +* California Multi-station Index + +Data is updated hourly and documentation on the API is available at +http://www.rcc-acis.org/docs_webservices.html + +A useful web tool for constructing query parameters is available here: +http://builder.rcc-acis.org/ diff --git a/siphon/simplewebservice/acis.py b/siphon/simplewebservice/acis.py index 3a51e1bec..b38ddc9d7 100644 --- a/siphon/simplewebservice/acis.py +++ b/siphon/simplewebservice/acis.py @@ -16,6 +16,15 @@ def acis_request(method, params): If a connection to the API fails, then it will raise an exception. Some bad calls will also return empty dictionaries. + ACIS Web Services is a distributed system! A call to the main URL can be + delivered to any climate center running a public instance of the service. + This makes the calls efficient, but also occasionaly results in failed + calls when a server you are directed to is having problems. Generally, + reconnecting after waiting a few seconds will resolve a problem. If problems + are persistent, contact ACIS developers at the High Plains Regional Climate + Center or Northeast Regional Climate Center who will look into server + issues. + Parameters ---------- method : str @@ -34,7 +43,6 @@ def acis_request(method, params): unparsable data. """ - #params = json.dumps(params).encode('utf8') base_url = 'http://data.rcc-acis.org/' # ACIS Web API URL @@ -44,7 +52,7 @@ def acis_request(method, params): timeout=60 try: - response = requests.post(base_url+method, data=params, timeout=timeout) + response = requests.post(base_url+method, json=params, timeout=timeout) return response.json() except requests.exceptions.Timeout: raise ACIS_API_Exception("Connection Timeout") From 5a5a44c45867072402cd253dd86f77d32d2d067d Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Thu, 18 Jan 2018 11:27:45 -0600 Subject: [PATCH 06/15] Fixes issues raised in Codacy check --- examples/acis/Basic_Overview.py | 3 ++- examples/acis/Mapping_Example.py | 2 -- siphon/simplewebservice/acis.py | 8 ++------ 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/examples/acis/Basic_Overview.py b/examples/acis/Basic_Overview.py index dafb5eaa6..0d522a331 100644 --- a/examples/acis/Basic_Overview.py +++ b/examples/acis/Basic_Overview.py @@ -20,7 +20,8 @@ # from January 1, 1997 to December 1, 2017. While we could get the daily data, # we will instead request the monthly averages, which the remote service will # find for us. -parameters = {"sid":"KDEN", "sdate":"19970101", "edate":"20171231","elems":[{"name":"avgt","interval":"mly","duration":"mly","reduce":"mean"}]} +parameters = {"sid":"KDEN", "sdate":"19970101", "edate":"20171231","elems":[ + {"name":"avgt","interval":"mly","duration":"mly","reduce":"mean"}]} ########################################### # These parameters are used to specify what kind of data we want. We are diff --git a/examples/acis/Mapping_Example.py b/examples/acis/Mapping_Example.py index b6a51448e..ac5b12a15 100644 --- a/examples/acis/Mapping_Example.py +++ b/examples/acis/Mapping_Example.py @@ -11,8 +11,6 @@ import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature as feat -import matplotlib.pyplot as plt -import numpy as np ########################################### # First, we need to assemble a dictionary containing the information we want. diff --git a/siphon/simplewebservice/acis.py b/siphon/simplewebservice/acis.py index b38ddc9d7..70fb61134 100644 --- a/siphon/simplewebservice/acis.py +++ b/siphon/simplewebservice/acis.py @@ -1,9 +1,4 @@ -import json -import urllib.request -import urllib.parse import requests -import json -import socket def acis_request(method, params): """ @@ -59,7 +54,8 @@ def acis_request(method, params): except requests.exceptions.TooManyRedirects: raise ACIS_API_Exception("Bad URL. Check your ACIS connection method string.") except ValueError: - raise ACIS_API_Exception("No data returned! The ACIS parameter dictionary may be incorrectly formatted") + raise ACIS_API_Exception("No data returned! The ACIS parameter dictionary\ + may be incorrectly formatted") class ACIS_API_Exception(Exception): """ From f3337102c793c8fdabf33063d9c2f321fb2a2bb5 Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Fri, 19 Jan 2018 08:28:34 -0600 Subject: [PATCH 07/15] - Fixes formatting issues - Changes use of requests directly in acis_request() to use siphon create_http_session() function. --- examples/acis/Basic_Overview.py | 18 +++++++++--------- examples/acis/Mapping_Example.py | 26 +++++++++++++------------- siphon/simplewebservice/acis.py | 27 ++++++++++++--------------- 3 files changed, 34 insertions(+), 37 deletions(-) diff --git a/examples/acis/Basic_Overview.py b/examples/acis/Basic_Overview.py index 0d522a331..ca60e23be 100644 --- a/examples/acis/Basic_Overview.py +++ b/examples/acis/Basic_Overview.py @@ -1,4 +1,4 @@ -""" +''' ============================= Basic ACIS Web Services Usage ============================= @@ -9,7 +9,7 @@ In this example we will be querying the service for 20 years of temperature data from Denver International Airport. -""" +''' from siphon.simplewebservice.acis import acis_request import matplotlib.pyplot as plt @@ -20,8 +20,8 @@ # from January 1, 1997 to December 1, 2017. While we could get the daily data, # we will instead request the monthly averages, which the remote service will # find for us. -parameters = {"sid":"KDEN", "sdate":"19970101", "edate":"20171231","elems":[ - {"name":"avgt","interval":"mly","duration":"mly","reduce":"mean"}]} +parameters = {'sid': 'KDEN', 'sdate': '19970101', 'edate': '20171231', 'elems': [ + {'name': 'avgt', 'interval': 'mly', 'duration': 'mly', 'reduce': 'mean'}]} ########################################### # These parameters are used to specify what kind of data we want. We are @@ -49,13 +49,13 @@ # In this case we are interested in a single station, so we will be using the # method set aside for this called, 'StnData'. -method = "StnData" +method = 'StnData' ########################################### # Now that we have our request information ready, we can call the acis_request # function and recieve our data! -myData = acis_request(method,parameters) +myData = acis_request(method, parameters) ########################################### # The data is also returned in a dictionary format, decoded from a JSON string. @@ -87,8 +87,8 @@ X = list(range(len(avgt))) plt.title(stnName) -plt.ylabel("Average Temperature (F)") -plt.plot(X,avgt) -plt.xticks(X,dates,rotation=45) +plt.ylabel('Average Temperature (F)') +plt.plot(X, avgt) +plt.xticks(X, dates, rotation=45) plt.show() diff --git a/examples/acis/Mapping_Example.py b/examples/acis/Mapping_Example.py index ac5b12a15..6a5f48b2b 100644 --- a/examples/acis/Mapping_Example.py +++ b/examples/acis/Mapping_Example.py @@ -1,4 +1,4 @@ -""" +''' =============================== Multi Station Calls and Mapping =============================== @@ -6,7 +6,7 @@ In this example we will be using Siphon's simplewebservice support to query ACIS Web Services for multiple stations. We will plot precipitation values recorded in Colorado and Wyoming during the 2013 flooding event. -""" +''' from siphon.simplewebservice.acis import acis_request import matplotlib.pyplot as plt import cartopy.crs as ccrs @@ -21,20 +21,20 @@ # and ask it to return what the departure from normal precipitation was on # this day. -parameters = {"state":"co","sdate":"20130909","edate":"20130912","elems":[ - {"name":"pcpn","interval":"dly"}, - {"name":"pcpn","interval":"dly","normal":"departure"}]} +parameters = {'state': 'co', 'sdate': '20130909', 'edate': '20130912', 'elems': [ + {'name': 'pcpn', 'interval': 'dly'}, + {'name': 'pcpn', 'interval': 'dly', 'normal': 'departure'}]} -method = "MultiStnData" +method = 'MultiStnData' ########################################### # In this case, rather than using station ID's, we are able to specify a new # parameter called 'state'. If we were interested in other states, we could just -# add another to the list like this: "co,wy". Also notice how we are getting +# add another to the list like this: 'co,wy'. Also notice how we are getting # both the precipitation and departure from normal within one variable. We'll # see how this changes the final data dictionary. Now let's make our call and # review our data. -myData = acis_request(method,parameters) +myData = acis_request(method, parameters) print(myData) @@ -49,11 +49,11 @@ # than doing it in Python, let's make another ACIS call that prepares this for # us. -parameters = {"state":"co","sdate":"20130909","edate":"20130912","elems":[ - {"name":"pcpn","interval":"dly","smry":"sum","smry_only":1}, - {"name":"pcpn","interval":"dly","smry":"sum","smry_only":1,"normal":"departure"}]} +parameters = {'state': 'co', 'sdate': '20130909', 'edate': '20130912', 'elems': [ + {'name': 'pcpn', 'interval': 'dly', 'smry': 'sum', 'smry_only': 1}, + {'name': 'pcpn', 'interval': 'dly', 'smry': 'sum', 'smry_only': 1, 'normal': 'departure'}]} -myData = acis_request(method,parameters) +myData = acis_request(method, parameters) print(myData) @@ -72,7 +72,7 @@ # all 4 days of data, we would simply remove that parameter. # # To wrap up this example, we will finally plot our precipitation sums and -# departures onto a map using CartoPy and MetPy. To do this we will utilize +# departures onto a map using CartoPy. To do this we will utilize # the meta data that is provided with each station's data. Within the metadata # is a 'll' element that contains the latitude and longitude, which is perfect # for plotting! diff --git a/siphon/simplewebservice/acis.py b/siphon/simplewebservice/acis.py index 70fb61134..27d54d2a4 100644 --- a/siphon/simplewebservice/acis.py +++ b/siphon/simplewebservice/acis.py @@ -1,7 +1,8 @@ import requests +from ..http_util import create_http_session def acis_request(method, params): - """ + ''' This function will make a request to the ACIS Web Services API for data based on the given method (StnMeta,StnData,MultiStnData,GridData,General) @@ -23,7 +24,7 @@ def acis_request(method, params): Parameters ---------- method : str - The Web Services request method (MultiStn,StnMeta,etc) + The Web Services request method (StnMeta, StnData, MultiStnData, GridData, General) params : dict A JSON array of parameters (See Web Services API) @@ -37,29 +38,25 @@ def acis_request(method, params): When the API is unable to establish a connection or returns unparsable data. - """ + ''' base_url = 'http://data.rcc-acis.org/' # ACIS Web API URL - if method == 'MultiStnData': - timeout=300 - else: - timeout=60 + timeout = 300 if method == 'MultiStnData' else 60 try: - response = requests.post(base_url+method, json=params, timeout=timeout) + response = create_http_session().post(base_url + method, json=params, timeout=timeout) return response.json() except requests.exceptions.Timeout: - raise ACIS_API_Exception("Connection Timeout") + raise ACIS_API_Exception('Connection Timeout') except requests.exceptions.TooManyRedirects: - raise ACIS_API_Exception("Bad URL. Check your ACIS connection method string.") + raise ACIS_API_Exception('Bad URL. Check your ACIS connection method string.') except ValueError: - raise ACIS_API_Exception("No data returned! The ACIS parameter dictionary\ - may be incorrectly formatted") + raise ACIS_API_Exception('No data returned! The ACIS parameter dictionary' + 'may be incorrectly formatted') class ACIS_API_Exception(Exception): - """ - + ''' This class handles exceptions raised by the acis_request function. - """ + ''' pass From 7d00b16470ef2098c559c8eee1510daad71db657 Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Fri, 19 Jan 2018 11:38:44 -0600 Subject: [PATCH 08/15] Adds unit test for acis.py --- siphon/tests/test_acis.py | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 siphon/tests/test_acis.py diff --git a/siphon/tests/test_acis.py b/siphon/tests/test_acis.py new file mode 100644 index 000000000..e074a3361 --- /dev/null +++ b/siphon/tests/test_acis.py @@ -0,0 +1,41 @@ +'''Test ACIS Web Services API Access''' +from siphon.simplewebservice.acis import acis_request +from siphon.testing import get_recorder + +recorder = get_recorder(__file__) + +@recorder.use_cassette('acis_request') +def test_acis(): + '''Testing each protocol for consistent form.''' + data = acis_request('StnMeta', {'sids': 'KLNK'}) + + assert data['meta'][0]['uid'] == 12527 + + data = acis_request('StnData', {'sid': 'klnk', 'elems': [ + {'name': 'avgt', 'interval': 'dly'}, + {'name': 'mint', 'interval': 'dly'}], 'date': '20000101'}) + + assert data['meta']['uid'] == 12527 + assert data['data'][0][0] == '2000-01-01' + assert data['data'][0][1] == '37.5' + assert data['data'][0][2] == '26' + + data = acis_request('MultiStnData', {'sids': 'klnk,kgso', 'elems': [ + {'name': 'avgt', 'interval': 'dly'}, + {'name': 'mint', 'interval': 'dly'}], 'date':'20000101'}) + + assert data['data'][0]['meta']['uid'] == 12527 + assert data['data'][0]['data'][0] == '37.5' + assert data['data'][1]['meta']['uid'] == 13284 + assert data['data'][1]['data'][0] == '49.0' + + data = acis_request('GridData', {'loc': '-95.36, 29.76', 'sdate': '2000-01', + 'edate': '2000-07', 'grid': '3', 'elems': [ + {'name': 'maxt', 'interval': 'mly', 'reduce': 'max', 'smry': 'max'} + ]}) + + assert data['data'][0][1] == 81 + + data = acis_request('General/state', {'state': 'ne'}) + + assert data['meta'][0]['name'] == 'Nebraska' From 1bb8b4b5f5f7aaa7ca3082a35da88f90872badbc Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Fri, 19 Jan 2018 13:27:32 -0600 Subject: [PATCH 09/15] Adds acis_request VCR data to siphon/tests/fixtures --- siphon/tests/fixtures/acis_request | 148 +++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 siphon/tests/fixtures/acis_request diff --git a/siphon/tests/fixtures/acis_request b/siphon/tests/fixtures/acis_request new file mode 100644 index 000000000..9b0979e18 --- /dev/null +++ b/siphon/tests/fixtures/acis_request @@ -0,0 +1,148 @@ +interactions: +- request: + body: '{"sids": "KLNK"}' + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + Content-Length: ['16'] + Content-Type: [application/json] + User-Agent: [Siphon (0.6.0+10.g7d00b16.dirty)] + method: POST + uri: http://data.rcc-acis.org/StnMeta + response: + body: {string: '{"meta":[ + + {"name": "LINCOLN AIRPORT", "ll": [-96.7475, 40.8508], "sids": ["14939 1", + "254795 2", "LNK 3", "72551 4", "KLNK 5", "USW00014939 6", "LNK 7"], "state": + "NE", "elev": 1190.0, "uid": 12527}]} + + '} + headers: + Access-Control-Allow-Origin: ['*'] + Connection: [keep-alive] + Content-Type: [application/json] + Date: ['Fri, 19 Jan 2018 19:04:12 GMT'] + Server: [nginx/1.12.2] + status: {code: 200, message: OK} +- request: + body: '{"sid": "klnk", "elems": [{"name": "avgt", "interval": "dly"}, {"name": + "mint", "interval": "dly"}], "date": "20000101"}' + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + Content-Length: ['120'] + Content-Type: [application/json] + User-Agent: [Siphon (0.6.0+10.g7d00b16.dirty)] + method: POST + uri: http://data.rcc-acis.org/StnData + response: + body: {string: '{"meta":{"uid": 12527, "ll": [-96.7475, 40.8508], "sids": ["14939 + 1", "254795 2", "LNK 3", "72551 4", "KLNK 5", "USW00014939 6", "LNK 7"], "state": + "NE", "elev": 1190.0, "name": "LINCOLN AIRPORT"}, + + "data":[["2000-01-01","37.5","26"]]} + + '} + headers: + Access-Control-Allow-Origin: ['*'] + Connection: [keep-alive] + Content-Type: [application/json] + Date: ['Fri, 19 Jan 2018 19:04:14 GMT'] + Server: [nginx/1.12.2] + status: {code: 200, message: OK} +- request: + body: '{"sids": "klnk,kgso", "elems": [{"name": "avgt", "interval": "dly"}, {"name": + "mint", "interval": "dly"}], "date": "20000101"}' + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + Content-Length: ['126'] + Content-Type: [application/json] + User-Agent: [Siphon (0.6.0+10.g7d00b16.dirty)] + method: POST + uri: http://data.rcc-acis.org/MultiStnData + response: + body: {string: '{"data":[ + + {"meta":{"uid": 12527, "ll": [-96.7475, 40.8508], "sids": ["14939 1", "254795 + 2", "LNK 3", "72551 4", "KLNK 5", "USW00014939 6", "LNK 7"], "state": "NE", + "elev": 1190.0, "name": "LINCOLN AIRPORT"},"data":["37.5","26"]}, + + {"meta":{"uid": 13284, "ll": [-79.9432, 36.0969], "sids": ["13723 1", "313630 + 2", "GSO 3", "72317 4", "KGSO 5", "USW00013723 6", "GSO 7"], "state": "NC", + "elev": 890.0, "name": "GREENSBORO AP"},"data":["49.0","37"]}]} + + '} + headers: + Access-Control-Allow-Origin: ['*'] + Connection: [keep-alive] + Content-Type: [application/json] + Date: ['Fri, 19 Jan 2018 19:04:14 GMT'] + Server: [nginx/1.12.2] + status: {code: 200, message: OK} +- request: + body: '{"loc": "-95.36, 29.76", "sdate": "2000-01", "edate": "2000-07", "grid": + "3", "elems": [{"name": "maxt", "interval": "mly", "reduce": "max", "smry": + "max"}]}' + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + Content-Length: ['157'] + Content-Type: [application/json] + User-Agent: [Siphon (0.6.0+10.g7d00b16.dirty)] + method: POST + uri: http://data.rcc-acis.org/GridData + response: + body: {string: '{"data":[["2000-01",81], + + ["2000-02",82], + + ["2000-03",87], + + ["2000-04",89], + + ["2000-05",93], + + ["2000-06",94], + + ["2000-07",103]], + + "smry":[103]} + + '} + headers: + Access-Control-Allow-Origin: ['*'] + Connection: [keep-alive] + Content-Type: [application/json] + Date: ['Fri, 19 Jan 2018 19:04:15 GMT'] + Server: [nginx/1.12.2] + status: {code: 200, message: OK} +- request: + body: '{"state": "ne"}' + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + Content-Length: ['15'] + Content-Type: [application/json] + User-Agent: [Siphon (0.6.0+10.g7d00b16.dirty)] + method: POST + uri: http://data.rcc-acis.org/General/state + response: + body: {string: '{"meta":[ + + {"id":"NE","name":"Nebraska"}]} + + '} + headers: + Access-Control-Allow-Origin: ['*'] + Connection: [keep-alive] + Content-Type: [application/json] + Date: ['Fri, 19 Jan 2018 19:04:15 GMT'] + Server: [nginx/1.12.2] + status: {code: 200, message: OK} +version: 1 From 43a51e36acc55a0a7e3b1c59ea6f1d23919fae67 Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Fri, 19 Jan 2018 14:04:40 -0600 Subject: [PATCH 10/15] Splits acis_test into 5 separate unit tests. --- siphon/tests/test_acis.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/siphon/tests/test_acis.py b/siphon/tests/test_acis.py index e074a3361..6b183060e 100644 --- a/siphon/tests/test_acis.py +++ b/siphon/tests/test_acis.py @@ -5,12 +5,13 @@ recorder = get_recorder(__file__) @recorder.use_cassette('acis_request') -def test_acis(): +def test_acis_metadata(): '''Testing each protocol for consistent form.''' data = acis_request('StnMeta', {'sids': 'KLNK'}) assert data['meta'][0]['uid'] == 12527 +def test_acis_stndata(): data = acis_request('StnData', {'sid': 'klnk', 'elems': [ {'name': 'avgt', 'interval': 'dly'}, {'name': 'mint', 'interval': 'dly'}], 'date': '20000101'}) @@ -20,6 +21,7 @@ def test_acis(): assert data['data'][0][1] == '37.5' assert data['data'][0][2] == '26' +def test_acis_multistn(): data = acis_request('MultiStnData', {'sids': 'klnk,kgso', 'elems': [ {'name': 'avgt', 'interval': 'dly'}, {'name': 'mint', 'interval': 'dly'}], 'date':'20000101'}) @@ -29,6 +31,7 @@ def test_acis(): assert data['data'][1]['meta']['uid'] == 13284 assert data['data'][1]['data'][0] == '49.0' +def test_acis_griddata(): data = acis_request('GridData', {'loc': '-95.36, 29.76', 'sdate': '2000-01', 'edate': '2000-07', 'grid': '3', 'elems': [ {'name': 'maxt', 'interval': 'mly', 'reduce': 'max', 'smry': 'max'} @@ -36,6 +39,7 @@ def test_acis(): assert data['data'][0][1] == 81 +def test_acis_general(): data = acis_request('General/state', {'state': 'ne'}) assert data['meta'][0]['name'] == 'Nebraska' From 17860de3d737760c4d1c272651750767fde39132 Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Fri, 19 Jan 2018 14:06:51 -0600 Subject: [PATCH 11/15] Adds neccessary comments to each unit test in test_acis.py --- siphon/tests/test_acis.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/siphon/tests/test_acis.py b/siphon/tests/test_acis.py index 6b183060e..1a4c2ecd2 100644 --- a/siphon/tests/test_acis.py +++ b/siphon/tests/test_acis.py @@ -6,12 +6,13 @@ @recorder.use_cassette('acis_request') def test_acis_metadata(): - '''Testing each protocol for consistent form.''' + '''Testing ACIS MetaData request.''' data = acis_request('StnMeta', {'sids': 'KLNK'}) assert data['meta'][0]['uid'] == 12527 def test_acis_stndata(): + '''Testing ACIS Station Data request.''' data = acis_request('StnData', {'sid': 'klnk', 'elems': [ {'name': 'avgt', 'interval': 'dly'}, {'name': 'mint', 'interval': 'dly'}], 'date': '20000101'}) @@ -22,6 +23,7 @@ def test_acis_stndata(): assert data['data'][0][2] == '26' def test_acis_multistn(): + '''Testing ACIS Multi Station Data request.''' data = acis_request('MultiStnData', {'sids': 'klnk,kgso', 'elems': [ {'name': 'avgt', 'interval': 'dly'}, {'name': 'mint', 'interval': 'dly'}], 'date':'20000101'}) @@ -32,6 +34,7 @@ def test_acis_multistn(): assert data['data'][1]['data'][0] == '49.0' def test_acis_griddata(): + '''Testing ACIS Gridded Data request.''' data = acis_request('GridData', {'loc': '-95.36, 29.76', 'sdate': '2000-01', 'edate': '2000-07', 'grid': '3', 'elems': [ {'name': 'maxt', 'interval': 'mly', 'reduce': 'max', 'smry': 'max'} @@ -40,6 +43,7 @@ def test_acis_griddata(): assert data['data'][0][1] == 81 def test_acis_general(): + '''Testing ACIS General request.''' data = acis_request('General/state', {'state': 'ne'}) assert data['meta'][0]['name'] == 'Nebraska' From c62483f62650fdffcf3dedee6987a5052939de17 Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Fri, 19 Jan 2018 14:41:47 -0600 Subject: [PATCH 12/15] Fixes initial style issues found by Travis-CI --- examples/acis/Basic_Overview.py | 6 +++--- examples/acis/Mapping_Example.py | 21 +++++++++++---------- siphon/simplewebservice/acis.py | 22 ++++++++++++---------- siphon/tests/test_acis.py | 16 ++++++++++------ 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/examples/acis/Basic_Overview.py b/examples/acis/Basic_Overview.py index ca60e23be..eed7f4f31 100644 --- a/examples/acis/Basic_Overview.py +++ b/examples/acis/Basic_Overview.py @@ -1,4 +1,4 @@ -''' +""" ============================= Basic ACIS Web Services Usage ============================= @@ -9,10 +9,10 @@ In this example we will be querying the service for 20 years of temperature data from Denver International Airport. -''' +""" -from siphon.simplewebservice.acis import acis_request import matplotlib.pyplot as plt +from siphon.simplewebservice.acis import acis_request ########################################### # First, we need to assemble a dictionary containing the information we want. diff --git a/examples/acis/Mapping_Example.py b/examples/acis/Mapping_Example.py index 6a5f48b2b..cd072365c 100644 --- a/examples/acis/Mapping_Example.py +++ b/examples/acis/Mapping_Example.py @@ -1,4 +1,4 @@ -''' +""" =============================== Multi Station Calls and Mapping =============================== @@ -6,11 +6,12 @@ In this example we will be using Siphon's simplewebservice support to query ACIS Web Services for multiple stations. We will plot precipitation values recorded in Colorado and Wyoming during the 2013 flooding event. -''' -from siphon.simplewebservice.acis import acis_request -import matplotlib.pyplot as plt +""" + import cartopy.crs as ccrs import cartopy.feature as feat +import matplotlib.pyplot as plt +from siphon.simplewebservice.acis import acis_request ########################################### # First, we need to assemble a dictionary containing the information we want. @@ -134,14 +135,14 @@ # Plot each station, labeling based on departure for stn in range(len(pcpn)): if pcpn_dep[stn] >= 0 and pcpn_dep[stn] < 2: - ax.plot(lon[stn],lat[stn],'g+', markersize=7, transform=ccrs.Geodetic()) - ax.text(lon[stn],lat[stn], pcpn[stn], transform=ccrs.Geodetic()) + ax.plot(lon[stn], lat[stn], 'g+', markersize=7, transform=ccrs.Geodetic()) + ax.text(lon[stn], lat[stn], pcpn[stn], transform=ccrs.Geodetic()) elif pcpn_dep[stn] >= 2: - ax.plot(lon[stn],lat[stn],'m+', markersize=7, transform=ccrs.Geodetic()) - ax.text(lon[stn],lat[stn], pcpn[stn], transform=ccrs.Geodetic()) + ax.plot(lon[stn], lat[stn], 'm+', markersize=7, transform=ccrs.Geodetic()) + ax.text(lon[stn], lat[stn], pcpn[stn], transform=ccrs.Geodetic()) elif pcpn_dep[stn] < 0: - ax.plot(lon[stn],lat[stn],'r+', markersize=7, transform=ccrs.Geodetic()) - ax.text(lon[stn],lat[stn], pcpn[stn], transform=ccrs.Geodetic()) + ax.plot(lon[stn], lat[stn], 'r+', markersize=7, transform=ccrs.Geodetic()) + ax.text(lon[stn], lat[stn], pcpn[stn], transform=ccrs.Geodetic()) ax.plot(pcpn) plt.show() diff --git a/siphon/simplewebservice/acis.py b/siphon/simplewebservice/acis.py index 27d54d2a4..eaf393b39 100644 --- a/siphon/simplewebservice/acis.py +++ b/siphon/simplewebservice/acis.py @@ -1,8 +1,11 @@ +"""Requests data from the ACIS Web Services API""" + import requests from ..http_util import create_http_session + def acis_request(method, params): - ''' + """ This function will make a request to the ACIS Web Services API for data based on the given method (StnMeta,StnData,MultiStnData,GridData,General) @@ -38,8 +41,7 @@ def acis_request(method, params): When the API is unable to establish a connection or returns unparsable data. - ''' - + """ base_url = 'http://data.rcc-acis.org/' # ACIS Web API URL timeout = 300 if method == 'MultiStnData' else 60 @@ -48,15 +50,15 @@ def acis_request(method, params): response = create_http_session().post(base_url + method, json=params, timeout=timeout) return response.json() except requests.exceptions.Timeout: - raise ACIS_API_Exception('Connection Timeout') + raise AcisApiException('Connection Timeout') except requests.exceptions.TooManyRedirects: - raise ACIS_API_Exception('Bad URL. Check your ACIS connection method string.') + raise AcisApiException('Bad URL. Check your ACIS connection method string.') except ValueError: - raise ACIS_API_Exception('No data returned! The ACIS parameter dictionary' + raise AcisApiException('No data returned! The ACIS parameter dictionary' 'may be incorrectly formatted') -class ACIS_API_Exception(Exception): - ''' - This class handles exceptions raised by the acis_request function. - ''' + +class AcisApiException(Exception): + """This class handles exceptions raised by the acis_request function.""" + pass diff --git a/siphon/tests/test_acis.py b/siphon/tests/test_acis.py index 1a4c2ecd2..53a353450 100644 --- a/siphon/tests/test_acis.py +++ b/siphon/tests/test_acis.py @@ -1,18 +1,19 @@ -'''Test ACIS Web Services API Access''' +"""Test ACIS Web Services API Access.""" from siphon.simplewebservice.acis import acis_request from siphon.testing import get_recorder recorder = get_recorder(__file__) + @recorder.use_cassette('acis_request') def test_acis_metadata(): - '''Testing ACIS MetaData request.''' + """Testing ACIS MetaData request.""" data = acis_request('StnMeta', {'sids': 'KLNK'}) assert data['meta'][0]['uid'] == 12527 def test_acis_stndata(): - '''Testing ACIS Station Data request.''' + """Testing ACIS Station Data request.""" data = acis_request('StnData', {'sid': 'klnk', 'elems': [ {'name': 'avgt', 'interval': 'dly'}, {'name': 'mint', 'interval': 'dly'}], 'date': '20000101'}) @@ -22,8 +23,9 @@ def test_acis_stndata(): assert data['data'][0][1] == '37.5' assert data['data'][0][2] == '26' + def test_acis_multistn(): - '''Testing ACIS Multi Station Data request.''' + """Testing ACIS Multi Station Data request.""" data = acis_request('MultiStnData', {'sids': 'klnk,kgso', 'elems': [ {'name': 'avgt', 'interval': 'dly'}, {'name': 'mint', 'interval': 'dly'}], 'date':'20000101'}) @@ -33,8 +35,9 @@ def test_acis_multistn(): assert data['data'][1]['meta']['uid'] == 13284 assert data['data'][1]['data'][0] == '49.0' + def test_acis_griddata(): - '''Testing ACIS Gridded Data request.''' + """Testing ACIS Gridded Data request.""" data = acis_request('GridData', {'loc': '-95.36, 29.76', 'sdate': '2000-01', 'edate': '2000-07', 'grid': '3', 'elems': [ {'name': 'maxt', 'interval': 'mly', 'reduce': 'max', 'smry': 'max'} @@ -42,8 +45,9 @@ def test_acis_griddata(): assert data['data'][0][1] == 81 + def test_acis_general(): - '''Testing ACIS General request.''' + """Testing ACIS General request.""" data = acis_request('General/state', {'state': 'ne'}) assert data['meta'][0]['name'] == 'Nebraska' From 67227f4c58b17782b251ef09a957d287684a69b8 Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Fri, 19 Jan 2018 15:07:05 -0600 Subject: [PATCH 13/15] Fixes more PEP8 style issues found by Travis-CI --- examples/acis/Basic_Overview.py | 1 + examples/acis/Mapping_Example.py | 1 + siphon/simplewebservice/acis.py | 13 +++++++------ siphon/tests/test_acis.py | 7 ++++--- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/examples/acis/Basic_Overview.py b/examples/acis/Basic_Overview.py index eed7f4f31..700e680ca 100644 --- a/examples/acis/Basic_Overview.py +++ b/examples/acis/Basic_Overview.py @@ -12,6 +12,7 @@ """ import matplotlib.pyplot as plt + from siphon.simplewebservice.acis import acis_request ########################################### diff --git a/examples/acis/Mapping_Example.py b/examples/acis/Mapping_Example.py index cd072365c..075d5815f 100644 --- a/examples/acis/Mapping_Example.py +++ b/examples/acis/Mapping_Example.py @@ -11,6 +11,7 @@ import cartopy.crs as ccrs import cartopy.feature as feat import matplotlib.pyplot as plt + from siphon.simplewebservice.acis import acis_request ########################################### diff --git a/siphon/simplewebservice/acis.py b/siphon/simplewebservice/acis.py index eaf393b39..015447254 100644 --- a/siphon/simplewebservice/acis.py +++ b/siphon/simplewebservice/acis.py @@ -1,14 +1,15 @@ -"""Requests data from the ACIS Web Services API""" +"""Requests data from the ACIS Web Services API.""" import requests + from ..http_util import create_http_session def acis_request(method, params): - """ + """Requests data from the ACIS Web Services API. - This function will make a request to the ACIS Web Services API for data - based on the given method (StnMeta,StnData,MultiStnData,GridData,General) + Makes a request from the ACIS Web Services API for data + based on a given method (StnMeta,StnData,MultiStnData,GridData,General) and parameters string. Information about the parameters can be obtained at: http://www.rcc-acis.org/docs_webservices.html @@ -55,9 +56,9 @@ def acis_request(method, params): raise AcisApiException('Bad URL. Check your ACIS connection method string.') except ValueError: raise AcisApiException('No data returned! The ACIS parameter dictionary' - 'may be incorrectly formatted') + 'may be incorrectly formatted') + - class AcisApiException(Exception): """This class handles exceptions raised by the acis_request function.""" diff --git a/siphon/tests/test_acis.py b/siphon/tests/test_acis.py index 53a353450..84c5df70d 100644 --- a/siphon/tests/test_acis.py +++ b/siphon/tests/test_acis.py @@ -12,6 +12,7 @@ def test_acis_metadata(): assert data['meta'][0]['uid'] == 12527 + def test_acis_stndata(): """Testing ACIS Station Data request.""" data = acis_request('StnData', {'sid': 'klnk', 'elems': [ @@ -28,7 +29,7 @@ def test_acis_multistn(): """Testing ACIS Multi Station Data request.""" data = acis_request('MultiStnData', {'sids': 'klnk,kgso', 'elems': [ {'name': 'avgt', 'interval': 'dly'}, - {'name': 'mint', 'interval': 'dly'}], 'date':'20000101'}) + {'name': 'mint', 'interval': 'dly'}], 'date': '20000101'}) assert data['data'][0]['meta']['uid'] == 12527 assert data['data'][0]['data'][0] == '37.5' @@ -40,8 +41,8 @@ def test_acis_griddata(): """Testing ACIS Gridded Data request.""" data = acis_request('GridData', {'loc': '-95.36, 29.76', 'sdate': '2000-01', 'edate': '2000-07', 'grid': '3', 'elems': [ - {'name': 'maxt', 'interval': 'mly', 'reduce': 'max', 'smry': 'max'} - ]}) + {'name': 'maxt', 'interval': 'mly', 'reduce': 'max', + 'smry': 'max'}]}) assert data['data'][0][1] == 81 From fd8bee4612d9551925238dae81f1dea76146efa7 Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Fri, 19 Jan 2018 15:38:12 -0600 Subject: [PATCH 14/15] Fixes PEP-8 style issues found by Travis-CI --- siphon/simplewebservice/acis.py | 2 +- siphon/tests/test_acis.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/siphon/simplewebservice/acis.py b/siphon/simplewebservice/acis.py index 015447254..07dbe221e 100644 --- a/siphon/simplewebservice/acis.py +++ b/siphon/simplewebservice/acis.py @@ -6,7 +6,7 @@ def acis_request(method, params): - """Requests data from the ACIS Web Services API. + """Request data from the ACIS Web Services API. Makes a request from the ACIS Web Services API for data based on a given method (StnMeta,StnData,MultiStnData,GridData,General) diff --git a/siphon/tests/test_acis.py b/siphon/tests/test_acis.py index 84c5df70d..a6d115b52 100644 --- a/siphon/tests/test_acis.py +++ b/siphon/tests/test_acis.py @@ -39,10 +39,10 @@ def test_acis_multistn(): def test_acis_griddata(): """Testing ACIS Gridded Data request.""" - data = acis_request('GridData', {'loc': '-95.36, 29.76', 'sdate': '2000-01', - 'edate': '2000-07', 'grid': '3', 'elems': [ - {'name': 'maxt', 'interval': 'mly', 'reduce': 'max', - 'smry': 'max'}]}) + data = acis_request('GridData', + {'loc': '-95.36, 29.76', 'sdate': '2000-01', 'edate': '2000-07', + 'grid': '3', 'elems': [{'name': 'maxt', 'interval': 'mly', + 'reduce': 'max', 'smry': 'max'}]}) assert data['data'][0][1] == 81 From fab1c2ab28cf3ce22d69b254cee4f90439f87eca Mon Sep 17 00:00:00 2001 From: Warren Pettee Date: Tue, 30 Jan 2018 08:29:48 -0600 Subject: [PATCH 15/15] Makes Pythonic changes to some string searches. --- examples/acis/Basic_Overview.py | 2 +- examples/acis/Mapping_Example.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/acis/Basic_Overview.py b/examples/acis/Basic_Overview.py index 700e680ca..4ccfc61cd 100644 --- a/examples/acis/Basic_Overview.py +++ b/examples/acis/Basic_Overview.py @@ -79,7 +79,7 @@ avgt = [] dates = [] for obs in myData['data']: - if obs[0][-2:] == '01': + if obs[0].endswith('01'): dates.append(obs[0]) else: dates.append('') diff --git a/examples/acis/Mapping_Example.py b/examples/acis/Mapping_Example.py index 075d5815f..9038d87c3 100644 --- a/examples/acis/Mapping_Example.py +++ b/examples/acis/Mapping_Example.py @@ -93,7 +93,7 @@ for stn in myData['data']: # Skip threaded stations! They have no lat/lons - if stn['meta']['sids'][-1][-1] == '9': + if stn['meta']['sids'][-1].endswith('9'): continue # Skip stations with missing data if stn['smry'][0] == 'M' or stn['smry'][1] == 'M':