Skip to content
109 changes: 103 additions & 6 deletions notebooks/demo_individual/demo_parameters.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
"from birdy import WPSClient\n",
"from pkg_resources import resource_filename\n",
"\n",
"import requests"
"import requests\n",
"\n",
"# For mixed demo\n",
"from tempfile import NamedTemporaryFile"
]
},
{
Expand Down Expand Up @@ -43,7 +46,7 @@
"data": {
"text/plain": [
"\u001b[0;31mType:\u001b[0m WPSClient\n",
"\u001b[0;31mString form:\u001b[0m <birdy.client.base.WPSClient object at 0x7fa7f84f42e8>\n",
"\u001b[0;31mString form:\u001b[0m <birdy.client.base.WPSClient object at 0x7f07302baeb8>\n",
"\u001b[0;31mFile:\u001b[0m ~/osprey-venv/lib/python3.6/site-packages/birdy/client/base.py\n",
"\u001b[0;31mDocstring:\u001b[0m \n",
"A Web Processing Service for Climate Data Analysis.\n",
Expand Down Expand Up @@ -145,8 +148,8 @@
}
],
"source": [
"cfg_file = resource_filename(\"tests\", \"data/samples/sample_parameter_config.cfg\")\n",
"print(cfg_file)"
"cfg_file_local = resource_filename(\"tests\", \"data/samples/sample_parameter_config.cfg\")\n",
"print(cfg_file_local)"
]
},
{
Expand All @@ -157,7 +160,7 @@
"source": [
"# run parameters\n",
"output = osprey.parameters(\n",
" config = cfg_file\n",
" config = cfg_file_local\n",
")"
]
},
Expand All @@ -170,7 +173,7 @@
"data": {
"text/plain": [
"parametersResponse(\n",
" output='http://localhost:5002/outputs/22f2799c-dc02-11ea-a870-c86000e3f2fd/sample.rvic.prm.COLUMBIA.20200811.nc'\n",
" output='http://localhost:5002/outputs/c70edd66-e893-11ea-a870-c86000e3f2fd/sample.rvic.prm.COLUMBIA.20200827.nc'\n",
")"
]
},
Expand All @@ -182,6 +185,100 @@
"source": [
"output.get()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"/home/slim/osprey/tests/configs/parameter_mixed.cfg\n"
]
}
],
"source": [
"# FILE_PATHS are a mix of local paths and https urls\n",
"cfg_file_mixed = resource_filename(\"tests\", \"configs/parameter_mixed.cfg\")\n",
"print(cfg_file_mixed)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"config_name = os.path.splitext(cfg_file_mixed)[0] # Remove .cfg extension\n",
"with NamedTemporaryFile(\n",
" suffix=\".cfg\", prefix=os.path.basename(config_name), mode=\"w+t\"\n",
") as temp_config: # Avoid permanent replacement of https URLs\n",
" read_config = open(cfg_file_mixed, \"r\")\n",
" temp_config.writelines(read_config.read())\n",
" temp_config.read()\n",
" output = osprey.parameters(\n",
" config = temp_config.name\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"parametersResponse(\n",
" output='http://localhost:5002/outputs/ce1ee182-e893-11ea-a870-c86000e3f2fd/sample.rvic.prm.COLUMBIA.20200827.nc'\n",
")"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"output.get()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
2 changes: 1 addition & 1 deletion osprey/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def stop():
@click.option(
"--parallelprocesses",
metavar="INT",
default="2",
default="20",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert this change

help="parallelprocesses in PyWPS configuration.",
)
@click.option(
Expand Down
4 changes: 3 additions & 1 deletion osprey/processes/wps_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@
log_level,
nc_output,
)
from osprey.utils import logger
from osprey.utils import logger, replace_urls

# Library imports
import os
import json
from datetime import datetime
from pkg_resources import resource_filename


class Parameters(Process):
Expand Down Expand Up @@ -97,6 +98,7 @@ def _handler(self, request, response):
logger.info(version.short_version)

(config, np, loglevel) = self.collect_args(request)
replace_urls(config, self.workdir)
log_handler(
self,
response,
Expand Down
28 changes: 28 additions & 0 deletions osprey/testing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from pkg_resources import resource_filename


def make_mock_urls(config, requests_mock):
"""Create mock get requests for urls in
config file

Since it is possible for a test file to not
exist on THREDDS, requests_mock is used to
get these urls, and their content is the corresponding
data coming from the same file in local storage.

Parameters:
config (str): Path to config file
requests_mock: requests_mock fixture
"""
read_config = open(config, "r")
config_data = read_config.readlines()
read_config.close()
for line in config_data:
if "https" in line:
url = line.split(" ")[-1] # https url is last word in line
url = url.rstrip() # remove \n character at end
filename = url.split("/")[-1]
f = open(resource_filename("tests", f"data/samples/{filename}"), "rb")
filedata = f.read()
f.close()
requests_mock.get(url, content=filedata)
34 changes: 34 additions & 0 deletions osprey/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import logging
import os
import json
import requests
from datetime import datetime, timedelta
from tempfile import NamedTemporaryFile

logger = logging.getLogger("PYWPS")
logger.setLevel(logging.NOTSET)
Expand Down Expand Up @@ -34,6 +36,38 @@ def replace_filenames(config, temp_config):
temp_config.writelines(newdata)


def replace_urls(config, outdir):
"""
Copy https URLs to local storage and replace URLs
with local paths in config file.
Parameters:
config (str): Config file
outdir (str): Output directory
"""
read_config = open(config, "r")
filedata = read_config.readlines()
read_config.close()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use a context manager here.


for i in range(len(filedata)):
if "https" in filedata[i]:
url = filedata[i].split(" ")[-1] # https url is last word in line
url = url.rstrip() # remove \n character at end
r = requests.get(url)
filename = url.split("/")[-1]
prefix, suffix = filename.split(".")
suffix = "." + suffix
local_file = NamedTemporaryFile(
suffix=suffix, prefix=prefix, dir=outdir, delete=False
)
Comment on lines +57 to +59

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great use of tempfile here 👍

local_file.write(r.content)
filedata[i] = filedata[i].replace(url, local_file.name)
Comment on lines +49 to +61

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this is fine, we generally don't want to use indices if we can help it. It is more understandable to iterate through the iterable object : for data in filedata:....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used the index because I wasn't sure if the assignment in line 63 would modify the filedata list if I iterated through each element.


write_config = open(config, "w")
for line in filedata:
write_config.write(f"{line}")
write_config.close()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, we can use a context manager.



def config_hander(workdir, unprocessed, config_template):
"""
This function enables users to provide dictionary-like string for Configuration input.
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ pywps>=4.2
jinja2
click
psutil
rvic==1.1.0post1
rvic==1.1.1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

nchelpers==5.5.7
wps-tools==0.1.2
1 change: 1 addition & 0 deletions requirements_dev.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pytest
flake8
pytest-flake8
requests-mock

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know this package existed. I wonder if we can apply to our notebooks to make truly offline tests.

ipython
pytest-notebook
nbsphinx
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ SEARCH_FOR_CHANNEL: False
#-- Path to Pour Points File (char) --#
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to use this file in the jupyter lab demo as well

# A comma separated file of outlets to route to [lons, lats] - one coordinate pair per line (order not important)
# May optionally include a column [names] - which will (if not aggregating) be included in param file
FILE_NAME: https://docker-dev03.pcic.uvic.ca/twitcher/ows/proxy/thredds/dodsC/datasets/RVIC/sample_pour.txt
FILE_NAME: https://docker-dev03.pcic.uvic.ca/twitcher/ows/proxy/thredds/fileServer/datasets/RVIC/sample_pour.txt

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this change from dodsC to fileServer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is so that https instead of OpenDAP is used to download the file from THREDDS. James told me that it makes downloading entire files easier since I won't have to specify attributes or time ranges.


Copy link
Contributor

@sum1lim sum1lim Aug 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the ideal use of pour input is to get user inputs (lon and lat) and create a pour.txt file in the tmp directory. It is a variable that needs to be dynamically defined by users. @jameshiebert @corviday , do you think this is the right approach? I guess we don't have to worry about that in this PR. I will write an issue if it is needed.

#-- ====================================== --#

Expand All @@ -83,7 +83,7 @@ FILE_NAME: https://docker-dev03.pcic.uvic.ca/twitcher/ows/proxy/thredds/dodsC/da
# This defines the unit hydrograph to rout flow to the edge of each grid cell.
# A comma separated file of [time in seconds, unit hydrograph ordinate] - one timestep per line
# The timestep should be 1hr (3600 sec) or less.
FILE_NAME: https://docker-dev03.pcic.uvic.ca/twitcher/ows/proxy/thredds/dodsC/datasets/RVIC/uhbox.csv
FILE_NAME: https://docker-dev03.pcic.uvic.ca/twitcher/ows/proxy/thredds/fileServer/datasets/RVIC/uhbox.csv

#-- Number of Header lines to ignore in [UH_BOX]FILE_NAME (INT) --#
HEADER_LINES = 1
Expand All @@ -92,7 +92,7 @@ HEADER_LINES = 1
[ROUTING]
#-- ====================================== --#
#-- Path to routing inputs netcdf (char) --#
FILE_NAME: https://docker-dev03.pcic.uvic.ca/twitcher/ows/proxy/thredds/dodsC/datasets/RVIC/sample_flow_parameters.nc
FILE_NAME: https://docker-dev03.pcic.uvic.ca/twitcher/ows/proxy/thredds/fileServer/datasets/RVIC/sample_flow_parameters.nc

#-- netCDF Variable Names --#
LONGITUDE_VAR: lon
Expand Down Expand Up @@ -124,7 +124,7 @@ CELL_FLOWDAYS: 4
[DOMAIN]
#-- ====================================== --#
#-- Path to cesm compliant domain file (char) --#
FILE_NAME: https://docker-dev03.pcic.uvic.ca/twitcher/ows/proxy/thredds/dodsC/datasets/RVIC/sample_routing_domain.nc
FILE_NAME: https://docker-dev03.pcic.uvic.ca/twitcher/ows/proxy/thredds/fileServer/datasets/RVIC/sample_routing_domain.nc

#-- netCDF Variable Names --#
LONGITUDE_VAR: lon
Expand Down
Loading