Skip to content

Commit 4095375

Browse files
authored
release(1.2.7) update MODFLOW 6 version to 6.4.1 (modflowpy#128)
Update download._request_get() and dowload._request_header() to improve ability to retry url requests. Improved flakyness of autotest/test_requests.py. Update to usgsprograms.export_json() to handle directory paths appended to fpth by separating it into a appdir and file_name. Also writing sorted code.json and code.md.
1 parent 8ef06bb commit 4095375

File tree

8 files changed

+101
-83
lines changed

8 files changed

+101
-83
lines changed

.github/workflows/pymake-requests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
3333
- name: Run pytest
3434
run: |
35-
pytest -v -m requests --durations=0 --cov=pymake --cov-report=xml autotest/
35+
pytest -v -n=auto -m requests --durations=0 --cov=pymake --cov-report=xml autotest/
3636
3737
- name: Run scheduled tests
3838
if: ${{ github.event_name == 'schedule' }}

.gitignore

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,14 @@ target/
6262

6363
# files in the autotest directory
6464
autotest/temp*/
65+
autotest/*.json
66+
autotest/code.md
6567
mod_temp/
6668
obj_temp/
6769
src_temp/
6870
*.exe
6971
Dependencies
7072

71-
# files in the examples directory
72-
examples/win32/
73-
examples/win64/
74-
examples/mac/
75-
examples/linux/
76-
examples/temp/
77-
73+
# files in the doc directory
7874
docs/source/
7975

autotest/test_requests.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ def initialize_working_dir():
4242
os.makedirs(dstpth, exist_ok=True)
4343

4444

45-
def export_code_json():
45+
def export_code_json(file_name="code.json"):
4646
# make sure the test directory exists
4747
initialize_working_dir()
4848

4949
# make the json file
50-
fpth = os.path.join(dstpth, "code.test.json")
50+
fpth = os.path.join(dstpth, file_name)
5151
pymake.usgs_program_data.export_json(
5252
fpth=fpth,
5353
current=True,
@@ -302,7 +302,7 @@ def test_target_keys():
302302
@pytest.mark.requests
303303
def test_usgsprograms_export_json():
304304
# export code.json and return json file path
305-
fpth = export_code_json()
305+
fpth = export_code_json(file_name="code.export.json")
306306

307307
# test the json export
308308
with open(fpth, "r") as f:
@@ -353,7 +353,7 @@ def test_usgsprograms_load_json():
353353
print("test_usgsprograms_load_json()")
354354

355355
# export code.json and return json file path
356-
fpth = export_code_json()
356+
fpth = export_code_json(file_name="code.load.json")
357357

358358
json_dict = pymake.usgs_program_data.load_json(fpth)
359359

@@ -383,7 +383,7 @@ def test_usgsprograms_list_json():
383383
print("test_usgsprograms_list_json()")
384384

385385
# export code.json and return json file path
386-
fpth = export_code_json()
386+
fpth = export_code_json(file_name="code.list.json")
387387

388388
# list the contents of the json file
389389
pymake.usgs_program_data.list_json(fpth=fpth)

pymake/cmds/createjson.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def main() -> None:
9191
"tag": ("--write_markdown",),
9292
"help": "If True, write markdown file that includes the "
9393
+ "target name, version, and the last-modified date of "
94-
+ "the download asset (url). Default is False.",
94+
+ "the download asset (url). Default is True.",
9595
"default": True,
9696
"choices": None,
9797
"action": "store_true",

pymake/utils/download.py

Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
import shutil
1616
import sys
1717
import tarfile
18-
import time
1918
import timeit
19+
from http.client import responses
2020
from zipfile import ZIP_DEFLATED, ZipFile, ZipInfo
2121

2222
import requests
@@ -202,32 +202,38 @@ def _request_get(url, verify=True, timeout=1, max_requests=10, verbose=False):
202202
request object for url
203203
204204
"""
205+
if verbose:
206+
print(f"request url '{url}'")
207+
205208
for idx in range(max_requests):
206209
if verbose:
207-
msg = f"open request attempt {idx + 1} of {max_requests}"
208-
print(msg)
210+
print(f" request attempt {idx + 1} of {max_requests}")
209211
req = None
210212
try:
211213
req = requests.get(
212-
url, stream=True, verify=verify, timeout=timeout
214+
url,
215+
stream=True,
216+
verify=verify,
217+
timeout=timeout,
213218
)
219+
if verbose:
220+
print(f" status: {responses[req.status_code]}")
214221
except:
215-
if idx < max_requests - 1:
216-
time.sleep(13)
217-
continue
218-
else:
219-
msg = "Cannot open request from:\n" + f" {url}\n\n"
220-
print(msg)
221-
if req is not None:
222-
req.raise_for_status()
222+
continue
223223

224-
# successful request
225-
break
224+
if req.status_code == 200:
225+
break
226+
227+
# final test for success
228+
if req is None:
229+
raise ConnectionError(f"Could not get data from: {url}")
230+
else:
231+
req.raise_for_status()
226232

227233
return req
228234

229235

230-
def _request_header(url, max_requests=10, verbose=False):
236+
def _request_header(url, max_requests=10, timeout=1, verbose=False):
231237
"""Get the headers from a url
232238
233239
Parameters
@@ -236,6 +242,8 @@ def _request_header(url, max_requests=10, verbose=False):
236242
url address for the zip file
237243
max_requests : int
238244
number of url download request attempts (default is 10)
245+
timeout : int
246+
url request time out length (default is 1 seconds)
239247
verbose : bool
240248
boolean indicating if output will be printed to the terminal
241249
(default is False)
@@ -246,23 +254,32 @@ def _request_header(url, max_requests=10, verbose=False):
246254
request header object for url
247255
248256
"""
257+
if verbose:
258+
print(f"request url: '{url}'")
259+
249260
for idx in range(max_requests):
250261
if verbose:
251-
msg = f"open request attempt {idx + 1} of {max_requests}"
252-
print(msg)
262+
print(f" request attempt {idx + 1} of {max_requests}")
263+
header = None
264+
try:
265+
header = requests.head(
266+
url,
267+
allow_redirects=True,
268+
timeout=timeout,
269+
)
270+
if verbose:
271+
print(f" status: {responses[header.status_code]}")
272+
except:
273+
continue
253274

254-
header = requests.head(url, allow_redirects=True)
255-
if header.status_code != 200:
256-
if idx < max_requests - 1:
257-
time.sleep(13)
258-
continue
259-
else:
260-
msg = "Cannot open request from:\n" + f" {url}\n\n"
261-
print(msg)
262-
header.raise_for_status()
275+
if header.status_code == 200:
276+
break
263277

264-
# successful header request
265-
break
278+
# final test for success
279+
if header is None:
280+
raise ConnectionError(f"Could not get header from: {url}")
281+
else:
282+
header.raise_for_status()
266283

267284
return header
268285

pymake/utils/usgsprograms.py

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import datetime
2222
import json
2323
import os
24+
import pathlib as pl
2425
import sys
2526

2627
from .download import _request_header
@@ -341,12 +342,25 @@ def export_json(
341342
print(
342343
f'writing a json file ("{fpth}") '
343344
+ f"of {sel} USGS programs\n"
344-
+ f'in the "{program_data_file}" database.'
345+
+ f'in the "{program_data_file}" database.\n'
345346
)
346347
if prog_data is not None:
347348
for idx, key in enumerate(prog_data.keys()):
348349
print(f" {idx + 1:>2d}: {key}")
349-
print("\n")
350+
351+
# process the passed file path into appdir and file_name
352+
appdir = pl.Path(".")
353+
file_name = pl.Path(fpth)
354+
if file_name.parent != str(appdir):
355+
appdir = file_name.parent
356+
file_name = file_name.name
357+
else:
358+
for idx, argv in enumerate(sys.argv):
359+
if argv in ("--appdir", "-ad"):
360+
appdir = pl.Path(sys.argv[idx + 1])
361+
362+
if str(appdir) != ".":
363+
appdir.mkdir(parents=True, exist_ok=True)
350364

351365
# get usgs program data
352366
udata = usgs_program_data.get_program_dict()
@@ -392,48 +406,38 @@ def export_json(
392406

393407
# export file
394408
try:
395-
with open(fpth, "w") as f:
396-
json.dump(prog_data, f, indent=4)
409+
with open(file_name, "w") as file_obj:
410+
json.dump(prog_data, file_obj, indent=4, sort_keys=True)
397411
except:
398-
msg = f'could not export json file "{fpth}"'
412+
msg = f'could not export json file "{file_name}"'
399413
raise IOError(msg)
400414

401-
# export code.json to --appdir directory, if the
402-
# command line argument was specified. Only done if not CI
403-
# command line argument was specified. Only done if not CI
404-
appdir = "."
405-
for idx, argv in enumerate(sys.argv):
406-
if argv in ("--appdir", "-ad"):
407-
appdir = sys.argv[idx + 1]
408-
409-
# make appdir if it does not already exist
410-
if not os.path.isdir(appdir):
411-
os.makedirs(appdir)
412-
413415
# write code.json
414-
if appdir != ".":
415-
dst = os.path.join(appdir, fpth)
416-
with open(dst, "w") as f:
417-
json.dump(prog_data, f, indent=4)
416+
if str(appdir) != ".":
417+
dst = appdir / file_name
418+
with open(dst, "w") as file_obj:
419+
json.dump(prog_data, file_obj, indent=4, sort_keys=True)
418420

419421
# write code.md
420422
if prog_data is not None and write_markdown:
421-
file_obj = open("code.md", "w")
422-
line = "| Program | Version | UTC Date |"
423-
file_obj.write(line + "\n")
424-
line = "| ------- | ------- | ---- |"
425-
file_obj.write(line + "\n")
426-
for target, target_dict in prog_data.items():
427-
keys = list(target_dict.keys())
428-
line = f"| {target} | {target_dict['version']} |"
429-
date_key = "url_download_asset_date"
430-
if date_key in keys:
431-
line += f" {target_dict[date_key]} |"
432-
else:
433-
line += " |"
434-
line += "\n"
435-
file_obj.write(line)
436-
file_obj.close()
423+
sorted_prog_data = {
424+
key: prog_data[key] for key in sorted(list(prog_data.keys()))
425+
}
426+
with open("code.md", "w") as file_obj:
427+
line = "| Program | Version | UTC Date |"
428+
file_obj.write(line + "\n")
429+
line = "| ------- | ------- | ---- |"
430+
file_obj.write(line + "\n")
431+
for target, target_dict in sorted_prog_data.items():
432+
keys = list(target_dict.keys())
433+
line = f"| {target} | {target_dict['version']} |"
434+
date_key = "url_download_asset_date"
435+
if date_key in keys:
436+
line += f" {target_dict[date_key]} |"
437+
else:
438+
line += " |"
439+
line += "\n"
440+
file_obj.write(line)
437441

438442
return
439443

pymake/utils/usgsprograms.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
target , version, current, url , dirname , srcdir , standard_switch, double_switch, shared_object
2-
mf6 , 6.4.0 , True , https://github.com/MODFLOW-USGS/modflow6/releases/download/6.4.0/mf6.4.0_linux.zip , mf6.4.0 , src , True , False , False
3-
zbud6 , 6.4.0 , True , https://github.com/MODFLOW-USGS/modflow6/releases/download/6.4.0/mf6.4.0_linux.zip , mf6.4.0 , utils/zonebudget/src, True , False , False
4-
libmf6 , 6.4.0 , True , https://github.com/MODFLOW-USGS/modflow6/releases/download/6.4.0/mf6.4.0_linux.zip , mf6.4.0 , srcbmi , True , False , True
2+
mf6 , 6.4.1 , True , https://github.com/MODFLOW-USGS/modflow6/releases/download/6.4.1/mf6.4.1_linux.zip , mf6.4.1_linux , src , True , False , False
3+
zbud6 , 6.4.1 , True , https://github.com/MODFLOW-USGS/modflow6/releases/download/6.4.1/mf6.4.1_linux.zip , mf6.4.1_linux , utils/zonebudget/src, True , False , False
4+
libmf6 , 6.4.1 , True , https://github.com/MODFLOW-USGS/modflow6/releases/download/6.4.1/mf6.4.1_linux.zip , mf6.4.1_linux , srcbmi , True , False , True
55
mp7 , 7.2.001, True , https://water.usgs.gov/water-resources/software/MODPATH/modpath_7_2_001.zip , modpath_7_2_001 , source , True , False , False
66
mt3dms , 5.3.0 , True , https://hydro.geo.ua.edu/mt3d/mt3dms_530.exe , mt3dms5.3.0 , src/true-binary , True , False , False
77
mt3dusgs , 1.1.0 , True , https://water.usgs.gov/water-resources/software/MT3D-USGS/mt3dusgs1.1.0.zip , mt3dusgs1.1.0 , src , True , False , False

pytest.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[pytest]
22
markers =
33
base: base tests
4-
regression: base and regression tests
4+
regression: regression tests
55
requests: usgsprograms requests tests
6+
schedule: tests to run if a scheduled job

0 commit comments

Comments
 (0)