From e3bd5fcc0c77b6262126a1733789c79b194deccb Mon Sep 17 00:00:00 2001 From: Trevor James Smith <10819524+Zeitsperre@users.noreply.github.com> Date: Wed, 16 Oct 2024 14:10:58 -0400 Subject: [PATCH 1/7] re-introduce cruft --- .cruft.json | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .cruft.json diff --git a/.cruft.json b/.cruft.json new file mode 100644 index 00000000..010cd53c --- /dev/null +++ b/.cruft.json @@ -0,0 +1,24 @@ +{ + "template": "https://github.com/bird-house/cookiecutter-birdhouse", + "commit": "b6969697401008114c8e25846ae5801e7e65224d", + "skip": [], + "context": { + "cookiecutter": { + "full_name": "David Huard", + "email": "huard.david@ouranos.ca", + "github_username": "Ouranosinc", + "project_name": "Raven", + "project_slug": "raven", + "project_repo_name": "raven", + "project_readthedocs_name": "pavics-raven", + "project_short_description": "Raven offers processes related to hydrological modeling, and in particular, the Raven hydrological modeling framework.", + "version": "0.17.1", + "open_source_license": "MIT license", + "http_port": "9099", + "_copy_without_render": [ + "{{cookiecutter.project_slug}}/templates/*.cfg" + ], + "_template": "https://github.com/bird-house/cookiecutter-birdhouse" + } + } +} From a30cd457476119df4905a3e267e97ed31ffaddcb Mon Sep 17 00:00:00 2001 From: Trevor James Smith <10819524+Zeitsperre@users.noreply.github.com> Date: Wed, 16 Oct 2024 16:49:47 -0400 Subject: [PATCH 2/7] fast-forward cookiecutter, update documentation --- .cruft.json | 9 +- .gitignore | 142 +++++++++--- .readthedocs.yml | 2 +- CHANGES.rst => CHANGELOG.rst | 107 ++++----- CODE_OF_CONDUCT.md | 128 +++++++++++ Dockerfile | 4 +- LICENSE.txt => LICENSE | 2 +- Makefile | 215 ++++++++---------- README.rst | 18 +- docs/source/.gitignore | 3 - docs/source/authors.rst | 1 + docs/source/index.rst | 1 + docs/source/installation.rst | 141 +++++------- environment-dev.yml | 5 +- environment-docs.yml | 8 +- environment.yml | 10 +- pyproject.toml | 22 +- raven/__init__.py | 3 - src/raven/__init__.py | 28 +++ {raven => src/raven}/__version__.py | 4 +- {raven => src/raven}/cli.py | 61 +++-- {raven => src/raven}/config.py | 0 .../hybas_lake_ar_lev01_v1c.zip | Bin .../hybas_lake_na_lev01_v1c.zip | Bin {raven => src/raven}/default.cfg | 0 {raven => src/raven}/processes/__init__.py | 2 + {raven => src/raven}/processes/base_xclim.py | 0 .../processes/wps_generic_raster_subset.py | 0 .../processes/wps_generic_shape_properties.py | 0 .../processes/wps_generic_terrain_analysis.py | 0 .../processes/wps_generic_zonal_stats.py | 0 .../wps_hydrobasins_shape_selection.py | 0 .../processes/wps_nalcms_zonal_stats.py | 0 .../wps_nalcms_zonal_stats_raster.py | 0 {raven => src/raven}/processes/wpsio.py | 0 src/raven/raven.py | 1 + {raven => src/raven}/templates/pywps.cfg | 6 +- {raven => src/raven}/utilities/__init__.py | 0 {raven => src/raven}/utilities/analysis.py | 0 {raven => src/raven}/utilities/checks.py | 0 {raven => src/raven}/utilities/geo.py | 0 {raven => src/raven}/utilities/geoserver.py | 0 {raven => src/raven}/utilities/io.py | 0 {raven => src/raven}/utilities/testdata.py | 0 {raven => src/raven}/utils.py | 0 {raven => src/raven}/wsgi.py | 6 +- tox.ini | 31 +++ 47 files changed, 595 insertions(+), 365 deletions(-) rename CHANGES.rst => CHANGELOG.rst (88%) create mode 100644 CODE_OF_CONDUCT.md rename LICENSE.txt => LICENSE (92%) delete mode 100644 docs/source/.gitignore create mode 100644 docs/source/authors.rst delete mode 100644 raven/__init__.py create mode 100644 src/raven/__init__.py rename {raven => src/raven}/__version__.py (81%) rename {raven => src/raven}/cli.py (79%) rename {raven => src/raven}/config.py (100%) rename {raven => src/raven}/data/hydrobasins_domains/hybas_lake_ar_lev01_v1c.zip (100%) rename {raven => src/raven}/data/hydrobasins_domains/hybas_lake_na_lev01_v1c.zip (100%) rename {raven => src/raven}/default.cfg (100%) rename {raven => src/raven}/processes/__init__.py (94%) rename {raven => src/raven}/processes/base_xclim.py (100%) rename {raven => src/raven}/processes/wps_generic_raster_subset.py (100%) rename {raven => src/raven}/processes/wps_generic_shape_properties.py (100%) rename {raven => src/raven}/processes/wps_generic_terrain_analysis.py (100%) rename {raven => src/raven}/processes/wps_generic_zonal_stats.py (100%) rename {raven => src/raven}/processes/wps_hydrobasins_shape_selection.py (100%) rename {raven => src/raven}/processes/wps_nalcms_zonal_stats.py (100%) rename {raven => src/raven}/processes/wps_nalcms_zonal_stats_raster.py (100%) rename {raven => src/raven}/processes/wpsio.py (100%) create mode 100644 src/raven/raven.py rename {raven => src/raven}/templates/pywps.cfg (81%) rename {raven => src/raven}/utilities/__init__.py (100%) rename {raven => src/raven}/utilities/analysis.py (100%) rename {raven => src/raven}/utilities/checks.py (100%) rename {raven => src/raven}/utilities/geo.py (100%) rename {raven => src/raven}/utilities/geoserver.py (100%) rename {raven => src/raven}/utilities/io.py (100%) rename {raven => src/raven}/utilities/testdata.py (100%) rename {raven => src/raven}/utils.py (100%) rename {raven => src/raven}/wsgi.py (66%) create mode 100644 tox.ini diff --git a/.cruft.json b/.cruft.json index 010cd53c..b1919561 100644 --- a/.cruft.json +++ b/.cruft.json @@ -1,6 +1,6 @@ { "template": "https://github.com/bird-house/cookiecutter-birdhouse", - "commit": "b6969697401008114c8e25846ae5801e7e65224d", + "commit": "2964f01a05703d88c087bb491811d16c703307b6", "skip": [], "context": { "cookiecutter": { @@ -15,10 +15,15 @@ "version": "0.17.1", "open_source_license": "MIT license", "http_port": "9099", + "use_pytest": "y", + "use_black": "n", + "create_author_file": "y", "_copy_without_render": [ "{{cookiecutter.project_slug}}/templates/*.cfg" ], + "__gh_slug": "Ouranosinc/raven", "_template": "https://github.com/bird-house/cookiecutter-birdhouse" } - } + }, + "checkout": null } diff --git a/.gitignore b/.gitignore index 0f9f3df3..1f1e41e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,34 +1,68 @@ -# installer -#Makefile - -# Docker -#Dockerfile +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class # PyWPS custom.cfg .custom.cfg *.pid +# C extensions +*.so + # Python / Extensions etc. *~ -*.mo -*.so *.pyc *.pyo -*.egg -*.egg-info *.sqlite *.bak __pycache__ ++# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg + # Unit test / Coverage reports +*.cover +*.lock +*.log .cache -.pytest_cache .coverage -.tox +.coverage.* +.hypothesis/ +.pytest_cache/ +.tox/ +coverage.xml +coverage/ +htmlcov/ nosetests.xml +testdata.json unit_tests/testdata.json -coverage/ + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt # Raven specific Raven_errors.txt @@ -36,11 +70,6 @@ Raven_errors.txt # R *.Rhistory -# Eclipse / PyDev -.project -.pydevproject -.settings - # PyCharm *.idea @@ -53,6 +82,10 @@ Raven_errors.txt # Sublime Text Editor *.sublime* +# Translations +*.mo +*.pot + # buildout bin develop-eggs @@ -61,38 +94,54 @@ parts build dist downloads -.installed.cfg .mr.developer.cfg bootstrap-buildout.py bootstrap.py -#generated by buildout - -*.pid -# sphinx -#docs/Makefile -docs/make.bat +# Sphinx documentation +docs/Makefile +docs/_build/ +docs/_html/ +docs/build/ docs/doctrees/ docs/html/ -docs/build/ +docs/make.bat +docs/source/modules.rst docs/source/output-sanitize.cfg +docs/source/raven.*.rst +docs/source/raven.rst + +# PyBuilder +target/ # External Sources #src/external src/ # tests -*.log -*.lock -testdata.json tests/*/*/processor_0 tests/*/*/OstOutput* tests/*/*/*.nc # IPython -.ipynb_checkpoints docs/source/notebooks/*.nc +# Jupyter Notebook +.ipynb_checkpoints + +# Flask stuff: +instance/ +.webassets-cache + +# Dask worker cache +dask-worker-space/ + +# Scrapy stuff: +.scrapy + +# pyenv +.python-version + # gcc/fortran *.o *.a @@ -102,4 +151,37 @@ docs/source/notebooks/*.nc # Merge conflict *.orig -venv +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +# VSCode +.vscode/ + +# Eclipse / PyDev +.project +.pydevproject +.settings diff --git a/.readthedocs.yml b/.readthedocs.yml index 61869d53..4b5e76f2 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -15,7 +15,7 @@ sphinx: build: os: ubuntu-22.04 tools: - python: "mambaforge-4.10" + python: "mambaforge-22.9" formats: all diff --git a/CHANGES.rst b/CHANGELOG.rst similarity index 88% rename from CHANGES.rst rename to CHANGELOG.rst index d5c37845..9ba9fa22 100644 --- a/CHANGES.rst +++ b/CHANGELOG.rst @@ -1,30 +1,30 @@ Changes ======= -0.18.3 (unreleased) -------------------- +v0.18.3 (unreleased) +-------------------- * Added a GitHub Workflow to test the Dockerfile recipe configuration for RavenWPS. * Cleaned up the Dockerfile recipe configuration for RavenWPS, now using Gunicorn for service management. * Removed `pysheds` and watershed delineation process due to a licensing issue. -0.18.2 (2023-07-06) -------------------- +v0.18.2 (2023-07-06) +-------------------- * Removed pin on `owslib` below v0.29 and pin on `fiona` below v2.0. * Added a GitHub Workflow to test against macOS builds. * Adapted zonal statistics processes to support the latest `fiona` and `zonalstats` API changes. -0.18.1 (2023-05-23) -------------------- +v0.18.1 (2023-05-23) +-------------------- * Removed obsolete components related to HPC interfaces (#477) * Added Python3.11 to supported versions with a build for Python3.11 in CI (#477) * Adjusted ReadMe to reflect recent significant changes (#477) * Updated deprecated GitHub Actions (#477) -0.18.0 (2023-05-23) -------------------- +v0.18.0 (2023-05-23) +-------------------- Major Changes ^^^^^^^^^^^^^ @@ -34,16 +34,16 @@ Major Changes * Removed all tests related to Raven WPS modelling (#464) * Raise error message if shape area for NALCMS zonal stats raster is above 100,000 km2. (#473) -0.17.1 (2023-04-04) -------------------- +v0.17.1 (2023-04-04) +-------------------- Internal Changes ^^^^^^^^^^^^^^^^ * Dockerfile configuration now uses Python3.8 and `condaforge/mambaforge` base image (#466) * `pandas` is temporarily pinned below v2.0 (#466) -0.17.0 (2023-02-28) -------------------- +v0.17.0 (2023-02-28) +-------------------- Major Changes ^^^^^^^^^^^^^ @@ -58,8 +58,8 @@ Internal Changes * Pre-commit style updates (#446, #447, #449, #461) * Use `provision-with-micromamba` GitHub Action in CI workflows (#462) -0.16.0 (2022-11-01) -------------------- +v0.16.0 (2022-11-01) +-------------------- Major Changes ^^^^^^^^^^^^^ @@ -82,57 +82,57 @@ Internal Changes - check-jsonschema: Verify that GitHub and ReadTheDocs workflows are valid * Added a Zenodo/DOI configuration -0.15.1 (2022-01-14) -------------------- +v0.15.1 (2022-01-14) +-------------------- * Modified handling for GDAL to better support conda-build configuration * Update to RavenPy 0.7.8 * Upgrade to PyWPS 4.5.1 -0.15.0 (2021-12-22) -------------------- +v0.15.0 (2021-12-22) +-------------------- * Update to RavenPy 0.7.7 * Update required Python consistently to v3.7+ * Set development status to Beta. * Replace pip-installed packages with conda-forge equivalents. -0.14.2 (2021-09-03) -------------------- +v0.14.2 (2021-09-03) +-------------------- * Update to RavenPy 0.7.4 (pin climpred below version 2.1.6) * Fixed a process-breaking bug in `wps_hydrobasins_shape_selection` -0.14.1 (2021-08-31) -------------------- +v0.14.1 (2021-08-31) +-------------------- * Update to RavenPy 0.7.3 (pin xclim version 0.28.1) -0.14.0 (2021-08-30) -------------------- +v0.14.0 (2021-08-30) +-------------------- * Update to RavenPy 0.7.2 * Use new OWSlib WFS topological filters * More informative install documentation * Upgrade to PyWPS 4.4.5 -0.13.0 (2021-05-14) -------------------- +v0.13.0 (2021-05-14) +-------------------- * Update RavenPy to 0.5.1 * Remove the ``name`` (watershed name) from the WPS interface for Raven processes * Add ``random_numbers`` WPS param to pass optional ``OstRandomNumbers.txt`` file to Ostrich processes * Add error handlers for regionalisation and climatology processes -0.12.1 (2021-04-16) -------------------- +v0.12.1 (2021-04-16) +-------------------- * Fix bug where the name of configuration files was used, while the client transmission of data does not carry the file name. * Update notebooks * Move draft notebooks to sandbox -0.12.0 (2021-04-14) -------------------- +v0.12.0 (2021-04-14) +-------------------- * Update RavenPy to 0.4.2 * Migrate utilities to RavenPy @@ -148,9 +148,8 @@ Internal Changes * Fix broken notebooks * Improve error reporting by including stack trace in error messages. - -0.11.x (2021-02-01) -------------------- +v0.11.x (2021-02-01) +-------------------- * Add processes to run hydrological simulations on ECCC GEPS forecasts/hindcasts * Add process to create forecast graphic @@ -171,8 +170,8 @@ Internal Changes * Simplify documentation build environment. -0.10.x (2020-03-09) Oxford --------------------------- +v0.10.x (2020-03-09) Oxford +--------------------------- * ``suppress_ouput`` also triggers ``:DontWriteWatershedStorage`` * Added support for ERA5 (hourly), NRCan and CANOPEX datasets @@ -182,15 +181,13 @@ Internal Changes * Updated Raven version to 295 * Support passing shapes as zip files - -0.9.x (2019-11-11) ------------------- +v0.9.x (2019-11-11) +------------------- * Return configuration files used to run model in a zip archive - -0.8.x (2019-10-22) ------------------- +v0.8.x (2019-10-22) +-------------------- * Added more documentation for users * Fixed reprojection errors in GIS utilities * Specified HydroBASINS in lieu of HydroSHEDS in processes @@ -199,18 +196,16 @@ Internal Changes * Employed ipyleaflets for notebook-based web-maps * Run py.test on notebooks from local or remote server - -0.7.x (2019-06-25) ------------------- +v0.7.x (2019-06-25) +------------------- * Regionalization database * Graphics for frequency analysis * Many new notebook tutorials * Bug fixes - -0.6.x (2019-06-05) ------------------- +v0.6.x (2019-06-05) +------------------- * Regionalization process allowing the estimation of parameters of ungauged watersheds * Added time series analysis processes, including frequential analysis @@ -218,9 +213,8 @@ Internal Changes * GIS processes now use GeoServer capabilities * Docker configuration - -0.5.0 (2019-04-12) ------------------- +v0.5.0 (2019-04-12) +------------------- * Added watershed geospatial analysis processes - Hydroshed basin selection (with upstream contributors) @@ -231,23 +225,20 @@ Internal Changes * Added multi-model parallel simulations * Added multi-bassin parallel simulations - -0.4.0 (2019-03-12) ------------------- +v0.4.0 (2019-03-12) +------------------- * Added model calibration processes using Ostrich * Added support for launching a singularity image * Added library functions for model regionalization - -0.3.0 (2019-01-24) ------------------- +v0.3.0 (2019-01-24) +------------------- * Adds process for MOHYSE emulator * Adds process for HBV-EC emulator - -0.2.0 (2018-11-29) Washington +v0.2.0 (2018-11-29) Washington ----------------------------- * Provides generic RAVEN framework configuration diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..e0ee82bd --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or + advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email + address, without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[github-support@ouranos.ca](mailto:github-support@ouranos.ca). +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. + +[homepage]: https://www.contributor-covenant.org diff --git a/Dockerfile b/Dockerfile index 68d22e31..eaf676f6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,9 +10,7 @@ WORKDIR /code # Create conda environment COPY environment.yml . -RUN mamba env create -n raven -f environment.yml \ - && mamba install -n raven gunicorn \ - && mamba clean --all --yes +RUN mamba env create -n raven -f environment.yml && mamba install -n raven gunicorn && mamba clean --all --yes # Add the raven conda environment to the path ENV PATH /opt/conda/envs/raven/bin:$PATH diff --git a/LICENSE.txt b/LICENSE similarity index 92% rename from LICENSE.txt rename to LICENSE index 8daef36e..36b0c5a3 100644 --- a/LICENSE.txt +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018-2022, David Huard +Copyright (c) 2018-2024, David Huard, Richard Arsenault, Trevor James Smith, Tuan Long Vu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index 76af20d2..ee7ca429 100644 --- a/Makefile +++ b/Makefile @@ -58,102 +58,62 @@ endif # end of configuration -.DEFAULT_GOAL := help +define PRINT_HELP_PYSCRIPT +import re, sys + +for line in sys.stdin: + match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line) + if match: + target, help = match.groups() + print("%-20s %s" % (target, help)) + else: + match = re.match(r'^## (.*)$$', line) + if match: + help = match.groups()[0] + print("\n%s" % (help)) +endef +export PRINT_HELP_PYSCRIPT + +BROWSER := python -c "$$BROWSER_PYSCRIPT" -.PHONY: all -all: help +.DEFAULT_GOAL := help -.PHONY: help -help: +help: ## print this help message. (Default) @echo "Please use 'make ' where is one of:" - @echo " help to print this help message. (Default)" - @echo " install to install app by running 'pip install -e .'" - @echo " develop to install with additional development requirements." - @echo " start to start $(APP_NAME) service as daemon (background process)." - @echo " stop to stop $(APP_NAME) service." - @echo " restart to restart $(APP_NAME) service." - @echo " status to show status of $(APP_NAME) service." - @echo " clean to remove all files generated by build and tests." - @echo "\nTesting targets:" - @echo " test to run tests (but skip long running tests)." - @echo " test-all to run all tests (including long running tests)." - @echo " test-notebooks to verify Jupyter Notebook test outputs are valid." - @echo " lint to run code style checks with flake8." - @echo " refresh-notebooks to verify Jupyter Notebook test outputs are valid." - @echo " pep8 to run pep8 code style checks." - @echo "\nSphinx targets:" - @echo " docs to generate HTML documentation with Sphinx." - @echo "\nDeployment targets:" - @echo " dist to build source and wheel package." - -## Anaconda targets - -.PHONY: anaconda -anaconda: - @echo "Installing Anaconda ..." - test -e $(ANACONDA_HOME)/bin/conda || curl $(ANACONDA_URL)/$(FN) --silent --insecure --output "$(DOWNLOAD_CACHE)/$(FN)" - test -e $(ANACONDA_HOME)/bin/conda || bash "$(DOWNLOAD_CACHE)/$(FN)" -b -p $(ANACONDA_HOME) - -.PHONY: conda_env -conda_env: - @echo "Updating conda environment $(CONDA_ENV) ..." - "$(ANACONDA_HOME)/bin/conda" create --yes -n $(CONDA_ENV) python=$(PYTHON_VERSION) - "$(ANACONDA_HOME)/bin/conda" env update -n $(CONDA_ENV) -f environment.yml - -.PHONY: env_clean -env_clean: - @echo "Removing conda env $(CONDA_ENV)" - @-"$(CONDA)" env remove -n $(CONDA_ENV) --yes - -## Build targets - -.PHONY: bootstrap -bootstrap: anaconda conda_env bootstrap_dev - @echo "Bootstrap ..." - -.PHONY: bootstrap_dev -bootstrap_dev: - @echo "Installing development requirements for tests and docs ..." - @bash -c "source $(ANACONDA_HOME)/bin/activate $(CONDA_ENV) && pip install -r requirements_dev.txt" + @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) -.PHONY: install -install: +## Build targets: + +install: ## install raven application ifdef GDAL_VERSION @echo "Installing application with GIS..." @-bash -c "pip install --no-cache-dir gdal==$(GDAL_VERSION)" endif @-bash -c "pip install -e ." - @echo "Start service with \`make start\`" + @echo "\nStart service with \`make start\` and stop with \`make stop\`." -.PHONY: develop -develop: +develop: ## install raven application with development libraries @echo "Installing development requirements for tests and docs ..." @-bash -c 'pip install -e ".[dev]"' -.PHONY: start -start: +start: ## start raven service as daemon (background process) @echo "Starting application ..." @-bash -c "$(APP_NAME) start -d" -.PHONY: stop -stop: +stop: ## stop raven service @echo "Stopping application ..." @-bash -c "$(APP_NAME) stop" -.PHONY: restart -restart: stop start +restart: stop start ## restart raven service @echo "Restarting application ..." -.PHONY: status -status: +status: ## show status of raven service @echo "Showing status ..." @-bash -c "$(APP_NAME) status" -.PHONY: clean clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts -.PHONY: clean-build -clean-build: +clean-build: ## remove build artifacts @echo "Removing build artifacts ..." @-rm -fr build/ @-rm -fr dist/ @@ -163,51 +123,62 @@ clean-build: @-find . -name '*.log' -exec rm -fr {} + @-find . -name '*.sqlite' -exec rm -fr {} + -.PHONY: clean-pyc -clean-pyc: +clean-pyc: ## remove Python file artifacts @echo "Removing Python file artifacts ..." @-find . -name '*.pyc' -exec rm -f {} + @-find . -name '*.pyo' -exec rm -f {} + @-find . -name '*~' -exec rm -f {} + @-find . -name '__pycache__' -exec rm -fr {} + -.PHONY: clean-test -clean-test: +clean-test: ## remove test and coverage artifacts @echo "Removing test artifacts ..." @-rm -fr .pytest_cache -.PHONY: clean-dist -clean-dist: clean +clean-dist: clean ## remove git ignored files and directories @echo "Running 'git clean' ..." @git diff --quiet HEAD || echo "There are uncommitted changes! Aborting 'git clean' ..." ## do not use git clean -e/--exclude here, add them to .gitignore instead @-git clean -dfx -## Test targets +clean-docs: ## remove documentation artifacts + @echo "Removing documentation artifacts ..." + @-rm -f docs/raven.rst + @-rm -f docs/modules.rst + $(MAKE) -C docs clean + +lint: ## check code style + @echo "Running black, ruff, isort, and yamllint code style checks ..." + black --check raven tests + isort --check raven tests + flake8 raven tests + yamllint --config-file=.yamllint.yaml raven + +## Testing targets: -.PHONY: test -test: +test: ## run tests quickly with the default Python @echo "Running tests (skip slow and online tests) ..." @bash -c "pytest -v -m 'not slow and not online and not very_slow' tests/" -.phony: test-advanced -test-advanced: +test-advanced: ## run tests with slow and online tests @echo "Running advanced tests (skip very_slow tests) ..." @bash -c "pytest -v -m 'not very_slow' tests/" -.PHONY: test-all -test-all: +test-all: ## run all tests @echo "Running all tests (including slow and online tests) ..." @bash -c "pytest -v tests/" -.PHONY: notebook-sanitizer -notebook-sanitizer: +test_pdb: ## run tests quickly with the default Python and drop into pdb + @echo "Running tests (skip slow and online tests) with --pdb ..." + @bash -c "pytest -v -m 'not slow and not online' --pdb" + +test-tox: ## run tests on every available Python version with tox + @bash -c 'tox' + +notebook-sanitizer: ## sanitize notebooks with configuration file @echo "Copying notebook output sanitizer ..." @-bash -c "curl -L $(SANITIZE_FILE) -o $(CURDIR)/docs/source/output-sanitize.cfg --silent" -# Test all notebooks. -.PHONY: test-notebooks -test-notebooks: notebook-sanitizer +test-notebooks: notebook-sanitizer ## run notebook-based tests @echo "Running notebook-based tests" @$(MAKE) -f $(THIS_FILE) test-notebooks-impl @@ -218,33 +189,27 @@ test-notebooks: notebook-sanitizer @$(MAKE) -f $(THIS_FILE) test-notebooks-impl NB_FILE="$<" NB_FILE := $(CURDIR)/docs/source/notebooks/ -.PHONY: test-notebooks-impl test-notebooks-impl: - bash -c "env WPS_URL=$(WPS_URL) FINCH_WPS_URL=$(FINCH_WPS_URL) pytest --numprocesses=0 --nbval-lax --verbose $(NB_FILE) --sanitize-with $(CURDIR)/docs/source/output-sanitize.cfg --ignore $(CURDIR)/docs/source/notebooks/.ipynb_checkpoints" + @bash -c "env WPS_URL=$(WPS_URL) FINCH_WPS_URL=$(FINCH_WPS_URL) pytest --numprocesses=0 --nbval-lax --verbose $(NB_FILE) --sanitize-with $(CURDIR)/docs/source/output-sanitize.cfg --ignore $(CURDIR)/docs/source/notebooks/.ipynb_checkpoints" ifeq "$(JUPYTER_NB_IP)" "" JUPYTER_NB_IP := 0.0.0.0 endif -.PHONY: notebook -notebook: +notebook: ## run Jupyter notebook server @echo "Running notebook server" - @bash -c "env WPS_URL=$(WPS_URL) FINCH_WPS_URL=$(FINCH_WPS_URL) jupyter notebook --ip=$(JUPYTER_NB_IP) $(CURDIR)/docs/source/notebooks/" + @bash -c "env WPS_URL=$(WPS_URL) FINCH_WPS_URL=$(FINCH_WPS_URL) jupyter notebook --ip=$(JUPYTER_NB_IP) $(NB_FILE)" -.PHONY: lint -lint: - @echo "Running flake8 code style checks ..." - black --check raven tests - isort --check raven tests - flake8 raven tests - yamllint --config-file=.yamllint.yaml raven +coverage: ## check code coverage quickly with the default Python + @bash -c 'coverage run --source raven -m pytest' + @bash -c 'coverage report -m' + @bash -c 'coverage html' + $(BROWSER) htmlcov/index.html -# Only works for notebooks that passed ``make test-notebooks`` above. For -# those that failed, manually starting a local Jupyter server and refresh them -# manually. -.PHONY: refresh-notebooks -refresh-notebooks: +# Only works for notebooks that passed ``make test-notebooks`` above. +# For those that failed, manually starting a local Jupyter server and refresh them manually. +refresh-notebooks: ## refreshing all notebook outputs under docs/source/notebooks @echo "Refresh all notebook outputs under docs/source/notebooks" - bash -c 'for nb in $(CURDIR)/docs/source/notebooks/*.ipynb; do $(MAKE) -f $(THIS_FILE) refresh-notebooks-impl NB_REFRESH_FILE="$$nb"; done; cd $(APP_ROOT)' + @bash -c 'for nb in $(NB_FILE)/*.ipynb; do $(MAKE) -f $(THIS_FILE) refresh-notebooks-impl NB_REFRESH_FILE="$$nb"; done; cd $(APP_ROOT)' # refresh one single notebook (add .refresh at the end of notebook path). %.ipynb.refresh: %.ipynb @@ -252,30 +217,28 @@ refresh-notebooks: @$(MAKE) -f $(THIS_FILE) refresh-notebooks-impl NB_REFRESH_FILE="$<" NB_REFRESH_FILE := "" -.PHONY: refresh-notebooks-impl -refresh-notebooks-impl: - bash -c 'WPS_URL="$(WPS_URL)" FINCH_WPS_URL="$(FINCH_WPS_URL)" jupyter nbconvert --to notebook --execute --ExecutePreprocessor.timeout=240 --output "$(NB_REFRESH_FILE)" --output-dir . "$(NB_REFRESH_FILE)"; sed -i "s@$(WPS_OUTPUT_URL)/@$(OUTPUT_URL)/@g" "$(NB_REFRESH_FILE)"' +refresh-notebooks-impl: ## refresh one single notebook + @bash -c 'WPS_URL="$(WPS_URL)" FINCH_WPS_URL="$(FINCH_WPS_URL)" jupyter nbconvert --to notebook --execute --ExecutePreprocessor.timeout=240 --output "$(NB_REFRESH_FILE)" --output-dir . "$(NB_REFRESH_FILE)"; sed -i "s@$(WPS_OUTPUT_URL)/@$(OUTPUT_URL)/@g" "$(NB_REFRESH_FILE)"' -.PHONY: test_pdb -test_pdb: - @echo "Running tests (skip slow and online tests) with --pdb ..." - @bash -c "pytest -v -m 'not slow and not online' --pdb" - -## Sphinx targets +## Sphinx targets: -.PHONY: docs -docs: +docs: clean-docs ## generate Sphinx HTML documentation, including API docs @echo "Generating docs with Sphinx ..." - @bash -c '$(MAKE) -C $@ clean html' + @bash -c '$(MAKE) -C docs html' @echo "Open your browser to: file:/$(APP_ROOT)/docs/build/html/index.html" - ## do not execute xdg-open automatically since it hangs travis and job does not complete + ## do not execute xdg-open automatically since it hangs ReadTheDocs and job does not complete @echo "xdg-open $(APP_ROOT)/docs/build/html/index.html" -## Deployment targets +servedocs: docs ## compile the docs watching for changes + @echo "Compiling the docs and watching for changes ..." + @watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D . + +## Deployment targets: + +dist: clean ## build source and wheel package + @python -m build --sdist + @bash -c 'ls -l dist/' -.PHONY: dist -dist: clean - @echo "Building source and wheel package ..." - @-python setup.py sdist - @-python setup.py bdist_wheel - @-bash -c 'ls -l dist/' +release: dist ## upload source and wheel packages + @echo "Uploading source and wheel packages ..." + @python -m flit publish dist/* diff --git a/README.rst b/README.rst index 684731a5..2350b332 100644 --- a/README.rst +++ b/README.rst @@ -1,6 +1,11 @@ +=========================================== Raven : Hydrological modeling and analytics =========================================== +.. image:: https://img.shields.io/pypi/v/birdhouse-raven.svg + :target: https://pypi.python.org/pypi/birdhouse-raven + :alt: PyPI + .. image:: https://readthedocs.org/projects/pavics-raven/badge/?version=latest :target: https://pavics-raven.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status @@ -37,23 +42,22 @@ Raven can be compiled and installed, or simply deployed using docker. A hosted v Documentation ------------- -Learn more about Raven in its official documentation at -https://pavics-raven.readthedocs.io. +Learn more about Raven in its official documentation at https://pavics-raven.readthedocs.io. -Submit bug reports, questions and feature requests at -https://github.com/Ouranosinc/raven/issues +Submit bug reports, questions and feature requests at https://github.com/Ouranosinc/raven/issues Contributing ------------ You can find information about contributing in our `Developer Guide`_. -Please use bumpversion_ to release a new version. +Please use bump2version_ to release a new version. License ------- -Free software: MIT license +* Free software: MIT license +* Documentation: https://raven.readthedocs.io. Credits ------- @@ -72,4 +76,4 @@ This package was created with Cookiecutter_ and the `bird-house/cookiecutter-bir .. _Cookiecutter: https://github.com/audreyr/cookiecutter .. _`bird-house/cookiecutter-birdhouse`: https://github.com/bird-house/cookiecutter-birdhouse .. _`Developer Guide`: https://pavics-raven.readthedocs.io/en/latest/dev_guide.html -.. _bumpversion: https://pavics-raven.readthedocs.io/en/latest/dev_guide.html#bump-a-new-version +.. _bump2version: https://pavics-raven.readthedocs.io/en/latest/dev_guide.html#bump-a-new-version diff --git a/docs/source/.gitignore b/docs/source/.gitignore deleted file mode 100644 index f1e62f40..00000000 --- a/docs/source/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/raven.rst -/raven.*.rst -/modules.rst diff --git a/docs/source/authors.rst b/docs/source/authors.rst new file mode 100644 index 00000000..7739272f --- /dev/null +++ b/docs/source/authors.rst @@ -0,0 +1 @@ +.. include:: ../../AUTHORS.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index 5afa62aa..591d8b56 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -20,6 +20,7 @@ User documentation notebooks/index dev_guide processes + authors changes Credits diff --git a/docs/source/installation.rst b/docs/source/installation.rst index 11523aab..2e839d8a 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst @@ -1,5 +1,3 @@ -.. highlight:: console - .. _installation: Installation @@ -12,129 +10,119 @@ Installation Install from Conda-Forge (suggested) ------------------------------------ -Create an Anaconda environment named `ravenwps-env`:: +Create an Anaconda environment named `ravenwps-env`: + + .. code-block:: bash - $ conda env create -n ravenwps-env python=3.7 - $ source activate ravenwps-env + conda env create -n ravenwps-env python=3.9 + source activate ravenwps-env This should now prepend the environment to your shell commands (ie: `(ravenwps-env) $`). -Now install directly from `conda-forge`:: +Now install directly from `conda-forge`: + + .. code-block:: bash - (ravenwps-env) $ conda install -c conda-forge raven-wps + (ravenwps-env) $ conda install -c conda-forge raven-wps Install from GitHub ------------------- -Check out code from the Raven GitHub repo and start the installation:: +Check out code from the Raven GitHub repo and start the installation: - $ git clone https://github.com/Ouranosinc/raven.git - $ cd raven + .. code-block:: bash + + git clone https://github.com/Ouranosinc/raven.git + cd raven Environment Setup with Anaconda (macOS/Linux) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Create Conda environment named `raven`:: - - $ conda env create -n ravenwps-env -f environment.yml - # or alternatively, - $ make conda_env +Create Conda environment named `raven`: -The environment can then be activated with:: + .. code-block:: bash - $ source activate ravenwps-env + conda env create -n ravenwps-env -f environment.yml -This should now prepend the environment to your shell commands (ie: `(ravenwps-env) $`). +The environment can then be activated with: -Environment Setup using System Libraries and Sources (Linux) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + .. code-block:: bash -.. warning:: - This approach is not formally supported, but is presently working for the time being. - It is up to the user to install the `raven` model and `ostrich` model optimization binaries. - Those can be downloaded from source via the following links: + source activate ravenwps-env - - RAVEN: http://raven.uwaterloo.ca/Downloads.html - - OSTRICH: https://github.com/usbr/ostrich/ +This should now prepend the environment to your shell commands (ie: `(ravenwps-env) $`). +Installing and Launching RavenWPS +--------------------------------- -.. note:: - While the following shows how to install `raven` for an Deb-based Linux, if the OS-equivalent dependencies - are available to Python, `raven` should be able to run on any modern operating system (macOS/Windows/\*nix). +Now we can install the raven-wps service: -First we need to install several system libraries that RavenWPS and RavenPy depend upon and make a virtual environment:: + .. code-block:: bash - $ sudo apt-get install libhdf5-dev netcdf-bin libnetcdf-dev libgdal-dev libproj-dev libgeos-dev libspatialindex-dev python3-dev - $ pip3 install virtualenv - $ virtualenv ravenwps-env - $ . ravenwps-env/bin/activate + pip install -e . -We then need to install the `ravenpy` python library from sources:: +Or alternatively: - (ravenwps-env) $ git clone https://github.com/CSHS-CWRA/RavenPy/ - (ravenwps-env) $ pip install RavenPy/.[gis] - (ravenwps-env) $ pip install RavenPy/. --verbose --install-option="--with-binaries" + .. code-block:: bash -If we want to perform an interactive/editable installation for dev purposes, substitute the following for the final installation command:: + make install - (ravenwps-env) $ pip install -e RavenPy/. --verbose --install-option="--with-binaries" +For development you can use this command: -Installing and Launching RavenWPS ---------------------------------- + .. code-block:: bash -Now we can install the raven-wps service:: + pip install -e .[dev] - (ravenwps-env) $ pip install -e . - # or alternatively, - (ravenwps-env) $ make install +Or alternatively: -For development you can use this command:: + .. code-block:: bash - (ravenwps-env) $ pip install -e .[dev] - # or alternatively, - (ravenwps-env) $ make develop + make develop -Then clone the Raven Test Data repo somewhere on your disk:: +Start Raven PyWPS service +~~~~~~~~~~~~~~~~~~~~~~~~~ - (ravenwps-env) $ git clone https://github.com/Ouranosinc/raven-testdata.git +After successful installation you can start the service using the ``raven`` command-line: -You can then run the test suite by doing:: + .. code-block:: bash - (ravenwps-env) $ export RAVENPY_TESTDATA_PATH=/path/to/raven-testdata - (ravenwps-env) $ pytest + (ravenwps-env) $ raven-wps --help # show help + (ravenwps-env) $ raven-wps start # start service with default configuration -Start Raven PyWPS service -~~~~~~~~~~~~~~~~~~~~~~~~~ +or alternatively, -After successful installation you can start the service using the ``raven`` command-line:: + .. code-block:: bash - (ravenwps-env) $ raven-wps --help # show help - (ravenwps-env) $ raven-wps start # start service with default configuration - # or alternatively, - (ravenwps-env) $ raven-wps start --daemon # start service as daemon - loading configuration - forked process id: 42 + (ravenwps-env) $ raven-wps start --daemon # start service as daemon + loading configuration + forked process id: 42 The deployed WPS service is by default available on: http://localhost:9099/wps?service=WPS&version=1.0.0&request=GetCapabilities. -You can find which process uses a given port using the following command (here for port 5000)::: +You can find which process uses a given port using the following command (here for port 5000): + + .. code-block:: bash - $ netstat -nlp | grep :5000 + netstat -nlp | grep :5000 -Check the log files for errors:: +Check the log files for errors: - $ tail -f pywps.log + .. code-block:: bash + + tail -f pywps.log ... or do it the lazy way ~~~~~~~~~~~~~~~~~~~~~~~~~ -You can also use the ``Makefile`` to start and stop the service:: +You can also use the ``Makefile`` to start and stop the service: + + .. code-block:: bash - (ravenwps-env) $ make start - (ravenwps-env) $ make status - (ravenwps-env) $ tail -f pywps.log - (ravenwps-env) $ make stop + (ravenwps-env) $ make start + (ravenwps-env) $ make status + (ravenwps-env) $ tail -f pywps.log + (ravenwps-env) $ make stop .. Run Raven as Docker container @@ -147,10 +135,3 @@ You can also run Raven as a Docker container. .. :: TODO: Describe Docker container support. - -Use Ansible to deploy Raven on your System ------------------------------------------- - -Use the `Ansible playbook`_ for PyWPS to deploy Raven on your system. - -.. _Ansible playbook: http://ansible-wps-playbook.readthedocs.io/en/latest/index.html diff --git a/environment-dev.yml b/environment-dev.yml index ccc6c265..eae9fa5d 100644 --- a/environment-dev.yml +++ b/environment-dev.yml @@ -4,6 +4,7 @@ channels: - defaults dependencies: - python >=3.9,<3.13 + - flit >=3.8,<4.0 - birdy - black >=24.10.0 - bump-my-version >=0.21.0 @@ -19,6 +20,4 @@ dependencies: - pymetalink - pytest >=8.0.0 - pytest-xdist >=3.2 - - pip - - pip: - - flake8-alphabetize + - python-build diff --git a/environment-docs.yml b/environment-docs.yml index 9b1f7ea4..763f9b84 100644 --- a/environment-docs.yml +++ b/environment-docs.yml @@ -5,12 +5,12 @@ channels: - defaults dependencies: - python >=3.9,<3.13 - - pywps >=4.5.1 + - pywps >=4.6 - ipyleaflet - - ipython + - ipython >=8.5.0 - ipywidgets - - nbsphinx - - numpy + - nbsphinx >=0.9.5 + - numpy >=1.23.0 - pandas >=2.2 - sphinx >=7.0.0 - sphinx-autoapi diff --git a/environment.yml b/environment.yml index 0d0d586a..0be32887 100644 --- a/environment.yml +++ b/environment.yml @@ -4,23 +4,23 @@ channels: - defaults dependencies: - python >=3.9,<3.13 - - pywps >=4.5.1 + - pywps >=4.6 - affine - anyascii - cartopy >=0.23.0 - - click + - click >=8.1.7 - fiona >=1.9 - geopandas >=0.12.0 - geojson - gdal >=3.0 - - jinja2 + - jinja2 >=3.1.4 - matplotlib - nbval - netcdf4 - - numpy + - numpy >=1.23.0 - owslib - pandas >=2.2 - - psutil + - psutil >=6.0.0 - psycopg2 - pymetalink - pyogrio >=0.7.2 diff --git a/pyproject.toml b/pyproject.toml index fe64ad02..b79ac62c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["flit_core >=3.8,<4"] build-backend = "flit_core.buildapi" [project] -name = "raven" +name = "birdhouse-raven" authors = [ {name = "David Huard", email = "huard.david@ouranos.ca"}, {name = "Richard Arsenault", email = "richard.arsenault@etsmtl.ca"} @@ -39,15 +39,15 @@ classifiers = [ dynamic = ["description", "version"] dependencies = [ "anyascii", - "click", - "jinja2", + "click >=8.1.7", + "jinja2 >=3.1.4", "matplotlib", "netCDF4", - "numpy", + "numpy >=1.23.0", "owslib", "pandas >=2.2", - "psutil", - "pywps >=4.5.1", + "psutil >=6.0.0", + "pywps >=4.6", "requests", "xarray >=2023.11.0", "xclim >=0.48.2", @@ -74,11 +74,13 @@ dependencies = [ dev = [ # Dev tools and testing "birdhouse-birdy", - "black >=24.4.2", + "black >=24.10.0", + "build", "bump-my-version >=0.21.0", "flake8 >=7.0.0", "flake8-alphabetize", "flake8-rst-docstrings", + "flit >=3.8,<4.0", "ipykernel", "isort >=5.13.2", "nbconvert", @@ -91,10 +93,10 @@ dev = [ "yamllint" ] docs = [ - "ipython", + "ipyleaflet", + "ipython >=8.5.0", "ipywidgets", - "nbsphinx", - "pywps >=4.5.1", + "nbsphinx >=0.9.5", "sphinx >=7.0.0", "sphinx-autoapi", "sphinx-autodoc-typehints", diff --git a/raven/__init__.py b/raven/__init__.py deleted file mode 100644 index d38eb479..00000000 --- a/raven/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -"""WPS processes related to GIS and hydrological modeling, namely the Raven hydrological modeling framework.""" - -from .__version__ import __author__, __email__, __version__ # noqa: F401 diff --git a/src/raven/__init__.py b/src/raven/__init__.py new file mode 100644 index 00000000..4208977f --- /dev/null +++ b/src/raven/__init__.py @@ -0,0 +1,28 @@ +"""Raven offers processes related to hydrological modeling, and in particular, the Raven hydrological modeling framework.""" + +################################################################################### +# MIT License +# +# Copyright (c) 2018-2024, David Huard, Richard Arsenault, Trevor James Smith, Tuan Long Vu +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +################################################################################### + +from .__version__ import __author__, __email__, __version__ # noqa: F401 +from .wsgi import application # noqa: F401 diff --git a/raven/__version__.py b/src/raven/__version__.py similarity index 81% rename from raven/__version__.py rename to src/raven/__version__.py index 2b456180..25ebda70 100644 --- a/raven/__version__.py +++ b/src/raven/__version__.py @@ -1,7 +1,9 @@ +"""Raven version information.""" + # This information is located in its own file so that it can be loaded # without importing the main package when its dependencies are not installed. # See: https://packaging.python.org/guides/single-sourcing-package-version -__author__ = "David Huard" +__author__ = """David Huard""" __email__ = "huard.david@ouranos.ca" __version__ = "0.18.2" diff --git a/raven/cli.py b/src/raven/cli.py similarity index 79% rename from raven/cli.py rename to src/raven/cli.py index 1b20a718..d8fbb7e4 100644 --- a/raven/cli.py +++ b/src/raven/cli.py @@ -1,11 +1,12 @@ +"""Demo WPS service for testing and debugging.""" + ########################################################### -# Demo WPS service for testing and debugging. -# # See the werkzeug documentation on how to use the debugger: # http://werkzeug.pocoo.org/docs/0.12/debug/ ########################################################### import os +from pathlib import Path from urllib.parse import urlparse import click @@ -15,23 +16,28 @@ from . import wsgi -PID_FILE = os.path.abspath(os.path.join(os.path.curdir, "pywps.pid")) +PID_FILE = Path(__file__).parent.joinpath("pywps.pid").resolve() CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"]) -template_env = Environment(loader=PackageLoader("raven", "templates"), autoescape=True) +template_env = Environment( + loader=PackageLoader("raven", "templates"), + autoescape=True, +) def write_user_config(**kwargs): + """Write a custom configuration file.""" config_templ = template_env.get_template("pywps.cfg") rendered_config = config_templ.render(**kwargs) - config_file = os.path.abspath(os.path.join(os.path.curdir, ".custom.cfg")) - with open(config_file, "w") as fp: + config_file = Path(__file__).parent.joinpath(".custom.cfg").resolve() + with config_file.open("w") as fp: fp.write(rendered_config) return config_file def get_host(): + """Gather host information.""" url = configuration.get_config_value("server", "url") url = url or "http://localhost:9099/wps" @@ -48,11 +54,10 @@ def get_host(): def run_process_action(action=None): - """Run an action with psutil on current process - and return a status message.""" + """Run an action with psutil on current process and return a status message.""" action = action or "status" try: - with open(PID_FILE) as fp: + with PID_FILE.open() as fp: pid = int(fp.read()) p = psutil.Process(pid) if action == "stop": @@ -61,11 +66,9 @@ def run_process_action(action=None): else: from psutil import _pprint_secs - msg = "pid={}, status={}, created={}".format( - p.pid, p.status(), _pprint_secs(p.create_time()) - ) + msg = f"pid={p.pid}, status={p.status()}, created={_pprint_secs(p.create_time())}" if action == "stop": - os.remove(PID_FILE) + PID_FILE.unlink() except OSError: msg = 'No PID file found. Service not running? Try "netstat -nlp | grep :5000".' except psutil.NoSuchProcess as e: @@ -97,24 +100,25 @@ def _run(application, bind_host=None, daemon=False): @click.group(context_settings=CONTEXT_SETTINGS) @click.version_option() def cli(): - """Command line to start/stop a PyWPS service. + """ + Command line to start/stop a PyWPS service. Do not use this service in a production environment. It's intended to be running in a test environment only! - For more documentation, visit http://pywps.org/doc + For more documentation, visit https://pywps.org/doc """ pass @cli.command() def status(): - """Show status of PyWPS service""" + """Show status of PyWPS service.""" run_process_action(action="status") @cli.command() def stop(): - """Stop PyWPS service""" + """Stop PyWPS service.""" run_process_action(action="stop") @@ -137,7 +141,7 @@ def stop(): help="hostname in PyWPS configuration.", ) @click.option( - "--port", metavar="PORT", default="9099", help="port in PyWPS configuration." + "--port", metavar="PORT", default="5000", help="port in PyWPS configuration." ) @click.option( "--maxsingleinputsize", @@ -173,6 +177,10 @@ def stop(): default="sqlite:///pywps-logs.sqlite", help="database in PyWPS configuration", ) +@click.option("--outputurl", default="", help="base URL for file downloads") +@click.option( + "--outputpath", default="", help="base directory where outputs are written" +) def start( config, bind_host, @@ -185,15 +193,18 @@ def start( log_level, log_file, database, + outputurl, + outputpath, ): - """Start PyWPS service. + """ + Start PyWPS service. + This service is by default available at http://localhost:9099/wps """ - if os.path.exists(PID_FILE): + if PID_FILE.exists(): click.echo(f'PID file exists: "{PID_FILE}". Service still running?') os._exit(0) - cfgfiles = [] - cfgfiles.append( + cfgfiles = [ write_user_config( wps_hostname=hostname, wps_port=port, @@ -203,8 +214,10 @@ def start( wps_log_level=log_level, wps_log_file=log_file, wps_database=database, + wps_outputurl=outputurl, + wps_outputpath=outputpath, ) - ) + ] if config: cfgfiles.append(config) app = wsgi.create_app(cfgfiles) @@ -219,7 +232,7 @@ def start( pid = os.fork() if pid: click.echo(f"forked process id: {pid}") - with open(PID_FILE, "w") as fp: + with PID_FILE.open("w") as fp: fp.write(f"{pid}") except OSError as e: raise Exception("%s [%d]" % (e.strerror, e.errno)) diff --git a/raven/config.py b/src/raven/config.py similarity index 100% rename from raven/config.py rename to src/raven/config.py diff --git a/raven/data/hydrobasins_domains/hybas_lake_ar_lev01_v1c.zip b/src/raven/data/hydrobasins_domains/hybas_lake_ar_lev01_v1c.zip similarity index 100% rename from raven/data/hydrobasins_domains/hybas_lake_ar_lev01_v1c.zip rename to src/raven/data/hydrobasins_domains/hybas_lake_ar_lev01_v1c.zip diff --git a/raven/data/hydrobasins_domains/hybas_lake_na_lev01_v1c.zip b/src/raven/data/hydrobasins_domains/hybas_lake_na_lev01_v1c.zip similarity index 100% rename from raven/data/hydrobasins_domains/hybas_lake_na_lev01_v1c.zip rename to src/raven/data/hydrobasins_domains/hybas_lake_na_lev01_v1c.zip diff --git a/raven/default.cfg b/src/raven/default.cfg similarity index 100% rename from raven/default.cfg rename to src/raven/default.cfg diff --git a/raven/processes/__init__.py b/src/raven/processes/__init__.py similarity index 94% rename from raven/processes/__init__.py rename to src/raven/processes/__init__.py index d1df83c5..bb5de7c8 100644 --- a/raven/processes/__init__.py +++ b/src/raven/processes/__init__.py @@ -1,3 +1,5 @@ +"""Processes for the Raven WPS server.""" + from .wps_generic_raster_subset import RasterSubsetProcess from .wps_generic_shape_properties import ShapePropertiesProcess from .wps_generic_terrain_analysis import TerrainAnalysisProcess diff --git a/raven/processes/base_xclim.py b/src/raven/processes/base_xclim.py similarity index 100% rename from raven/processes/base_xclim.py rename to src/raven/processes/base_xclim.py diff --git a/raven/processes/wps_generic_raster_subset.py b/src/raven/processes/wps_generic_raster_subset.py similarity index 100% rename from raven/processes/wps_generic_raster_subset.py rename to src/raven/processes/wps_generic_raster_subset.py diff --git a/raven/processes/wps_generic_shape_properties.py b/src/raven/processes/wps_generic_shape_properties.py similarity index 100% rename from raven/processes/wps_generic_shape_properties.py rename to src/raven/processes/wps_generic_shape_properties.py diff --git a/raven/processes/wps_generic_terrain_analysis.py b/src/raven/processes/wps_generic_terrain_analysis.py similarity index 100% rename from raven/processes/wps_generic_terrain_analysis.py rename to src/raven/processes/wps_generic_terrain_analysis.py diff --git a/raven/processes/wps_generic_zonal_stats.py b/src/raven/processes/wps_generic_zonal_stats.py similarity index 100% rename from raven/processes/wps_generic_zonal_stats.py rename to src/raven/processes/wps_generic_zonal_stats.py diff --git a/raven/processes/wps_hydrobasins_shape_selection.py b/src/raven/processes/wps_hydrobasins_shape_selection.py similarity index 100% rename from raven/processes/wps_hydrobasins_shape_selection.py rename to src/raven/processes/wps_hydrobasins_shape_selection.py diff --git a/raven/processes/wps_nalcms_zonal_stats.py b/src/raven/processes/wps_nalcms_zonal_stats.py similarity index 100% rename from raven/processes/wps_nalcms_zonal_stats.py rename to src/raven/processes/wps_nalcms_zonal_stats.py diff --git a/raven/processes/wps_nalcms_zonal_stats_raster.py b/src/raven/processes/wps_nalcms_zonal_stats_raster.py similarity index 100% rename from raven/processes/wps_nalcms_zonal_stats_raster.py rename to src/raven/processes/wps_nalcms_zonal_stats_raster.py diff --git a/raven/processes/wpsio.py b/src/raven/processes/wpsio.py similarity index 100% rename from raven/processes/wpsio.py rename to src/raven/processes/wpsio.py diff --git a/src/raven/raven.py b/src/raven/raven.py new file mode 100644 index 00000000..dd0b80ed --- /dev/null +++ b/src/raven/raven.py @@ -0,0 +1 @@ +"""Main module.""" diff --git a/raven/templates/pywps.cfg b/src/raven/templates/pywps.cfg similarity index 81% rename from raven/templates/pywps.cfg rename to src/raven/templates/pywps.cfg index 20951f8a..c4ed66ce 100644 --- a/raven/templates/pywps.cfg +++ b/src/raven/templates/pywps.cfg @@ -21,7 +21,7 @@ workdir={{ wps_workdir }} {% endif %} [logging] -level = {{ wps_log_level|default('INFO') }} -file = {{ wps_log_file|default('pywps.log') }} -database = {{ wps_database|default('sqlite:///pywps-logs.sqlite') }} +level = INFO +file = pywps.log +database = sqlite:///pywps-logs.sqlite format = %(asctime)s] [%(levelname)s] line=%(lineno)s module=%(module)s %(message)s diff --git a/raven/utilities/__init__.py b/src/raven/utilities/__init__.py similarity index 100% rename from raven/utilities/__init__.py rename to src/raven/utilities/__init__.py diff --git a/raven/utilities/analysis.py b/src/raven/utilities/analysis.py similarity index 100% rename from raven/utilities/analysis.py rename to src/raven/utilities/analysis.py diff --git a/raven/utilities/checks.py b/src/raven/utilities/checks.py similarity index 100% rename from raven/utilities/checks.py rename to src/raven/utilities/checks.py diff --git a/raven/utilities/geo.py b/src/raven/utilities/geo.py similarity index 100% rename from raven/utilities/geo.py rename to src/raven/utilities/geo.py diff --git a/raven/utilities/geoserver.py b/src/raven/utilities/geoserver.py similarity index 100% rename from raven/utilities/geoserver.py rename to src/raven/utilities/geoserver.py diff --git a/raven/utilities/io.py b/src/raven/utilities/io.py similarity index 100% rename from raven/utilities/io.py rename to src/raven/utilities/io.py diff --git a/raven/utilities/testdata.py b/src/raven/utilities/testdata.py similarity index 100% rename from raven/utilities/testdata.py rename to src/raven/utilities/testdata.py diff --git a/raven/utils.py b/src/raven/utils.py similarity index 100% rename from raven/utils.py rename to src/raven/utils.py diff --git a/raven/wsgi.py b/src/raven/wsgi.py similarity index 66% rename from raven/wsgi.py rename to src/raven/wsgi.py index 12677601..442f852b 100644 --- a/raven/wsgi.py +++ b/src/raven/wsgi.py @@ -1,4 +1,7 @@ +"""Web Service Gateway Interface for PyWPS processes.""" + import os +from pathlib import Path from pywps.app.Service import Service @@ -6,7 +9,8 @@ def create_app(cfgfiles=None): - config_files = [os.path.join(os.path.dirname(__file__), "default.cfg")] + """Create PyWPS application.""" + config_files = [Path(__file__).parent.joinpath("default.cfg")] if cfgfiles: config_files.extend(cfgfiles) if "PYWPS_CFG" in os.environ: diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..31e4fc61 --- /dev/null +++ b/tox.ini @@ -0,0 +1,31 @@ +[tox] +min_version = 4.18.0 +envlist = + py{39,310,311,312}, + lint +requires = pip >= 24.2.0 +opts = -v + +[testenv:lint] +basepython = python +deps = + ruff >=0.5.7 +commands = + make lint +allowlist_externals = + make + +[testenv] +setenv = + PYTHONPATH = {toxinidir} +passenv = + GITHUB_* +install_command = python -m pip install --no-user {opts} {packages} +download = True +deps = +extras = dev +commands_pre = + python -m pip list + python -m pip check +commands = + python -m pytest --basetemp={envtmpdir} From d4452daf2a100f6f10fc8d36d52579b55411aa67 Mon Sep 17 00:00:00 2001 From: Zeitsperre <10819524+Zeitsperre@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:09:49 -0400 Subject: [PATCH 3/7] add module name --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index b79ac62c..75820013 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -151,6 +151,9 @@ replace = "Version=\"{new_version}\"" relative_files = true omit = ["tests/*.py"] +[tool.flit.module] +name = "raven" + [tool.flit.sdist] include = [ "AUTHORS.rst", From a5b00f8572f14a4cbc24d264ddc2f71511c57017 Mon Sep 17 00:00:00 2001 From: Zeitsperre <10819524+Zeitsperre@users.noreply.github.com> Date: Thu, 17 Oct 2024 11:53:55 -0400 Subject: [PATCH 4/7] remove conditional dependencies, update pre-commit, configure tox --- .github/workflows/main.yml | 3 +-- .pre-commit-config.yaml | 12 +++++----- Makefile | 8 +++---- README.rst | 2 +- pyproject.toml | 17 +++++++------- src/raven/utilities/__init__.py | 13 +---------- src/raven/utilities/analysis.py | 13 +++-------- src/raven/utilities/checks.py | 16 ++++--------- src/raven/utilities/geo.py | 39 +++++++++++++------------------- src/raven/utilities/geoserver.py | 22 ++++++------------ src/raven/utilities/io.py | 20 ++++++---------- tox.ini | 38 +++++++++++++++++++++++++++---- 12 files changed, 92 insertions(+), 111 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0cba50b2..fadf6937 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -81,11 +81,10 @@ jobs: uses: mamba-org/setup-micromamba@f8b8a1e23a26f60a44c853292711bacfd3eac822 # v1.9.0 with: cache-downloads: true - cache-environment: false + cache-environment: true environment-file: environment.yml create-args: >- python=${{ matrix.python-version }} - micromamba-version: "1.5.10-0" # pinned to avoid the breaking changes with mamba and micromamba (2.0.0). - name: Install RavenWPS run: | python -m pip install --no-user --editable ".[dev]" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cbcf94c4..b082aad9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ default_language_version: repos: - repo: https://github.com/asottile/pyupgrade - rev: v3.17.0 + rev: v3.18.0 hooks: - id: pyupgrade args: [ '--py39-plus' ] @@ -40,7 +40,6 @@ repos: - id: flake8 args: [ '--config=.flake8' ] additional_dependencies: - - "flake8-alphabetize==0.0.21" - "flake8-rst-docstrings==0.3.0" - repo: https://github.com/PyCQA/isort rev: 5.13.2 @@ -51,9 +50,9 @@ repos: hooks: - id: nbqa-pyupgrade args: [ '--py39-plus' ] - additional_dependencies: [ 'pyupgrade==v3.15.2' ] + additional_dependencies: [ 'pyupgrade==v3.18.0' ] - id: nbqa-black - additional_dependencies: [ 'black==24.4.2' ] + additional_dependencies: [ 'black==24.10.0' ] - id: nbqa-isort additional_dependencies: [ 'isort==5.13.2' ] - repo: https://github.com/pycqa/pydocstyle @@ -65,14 +64,15 @@ repos: rev: v0.3.9 hooks: - id: blackdoc - additional_dependencies: [ 'black==24.4.2' ] + additional_dependencies: [ 'black==24.10.0' ] + - id: blackdoc-autoupdate-black - repo: https://github.com/adrienverge/yamllint.git rev: v1.35.1 hooks: - id: yamllint args: [ '--config-file=.yamllint.yaml' ] - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.29.3 + rev: 0.29.4 hooks: - id: check-github-workflows - id: check-readthedocs diff --git a/Makefile b/Makefile index ee7ca429..f7c6d0e9 100644 --- a/Makefile +++ b/Makefile @@ -148,10 +148,10 @@ clean-docs: ## remove documentation artifacts lint: ## check code style @echo "Running black, ruff, isort, and yamllint code style checks ..." - black --check raven tests - isort --check raven tests - flake8 raven tests - yamllint --config-file=.yamllint.yaml raven + black --check src/raven tests + isort --check src/raven tests + flake8 src/raven tests + yamllint --config-file=.yamllint.yaml src/raven ## Testing targets: diff --git a/README.rst b/README.rst index 2350b332..1d47dce8 100644 --- a/README.rst +++ b/README.rst @@ -15,7 +15,7 @@ Raven : Hydrological modeling and analytics :alt: Build status .. image:: https://img.shields.io/github/license/Ouranosinc/raven.svg - :target: https://github.com/Ouranosinc/raven/blob/main/LICENSE.txt + :target: https://github.com/Ouranosinc/raven/blob/main/LICENSE :alt: GitHub license .. image:: https://badges.gitter.im/bird-house/birdhouse.svg diff --git a/pyproject.toml b/pyproject.toml index 75820013..55ff49ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["flit_core >=3.8,<4"] +requires = ["flit_core >=3.9,<4"] build-backend = "flit_core.buildapi" [project] @@ -15,7 +15,7 @@ maintainers = [ readme = {file = "README.rst", content-type = "text/x-rst"} requires-python = ">=3.9.0" keywords = ["wps", "pywps", "birdhouse", "raven", "hydrology", "gis", "analysis"] -license = {file = "LICENSE.txt"} +license = {file = "LICENSE"} classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", @@ -157,9 +157,9 @@ name = "raven" [tool.flit.sdist] include = [ "AUTHORS.rst", - "CHANGES.rst", + "CHANGELOG.rst", "CONTRIBUTING.rst", - "LICENSE.txt", + "LICENSE", "Makefile", "README.rst", "Dockerfile", @@ -170,11 +170,10 @@ include = [ "docs/Makefile", "docs/source/conf.py", "environment*.yml", - "raven/**/*.py", - "raven/data/**/*.zip", - "raven/default.cfg", - "raven/hpc_interface/**/*", - "raven/templates/pywps.cfg", + "src/raven/**/*.py", + "src/raven/data/**/*.zip", + "src/raven/default.cfg", + "src/raven/templates/pywps.cfg", "setup.cfg", "tests/*.py", "tests/test.cfg" diff --git a/src/raven/utilities/__init__.py b/src/raven/utilities/__init__.py index efc94537..e26fbdb6 100644 --- a/src/raven/utilities/__init__.py +++ b/src/raven/utilities/__init__.py @@ -1,12 +1 @@ -# TODO: Merge these into one message. -gis_import_error_message = ( - "`{}` requires installation of the RavenPy GIS libraries. These can be installed using the" - " `pip install ravenpy[gis]` recipe or via Anaconda (`conda env update -n ravenpy-env -f environment.yml`)" - " from the RavenPy repository source files." -) - -dev_import_error_message = ( - "`{}` requires installation of the RavenPy development libraries. These can be installed using the" - " `pip install ravenpy[dev]` recipe or via Anaconda (`conda env update -n ravenpy-env -f environment.yml`)" - " from the RavenPy repository source files." -) +"""Raven WPS """ diff --git a/src/raven/utilities/analysis.py b/src/raven/utilities/analysis.py index 4bde0545..541f6bed 100644 --- a/src/raven/utilities/analysis.py +++ b/src/raven/utilities/analysis.py @@ -4,16 +4,9 @@ from typing import List, Optional, Union import numpy as np - -from . import gis_import_error_message - -try: - import rasterio - from osgeo.gdal import Dataset, DEMProcessing - from shapely.geometry import GeometryCollection, MultiPolygon, Polygon, shape -except (ImportError, ModuleNotFoundError) as e: - msg = gis_import_error_message.format(Path(__file__).stem) - raise ImportError(msg) from e +import rasterio +from osgeo.gdal import Dataset, DEMProcessing +from shapely.geometry import GeometryCollection, MultiPolygon, Polygon, shape from raven.utilities.geo import generic_raster_clip diff --git a/src/raven/utilities/checks.py b/src/raven/utilities/checks.py index 0b29118c..6f6c7bd1 100644 --- a/src/raven/utilities/checks.py +++ b/src/raven/utilities/checks.py @@ -7,17 +7,11 @@ from pathlib import Path from typing import Any, Union -from . import gis_import_error_message - -try: - import fiona - import rasterio - from pyproj import CRS - from pyproj.exceptions import CRSError - from shapely.geometry import GeometryCollection, MultiPolygon, Point, shape -except (ImportError, ModuleNotFoundError) as e: - msg = gis_import_error_message.format(Path(__file__).stem) - raise ImportError(msg) from e +import fiona +import rasterio +from pyproj import CRS +from pyproj.exceptions import CRSError +from shapely.geometry import GeometryCollection, MultiPolygon, Point, shape import raven.utilities.io as io diff --git a/src/raven/utilities/geo.py b/src/raven/utilities/geo.py index d0768782..cf59e1c7 100644 --- a/src/raven/utilities/geo.py +++ b/src/raven/utilities/geo.py @@ -3,33 +3,26 @@ import collections import logging from pathlib import Path -from typing import List, Optional, Union +from typing import Optional, Union +import fiona import geopandas import pandas as pd +import rasterio +import rasterio.mask +import rasterio.vrt +import rasterio.warp from fiona import Feature - -from . import gis_import_error_message - -try: - import fiona - import rasterio - import rasterio.mask - import rasterio.vrt - import rasterio.warp - from pyproj import CRS - from shapely.geometry import ( - GeometryCollection, - MultiPolygon, - Point, - Polygon, - mapping, - shape, - ) - from shapely.ops import transform -except (ImportError, ModuleNotFoundError) as e: - gis_msg = gis_import_error_message.format(Path(__file__).stem) - raise ImportError(gis_msg) from e +from pyproj import CRS +from shapely.geometry import ( + GeometryCollection, + MultiPolygon, + Point, + Polygon, + mapping, + shape, +) +from shapely.ops import transform RASTERIO_TIFF_COMPRESSION = "lzw" LOGGER = logging.getLogger("RavenPy") diff --git a/src/raven/utilities/geoserver.py b/src/raven/utilities/geoserver.py index 408f37a7..3fdaf7b1 100644 --- a/src/raven/utilities/geoserver.py +++ b/src/raven/utilities/geoserver.py @@ -23,23 +23,15 @@ from typing import Optional, Tuple, Union from urllib.parse import urljoin +import fiona +import geopandas as gpd +import pandas as pd +from lxml import etree +from owslib.fes import PropertyIsLike +from owslib.wcs import WebCoverageService +from owslib.wfs import WebFeatureService from requests import Request -from . import gis_import_error_message - -try: - import fiona - import geopandas as gpd - import pandas as pd - from lxml import etree - from owslib.fes import PropertyIsEqualTo, PropertyIsLike - from owslib.wcs import WebCoverageService - from owslib.wfs import WebFeatureService - from shapely.geometry import Point, shape -except (ImportError, ModuleNotFoundError) as e: - msg = gis_import_error_message.format(Path(__file__).stem) - raise ImportError(msg) from e - try: from owslib.fes2 import Intersects from owslib.gml import Point as wfs_Point diff --git a/src/raven/utilities/io.py b/src/raven/utilities/io.py index a1a23834..95d95ed5 100644 --- a/src/raven/utilities/io.py +++ b/src/raven/utilities/io.py @@ -6,21 +6,15 @@ import tempfile import warnings import zipfile -from collections.abc import Iterable, Sequence +from collections.abc import Sequence from pathlib import Path from re import search -from typing import List, Optional, Tuple, Union - -from . import gis_import_error_message - -try: - import fiona - import rasterio - from pyproj import CRS - from shapely.geometry import shape -except (ImportError, ModuleNotFoundError) as e: - msg = gis_import_error_message.format(Path(__file__).stem) - raise ImportError(msg) from e +from typing import List, Optional, Union + +import fiona +import rasterio +from pyproj import CRS +from shapely.geometry import shape LOGGER = logging.getLogger("RavenPy") WGS84 = 4326 diff --git a/tox.ini b/tox.ini index 31e4fc61..6d4d6d15 100644 --- a/tox.ini +++ b/tox.ini @@ -1,14 +1,31 @@ [tox] min_version = 4.18.0 envlist = - py{39,310,311,312}, - lint -requires = pip >= 24.2.0 -opts = -v + lint, + py{39,310,311,312} +requires = + flit >= 3.9.0,<4.0 + pip >= 24.2.0 + setuptools >= 71.0 +opts = + --verbose + +[gh] +python = + 3.9 = py39-coveralls + 3.10 = py310-coveralls + 3.11 = py311-coveralls + 3.12 = py312-coveralls + 3.13 = py313-coveralls [testenv:lint] +skip_install = True basepython = python deps = + black ==24.10.0 + isort ==5.13.2 + flake8 >=7.1.1 + flake8-rst-docstrings >=0.3.0 ruff >=0.5.7 commands = make lint @@ -19,13 +36,24 @@ allowlist_externals = setenv = PYTHONPATH = {toxinidir} passenv = + CI + COVERALLS_* + GDAL_VERSION GITHUB_* install_command = python -m pip install --no-user {opts} {packages} download = True deps = -extras = dev + ; numpy must be present in python env before GDAL is installed + numpy <2.0.0 + gdal == {env:GDAL_VERSION} + setuptools >=71.0.0 +extras = + dev commands_pre = python -m pip list python -m pip check commands = + ; Rebuild GDAL in order to gain access to GDAL system-level objects + python -m pip install --upgrade --force-reinstall --no-deps --no-cache-dir --no-build-isolation gdal[numpy]=={env:GDAL_VERSION}.* + ; Run tests python -m pytest --basetemp={envtmpdir} From 65e2f277117ccb2e63942ccf7da6829c5eff1277 Mon Sep 17 00:00:00 2001 From: Zeitsperre <10819524+Zeitsperre@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:07:26 -0400 Subject: [PATCH 5/7] remove macOS artifact --- .../model/data_obs/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 raven/hpc_interface/test_data/ostrich-mohyse-salmon/model/data_obs/.DS_Store diff --git a/raven/hpc_interface/test_data/ostrich-mohyse-salmon/model/data_obs/.DS_Store b/raven/hpc_interface/test_data/ostrich-mohyse-salmon/model/data_obs/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Thu, 17 Oct 2024 13:07:49 -0400 Subject: [PATCH 6/7] rename changes to changelog, remove unused config --- Dockerfile | 1 - docs/source/changelog.rst | 1 + docs/source/changes.rst | 1 - docs/source/index.rst | 2 +- 4 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 docs/source/changelog.rst delete mode 100644 docs/source/changes.rst diff --git a/Dockerfile b/Dockerfile index eaf676f6..d3fef527 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,5 @@ # vim:set ft=dockerfile: FROM condaforge/mambaforge -ARG DEBIAN_FRONTEND=noninteractive ENV PIP_ROOT_USER_ACTION=ignore LABEL org.opencontainers.image.authors="https://github.com/Ouranosinc/raven" LABEL Description="Raven WPS" Vendor="Birdhouse" Version="0.18.2" diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst new file mode 100644 index 00000000..09929fe4 --- /dev/null +++ b/docs/source/changelog.rst @@ -0,0 +1 @@ +.. include:: ../../CHANGELOG.rst diff --git a/docs/source/changes.rst b/docs/source/changes.rst deleted file mode 100644 index d76c92b6..00000000 --- a/docs/source/changes.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../CHANGES.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index 591d8b56..cb7ba1af 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -21,7 +21,7 @@ User documentation dev_guide processes authors - changes + changelog Credits ------- From 77c006d30b559afd095bf9d8d8c51cc06560248b Mon Sep 17 00:00:00 2001 From: Zeitsperre <10819524+Zeitsperre@users.noreply.github.com> Date: Thu, 17 Oct 2024 13:21:57 -0400 Subject: [PATCH 7/7] fix CHANGELOG.rst --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9ba9fa22..f0405e15 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -239,7 +239,7 @@ v0.3.0 (2019-01-24) * Adds process for HBV-EC emulator v0.2.0 (2018-11-29) Washington ------------------------------ +------------------------------ * Provides generic RAVEN framework configuration * Process for GR4J-Cemaneige emulator