diff --git a/.github/workflows/build_workflow.yml b/.github/workflows/build_workflow.yml index 8afb2a4f..a1fb15f0 100644 --- a/.github/workflows/build_workflow.yml +++ b/.github/workflows/build_workflow.yml @@ -26,20 +26,20 @@ jobs: - if: ${{ steps.skip_check.outputs.should_skip != 'true' }} name: Checkout Code Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - if: ${{ steps.skip_check.outputs.should_skip != 'true' }} - name: Set up Python 3.9 - uses: actions/setup-python@v2 + name: Set up Python 3.10 + uses: actions/setup-python@v3 with: - python-version: 3.9 + python-version: "3.10" - if: ${{ steps.skip_check.outputs.should_skip != 'true' }} # Run all pre-commit hooks on all the files. # Getting only staged files can be tricky in case a new PR is opened # since the action is run on a branch in detached head state name: Install and Run Pre-commit - uses: pre-commit/action@v2.0.3 + uses: pre-commit/action@v3.0.0 build: name: Build (Python ${{ matrix.python-version }}) @@ -60,11 +60,11 @@ jobs: do_not_skip: '["push", "workflow_dispatch"]' - if: ${{ steps.skip_check.outputs.should_skip != 'true' }} - uses: actions/checkout@v2 + uses: actions/checkout@v3 - if: ${{ steps.skip_check.outputs.should_skip != 'true' }} name: Cache Conda - uses: actions/cache@v2 + uses: actions/cache@v3 env: # Increase this value to reset cache if conda-env/ci.yml has not changed in the workflow CACHE_NUMBER: 0 @@ -96,7 +96,7 @@ jobs: - if: ${{ steps.skip_check.outputs.should_skip != 'true' }} name: Upload Coverage Report - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: file: "tests_coverage_reports/coverage.xml" fail_ci_if_error: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4293751d..8db98822 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: check-yaml - repo: https://github.com/psf/black - rev: 22.6.0 + rev: 22.10.0 hooks: - id: black @@ -23,22 +23,22 @@ repos: # Need to use flake8 GitHub mirror due to CentOS git issue with GitLab # https://github.com/pre-commit/pre-commit/issues/1206 - repo: https://github.com/pycqa/flake8 - rev: 4.0.1 + rev: 5.0.4 hooks: - id: flake8 args: ["--config=setup.cfg"] additional_dependencies: [flake8-isort] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.971 + rev: v0.990 hooks: - id: mypy args: ["--config=setup.cfg"] additional_dependencies: [ - dask==2022.7.1, - numpy==1.22.4, - pandas==1.4.3, - xarray==2022.6.0, + dask==2022.10.2, + numpy==1.23.4, + pandas==1.5.1, + xarray==2022.11.0, types-python-dateutil==2.8.19, ] diff --git a/HISTORY.rst b/HISTORY.rst index ca91464b..a5cb8f04 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -2,6 +2,79 @@ History ======= +v0.4.0 (9 November 2022) +-------------------------- + +This minor release includes a feature update to support datasets that +have *N* dimensions mapped to *N* coordinates to represent an axis. This +means ``xcdat`` APIs are able to intelligently select which axis's +coordinates and bounds to work with if multiple are present within the +dataset. Decoding time is now a lazy operation, leading to significant +upfront runtime improvements when opening datasets with +``decode_times=True``. + +A new notebook called “A Gentle Introduction to xCDAT” was added to the +documentation gallery to help guide new xarray/xcdat users. xCDAT is now +hosted on Zenodo with a DOI for citations. + +There are various bug fixes for bounds, naming of spatial weights, and a +missing flag for ``xesmf`` that broke curvilinear regridding. + +Features +~~~~~~~~ + +- Support for N axis dimensions mapped to N coordinates by + `Tom Vo`_ and `Stephen Po-Chedley`_ in + https://github.com/xCDAT/xcdat/pull/343 + + - Rename ``get_axis_coord()`` to ``get_dim_coords()`` and + ``get_axis_dim()`` to ``get_dim_keys()`` + - Update spatial and temporal accessor class methods to refer to the + dimension coordinate variable on the data_var being operated on, + rather than the parent dataset + +- Decoding times (``decode_time()``) is now a lazy operation, which + results in significant runtime improvements by `Tom Vo`_ in + https://github.com/xCDAT/xcdat/pull/343 + +Bug Fixes +~~~~~~~~~ + +- Fix ``add_bounds()`` not ignoring 0-dim singleton coords by + `Tom Vo`_ and `Stephen Po-Chedley`_ in + https://github.com/xCDAT/xcdat/pull/343 +- Fix name of spatial weights with singleton coord by `Tom Vo`_ in + https://github.com/xCDAT/xcdat/pull/379 +- Fixes ``xesmf`` flag that was missing which broke curvilinear + regridding by `Jason Boutte`_ and `Stephen Po-Chedley`_ in + https://github.com/xCDAT/xcdat/pull/374 + +Documentation +~~~~~~~~~~~~~ + +- Add FAQs section for temporal metadata by `Tom Vo`_ in + https://github.com/xCDAT/xcdat/pull/383 +- Add gentle introduction notebook by `Tom Vo`_ in + https://github.com/xCDAT/xcdat/pull/373 +- Link repo to Zenodo and upload GitHub releases by `Tom Vo`_ in + https://github.com/xCDAT/xcdat/pull/367 +- Update project overview, FAQs, and add a link to xarray tutorials by + `Tom Vo`_ in https://github.com/xCDAT/xcdat/pull/365 +- Update feature list, add metadata interpretation to FAQs, and add + ``ipython`` syntax highlighting for notebooks by `Tom Vo`_ in + https://github.com/xCDAT/xcdat/pull/362 + +DevOps +~~~~~~ + +- Update release-drafter template by `Tom Vo`_ in + https://github.com/xCDAT/xcdat/pull/371 and + https://github.com/xCDAT/xcdat/pull/370 +- Automate release notes generation by `Tom Vo`_ in + https://github.com/xCDAT/xcdat/pull/368 + +**Full Changelog**: https://github.com/xCDAT/xcdat/compare/v0.3.3...v0.4.0 + v0.3.3 (12 October 2022) ------------------------ diff --git a/conda-env/ci.yml b/conda-env/ci.yml index 80a5ed4c..eabc0a8b 100644 --- a/conda-env/ci.yml +++ b/conda-env/ci.yml @@ -14,7 +14,6 @@ dependencies: - dask - esmpy - netcdf4 - - numba >=0.55.2 # TODO: Remove this pin once `numba` is properly patched with `numpy` compatability. - numpy - pandas - xarray diff --git a/conda-env/dev.yml b/conda-env/dev.yml index b812fec1..a262b531 100644 --- a/conda-env/dev.yml +++ b/conda-env/dev.yml @@ -8,17 +8,16 @@ dependencies: # Base # ================== # NOTE: If versions are updated, also `additional_dependencies` list for mypy in `.pre-commit-config.yaml` - - python=3.9.13 # TODO: Update to >=3.10 once sphinxcontrib-napoleon supports it. - - pip=22.2.2 + - python=3.10.6 + - pip=22.3.1 - cf_xarray=0.7.4 - - cftime=1.6.1 - - dask=2022.8.0 - - netcdf4=1.6.0 - - numba=0.55.2 # TODO: Remove this pin once `numba` is properly patched with `numpy` compatibility. - - numpy=1.22.4 - - pandas=1.4.3 + - cftime=1.6.2 + - dask=2022.10.2 + - netcdf4=1.6.1 + - numpy=1.23.4 + - pandas=1.5.1 - python-dateutil=2.8.2 - - xarray=2022.6.0 + - xarray=2022.11.0 # ================== # Optional # ================== @@ -27,32 +26,32 @@ dependencies: # Documentation # ================== - sphinx=4.5.0 - - sphinxcontrib-napoleon=0.7 - sphinx-autosummary-accessors=2022.4.0 - sphinx-book-theme=0.3.3 - sphinx-copybutton=0.5.0 - nbsphinx=0.8.9 - - pandoc=2.19 + - pandoc=2.19.2 + - ipython=8.5.0 # Required for nbsphinx syntax highlighting # ================== # Quality Assurance # ================== # NOTE: If versions are updated, also update 'rev' in `.pre-commit.config.yaml` - - black=22.6.0 + - black=22.10.0 - flake8=5.0.4 - - flake8-isort=4.2.0 + - flake8-isort=5.0.0 - isort=5.10.1 - - mypy=0.971 + - mypy=0.990 - pre-commit=2.20.0 - types-python-dateutil=2.8.19 # ================== # Testing # ================== - - pytest=7.1.2 - - pytest-cov=3.0.0 + - pytest=7.2.0 + - pytest-cov=4.0.0 # ================== # Developer Tools # ================== - - matplotlib=3.5.2 - - jupyterlab=3.4.5 + - matplotlib=3.6.2 + - jupyterlab=3.5.0 - tbump=6.9.0 prefix: /opt/miniconda3/envs/xcdat_dev diff --git a/conda-env/dev_min.yml b/conda-env/dev_min.yml deleted file mode 100644 index 65b7366c..00000000 --- a/conda-env/dev_min.yml +++ /dev/null @@ -1,46 +0,0 @@ -# A conda development environment without the optional and documentation dependencies. -# Use the environment if you are developing on an `osx-arm64` or `windows` platform (`xesmf`/`esmpy` not supported) -name: xcdat_dev_min -channels: - - conda-forge - - defaults -dependencies: - # ================== - # Base - # ================== - # NOTE: If versions are updated, also `additional_dependencies` list for mypy in `.pre-commit-config.yaml` - - python=3.9.13 # TODO: Update to >=3.10 once sphinxcontrib-napoleon supports it. - - pip=22.2.2 - - cf_xarray=0.7.4 - - cftime=1.6.1 - - dask=2022.8.0 - - netcdf4=1.6.0 - - numba=0.55.2 # TODO: Remove this pin once `numba` is properly patched with `numpy` compatibility. - - numpy=1.22.4 - - pandas=1.4.3 - - python-dateutil=2.8.2 - - xarray=2022.6.0 - # ================== - # Quality Assurance - # ================== - # NOTE: If versions are updated, also update 'rev' in `.pre-commit.config.yaml` - - black=22.6.0 - - flake8=5.0.4 - - flake8-isort=4.2.0 - - isort=5.10.1 - - mypy=0.971 - - pre-commit=2.20.0 - - types-python-dateutil=2.8.19 - # ================== - # Testing - # ================== - - pytest=7.1.2 - - pytest-cov=3.0.0 - # ================== - # Developer Tools - # ================== - - matplotlib=3.5.2 - - jupyterlab=3.4.5 - - tbump=6.9.0 - -prefix: /opt/miniconda3/envs/xcdat_dev_min diff --git a/conda-env/readthedocs.yml b/conda-env/readthedocs.yml index c0d4c0ab..a288f80a 100644 --- a/conda-env/readthedocs.yml +++ b/conda-env/readthedocs.yml @@ -7,31 +7,32 @@ dependencies: # Base # ================== # NOTE: If versions are updated, also `additional_dependencies` list for mypy in `.pre-commit-config.yaml` - - python=3.9.13 # TODO: Update to >=3.10 once sphinxcontrib-napoleon supports it. - - pip=22.2.2 + - python=3.10.6 + - pip=22.3.1 - cf_xarray=0.7.4 - - cftime=1.6.1 - - dask=2022.8.0 - - netcdf4=1.6.0 - - numba=0.55.2 # TODO: Remove this pin once `numba` is properly patched with `numpy` compatibility. - - numpy=1.22.4 - - pandas=1.4.3 + - cftime=1.6.2 + - dask=2022.10.2 + - netcdf4=1.6.1 + - numpy=1.23.4 + - pandas=1.5.1 - python-dateutil=2.8.2 - - types-python-dateutil=2.8.19 - - xarray=2022.6.0 + - xarray=2022.11.0 # ================== # Optional # ================== - xesmf=0.6.3 # ================== + # ================== + # Quality Assurance + # ================== + - types-python-dateutil=2.8.19 # Documentation # ================== - sphinx=4.5.0 - - sphinxcontrib-napoleon=0.7 - sphinx-autosummary-accessors=2022.4.0 - sphinx-book-theme=0.3.3 - sphinx-copybutton=0.5.0 - nbsphinx=0.8.9 - pandoc=2.19 - - ipython=8.5.0 # Required for nbsphinx syntax highlighting. + - ipython=8.5.0 # Required for nbsphinx syntax highlighting. prefix: /opt/miniconda3/envs/xcdat_rtd diff --git a/docs/conf.py b/docs/conf.py index f9d07f6a..2c66ab12 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -37,10 +37,10 @@ extensions = [ "sphinx.ext.autodoc", "sphinx.ext.autosummary", - "sphinx_autosummary_accessors", + "sphinx.ext.napoleon", "sphinx.ext.viewcode", + "sphinx_autosummary_accessors", "sphinx_copybutton", - "sphinxcontrib.napoleon", "nbsphinx", ] diff --git a/setup.cfg b/setup.cfg index 7b50974e..0c10dbed 100644 --- a/setup.cfg +++ b/setup.cfg @@ -46,7 +46,7 @@ exclude = venv [mypy] -python_version = 3.9 +python_version = 3.10 check_untyped_defs = True ignore_missing_imports = True warn_unused_ignores = True diff --git a/setup.py b/setup.py index 0584d199..789ad49d 100755 --- a/setup.py +++ b/setup.py @@ -35,6 +35,6 @@ test_suite="tests", tests_require=test_requires, url="https://github.com/xCDAT/xcdat", - version="0.3.3", + version="0.4.0", zip_safe=False, ) diff --git a/tbump.toml b/tbump.toml index fa36900d..a8b1dfb1 100644 --- a/tbump.toml +++ b/tbump.toml @@ -2,7 +2,7 @@ github_url = "https://github.com/xCDAT/xcdat" [version] -current = "0.3.3" +current = "0.4.0" # Example of a semver regexp. # Make sure this matches current_version before diff --git a/xcdat/__init__.py b/xcdat/__init__.py index f526145d..52d1ea2c 100644 --- a/xcdat/__init__.py +++ b/xcdat/__init__.py @@ -19,4 +19,4 @@ from xcdat.temporal import TemporalAccessor # noqa: F401 from xcdat.utils import compare_datasets # noqa: F401 -__version__ = "0.3.3" +__version__ = "0.4.0" diff --git a/xcdat/regridder/xesmf.py b/xcdat/regridder/xesmf.py index ac57618d..89b4001a 100644 --- a/xcdat/regridder/xesmf.py +++ b/xcdat/regridder/xesmf.py @@ -1,3 +1,5 @@ +from typing import Optional + import xarray as xr from xcdat.regridder.base import BaseRegridder, preserve_bounds @@ -34,9 +36,9 @@ def __init__( output_grid: xr.Dataset, method: str, periodic: bool = False, - extrap_method: str = None, - extrap_dist_exponent: float = None, - extrap_num_src_pnts: int = None, + extrap_method: Optional[str] = None, + extrap_dist_exponent: Optional[float] = None, + extrap_num_src_pnts: Optional[int] = None, ignore_degenerate: bool = True, **options, ): @@ -58,14 +60,14 @@ def __init__( - nearest_d2s periodic : bool Treat longitude as periodic. Used for global grids. - extrap_method : str + extrap_method : Optional[str] Extrapolation method. Options are - inverse_dist - nearest_s2d - extrap_dist_exponent : float + extrap_dist_exponent : Optional[float] The exponent to raise the distance to when calculating weights for the extrapolation method. - extrap_num_src_pnts : int + extrap_num_src_pnts : Optional[int] The number of source points to use for the extrapolation methods that use more than one source point. ignore_degenerate : bool diff --git a/xcdat/spatial.py b/xcdat/spatial.py index c5a15d70..c2ef2d8b 100644 --- a/xcdat/spatial.py +++ b/xcdat/spatial.py @@ -493,7 +493,7 @@ def _get_latitude_weights( domain_bounds = self._scale_domain_to_region(domain_bounds, region_bounds) d_bounds = np.sin(np.radians(domain_bounds)) - weights = self._calculate_weights(d_bounds) # type: ignore + weights = self._calculate_weights(d_bounds) return weights def _calculate_weights(self, domain_bounds: xr.DataArray): diff --git a/xcdat/temporal.py b/xcdat/temporal.py index f5361cdf..a02cf48b 100644 --- a/xcdat/temporal.py +++ b/xcdat/temporal.py @@ -700,7 +700,7 @@ def _averager( # it becomes obsolete after the data variable is averaged. When the # averaged data variable is added to the dataset, the new time dimension # and its associated coordinates are also added. - ds = ds.drop_dims(self.dim) + ds = ds.drop_dims(self.dim) # type: ignore ds[dv.name] = dv if keep_weights: @@ -985,9 +985,9 @@ def _average( with xr.set_options(keep_attrs=True): if self._weighted: self._weights = self._get_weights(time_bounds) - dv = dv.weighted(self._weights).mean(dim=self.dim) + dv = dv.weighted(self._weights).mean(dim=self.dim) # type: ignore else: - dv = dv.mean(dim=self.dim) + dv = dv.mean(dim=self.dim) # type: ignore dv = self._add_operation_attrs(dv)