Skip to content

Conversation

@sol1105
Copy link
Contributor

@sol1105 sol1105 commented Aug 13, 2025

Pull Request Checklist:

What kind of change does this PR introduce?:

  • Fixed regrid.ipynb
  • Removed need for psymaps / psyplot dependency
  • utils/common.py:
    • Updated require_module to accept an interval of unsupported versions
  • utils/dataset_utils.py:
    • Added option to get_coord_by_type to suppress warning about a main variable not being identifiable
  • utils/output_utils.py:
    • Added functions fix_netcdf_attrs_encoding and '_fix_str_encoding to fix utf-8 encoding issues for global and variable attributes
  • ops/base_operation.py:
    • Applying above fix to correct utf-8 encoding issues
  • core/regrid.py:
    • xarray version warning correctly triggered for versions outside of compatible version interval
    • Grid.detect_extent:
      • determins now also extent in latitude
      • using now average resolution in x and y direction, respectively, rather than the average resolution, to determine the extent in lon/lat direction
      • now returning (lon_extent, lat_extent) instead of just lon_extent
    • Grid._grid_from_ds_adaptive:
      • Added fix for regional grids that include either meridian or antimeridian
      • Grids that are considered global in lon or lat direction, will now be defined within 0,360 / -180,180 or -90,90 degrees_east/north
    • Grid.to_netcdf:
      • Added fix for ds.encoding['unlimited_dims'] not being updated by xarray when dropping all time-dependent variables to write out solely the horizontal grid
      • Applying above fix for utf-8 encoding issues
    • Grid.extent_lat, Grid.extent_lon: added new attributes
    • Weights:
      • Will now use post_mask_source='domain_edge' setting when remapping a regional grid via nearest neighbour method, to avoid extrapolation beyond the original source domain (xESMF PR yet to be approved and merged)
  • Tests:
    • Added / modified tests for code changes
    • Added some tests to increase coverage
    • Reverted skipping or xfailing tests that used to fail with engine="h5netcdf"

Does this PR introduce a breaking change?:

  • clisops.core.regrid.Grid.detect_extent now returns the tuple (lon_extent, lat_extent) rather than just lon_extent
  • Grid.extent now carries the combined extent in lon and lat direction and no longer just the extent in lon direction. If the grid is considered global in extent of both, lon and lat coordinates, Grid.extent is set to "global" else, it is set to "regional". Grid.extent_lon and Grid.extent_lat allow accessing the extent in only lon and lat direction, respectively.

Other information:

I can update HISTORY.rst once all changes made by the PR are approved and potential feedback worked in.
There are currently two xesmf PRs open (#444 #445) that should be merged and a xesmf release triggered before merging this in.

- utils/common.py:
  - Updated require_module to accept an interval of unsupported versions
- utils/dataset_utils.py:
  - Added option to get_coord_by_type to suppress warning about a main variable
    not being identifiable
- utils/output_utils.py
  - Added functions 'fix_netcdf_attrs_encoding' and '_fix_str_encoding' to
    fix utf-8 encoding issues for global and variable attributes
- ops/base_operation.py:
  - Applying above fix to correct utf-8 encoding issues
- core/regrid.py:
  - xarray version warning correctly triggered for versions
    outside of compatible version interval
  - Grid.detect_extent:
    + determins now also extent in latitude
    + using now average resolution in x and y direction, respectively,
      rather than the average resolution, to determine the extent in lon/lat
      direction
    + now returning (lon_extent, lat_extent) instead of just lon_extent
  - Grid._grid_from_ds_adaptive:
    + Added fix for regional grids that include either meridian or antimeridian
  - Grid.to_netcdf:
    + Added fix for ds.encoding['unlimited_dims'] not being updated by xarray
      when dropping all time-dependent variables to write out solely the horizontal grid
    + Applying above fix for utf-8 encoding issues
  - Grid.extent_lat: added new attribute
  - Weights:
    + Will now use "post_mask_source='domain_edge'" setting when remapping a regional grid
      via nearest neighbour method, to avoid extrapolation beyond the original source domain
- Tests:
  - Added / modified tests for code changes
  - Reverted skipping or xfailing tests that used to fail with engine h5netcdf
@coveralls
Copy link

coveralls commented Aug 13, 2025

Pull Request Test Coverage Report for Build 19869800153

Details

  • 76 of 95 (80.0%) changed or added relevant lines in 5 files are covered.
  • 3 unchanged lines in 1 file lost coverage.
  • Overall coverage increased (+0.8%) to 87.288%

Changes Missing Coverage Covered Lines Changed/Added Lines %
clisops/utils/common.py 3 5 60.0%
clisops/utils/output_utils.py 21 26 80.77%
clisops/core/regrid.py 39 51 76.47%
Files with Coverage Reduction New Missed Lines %
clisops/utils/common.py 3 79.1%
Totals Coverage Status
Change from base Build 19505413673: 0.8%
Covered Lines: 3186
Relevant Lines: 3650

💛 - Coveralls

- Consistent distinction between extent, extent_lon, extent_lat
- Adaptive grids with global extent in lon/lat will not exceed
  -180,180 or 0,360 in lon / -90,90 in lat
- Modified tests accordingly
- Added tests for yet untested parts of the regrid code to boost coverage
@sol1105
Copy link
Contributor Author

sol1105 commented Sep 9, 2025

ToDo: Replace all .item calls with .data or .values (#451).

@Zeitsperre
Copy link
Collaborator

@sol1105 Is this ready for review? I can start looking at it next week if so.

@sol1105
Copy link
Contributor Author

sol1105 commented Nov 21, 2025

@Zeitsperre Thank you, it would be great if you had a look the changes :)

The changes require a feature recently merged into the xesmf master branch. So we need to wait for a xesmf release (which is likely to happen pretty soon) before merging this.

Copy link
Collaborator

@Zeitsperre Zeitsperre left a comment

Choose a reason for hiding this comment

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

LGTM. Given that @aulemahal implemented some of these changes in xesmf, I'll throw the ball to him to weigh in on this as well.

s : str, byte
The string to be fixed. If the input is not of type str or bytes,
it is returned as is.
encoding : str, optional
Copy link
Collaborator

Choose a reason for hiding this comment

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

optional suggests that encoding can be passed as None. Be sure to handle that case if so.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

def _fix_str_encoding(s, encoding="utf-8"):
     [...]
     encoding : str, optional
         The encoding to be used. Default is "utf-8".

I thought optional only means that else the default is used and if None should be allowed it would be set as
encoding: str or None, optional?

Copy link
Collaborator

Choose a reason for hiding this comment

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

From my understanding, optional and something | None are the same thing. It's a shorthand that resembles the optional you would find in other languages (like C++ or Rust) meaning that the function accepts a Null value.

For more info: https://docs.python.org/3/library/typing.html#typing.Optional

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the confusion here stems from the caveat in the standard library: Note that this is not the same concept as an optional argument, which is one that has a default.

When I see ,optional in a docstring, I think of the call signature Optional. It's a bit ambiguous, I suppose.

@sol1105
Copy link
Contributor Author

sol1105 commented Nov 25, 2025

@Zeitsperre Thanks for having such a thorough look at the changes :)

@sol1105
Copy link
Contributor Author

sol1105 commented Nov 28, 2025

@aulemahal Many thanks for all the effort you put into getting the xesmf release out 😃

@Zeitsperre I think I made all necessary changes and all tests pass. Only for Anaconda python3.10 the environment cannot be built because xesmf does no longer support python 3.10.

@aulemahal
Copy link
Collaborator

Sorry about the drop. I hope this is not problematic on your side ? I chose to drop support in the lack of resources to fix bugs related to older python/xarray/sparse versions.

Unless you have objections, I will try to remove xESMF 0.9 and 0.9.1 from PyPi because their "support" of Python 3.10 is only partial.

@Zeitsperre
Copy link
Collaborator

Zeitsperre commented Nov 28, 2025

@sol1105 I think we can either drop Python3.10 (loses security support in a year; https://endoflife.date/python) or we can add a version check for the regridding tools, maybe something like:

  • Add a version specifier for xesmf: xesmf >=0.9.2; python_version >= '3.11'"
  • Add a check when someone tries to import the regridding functions that fails if python <= 3.10.

I would be fine with us dropping Python3.10; There have been many changes to clisops lately, and I still would like to see us split off core, possibly early 2026.

@sol1105
Copy link
Contributor Author

sol1105 commented Dec 2, 2025

I think we can either drop Python3.10 (loses security support in a year; https://endoflife.date/python) or we can add a version check for the regridding tools

@Zeitsperre I do not have any preference here. Should these changes however be done in a different PR?

@cehbrecht What do you think?

@cehbrecht
Copy link
Collaborator

I think we can either drop Python3.10 (loses security support in a year; https://endoflife.date/python) or we can add a version check for the regridding tools

@Zeitsperre I do not have any preference here. Should these changes however be done in a different PR?

@cehbrecht What do you think?

I don't mind when we skip Python 3.10. If this regird PR will be "pending" one could already do the "skip" in another PR and merge it back in here again. What ever is easier for you :)

### What kind of change does this PR introduce?: <!--(Bug fix, feature,
docs update, etc.)-->

* Drops support for Python3.10
* Raises the minimum supported `numpy` to v1.26

### Does this PR introduce a breaking change?: <!--(Has there been an
API change? New dependencies?)-->

Yes, the minimum Python is now 3.11 and the minimum `numpy` is at the
absolute last version before `v2.0`. This is roughly following the
[scipy SPEC-0
recommendations](https://scientific-python.org/specs/spec-0000/).
@sol1105
Copy link
Contributor Author

sol1105 commented Dec 5, 2025

@Zeitsperre Do you have any objections against a simple merge commit without squash/rebase?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants