diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e5797077df..82ba80c4ff 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,7 +6,9 @@ version: 2 updates: - package-ecosystem: "github-actions" - directory: "/" + directories: + - "/" + - "/.github/workflows/composite/*" schedule: # Check later in the week - the upstream dependabot check in `workflows` runs deliberately early in the week. # Therefore allowing time for the `workflows` update to be merged-and-released first. diff --git a/.github/workflows/benchmarks_run.yml b/.github/workflows/benchmarks_run.yml index dfb2c7c33a..287735c335 100644 --- a/.github/workflows/benchmarks_run.yml +++ b/.github/workflows/benchmarks_run.yml @@ -60,7 +60,7 @@ jobs: env: IRIS_TEST_DATA_LOC_PATH: benchmarks IRIS_TEST_DATA_PATH: benchmarks/iris-test-data - IRIS_TEST_DATA_VERSION: "2.22" + IRIS_TEST_DATA_VERSION: "2.28" # Lets us manually bump the cache to rebuild ENV_CACHE_BUILD: "0" TEST_DATA_CACHE_BUILD: "2" diff --git a/.github/workflows/ci-manifest.yml b/.github/workflows/ci-manifest.yml index cf79783a82..57dd7e0371 100644 --- a/.github/workflows/ci-manifest.yml +++ b/.github/workflows/ci-manifest.yml @@ -23,4 +23,4 @@ concurrency: jobs: manifest: name: "check-manifest" - uses: scitools/workflows/.github/workflows/ci-manifest.yml@2024.09.1 + uses: scitools/workflows/.github/workflows/ci-manifest.yml@2024.10.2 diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 2d59294cbb..4b21e73384 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -50,7 +50,8 @@ jobs: session: "tests" env: - IRIS_TEST_DATA_VERSION: "2.25" + # NOTE: IRIS_TEST_DATA_VERSION is also set in benchmarks_run.yml + IRIS_TEST_DATA_VERSION: "2.28" ENV_NAME: "ci-tests" steps: @@ -68,14 +69,14 @@ jobs: - name: "data cache" uses: ./.github/workflows/composite/iris-data-cache with: - cache_build: 0 + cache_build: 6 env_name: ${{ env.ENV_NAME }} version: ${{ env.IRIS_TEST_DATA_VERSION }} - name: "conda package cache" uses: ./.github/workflows/composite/conda-pkg-cache with: - cache_build: 0 + cache_build: 6 cache_period: ${{ env.CACHE_PERIOD }} env_name: ${{ env.ENV_NAME }} @@ -83,15 +84,14 @@ jobs: uses: conda-incubator/setup-miniconda@v3 with: miniforge-version: latest - channels: conda-forge,defaults + channels: conda-forge activate-environment: ${{ env.ENV_NAME }} auto-update-conda: false - use-only-tar-bz2: true - name: "conda environment cache" uses: ./.github/workflows/composite/conda-env-cache with: - cache_build: 0 + cache_build: 6 cache_period: ${{ env.CACHE_PERIOD }} env_name: ${{ env.ENV_NAME }} install_packages: "cartopy nox pip" @@ -104,14 +104,14 @@ jobs: - name: "cartopy cache" uses: ./.github/workflows/composite/cartopy-cache with: - cache_build: 0 + cache_build: 6 cache_period: ${{ env.CACHE_PERIOD }} env_name: ${{ env.ENV_NAME }} - name: "nox cache" uses: ./.github/workflows/composite/nox-cache with: - cache_build: 2 + cache_build: 6 env_name: ${{ env.ENV_NAME }} lock_file: ${{ env.LOCK_FILE }} diff --git a/.github/workflows/composite/cartopy-cache/action.yml b/.github/workflows/composite/cartopy-cache/action.yml index e805cbacc1..d42e5c36cb 100644 --- a/.github/workflows/composite/cartopy-cache/action.yml +++ b/.github/workflows/composite/cartopy-cache/action.yml @@ -20,7 +20,7 @@ inputs: runs: using: "composite" steps: - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: cartopy-cache with: path: ~/.local/share/cartopy diff --git a/.github/workflows/composite/conda-env-cache/action.yml b/.github/workflows/composite/conda-env-cache/action.yml index 6bfd6fff90..15eaaec63c 100644 --- a/.github/workflows/composite/conda-env-cache/action.yml +++ b/.github/workflows/composite/conda-env-cache/action.yml @@ -23,7 +23,7 @@ inputs: runs: using: "composite" steps: - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: conda-env-cache with: path: ${{ env.CONDA }}/envs/${{ inputs.env_name }} diff --git a/.github/workflows/composite/conda-pkg-cache/action.yml b/.github/workflows/composite/conda-pkg-cache/action.yml index 4472d7e415..48c4470e44 100644 --- a/.github/workflows/composite/conda-pkg-cache/action.yml +++ b/.github/workflows/composite/conda-pkg-cache/action.yml @@ -16,7 +16,7 @@ inputs: runs: using: "composite" steps: - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ~/conda_pkgs_dir key: ${{ runner.os }}-conda-pkgs-${{ inputs.env_name }}-p${{ inputs.cache_period }}-b${{ inputs.cache_build }} diff --git a/.github/workflows/composite/iris-data-cache/action.yml b/.github/workflows/composite/iris-data-cache/action.yml index 7bf72fae8b..7ba7acb2cc 100644 --- a/.github/workflows/composite/iris-data-cache/action.yml +++ b/.github/workflows/composite/iris-data-cache/action.yml @@ -16,7 +16,7 @@ inputs: runs: using: "composite" steps: - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: data-cache with: path: ~/iris-test-data diff --git a/.github/workflows/composite/nox-cache/action.yml b/.github/workflows/composite/nox-cache/action.yml index 468dd22d81..00387331e7 100644 --- a/.github/workflows/composite/nox-cache/action.yml +++ b/.github/workflows/composite/nox-cache/action.yml @@ -16,7 +16,7 @@ inputs: runs: using: "composite" steps: - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ${{ github.workspace }}/.nox key: ${{ runner.os }}-nox-${{ inputs.env_name }}-s${{ matrix.session }}-py${{ matrix.python-version }}-b${{ inputs.cache_build }}-${{ hashFiles(inputs.lock_file) }} diff --git a/.github/workflows/refresh-lockfiles.yml b/.github/workflows/refresh-lockfiles.yml index 24e72e059c..f01a7d9b33 100644 --- a/.github/workflows/refresh-lockfiles.yml +++ b/.github/workflows/refresh-lockfiles.yml @@ -14,5 +14,5 @@ on: jobs: refresh_lockfiles: - uses: scitools/workflows/.github/workflows/refresh-lockfiles.yml@2024.09.1 + uses: scitools/workflows/.github/workflows/refresh-lockfiles.yml@2024.10.2 secrets: inherit diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index feedba5b74..053e4f839a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ minimum_pre_commit_version: 1.21.0 repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: # Prevent giant files from being committed. - id: check-added-large-files @@ -29,7 +29,7 @@ repos: - id: no-commit-to-branch - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.4.10" + rev: "v0.7.0" hooks: - id: ruff types: [file, python] @@ -45,13 +45,13 @@ repos: additional_dependencies: [tomli] - repo: https://github.com/PyCQA/flake8 - rev: 7.1.0 + rev: 7.1.1 hooks: - id: flake8 types: [file, python] - repo: https://github.com/asottile/blacken-docs - rev: 1.16.0 + rev: 1.19.0 hooks: - id: blacken-docs types: [file, rst] @@ -63,7 +63,7 @@ repos: types: [file, python] - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v1.9.0' + rev: 'v1.12.1' hooks: - id: mypy additional_dependencies: @@ -71,7 +71,7 @@ repos: exclude: 'noxfile\.py|docs/src/conf\.py' - repo: https://github.com/numpy/numpydoc - rev: v1.7.0 + rev: v1.8.0 hooks: - id: numpydoc-validation exclude: "^lib/iris/tests/|docs/gallery_code/" diff --git a/benchmarks/benchmarks/cube.py b/benchmarks/benchmarks/cube.py index 2030547b46..0b6829ee2d 100644 --- a/benchmarks/benchmarks/cube.py +++ b/benchmarks/benchmarks/cube.py @@ -4,6 +4,8 @@ # See LICENSE in the root of the repository for full licensing details. """Cube benchmark tests.""" +from collections.abc import Iterable + from iris import coords from iris.cube import Cube @@ -21,9 +23,9 @@ def setup(self, w_mesh: bool, _) -> None: source_cube = realistic_4d_w_everything(w_mesh=w_mesh) def get_coords_and_dims( - coords_tuple: tuple[coords._DimensionalMetadata, ...], + coords_iter: Iterable[coords._DimensionalMetadata], ) -> list[tuple[coords._DimensionalMetadata, tuple[int, ...]]]: - return [(c, c.cube_dims(source_cube)) for c in coords_tuple] + return [(c, c.cube_dims(source_cube)) for c in coords_iter] self.cube_kwargs = dict( data=source_cube.data, diff --git a/docs/src/common_links.inc b/docs/src/common_links.inc index 3a329fe40b..a49a98bfa6 100644 --- a/docs/src/common_links.inc +++ b/docs/src/common_links.inc @@ -79,5 +79,6 @@ .. _@stephenworsley: https://github.com/stephenworsley .. _@tkknight: https://github.com/tkknight .. _@trexfeathers: https://github.com/trexfeathers +.. _@ukmo-ccbunney: https://github.com/ukmo-ccbunney .. _@wjbenfold: https://github.com/wjbenfold .. _@zklaus: https://github.com/zklaus diff --git a/docs/src/conf.py b/docs/src/conf.py index 4c8f59564f..70b1063585 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -211,7 +211,7 @@ def _dotv(version): } # https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_typehints -autodoc_typehints = "none" +autodoc_typehints = "description" autosummary_generate = True autosummary_imported_members = True autopackage_name = ["iris"] @@ -246,17 +246,17 @@ def _dotv(version): # See https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html intersphinx_mapping = { "cartopy": ("https://scitools.org.uk/cartopy/docs/latest/", None), + "cf_units": ("https://cf-units.readthedocs.io/en/stable/", None), "cftime": ("https://unidata.github.io/cftime/", None), "dask": ("https://docs.dask.org/en/stable/", None), + "geovista": ("https://geovista.readthedocs.io/en/latest/", None), "iris-esmf-regrid": ("https://iris-esmf-regrid.readthedocs.io/en/stable/", None), "matplotlib": ("https://matplotlib.org/stable/", None), "numpy": ("https://numpy.org/doc/stable/", None), - "python": ("https://docs.python.org/3/", None), - "scipy": ("https://docs.scipy.org/doc/scipy/", None), "pandas": ("https://pandas.pydata.org/docs/", None), - "dask": ("https://docs.dask.org/en/stable/", None), - "geovista": ("https://geovista.readthedocs.io/en/latest/", None), + "python": ("https://docs.python.org/3/", None), "pyvista": ("https://docs.pyvista.org/", None), + "scipy": ("https://docs.scipy.org/doc/scipy/", None), } # The name of the Pygments (syntax highlighting) style to use. diff --git a/docs/src/further_topics/controlling_merge.rst b/docs/src/further_topics/controlling_merge.rst new file mode 100644 index 0000000000..85fe46e745 --- /dev/null +++ b/docs/src/further_topics/controlling_merge.rst @@ -0,0 +1,222 @@ +.. _controlling_merge: + +================================= +Controlling Merge and Concatenate +================================= + +Preliminaries +------------- + +The following code would have been necessary with loading behaviour prior to version 3.11.0 . For the sake of +demonstration, we will revert back to this legacy loading behaviour as follows: + + >>> iris.LOAD_POLICY.set("legacy") + +.. note:: + The default settings for :data:`iris.LOAD_POLICY` effectively implements some version of the following demonstration + automatically upon loading. It may still be worth being aware of how to handle this manually if an even finer degree + of control is required. + +How to Merge Cubes When Coordinates Differ +------------------------------------------ + +Sometimes it is not possible to appropriately combine a CubeList using merge and concatenate on their own. In such cases +it is possible to achieve much more control over cube combination by using the :func:`~iris.util.new_axis` utility. +Consider the following set of cubes: + + >>> file_1 = iris.sample_data_path("time_varying_hybrid_height", "*_2160-12.pp") + >>> file_2 = iris.sample_data_path("time_varying_hybrid_height", "*_2161-01.pp") + >>> cubes = iris.load([file_1, file_2], "x_wind") + >>> print(cubes[0]) + x_wind / (m s-1) (model_level_number: 5; latitude: 144; longitude: 192) + Dimension coordinates: + model_level_number x - - + latitude - x - + longitude - - x + Auxiliary coordinates: + level_height x - - + sigma x - - + surface_altitude - x x + Derived coordinates: + altitude x x x + Scalar coordinates: + forecast_period 1338840.0 hours, bound=(1338480.0, 1339200.0) hours + forecast_reference_time 2006-01-01 00:00:00 + time 2160-12-16 00:00:00, bound=(2160-12-01 00:00:00, 2161-01-01 00:00:00) + Cell methods: + 0 time: mean (interval: 1 hour) + Attributes: + STASH m01s00i002 + source 'Data from Met Office Unified Model' + um_version '12.1' + >>> print(cubes[1]) + x_wind / (m s-1) (model_level_number: 5; latitude: 144; longitude: 192) + Dimension coordinates: + model_level_number x - - + latitude - x - + longitude - - x + Auxiliary coordinates: + level_height x - - + sigma x - - + surface_altitude - x x + Derived coordinates: + altitude x x x + Scalar coordinates: + forecast_period 1339560.0 hours, bound=(1339200.0, 1339920.0) hours + forecast_reference_time 2006-01-01 00:00:00 + time 2161-01-16 00:00:00, bound=(2161-01-01 00:00:00, 2161-02-01 00:00:00) + Cell methods: + 0 time: mean (interval: 1 hour) + Attributes: + STASH m01s00i002 + source 'Data from Met Office Unified Model' + um_version '12.1' + +These two cubes have different time points (i.e. scalar time value). So we would normally be able to merge them, +creating a time dimension. However, in this case we can not combine them with :meth:`~iris.cube.Cube.merge` +due to the fact that their ``surface_altitude`` coordinate also varies over time: + + >>> cubes.merge_cube() + Traceback (most recent call last): + ... + iris.exceptions.MergeError: failed to merge into a single cube. + Coordinates in cube.aux_coords (non-scalar) differ: surface_altitude. + +Since surface altitude is preventing merging, we want to find a way of combining these cubes while also *explicitly* +combining the ``surface_altitude`` coordinate so that it also varies along the time dimension. We can do this by first +adding a dimension to the cube *and* the ``surface_altitude`` coordinate using :func:`~iris.util.new_axis`, and then +concatenating those cubes together. We can attempt this as follows: + + >>> from iris.util import new_axis + >>> from iris.cube import CubeList + >>> processed_cubes = CubeList([new_axis(cube, scalar_coord="time", expand_extras=["surface_altitude"]) for cube in cubes]) + >>> processed_cubes.concatenate_cube() + Traceback (most recent call last): + ... + iris.exceptions.ConcatenateError: failed to concatenate into a single cube. + Scalar coordinates values or metadata differ: forecast_period != forecast_period + +This error alerts us to the fact that the ``forecast_period`` coordinate is also varying over time. To get concatenation +to work, we will have to expand the dimensions of this coordinate to include "time", by passing it also to the +``expand_extras`` keyword. + + >>> processed_cubes = CubeList( + ... [new_axis(cube, scalar_coord="time", expand_extras=["surface_altitude", "forecast_period"]) for cube in cubes] + ... ) + >>> result = processed_cubes.concatenate_cube() + >>> print(result) + x_wind / (m s-1) (time: 2; model_level_number: 5; latitude: 144; longitude: 192) + Dimension coordinates: + time x - - - + model_level_number - x - - + latitude - - x - + longitude - - - x + Auxiliary coordinates: + forecast_period x - - - + surface_altitude x - x x + level_height - x - - + sigma - x - - + Derived coordinates: + altitude x x x x + Scalar coordinates: + forecast_reference_time 2006-01-01 00:00:00 + Cell methods: + 0 time: mean (interval: 1 hour) + Attributes: + STASH m01s00i002 + source 'Data from Met Office Unified Model' + um_version '12.1' + +.. note:: + Since the derived coordinate ``altitude`` derives from ``surface_altitude``, adding ``time`` to the dimensions of + ``surface_altitude`` also means it is added to the dimensions of ``altitude``. So in the combined cube, both of + these coordinates vary along the ``time`` dimension. + +Controlling over multiple dimensions +------------------------------------ + +We now consider a more complex case. Instead of loading 2 files across different time steps we now load 15 such files. +Each of these files covers a month's time step, however, the ``surface_altitude`` coordinate changes only once per year. +The files span 3 years so there are 3 different ``surface_altitude`` coordinates. + + >>> filename = iris.sample_data_path('time_varying_hybrid_height', '*.pp') + >>> cubes = iris.load(filename, constraints="x_wind") + >>> print(cubes) + 0: x_wind / (m s-1) (time: 2; model_level_number: 5; latitude: 144; longitude: 192) + 1: x_wind / (m s-1) (time: 12; model_level_number: 5; latitude: 144; longitude: 192) + 2: x_wind / (m s-1) (model_level_number: 5; latitude: 144; longitude: 192) + +When :func:`iris.load` attempts to merge these cubes, it creates a cube for every unique ``surface_altitude`` coordinate. +Note that since there is only one time point associated with the last cube, the "time" coordinate has not been promoted +to a dimension. The ``surface_altitude`` in each of the above cubes is 2D, however, since some of these coordinates +already have a time dimension, it is not possible to use :func:`~iris.util.new_axis` as above to promote +``surface_altitude`` as we have done above. + +In order to fully control the merge process we instead use :func:`iris.load_raw`: + + >>> raw_cubes = iris.load_raw(filename, constraints="x_wind") + >>> print(raw_cubes) + 0: x_wind / (m s-1) (latitude: 144; longitude: 192) + 1: x_wind / (m s-1) (latitude: 144; longitude: 192) + ... + 73: x_wind / (m s-1) (latitude: 144; longitude: 192) + 74: x_wind / (m s-1) (latitude: 144; longitude: 192) + +The raw cubes also separate cubes along the ``model_level_number`` dimension. In this instance, we will need to +merge/concatenate along two different dimensions. Specifically, we can merge by promoting the ``model_level_number`` to +a dimension, since ``surface_altitude`` does not vary along this dimension, and we can concatenate along the ``time`` +dimension as before. We expand the ``time`` dimension first, as before: + + >>> processed_raw_cubes = CubeList( + ... [new_axis(cube, scalar_coord="time", expand_extras=["surface_altitude", "forecast_period"]) for cube in raw_cubes] + ... ) + >>> print(processed_raw_cubes) + 0: x_wind / (m s-1) (time: 1; latitude: 144; longitude: 192) + 1: x_wind / (m s-1) (time: 1; latitude: 144; longitude: 192) + ... + 73: x_wind / (m s-1) (time: 1; latitude: 144; longitude: 192) + 74: x_wind / (m s-1) (time: 1; latitude: 144; longitude: 192) + +Then we merge, promoting the different ``model_level_number`` scalar coordinates to a dimension coordinate. +Note, however, that merging these cubes does *not* affect the ``time`` dimension, since merging only +applies to scalar coordinates, not dimension coordinates of length 1. + + >>> merged_cubes = processed_raw_cubes.merge() + >>> print(merged_cubes) + 0: x_wind / (m s-1) (model_level_number: 5; time: 1; latitude: 144; longitude: 192) + 1: x_wind / (m s-1) (model_level_number: 5; time: 1; latitude: 144; longitude: 192) + ... + 13: x_wind / (m s-1) (model_level_number: 5; time: 1; latitude: 144; longitude: 192) + 14: x_wind / (m s-1) (model_level_number: 5; time: 1; latitude: 144; longitude: 192) + +Once merged, we can now concatenate all these cubes into a single result cube, which is what we wanted: + + >>> result = merged_cubes.concatenate_cube() + >>> print(result) + x_wind / (m s-1) (model_level_number: 5; time: 15; latitude: 144; longitude: 192) + Dimension coordinates: + model_level_number x - - - + time - x - - + latitude - - x - + longitude - - - x + Auxiliary coordinates: + level_height x - - - + sigma x - - - + forecast_period - x - - + surface_altitude - x x x + Derived coordinates: + altitude x x x x + Scalar coordinates: + forecast_reference_time 2006-01-01 00:00:00 + Cell methods: + 0 time: mean (interval: 1 hour) + Attributes: + STASH m01s00i002 + source 'Data from Met Office Unified Model' + um_version '12.1' + +See Also +-------- +* :data:`iris.LOAD_POLICY` can be controlled to apply similar operations + within the load functions, i.e. :func:`~iris.load`, :func:`~iris.load_cube` and + :func:`~iris.load_cubes`. diff --git a/docs/src/further_topics/index.rst b/docs/src/further_topics/index.rst index 73ce3d55e7..67cadc4612 100644 --- a/docs/src/further_topics/index.rst +++ b/docs/src/further_topics/index.rst @@ -18,4 +18,5 @@ Extra information on specific technical issues. netcdf_io dask_best_practices/index ugrid/index - which_regridder_to_use \ No newline at end of file + which_regridder_to_use + controlling_merge \ No newline at end of file diff --git a/docs/src/further_topics/metadata.rst b/docs/src/further_topics/metadata.rst index 6d32b10b7a..f66f253a90 100644 --- a/docs/src/further_topics/metadata.rst +++ b/docs/src/further_topics/metadata.rst @@ -403,10 +403,10 @@ instances. Normally, this would cause issues. For example, >>> simply = {"one": np.int32(1), "two": np.array([1.0, 2.0])} >>> simply - {'one': 1, 'two': array([1., 2.])} + {'one': np.int32(1), 'two': array([1., 2.])} >>> fruity = {"one": np.int32(1), "two": np.array([1.0, 2.0])} >>> fruity - {'one': 1, 'two': array([1., 2.])} + {'one': np.int32(1), 'two': array([1., 2.])} >>> simply == fruity Traceback (most recent call last): ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() @@ -418,9 +418,9 @@ However, metadata class equality is rich enough to handle this eventuality, >>> metadata1 = cube.metadata._replace(attributes=simply) >>> metadata2 = cube.metadata._replace(attributes=fruity) >>> metadata1 - CubeMetadata(standard_name='air_temperature', long_name=None, var_name='air_temperature', units=Unit('K'), attributes={'one': 1, 'two': array([1., 2.])}, cell_methods=(CellMethod(method='mean', coord_names=('time',), intervals=('6 hour',), comments=()),)) + CubeMetadata(standard_name='air_temperature', long_name=None, var_name='air_temperature', units=Unit('K'), attributes={'one': np.int32(1), 'two': array([1., 2.])}, cell_methods=(CellMethod(method='mean', coord_names=('time',), intervals=('6 hour',), comments=()),)) >>> metadata2 - CubeMetadata(standard_name='air_temperature', long_name=None, var_name='air_temperature', units=Unit('K'), attributes={'one': 1, 'two': array([1., 2.])}, cell_methods=(CellMethod(method='mean', coord_names=('time',), intervals=('6 hour',), comments=()),)) + CubeMetadata(standard_name='air_temperature', long_name=None, var_name='air_temperature', units=Unit('K'), attributes={'one': np.int32(1), 'two': array([1., 2.])}, cell_methods=(CellMethod(method='mean', coord_names=('time',), intervals=('6 hour',), comments=()),)) .. doctest:: richer-metadata @@ -430,10 +430,10 @@ However, metadata class equality is rich enough to handle this eventuality, .. doctest:: richer-metadata >>> metadata1 - CubeMetadata(standard_name='air_temperature', long_name=None, var_name='air_temperature', units=Unit('K'), attributes={'one': 1, 'two': array([1., 2.])}, cell_methods=(CellMethod(method='mean', coord_names=('time',), intervals=('6 hour',), comments=()),)) + CubeMetadata(standard_name='air_temperature', long_name=None, var_name='air_temperature', units=Unit('K'), attributes={'one': np.int32(1), 'two': array([1., 2.])}, cell_methods=(CellMethod(method='mean', coord_names=('time',), intervals=('6 hour',), comments=()),)) >>> metadata2 = cube.metadata._replace(attributes={"one": np.int32(1), "two": np.array([1000.0, 2000.0])}) >>> metadata2 - CubeMetadata(standard_name='air_temperature', long_name=None, var_name='air_temperature', units=Unit('K'), attributes={'one': 1, 'two': array([1000., 2000.])}, cell_methods=(CellMethod(method='mean', coord_names=('time',), intervals=('6 hour',), comments=()),)) + CubeMetadata(standard_name='air_temperature', long_name=None, var_name='air_temperature', units=Unit('K'), attributes={'one': np.int32(1), 'two': array([1000., 2000.])}, cell_methods=(CellMethod(method='mean', coord_names=('time',), intervals=('6 hour',), comments=()),)) >>> metadata1 == metadata2 False diff --git a/docs/src/further_topics/ugrid/operations.rst b/docs/src/further_topics/ugrid/operations.rst index 97dfaaa5b1..14e746352f 100644 --- a/docs/src/further_topics/ugrid/operations.rst +++ b/docs/src/further_topics/ugrid/operations.rst @@ -500,7 +500,7 @@ GeoVista :external+geovista:doc:`generated/gallery/index`. Attributes: NCO 'netCDF Operators version 4.7.5 (Homepage = http://nco.sf.net, Code = h ...' history 'Mon Apr 12 01:44:41 2021: ncap2 -s synthetic=float(synthetic) mesh_C4_synthetic.nc ...' - nco_openmp_thread_number 1 + nco_openmp_thread_number np.int32(1) # Convert our mesh+data to a PolyData object. >>> face_polydata = cube_to_polydata(sample_mesh_cube) @@ -600,7 +600,7 @@ below: Attributes: NCO 'netCDF Operators version 4.7.5 (Homepage = http://nco.sf.net, Code = h ...' history 'Mon Apr 12 01:44:41 2021: ncap2 -s synthetic=float(synthetic) mesh_C4_synthetic.nc ...' - nco_openmp_thread_number 1 + nco_openmp_thread_number np.int32(1) >>> regional_cube = extract_unstructured_region( ... cube=sample_mesh_cube, @@ -619,7 +619,7 @@ below: Attributes: NCO 'netCDF Operators version 4.7.5 (Homepage = http://nco.sf.net, Code = h ...' history 'Mon Apr 12 01:44:41 2021: ncap2 -s synthetic=float(synthetic) mesh_C4_synthetic.nc ...' - nco_openmp_thread_number 1 + nco_openmp_thread_number np.int32(1) Regridding diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 0a016ba82b..cdb29b5c57 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -24,13 +24,31 @@ This document explains the changes made to Iris for this release 📢 Announcements ================ -#. N/A +#. Iris is now compliant with NumPy v2. This may affect your scripts. + :ref:`See the full What's New entry for more details `. ✨ Features =========== -#. N/A +#. `@jrackham-mo`_ added :meth:`~iris.io.format_picker.FormatAgent.copy` and + equality methods to :class:`iris.io.format_picker.FormatAgent`, as requested + in :issue:`6108`, actioned in :pull:`6119`. + +#. `@ukmo-ccbunney`_ added ``colorbar`` keyword to allow optional creation of + the colorbar in the following quickplot methods: + + * :meth:`iris.quickplot.contourf` + + * :meth:`iris.quickplot.pcolor` + + * :meth:`iris.quickplot.pcolormesh` + + Requested in :issue:`5970`, actioned in :pull:`6169`. + +#. `@pp-mo`_ and `@stephenworsley`_ added support for hybrid coordinates whose + references are split across multiple input fields, and :meth:`~iris.LOAD_POLICY` to + control it, as requested in :issue:`5369`, actioned in :pull:`6168`. 🐛 Bugs Fixed @@ -42,6 +60,13 @@ This document explains the changes made to Iris for this release #. `@bouweandela`_ made further updates to the ``chunktype`` of Dask arrays, so it corresponds better with the array content. (:pull:`5989`) +#. `@ukmo-ccbunney`_ improved error handling for malformed `cell_method` + attribute. Also made cell_method string parsing more lenient w.r.t. + whitespace. (:pull:`6083`) + +#. `@ukmo-ccbunney`_ fixed comparison of cubes with array type attributes; + fixes :issue:`6027` (:pull:`6181`) + 💣 Incompatible Changes ======================= @@ -67,7 +92,7 @@ This document explains the changes made to Iris for this release may happen when there are very many or large auxiliary coordinates, derived coordinates, cell measures, or ancillary variables to be checked that span the concatenation axis. This issue can be avoided by disabling the - problematic check. (:pull:`5926`) + problematic check. (:pull:`5926` and :pull:`6187`) 🔥 Deprecations =============== @@ -78,14 +103,21 @@ This document explains the changes made to Iris for this release 🔗 Dependencies =============== -#. N/A +.. _numpy2: + +#. `@trexfeathers`_ adapted the Iris codebase to work with NumPy v2. The + `NumPy v2 full release notes`_ have the exhaustive details. Notable + changes that may affect your Iris scripts are below. (:pull:`6035`) + + * `NumPy v2 changed data type promotion`_ + + * `NumPy v2 changed scalar printing`_ 📚 Documentation ================ -#. N/A - +#. `@bouweandela`_ added type hints for :class:`~iris.cube.Cube`. (:pull:`6037`) 💼 Internal =========== @@ -94,13 +126,24 @@ This document explains the changes made to Iris for this release in Iris v3.10.0, :pull:`5948`) to use the same statistical repeat strategy as timing benchmarks. (:pull:`5981`) +#. `@trexfeathers`_ adapted Iris to work with Cartopy v0.24. (:pull:`6171`, + :pull:`6172`) + +#. `@trexfeathers`_ refactored spanning checks in :mod:`iris.fileformats.cf` + to reduce code duplication. (:pull:`6196`) + .. comment Whatsnew author names (@github name) in alphabetical order. Note that, core dev names are automatically included by the common_links.inc: - +.. _@jrackham-mo: https://github.com/jrackham-mo .. comment Whatsnew resources in alphabetical order: + +.. _cartopy#2390: https://github.com/SciTools/cartopy/issues/2390 +.. _NumPy v2 changed data type promotion: https://numpy.org/doc/stable/numpy_2_0_migration_guide.html#changes-to-numpy-data-type-promotion +.. _NumPy v2 changed scalar printing: https://numpy.org/doc/stable/release/2.0.0-notes.html#representation-of-numpy-scalars-changed +.. _NumPy v2 full release notes: https://numpy.org/doc/stable/release/2.0.0-notes.html diff --git a/lib/iris/__init__.py b/lib/iris/__init__.py index a06e36a2e2..d4454efe89 100644 --- a/lib/iris/__init__.py +++ b/lib/iris/__init__.py @@ -94,7 +94,7 @@ def callback(cube, field, filename): import itertools import os.path import threading -from typing import Callable, Literal +from typing import Callable, Literal, Mapping import iris._constraints import iris.config @@ -121,6 +121,8 @@ def callback(cube, field, filename): "FUTURE", "Future", "IrisDeprecation", + "LOAD_POLICY", + "LoadPolicy", "NameConstraint", "load", "load_cube", @@ -292,8 +294,17 @@ def _generate_cubes(uris, callback, constraints): def _load_collection(uris, constraints=None, callback=None): from iris.cube import _CubeFilterCollection + from iris.fileformats.rules import _MULTIREF_DETECTION try: + # This routine is called once per iris load operation. + # Control of the "multiple refs" handling is implicit in this routine + # NOTE: detection of multiple reference fields, and it's enabling of post-load + # concatenation, is triggered **per-load, not per-cube** + # This behaves unexpectefly for "iris.load_cubes" : a post-concatenation is + # triggered for all cubes or none, not per-cube (i.e. per constraint). + _MULTIREF_DETECTION.found_multiple_refs = False + cubes = _generate_cubes(uris, callback, constraints) result = _CubeFilterCollection.from_cubes(cubes, constraints) except EOFError as e: @@ -303,6 +314,326 @@ def _load_collection(uris, constraints=None, callback=None): return result +class LoadPolicy(threading.local): + """A container for loading strategy options. + + Controls merge/concatenate usage during loading. + + Also controls the detection and handling of cases where a hybrid coordinate + uses multiple reference fields : for example, a UM file which contains a series of + fields describing time-varying orography. + + Options can be set directly, or via :meth:`~iris.LoadPolicy.set`, or changed for + the scope of a code block with :meth:`~iris.LoadPolicy.context`. + + .. note :: + + The default behaviour will "fix" loading for cases like the one just described. + However this is not strictly backwards-compatible. If this causes problems, + you can force identical loading behaviour to earlier Iris versions with + ``LOAD_POLICY.set("legacy")`` or equivalent. + + .. testsetup:: + + from iris import LOAD_POLICY + + Notes + ----- + The individual configurable options are : + + * ``support_multiple_references`` = True / False + When enabled, the presence of multiple aux-factory reference cubes, which merge + to define a extra dimension, will add that dimension to the loaded cubes. + This is essential for correct support of time-dependent hybrid coordinates (i.e. + aux factories) when loading from fields-based data (e.g. PP or GRIB). + For example (notably) time-dependent orography in UM data on hybrid-heights. + + In addition, when such multiple references are detected, an extra concatenate + step is added to the 'merge_concat_sequence' (see below), if none is already + configured there. + + * ``merge_concat_sequence`` = "m" / "c" / "cm" / "mc" + Specifies whether to merge, or concatenate, or both in either order. + This is the "combine" operation which is applied to loaded data. + + * ``repeat_until_unchanged`` = True / False + When enabled, the configured "combine" operation will be repeated until the + result is stable (no more cubes are combined). + + Several common sets of options are provided in :data:`~iris.LOAD_POLICY.SETTINGS` : + + * ``"legacy"`` + Produces results identical to Iris versions < 3.11, i.e. before the varying + hybrid references were supported. + + * ``"default"`` + As "legacy" except that ``support_multiple_references=True``. This differs + from "legacy" only when multiple mergeable reference fields are encountered, + in which case incoming cubes are extended into the extra dimension, and a + concatenate step is added. + + * ``"recommended"`` + Enables multiple reference handling, and applies a merge step followed by + a concatenate step. + + * ``"comprehensive"`` + Like "recommended", but will also *repeat* the merge+concatenate steps until no + further change is produced. + + .. note :: + + The 'comprehensive' policy makes a maximum effort to reduce the number of + cubes to a minimum. However, it still cannot combine cubes with a mixture + of matching dimension and scalar coordinates. This may be supported at + some later date, but for now is not possible without specific user actions. + + .. Note :: + + See also : :ref:`controlling_merge`. + + Examples + -------- + >>> LOAD_POLICY.set("legacy") + >>> print(LOAD_POLICY) + LoadPolicy(support_multiple_references=False, merge_concat_sequence='m', repeat_until_unchanged=False) + >>> LOAD_POLICY.support_multiple_references = True + >>> print(LOAD_POLICY) + LoadPolicy(support_multiple_references=True, merge_concat_sequence='m', repeat_until_unchanged=False) + >>> LOAD_POLICY.set(merge_concat_sequence="cm") + >>> print(LOAD_POLICY) + LoadPolicy(support_multiple_references=True, merge_concat_sequence='cm', repeat_until_unchanged=False) + >>> with LOAD_POLICY.context("comprehensive"): + ... print(LOAD_POLICY) + LoadPolicy(support_multiple_references=True, merge_concat_sequence='mc', repeat_until_unchanged=True) + >>> print(LOAD_POLICY) + LoadPolicy(support_multiple_references=True, merge_concat_sequence='cm', repeat_until_unchanged=False) + + """ + + # Useful constants + OPTION_KEYS = ( + "support_multiple_references", + "merge_concat_sequence", + "repeat_until_unchanged", + ) + _OPTIONS_ALLOWED_VALUES = { + "support_multiple_references": (False, True), + "merge_concat_sequence": ("", "m", "c", "mc", "cm"), + "repeat_until_unchanged": (False, True), + } + SETTINGS = { + "legacy": dict( + support_multiple_references=False, + merge_concat_sequence="m", + repeat_until_unchanged=False, + ), + "default": dict( + support_multiple_references=True, + merge_concat_sequence="m", + repeat_until_unchanged=False, + ), + "recommended": dict( + support_multiple_references=True, + merge_concat_sequence="mc", + repeat_until_unchanged=False, + ), + "comprehensive": dict( + support_multiple_references=True, + merge_concat_sequence="mc", + repeat_until_unchanged=True, + ), + } + + def __init__(self, options: str | dict | None = None, **kwargs): + """Create loading strategy control object.""" + self.set("default") + self.set(options, **kwargs) + + def __setattr__(self, key, value): + if key not in self.OPTION_KEYS: + raise KeyError(f"LoadPolicy object has no property '{key}'.") + + allowed_values = self._OPTIONS_ALLOWED_VALUES[key] + if value not in allowed_values: + msg = ( + f"{value!r} is not a valid setting for LoadPolicy.{key} : " + f"must be one of '{allowed_values}'." + ) + raise ValueError(msg) + + self.__dict__[key] = value + + def set(self, options: str | dict | None = None, **kwargs): + """Set new options. + + Parameters + ---------- + * options : str or dict, optional + A dictionary of options values, or the name of one of the + :data:`~iris.LoadPolicy.SETTINGS` standard option sets, + e.g. "legacy" or "comprehensive". + * kwargs : dict + Individual option settings, from :data:`~iris.LoadPolicy.OPTION_KEYS`. + + Note + ---- + Keyword arguments are applied after the 'options' arg, and + so will take precedence. + + """ + if options is None: + options = {} + elif isinstance(options, str) and options in self.SETTINGS: + options = self.SETTINGS[options] + elif not isinstance(options, Mapping): + msg = ( + f"Invalid arg options={options!r} : " + f"must be a dict, or one of {tuple(self.SETTINGS.keys())}" + ) + raise TypeError(msg) + + # Override any options with keywords + options.update(**kwargs) + bad_keys = [key for key in options if key not in self.OPTION_KEYS] + if bad_keys: + msg = f"Unknown options {bad_keys} : valid options are {self.OPTION_KEYS}." + raise ValueError(msg) + + # Implement all options by changing own content. + for key, value in options.items(): + setattr(self, key, value) + + def settings(self): + """Return an options dict containing the current settings.""" + return {key: getattr(self, key) for key in self.OPTION_KEYS} + + def __repr__(self): + msg = f"{self.__class__.__name__}(" + msg += ", ".join(f"{key}={getattr(self, key)!r}" for key in self.OPTION_KEYS) + msg += ")" + return msg + + @contextlib.contextmanager + def context(self, settings=None, **kwargs): + """Return a context manager applying given options. + + Parameters + ---------- + settings : str or dict + Options dictionary or name, as for :meth:`~LoadPolicy.set`. + kwargs : dict + Option values, as for :meth:`~LoadPolicy.set`. + + Examples + -------- + .. testsetup:: + + import iris + from iris import LOAD_POLICY, sample_data_path + + >>> path = sample_data_path("time_varying_hybrid_height", "*.pp") + >>> with LOAD_POLICY.context("legacy"): + ... cubes = iris.load(path, "x_wind") + >>> print(cubes) + 0: x_wind / (m s-1) (time: 2; model_level_number: 5; latitude: 144; longitude: 192) + 1: x_wind / (m s-1) (time: 12; model_level_number: 5; latitude: 144; longitude: 192) + 2: x_wind / (m s-1) (model_level_number: 5; latitude: 144; longitude: 192) + >>> + >>> with LOAD_POLICY.context("recommended"): + ... cubes = iris.load(path, "x_wind") + >>> print(cubes) + 0: x_wind / (m s-1) (model_level_number: 5; time: 15; latitude: 144; longitude: 192) + """ + # Save the current state + saved_settings = self.settings() + + # Apply the new options and execute the context + try: + self.set(settings, **kwargs) + yield + finally: + # Re-establish the former state + self.set(saved_settings) + + +#: A control object containing the current file loading options. +LOAD_POLICY = LoadPolicy() + + +def _combine_cubes(cubes, options, merge_require_unique): + """Combine cubes as for load, according to "loading policy" options. + + Applies :meth:`~iris.cube.CubeList.merge`/:meth:`~iris.cube.CubeList.concatenate` + steps to the given cubes, as determined by the 'settings'. + + Parameters + ---------- + cubes : list of :class:`~iris.cube.Cube` + A list of cubes to combine. + options : dict + Settings, as described for :meth:`iris.LOAD_POLICY.set`. + Defaults to current :meth:`iris.LOAD_POLICY.settings`. + merge_require_unique : bool + Value for the 'unique' keyword in any merge operations. + + Returns + ------- + :class:`~iris.cube.CubeList` + + .. Note:: + The ``support_multiple_references`` keyword/property has no effect on the + :func:`_combine_cubes` operation : it only takes effect during a load operation. + + Notes + ----- + TODO: make this public API in future. + At that point, change the API to support (options=None, **kwargs) + add testing of + those modes (notably arg type = None / str / dict). + + """ + from iris.cube import CubeList + + if not isinstance(cubes, CubeList): + cubes = CubeList(cubes) + + while True: + n_original_cubes = len(cubes) + sequence = options["merge_concat_sequence"] + + if sequence[0] == "c": + # concat if it comes first + cubes = cubes.concatenate() + if "m" in sequence: + # merge if requested + cubes = cubes.merge(unique=merge_require_unique) + if sequence[-1] == "c": + # concat if it comes last + cubes = cubes.concatenate() + + # Repeat if requested, *and* this step reduced the number of cubes + if not options["repeat_until_unchanged"] or len(cubes) >= n_original_cubes: + break + + return cubes + + +def _combine_load_cubes(cubes, merge_require_unique=False): + # A special version to call _combine_cubes while also implementing the + # _MULTIREF_DETECTION behaviour + options = LOAD_POLICY.settings() + if ( + options["support_multiple_references"] + and "c" not in options["merge_concat_sequence"] + ): + # Add a concatenate to implement the "multiref triggers concatenate" mechanism + from iris.fileformats.rules import _MULTIREF_DETECTION + + if _MULTIREF_DETECTION.found_multiple_refs: + options["merge_concat_sequence"] += "c" + + return _combine_cubes(cubes, options, merge_require_unique=merge_require_unique) + + def load(uris, constraints=None, callback=None): """Load any number of Cubes for each constraint. @@ -327,7 +658,8 @@ def load(uris, constraints=None, callback=None): were random. """ - return _load_collection(uris, constraints, callback).merged().cubes() + cubes = _load_collection(uris, constraints, callback).combined().cubes() + return cubes def load_cube(uris, constraint=None, callback=None): @@ -355,9 +687,11 @@ def load_cube(uris, constraint=None, callback=None): if len(constraints) != 1: raise ValueError("only a single constraint is allowed") - cubes = _load_collection(uris, constraints, callback).cubes() + cubes = _load_collection(uris, constraints, callback).combined(unique=False).cubes() try: + # NOTE: this call currently retained to preserve the legacy exceptions + # TODO: replace with simple testing to duplicate the relevant error cases cube = cubes.merge_cube() except iris.exceptions.MergeError as e: raise iris.exceptions.ConstraintMismatchError(str(e)) @@ -392,7 +726,7 @@ def load_cubes(uris, constraints=None, callback=None): """ # Merge the incoming cubes - collection = _load_collection(uris, constraints, callback).merged() + collection = _load_collection(uris, constraints, callback).combined() # Make sure we have exactly one merged cube per constraint bad_pairs = [pair for pair in collection.pairs if len(pair) != 1] diff --git a/lib/iris/_concatenate.py b/lib/iris/_concatenate.py index 90f2438742..ac9e699790 100644 --- a/lib/iris/_concatenate.py +++ b/lib/iris/_concatenate.py @@ -310,7 +310,7 @@ def _hash_ndarray(a: np.ndarray) -> np.ndarray: # Hash the bytes representing the array data. hash.update(b"data=") - if isinstance(a, np.ma.MaskedArray): + if np.ma.is_masked(a): # Hash only the unmasked data hash.update(a.compressed().tobytes()) # Hash the mask @@ -690,9 +690,9 @@ def __init__(self, cube: iris.cube.Cube) -> None: # # Collate the dimension coordinate metadata. # - for coord in self.dim_coords: - dims = cube.coord_dims(coord) - self.dim_metadata.append(_CoordMetaData(coord, dims)) + for dim_coord in self.dim_coords: + dims = cube.coord_dims(dim_coord) + self.dim_metadata.append(_CoordMetaData(dim_coord, dims)) self.dim_mapping.append(dims[0]) # @@ -709,13 +709,13 @@ def key_func(coord): cube.coord_dims(coord), ) - for coord in sorted(cube.aux_coords, key=key_func): - dims = cube.coord_dims(coord) + for aux_coord in sorted(cube.aux_coords, key=key_func): + dims = cube.coord_dims(aux_coord) if dims: - self.aux_metadata.append(_CoordMetaData(coord, dims)) - self.aux_coords_and_dims.append(_CoordAndDims(coord, tuple(dims))) + self.aux_metadata.append(_CoordMetaData(aux_coord, dims)) + self.aux_coords_and_dims.append(_CoordAndDims(aux_coord, tuple(dims))) else: - self.scalar_coords.append(coord) + self.scalar_coords.append(aux_coord) def meta_key_func(dm): return (dm.metadata, dm.cube_dims(cube)) diff --git a/lib/iris/_constraints.py b/lib/iris/_constraints.py index b8f4665b46..765a975651 100644 --- a/lib/iris/_constraints.py +++ b/lib/iris/_constraints.py @@ -491,7 +491,7 @@ def list_of_constraints(constraints): return [as_constraint(constraint) for constraint in constraints] -def as_constraint(thing): +def as_constraint(thing: Constraint | str | None) -> Constraint: """Cast an object into a cube constraint where possible. Cast an object into a cube constraint where possible, otherwise diff --git a/lib/iris/_merge.py b/lib/iris/_merge.py index 2d8beb6f27..5e00d9b2f0 100644 --- a/lib/iris/_merge.py +++ b/lib/iris/_merge.py @@ -388,7 +388,9 @@ def _defn_msgs(self, other_defn): diff_attrs = [ repr(key[1]) for key in attrs_1 - if np.all(attrs_1[key] != attrs_2[key]) + if not np.array_equal( + np.array(attrs_1[key], ndmin=1), np.array(attrs_2[key], ndmin=1) + ) ] diff_attrs = ", ".join(sorted(diff_attrs)) msgs.append( diff --git a/lib/iris/_representation/cube_summary.py b/lib/iris/_representation/cube_summary.py index a28bfc549a..20d93f1acf 100644 --- a/lib/iris/_representation/cube_summary.py +++ b/lib/iris/_representation/cube_summary.py @@ -47,6 +47,8 @@ def __init__(self, cube, name_padding=35): def string_repr(text, quote_strings=False, clip_strings=False): """Produce a one-line printable form of a text string.""" + # Convert any np.str_ instances to plain strings. + text = str(text) force_quoted = re.findall("[\n\t]", text) or quote_strings if force_quoted: # Replace the string with its repr (including quotes). diff --git a/lib/iris/analysis/__init__.py b/lib/iris/analysis/__init__.py index ca3b820cb3..2c890ef8cc 100644 --- a/lib/iris/analysis/__init__.py +++ b/lib/iris/analysis/__init__.py @@ -35,13 +35,13 @@ from __future__ import annotations -from collections.abc import Iterable +from collections.abc import Iterable, Sequence import functools from functools import wraps from inspect import getfullargspec import itertools from numbers import Number -from typing import Optional, Union +from typing import Optional, Protocol, Union import warnings from cf_units import Unit @@ -56,7 +56,7 @@ from iris.analysis._interpolation import EXTRAPOLATION_MODES, RectilinearInterpolator from iris.analysis._regrid import CurvilinearRegridder, RectilinearRegridder import iris.coords -from iris.coords import _DimensionalMetadata +from iris.coords import AuxCoord, DimCoord, _DimensionalMetadata from iris.exceptions import LazyAggregatorError import iris.util @@ -2289,8 +2289,8 @@ class _Groupby: def __init__( self, - groupby_coords: list[iris.coords.Coord], - shared_coords: Optional[list[tuple[iris.coords.Coord, int]]] = None, + groupby_coords: Iterable[AuxCoord | DimCoord], + shared_coords: Optional[Iterable[tuple[AuxCoord | DimCoord, int]]] = None, climatological: bool = False, ) -> None: """Determine the group slices over the group-by coordinates. @@ -2311,9 +2311,9 @@ def __init__( """ #: Group-by and shared coordinates that have been grouped. - self.coords: list[iris.coords.Coord] = [] - self._groupby_coords: list[iris.coords.Coord] = [] - self._shared_coords: list[tuple[iris.coords.Coord, int]] = [] + self.coords: list[AuxCoord | DimCoord] = [] + self._groupby_coords: list[AuxCoord | DimCoord] = [] + self._shared_coords: list[tuple[AuxCoord | DimCoord, int]] = [] self._groupby_indices: list[tuple[int, ...]] = [] self._stop = None # Ensure group-by coordinates are iterable. @@ -2339,10 +2339,10 @@ def __init__( # Stores mapping from original cube coords to new ones, as metadata may # not match self.coord_replacement_mapping: list[ - tuple[iris.coords.Coord, iris.coords.Coord] + tuple[AuxCoord | DimCoord, AuxCoord | DimCoord] ] = [] - def _add_groupby_coord(self, coord: iris.coords.Coord) -> None: + def _add_groupby_coord(self, coord: AuxCoord | DimCoord) -> None: if coord.ndim != 1: raise iris.exceptions.CoordinateMultiDimError(coord) if self._stop is None: @@ -2351,7 +2351,7 @@ def _add_groupby_coord(self, coord: iris.coords.Coord) -> None: raise ValueError("Group-by coordinates have different lengths.") self._groupby_coords.append(coord) - def _add_shared_coord(self, coord: iris.coords.Coord, dim: int) -> None: + def _add_shared_coord(self, coord: AuxCoord | DimCoord, dim: int) -> None: if coord.shape[dim] != self._stop and self._stop is not None: raise ValueError("Shared coordinates have different lengths.") self._shared_coords.append((coord, dim)) @@ -2584,6 +2584,37 @@ def clear_phenomenon_identity(cube): ############################################################################### +class Interpolator(Protocol): + def __call__( # noqa: E704 # ruff formatting conflicts with flake8 + self, + sample_points: Sequence[np.typing.ArrayLike], + collapse_scalar: bool, + ) -> iris.cube.Cube: ... + + +class InterpolationScheme(Protocol): + def interpolator( # noqa: E704 # ruff formatting conflicts with flake8 + self, + cube: iris.cube.Cube, + coords: AuxCoord | DimCoord | str, + ) -> Interpolator: ... + + +class Regridder(Protocol): + def __call__( # noqa: E704 # ruff formatting conflicts with flake8 + self, + src: iris.cube.Cube, + ) -> iris.cube.Cube: ... + + +class RegriddingScheme(Protocol): + def regridder( # noqa: E704 # ruff formatting conflicts with flake8 + self, + src_grid: iris.cube.Cube, + target_grid: iris.cube.Cube, + ) -> Regridder: ... + + class Linear: """Describes the linear interpolation and regridding scheme. diff --git a/lib/iris/analysis/_regrid.py b/lib/iris/analysis/_regrid.py index 442f208cae..fd56eb04a1 100644 --- a/lib/iris/analysis/_regrid.py +++ b/lib/iris/analysis/_regrid.py @@ -156,22 +156,30 @@ def _src_align_and_flatten(coord): # # Wrap modular values (e.g. longitudes) if required. - modulus = sx.units.modulus + _modulus = sx.units.modulus + # Convert to NumPy scalar to enable cast checking. + modulus = np.min_scalar_type(_modulus).type(_modulus) + + def _cast_sx_points(sx_points_: np.ndarray): + """Ensure modulus arithmetic will not raise a TypeError.""" + if not np.can_cast(modulus, sx_points_.dtype): + new_type = np.promote_types(sx_points_.dtype, modulus.dtype) + result = sx_points_.astype(new_type, casting="safe") + else: + result = sx_points_ + return result + if modulus is not None: # Match the source cube x coordinate range to the target grid # cube x coordinate range. min_sx, min_tx = np.min(sx.points), np.min(tx.points) if min_sx < 0 and min_tx >= 0: indices = np.where(sx_points < 0) - # Ensure += doesn't raise a TypeError - if not np.can_cast(modulus, sx_points.dtype): - sx_points = sx_points.astype(type(modulus), casting="safe") + sx_points = _cast_sx_points(sx_points) sx_points[indices] += modulus elif min_sx >= 0 and min_tx < 0: indices = np.where(sx_points > (modulus / 2)) - # Ensure -= doesn't raise a TypeError - if not np.can_cast(modulus, sx_points.dtype): - sx_points = sx_points.astype(type(modulus), casting="safe") + sx_points = _cast_sx_points(sx_points) sx_points[indices] -= modulus # Create target grid cube x and y cell boundaries. diff --git a/lib/iris/analysis/cartography.py b/lib/iris/analysis/cartography.py index 2e7c3a3677..d3967dfef3 100644 --- a/lib/iris/analysis/cartography.py +++ b/lib/iris/analysis/cartography.py @@ -1128,7 +1128,7 @@ def rotate_winds(u_cube, v_cube, target_cs): Returns ------- - (u', v') tuple of :class:`iris.cube.Cube` + tuple of :class:`iris.cube.Cube` A (u', v') tuple of :class:`iris.cube.Cube` instances that are the u and v components in the requested target coordinate system. The units are the same as the inputs. diff --git a/lib/iris/analysis/maths.py b/lib/iris/analysis/maths.py index bd20b26019..62adf7b638 100644 --- a/lib/iris/analysis/maths.py +++ b/lib/iris/analysis/maths.py @@ -867,7 +867,7 @@ def _binary_op_common( if iris._lazy_data.is_lazy_data(other): rhs = other else: - rhs = np.asanyarray(other) + rhs = np.asanyarray(other, dtype=new_dtype) def unary_func(lhs): data = operation_function(lhs, rhs) diff --git a/lib/iris/common/metadata.py b/lib/iris/common/metadata.py index 8705c79816..bfbc75507e 100644 --- a/lib/iris/common/metadata.py +++ b/lib/iris/common/metadata.py @@ -4,17 +4,23 @@ # See LICENSE in the root of the repository for full licensing details. """Provides the infrastructure to support the common metadata API.""" +from __future__ import annotations + from abc import ABCMeta from collections import namedtuple from collections.abc import Iterable, Mapping from copy import deepcopy from functools import lru_cache, wraps import re +from typing import TYPE_CHECKING, Any +import cf_units import numpy as np import numpy.ma as ma from xxhash import xxh64_hexdigest +if TYPE_CHECKING: + from iris.coords import CellMethod from ..config import get_logger from ._split_attribute_dicts import adjust_for_split_attribute_dictionaries from .lenient import _LENIENT @@ -153,6 +159,12 @@ class BaseMetadata(metaclass=_NamedTupleMeta): __slots__ = () + standard_name: str | None + long_name: str | None + var_name: str | None + units: cf_units.Unit + attributes: Any + @lenient_service def __eq__(self, other): """Determine whether the associated metadata members are equivalent. @@ -683,7 +695,7 @@ def from_metadata(cls, other): result = cls(**kwargs) return result - def name(self, default=None, token=False): + def name(self, default: str | None = None, token: bool = False) -> str: """Return a string name representing the identity of the metadata. First it tries standard name, then it tries the long name, then @@ -692,10 +704,10 @@ def name(self, default=None, token=False): Parameters ---------- - default : optional + default : The fall-back string representing the default name. Defaults to the string 'unknown'. - token : bool, default=False + token : If True, ensures that the name returned satisfies the criteria for the characters required by a valid NetCDF name. If it is not possible to return a valid name, then a ValueError exception is @@ -1039,6 +1051,8 @@ class CubeMetadata(BaseMetadata): _members = "cell_methods" + cell_methods: tuple[CellMethod, ...] + __slots__ = () @wraps(BaseMetadata.__eq__, assigned=("__doc__",), updated=()) diff --git a/lib/iris/common/mixin.py b/lib/iris/common/mixin.py index 2d9605de83..87d58944c7 100644 --- a/lib/iris/common/mixin.py +++ b/lib/iris/common/mixin.py @@ -4,10 +4,14 @@ # See LICENSE in the root of the repository for full licensing details. """Provides common metadata mixin behaviour.""" +from __future__ import annotations + from collections.abc import Mapping from functools import wraps +from typing import Any import cf_units +import numpy as np import iris.std_names @@ -101,11 +105,9 @@ def __eq__(self, other): match = set(self.keys()) == set(other.keys()) if match: for key, value in self.items(): - match = value == other[key] - try: - match = bool(match) - except ValueError: - match = match.all() + match = np.array_equal( + np.array(value, ndmin=1), np.array(other[key], ndmin=1) + ) if not match: break return match @@ -138,11 +140,17 @@ def update(self, other, **kwargs): class CFVariableMixin: + _metadata_manager: Any + @wraps(BaseMetadata.name) - def name(self, default=None, token=None): + def name( + self, + default: str | None = None, + token: bool | None = None, + ) -> str: return self._metadata_manager.name(default=default, token=token) - def rename(self, name): + def rename(self, name: str | None) -> None: """Change the human-readable name. If 'name' is a valid standard name it will assign it to @@ -161,30 +169,30 @@ def rename(self, name): self.var_name = None @property - def standard_name(self): + def standard_name(self) -> str | None: """The CF Metadata standard name for the object.""" return self._metadata_manager.standard_name @standard_name.setter - def standard_name(self, name): + def standard_name(self, name: str | None) -> None: self._metadata_manager.standard_name = _get_valid_standard_name(name) @property - def long_name(self): + def long_name(self) -> str | None: """The CF Metadata long name for the object.""" return self._metadata_manager.long_name @long_name.setter - def long_name(self, name): + def long_name(self, name: str | None) -> None: self._metadata_manager.long_name = name @property - def var_name(self): + def var_name(self) -> str | None: """The NetCDF variable name for the object.""" return self._metadata_manager.var_name @var_name.setter - def var_name(self, name): + def var_name(self, name: str | None) -> None: if name is not None: result = self._metadata_manager.token(name) if result is None or not name: @@ -193,20 +201,20 @@ def var_name(self, name): self._metadata_manager.var_name = name @property - def units(self): + def units(self) -> cf_units.Unit: """The S.I. unit of the object.""" return self._metadata_manager.units @units.setter - def units(self, unit): + def units(self, unit: cf_units.Unit | str | None) -> None: self._metadata_manager.units = cf_units.as_unit(unit) @property - def attributes(self): + def attributes(self) -> LimitedAttributeDict: return self._metadata_manager.attributes @attributes.setter - def attributes(self, attributes): + def attributes(self, attributes: Mapping) -> None: self._metadata_manager.attributes = LimitedAttributeDict(attributes or {}) @property diff --git a/lib/iris/common/resolve.py b/lib/iris/common/resolve.py index 87ad05791b..c4bc18309b 100644 --- a/lib/iris/common/resolve.py +++ b/lib/iris/common/resolve.py @@ -2358,16 +2358,16 @@ def cube(self, data, in_place=False): >>> resolver.map_rhs_to_lhs True >>> cube1.data.sum() - 124652160.0 + np.float32(124652160.0) >>> zeros.shape (240, 37, 49) >>> zeros.sum() - 0.0 + np.float32(0.0) >>> result = resolver.cube(zeros, in_place=True) >>> result is cube1 True >>> cube1.data.sum() - 0.0 + np.float32(0.0) """ from iris.cube import Cube diff --git a/lib/iris/coord_categorisation.py b/lib/iris/coord_categorisation.py index 770f8327a1..12ad93a9c3 100644 --- a/lib/iris/coord_categorisation.py +++ b/lib/iris/coord_categorisation.py @@ -30,7 +30,7 @@ def add_categorised_coord( cube: iris.cube.Cube, name: str, - from_coord: iris.coords.Coord | str, + from_coord: iris.coords.DimCoord | iris.coords.AuxCoord | str, category_function: Callable, units: str = "1", ) -> None: @@ -41,18 +41,18 @@ def add_categorised_coord( Parameters ---------- - cube : :class:`iris.cube.Cube` + cube : The cube containing 'from_coord'. The new coord will be added into it. - name : str + name : Name of the created coordinate. - from_coord : :class:`iris.coords.Coord` or str + from_coord : Coordinate in 'cube', or the name of one. - category_function : callable + category_function : Function(coordinate, value), returning a category value for a coordinate point-value. If ``value`` has a type hint :obj:`cftime.datetime`, the coordinate points are translated to :obj:`cftime.datetime` s before calling ``category_function``. - units : str, default="1" + units : Units of the category value, typically 'no_unit' or '1'. """ # Interpret coord, if given as a name diff --git a/lib/iris/coords.py b/lib/iris/coords.py index 8afe9dad41..06a271cbba 100644 --- a/lib/iris/coords.py +++ b/lib/iris/coords.py @@ -2431,9 +2431,9 @@ def nearest_neighbour_index(self, point): >>> cube = iris.load_cube(iris.sample_data_path('ostia_monthly.nc')) >>> cube.coord('latitude').nearest_neighbour_index(0) - 9 + np.int64(9) >>> cube.coord('longitude').nearest_neighbour_index(10) - 12 + np.int64(12) .. note:: If the coordinate contains bounds, these will be used to determine the nearest neighbour instead of the point values. diff --git a/lib/iris/cube.py b/lib/iris/cube.py index bc90443a51..30ac3432b7 100644 --- a/lib/iris/cube.py +++ b/lib/iris/cube.py @@ -5,25 +5,27 @@ """Classes for representing multi-dimensional data with metadata.""" -from collections import OrderedDict -import copy -from copy import deepcopy -from functools import partial, reduce -import itertools -import operator -from typing import ( +from __future__ import annotations + +from collections.abc import ( Container, Iterable, Iterator, Mapping, MutableMapping, - Optional, ) +import copy +from copy import deepcopy +from functools import partial, reduce +import itertools +import operator +from typing import TYPE_CHECKING, Any, Optional, TypeGuard import warnings from xml.dom.minidom import Document import zlib from cf_units import Unit +import dask.array as da import numpy as np import numpy.ma as ma @@ -36,11 +38,17 @@ from iris.analysis.cartography import wrap_lons import iris.analysis.maths import iris.aux_factory +from iris.aux_factory import AuxCoordFactory from iris.common import CFVariableMixin, CubeMetadata, metadata_manager_factory -from iris.common.metadata import metadata_filter +from iris.common.metadata import CoordMetadata, metadata_filter from iris.common.mixin import LimitedAttributeDict import iris.coord_systems import iris.coords +from iris.coords import AncillaryVariable, AuxCoord, CellMeasure, CellMethod, DimCoord + +if TYPE_CHECKING: + import iris.mesh + from iris.mesh import MeshCoord import iris.exceptions import iris.util import iris.warnings @@ -70,8 +78,10 @@ def add(self, cube): if sub_cube is not None: self.cubes.append(sub_cube) - def merged(self, unique=False): - """Return a new :class:`_CubeFilter` by merging the list of cubes. + def combined(self, unique=False): + """Return a new :class:`_CubeFilter` by combining the list of cubes. + + Combines the list of cubes with :func:`~iris._combine_load_cubes`. Parameters ---------- @@ -80,7 +90,12 @@ def merged(self, unique=False): duplicate cubes are detected. """ - return _CubeFilter(self.constraint, self.cubes.merge(unique)) + from iris import _combine_load_cubes + + return _CubeFilter( + self.constraint, + _combine_load_cubes(self.cubes, merge_require_unique=unique), + ) class _CubeFilterCollection: @@ -105,14 +120,18 @@ def add_cube(self, cube): pair.add(cube) def cubes(self): - """Return all the cubes in this collection concatenated into a single :class:`CubeList`.""" + """Return all the cubes in this collection in a single :class:`CubeList`.""" + from iris.cube import CubeList + result = CubeList() for pair in self.pairs: result.extend(pair.cubes) return result - def merged(self, unique=False): - """Return a new :class:`_CubeFilterCollection` by merging all the cube lists of this collection. + def combined(self, unique=False): + """Return a new :class:`_CubeFilterCollection` by combining all the cube lists of this collection. + + Combines each list of cubes using :func:`~iris._combine_load_cubes`. Parameters ---------- @@ -121,7 +140,7 @@ def merged(self, unique=False): duplicate cubes are detected. """ - return _CubeFilterCollection([pair.merged(unique) for pair in self.pairs]) + return _CubeFilterCollection([pair.combined(unique) for pair in self.pairs]) class CubeList(list): @@ -547,7 +566,7 @@ def concatenate_cube( raise ValueError("can't concatenate an empty CubeList") names = [cube.metadata.name() for cube in self] - unique_names = list(OrderedDict.fromkeys(names)) + unique_names = list(dict.fromkeys(names)) if len(unique_names) == 1: res = concatenate( self, @@ -730,7 +749,7 @@ def copy(self): return deepcopy(self) -def _is_single_item(testee): +def _is_single_item(testee) -> TypeGuard[str | AuxCoord | DimCoord | int]: """Return whether this is a single item, rather than an iterable. We count string types as 'single', also. @@ -1171,18 +1190,20 @@ def _walk_nodes(node): def __init__( self, - data, - standard_name=None, - long_name=None, - var_name=None, - units=None, - attributes=None, - cell_methods=None, - dim_coords_and_dims=None, - aux_coords_and_dims=None, - aux_factories=None, - cell_measures_and_dims=None, - ancillary_variables_and_dims=None, + data: np.typing.ArrayLike, + standard_name: str | None = None, + long_name: str | None = None, + var_name: str | None = None, + units: Unit | str | None = None, + attributes: Mapping | None = None, + cell_methods: Iterable[CellMethod] | None = None, + dim_coords_and_dims: Iterable[tuple[DimCoord, int]] | None = None, + aux_coords_and_dims: Iterable[tuple[AuxCoord, int | Iterable[int]]] + | None = None, + aux_factories: Iterable[AuxCoordFactory] | None = None, + cell_measures_and_dims: Iterable[tuple[CellMeasure, int]] | None = None, + ancillary_variables_and_dims: Iterable[tuple[AncillaryVariable, int]] + | None = None, ): """Create a cube with data and optional metadata. @@ -1201,33 +1222,33 @@ def __init__( array_like (as described in :func:`numpy.asarray`). See :attr:`Cube.data`. - standard_name : optional + standard_name : The standard name for the Cube's data. - long_name : optional + long_name : An unconstrained description of the cube. - var_name : optional + var_name : The NetCDF variable name for the cube. - units : optional + units : The unit of the cube, e.g. ``"m s-1"`` or ``"kelvin"``. - attributes : optional + attributes : A dictionary of cube attributes. - cell_methods : optional + cell_methods : A tuple of CellMethod objects, generally set by Iris, e.g. ``(CellMethod("mean", coords='latitude'), )``. - dim_coords_and_dims : optional + dim_coords_and_dims : A list of coordinates with scalar dimension mappings, e.g ``[(lat_coord, 0), (lon_coord, 1)]``. - aux_coords_and_dims : optional + aux_coords_and_dims : A list of coordinates with dimension mappings, e.g ``[(lat_coord, 0), (lon_coord, (0, 1))]``. See also :meth:`Cube.add_dim_coord()` and :meth:`Cube.add_aux_coord()`. - aux_factories : optional + aux_factories : A list of auxiliary coordinate factories. See :mod:`iris.aux_factory`. - cell_measures_and_dims : optional + cell_measures_and_dims : A list of CellMeasures with dimension mappings. - ancillary_variables_and_dims : optional + ancillary_variables_and_dims : A list of AncillaryVariables with dimension mappings. Examples @@ -1269,22 +1290,28 @@ def __init__( #: The NetCDF variable name for the Cube. self.var_name = var_name - self.cell_methods = cell_methods + # See https://github.com/python/mypy/issues/3004. + self.cell_methods = cell_methods # type: ignore[assignment] #: A dictionary for arbitrary Cube metadata. #: A few keys are restricted - see :class:`CubeAttrsDict`. - self.attributes = attributes + # See https://github.com/python/mypy/issues/3004. + self.attributes = attributes # type: ignore[assignment] # Coords - self._dim_coords_and_dims = [] - self._aux_coords_and_dims = [] - self._aux_factories = [] + self._dim_coords_and_dims: list[tuple[DimCoord, int]] = [] + self._aux_coords_and_dims: list[ + tuple[AuxCoord | DimCoord, tuple[int, ...]] + ] = [] + self._aux_factories: list[AuxCoordFactory] = [] # Cell Measures - self._cell_measures_and_dims = [] + self._cell_measures_and_dims: list[tuple[CellMeasure, tuple[int, ...]]] = [] # Ancillary Variables - self._ancillary_variables_and_dims = [] + self._ancillary_variables_and_dims: list[ + tuple[AncillaryVariable, tuple[int, ...]] + ] = [] identities = set() if dim_coords_and_dims: @@ -1299,12 +1326,12 @@ def __init__( dims.add(dim) if aux_coords_and_dims: - for coord, dims in aux_coords_and_dims: - identity = coord.standard_name, coord.long_name + for auxcoord, auxdims in aux_coords_and_dims: + identity = auxcoord.standard_name, auxcoord.long_name if identity not in identities: - self._add_unique_aux_coord(coord, dims) + self._add_unique_aux_coord(auxcoord, auxdims) else: - self.add_aux_coord(coord, dims) + self.add_aux_coord(auxcoord, auxdims) identities.add(identity) if aux_factories: @@ -1312,15 +1339,15 @@ def __init__( self.add_aux_factory(factory) if cell_measures_and_dims: - for cell_measure, dims in cell_measures_and_dims: - self.add_cell_measure(cell_measure, dims) + for cell_measure, cmdims in cell_measures_and_dims: + self.add_cell_measure(cell_measure, cmdims) if ancillary_variables_and_dims: - for ancillary_variable, dims in ancillary_variables_and_dims: - self.add_ancillary_variable(ancillary_variable, dims) + for ancillary_variable, avdims in ancillary_variables_and_dims: + self.add_ancillary_variable(ancillary_variable, avdims) @property - def _names(self): + def _names(self) -> tuple[str | None, str | None, str | None, str | None]: """Tuple containing the value of each name participating in the identity of a :class:`iris.cube.Cube`. A tuple containing the value of each name participating in the identity @@ -1334,12 +1361,12 @@ def _names(self): # # Ensure that .attributes is always a :class:`CubeAttrsDict`. # - @property + @property # type: ignore[override] def attributes(self) -> CubeAttrsDict: - return super().attributes + return super().attributes # type: ignore[return-value] @attributes.setter - def attributes(self, attributes: Optional[Mapping]): + def attributes(self, attributes: Mapping | None) -> None: """Override to CfVariableMixin.attributes.setter. An override to CfVariableMixin.attributes.setter, which ensures that Cube @@ -1371,7 +1398,11 @@ def _dimensional_metadata(self, name_or_dimensional_metadata): raise KeyError(f"{name_or_dimensional_metadata} was not found in {self}.") return found_item - def is_compatible(self, other, ignore=None): + def is_compatible( + self, + other: Cube | CubeMetadata, + ignore: Iterable[str] | str | None = None, + ) -> bool: """Return whether the cube is compatible with another. Compatibility is determined by comparing :meth:`iris.cube.Cube.name()`, @@ -1383,7 +1414,7 @@ def is_compatible(self, other, ignore=None): other : An instance of :class:`iris.cube.Cube` or :class:`iris.cube.CubeMetadata`. - ignore : optional + ignore : A single attribute key or iterable of attribute keys to ignore when comparing the cubes. Default is None. To ignore all attributes set this to other.attributes. @@ -1425,7 +1456,7 @@ def is_compatible(self, other, ignore=None): return compatible - def convert_units(self, unit): + def convert_units(self, unit: str | Unit) -> None: """Change the cube's units, converting the values in the data array. For example, if a cube's :attr:`~iris.cube.Cube.units` are @@ -1462,11 +1493,15 @@ def convert_units(self, unit): self.data = new_data self.units = unit - def add_cell_method(self, cell_method): + def add_cell_method(self, cell_method: CellMethod) -> None: """Add a :class:`~iris.coords.CellMethod` to the Cube.""" self.cell_methods += (cell_method,) - def add_aux_coord(self, coord, data_dims=None): + def add_aux_coord( + self, + coord: AuxCoord | DimCoord, + data_dims: Iterable[int] | int | None = None, + ) -> None: """Add a CF auxiliary coordinate to the cube. Parameters @@ -1474,7 +1509,7 @@ def add_aux_coord(self, coord, data_dims=None): coord : The :class:`iris.coords.DimCoord` or :class:`iris.coords.AuxCoord` instance to add to the cube. - data_dims : optional + data_dims : Integer or iterable of integers giving the data dimensions spanned by the coordinate. @@ -1496,11 +1531,15 @@ def add_aux_coord(self, coord, data_dims=None): ) self._add_unique_aux_coord(coord, data_dims) - def _check_multi_dim_metadata(self, metadata, data_dims): + def _check_multi_dim_metadata( + self, + metadata: iris.coords._DimensionalMetadata, + data_dims: Iterable[int] | int | None, + ) -> tuple[int, ...]: # Convert to a tuple of integers if data_dims is None: data_dims = tuple() - elif isinstance(data_dims, Container): + elif isinstance(data_dims, Iterable): data_dims = tuple(int(d) for d in data_dims) else: data_dims = (int(data_dims),) @@ -1534,9 +1573,17 @@ def _check_multi_dim_metadata(self, metadata, data_dims): raise iris.exceptions.CannotAddError(msg) return data_dims - def _add_unique_aux_coord(self, coord, data_dims): + def _add_unique_aux_coord( + self, + coord: AuxCoord | DimCoord, + data_dims: Iterable[int] | int | None, + ) -> None: data_dims = self._check_multi_dim_metadata(coord, data_dims) - if hasattr(coord, "mesh"): + + def is_mesh_coord(anycoord: iris.coords.Coord) -> TypeGuard[MeshCoord]: + return hasattr(anycoord, "mesh") + + if is_mesh_coord(coord): mesh = self.mesh if mesh: msg = ( @@ -1576,7 +1623,7 @@ def _add_unique_aux_coord(self, coord, data_dims): self._aux_coords_and_dims.append((coord, data_dims)) - def add_aux_factory(self, aux_factory): + def add_aux_factory(self, aux_factory: AuxCoordFactory) -> None: """Add an auxiliary coordinate factory to the cube. Parameters @@ -1608,7 +1655,11 @@ def coordsonly(coords_and_dims): ) self._aux_factories.append(aux_factory) - def add_cell_measure(self, cell_measure, data_dims=None): + def add_cell_measure( + self, + cell_measure: CellMeasure, + data_dims: Iterable[int] | int | None = None, + ) -> None: """Add a CF cell measure to the cube. Parameters @@ -1616,7 +1667,7 @@ def add_cell_measure(self, cell_measure, data_dims=None): cell_measure : The :class:`iris.coords.CellMeasure` instance to add to the cube. - data_dims : optional + data_dims : Integer or iterable of integers giving the data dimensions spanned by the coordinate. @@ -1642,7 +1693,11 @@ def add_cell_measure(self, cell_measure, data_dims=None): key=lambda cm_dims: (cm_dims[0].metadata, cm_dims[1]) ) - def add_ancillary_variable(self, ancillary_variable, data_dims=None): + def add_ancillary_variable( + self, + ancillary_variable: AncillaryVariable, + data_dims: Iterable[int] | int | None = None, + ) -> None: """Add a CF ancillary variable to the cube. Parameters @@ -1650,7 +1705,7 @@ def add_ancillary_variable(self, ancillary_variable, data_dims=None): ancillary_variable : The :class:`iris.coords.AncillaryVariable` instance to be added to the cube. - data_dims : optional + data_dims : Integer or iterable of integers giving the data dimensions spanned by the ancillary variable. @@ -1672,12 +1727,12 @@ def add_ancillary_variable(self, ancillary_variable, data_dims=None): key=lambda av_dims: (av_dims[0].metadata, av_dims[1]) ) - def add_dim_coord(self, dim_coord, data_dim): + def add_dim_coord(self, dim_coord: DimCoord, data_dim: int | tuple[int]) -> None: """Add a CF coordinate to the cube. Parameters ---------- - dim_coord : :class:`iris.coords.DimCoord` + dim_coord : The :class:`iris.coords.DimCoord` instance to add to the cube. data_dim : Integer giving the data dimension spanned by the coordinate. @@ -1707,7 +1762,11 @@ def add_dim_coord(self, dim_coord, data_dim): ) self._add_unique_dim_coord(dim_coord, data_dim) - def _add_unique_dim_coord(self, dim_coord, data_dim): + def _add_unique_dim_coord( + self, + dim_coord: DimCoord, + data_dim: int | tuple[int], + ) -> None: if isinstance(dim_coord, iris.coords.AuxCoord): raise iris.exceptions.CannotAddError( "The dim_coord may not be an AuxCoord instance." @@ -1743,11 +1802,11 @@ def _add_unique_dim_coord(self, dim_coord, data_dim): self._dim_coords_and_dims.append((dim_coord, int(data_dim))) - def remove_aux_factory(self, aux_factory): + def remove_aux_factory(self, aux_factory: AuxCoordFactory) -> None: """Remove the given auxiliary coordinate factory from the cube.""" self._aux_factories.remove(aux_factory) - def _remove_coord(self, coord): + def _remove_coord(self, coord: DimCoord | AuxCoord) -> None: self._dim_coords_and_dims = [ (coord_, dim) for coord_, dim in self._dim_coords_and_dims @@ -1762,12 +1821,12 @@ def _remove_coord(self, coord): if coord.metadata == aux_factory.metadata: self.remove_aux_factory(aux_factory) - def remove_coord(self, coord): + def remove_coord(self, coord: str | DimCoord | AuxCoord | AuxCoordFactory) -> None: """Remove a coordinate from the cube. Parameters ---------- - coord : str or coord + coord : The (name of the) coordinate to remove from the cube. See Also @@ -1784,12 +1843,12 @@ def remove_coord(self, coord): for factory in self.aux_factories: factory.update(coord) - def remove_cell_measure(self, cell_measure): + def remove_cell_measure(self, cell_measure: str | CellMeasure) -> None: """Remove a cell measure from the cube. Parameters ---------- - cell_measure : str or cell_measure + cell_measure : The (name of the) cell measure to remove from the cube. As either * (a) a :attr:`standard_name`, :attr:`long_name`, or @@ -1820,12 +1879,15 @@ def remove_cell_measure(self, cell_measure): if cell_measure_ is not cell_measure ] - def remove_ancillary_variable(self, ancillary_variable): + def remove_ancillary_variable( + self, + ancillary_variable: str | AncillaryVariable, + ) -> None: """Remove an ancillary variable from the cube. Parameters ---------- - ancillary_variable : str or AncillaryVariable + ancillary_variable : The (name of the) AncillaryVariable to remove from the cube. """ @@ -1837,7 +1899,7 @@ def remove_ancillary_variable(self, ancillary_variable): if ancillary_variable_ is not ancillary_variable ] - def replace_coord(self, new_coord): + def replace_coord(self, new_coord: DimCoord | AuxCoord) -> None: """Replace the coordinate whose metadata matches the given coordinate.""" old_coord = self.coord(new_coord) dims = self.coord_dims(old_coord) @@ -1851,7 +1913,9 @@ def replace_coord(self, new_coord): for factory in self.aux_factories: factory.update(old_coord, new_coord) - def coord_dims(self, coord): + def coord_dims( + self, coord: str | DimCoord | AuxCoord | AuxCoordFactory + ) -> tuple[int, ...]: """Return a tuple of the data dimensions relevant to the given coordinate. When searching for the given coordinate in the cube the comparison is @@ -1861,9 +1925,13 @@ def coord_dims(self, coord): Parameters ---------- - coord : str or coord + coord : The (name of the) coord to look for. + Returns + ------- + tuple: + A tuple of the data dimensions relevant to the given coordinate. """ name_provided = False if isinstance(coord, str): @@ -1874,7 +1942,9 @@ def coord_dims(self, coord): coord_id = id(coord) # Dimension of dimension coordinate by object id - dims_by_id = {id(c): (d,) for c, d in self._dim_coords_and_dims} + dims_by_id: dict[int, tuple[int, ...]] = { + id(c): (d,) for c, d in self._dim_coords_and_dims + } # Check for id match - faster than equality check match = dims_by_id.get(coord_id) @@ -1911,14 +1981,18 @@ def matcher(factory): return match - def cell_measure_dims(self, cell_measure): + def cell_measure_dims(self, cell_measure: str | CellMeasure) -> tuple[int, ...]: """Return a tuple of the data dimensions relevant to the given CellMeasure. Parameters ---------- - cell_measure : str or CellMeasure + cell_measure : The (name of the) cell measure to look for. + Returns + ------- + tuple: + A tuple of the data dimensions relevant to the given cell measure. """ cell_measure = self.cell_measure(cell_measure) @@ -1933,7 +2007,10 @@ def cell_measure_dims(self, cell_measure): return matches[0] - def ancillary_variable_dims(self, ancillary_variable): + def ancillary_variable_dims( + self, + ancillary_variable: str | AncillaryVariable, + ) -> tuple[int, ...]: """Return a tuple of the data dimensions relevant to the given AncillaryVariable. Parameters @@ -1941,6 +2018,10 @@ def ancillary_variable_dims(self, ancillary_variable): ancillary_variable : str or AncillaryVariable The (name of the) AncillaryVariable to look for. + Returns + ------- + tuple: + A tuple of the data dimensions relevant to the given ancillary variable. """ ancillary_variable = self.ancillary_variable(ancillary_variable) @@ -1959,7 +2040,13 @@ def ancillary_variable_dims(self, ancillary_variable): return matches[0] - def aux_factory(self, name=None, standard_name=None, long_name=None, var_name=None): + def aux_factory( + self, + name: str | None = None, + standard_name: str | None = None, + long_name: str | None = None, + var_name: str | None = None, + ) -> AuxCoordFactory: """Return the single coordinate factory that matches the criteria. Return the single coordinate factory that matches the criteria, @@ -1967,18 +2054,23 @@ def aux_factory(self, name=None, standard_name=None, long_name=None, var_name=No Parameters ---------- - name : optional + name : If not None, matches against factory.name(). - standard_name : optional + standard_name : The CF standard name of the desired coordinate factory. If None, does not check for standard name. - long_name : optional + long_name : An unconstrained description of the coordinate factory. If None, does not check for long_name. - var_name : optional + var_name : The NetCDF variable name of the desired coordinate factory. If None, does not check for var_name. + Returns + ------- + AuxCoordFactory: + The single coordinate factory that matches the criteria. + Notes ----- .. note:: @@ -1988,7 +2080,7 @@ def aux_factory(self, name=None, standard_name=None, long_name=None, var_name=No :class:`iris.exceptions.CoordinateNotFoundError` is raised. """ - factories = self.aux_factories + factories = list(self.aux_factories) if name is not None: factories = [factory for factory in factories if factory.name() == name] @@ -2027,23 +2119,28 @@ def aux_factory(self, name=None, standard_name=None, long_name=None, var_name=No def coords( self, - name_or_coord=None, - standard_name=None, - long_name=None, - var_name=None, - attributes=None, - axis=None, + name_or_coord: str + | DimCoord + | AuxCoord + | AuxCoordFactory + | CoordMetadata + | None = None, + standard_name: str | None = None, + long_name: str | None = None, + var_name: str | None = None, + attributes: Mapping | None = None, + axis: iris.util.Axis | None = None, contains_dimension=None, - dimensions=None, + dimensions: Iterable[int] | int | None = None, coord_system=None, - dim_coords=None, - mesh_coords=None, - ): + dim_coords: bool | None = None, + mesh_coords: bool | None = None, + ) -> list[DimCoord | AuxCoord]: r"""Return a list of coordinates from the :class:`Cube` that match the provided criteria. Parameters ---------- - name_or_coord : optional + name_or_coord : Either, * a :attr:`~iris.common.mixin.CFVariableMixin.standard_name`, @@ -2054,39 +2151,39 @@ def coords( * a coordinate or metadata instance equal to that of the desired coordinate e.g., :class:`~iris.coords.DimCoord` or :class:`~iris.common.metadata.CoordMetadata`. - standard_name : optional + standard_name : The CF standard name of the desired coordinate. If ``None``, does not check for ``standard name``. - long_name : optional + long_name : An unconstrained description of the coordinate. If ``None``, does not check for ``long_name``. - var_name : optional + var_name : The NetCDF variable name of the desired coordinate. If ``None``, does not check for ``var_name``. - attributes : optional + attributes : A dictionary of attributes desired on the coordinates. If ``None``, does not check for ``attributes``. - axis : optional + axis : The desired coordinate axis, see :func:`iris.util.guess_coord_axis`. If ``None``, does not check for ``axis``. Accepts the values ``X``, ``Y``, ``Z`` and ``T`` (case-insensitive). - contains_dimension : optional + contains_dimension : The desired coordinate contains the data dimension. If ``None``, does not check for the dimension. - dimensions : optional + dimensions : The exact data dimensions of the desired coordinate. Coordinates with no data dimension can be found with an empty ``tuple`` or ``list`` i.e., ``()`` or ``[]``. If ``None``, does not check for dimensions. - coord_system : optional + coord_system : Whether the desired coordinates have a coordinate system equal to the given coordinate system. If ``None``, no check is done. - dim_coords : optional + dim_coords : Set to ``True`` to only return coordinates that are the cube's dimension coordinates. Set to ``False`` to only return coordinates that are the cube's auxiliary, mesh and derived coordinates. If ``None``, returns all coordinates. - mesh_coords : optional + mesh_coords : Set to ``True`` to return only coordinates which are :class:`~iris.mesh.MeshCoord`\'s. Set to ``False`` to return only non-mesh coordinates. @@ -2103,7 +2200,7 @@ def coords( """ - coords_and_factories = [] + coords_and_factories: list[DimCoord | AuxCoord | AuxCoordFactory] = [] if dim_coords in [True, None]: coords_and_factories += list(self.dim_coords) @@ -2153,7 +2250,7 @@ def coords( ] if dimensions is not None: - if not isinstance(dimensions, Container): + if not isinstance(dimensions, Iterable): dimensions = [dimensions] dimensions = tuple(dimensions) coords_and_factories = [ @@ -2184,23 +2281,28 @@ def extract_coord(coord_or_factory): def coord( self, - name_or_coord=None, - standard_name=None, - long_name=None, - var_name=None, - attributes=None, - axis=None, + name_or_coord: str + | DimCoord + | AuxCoord + | AuxCoordFactory + | CoordMetadata + | None = None, + standard_name: str | None = None, + long_name: str | None = None, + var_name: str | None = None, + attributes: Mapping | None = None, + axis: iris.util.Axis | None = None, contains_dimension=None, - dimensions=None, + dimensions: Iterable[int] | int | None = None, coord_system=None, - dim_coords=None, - mesh_coords=None, - ): + dim_coords: bool | None = None, + mesh_coords: bool | None = None, + ) -> DimCoord | AuxCoord: r"""Return a single coordinate from the :class:`Cube` that matches the provided criteria. Parameters ---------- - name_or_coord : optional + name_or_coord : Either, * a :attr:`~iris.common.mixin.CFVariableMixin.standard_name`, @@ -2211,39 +2313,39 @@ def coord( * a coordinate or metadata instance equal to that of the desired coordinate e.g., :class:`~iris.coords.DimCoord` or :class:`~iris.common.metadata.CoordMetadata`. - standard_name : optional + standard_name : The CF standard name of the desired coordinate. If ``None``, does not check for ``standard name``. - long_name : optional + long_name : An unconstrained description of the coordinate. If ``None``, does not check for ``long_name``. - var_name : optional + var_name : The NetCDF variable name of the desired coordinate. If ``None``, does not check for ``var_name``. - attributes : optional + attributes : A dictionary of attributes desired on the coordinates. If ``None``, does not check for ``attributes``. - axis : optional + axis : The desired coordinate axis, see :func:`iris.util.guess_coord_axis`. If ``None``, does not check for ``axis``. Accepts the values ``X``, ``Y``, ``Z`` and ``T`` (case-insensitive). - contains_dimension : optional + contains_dimension : The desired coordinate contains the data dimension. If ``None``, does not check for the dimension. - dimensions : optional + dimensions : The exact data dimensions of the desired coordinate. Coordinates with no data dimension can be found with an empty ``tuple`` or ``list`` i.e., ``()`` or ``[]``. If ``None``, does not check for dimensions. - coord_system : optional + coord_system : Whether the desired coordinates have a coordinate system equal to the given coordinate system. If ``None``, no check is done. - dim_coords : optional + dim_coords : Set to ``True`` to only return coordinates that are the cube's dimension coordinates. Set to ``False`` to only return coordinates that are the cube's auxiliary, mesh and derived coordinates. If ``None``, returns all coordinates. - mesh_coords : optional + mesh_coords : Set to ``True`` to return only coordinates which are :class:`~iris.mesh.MeshCoord`\'s. Set to ``False`` to return only non-mesh coordinates. @@ -2277,6 +2379,7 @@ def coord( dimensions=dimensions, coord_system=coord_system, dim_coords=dim_coords, + mesh_coords=mesh_coords, ) if len(coords) > 1: @@ -2305,7 +2408,10 @@ def coord( return coords[0] - def coord_system(self, spec=None): + def coord_system( + self, + spec: str | type[iris.coord_systems.CoordSystem] | None = None, + ) -> iris.coord_systems.CoordSystem | None: """Find the coordinate system of the given type. If no target coordinate system is provided then find @@ -2313,7 +2419,7 @@ def coord_system(self, spec=None): Parameters ---------- - spec : optional + spec : The the name or type of a coordinate system subclass. E.g. :: @@ -2354,17 +2460,17 @@ def coord_system(self, spec=None): return result - def _any_meshcoord(self): + def _any_meshcoord(self) -> MeshCoord | None: """Return a MeshCoord if there are any, else None.""" mesh_coords = self.coords(mesh_coords=True) if mesh_coords: result = mesh_coords[0] else: result = None - return result + return result # type: ignore[return-value] @property - def mesh(self): + def mesh(self) -> iris.mesh.MeshXY | None: r"""Return the unstructured :class:`~iris.mesh.MeshXY` associated with the cube. Return the unstructured :class:`~iris.mesh.MeshXY` @@ -2380,13 +2486,15 @@ def mesh(self): or ``None``. """ - result = self._any_meshcoord() - if result is not None: - result = result.mesh + coord = self._any_meshcoord() + if coord is None: + result = None + else: + result = coord.mesh return result @property - def location(self): + def location(self) -> iris.mesh.components.Location | None: r"""Return the mesh "location" of the cube data. Return the mesh "location" of the cube data, if the cube has any @@ -2401,12 +2509,14 @@ def location(self): (i.e. one of 'face' / 'edge' / 'node'), or ``None``. """ - result = self._any_meshcoord() - if result is not None: - result = result.location + coord = self._any_meshcoord() + if coord is None: + result = None + else: + result = coord.location return result - def mesh_dim(self): + def mesh_dim(self) -> int | None: r"""Return the cube dimension of the mesh. Return the cube dimension of the mesh, if the cube has any @@ -2421,17 +2531,22 @@ def mesh_dim(self): or ``None``. """ - result = self._any_meshcoord() - if result is not None: - (result,) = self.coord_dims(result) # result is a 1-tuple + coord = self._any_meshcoord() + if coord is None: + result = None + else: + (result,) = self.coord_dims(coord) # result is a 1-tuple return result - def cell_measures(self, name_or_cell_measure=None): + def cell_measures( + self, + name_or_cell_measure: str | CellMeasure | None = None, + ) -> list[CellMeasure]: """Return a list of cell measures in this cube fitting the given criteria. Parameters ---------- - name_or_cell_measure : optional + name_or_cell_measure : Either * (a) a :attr:`standard_name`, :attr:`long_name`, or @@ -2442,6 +2557,11 @@ def cell_measures(self, name_or_cell_measure=None): * (b) a cell_measure instance with metadata equal to that of the desired cell_measures. + Returns + ------- + list + List of cell measures in this cube fitting the given criteria. + See Also -------- cell_measure : @@ -2466,7 +2586,10 @@ def cell_measures(self, name_or_cell_measure=None): cell_measures.append(cm) return cell_measures - def cell_measure(self, name_or_cell_measure=None): + def cell_measure( + self, + name_or_cell_measure: str | CellMeasure | None = None, + ) -> CellMeasure: """Return a single cell_measure given the same arguments as :meth:`Cube.cell_measures`. Notes @@ -2477,6 +2600,11 @@ def cell_measure(self, name_or_cell_measure=None): being matched, an :class:`iris.exceptions.CellMeasureNotFoundError` is raised. + Returns + ------- + CellMeasure + A single cell measure in this cube fitting the given criteria. + See Also -------- cell_measures : @@ -2514,12 +2642,15 @@ def cell_measure(self, name_or_cell_measure=None): return cell_measures[0] - def ancillary_variables(self, name_or_ancillary_variable=None): + def ancillary_variables( + self, + name_or_ancillary_variable: str | AncillaryVariable | None = None, + ) -> list[AncillaryVariable]: """Return a list of ancillary variable in this cube fitting the given criteria. Parameters ---------- - name_or_ancillary_variable : optional + name_or_ancillary_variable : Either * (a) a :attr:`standard_name`, :attr:`long_name`, or @@ -2530,10 +2661,15 @@ def ancillary_variables(self, name_or_ancillary_variable=None): * (b) a ancillary_variable instance with metadata equal to that of the desired ancillary_variables. + Returns + ------- + list + List of ancillary variables in this cube fitting the given criteria. + See Also -------- ancillary_variable : - Return a single ancillary_variable. + Return a ancillary_variable. """ name = None @@ -2554,7 +2690,10 @@ def ancillary_variables(self, name_or_ancillary_variable=None): ancillary_variables.append(av) return ancillary_variables - def ancillary_variable(self, name_or_ancillary_variable=None): + def ancillary_variable( + self, + name_or_ancillary_variable: str | AncillaryVariable | None = None, + ) -> AncillaryVariable: """Return a single ancillary_variable given the same arguments as :meth:`Cube.ancillary_variables`. Notes @@ -2565,6 +2704,11 @@ def ancillary_variable(self, name_or_ancillary_variable=None): ancillary_variable being matched, an :class:`iris.exceptions.AncillaryVariableNotFoundError` is raised. + Returns + ------- + AncillaryVariable + A single ancillary variable in this cube fitting the given criteria. + See Also -------- ancillary_variables : @@ -2606,7 +2750,7 @@ def ancillary_variable(self, name_or_ancillary_variable=None): return ancillary_variables[0] @property - def cell_methods(self): + def cell_methods(self) -> tuple[CellMethod, ...]: """Tuple of :class:`iris.coords.CellMethod`. Tuple of :class:`iris.coords.CellMethod` representing the processing @@ -2616,7 +2760,10 @@ def cell_methods(self): return self._metadata_manager.cell_methods @cell_methods.setter - def cell_methods(self, cell_methods: Iterable): + def cell_methods( + self, + cell_methods: Iterable[CellMethod] | None, + ) -> None: if not cell_methods: # For backwards compatibility: Empty or null value is equivalent to (). cell_methods = () @@ -2627,14 +2774,14 @@ def cell_methods(self, cell_methods: Iterable): # All contents should be CellMethods. Requiring class membership is # somewhat non-Pythonic, but simple, and not a problem for now. if not isinstance(cell_method, iris.coords.CellMethod): - msg = ( + msg = ( # type: ignore[unreachable] f"Cube.cell_methods assigned value includes {cell_method}, " "which is not an iris.coords.CellMethod." ) raise ValueError(msg) self._metadata_manager.cell_methods = cell_methods - def core_data(self): + def core_data(self) -> np.ndarray | da.Array: """Retrieve the data array of this :class:`~iris.cube.Cube`. Retrieve the data array of this :class:`~iris.cube.Cube` in its @@ -2649,7 +2796,7 @@ def core_data(self): return self._data_manager.core_data() @property - def shape(self): + def shape(self) -> tuple[int, ...]: """The shape of the data of this cube.""" return self._data_manager.shape @@ -2659,11 +2806,11 @@ def dtype(self): return self._data_manager.dtype @property - def ndim(self): + def ndim(self) -> int: """The number of dimensions in the data of this cube.""" return self._data_manager.ndim - def lazy_data(self): + def lazy_data(self) -> da.Array: """Return a "lazy array" representing the Cube data. Return a "lazy array" representing the Cube data. A lazy array @@ -2688,7 +2835,7 @@ def lazy_data(self): return self._data_manager.lazy_data() @property - def data(self): + def data(self) -> np.ndarray: """The :class:`numpy.ndarray` representing the multi-dimensional data of the cube. Notes @@ -2723,10 +2870,10 @@ def data(self): return self._data_manager.data @data.setter - def data(self, data): + def data(self, data: np.typing.ArrayLike) -> None: self._data_manager.data = data - def has_lazy_data(self): + def has_lazy_data(self) -> bool: """Detail whether this :class:`~iris.cube.Cube` has lazy data. Returns @@ -2737,7 +2884,7 @@ def has_lazy_data(self): return self._data_manager.has_lazy_data() @property - def dim_coords(self): + def dim_coords(self) -> tuple[DimCoord, ...]: """Return a tuple of all the dimension coordinates, ordered by dimension. .. note:: @@ -2761,7 +2908,7 @@ def dim_coords(self): ) @property - def aux_coords(self): + def aux_coords(self) -> tuple[AuxCoord | DimCoord, ...]: """Return a tuple of all the auxiliary coordinates, ordered by dimension(s).""" return tuple( ( @@ -2774,7 +2921,7 @@ def aux_coords(self): ) @property - def derived_coords(self): + def derived_coords(self) -> tuple[AuxCoord, ...]: """Return a tuple of all the coordinates generated by the coordinate factories.""" return tuple( factory.make_coord(self.coord_dims) @@ -2784,11 +2931,11 @@ def derived_coords(self): ) @property - def aux_factories(self): + def aux_factories(self) -> tuple[AuxCoordFactory, ...]: """Return a tuple of all the coordinate factories.""" return tuple(self._aux_factories) - def summary(self, shorten=False, name_padding=35): + def summary(self, shorten: bool = False, name_padding: int = 35) -> str: """Summary of the Cube. String summary of the Cube with name+units, a list of dim coord names @@ -2796,11 +2943,11 @@ def summary(self, shorten=False, name_padding=35): Parameters ---------- - shorten : bool, default=False + shorten : If set, produce a one-line summary of minimal width, showing only the cube name, units and dimensions. When not set (default), produces a full multi-line summary string. - name_padding : int, default=35 + name_padding : Control the *minimum* width of the cube name + units, i.e. the indent of the dimension map section. @@ -2811,13 +2958,13 @@ def summary(self, shorten=False, name_padding=35): summary = printer.to_string(oneline=shorten, name_padding=name_padding) return summary - def __str__(self): + def __str__(self) -> str: return self.summary() - def __repr__(self): + def __repr__(self) -> str: return "" % self.summary(shorten=True, name_padding=1) - def _repr_html_(self): + def _repr_html_(self) -> str: from iris.experimental.representation import CubeRepresentation representer = CubeRepresentation(self) @@ -2827,7 +2974,7 @@ def _repr_html_(self): # TypeError with a useful message if a Cube is iterated over. __iter__ = None - def __getitem__(self, keys): + def __getitem__(self, keys) -> Cube: """Cube indexing has been implemented at the data level. Cube indexing (through use of square bracket notation) has been @@ -2878,7 +3025,7 @@ def new_ancillary_variable_dims(av_): data = ma.array(data.data, mask=data.mask, dtype=cube_data.dtype) # Make the new cube slice - cube = Cube(data) + cube = self.__class__(data) cube.metadata = deepcopy(self.metadata) # Record a mapping from old coordinate IDs to new coordinates, @@ -2936,7 +3083,7 @@ def new_ancillary_variable_dims(av_): return cube - def subset(self, coord): + def subset(self, coord: AuxCoord | DimCoord) -> Cube | None: """Get a subset of the cube by providing the desired resultant coordinate. Get a subset of the cube by providing the desired resultant @@ -2976,24 +3123,23 @@ def subset(self, coord): if coord_indices.size == 0: # No matches found. - return + return None # Build up a slice which spans the whole of the cube full_slice = [slice(None, None)] * len(self.shape) # Update the full slice to only extract specific indices which # were identified above full_slice[coord_to_extract_dim] = coord_indices - full_slice = tuple(full_slice) - result = self[full_slice] + result = self[tuple(full_slice)] return result - def extract(self, constraint): + def extract(self, constraint: iris.Constraint | str | None) -> Cube: """Filter cube by the given constraint using :meth:`iris.Constraint.extract`.""" # Cast the constraint into a proper constraint if it is not so already constraint = iris._constraints.as_constraint(constraint) return constraint.extract(self) - def intersection(self, *args, **kwargs): + def intersection(self, *args, **kwargs) -> Cube: """Return the intersection of the cube with specified coordinate ranges. Coordinate ranges can be specified as: @@ -3072,23 +3218,28 @@ def intersection(self, *args, **kwargs): for arg in args: result = result._intersect( *arg, ignore_bounds=ignore_bounds, threshold=threshold - ) + ) # type: ignore[misc] for name, value in kwargs.items(): result = result._intersect( name, *value, ignore_bounds=ignore_bounds, threshold=threshold - ) + ) # type: ignore[misc] return result def _intersect( self, - name_or_coord, - minimum, - maximum, - min_inclusive=True, - max_inclusive=True, - ignore_bounds=False, + name_or_coord: str + | DimCoord + | AuxCoord + | AuxCoordFactory + | CoordMetadata + | None, + minimum: float | int, + maximum: float | int, + min_inclusive: bool = True, + max_inclusive: bool = True, + ignore_bounds: bool = False, threshold=0, - ): + ) -> Cube: coord = self.coord(name_or_coord) if coord.ndim != 1: raise iris.exceptions.CoordinateMultiDimError(coord) @@ -3206,7 +3357,13 @@ def create_metadata(src_metadatas, add_metadata, get_metadata): result.add_aux_factory(factory.updated(coord_mapping)) return result - def _intersect_derive_subset(self, coord, points, bounds, inside_indices): + def _intersect_derive_subset( + self, + coord: AuxCoord | DimCoord, + points: np.ndarray, + bounds: np.ndarray, + inside_indices: np.ndarray, + ) -> list[slice]: # Return the subsets, i.e. the means to allow the slicing of # coordinates to ensure that they remain contiguous. modulus = coord.units.modulus @@ -3290,14 +3447,14 @@ def dim_coord_subset(): def _intersect_modulus( self, - coord, - minimum, - maximum, - min_inclusive, - max_inclusive, - ignore_bounds, - threshold, - ): + coord: AuxCoord | DimCoord, + minimum: float | int, + maximum: float | int, + min_inclusive: bool, + max_inclusive: bool, + ignore_bounds: bool, + threshold: float | int, + ) -> tuple[list[slice], np.ndarray, np.ndarray]: modulus = coord.units.modulus if maximum > minimum + modulus: raise ValueError("requested range greater than coordinate's unit's modulus") @@ -3381,7 +3538,7 @@ def _intersect_modulus( subsets = self._intersect_derive_subset(coord, points, bounds, inside_indices) return subsets, points, bounds - def _as_list_of_coords(self, names_or_coords): + def _as_list_of_coords(self, names_or_coords) -> list[AuxCoord | DimCoord]: """Convert a name, coord, or list of names/coords to a list of coords.""" # If not iterable, convert to list of a single item if _is_single_item(names_or_coords): @@ -3390,7 +3547,7 @@ def _as_list_of_coords(self, names_or_coords): coords = [] for name_or_coord in names_or_coords: if isinstance(name_or_coord, str) or isinstance( - name_or_coord, iris.coords.Coord + name_or_coord, (iris.coords.DimCoord, iris.coords.AuxCoord) ): coords.append(self.coord(name_or_coord)) else: @@ -3403,7 +3560,14 @@ def _as_list_of_coords(self, names_or_coords): raise TypeError(msg) return coords - def slices_over(self, ref_to_slice): + def slices_over( + self, + ref_to_slice: str + | AuxCoord + | DimCoord + | int + | Iterable[str | AuxCoord | DimCoord | int], + ) -> Iterable[Cube]: """Return an iterator of all subcubes. Return an iterator of all subcubes along a given coordinate or @@ -3411,7 +3575,7 @@ def slices_over(self, ref_to_slice): Parameters ---------- - ref_to_slice : str, coord, dimension index or a list of these + ref_to_slice : Determines which dimensions will be iterated along (i.e. the dimensions that are not returned in the subcubes). A mix of input types can also be provided. @@ -3472,12 +3636,12 @@ def slices_over(self, ref_to_slice): if _is_single_item(ref_to_slice): ref_to_slice = [ref_to_slice] - slice_dims = set() - for ref in ref_to_slice: + slice_dims: set[int] = set() + for ref in ref_to_slice: # type: ignore[union-attr] try: (coord,) = self._as_list_of_coords(ref) except TypeError: - dim = int(ref) + dim = int(ref) # type: ignore[arg-type] if dim < 0 or dim > self.ndim: msg = ( "Requested an iterator over a dimension ({}) " @@ -3486,7 +3650,7 @@ def slices_over(self, ref_to_slice): raise ValueError(msg) # Convert coord index to a single-element list to prevent a # TypeError when `slice_dims.update` is called with it. - dims = [dim] + dims: tuple[int, ...] = (dim,) else: dims = self.coord_dims(coord) slice_dims.update(dims) @@ -3495,7 +3659,15 @@ def slices_over(self, ref_to_slice): opposite_dims = list(all_dims - slice_dims) return self.slices(opposite_dims, ordered=False) - def slices(self, ref_to_slice, ordered=True): + def slices( + self, + ref_to_slice: str + | AuxCoord + | DimCoord + | int + | Iterable[str | AuxCoord | DimCoord | int], + ordered: bool = True, + ) -> Iterator[Cube]: """Return an iterator of all subcubes given the coordinates or dimension indices. Return an iterator of all subcubes given the coordinates or dimension @@ -3503,12 +3675,12 @@ def slices(self, ref_to_slice, ordered=True): Parameters ---------- - ref_to_slice : str, coord, dimension index or a list of these + ref_to_slice : Determines which dimensions will be returned in the subcubes (i.e. the dimensions that are not iterated over). A mix of input types can also be provided. They must all be orthogonal (i.e. point to different dimensions). - ordered : bool, default=True + ordered : If True, subcube dimensions are ordered to match the dimension order in `ref_to_slice`. If False, the order will follow that of the source cube. @@ -3571,8 +3743,8 @@ def slices(self, ref_to_slice, ordered=True): if _is_single_item(ref_to_slice): ref_to_slice = [ref_to_slice] - dim_to_slice = [] - for ref in ref_to_slice: + dim_to_slice: list[int] = [] + for ref in ref_to_slice: # type: ignore[union-attr] try: # attempt to handle as coordinate coord = self._as_list_of_coords(ref)[0] @@ -3589,7 +3761,7 @@ def slices(self, ref_to_slice, ordered=True): except TypeError: try: # attempt to handle as dimension index - dim = int(ref) + dim = int(ref) # type: ignore[arg-type] except ValueError: raise ValueError( "{} Incompatible type {} for slicing".format(ref, type(ref)) @@ -3615,12 +3787,12 @@ def slices(self, ref_to_slice, ordered=True): return _SliceIterator(self, dims_index, dim_to_slice, ordered) - def transpose(self, new_order=None): + def transpose(self, new_order: list[int] | None = None) -> None: """Re-order the data dimensions of the cube in-place. Parameters ---------- - new_order : list of ints, optional + new_order : By default, reverse the dimensions, otherwise permute the axes according to the values given. @@ -3679,7 +3851,12 @@ def remap_cube_metadata(metadata_and_dims): map(remap_cube_metadata, self._ancillary_variables_and_dims) ) - def xml(self, checksum=False, order=True, byteorder=True): + def xml( + self, + checksum: bool = False, + order: bool = True, + byteorder: bool = True, + ) -> str: """Return a fully valid CubeML string representation of the Cube.""" doc = Document() @@ -3852,12 +4029,12 @@ def _order(array): return cube_xml_element - def copy(self, data=None): + def copy(self, data: np.typing.ArrayLike | None = None) -> Cube: """Return a deep copy of this cube. Parameters ---------- - data : optional + data : Replace the data of the cube copy with provided data payload. Returns @@ -3865,7 +4042,7 @@ def copy(self, data=None): A copy instance of the :class:`Cube`. """ - memo = {} + memo: dict[int, Any] = {} cube = self._deepcopy(memo, data=data) return cube @@ -4032,7 +4209,12 @@ def __neg__(self): # END OPERATOR OVERLOADS - def collapsed(self, coords, aggregator, **kwargs): + def collapsed( + self, + coords: str | AuxCoord | DimCoord | Iterable[str | AuxCoord | DimCoord], + aggregator: iris.analysis.Aggregator, + **kwargs, + ) -> Cube: """Collapse one or more dimensions over the cube given the coordinate/s and an aggregation. Examples of aggregations that may be used include @@ -4062,12 +4244,12 @@ def collapsed(self, coords, aggregator, **kwargs): Parameters ---------- - coords : str, coord or a list of strings/coords + coords : Coordinate names/coordinates over which the cube should be collapsed. - aggregator : :class:`iris.analysis.Aggregator` + aggregator : Aggregator to be applied for collapse operation. - **kwargs : dict, optional + **kwargs : Aggregation function keyword arguments. Returns @@ -4136,13 +4318,13 @@ def collapsed(self, coords, aggregator, **kwargs): kwargs["weights"] = weights_info.array # Convert any coordinate names to coordinates - coords = self._as_list_of_coords(coords) + coordinates = self._as_list_of_coords(coords) if isinstance( aggregator, iris.analysis.WeightedAggregator ) and not aggregator.uses_weighting(**kwargs): msg = "Collapsing spatial coordinate {!r} without weighting" - lat_match = [coord for coord in coords if "latitude" in coord.name()] + lat_match = [coord for coord in coordinates if "latitude" in coord.name()] if lat_match: for coord in lat_match: warnings.warn( @@ -4151,18 +4333,11 @@ def collapsed(self, coords, aggregator, **kwargs): ) # Determine the dimensions we need to collapse (and those we don't) - if aggregator.cell_method == "peak": - dims_to_collapse = [list(self.coord_dims(coord)) for coord in coords] - - # Remove duplicate dimensions. - new_dims = OrderedDict.fromkeys(d for dim in dims_to_collapse for d in dim) - # Reverse the dimensions so the order can be maintained when - # reshaping the data. - dims_to_collapse = list(new_dims)[::-1] - else: - dims_to_collapse = set() - for coord in coords: - dims_to_collapse.update(self.coord_dims(coord)) + # Remove duplicate dimensions and reverse the dimensions so the order + # can be maintained when reshaping the data. + dims_to_collapse = list( + dict.fromkeys(d for coord in coordinates for d in self.coord_dims(coord)) + )[::-1] if aggregator.name() == "max_run" and len(dims_to_collapse) > 1: msg = "Not possible to calculate runs over more than one dimension" @@ -4172,17 +4347,17 @@ def collapsed(self, coords, aggregator, **kwargs): msg = "Cannot collapse a dimension which does not describe any data." raise iris.exceptions.CoordinateCollapseError(msg) - untouched_dims = set(range(self.ndim)) - set(dims_to_collapse) + untouched_dims = sorted(set(range(self.ndim)) - set(dims_to_collapse)) collapsed_cube = iris.util._strip_metadata_from_dims(self, dims_to_collapse) # Remove the collapsed dimension(s) from the metadata - indices = [slice(None, None)] * self.ndim + indices: list[slice | int] = [slice(None, None)] * self.ndim for dim in dims_to_collapse: indices[dim] = 0 collapsed_cube = collapsed_cube[tuple(indices)] - # Collapse any coords that span the dimension(s) being collapsed + # Collapse any coordinates that span the dimension(s) being collapsed for coord in self.dim_coords + self.aux_coords: coord_dims = self.coord_dims(coord) if set(dims_to_collapse).intersection(coord_dims): @@ -4193,8 +4368,6 @@ def collapsed(self, coords, aggregator, **kwargs): ] collapsed_cube.replace_coord(coord.collapsed(local_dims)) - untouched_dims = sorted(untouched_dims) - # Record the axis(s) argument passed to 'aggregation', so the same is # passed to the 'update_metadata' function. collapse_axis = -1 @@ -4221,11 +4394,12 @@ def collapsed(self, coords, aggregator, **kwargs): # on the cube lazy array. # NOTE: do not reform the data in this case, as 'lazy_aggregate' # accepts multiple axes (unlike 'aggregate'). - collapse_axes = list(dims_to_collapse) - if len(collapse_axes) == 1: + if len(dims_to_collapse) == 1: # Replace a "list of 1 axes" with just a number : This single-axis form is *required* by functions # like da.average (and np.average), if a 1d weights array is specified. - collapse_axes = collapse_axes[0] + collapse_axes: int | list[int] = dims_to_collapse[0] + else: + collapse_axes = list(dims_to_collapse) try: data_result = aggregator.lazy_aggregate( @@ -4263,15 +4437,23 @@ def collapsed(self, coords, aggregator, **kwargs): aggregator.update_metadata( collapsed_cube, - coords, + coordinates, axis=collapse_axis, _weights_units=getattr(weights_info, "units", None), **kwargs, ) - result = aggregator.post_process(collapsed_cube, data_result, coords, **kwargs) + result = aggregator.post_process( + collapsed_cube, data_result, coordinates, **kwargs + ) return result - def aggregated_by(self, coords, aggregator, climatological=False, **kwargs): + def aggregated_by( + self, + coords: str | AuxCoord | DimCoord | Iterable[str | AuxCoord | DimCoord], + aggregator: iris.analysis.Aggregator, + climatological: bool = False, + **kwargs, + ) -> Cube: """Perform aggregation over the cube given one or more "group coordinates". A "group coordinate" is a coordinate where repeating values represent a @@ -4297,17 +4479,17 @@ def aggregated_by(self, coords, aggregator, climatological=False, **kwargs): Parameters ---------- - coords : (list of coord names or :class:`iris.coords.Coord` instances) + coords : One or more coordinates over which group aggregation is to be performed. - aggregator : :class:`iris.analysis.Aggregator` + aggregator : Aggregator to be applied to each group. - climatological : bool, default=False + climatological : Indicates whether the output is expected to be climatological. For any aggregated time coord(s), this causes the climatological flag to be set and the point for each cell to equal its first bound, thereby preserving the time of year. - **kwargs : dict, optional + **kwargs : Aggregator and aggregation function keyword arguments. Returns @@ -4356,30 +4538,33 @@ def aggregated_by(self, coords, aggregator, climatological=False, **kwargs): kwargs["weights"] = weights_info.array groupby_coords = [] - dimension_to_groupby = None + dimension_to_groupby: int | None = None - coords = self._as_list_of_coords(coords) - for coord in sorted(coords, key=lambda coord: coord.metadata): + coordinates = self._as_list_of_coords(coords) + for coord in sorted(coordinates, key=lambda coord: coord.metadata): if coord.ndim > 1: msg = ( "Cannot aggregate_by coord %s as it is " "multidimensional." % coord.name() ) raise iris.exceptions.CoordinateMultiDimError(msg) - dimension = self.coord_dims(coord) - if not dimension: + dimensions = self.coord_dims(coord) + if not dimensions: msg = ( 'Cannot group-by the coordinate "%s", as its ' "dimension does not describe any data." % coord.name() ) raise iris.exceptions.CoordinateCollapseError(msg) if dimension_to_groupby is None: - dimension_to_groupby = dimension[0] - if dimension_to_groupby != dimension[0]: + dimension_to_groupby = dimensions[0] + if dimension_to_groupby != dimensions[0]: msg = "Cannot group-by coordinates over different dimensions." raise iris.exceptions.CoordinateCollapseError(msg) groupby_coords.append(coord) + if dimension_to_groupby is None: + raise ValueError("Unable to aggregate by an empty list of `coords`.") + # Check shape of weights. These must either match the shape of the cube # or be 1D (in this case, their length must be equal to the length of the # dimension we are aggregating over). @@ -4435,11 +4620,10 @@ def aggregated_by(self, coords, aggregator, climatological=False, **kwargs): aggregateby_cube = iris.util._strip_metadata_from_dims( self, [dimension_to_groupby] ) - key = [slice(None, None)] * self.ndim + key: list[slice | tuple[int, ...]] = [slice(None, None)] * self.ndim # Generate unique index tuple key to maintain monotonicity. key[dimension_to_groupby] = tuple(range(len(groupby))) - key = tuple(key) - aggregateby_cube = aggregateby_cube[key] + aggregateby_cube = aggregateby_cube[tuple(key)] for coord in groupby_coords + shared_coords: aggregateby_cube.remove_coord(coord) @@ -4464,19 +4648,17 @@ def aggregated_by(self, coords, aggregator, climatological=False, **kwargs): front_slice = (slice(None),) * dimension_to_groupby back_slice = (slice(None),) * (len(data_shape) - dimension_to_groupby - 1) - groupby_subarrs = map( - lambda groupby_slice: iris.util._slice_data_with_keys( + groupby_subarrs = ( + iris.util._slice_data_with_keys( input_data, front_slice + (groupby_slice,) + back_slice - )[1], - groupby.group(), + )[1] + for groupby_slice in groupby.group() ) if weights is not None: - groupby_subweights = map( - lambda groupby_slice: weights[ - front_slice + (groupby_slice,) + back_slice - ], - groupby.group(), + groupby_subweights = ( + weights[front_slice + (groupby_slice,) + back_slice] + for groupby_slice in groupby.group() ) else: groupby_subweights = (None for _ in range(len(groupby))) @@ -4485,7 +4667,7 @@ def aggregated_by(self, coords, aggregator, climatological=False, **kwargs): agg = iris.analysis.create_weighted_aggregator_fn( agg_method, axis=dimension_to_groupby, **kwargs ) - result = list(map(agg, groupby_subarrs, groupby_subweights)) + result = tuple(map(agg, groupby_subarrs, groupby_subweights)) # If weights are returned, "result" is a list of tuples (each tuple # contains two elements; the first is the aggregated data, the @@ -4493,12 +4675,13 @@ def aggregated_by(self, coords, aggregator, climatological=False, **kwargs): # (one for the aggregated data and one for the aggregated weights) # before combining the different slices. if return_weights: - result, weights_result = list(zip(*result)) + data_result, weights_result = list(zip(*result)) aggregateby_weights = _lazy.stack(weights_result, axis=dimension_to_groupby) else: + data_result = result aggregateby_weights = None - aggregateby_data = _lazy.stack(result, axis=dimension_to_groupby) + aggregateby_data = _lazy.stack(data_result, axis=dimension_to_groupby) # Ensure plain ndarray is output if plain ndarray was input. if ma.isMaskedArray(aggregateby_data) and not ma.isMaskedArray(input_data): aggregateby_data = ma.getdata(aggregateby_data) @@ -4512,9 +4695,9 @@ def aggregated_by(self, coords, aggregator, climatological=False, **kwargs): **kwargs, ) # Replace the appropriate coordinates within the aggregate-by cube. - (dim_coord,) = self.coords( - dimensions=dimension_to_groupby, dim_coords=True - ) or [None] + dim_coords = self.coords(dimensions=dimension_to_groupby, dim_coords=True) + dim_coord = dim_coords[0] if dim_coords else None + for coord in groupby.coords: new_coord = coord.copy() @@ -4548,12 +4731,18 @@ def aggregated_by(self, coords, aggregator, climatological=False, **kwargs): else: data_result = (aggregateby_data, aggregateby_weights) aggregateby_cube = aggregator.post_process( - aggregateby_cube, data_result, coords, **kwargs + aggregateby_cube, data_result, coordinates, **kwargs ) return aggregateby_cube - def rolling_window(self, coord, aggregator, window, **kwargs): + def rolling_window( + self, + coord: str | AuxCoord | DimCoord, + aggregator: iris.analysis.Aggregator, + window: int, + **kwargs, + ) -> Cube: """Perform rolling window aggregation on a cube. Perform rolling window aggregation on a cube given a coordinate, an @@ -4561,14 +4750,14 @@ def rolling_window(self, coord, aggregator, window, **kwargs): Parameters ---------- - coord : str or :class:`iris.coords.Coord` + coord : The coordinate over which to perform the rolling window aggregation. - aggregator : :class:`iris.analysis.Aggregator` + aggregator : Aggregator to be applied to the data. - window : int + window : Size of window to use. - **kwargs : dict, optional + **kwargs : Aggregator and aggregation function keyword arguments. The weights argument to the aggregator, if any, should be a 1d array, cube, or (names of) :meth:`~iris.cube.Cube.coords`, @@ -4660,13 +4849,13 @@ def rolling_window(self, coord, aggregator, window, **kwargs): if coord.ndim > 1: raise iris.exceptions.CoordinateMultiDimError(coord) - dimension = self.coord_dims(coord) - if len(dimension) != 1: + dimensions = self.coord_dims(coord) + if len(dimensions) != 1: raise iris.exceptions.CoordinateCollapseError( 'Cannot perform rolling window with coordinate "%s", ' "must map to one data dimension." % coord.name() ) - dimension = dimension[0] + dimension = dimensions[0] # Use indexing to get a result-cube of the correct shape. # NB. This indexes the data array which is wasted work. @@ -4757,7 +4946,12 @@ def rolling_window(self, coord, aggregator, window, **kwargs): result = aggregator.post_process(new_cube, data_result, [coord], **kwargs) return result - def interpolate(self, sample_points, scheme, collapse_scalar=True): + def interpolate( + self, + sample_points: Iterable[tuple[AuxCoord | DimCoord | str, np.typing.ArrayLike]], + scheme: iris.analysis.InterpolationScheme, + collapse_scalar: bool = True, + ) -> Cube: """Interpolate from this :class:`~iris.cube.Cube` to the given sample points. Interpolate from this :class:`~iris.cube.Cube` to the given @@ -4841,10 +5035,10 @@ def interpolate(self, sample_points, scheme, collapse_scalar=True): """ coords, points = zip(*sample_points) - interp = scheme.interpolator(self, coords) + interp = scheme.interpolator(self, coords) # type: ignore[arg-type] return interp(points, collapse_scalar=collapse_scalar) - def regrid(self, grid, scheme): + def regrid(self, grid: Cube, scheme: iris.analysis.RegriddingScheme) -> Cube: r"""Regrid this :class:`~iris.cube.Cube` on to the given target `grid`. Regrid this :class:`~iris.cube.Cube` on to the given target `grid` diff --git a/lib/iris/experimental/ugrid.py b/lib/iris/experimental/ugrid.py index 6e036ad96e..7db26ca26b 100644 --- a/lib/iris/experimental/ugrid.py +++ b/lib/iris/experimental/ugrid.py @@ -9,7 +9,7 @@ Notes ----- -This import path alios is provided for backwards compatibility, but will be removed +This import path alias is provided for backwards compatibility, but will be removed in a future release : Please re-write code to import from the new module path. This legacy import module will be removed in a future release. diff --git a/lib/iris/fileformats/_ff.py b/lib/iris/fileformats/_ff.py index 35b4f65bb7..b6b45b8b3c 100644 --- a/lib/iris/fileformats/_ff.py +++ b/lib/iris/fileformats/_ff.py @@ -5,6 +5,7 @@ """Provides UK Met Office Fields File (FF) format specific capabilities.""" import os +from typing import Any import warnings import numpy as np @@ -370,9 +371,22 @@ def __init__(self, filename, word_depth=DEFAULT_FF_WORD_DEPTH): setattr(self, elem, res) def __str__(self): + def _str_tuple(to_print: Any): + """Print NumPy scalars within tuples as numbers, not np objects. + + E.g. ``lookup_table`` is a tuple of NumPy scalars. + NumPy v2 by default prints ``np.int32(1)`` instead of ``1`` when + printing an iterable of scalars. + """ + if isinstance(to_print, tuple): + result = "(" + ", ".join([str(i) for i in to_print]) + ")" + else: + result = str(to_print) + return result + attributes = [] for name, _ in FF_HEADER: - attributes.append(" {}: {}".format(name, getattr(self, name))) + attributes.append(f" {name}: {_str_tuple(getattr(self, name))}") return "FF Header:\n" + "\n".join(attributes) def __repr__(self): diff --git a/lib/iris/fileformats/_nc_load_rules/helpers.py b/lib/iris/fileformats/_nc_load_rules/helpers.py index 5aed21bebf..faf40ad210 100644 --- a/lib/iris/fileformats/_nc_load_rules/helpers.py +++ b/lib/iris/fileformats/_nc_load_rules/helpers.py @@ -202,11 +202,11 @@ _CM_INTERVAL = "interval" _CM_METHOD = "method" _CM_NAME = "name" -_CM_PARSE_NAME = re.compile(r"([\w_]+\s*?:\s+)+") +_CM_PARSE_NAME = re.compile(r"([\w_]+\s*?:\s*)+") _CM_PARSE = re.compile( r""" - (?P([\w_]+\s*?:\s+)+) - (?P[\w_\s]+(?![\w_]*\s*?:))\s* + (?P([\w_]+\s*?:\s*)+) + (?P[^\s][\w_\s]+(?![\w_]*\s*?:))\s* (?: \(\s* (?P.+) @@ -296,6 +296,12 @@ def _split_cell_methods(nc_cell_methods: str) -> List[re.Match]: for m in _CM_PARSE_NAME.finditer(nc_cell_methods): name_start_inds.append(m.start()) + # No matches? Must be malformed cell_method string; warn and return + if not name_start_inds: + msg = f"Failed to parse cell method string: {nc_cell_methods}" + warnings.warn(msg, category=iris.warnings.IrisCfLoadWarning, stacklevel=2) + return [] + # Remove those that fall inside brackets bracket_depth = 0 for ind, cha in enumerate(nc_cell_methods): diff --git a/lib/iris/fileformats/cf.py b/lib/iris/fileformats/cf.py index 024bcb6f1d..e7b0d8063e 100644 --- a/lib/iris/fileformats/cf.py +++ b/lib/iris/fileformats/cf.py @@ -18,7 +18,7 @@ from collections.abc import Iterable, MutableMapping import os import re -from typing import ClassVar +from typing import ClassVar, Optional import warnings import numpy as np @@ -1448,6 +1448,35 @@ def _build(cf_variable): coordinate_names = list(self.cf_group.coordinates.keys()) cf_group = self.CFGroup() + def _span_check( + var_name: str, via_formula_terms: Optional[str] = None + ) -> None: + """Sanity check dimensionality.""" + var = self.cf_group[var_name] + # No span check is necessary if variable is attached to a mesh. + if is_mesh_var or var.spans(cf_variable): + cf_group[var_name] = var + else: + # Register the ignored variable. + # N.B. 'ignored' variable from enclosing scope. + ignored.add(var_name) + + text_formula = text_via = "" + if via_formula_terms: + text_formula = " formula terms" + text_via = f" via variable {via_formula_terms}" + + message = ( + f"Ignoring{text_formula} variable {var_name} " + f"referenced by variable {cf_variable.cf_name}" + f"{text_via}: Dimensions {var.dimensions} do not span " + f"{cf_variable.dimensions}" + ) + warnings.warn( + message, + category=iris.warnings.IrisCfNonSpanningVarWarning, + ) + # Build CF variable relationships. for variable_type in self._variable_types: ignore = [] @@ -1466,28 +1495,8 @@ def _build(cf_variable): warn=False, ) # Sanity check dimensionality coverage. - for cf_name, cf_var in match.items(): - # No span check is necessary if variable is attached to a mesh. - if is_mesh_var or cf_var.spans(cf_variable): - cf_group[cf_name] = self.cf_group[cf_name] - else: - # Register the ignored variable. - # N.B. 'ignored' variable from enclosing scope. - ignored.add(cf_name) - msg = ( - "Ignoring variable {!r} referenced " - "by variable {!r}: Dimensions {!r} do not " - "span {!r}".format( - cf_name, - cf_variable.cf_name, - cf_var.dimensions, - cf_variable.dimensions, - ) - ) - warnings.warn( - msg, - category=iris.warnings.IrisCfNonSpanningVarWarning, - ) + for cf_name in match: + _span_check(cf_name) # Build CF data variable relationships. if isinstance(cf_variable, CFDataVariable): @@ -1514,29 +1523,7 @@ def _build(cf_variable): for cf_var in self.cf_group.formula_terms.values(): for cf_root in cf_var.cf_terms_by_root: if cf_root in cf_group and cf_var.cf_name not in cf_group: - # Sanity check dimensionality. - if cf_var.spans(cf_variable): - cf_group[cf_var.cf_name] = cf_var - else: - # Register the ignored variable. - # N.B. 'ignored' variable from enclosing scope. - ignored.add(cf_var.cf_name) - msg = ( - "Ignoring formula terms variable {!r} " - "referenced by data variable {!r} via " - "variable {!r}: Dimensions {!r} do not " - "span {!r}".format( - cf_var.cf_name, - cf_variable.cf_name, - cf_root, - cf_var.dimensions, - cf_variable.dimensions, - ) - ) - warnings.warn( - msg, - category=iris.warnings.IrisCfNonSpanningVarWarning, - ) + _span_check(cf_var.cf_name, cf_root) # Add the CF group to the variable. cf_variable.cf_group = cf_group diff --git a/lib/iris/fileformats/netcdf/saver.py b/lib/iris/fileformats/netcdf/saver.py index cfc69143ae..8aa551be57 100644 --- a/lib/iris/fileformats/netcdf/saver.py +++ b/lib/iris/fileformats/netcdf/saver.py @@ -1387,9 +1387,13 @@ def _ensure_valid_dtype(self, values, src_name, src_object): val_min, val_max = (values.min(), values.max()) if is_lazy_data(values): val_min, val_max = _co_realise_lazy_arrays([val_min, val_max]) + # NumPy will inherit values.dtype even if the scalar numbers work + # with a smaller type. + min_dtype = np.promote_types( + *[np.min_scalar_type(m) for m in (val_min, val_max)] + ) # Cast to an integer type supported by netCDF3. - can_cast = all([np.can_cast(m, np.int32) for m in (val_min, val_max)]) - if not can_cast: + if not np.can_cast(min_dtype, np.int32): msg = ( "The data type of {} {!r} is not supported by {} and" " its values cannot be safely cast to a supported" diff --git a/lib/iris/fileformats/nimrod_load_rules.py b/lib/iris/fileformats/nimrod_load_rules.py index 2c0b4334db..4b3987003a 100644 --- a/lib/iris/fileformats/nimrod_load_rules.py +++ b/lib/iris/fileformats/nimrod_load_rules.py @@ -126,10 +126,11 @@ def units(cube, field): "n/a": "1", } + dtype_original = cube.dtype field_units = remove_unprintable_chars(field.units) if field_units == "m/2-25k": # Handle strange visibility units - cube.data = (cube.data.astype(np.float32) + 25000.0) * 2 + cube.data = (cube.data + 25000.0) * 2 field_units = "m" if "*" in field_units: # Split into unit string and integer @@ -137,31 +138,29 @@ def units(cube, field): if "^" in unit_list[1]: # Split out magnitude unit_sublist = unit_list[1].split("^") - cube.data = cube.data.astype(np.float32) / float(unit_sublist[0]) ** float( - unit_sublist[1] - ) + cube.data = cube.data / float(unit_sublist[0]) ** float(unit_sublist[1]) else: - cube.data = cube.data.astype(np.float32) / float(unit_list[1]) + cube.data = cube.data / float(unit_list[1]) field_units = unit_list[0] if "ug/m3E1" in field_units: # Split into unit string and integer unit_list = field_units.split("E") - cube.data = cube.data.astype(np.float32) / 10.0 + cube.data = cube.data / 10.0 field_units = unit_list[0] if field_units == "%": # Convert any percentages into fraction field_units = "1" - cube.data = cube.data.astype(np.float32) / 100.0 + cube.data = cube.data / 100.0 if field_units == "oktas": field_units = "1" - cube.data = cube.data.astype(np.float32) / 8.0 + cube.data = cube.data / 8.0 if field_units == "dBZ": # cf_units doesn't recognise decibels (dBZ), but does know BZ field_units = "BZ" - cube.data = cube.data.astype(np.float32) / 10.0 + cube.data = cube.data / 10.0 if field_units == "g/Kg": field_units = "kg/kg" - cube.data = cube.data.astype(np.float32) / 1000.0 + cube.data = cube.data / 1000.0 if not field_units: if field.field_code == 8: # Relative Humidity data are unitless, but not "unknown" @@ -175,6 +174,14 @@ def units(cube, field): # Deal with the case where the units are of the form '/unit' eg # '/second' in the Nimrod file. This converts to the form unit^-1 field_units = field_units[1:] + "^-1" + + if cube.dtype != dtype_original: + # Original development logic: if any arithmetic takes place, ensure + # the data type is float32 (starts as an int). Unknown why. + # Automatic casting is returning inconsistent types when masks are + # involved, so the new logic is to do the casting as the final step. + cube.data = cube.data.astype(np.float32) + try: cube.units = field_units except ValueError: diff --git a/lib/iris/fileformats/pp.py b/lib/iris/fileformats/pp.py index c2660d022c..ce92d4456e 100644 --- a/lib/iris/fileformats/pp.py +++ b/lib/iris/fileformats/pp.py @@ -11,6 +11,7 @@ import os import re import struct +from typing import Any import warnings import cf_units @@ -950,6 +951,21 @@ def t2(self): def __repr__(self): """Return a string representation of the PP field.""" + + def _str_tuple(to_print: Any): + """Print NumPy scalars within tuples as numbers, not np objects. + + E.g. ``lbuser`` is a tuple of NumPy scalars. + + NumPy v2 by default prints ``np.int32(1)`` instead of ``1`` when + printing an iterable of scalars. + """ + if isinstance(to_print, tuple): + result = "(" + ", ".join([str(i) for i in to_print]) + ")" + else: + result = str(to_print) + return result + # Define an ordering on the basic header names attribute_priority_lookup = {name: loc[0] for name, loc in self.HEADER_DEFN} @@ -975,9 +991,8 @@ def __repr__(self): ), ) - return ( - "PP Field" + "".join(["\n %s: %s" % (k, v) for k, v in attributes]) + "\n" - ) + contents = "".join([f"\n {k}: {_str_tuple(v)}" for k, v in attributes]) + return f"PP Field{contents}\n" @property def stash(self): @@ -1178,7 +1193,7 @@ def save(self, file_handle): data.dtype = data.dtype.newbyteorder(">") # Create the arrays which will hold the header information - lb = np.empty(shape=NUM_LONG_HEADERS, dtype=np.dtype(">u%d" % PP_WORD_DEPTH)) + lb = np.empty(shape=NUM_LONG_HEADERS, dtype=np.dtype(">i%d" % PP_WORD_DEPTH)) b = np.empty(shape=NUM_FLOAT_HEADERS, dtype=np.dtype(">f%d" % PP_WORD_DEPTH)) # Fill in the header elements from the PPField diff --git a/lib/iris/fileformats/rules.py b/lib/iris/fileformats/rules.py index 8299021fb5..2a1a74f374 100644 --- a/lib/iris/fileformats/rules.py +++ b/lib/iris/fileformats/rules.py @@ -5,6 +5,7 @@ """Generalised mechanisms for metadata translation and cube construction.""" import collections +import threading import warnings import cf_units @@ -143,7 +144,11 @@ class _ReferenceError(Exception): def _dereference_args(factory, reference_targets, regrid_cache, cube): - """Convert all the arguments for a factory into concrete coordinates.""" + """Convert all the arguments for a factory into concrete coordinates. + + Note: where multiple reference fields define an additional dimension, this routine + returns a modified 'cube', with the necessary additional dimensions. + """ args = [] for arg in factory.args: if isinstance(arg, Reference): @@ -151,7 +156,7 @@ def _dereference_args(factory, reference_targets, regrid_cache, cube): src = reference_targets[arg.name].as_cube() # If necessary, regrid the reference cube to # match the grid of this cube. - src = _ensure_aligned(regrid_cache, src, cube) + src, cube = _ensure_aligned(regrid_cache, src, cube) if src is not None: new_coord = iris.coords.AuxCoord( src.data, @@ -178,7 +183,8 @@ def _dereference_args(factory, reference_targets, regrid_cache, cube): # If it wasn't a Reference, then arg is a dictionary # of keyword arguments for cube.coord(...). args.append(cube.coord(**arg)) - return args + + return args, cube def _regrid_to_target(src_cube, target_coords, target_cube): @@ -211,9 +217,9 @@ def _ensure_aligned(regrid_cache, src_cube, target_cube): # Check that each of src_cube's dim_coords matches up with a single # coord on target_cube. try: - target_coords = [] + target_dimcoords = [] for dim_coord in src_cube.dim_coords: - target_coords.append(target_cube.coord(dim_coord)) + target_dimcoords.append(target_cube.coord(dim_coord)) except iris.exceptions.CoordinateNotFoundError: # One of the src_cube's dim_coords didn't exist on the # target_cube... so we can't regrid (i.e. just return None). @@ -222,7 +228,32 @@ def _ensure_aligned(regrid_cache, src_cube, target_cube): # So we can use `iris.analysis.interpolate.linear()` later, # ensure each target coord is either a scalar or maps to a # single, distinct dimension. - target_dims = [target_cube.coord_dims(coord) for coord in target_coords] + # PP-MOD: first promote any scalar coords when needed as dims + for target_coord in target_dimcoords: + from iris import LOAD_POLICY + + if ( + not target_cube.coord_dims(target_coord) + and LOAD_POLICY.support_multiple_references + ): + # The chosen coord is not a dimcoord in the target (yet) + # Make it one with 'new_axis' + from iris.util import new_axis + + _MULTIREF_DETECTION.found_multiple_refs = True + # Include the other coords on that dim in the src : this means the + # src merge identifies which belong on that dim + # (e.g. 'forecast_period' along with 'time') + (src_dim,) = src_cube.coord_dims(target_coord) # should have 1 dim + promote_other_coords = [ + target_cube.coord(src_coord) + for src_coord in src_cube.coords(contains_dimension=src_dim) + if src_coord.name() != target_coord.name() + ] + target_cube = new_axis( + target_cube, target_coord, expand_extras=promote_other_coords + ) + target_dims = [target_cube.coord_dims(coord) for coord in target_dimcoords] target_dims = list(filter(None, target_dims)) unique_dims = set() for dims in target_dims: @@ -236,19 +267,19 @@ def _ensure_aligned(regrid_cache, src_cube, target_cube): grids, cubes = regrid_cache[cache_key] # 'grids' is a list of tuples of coordinates, so convert # the 'target_coords' list into a tuple to be consistent. - target_coords = tuple(target_coords) + target_dimcoords = tuple(target_dimcoords) try: # Look for this set of target coordinates in the cache. - i = grids.index(target_coords) + i = grids.index(target_dimcoords) result_cube = cubes[i] except ValueError: # Not already cached, so do the hard work of interpolating. - result_cube = _regrid_to_target(src_cube, target_coords, target_cube) + result_cube = _regrid_to_target(src_cube, target_dimcoords, target_cube) # Add it to the cache. - grids.append(target_coords) + grids.append(target_dimcoords) cubes.append(result_cube) - return result_cube + return result_cube, target_cube class Loader( @@ -331,7 +362,7 @@ def _resolve_factory_references( # across multiple result cubes. for factory in factories: try: - args = _dereference_args( + args, cube = _dereference_args( factory, concrete_reference_targets, regrid_cache, cube ) except _ReferenceError as e: @@ -345,6 +376,34 @@ def _resolve_factory_references( aux_factory = factory.factory_class(*args) cube.add_aux_factory(aux_factory) + # In the case of multiple references which vary on a new dimension + # (such as time-dependent orography or surface-pressure), the cube may get replaced + # by one with a new dimension. + # In that case we must update the factory so its dependencies are coords of the + # new cube. + cube_coord_ids = [ + id(coord) for coord, _ in cube._dim_coords_and_dims + cube._aux_coords_and_dims + ] + for factory in cube.aux_factories: + for name, dep in list(factory.dependencies.items()): + if dep and id(dep) not in cube_coord_ids: + factory.update(dep, cube.coord(dep)) + + return cube + + +class MultipleReferenceFieldDetector(threading.local): + def __init__(self): + self.found_multiple_refs = False + + +# A single global object (per thread) to record whether multiple reference fields +# (e.g. time-dependent orography, or surface pressure fields) have been detected during +# the latest load operation. +# This is used purely to implement the iris.LOAD_POLICY.multiref_triggers_concatenate +# functionality. +_MULTIREF_DETECTION = MultipleReferenceFieldDetector() + def _load_pairs_from_fields_and_filenames( fields_and_filenames, converter, user_callback_wrapper=None @@ -355,6 +414,7 @@ def _load_pairs_from_fields_and_filenames( # needs a filename associated with each field to support the load callback. concrete_reference_targets = {} results_needing_reference = [] + for field, filename in fields_and_filenames: # Convert the field to a Cube, passing down the 'converter' function. cube, factories, references = _make_cube(field, converter) @@ -383,7 +443,7 @@ def _load_pairs_from_fields_and_filenames( regrid_cache = {} for cube, factories, field in results_needing_reference: - _resolve_factory_references( + cube = _resolve_factory_references( cube, factories, concrete_reference_targets, regrid_cache ) yield (cube, field) diff --git a/lib/iris/io/format_picker.py b/lib/iris/io/format_picker.py index b1b93707c9..c885a55074 100644 --- a/lib/iris/io/format_picker.py +++ b/lib/iris/io/format_picker.py @@ -84,6 +84,19 @@ def __str__(self): ["%s" % format_spec for format_spec in self._format_specs] ) + def __eq__(self, other): + return self._format_specs == other._format_specs + + def copy(self): + """Return a copy of the format agent. + + Returns + ------- + FormatAgent + A copy of the format agent. + """ + return FormatAgent(self._format_specs.copy()) + def get_spec(self, basename, buffer_obj): """Pick the first FormatSpecification. diff --git a/lib/iris/mesh/components.py b/lib/iris/mesh/components.py index a5936388f8..ef7b7c3575 100644 --- a/lib/iris/mesh/components.py +++ b/lib/iris/mesh/components.py @@ -13,7 +13,7 @@ from collections import namedtuple from collections.abc import Container from contextlib import contextmanager -from typing import Iterable +from typing import Iterable, Literal import warnings from cf_units import Unit @@ -2649,6 +2649,9 @@ def face_node(self): return self._members["face_node_connectivity"] +Location = Literal["edge", "node", "face"] + + class MeshCoord(AuxCoord): """Geographic coordinate values of data on an unstructured mesh. @@ -2687,16 +2690,16 @@ class MeshCoord(AuxCoord): def __init__( self, - mesh, - location, - axis, + mesh: MeshXY, + location: Location, + axis: Literal["x", "y"], ): # Setup the metadata. self._metadata_manager = metadata_manager_factory(MeshCoordMetadata) # Validate and record the class-specific constructor args. if not isinstance(mesh, MeshXY): - msg = ( + msg = ( # type: ignore[unreachable] "'mesh' must be an " f"{MeshXY.__module__}.{MeshXY.__name__}, " f"got {mesh}." @@ -2801,7 +2804,7 @@ def mesh(self): return self._mesh @property - def location(self): + def location(self) -> Location: return self._metadata_manager.location @property diff --git a/lib/iris/mesh/utils.py b/lib/iris/mesh/utils.py index 28ecd37dce..3930fa3f1b 100644 --- a/lib/iris/mesh/utils.py +++ b/lib/iris/mesh/utils.py @@ -134,23 +134,23 @@ def recombine_submeshes( for i_dim in range(mesh_cube.ndim): if i_dim == mesh_dim: # mesh dim : look for index coords (by name) - full_coord = mesh_cube.coords( + full_coords = mesh_cube.coords( name_or_coord=index_coord_name, dimensions=(i_dim,) ) - sub_coord = cube.coords( + sub_coords = cube.coords( name_or_coord=index_coord_name, dimensions=(i_dim,) ) else: # non-mesh dims : look for dim-coords (only) - full_coord = mesh_cube.coords(dim_coords=True, dimensions=(i_dim,)) - sub_coord = cube.coords(dim_coords=True, dimensions=(i_dim,)) + full_coords = mesh_cube.coords(dim_coords=True, dimensions=(i_dim,)) + sub_coords = cube.coords(dim_coords=True, dimensions=(i_dim,)) - if full_coord: - (full_coord,) = full_coord + if full_coords: + (full_coord,) = full_coords full_dimname = full_coord.name() full_metadata = full_coord.metadata._replace(var_name=None) - if sub_coord: - (sub_coord,) = sub_coord + if sub_coords: + (sub_coord,) = sub_coords sub_dimname = sub_coord.name() sub_metadata = sub_coord.metadata._replace(var_name=None) @@ -158,18 +158,18 @@ def recombine_submeshes( # N.B. checks for mesh- and non-mesh-dims are different if i_dim != mesh_dim: # i_dim == mesh_dim : checks for non-mesh dims - if full_coord and not sub_coord: + if full_coords and not sub_coords: err = ( f"{sub_str} has no dim-coord for dimension " f"{i_dim}, to match the 'mesh_cube' dimension " f'"{full_dimname}".' ) - elif sub_coord and not full_coord: + elif sub_coords and not full_coords: err = ( f'{sub_str} has a dim-coord "{sub_dimname}" for ' f"dimension {i_dim}, but 'mesh_cube' has none." ) - elif sub_coord != full_coord: + elif sub_coords != full_coords: err = ( f'{sub_str} has a dim-coord "{sub_dimname}" for ' f"dimension {i_dim}, which does not match that " @@ -177,13 +177,13 @@ def recombine_submeshes( ) else: # i_dim == mesh_dim : different rules for this one - if not sub_coord: + if not sub_coords: # Must have an index coord on the mesh dimension err = ( f'{sub_str} has no "{index_coord_name}" coord on ' f"the mesh dimension (dimension {mesh_dim})." ) - elif full_coord and sub_metadata != full_metadata: + elif full_coords and sub_metadata != full_metadata: # May *not* have full-cube index, but if so it must match err = ( f"{sub_str} has an index coord " diff --git a/lib/iris/pandas.py b/lib/iris/pandas.py index dd0f9fec89..78669eceb3 100644 --- a/lib/iris/pandas.py +++ b/lib/iris/pandas.py @@ -173,7 +173,7 @@ def as_cube( # 1.6 doesn't. Since we don't care about preserving the order we can # just force it back to C-order.) order = "C" if copy else "A" - data = np.array(pandas_array, copy=copy, order=order) + data = np.array(pandas_array.values, copy=copy, order=order) cube = Cube(np.ma.masked_invalid(data, copy=False)) _add_iris_coord(cube, "index", pandas_array.index, 0, calendars.get(0, None)) if pandas_array.ndim == 2: @@ -308,7 +308,7 @@ def as_cubes( Pandas uses ``NaN`` rather than masking data. Converted :class:`~iris.cube.Cube` can be masked in downstream user code : - >>> my_series = Series([300, np.NaN, 302], name="air_temperature") + >>> my_series = Series([300, np.nan, 302], name="air_temperature") >>> converted_cube = as_cubes(my_series)[0] >>> print(converted_cube.data) [300. nan 302.] diff --git a/lib/iris/plot.py b/lib/iris/plot.py index 8f5e074084..7d9812d11c 100644 --- a/lib/iris/plot.py +++ b/lib/iris/plot.py @@ -12,6 +12,7 @@ import datetime import warnings +import cartopy import cartopy.crs as ccrs from cartopy.geodesic import Geodesic import cartopy.mpl.geoaxes @@ -25,6 +26,7 @@ import matplotlib.transforms as mpl_transforms import numpy as np import numpy.ma as ma +from packaging.version import Version import iris.analysis.cartography as cartography import iris.coord_systems @@ -44,8 +46,9 @@ class _GeoAxesPatched(cartopy.mpl.geoaxes.GeoAxes): - # TODO: see cartopy#2390 - # Remove this once the bug is addressed in a Cartopy release. + # Workaround for a bug where titles collide with axis labels (cartopy#2390) + # Bug is only present in Cartopy v0.23, so this will only be invoked for + # that version. def _draw_preprocess(self, renderer): super()._draw_preprocess(renderer) @@ -57,7 +60,9 @@ def _draw_preprocess(self, renderer): artist._draw_gridliner(renderer=renderer) -cartopy.mpl.geoaxes.GeoAxes = _GeoAxesPatched +cartopy_version = Version(cartopy.__version__) +if cartopy_version.major == 0 and cartopy_version.minor == 23: + cartopy.mpl.geoaxes.GeoAxes = _GeoAxesPatched def _get_plot_defn_custom_coords_picked(cube, coords, mode, ndims=2): diff --git a/lib/iris/quickplot.py b/lib/iris/quickplot.py index b7d6e53f84..c1ca7f733f 100644 --- a/lib/iris/quickplot.py +++ b/lib/iris/quickplot.py @@ -48,14 +48,15 @@ def _title(cube_or_coord, with_units): return title -def _label(cube, mode, result=None, ndims=2, coords=None, axes=None): +def _label(cube, mode, result=None, ndims=2, coords=None, axes=None, colorbar=True): """Put labels on the current plot using the given cube.""" if axes is None: axes = plt.gca() axes.set_title(_title(cube, with_units=False)) - if result is not None: + # optional colorbar + if colorbar and result is not None: draw_edges = mode == iris.coords.POINT_MODE bar = plt.colorbar( result, ax=axes, orientation="horizontal", drawedges=draw_edges @@ -89,12 +90,16 @@ def _label(cube, mode, result=None, ndims=2, coords=None, axes=None): raise ValueError(msg) -def _label_with_bounds(cube, result=None, ndims=2, coords=None, axes=None): - _label(cube, iris.coords.BOUND_MODE, result, ndims, coords, axes) +def _label_with_bounds( + cube, result=None, ndims=2, coords=None, axes=None, colorbar=True +): + _label(cube, iris.coords.BOUND_MODE, result, ndims, coords, axes, colorbar) -def _label_with_points(cube, result=None, ndims=2, coords=None, axes=None): - _label(cube, iris.coords.POINT_MODE, result, ndims, coords, axes) +def _label_with_points( + cube, result=None, ndims=2, coords=None, axes=None, colorbar=True +): + _label(cube, iris.coords.POINT_MODE, result, ndims, coords, axes, colorbar) def _get_titles(u_object, v_object): @@ -181,6 +186,11 @@ def contourf(cube, *args, **kwargs): contour(cube, V) + Keywords + -------- + colorbar : bool, default=True + If True, an appropriate colorbar will be added to the plot. + See :func:`iris.plot.contourf` for details of valid keyword arguments. Notes @@ -190,8 +200,9 @@ def contourf(cube, *args, **kwargs): """ coords = kwargs.get("coords") axes = kwargs.get("axes") + colorbar = kwargs.pop("colorbar", True) result = iplt.contourf(cube, *args, **kwargs) - _label_with_points(cube, result, coords=coords, axes=axes) + _label_with_points(cube, result, coords=coords, axes=axes, colorbar=colorbar) return result @@ -229,6 +240,11 @@ def outline(cube, coords=None, color="k", linewidth=None, axes=None): def pcolor(cube, *args, **kwargs): """Draw a labelled pseudocolor plot based on the given Cube. + Keywords + -------- + colorbar : bool, default=True + If True, an appropriate colorbar will be added to the plot. + See :func:`iris.plot.pcolor` for details of valid keyword arguments. Notes @@ -238,14 +254,20 @@ def pcolor(cube, *args, **kwargs): """ coords = kwargs.get("coords") axes = kwargs.get("axes") + colorbar = kwargs.pop("colorbar", True) result = iplt.pcolor(cube, *args, **kwargs) - _label_with_bounds(cube, result, coords=coords, axes=axes) + _label_with_bounds(cube, result, coords=coords, axes=axes, colorbar=colorbar) return result def pcolormesh(cube, *args, **kwargs): """Draw a labelled pseudocolour plot based on the given Cube. + Keywords + -------- + colorbar : bool, default=True + If True, an appropriate colorbar will be added to the plot. + See :func:`iris.plot.pcolormesh` for details of valid keyword arguments. Notes @@ -256,8 +278,9 @@ def pcolormesh(cube, *args, **kwargs): """ coords = kwargs.get("coords") axes = kwargs.get("axes") + colorbar = kwargs.pop("colorbar", True) result = iplt.pcolormesh(cube, *args, **kwargs) - _label_with_bounds(cube, result, coords=coords, axes=axes) + _label_with_bounds(cube, result, coords=coords, axes=axes, colorbar=colorbar) return result diff --git a/lib/iris/tests/__init__.py b/lib/iris/tests/__init__.py index 7c6f578a5f..a2824f90c2 100644 --- a/lib/iris/tests/__init__.py +++ b/lib/iris/tests/__init__.py @@ -548,9 +548,7 @@ def assertRepr(self, obj, reference_filename): def _check_same(self, item, reference_path, type_comparison_name="CML"): if self._check_reference_file(reference_path): with open(reference_path, "rb") as reference_fh: - reference = "".join( - part.decode("utf-8") for part in reference_fh.readlines() - ) + reference = "".join(part.decode("utf-8") for part in reference_fh) self._assert_str_same(reference, item, reference_path, type_comparison_name) else: self._ensure_folder(reference_path) diff --git a/lib/iris/tests/experimental/regrid/test_regrid_area_weighted_rectilinear_src_and_grid.py b/lib/iris/tests/experimental/regrid/test_regrid_area_weighted_rectilinear_src_and_grid.py index 68fa47f25c..0727b3c36e 100644 --- a/lib/iris/tests/experimental/regrid/test_regrid_area_weighted_rectilinear_src_and_grid.py +++ b/lib/iris/tests/experimental/regrid/test_regrid_area_weighted_rectilinear_src_and_grid.py @@ -319,7 +319,7 @@ def test_regrid_reorder_axis(self): dest = _resampled_grid(self.realistic_cube[0, 0, :3, :2], 3, 3) res = regrid_area_weighted(src, dest) self.assertArrayShapeStats(src, (4, 3, 2), 288.08868, 0.008262919) - self.assertArrayShapeStats(res, (4, 9, 6), 288.08865, 0.00826281) + self.assertArrayShapeStats(res, (4, 9, 6), 288.0886, 0.008271061) # Reshape src so that the coords are ordered [x, z, y], # the mean and std statistics should be the same data = np.moveaxis(src.data.copy(), 2, 0) @@ -329,7 +329,7 @@ def test_regrid_reorder_axis(self): src.add_dim_coord(lon, 0) res = regrid_area_weighted(src, dest) self.assertArrayShapeStats(src, (2, 4, 3), 288.08868, 0.008262919) - self.assertArrayShapeStats(res, (6, 4, 9), 288.08865, 0.00826281) + self.assertArrayShapeStats(res, (6, 4, 9), 288.0886, 0.008271061) # Reshape src so that the coords are ordered [y, x, z], # the mean and std statistics should be the same data = np.moveaxis(src.data.copy(), 2, 0) @@ -340,7 +340,7 @@ def test_regrid_reorder_axis(self): dest = _resampled_grid(self.realistic_cube[0, 0, :3, :2], 3, 3) res = regrid_area_weighted(src, dest) self.assertArrayShapeStats(src, (3, 2, 4), 288.08868, 0.008262919) - self.assertArrayShapeStats(res, (9, 6, 4), 288.08865, 0.00826281) + self.assertArrayShapeStats(res, (9, 6, 4), 288.0886, 0.008271061) def test_regrid_lon_to_half_res(self): src = self.simple_cube diff --git a/lib/iris/tests/integration/fast_load/test_fast_load.py b/lib/iris/tests/integration/fast_load/test_fast_load.py index 41893ac948..239af35925 100644 --- a/lib/iris/tests/integration/fast_load/test_fast_load.py +++ b/lib/iris/tests/integration/fast_load/test_fast_load.py @@ -375,7 +375,7 @@ def callback(cube, collation, filename): # This is actually a NumPy int32, so honour that here. expected[0].attributes["LBVC"] = np.int32(8) else: - expected[0].attributes["A_LBVC"] = [8, 8] + expected[0].attributes["A_LBVC"] = [np.int32(8)] * 2 self.assertEqual(results, expected) diff --git a/lib/iris/tests/integration/test_netcdf__loadsaveattrs.py b/lib/iris/tests/integration/test_netcdf__loadsaveattrs.py index 1eeb5c4f0e..b89477bfe9 100644 --- a/lib/iris/tests/integration/test_netcdf__loadsaveattrs.py +++ b/lib/iris/tests/integration/test_netcdf__loadsaveattrs.py @@ -1022,7 +1022,7 @@ def test_16_localstyle(self, local_attr, origin_style, do_split): expected_result = [expect_global, expect_var] if do_split and origin_style == "input_global": # The result is simply the "other way around" - expected_result = expected_result[::-1] + expected_result.reverse() self.check_roundtrip_results(expected_result) @pytest.mark.parametrize("testcase", _MATRIX_TESTCASES[:max_param_attrs]) diff --git a/lib/iris/tests/integration/test_trajectory.py b/lib/iris/tests/integration/test_trajectory.py index aa4ce67a3b..f56970f9fa 100644 --- a/lib/iris/tests/integration/test_trajectory.py +++ b/lib/iris/tests/integration/test_trajectory.py @@ -11,6 +11,7 @@ import numpy as np import iris +from iris import LOAD_POLICY from iris._lazy_data import as_lazy_data from iris.analysis.trajectory import Trajectory from iris.analysis.trajectory import interpolate as traj_interpolate @@ -22,7 +23,9 @@ class TestColpex(tests.IrisTest): def setUp(self): # Load the COLPEX data => TZYX path = tests.get_data_path(["PP", "COLPEX", "theta_and_orog_subset.pp"]) - cube = iris.load_cube(path, "air_potential_temperature") + # Fix to ignore time-varying orography, for the purposes of these tests + with LOAD_POLICY.context(support_multiple_references=False): + cube = iris.load_cube(path, "air_potential_temperature") cube.coord("grid_latitude").bounds = None cube.coord("grid_longitude").bounds = None # TODO: Workaround until regrid can handle factories diff --git a/lib/iris/tests/integration/varying_references/__init__.py b/lib/iris/tests/integration/varying_references/__init__.py new file mode 100644 index 0000000000..3c37f02242 --- /dev/null +++ b/lib/iris/tests/integration/varying_references/__init__.py @@ -0,0 +1,12 @@ +# Copyright Iris contributors +# +# This file is part of Iris and is released under the BSD license. +# See LICENSE in the root of the repository for full licensing details. +"""Integration tests for loading with varying references. + +Practically, this mostly means loading from fields-based file formats such as PP and +GRIB, and when hybrid vertical coordinates which have time-varying reference fields. +E.G. hybrid height with time-varying orography, or hybrid-pressure with time-varying +surface pressure. + +""" diff --git a/lib/iris/tests/integration/varying_references/test_realdata_load.py b/lib/iris/tests/integration/varying_references/test_realdata_load.py new file mode 100644 index 0000000000..edf2b00824 --- /dev/null +++ b/lib/iris/tests/integration/varying_references/test_realdata_load.py @@ -0,0 +1,58 @@ +# Copyright Iris contributors +# +# This file is part of Iris and is released under the BSD license. +# See LICENSE in the root of the repository for full licensing details. +"""Test loading PP data with time-varying orography.""" + +import pytest + +import iris +from iris import LOAD_POLICY, sample_data_path + + +@pytest.fixture(params=["default", "recommended", "legacy"]) +def load_policy(request): + return request.param + + +def test_load_pp_timevarying_orography(load_policy): + testdata_dirpath = sample_data_path("time_varying_hybrid_height", "*.pp") + + with LOAD_POLICY.context(load_policy): + cubes = iris.load(testdata_dirpath) + + n_cubes = len(cubes) + if load_policy == "legacy": + # This doesn't merge fully: get a phenomenon cube for each reference field + assert n_cubes == 4 + else: + # Other load policies load with full merge, producing a 4D result. + assert n_cubes == 2 + phenom_cube = cubes.extract_cube("x_wind") + ref_cube = cubes.extract_cube("surface_altitude") + + cube_dims = [ + phenom_cube.coord(dim_coords=True, dimensions=i_dim).name() + for i_dim in range(phenom_cube.ndim) + ] + assert cube_dims == ["model_level_number", "time", "latitude", "longitude"] + + ref_coord = phenom_cube.coord("surface_altitude") + ref_coord_dims = [ + phenom_cube.coord(dim_coords=True, dimensions=i_dim).name() + for i_dim in phenom_cube.coord_dims(ref_coord) + ] + assert ref_coord_dims == ["time", "latitude", "longitude"] + + ref_cube_dims = [ + ref_cube.coord(dim_coords=True, dimensions=i_dim).name() + for i_dim in range(ref_cube.ndim) + ] + assert ref_cube_dims == ref_cube_dims + + derived_coord = phenom_cube.coord("altitude") + derived_dims = [ + phenom_cube.coord(dim_coords=True, dimensions=i_dim).name() + for i_dim in phenom_cube.coord_dims(derived_coord) + ] + assert derived_dims == ["model_level_number", "time", "latitude", "longitude"] diff --git a/lib/iris/tests/integration/varying_references/test_roundtrip_time_varying_references.py b/lib/iris/tests/integration/varying_references/test_roundtrip_time_varying_references.py new file mode 100644 index 0000000000..0ad4b5a941 --- /dev/null +++ b/lib/iris/tests/integration/varying_references/test_roundtrip_time_varying_references.py @@ -0,0 +1,341 @@ +# Copyright Iris contributors +# +# This file is part of Iris and is released under the BSD license. +# See LICENSE in the root of the repository for full licensing details. +"""Code to save and re-load hybrid vertical coordinates with variable reference fields. + +Tests all combinations of: + * file format: PP, GRIB and NetCDF + * reference fields: static (for legacy reference) and time-dependent + * hybrid coordinate fields: + * hybrid-height levels with orography, and + * hybrid-pressure levels with surface-pressure +""" + +import numpy as np +import pytest + +import iris +from iris import LOAD_POLICY +from iris.aux_factory import HybridHeightFactory, HybridPressureFactory +from iris.coord_systems import GeogCS +from iris.coords import AuxCoord, DimCoord +from iris.cube import Cube, CubeList +from iris.fileformats.pp import EARTH_RADIUS, STASH +from iris.util import new_axis + +try: + import iris_grib +except ImportError: + iris_grib = None + +# General test dimensions = (timepoints, levels, lats, lons) +NT, NZ, NY, NX = (3, 4, 5, 6) + + +def make_hybrid_z_testdata( + hybrid_zcoord_type="height", + make_reference_time_dependent=True, + include_reference_as_cube=False, +): + """Construct a realistic synthetic data cube with a hybrid vertical coordinate. + + Parameters + ---------- + hybrid_zcoord_type : string, default "height" + either "height" or "pressure" + make_reference_time_dependent : bool, default True + if True, the reference coord has dims (t, y, x), otherwise just (y, x) + include_reference_as_cube : bool, default False + if True, the result includes a separate cube of the reference values. + (Because this must be separately passed to save for the fields-based formats.) + + Returns + ------- + cubes + A list containing a cube with (t, z, y, x) dims and the appropriate + aux-factory. + Optionally, if "include_reference_as_cube" is True, an extra cube + containing the reference data is aldo returned. + + """ + crs = GeogCS(EARTH_RADIUS) + z_dim, t_dim, y_dim, x_dim = 0, 1, 2, 3 + co_t = DimCoord( + np.arange(NT, dtype=np.float32), + standard_name="time", + units="days since 2000-01-01", + ) + co_z = DimCoord( + np.arange(1, NZ + 1, dtype=np.int32), + standard_name="model_level_number", + units=1, + ) + co_y = DimCoord( + np.linspace(0, 120.0, NY, dtype=np.float32), + standard_name="latitude", + units="degrees", + coord_system=crs, + ) + co_x = DimCoord( + np.linspace(-30.0, 50.0, NX, dtype=np.float32), + standard_name="longitude", + units="degrees", + coord_system=crs, + ) + cube = Cube( + np.zeros((NZ, NT, NY, NX), dtype=np.float32), + standard_name="air_temperature", + units="K", + dim_coords_and_dims=zip((co_t, co_z, co_y, co_x), (t_dim, z_dim, y_dim, x_dim)), + ) + + delta_vals = np.linspace(200.0, 600, NZ, dtype=np.float32) + if hybrid_zcoord_type == "pressure": + co_delta = DimCoord(delta_vals, long_name="delta", units="hPa") + elif hybrid_zcoord_type == "height": + co_delta = DimCoord(delta_vals, long_name="level_height", units="m") + else: + raise ValueError(f"Unknown hybrid coordinate type: {hybrid_zcoord_type}") + + sigma_vals = np.linspace(0.2, 0.8, NZ, dtype=np.float32) + co_sigma = DimCoord(sigma_vals, long_name="sigma", units=1) + + # Note: will not save as HH to PP without bounds on delta+sigma + for coord in (co_delta, co_sigma): + coord.guess_bounds() + cube.add_aux_coord(co_delta, z_dim) + cube.add_aux_coord(co_sigma, z_dim) + + refdata = np.arange(NT * NY * NX, dtype=np.float32) + refdata = 1000.0 + refdata.reshape(NT, NY, NX) + if hybrid_zcoord_type == "pressure": + co_ref = AuxCoord( + refdata, + standard_name="surface_air_pressure", + units="hPa", + attributes={"STASH": STASH(model=1, section=0, item=409)}, + ) + elif hybrid_zcoord_type == "height": + co_ref = AuxCoord( + refdata, + standard_name="surface_altitude", + units="m", + attributes={"STASH": STASH(model=1, section=0, item=33)}, + ) + else: + raise ValueError(f"Unknown hybrid type: {hybrid_zcoord_type}") + + ref_dims = (t_dim, y_dim, x_dim) + if not make_reference_time_dependent: + co_ref = co_ref[0] + ref_dims = ref_dims[1:] + + cube.add_aux_coord(co_ref, ref_dims) + if hybrid_zcoord_type == "pressure": + factory = HybridPressureFactory( + sigma=co_sigma, delta=co_delta, surface_air_pressure=co_ref + ) + elif hybrid_zcoord_type == "height": + factory = HybridHeightFactory(sigma=co_sigma, delta=co_delta, orography=co_ref) + else: + raise ValueError(f"Unknown hybrid type: {hybrid_zcoord_type}") + + cube.add_aux_factory(factory) + + cubes = CubeList([cube]) + + if include_reference_as_cube: + ref_dimcoords = [ + cube.coord(dim_coords=True, dimensions=cube_refdim) + for cube_refdim in cube.coord_dims(co_ref) + ] + reference_cube = Cube( + co_ref.points, + standard_name=co_ref.standard_name, + units=co_ref.units, + dim_coords_and_dims=[ + (ref_dimcoord, i_refdim) + for i_refdim, ref_dimcoord in enumerate(ref_dimcoords) + ], + attributes=co_ref.attributes, + ) + if not reference_cube.coords("time"): + # Add a dummy time coordinate to non-time-dependent reference cube + # - mostly because otherwise it cannot be saved to GRIB format + # NOTE: we give this a different nominal time to any of the data : when + # there is only one reference field, it's recorded time value should be + # **ignored** by the loader + reference_cube.add_aux_coord( + DimCoord( + np.array(0, dtype=np.float32), + standard_name="time", + units="days since 1900-01-01", + ) + ) + cubes.append(reference_cube) + + return cubes + + +def check_expected(result_cubes, file_extension, time_dependence, zcoord_type): + assert len(result_cubes) == 2 + result_phenom = result_cubes.extract_cube("air_temperature") + + if zcoord_type == "pressure": + ref_coord_name = ref_cube_name = "surface_air_pressure" + if file_extension == "grib2": + ref_cube_name = "air_pressure" + elif zcoord_type == "height": + ref_coord_name = ref_cube_name = "surface_altitude" + else: + raise ValueError(f"Unknown hybrid coordinate type: {zcoord_type}") + + result_ref_cube = result_cubes.extract_cube(ref_cube_name) + result_ref_coord = result_phenom.coord(ref_coord_name) + + # Check that the reference cube and the coord are equivalent + assert result_ref_coord.shape == result_ref_cube.shape + assert np.array_equal(result_ref_cube.data, result_ref_coord.points) + assert not result_ref_coord.bounds # bounds are unused in our testcases + + # Check the expected phenomenon shape + if time_dependence == "static" and file_extension in ("pp", "grib2"): + phenom_shape = (NT, NZ, NY, NX) + else: + phenom_shape = (NZ, NT, NY, NX) + assert result_phenom.shape == phenom_shape + + # Check expected reference values against calculated values. + # This shows that the reference was correctly divided into 2d fields and + # reconstructed on load to match the original (for fields-based formats). + if time_dependence == "static": + ref_shape = (NY, NX) + else: + ref_shape = (NT, NY, NX) + ref_data = 1000.0 + np.arange(np.prod(ref_shape)).reshape(ref_shape) + if zcoord_type == "pressure" and file_extension == "grib2": + # values come back in Pa not hPa + ref_data *= 100.0 + assert np.array_equal(ref_data, result_ref_cube.data) + + +_file_formats = ["pp", "nc"] +if iris_grib: + _file_formats += ["grib2"] + + +@pytest.fixture(params=_file_formats) +def file_extension(request): + return request.param + + +@pytest.fixture(params=["static", "time_varying"]) +def time_dependence(request): + return request.param + + +@pytest.fixture(params=["height", "pressure"]) +def zcoord_type(request): + return request.param + + +@pytest.fixture(params=[f"{name}_policy" for name in LOAD_POLICY.SETTINGS]) +def load_policy(request): + return request.param + + +def test_roundtrip(file_extension, time_dependence, zcoord_type, load_policy, tmp_path): + if ( + load_policy == "legacy_policy" + and time_dependence == "time_varying" + and file_extension in ("pp", "grib2") + ): + pytest.skip("Testcase not supported in 'legacy' mode.") + + filepath = tmp_path / f"tmp.{file_extension}" + include_ref = file_extension in ("grib2", "pp") + is_time_dependent = time_dependence == "time_varying" + data = make_hybrid_z_testdata( + hybrid_zcoord_type=zcoord_type, + include_reference_as_cube=include_ref, + make_reference_time_dependent=is_time_dependent, + ) + + iris.save(data, filepath) + + policy_name = load_policy.split("_")[0] + with LOAD_POLICY.context(policy_name): + # NOTE: this is default, but "legacy" mode would fail + readback = iris.load(filepath) + + check_expected( + readback, + file_extension=file_extension, + time_dependence=time_dependence, + zcoord_type=zcoord_type, + ) + + +def test_split_netcdf_roundtrip(zcoord_type, load_policy, tmp_path): + # NetCDF special test : split the data into 2D slices (like "fields"), + # and save each to a different file. + policy_name = load_policy.split("_")[0] + reference_surface_name = { + "pressure": "surface_air_pressure", + "height": "surface_altitude", + }[zcoord_type] + + data = make_hybrid_z_testdata( + hybrid_zcoord_type=zcoord_type, + include_reference_as_cube=False, + make_reference_time_dependent=True, + ) + + # There is just 1 cube + (data,) = data # just 1 cube for netcdf, no separate reference cube + # split it into 2D YX "field" cubes + field_cubes = list(data.slices(("latitude", "longitude"))) + # Reinstate a length-1 "time" dimension in each cube. + field_cubes = [ + new_axis(field_cube, "time", expand_extras=[reference_surface_name]) + for field_cube in field_cubes + ] + # Save to 1 file per 'field_cube' + result_paths = [ + tmp_path / f"field_{i_field:02d}.nc" for i_field in range(len(field_cubes)) + ] + for field_cube, path in zip(field_cubes, result_paths): + iris.save(field_cube, path) + + # load back with the chosen policy. + with LOAD_POLICY.context(policy_name): + readback = iris.load(result_paths) + + n_cubes = len(readback) + n_datacubes = len(readback.extract("air_temperature")) + if policy_name == "legacy": + assert (n_cubes, n_datacubes) == (15, 3) + elif policy_name == "default": + assert (n_cubes, n_datacubes) == (15, 3) + elif policy_name == "recommended": + assert (n_cubes, n_datacubes) == (5, 1) + elif policy_name == "comprehensive": + assert (n_cubes, n_datacubes) == (5, 1) + else: + raise ValueError(f"unknown policy {policy_name!r}") + + if n_datacubes == 1: + check_expected( + CubeList( + [ + readback.extract_cube("air_temperature"), + # include only 1 of N (identical) reference cubes + # (all this would be easier if we could rely on load-cube ordering!) + readback.extract(reference_surface_name)[0], + ] + ), + file_extension=file_extension, + time_dependence=time_dependence, + zcoord_type=zcoord_type, + ) diff --git a/lib/iris/tests/results/cube_io/pickling/cubelist.cml b/lib/iris/tests/results/cube_io/pickling/cubelist.cml index c52486b1d0..6510b200e6 100644 --- a/lib/iris/tests/results/cube_io/pickling/cubelist.cml +++ b/lib/iris/tests/results/cube_io/pickling/cubelist.cml @@ -7,398 +7,2360 @@ - - + + + [[[32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + ..., + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ]], + + [[32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + ..., + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ]], + + [[32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + ..., + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ]], + + [[32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + ..., + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ]], + + [[32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + ..., + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ]], + + [[32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + ..., + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ]]], + + + [[[35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + ..., + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ]], + + [[35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + ..., + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ]], + + [[35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + ..., + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ]], + + [[35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + ..., + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ]], + + [[35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + ..., + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ]], + + [[35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + ..., + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ]]], + + + [[[40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + ..., + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ]], + + [[40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + ..., + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ]], + + [[40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + ..., + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ]], + + [[40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + ..., + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ]], + + [[40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + ..., + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ]], + + [[40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + ..., + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ]]]]" shape="(70, 6, 100, 100)" standard_name="altitude" units="Unit('m')" value_type="float32"> @@ -407,7 +2369,7 @@ - + @@ -436,7 +2398,7 @@ - + + + - - + + @@ -531,14 +2563,14 @@ - + - + diff --git a/lib/iris/tests/results/cube_io/pickling/single_cube.cml b/lib/iris/tests/results/cube_io/pickling/single_cube.cml index eb3e9d0112..aead0825ea 100644 --- a/lib/iris/tests/results/cube_io/pickling/single_cube.cml +++ b/lib/iris/tests/results/cube_io/pickling/single_cube.cml @@ -7,398 +7,2360 @@ - - + + + [[[32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + ..., + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ]], + + [[32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + ..., + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ]], + + [[32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + ..., + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ]], + + [[32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + ..., + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ]], + + [[32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + ..., + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ]], + + [[32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + ..., + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ], + [32192.732 , 32192.732 , 32192.732 , ..., + 32192.732 , 32192.732 , 32192.732 ]]], + + + [[[35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + ..., + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ]], + + [[35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + ..., + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ]], + + [[35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + ..., + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ]], + + [[35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + ..., + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ]], + + [[35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + ..., + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ]], + + [[35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + ..., + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ], + [35845.004 , 35845.004 , 35845.004 , ..., + 35845.004 , 35845.004 , 35845.004 ]]], + + + [[[40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + ..., + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ]], + + [[40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + ..., + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ]], + + [[40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + ..., + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ]], + + [[40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + ..., + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ]], + + [[40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + ..., + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ]], + + [[40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + ..., + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ], + [40000. , 40000. , 40000. , ..., + 40000. , 40000. , 40000. ]]]]" shape="(70, 6, 100, 100)" standard_name="altitude" units="Unit('m')" value_type="float32"> @@ -407,7 +2369,7 @@ - + @@ -436,7 +2398,7 @@ - + + + - - + + @@ -531,13 +2563,13 @@ - + - + diff --git a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lat_cross_section.cml b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lat_cross_section.cml index a0ed65bd29..9cfffb1342 100644 --- a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lat_cross_section.cml +++ b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lat_cross_section.cml @@ -6,54 +6,54 @@ - + [408.6315 , 447.17175], + [389.76822, 428.3958 ], + [363.19095, 401.94156]]]" id="9041e969" points="[[372.6527 , 377.71793, 374.74316, ..., + 323.53378, 304.47693, 277.62692], + [388.6133 , 393.66876, 390.69974, ..., + 339.5887 , 320.56845, 293.77 ], + [410.95926, 416.00113, 413.04007, ..., + 362.0666 , 343.0975 , 316.37115], + [439.6917 , 444.7161 , 441.76532, ..., + 390.96838, 372.065 , 345.4312 ], + [474.81216, 479.81528, 476.87698, ..., + 426.2954 , 407.4722 , 380.95132]]" shape="(5, 18)" standard_name="altitude" units="Unit('m')" value_type="float32"> @@ -68,29 +68,28 @@ - + @@ -122,11 +121,11 @@ 0.98717135]" shape="(5,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lat_cross_section.data.0.json b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lat_cross_section.data.0.json index 0c2b277ef0..138bdc6711 100644 --- a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lat_cross_section.data.0.json +++ b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lat_cross_section.data.0.json @@ -1 +1 @@ -{"std": 0.04919414967298508, "min": 287.8340148925781, "max": 288.0903625488281, "shape": [5, 18], "masked": false, "mean": 288.0065002441406} \ No newline at end of file +{"std": 0.04917990416288376, "min": 287.8338317871094, "max": 288.0901794433594, "shape": [5, 18], "masked": false, "mean": 288.00640869140625} \ No newline at end of file diff --git a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lon_cross_section.cml b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lon_cross_section.cml index efe8c37e2c..41cec442aa 100644 --- a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lon_cross_section.cml +++ b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/const_lon_cross_section.cml @@ -7,58 +7,58 @@ + [473.80203, 512.0405 ]]]" id="9041e969" points="[[389.81168, 380.65045, 338.00278, 295.5282 , + 278.92233, 280.889 , 327.14603, 342.9571 , + 368.6561 , 404.0448 , 416.55072, 389.3731 ], + [405.73932, 396.59567, 354.0299 , 311.6369 , + 295.06293, 297.02582, 343.194 , 358.9747 , + 384.62436, 419.9451 , 432.427 , 405.30157], + [428.03918, 418.92017, 376.4689 , 334.19 , + 317.6606 , 319.61823, 365.66217, 381.40042, + 406.98105, 442.20676, 454.65506, 427.6026 ], + [456.71246, 447.62503, 405.32083, 363.18835, + 346.71622, 348.66705, 394.5515 , 410.23526, + 435.72726, 470.83096, 483.23618, 456.2774 ], + [491.76077, 482.71185, 440.587 , 398.63315, + 382.23087, 384.17343, 429.86337, 445.4806 , + 470.86453, 505.8194 , 518.172 , 491.32755]]" shape="(5, 12)" standard_name="altitude" units="Unit('m')" value_type="float32"> @@ -68,8 +68,8 @@ - + -0.1185 , -0.11700001, -0.1155 , + -0.11400001, -0.11250001, -0.11100001]" shape="(12,)" standard_name="grid_latitude" units="Unit('degrees')" value_type="float32"> @@ -119,9 +119,9 @@ 0.98717135]" shape="(5,)" units="Unit('1')" value_type="float32"/> - + diff --git a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/hybridheight.cml b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/hybridheight.cml index efe348ffcb..f6bf6f86c2 100644 --- a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/hybridheight.cml +++ b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/hybridheight.cml @@ -6,327 +6,327 @@ - + [600.6252 , 589.63086, 574.741 , ..., + 351.04297, 348.4652 , 337.71198], + [584.26105, 574.0093 , 563.243 , ..., + 335.1148 , 333.11978, 329.5481 ], + [562.93256, 552.1968 , 545.87976, ..., + 329.34094, 327.58188, 325.25644]]]" shape="(5, 16, 21)" standard_name="altitude" units="Unit('m')" value_type="float32"> @@ -336,58 +336,57 @@ - + -0.1175625 , -0.1164375 , -0.11531251, + -0.11418751, -0.11306251, -0.11193752, + -0.11081252]" shape="(16,)" standard_name="grid_latitude" units="Unit('degrees')" value_type="float32"> - + @@ -419,19 +418,19 @@ 0.98717135]" shape="(5,)" units="Unit('1')" value_type="float32"/> - + [495.3127 , 484.17548, 469.0922 , ..., + 242.48706, 239.87582, 228.98285], + [478.73593, 468.3509 , 457.44473, ..., + 226.35193, 224.33096, 220.71288], + [457.13025, 446.25494, 439.85583, ..., + 220.50302, 218.7211 , 216.36543]]" shape="(16, 21)" standard_name="surface_altitude" units="Unit('m')" value_type="float32"/> diff --git a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/hybridheight.data.0.json b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/hybridheight.data.0.json index bdc0cad306..31ad377de6 100644 --- a/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/hybridheight.data.0.json +++ b/lib/iris/tests/results/experimental/regrid/regrid_area_weighted_rectilinear_src_and_grid/hybridheight.data.0.json @@ -1 +1 @@ -{"std": 0.10611984878778458, "min": 287.595703125, "max": 288.1650695800781, "shape": [2, 5, 16, 21], "masked": false, "mean": 287.91802978515625} \ No newline at end of file +{"std": 0.10612151026725769, "min": 287.5958251953125, "max": 288.1652526855469, "shape": [2, 5, 16, 21], "masked": false, "mean": 287.91802978515625} \ No newline at end of file diff --git a/lib/iris/tests/results/imagerepo.json b/lib/iris/tests/results/imagerepo.json index 69beacb848..42f7323201 100644 --- a/lib/iris/tests/results/imagerepo.json +++ b/lib/iris/tests/results/imagerepo.json @@ -2,7 +2,7 @@ "gallery_tests.test_plot_COP_1d.0": "aefec91c3601249cc9b3336dc4c8cdb31a64c6d997b3c0eccb5932d285e42f33", "gallery_tests.test_plot_COP_maps.0": "ea91789995668566913e43474adb6a917e8d947c4b46957ec6716a91958e6f81", "gallery_tests.test_plot_SOI_filtering.0": "fa56f295c5e0694a3c17a58d95e8da536233da99984c5af4c6739b4a9a444eb4", - "gallery_tests.test_plot_TEC.0": "e5a761b69a589a4bc46f9e48c65c6631ce61d1ce3982c13739b33193c0ee3f8c", + "gallery_tests.test_plot_TEC.0": "e59661969a589a49c06f1e69c27c66314e71c06e3986c1b739b33993c1df3fc4", "gallery_tests.test_plot_anomaly_log_colouring.0": "ec4464e384a39b13931a9b1c85696da968d5e6e63e26847bdbd399938d3c5a4c", "gallery_tests.test_plot_atlantic_profiles.0": "97c160f462a88f07203ebc77a1e36707e61f4e38d8f3d08a910597fc877cec58", "gallery_tests.test_plot_atlantic_profiles.1": "eeea64dd6ea8cd99991d1322b3741e2684571cd89995b3131f32a4765ee2a1cc", @@ -12,7 +12,7 @@ "gallery_tests.test_plot_custom_aggregation.0": "ee816f81917e907eb03ec73f856f7ac198d070186e90811f1be33ee1a57a6e18", "gallery_tests.test_plot_custom_file_loading.0": "fa81cb47845e34bc932797436cccc8343f11359b73523746c48c72d9d9b34da5", "gallery_tests.test_plot_deriving_phenomena.0": "ec97681793689768943c97e8926669d186e8c33f6c99c32e6b936c83d33e2c98", - "gallery_tests.test_plot_global_map.0": "fb997b958466846ed13e87467a997a898d66d17e2cc9906684696f99d3162e81", + "gallery_tests.test_plot_global_map.0": "fb997b958466846ed13e87467b997a898d66d1762cc9806684696f99d3162f81", "gallery_tests.test_plot_hovmoller.0": "eeb46cb4934b934bc07e974bc14b38949943c0fe3e94c17f6ea46cb4c07b3f00", "gallery_tests.test_plot_inset.0": "ebff6992b50096ad9267dac4d640949294924cdbc95d4b699d29952dcda46ed4", "gallery_tests.test_plot_lagged_ensemble.0": "bbbb31b1c44e64e4b1579b5b917133cecc61f146c414668eb1119b1bb197ce34", @@ -67,7 +67,7 @@ "iris.tests.test_mapping.TestLowLevel.test_params.1": "be21a71bc1de58e43a63a71b3e016061c1fe9b8c3e01a473847e5b94d1fb9ac3", "iris.tests.test_mapping.TestLowLevel.test_params.2": "fa81909f857e6520957e7acc7a8194716e31851e857e6ac281fe3ba17a81963f", "iris.tests.test_mapping.TestLowLevel.test_simple.0": "faa0e558855f9de7857a1ab16a85a51d36a1e55a854e58a5c13837096e8fe17a", - "iris.tests.test_mapping.TestMappingSubRegion.test_simple.0": "b9913d90c66eca6ec66ec2f3689195aecf5b2f00392cb3496495e21da4db6c92", + "iris.tests.test_mapping.TestMappingSubRegion.test_simple.0": "b9913d90c66eca6ec66ee2fb689195a6cf522f00392cb149648de69fa4db6c90", "iris.tests.test_mapping.TestUnmappable.test_simple.0": "fa81b54a817eca37817ec701857e3e64943e7bb41b806f996e817e006ee1b19b", "iris.tests.test_plot.Test1dFillBetween.test_coord_coord.0": "f31432798cebcd87723835b4a5c5c2dbcf139c6c8cf4730bf3c36d801e380378", "iris.tests.test_plot.Test1dFillBetween.test_coord_cube.0": "ea17352b92f0cbd42d6c8d25e59d36dc3a538d2bb2e42d26c6d2c2c8e4a1ce99", @@ -212,10 +212,13 @@ "iris.tests.test_quickplot.TestLabels.test_contourf.1": "bf802f85c17fc17fc07eb42ac17f3f929130c06e3f80c07f7aa02e85c07f3e81", "iris.tests.test_quickplot.TestLabels.test_contourf.2": "be816a95907ae508c17e955ac07f3fa0945bc07f3f80c07f3aa36f01c0ff3f80", "iris.tests.test_quickplot.TestLabels.test_contourf_nameless.0": "be816af5907ee508c17e955ac03f3f809419c07f3f80c07f3a8b6f81c0ff3f80", + "iris.tests.test_quickplot.TestLabels.test_contourf_no_colorbar.0": "bf80c391c17fe07ec07e1d1a917e3f42917879224834487c6e24ca3e2f87c2ff", "iris.tests.test_quickplot.TestLabels.test_map.0": "e85a634c86a597a793c9349b94b79969c396c95bcce69a64d938c9b039a58ca6", "iris.tests.test_quickplot.TestLabels.test_map.1": "e85a636c86a597a793c9349b94b69969c396c95bcce69a64d938c9b039a58ca6", "iris.tests.test_quickplot.TestLabels.test_pcolor.0": "eea16affc05ab500956e974ac53f3d80925ac03f2f81c07e3fa12da1c2fe3f80", + "iris.tests.test_quickplot.TestLabels.test_pcolor_no_colorbar.0": "eea1c2dac51ab54a905e2d20905a6da5d05e6da19d60dade6da1dade6da1d2d8", "iris.tests.test_quickplot.TestLabels.test_pcolormesh.0": "eea16affc05ab500956e974ac53f3d80925ac03f2f81c07e3fa12da1c2fe3f80", + "iris.tests.test_quickplot.TestLabels.test_pcolormesh_no_colorbar.0": "eea1c2dac51ab54a905e2d20905a6da1d05e6da19d60dade6da1dade6da1d2dc", "iris.tests.test_quickplot.TestLabels.test_pcolormesh_str_symbol.0": "eea16affc05ab500956e974ac53f3d80925ac03f3f80c07e3fa12d21c2ff3f80", "iris.tests.test_quickplot.TestPlotHist.test_horizontal.0": "b59cc3dadb433c24c4f166039438793591a7dbdcbcdc9ccc68c697a91b139131", "iris.tests.test_quickplot.TestPlotHist.test_vertical.0": "bf80c7c6c07d7959647e343a33364b699589c6c64ec0312b9e227ad681ffcc68", diff --git a/lib/iris/tests/results/integration/netcdf/general/TestPackedData/multi_packed_multi_dtype.cdl b/lib/iris/tests/results/integration/netcdf/general/TestPackedData/multi_packed_multi_dtype.cdl index 37dafe4745..8a8f481492 100644 --- a/lib/iris/tests/results/integration/netcdf/general/TestPackedData/multi_packed_multi_dtype.cdl +++ b/lib/iris/tests/results/integration/netcdf/general/TestPackedData/multi_packed_multi_dtype.cdl @@ -5,8 +5,8 @@ dimensions: time = 360 ; variables: short air_temperature(time, latitude, longitude) ; - air_temperature:scale_factor = 0.0024257504786326 ; - air_temperature:add_offset = 261.648002426021 ; + air_temperature:scale_factor = 0.00242575f ; + air_temperature:add_offset = 261.648f ; air_temperature:standard_name = "air_temperature" ; air_temperature:units = "K" ; air_temperature:um_stash_source = "m01s03i236" ; @@ -53,7 +53,7 @@ variables: precipitation_flux:grid_mapping = "latitude_longitude" ; precipitation_flux:coordinates = "forecast_period forecast_reference_time" ; ushort air_temperature_0(time, latitude, longitude) ; - air_temperature_0:scale_factor = 0.0020141666756075 ; + air_temperature_0:scale_factor = 0.002014167f ; air_temperature_0:add_offset = 176.7872f ; air_temperature_0:standard_name = "air_temperature" ; air_temperature_0:units = "K" ; diff --git a/lib/iris/tests/results/integration/netcdf/general/TestPackedData/multi_packed_single_dtype.cdl b/lib/iris/tests/results/integration/netcdf/general/TestPackedData/multi_packed_single_dtype.cdl index a3c90bf1f8..3f2c909ce8 100644 --- a/lib/iris/tests/results/integration/netcdf/general/TestPackedData/multi_packed_single_dtype.cdl +++ b/lib/iris/tests/results/integration/netcdf/general/TestPackedData/multi_packed_single_dtype.cdl @@ -5,8 +5,8 @@ dimensions: time = 360 ; variables: short air_temperature(time, latitude, longitude) ; - air_temperature:scale_factor = 0.0024257504786326 ; - air_temperature:add_offset = 261.648002426021 ; + air_temperature:scale_factor = 0.00242575f ; + air_temperature:add_offset = 261.648f ; air_temperature:standard_name = "air_temperature" ; air_temperature:units = "K" ; air_temperature:um_stash_source = "m01s03i236" ; @@ -46,8 +46,8 @@ variables: height:standard_name = "height" ; height:positive = "up" ; short precipitation_flux(time, latitude, longitude) ; - precipitation_flux:scale_factor = 2.9897383798121e-08 ; - precipitation_flux:add_offset = 0.000979677472296829 ; + precipitation_flux:scale_factor = 2.989738e-08f ; + precipitation_flux:add_offset = 0.0009796774f ; precipitation_flux:standard_name = "precipitation_flux" ; precipitation_flux:units = "kg m-2 s-1" ; precipitation_flux:um_stash_source = "m01s05i216" ; @@ -55,8 +55,8 @@ variables: precipitation_flux:grid_mapping = "latitude_longitude" ; precipitation_flux:coordinates = "forecast_period forecast_reference_time" ; short air_temperature_0(time, latitude, longitude) ; - air_temperature_0:scale_factor = 0.0020141666756075 ; - air_temperature_0:add_offset = 242.787445071619 ; + air_temperature_0:scale_factor = 0.002014167f ; + air_temperature_0:add_offset = 242.7874f ; air_temperature_0:standard_name = "air_temperature" ; air_temperature_0:units = "K" ; air_temperature_0:um_stash_source = "m01s03i236" ; diff --git a/lib/iris/tests/results/integration/netcdf/general/TestPackedData/single_packed_manual.cdl b/lib/iris/tests/results/integration/netcdf/general/TestPackedData/single_packed_manual.cdl index fece18b1f3..83e7329575 100644 --- a/lib/iris/tests/results/integration/netcdf/general/TestPackedData/single_packed_manual.cdl +++ b/lib/iris/tests/results/integration/netcdf/general/TestPackedData/single_packed_manual.cdl @@ -4,8 +4,8 @@ dimensions: longitude = 96 ; variables: short air_temperature(latitude, longitude) ; - air_temperature:scale_factor = 0.00119806791576066 ; - air_temperature:add_offset = 267.40062344802 ; + air_temperature:scale_factor = 0.001198068f ; + air_temperature:add_offset = 267.4006f ; air_temperature:standard_name = "air_temperature" ; air_temperature:units = "K" ; air_temperature:um_stash_source = "m01s03i236" ; diff --git a/lib/iris/tests/results/integration/netcdf/general/TestPackedData/single_packed_signed.cdl b/lib/iris/tests/results/integration/netcdf/general/TestPackedData/single_packed_signed.cdl index fece18b1f3..83e7329575 100644 --- a/lib/iris/tests/results/integration/netcdf/general/TestPackedData/single_packed_signed.cdl +++ b/lib/iris/tests/results/integration/netcdf/general/TestPackedData/single_packed_signed.cdl @@ -4,8 +4,8 @@ dimensions: longitude = 96 ; variables: short air_temperature(latitude, longitude) ; - air_temperature:scale_factor = 0.00119806791576066 ; - air_temperature:add_offset = 267.40062344802 ; + air_temperature:scale_factor = 0.001198068f ; + air_temperature:add_offset = 267.4006f ; air_temperature:standard_name = "air_temperature" ; air_temperature:units = "K" ; air_temperature:um_stash_source = "m01s03i236" ; diff --git a/lib/iris/tests/results/integration/netcdf/general/TestPackedData/single_packed_unsigned.cdl b/lib/iris/tests/results/integration/netcdf/general/TestPackedData/single_packed_unsigned.cdl index c85ba6aadd..7b9114309e 100644 --- a/lib/iris/tests/results/integration/netcdf/general/TestPackedData/single_packed_unsigned.cdl +++ b/lib/iris/tests/results/integration/netcdf/general/TestPackedData/single_packed_unsigned.cdl @@ -4,7 +4,7 @@ dimensions: longitude = 96 ; variables: ubyte air_temperature(latitude, longitude) ; - air_temperature:scale_factor = 0.30790345435049 ; + air_temperature:scale_factor = 0.3079035f ; air_temperature:add_offset = 228.1423f ; air_temperature:standard_name = "air_temperature" ; air_temperature:units = "K" ; diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_convection_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_convection_2km.cml index 4e3a95118e..cc657e4c97 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_convection_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_convection_2km.cml @@ -212,7 +212,7 @@ - + diff --git a/lib/iris/tests/results/nimrod/u1096_ng_ek00_relhumidity3d0060_2km.cml b/lib/iris/tests/results/nimrod/u1096_ng_ek00_relhumidity3d0060_2km.cml index 4cfec2d195..9c3cc9f181 100644 --- a/lib/iris/tests/results/nimrod/u1096_ng_ek00_relhumidity3d0060_2km.cml +++ b/lib/iris/tests/results/nimrod/u1096_ng_ek00_relhumidity3d0060_2km.cml @@ -62,6 +62,6 @@ - + diff --git a/lib/iris/tests/test_plot.py b/lib/iris/tests/test_plot.py index 50773f0d24..b263313b90 100644 --- a/lib/iris/tests/test_plot.py +++ b/lib/iris/tests/test_plot.py @@ -821,6 +821,9 @@ def setUp(self): super().setUp() filename = tests.get_data_path(("PP", "COLPEX", "theta_and_orog_subset.pp")) self.cube = load_cube_once(filename, "air_potential_temperature") + if self.cube.coord_dims("time") != (0,): + # A quick fix for data which has changed since we support time-varying orography + self.cube.transpose((1, 0, 2, 3)) self.draw_module = iris.plot self.contourf = LambdaStr( diff --git a/lib/iris/tests/test_pp_to_cube.py b/lib/iris/tests/test_pp_to_cube.py index da49ff8188..a61703761f 100644 --- a/lib/iris/tests/test_pp_to_cube.py +++ b/lib/iris/tests/test_pp_to_cube.py @@ -81,7 +81,7 @@ def test_regrid_missing_coord(self): # If the target cube is missing one of the source dimension # coords, ensure the re-grid fails nicely - i.e. returns None. self.target.remove_coord("bar") - new_ref = iris.fileformats.rules._ensure_aligned({}, self.ref, self.target) + new_ref, _ = iris.fileformats.rules._ensure_aligned({}, self.ref, self.target) self.assertIsNone(new_ref) def test_regrid_codimension(self): @@ -92,11 +92,11 @@ def test_regrid_codimension(self): new_foo = self.target.coord("bar").copy() new_foo.rename("foo") self.target.add_aux_coord(new_foo, 0) - new_ref = iris.fileformats.rules._ensure_aligned({}, self.ref, self.target) + new_ref, _ = iris.fileformats.rules._ensure_aligned({}, self.ref, self.target) self.assertIsNone(new_ref) def test_regrid_identity(self): - new_ref = iris.fileformats.rules._ensure_aligned({}, self.ref, self.target) + new_ref, _ = iris.fileformats.rules._ensure_aligned({}, self.ref, self.target) # Bounds don't make it through the re-grid process self.ref.coord("bar").bounds = None self.ref.coord("foo").bounds = None diff --git a/lib/iris/tests/test_quickplot.py b/lib/iris/tests/test_quickplot.py index fdd534a2c5..25bd8904a7 100644 --- a/lib/iris/tests/test_quickplot.py +++ b/lib/iris/tests/test_quickplot.py @@ -49,6 +49,9 @@ def setUp(self): tests.GraphicsTest.setUp(self) filename = tests.get_data_path(("PP", "COLPEX", "theta_and_orog_subset.pp")) self.cube = test_plot.load_cube_once(filename, "air_potential_temperature") + if self.cube.coord_dims("time") != (0,): + # A quick fix for data which has changed since we support time-varying orography + self.cube.transpose((1, 0, 2, 3)) self.draw_module = iris.quickplot self.contourf = test_plot.LambdaStr( @@ -174,10 +177,22 @@ def test_contourf_nameless(self): qplt.contourf(cube, coords=["grid_longitude", "model_level_number"]) self.check_graphic() + def test_contourf_no_colorbar(self): + qplt.contourf( + self._small(), + colorbar=False, + coords=["model_level_number", "grid_longitude"], + ) + self.check_graphic() + def test_pcolor(self): qplt.pcolor(self._small()) self.check_graphic() + def test_pcolor_no_colorbar(self): + qplt.pcolor(self._small(), colorbar=False) + self.check_graphic() + def test_pcolormesh(self): qplt.pcolormesh(self._small()) @@ -193,6 +208,10 @@ def test_pcolormesh_str_symbol(self): self.check_graphic() + def test_pcolormesh_no_colorbar(self): + qplt.pcolormesh(self._small(), colorbar=False) + self.check_graphic() + def test_map(self): cube = self._slice(["grid_latitude", "grid_longitude"]) qplt.contour(cube) diff --git a/lib/iris/tests/unit/common/mixin/test_LimitedAttributeDict.py b/lib/iris/tests/unit/common/mixin/test_LimitedAttributeDict.py index f538279bb1..dfb49f0f8d 100644 --- a/lib/iris/tests/unit/common/mixin/test_LimitedAttributeDict.py +++ b/lib/iris/tests/unit/common/mixin/test_LimitedAttributeDict.py @@ -42,12 +42,22 @@ def test___eq___numpy(self): right = LimitedAttributeDict(**values) self.assertEqual(left, right) self.assertEqual(left, values) + values = dict(one=np.arange(1), two=np.arange(1), three=np.arange(1)) left = LimitedAttributeDict(dict(one=0, two=0, three=0)) right = LimitedAttributeDict(**values) self.assertEqual(left, right) self.assertEqual(left, values) + # Test inequality: + values = dict(one=np.arange(1), two=np.arange(2), three=np.arange(3)) + left = LimitedAttributeDict(**values) + right = LimitedAttributeDict( + one=np.arange(3), two=np.arange(2), three=np.arange(1) + ) + self.assertNotEqual(left, right) + self.assertNotEqual(values, right) + def test___setitem__(self): for key in self.forbidden_keys: item = LimitedAttributeDict() diff --git a/lib/iris/tests/unit/concatenate/test_hashing.py b/lib/iris/tests/unit/concatenate/test_hashing.py index 7a56be1db8..24062a2af3 100644 --- a/lib/iris/tests/unit/concatenate/test_hashing.py +++ b/lib/iris/tests/unit/concatenate/test_hashing.py @@ -21,6 +21,8 @@ (np.array([np.nan, 1.0]), np.array([np.nan, 1.0]), True), (np.ma.array([1, 2], mask=[0, 1]), np.ma.array([1, 2], mask=[0, 1]), True), (np.ma.array([1, 2], mask=[0, 1]), np.ma.array([1, 2], mask=[0, 0]), False), + (np.ma.array([1, 2], mask=[1, 1]), np.ma.array([1, 2], mask=[1, 1]), True), + (np.ma.array([1, 2], mask=[0, 0]), np.ma.array([1, 2], mask=[0, 0]), True), (da.arange(6).reshape((2, 3)), da.arange(6, chunks=1).reshape((2, 3)), True), (da.arange(20, chunks=1), da.arange(20, chunks=2), True), ( @@ -33,6 +35,21 @@ da.ma.masked_array([1, 3], mask=[0, 1]), True, ), + ( + np.arange(2), + da.ma.masked_array(np.arange(2), mask=[0, 0]), + True, + ), + ( + np.arange(2), + da.ma.masked_array(np.arange(2), mask=[0, 1]), + False, + ), + ( + da.ma.masked_array(np.arange(10), mask=np.zeros(10)), + da.ma.masked_array(np.arange(10), mask=np.ma.nomask), + True, + ), ( np.ma.array([1, 2], mask=[0, 1]), np.ma.array([1, 3], mask=[0, 1], fill_value=10), diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/__init__.py b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/__init__.py index f768ae3587..7c79740023 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/__init__.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/__init__.py @@ -140,7 +140,7 @@ def run_testcase(self, warning_regex=None, **testcase_kwargs): if self.debug_info: print("\nCube:") print(cube) - print("") + print() return cube def _make_testcase_cdl(self, **kwargs): diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__latlon_dimcoords.py b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__latlon_dimcoords.py index fcaa67c308..15401a2ca1 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__latlon_dimcoords.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__latlon_dimcoords.py @@ -133,9 +133,9 @@ def check_result( self.assertEqual(1, len(cube.coords(dim_coords=True))) (coord,) = coords if self.debug_info: - print("") + print() print("DEBUG : result coord =", coord) - print("") + print() coord_stdname, coord_longname, coord_units, coord_crs = [ getattr(coord, name) diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_parse_cell_methods.py b/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_parse_cell_methods.py index 0f8fd0152f..528e9d7579 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_parse_cell_methods.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_parse_cell_methods.py @@ -19,6 +19,7 @@ class Test(tests.IrisTest): def test_simple(self): cell_method_strings = [ "time: mean", + "time:mean", "time : mean", ] expected = (CellMethod(method="mean", coords="time"),) @@ -125,6 +126,7 @@ def test_badly_formatted_warning(self): cell_method_strings = [ # "time: maximum (interval: 1 hr comment: first bit " # "time: mean (interval: 1 day comment: second bit)", + "time", "time: (interval: 1 hr comment: first bit) " "time: mean (interval: 1 day comment: second bit)", "time: maximum (interval: 1 hr comment: first bit) " diff --git a/lib/iris/tests/unit/fileformats/pp/test_PPField.py b/lib/iris/tests/unit/fileformats/pp/test_PPField.py index f3aed0bea2..e3d782b156 100644 --- a/lib/iris/tests/unit/fileformats/pp/test_PPField.py +++ b/lib/iris/tests/unit/fileformats/pp/test_PPField.py @@ -98,8 +98,8 @@ def field_checksum(data): def test_masked_mdi_value_warning(self): # Check that an unmasked MDI value raises a warning. field = DummyPPField()._ready_for_save() - field.bmdi = -123.4 # Make float32 data, as float64 default produces an extra warning. + field.bmdi = np.float32(-123.4) field.data = np.ma.masked_array([1.0, field.bmdi, 3.0], dtype=np.float32) msg = "PPField data contains unmasked points" with self.assertWarnsRegex(IrisMaskValueMatchWarning, msg): diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test__all_other_rules.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test__all_other_rules.py index aa6b79e9a0..e2c71790b4 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test__all_other_rules.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test__all_other_rules.py @@ -113,6 +113,9 @@ def test_multiple_unordered_lbprocs(self): x_bounds=None, _x_coord_name=lambda: "longitude", _y_coord_name=lambda: "latitude", + # Not under test but needed for the Mock to play nicely. + bzy=1, + bdy=1, ) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [ @@ -133,6 +136,9 @@ def test_multiple_unordered_rotated_lbprocs(self): x_bounds=None, _x_coord_name=lambda: "grid_longitude", _y_coord_name=lambda: "grid_latitude", + # Not under test but needed for the Mock to play nicely. + bzy=1, + bdy=1, ) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [ diff --git a/lib/iris/tests/unit/fileformats/test_load_functions.py b/lib/iris/tests/unit/fileformats/test_load_functions.py new file mode 100644 index 0000000000..3c3d361080 --- /dev/null +++ b/lib/iris/tests/unit/fileformats/test_load_functions.py @@ -0,0 +1,231 @@ +# Copyright Iris contributors +# +# This file is part of Iris and is released under the BSD license. +# See LICENSE in the root of the repository for full licensing details. +"""Unit tests for iris load functions. + +* :func:`iris.load` +* :func:`iris.load_cube` +* :func:`iris.load_cubes` +* :func:`iris.load_raw` +""" + +import re +from typing import Iterable +from unittest import mock + +import numpy as np +import pytest + +import iris +from iris.coords import AuxCoord, DimCoord +from iris.cube import Cube + +_time_unit = "days since 2001-01-01" + + +def cu(n="a", t=0, z=0): + """Create a single test cube. + + All cubes have, potentially, 4 dimensions (z, t, y, x). + The (y, x) dims are always the same, but (z, t) can be scalar, or various lengths. + t/z values which are scalar/vector produce likewise scalar/vector coordinates. + """ + yco = DimCoord(np.arange(3), long_name="latitude", units="degrees") + xco = DimCoord(np.arange(4), long_name="longitude", units="degrees") + dim_coords = [yco, xco] + shape = [3, 4] # the xy shape + scalar_coords = [] + tco = DimCoord( + np.array(t, dtype=np.float32), standard_name="time", units=_time_unit + ) + zco = DimCoord(np.array(z, dtype=np.float32), standard_name="height", units="m") + for tz, tzco in [(t, tco), (z, zco)]: + if isinstance(tz, Iterable): + # N.B. insert an extra dim at the front + dim_coords[:0] = [tzco] + shape[:0] = tzco.shape[:1] + else: + scalar_coords.append(tzco) + + cube = Cube( + data=np.zeros(shape), + long_name=n, + dim_coords_and_dims=[(dim, i_dim) for i_dim, dim in enumerate(dim_coords)], + aux_coords_and_dims=[(dim, ()) for dim in scalar_coords], + ) + return cube + + +@pytest.fixture(params=["load", "load_cube", "load_cubes", "load_raw"]) +def loadfunc_name(request): + # N.B. "request" is a standard PyTest fixture + return request.param # Return the name of the attribute to test. + + +def run_testcase(input_cubes, loadfunc_name, constraints=None): + loadfunc = getattr(iris, loadfunc_name) + + def mock_generate_cubes(uris, callback, constraints): + for cube in input_cubes: + yield cube + + try: + with mock.patch("iris._generate_cubes", mock_generate_cubes): + result = loadfunc(input_cubes, constraints) + except Exception as e: + result = e + + return result + + +def debug_result(cubes): + print() + print(cubes) + if isinstance(cubes, iris.cube.CubeList): + print(len(cubes), " cubes..") + for i_cube, cube in enumerate(cubes): + vh = cube.coord("height").points + vt = cube.coord("time").points + print(i_cube, cube.name(), ": h=", vh, " :: t=", vt) + + +def check_result(input_cubes, loadfunc_name, result, expected_results): + if "load_raw" not in expected_results and loadfunc_name == "load_raw": + expected = input_cubes + else: + expected = expected_results[loadfunc_name] + + if isinstance(expected, str): + # We expect an error result : stored 'expected' is a regexp to match its repr + assert re.search(expected, repr(result)) + else: + assert result == expected + + +class TestLoadFunctions: + def test_mergeable(self, loadfunc_name): + _cube = cu(t=(0, 1), z=(0, 1)) + input_cubes = [cu(t=i_t, z=i_z) for i_t in (0, 1) for i_z in (0, 1)] + expected_results = { + "load": [_cube], + "load_cube": _cube, + "load_cubes": [_cube], + } + result = run_testcase(input_cubes, loadfunc_name) + check_result(input_cubes, loadfunc_name, result, expected_results) + + def test_multiple(self, loadfunc_name): + input_cubes = [cu(), cu(n="b")] + expected_results = { + "load": [cu(), cu(n="b")], + "load_cube": "ConstraintMismatchError.*failed to merge into a single cube", + "load_cubes": r"ConstraintMismatchError.*-> \d+ cubes", + } + result = run_testcase(input_cubes, loadfunc_name) + check_result(input_cubes, loadfunc_name, result, expected_results) + + def test_multiple_constrained(self, loadfunc_name): + cube, cube_b = cu(), cu(n="b") + input_cubes = [cube, cube_b] + constraint = "a" + expected_results = { + "load": [cube], + "load_cube": cube, + "load_cubes": [cube], + "load_raw": [cube], + } + result = run_testcase(input_cubes, loadfunc_name, constraints=constraint) + check_result(input_cubes, loadfunc_name, result, expected_results) + + def test_multiple_multi_constraints(self, loadfunc_name): + ca, cb, cc = cu(), cu(n="b"), cu(n="c") + input_cubes = [ca, cb, cc] + constraints = ["c", "a"] + expected_results = { + "load": [cc, ca], + "load_cube": "ValueError.*only a single constraint is allowed", + "load_cubes": [cc, ca], + "load_raw": [cc, ca], + } + result = run_testcase(input_cubes, loadfunc_name, constraints=constraints) + check_result(input_cubes, loadfunc_name, result, expected_results) + + def test_nonmergeable_part_missing(self, loadfunc_name): + c1, c2, c3, c4 = [cu(t=i_t, z=i_z) for i_t in (0, 1) for i_z in (0, 1)] + input_cubes = [c1, c2, c4] + + c124 = cu(t=(0, 1, 2)) + c124.remove_coord("time") # we now have an unnamed dimension + c124.remove_coord("height") # we now have an unnamed dimension + c124.add_aux_coord(AuxCoord([0.0, 1, 1], standard_name="height", units="m"), 0) + c124.add_aux_coord( + AuxCoord([0.0, 0, 1], standard_name="time", units=_time_unit), 0 + ) + expected_results = { + "load": [c124], + "load_cube": c124, + "load_cubes": [c124], + } + result = run_testcase(input_cubes, loadfunc_name) + check_result(input_cubes, loadfunc_name, result, expected_results) + + def test_nonmergeable_part_extra(self, loadfunc_name): + c1, c2, c3, c4 = [cu(t=i_t, z=i_z) for i_t in (0, 1) for i_z in (0, 1)] + c5 = cu(t=5) + input_cubes = [c1, c2, c5, c4, c3] # scramble order, just to test + + cx = cu(t=range(5)) + cx.remove_coord("time") # we now have an unnamed dimension + cx.remove_coord("height") # we now have an unnamed dimension + cx.add_aux_coord( + AuxCoord([0.0, 1, 0, 1, 0], standard_name="height", units="m"), 0 + ) + cx.add_aux_coord( + AuxCoord([0.0, 0, 5, 1, 1], standard_name="time", units=_time_unit), 0 + ) + expected_results = { + "load": [cx], + "load_cube": cx, + "load_cubes": [cx], + } + result = run_testcase(input_cubes, loadfunc_name) + check_result(input_cubes, loadfunc_name, result, expected_results) + + def test_constraint_overlap(self, loadfunc_name): + c1, c2, c3, c4, c5, c6 = (cu(z=ind) for ind in (1, 2, 3, 4, 5, 6)) + input_cubes = [c1, c2, c3, c4, c5, c6] + constraints = [ + iris.Constraint(height=[1, 2]), + iris.Constraint(height=[1, 4, 5]), + ] + c12 = cu(z=[1, 2]) + c145 = cu(z=[1, 4, 5]) + expected_results = { + "load": [c12, c145], + "load_cube": "ValueError.*only a single constraint is allowed", + "load_cubes": [c12, c145], # selected parts merge, as for load + "load_raw": [c1, c2, c1, c4, c5], # THIS VERY STRANGE BEHAVIOUR!! + } + result = run_testcase(input_cubes, loadfunc_name, constraints=constraints) + check_result(input_cubes, loadfunc_name, result, expected_results) + + def test_multiple_match(self, loadfunc_name): + c1 = cu(z=1) + c2 = cu(z=2) + c3 = cu(n="b", z=1) + c4 = cu(n="b", z=2) + input_cubes = [c1, c2, c3, c4] + constraints = [ + iris.Constraint("a") & iris.Constraint(height=1), + iris.Constraint(height=2), + ] + expected_results = { + "load": [c1, c2, c4], + "load_cube": "ValueError.*only a single constraint is allowed", + "load_cubes": r"ConstraintMismatchError.*-> \d+ cubes", + "load_raw": [c1, c2, c4], + } + result = run_testcase(input_cubes, loadfunc_name, constraints=constraints) + debug_result(result) + check_result(input_cubes, loadfunc_name, result, expected_results) diff --git a/lib/iris/tests/unit/io/format_picker/test_FormatAgent.py b/lib/iris/tests/unit/io/format_picker/test_FormatAgent.py new file mode 100644 index 0000000000..3f5d3a87e3 --- /dev/null +++ b/lib/iris/tests/unit/io/format_picker/test_FormatAgent.py @@ -0,0 +1,23 @@ +# Copyright Iris contributors +# +# This file is part of Iris and is released under the BSD license. +# See LICENSE in the root of the repository for full licensing details. +"""Unit tests for the `iris.io.format_picker.FormatAgent` class.""" + +from iris.fileformats import FORMAT_AGENT +import iris.tests as tests + + +class TestFormatAgent(tests.IrisTest): + def test_copy_is_equal(self): + format_agent_copy = FORMAT_AGENT.copy() + self.assertEqual(format_agent_copy, FORMAT_AGENT) + + def test_modified_copy_not_equal(self): + format_agent_copy = FORMAT_AGENT.copy() + format_agent_copy._format_specs.pop() + self.assertNotEqual(format_agent_copy, FORMAT_AGENT) + + +if __name__ == "__main__": + tests.main() diff --git a/lib/iris/tests/unit/test_LoadPolicy.py b/lib/iris/tests/unit/test_LoadPolicy.py new file mode 100644 index 0000000000..8772b089c1 --- /dev/null +++ b/lib/iris/tests/unit/test_LoadPolicy.py @@ -0,0 +1,144 @@ +# Copyright Iris contributors +# +# This file is part of Iris and is released under the BSD license. +# See LICENSE in the root of the repository for full licensing details. +"""Unit tests for the :mod:`iris.io.loading.LoadPolicy` package.""" + +from unittest import mock + +import pytest + +from iris import LoadPolicy + + +class TestInit: + def test_init_empty(self): + # Check how a bare init works + options = LoadPolicy() + assert options.settings() == LoadPolicy.SETTINGS["default"] + + def test_init_args_kwargs(self): + # Check that init with args, kwargs equates to a pair of set() calls. + with mock.patch("iris.LoadPolicy.set") as mock_set: + test_option = mock.sentinel.option + test_kwargs = {"junk": "invalid"} + LoadPolicy(options=test_option, **test_kwargs) + assert mock_set.call_args_list == [ + mock.call("default"), + mock.call(test_option, **test_kwargs), + ] + + +class Test_settings: + """The .settings() returns a dict full of the settings.""" + + def test_settings(self): + options = LoadPolicy() + settings = options.settings() + assert isinstance(settings, dict) + assert tuple(settings.keys()) == LoadPolicy.OPTION_KEYS + for key in LoadPolicy.OPTION_KEYS: + assert settings[key] == getattr(options, key) + + +class Test_set: + """Check the .set(arg, **kwargs) behaviour.""" + + def test_empty(self): + options = LoadPolicy() + orig_settings = options.settings() + options.set() + assert options.settings() == orig_settings + + def test_arg_dict(self): + options = LoadPolicy() + assert options.settings()["merge_concat_sequence"] == "m" + assert options.settings()["repeat_until_unchanged"] is False + options.set({"merge_concat_sequence": "c", "repeat_until_unchanged": True}) + assert options.settings()["merge_concat_sequence"] == "c" + assert options.settings()["repeat_until_unchanged"] is True + + def test_arg_string(self): + options = LoadPolicy() + assert options.settings()["merge_concat_sequence"] == "m" + assert options.settings()["repeat_until_unchanged"] is False + options.set("comprehensive") + assert options.settings()["merge_concat_sequence"] == "mc" + assert options.settings()["repeat_until_unchanged"] is True + + def test_arg_bad_dict(self): + options = LoadPolicy() + expected = "Unknown options.*'junk'.* : valid options are" + with pytest.raises(ValueError, match=expected): + options.set({"junk": "invalid"}) + + def test_arg_bad_string(self): + options = LoadPolicy() + expected = "Invalid arg options='unknown' : must be a dict, or one of" + with pytest.raises(TypeError, match=expected): + options.set("unknown") + + def test_arg_bad_type(self): + options = LoadPolicy() + expected = "must be a dict, or one of" + with pytest.raises(TypeError, match=expected): + options.set((1, 2, 3)) + + def test_kwargs(self): + options = LoadPolicy() + assert options.settings()["merge_concat_sequence"] == "m" + assert options.settings()["repeat_until_unchanged"] is False + options.set(merge_concat_sequence="c", repeat_until_unchanged=True) + assert options.settings()["merge_concat_sequence"] == "c" + assert options.settings()["repeat_until_unchanged"] is True + + def test_arg_kwargs(self): + # Show that kwargs override arg + options = LoadPolicy( + support_multiple_references=False, + merge_concat_sequence="", + repeat_until_unchanged=False, + ) + options.set( + dict(merge_concat_sequence="c", repeat_until_unchanged=True), + merge_concat_sequence="mc", + ) + assert options.merge_concat_sequence == "mc" + assert options.repeat_until_unchanged is True + + def test_bad_kwarg(self): + options = LoadPolicy() + expected = "Unknown options.*'junk'.* : valid options are" + with pytest.raises(ValueError, match=expected): + options.set({"junk": "invalid"}) + + +class Test_AttributeAccess: + """Check operation of direct property access (with ".").""" + + def test_getattr(self): + options = LoadPolicy(merge_concat_sequence="m") + assert options.merge_concat_sequence == "m" + + def test_getattr_badname(self): + options = LoadPolicy() + expected = "'LoadPolicy' object has no attribute 'unknown'" + with pytest.raises(AttributeError, match=expected): + options.unknown + + def test_setattr(self): + options = LoadPolicy(merge_concat_sequence="m") + options.merge_concat_sequence = "mc" + assert options.merge_concat_sequence == "mc" + + def test_setattr_badname(self): + options = LoadPolicy() + expected = "LoadPolicy object has no property 'anyold_property'" + with pytest.raises(KeyError, match=expected): + options.anyold_property = "x" + + def test_setattr_badvalue(self): + options = LoadPolicy() + expected = "'mcm' is not a valid.*merge_concat_sequence : must be one of" + with pytest.raises(ValueError, match=expected): + options.merge_concat_sequence = "mcm" diff --git a/lib/iris/tests/unit/test_combine_cubes.py b/lib/iris/tests/unit/test_combine_cubes.py new file mode 100644 index 0000000000..e159582497 --- /dev/null +++ b/lib/iris/tests/unit/test_combine_cubes.py @@ -0,0 +1,89 @@ +# Copyright Iris contributors +# +# This file is part of Iris and is released under the BSD license. +# See LICENSE in the root of the repository for full licensing details. +"""Unit tests for the :func:`iris.io.loading.combine_cubes` function. + +Note: These tests are fairly extensive to cover functional uses within the loading +operations. +TODO: when function is public API, extend testing to the extended API options, +i.e. different types + defaulting of the 'options' arg, and **kwargs support. +""" + +import pytest + +from iris import LoadPolicy, _combine_cubes +from iris.tests.unit.fileformats.test_load_functions import cu + + +@pytest.fixture(params=list(LoadPolicy.SETTINGS.keys())) +def options(request): + # N.B. "request" is a standard PyTest fixture + return request.param # Return the name of the attribute to test. + + +# Interface to convert settings-name / kwargs into an options dict, +# TODO: remove this wrapper when the API of "combine_cubes" is opened up. +def combine_cubes(cubes, settings_name="default", **kwargs): + options = LoadPolicy.SETTINGS[settings_name] + options.update(kwargs) + return _combine_cubes(cubes, options, merge_require_unique=False) + + +class Test: + def test_mergeable(self, options): + c1, c2 = cu(t=1), cu(t=2) + c12 = cu(t=(1, 2)) + input_cubes = [c1, c2] + result = combine_cubes(input_cubes, options) + expected = [c12] # same in all cases + assert result == expected + + def test_catable(self, options): + c1, c2 = cu(t=(1, 2)), cu(t=(3, 4)) + c12 = cu(t=(1, 2, 3, 4)) + input_cubes = [c1, c2] + result = combine_cubes(input_cubes, options) + expected = { + "legacy": [c1, c2], # standard options can't do this .. + "default": [c1, c2], + "recommended": [c12], # .. but it works if you enable concatenate + "comprehensive": [c12], + }[options] + assert result == expected + + def test_cat_enables_merge(self, options): + c1, c2 = cu(t=(1, 2), z=1), cu(t=(3, 4, 5), z=1) + c3, c4 = cu(t=(1, 2, 3), z=2), cu(t=(4, 5), z=2) + c1234 = cu(t=(1, 2, 3, 4, 5), z=(1, 2)) + c12 = cu(t=(1, 2, 3, 4, 5), z=1) + c34 = cu(t=(1, 2, 3, 4, 5), z=2) + input_cubes = [c1, c2, c3, c4] + result = combine_cubes(input_cubes, options) + expected = { + "legacy": input_cubes, + "default": input_cubes, + "recommended": [c12, c34], # standard "mc" sequence can't do this one.. + "comprehensive": [c1234], # .. but works if you repeat + }[options] + assert result == expected + + def test_cat_enables_merge__custom(self): + c1, c2 = cu(t=(1, 2), z=1), cu(t=(3, 4, 5), z=1) + c3, c4 = cu(t=(1, 2, 3), z=2), cu(t=(4, 5), z=2) + c1234 = cu(t=(1, 2, 3, 4, 5), z=(1, 2)) + input_cubes = [c1, c2, c3, c4] + result = combine_cubes(input_cubes, merge_concat_sequence="cm") + assert result == [c1234] + + def test_nocombine_overlapping(self, options): + c1, c2 = cu(t=(1, 3)), cu(t=(2, 4)) + input_cubes = [c1, c2] + result = combine_cubes(input_cubes, options) + assert result == input_cubes # same in all cases : can't do this + + def test_nocombine_dim_scalar(self, options): + c1, c2 = cu(t=(1,)), cu(t=2) + input_cubes = [c1, c2] + result = combine_cubes(input_cubes, options) + assert result == input_cubes # can't do this at present diff --git a/lib/iris/util.py b/lib/iris/util.py index 4924ca68d2..a808087fd8 100644 --- a/lib/iris/util.py +++ b/lib/iris/util.py @@ -14,6 +14,7 @@ import os.path import sys import tempfile +from typing import Literal import cf_units from dask import array as da @@ -252,7 +253,10 @@ def describe_diff(cube_a, cube_b, output_file=None): ) -def guess_coord_axis(coord): +Axis = Literal["X", "Y", "Z", "T"] + + +def guess_coord_axis(coord) -> Axis | None: """Return a "best guess" axis name of the coordinate. Heuristic categorisation of the coordinate into either label @@ -276,7 +280,7 @@ def guess_coord_axis(coord): :attr:`~iris.coords.Coord.ignore_axis` property on `coord` to ``False``. """ - axis = None + axis: Axis | None = None if hasattr(coord, "ignore_axis") and coord.ignore_axis is True: return axis @@ -1411,10 +1415,16 @@ def regular_points(zeroth, step, count): This function does maintain laziness when called; it doesn't realise data. See more at :doc:`/userguide/real_and_lazy_data`. """ - points = (zeroth + step) + step * np.arange(count, dtype=np.float32) + + def make_steps(dtype: np.dtype): + start = np.add(zeroth, step, dtype=dtype) + steps = np.multiply(step, np.arange(count), dtype=dtype) + return np.add(start, steps, dtype=dtype) + + points = make_steps(np.float32) _, regular = iris.util.points_step(points) if not regular: - points = (zeroth + step) + step * np.arange(count, dtype=np.float64) + points = make_steps(np.float64) return points diff --git a/pyproject.toml b/pyproject.toml index c55f4597d5..b849dae9e6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -149,7 +149,8 @@ omit = [ [tool.coverage.report] exclude_lines = [ "pragma: no cover", - "if __name__ == .__main__.:" + "if __name__ == .__main__.:", + "if TYPE_CHECKING:", ] [tool.codespell] @@ -164,14 +165,16 @@ ignore = [ [tool.mypy] # See https://mypy.readthedocs.io/en/stable/config_file.html -ignore_missing_imports = true -warn_unused_configs = true -warn_unreachable = true +# TODO: remove when MyPy fixed (see https://github.com/python/mypy/issues/17166) +disable_error_code = ["call-arg"] enable_error_code = ["ignore-without-code", "truthy-bool"] exclude = [ 'noxfile\.py', 'docs/src/conf\.py' ] +ignore_missing_imports = true +warn_unreachable = true +warn_unused_configs = true [tool.numpydoc_validation] checks = [ @@ -210,7 +213,7 @@ checks = [ "PR01", # Parameters ... not documented "PR02", # Unknown parameters {....} "PR04", # Parameter "...." has no type - "PR07", # Parameter "...." has no description + "PR07", # Parameter "...." has no description "RT01", # No Returns section found "RT03", # Return value has no description ] diff --git a/requirements/locks/py310-linux-64.lock b/requirements/locks/py310-linux-64.lock index 37fd003043..a67480e8a2 100644 --- a/requirements/locks/py310-linux-64.lock +++ b/requirements/locks/py310-linux-64.lock @@ -1,198 +1,206 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: ae0608976ff47569c86692e74307d174a2bf60467441b37c1f0679cff7953c4c +# input_hash: 372c3b278b46d5c658024f7b6b47d7b92266bb7ca5a25b0eb4f67e055b8a02a7 @EXPLICIT https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 -https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.7.4-hbcca054_0.conda#23ab7665c5f63cfb9f1f6195256daac6 +https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda#c27d1c142233b5bc9ca570c6e2e0c244 https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb -https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_2.conda#cbbe59391138ea5ad3658c76912e147f -https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-hf3520f5_7.conda#b80f2f396ca2c28b8c14c437a4ed1e74 -https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.11.3-h59595ed_0.conda#df9ae69b85e0cab9bde23eff1e87f183 -https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.10-4_cp310.conda#26322ec5d7712c3ded99dd656142b8ce -https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda#161081fc7cec0bfda0d86d7cb595f8d8 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda#49023d73832ef61042f6a237cb2687e7 +https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.10-5_cp310.conda#2921c34715e74b3587b4cff4d36844f9 +https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda#8ac3367aafb1cc0a068483c580af8015 https://conda.anaconda.org/conda-forge/linux-64/utfcpp-4.0.5-ha770c72_0.conda#25965c1d1d5fc00ce2b663b73008e3b7 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 -https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.1.0-h77fa898_0.conda#ae061a5ed5f05818acdf9adab72c146d +https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_2.conda#048b02e3962f066da18efe3a21b77672 +https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_1.conda#1ece2ccb1dc8c68639712b05e0fae070 +https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h77fa898_1.conda#cc3573974587f12dda90d96e3e55a702 https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#73aaf86a425cc6e73fcf236a5a46396d https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab -https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.1.0-h77fa898_0.conda#ca0fad6a41ddaef54a153b78eccb5037 +https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_1.conda#38a5cd3be5fb620b48069e27285f1a44 +https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h77fa898_1.conda#3cb76c3f10d3bc7f1105b2fc9db984df +https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.2-heb4867d_0.conda#2b780c0338fc0ffa678ac82c54af51fd +https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb9d3cd8_2.conda#41b599ed2b02abcfdd84302bff174b23 +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.22-hb9d3cd8_0.conda#b422943d5d772b7cc858b36ad2a92db5 +https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.3-h5888daf_0.conda#59f4c43bb1b5ef1c71946ff2cbf59524 +https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_1.conda#e39480b9ca41323497b05492a63bc35b +https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hd5240d6_1.conda#9822b874ea29af082e5d36098d25427d +https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-hc0a3c3a_1.conda#234a5554c53625688d51062645337328 +https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda#edb0dca6bc32e4f4789199455a1dbeb8 +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.2-hb9d3cd8_0.conda#4d638782050ab6faa27275bed57e9b4e +https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda#b3c17d95b5a10c6e64a21fa17573e70e +https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.1-hb9d3cd8_1.conda#19608a9656912805b2b9a2f6bd257b04 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hb9d3cd8_1.conda#77cbc488235ebbaab2b6e912d3934bae +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda#8035c64cb77ed555e3f150b7b3972480 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-hb9d3cd8_1004.conda#bc4cd53a083b6720d61a1519a1900878 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xorgproto-2024.1-hb9d3cd8_1.conda#7c21106b851ec72c037b162c216d8f05 +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.12-h4ab18f5_0.conda#7ed427f0871fd41cb1d9c17727c17589 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda#62ee74e96c5ebb0af99386de58cf9553 -https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.32.2-h4bc722e_0.conda#8024af1ee7078e37fa3101c0a0296af2 https://conda.anaconda.org/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda#418c6ca5929a611cbd69204907a83995 +https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.3-h5888daf_0.conda#6595440079bed734b113de44ffd3cd0a https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.10-h36c2ea0_0.tar.bz2#ac7bc6a654f8f41b352b38f4051135f8 -https://conda.anaconda.org/conda-forge/linux-64/gettext-tools-0.22.5-h59595ed_2.conda#985f2f453fb72408d6b6f1be0f324033 -https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda#3bf7b9fd5a7136126e0234db4b87c8b6 +https://conda.anaconda.org/conda-forge/linux-64/geos-3.13.0-h5888daf_0.conda#40b4ab956c90390e407bb177f8a58bab +https://conda.anaconda.org/conda-forge/linux-64/jsoncpp-1.9.6-h84d6215_0.conda#1190da4988807db89b31e2173128892f https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2#a8832b479f93521a9e7b5b743803be51 -https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hd590300_1.conda#aec6c91c7371c26392a06708a73c70e5 -https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.20-hd590300_0.conda#8e88f9389f1165d7c0936fe40d9a9a79 +https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240722.0-cxx17_h5888daf_1.conda#e1f604644fe8d78e22660e2fec6756bc +https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hb9d3cd8_2.conda#9566f0bd264fbd463002e759b8a82401 +https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hb9d3cd8_2.conda#06f70867945ea6a84d35836af780f1de https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda#172bf1cd1ff8629f2b1179945ed45055 -https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.2-h59595ed_0.conda#e7ba12deb7020dd080c6c70e7b6f6a3d https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 -https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-0.22.5-h59595ed_2.conda#172bcc51059416e7ce99e7b528cede83 -https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.1.0-hc5f4f2c_0.conda#6456c2620c990cd8dde2428a27ba0bc5 +https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_1.conda#f1fd30127802683586f768875127a987 https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda#d66573916ffcf376178462f1b61c941e https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.0.0-hd590300_1.conda#ea25936bb4080d843790b586850f82b8 https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda#30fd6e37fe21f86f4bd26d6ee73eeec7 +https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.4-h7f98852_1002.tar.bz2#e728e874159b042d92b90238a3cb0dc2 https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.5-h4ab18f5_0.conda#601bfb4b3c6f0b844443bb81a56651e0 https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hd590300_0.conda#48f4330bfcd959c3cfb704d424903c82 -https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.1.0-hc0a3c3a_0.conda#1cb187a157136398ddbaae90713e2498 -https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.19.0-h166bdaf_0.tar.bz2#93840744a8552e9ebf6bb1a5dffc125a -https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2#7245a044b4a1980ed83196176b78b73a +https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.44-hadc24fc_0.conda#f4cc49d7aa68316213e4b12be35308d1 +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.0-hadc24fc_0.conda#540296f0ce9d3352188c15a89b30b9ac +https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.0-h0841786_0.conda#1f5a58e686b13bcfde88b93f547d23fe +https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_1.conda#8371ac6457591af2cf6159439c1fd051 +https://conda.anaconda.org/conda-forge/linux-64/libudunits2-2.2.28-h40f5838_3.conda#4bdace082e911a3e1f1f0b721bed5b56 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.4.0-hd590300_0.conda#b26e8aa824079e1be0294e7152ca4559 +https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda#92ed62436b625154323d40d5f2f11dd7 https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda#5aa797f8787fe7a17d1b0821485b5adc -https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-h4ab18f5_1.conda#57d7dc60e9325e3de37ff8dffd18e814 -https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hd590300_1001.conda#ec7398d21e2651e0dcb0044d03b9a339 -https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h59595ed_0.conda#fcea371545eda051b6deafb24889fc69 -https://conda.anaconda.org/conda-forge/linux-64/nettle-3.9.1-h7ab15ed_0.conda#2bf1915cc107738811368afcb0993a59 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_2.conda#85c0dc0bcd110c998b01856975486ee7 +https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda#70caf8bb6cf39a0b6b7efc885f51c0fe https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.2-hd590300_1.conda#c66f837ac65e4d1cdeb80e2a1d5fcc3d -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.1-h4bc722e_2.conda#e1b454497f9f7c1147fdde4b53f1b512 -https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 +https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc https://conda.anaconda.org/conda-forge/linux-64/x264-1!164.3095-h166bdaf_2.tar.bz2#6c99772d483f566d59e25037fea2c4b1 -https://conda.anaconda.org/conda-forge/linux-64/xorg-damageproto-1.2.1-h7f98852_1002.tar.bz2#58c9bb067637c5a13a045a7124eeb027 -https://conda.anaconda.org/conda-forge/linux-64/xorg-glproto-1.4.17-h7f98852_1002.tar.bz2#e41bf01f80d46be87dcae2333a766e75 -https://conda.anaconda.org/conda-forge/linux-64/xorg-kbproto-1.0.7-h7f98852_1002.tar.bz2#4b230e8381279d76131116660f5a241a -https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.1-hd590300_0.conda#b462a33c0be1421532f28bfe8f4a7514 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hd590300_0.conda#2c80dc38fface310c9bd81b17037fee5 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.3-h7f98852_0.tar.bz2#be93aabceefa2fac576e971aef407908 -https://conda.anaconda.org/conda-forge/linux-64/xorg-randrproto-1.5.0-h7f98852_1001.tar.bz2#68cce654461713977dac6f9ac1bce89a -https://conda.anaconda.org/conda-forge/linux-64/xorg-renderproto-0.11.1-h7f98852_1002.tar.bz2#06feff3d2634e3097ce2fe681474b534 -https://conda.anaconda.org/conda-forge/linux-64/xorg-util-macros-1.19.3-h7f98852_0.tar.bz2#b1780cc89cf3949f670d6ca2aa6a7e42 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-h0b41bf4_1003.conda#bce9f945da8ad2ae9b1d7165a64d0f87 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xf86vidmodeproto-2.3.1-h7f98852_1002.tar.bz2#3ceea9668625c18f19530de98b15d5b0 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007.tar.bz2#b4a4381d54784606820704f7b5f05a15 https://conda.anaconda.org/conda-forge/linux-64/xxhash-0.8.2-hd590300_0.conda#f08fb5c89edfc4aadee1c81d4cfb1fa1 https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2#4cb3ad778ec2d5a7acbdf254eb1c42ae +https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda#c9f075ab2f33b3bbee9e62d4ad0a6cd8 https://conda.anaconda.org/conda-forge/linux-64/aom-3.9.1-hac33072_0.conda#346722a0be40f6edc53f12640d301338 +https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb9d3cd8_2.conda#c63b5e52939e795ba8d26e35d767a843 https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.3.0-h59595ed_0.conda#c2f83a5ddadadcdb08fe05863295ee97 https://conda.anaconda.org/conda-forge/linux-64/eigen-3.4.0-h00ab1b0_0.conda#b1b879d6d093f55dd40d58b5eb2f0699 -https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.2-h59595ed_0.conda#53fb86322bdb89496d7579fe3f02fd61 -https://conda.anaconda.org/conda-forge/linux-64/geos-3.12.2-hac33072_0.conda#621d814955342209dc8e7f87c41f1ba0 +https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-h267a509_2.conda#9ae35c3d96db2c94ce0cef86efdfa2cb +https://conda.anaconda.org/conda-forge/linux-64/gl2ps-1.4.2-hae5d5c5_1.conda#00e642ec191a19bf806a3915800e9524 https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hac33072_2.conda#c94a5994ef49749880a8139cf9afcbe1 https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.conda#f87c7b7c2cb45f323ffbce941c78ab7c https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda#bd77f8da987968ec3927990495dc22e4 -https://conda.anaconda.org/conda-forge/linux-64/icu-73.2-h59595ed_0.conda#cc47e1facc155f91abd89b11e48e72ff -https://conda.anaconda.org/conda-forge/linux-64/jsoncpp-1.9.5-h4bd325d_1.tar.bz2#ae7f50dd1e78c7e78b5d2cf7062e559d +https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda#8b189310083baabfb622af68fd9d3ae3 https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f -https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240116.2-cxx17_he02047a_1.conda#c48fc56ec03229f294176923c3265c05 https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.3-h59595ed_0.conda#5e97e271911b8b2001a8b71860c32faa -https://conda.anaconda.org/conda-forge/linux-64/libasprintf-0.22.5-h661eb56_2.conda#dd197c968bf9760bba0031888d431ede -https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hd590300_1.conda#f07002e225d7a60a694d42a7bf5ff53f -https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hd590300_1.conda#5fc11c6020d421960607d821310fcd4d -https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.122-h4ab18f5_0.conda#bbfc4dbe5e97b385ef088f354d65e563 +https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.123-hb9d3cd8_0.conda#ee605e794bdc14e2b7f84c4faa0d8c2c https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 -https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-devel-0.22.5-h59595ed_2.conda#b63d9b6da3653179a278077f0de20014 -https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.1.0-h69a702a_0.conda#f4ca84fbd6d06b0a052fb2d5b96dde41 +https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.2.0-h69a702a_1.conda#0a7f4cd238267c88e5d69f7826a407eb https://conda.anaconda.org/conda-forge/linux-64/libmo_unpack-3.1.2-hf484d3e_1001.tar.bz2#95f32a6a5a666d33886ca5627239f03d -https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.58.0-h47da74e_1.conda#700ac6ea6d53d5510591c4344d5c989a -https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.43-h2797004_0.conda#009981dd9cfcaa4dbfa25ffaed86bcae -https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.46.0-hde9e2c9_0.conda#18aa975d2094c34aef978060ae7da7d8 -https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.0-h0841786_0.conda#1f5a58e686b13bcfde88b93f547d23fe -https://conda.anaconda.org/conda-forge/linux-64/libudunits2-2.2.28-h40f5838_3.conda#4bdace082e911a3e1f1f0b721bed5b56 +https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.64.0-h161d5f1_0.conda#19e57602824042dfd0446292ef90488b +https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-5.28.2-h5b01275_0.conda#ab0bff36363bec94720275a681af8b83 https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libvpx-1.14.1-hac33072_0.conda#cde393f461e0c169d9ffb2fc70f81c33 -https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.16-hd590300_0.conda#151cba22b85a989c2d6ef9633ffee1e4 -https://conda.anaconda.org/conda-forge/linux-64/libzip-1.10.1-h2629f0a_3.conda#ac79812548e7e8cf61f7b0abdef01d3b +https://conda.anaconda.org/conda-forge/linux-64/libzip-1.11.1-hf83b1b0_0.conda#e8536ec89df2aec5f65fefcf4ccd58ba https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 +https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.11.3-he02047a_1.conda#e46f7ac4917215b49df2ea09a694a3fa https://conda.anaconda.org/conda-forge/linux-64/openh264-2.4.1-h59595ed_0.conda#3dfcf61b8e78af08110f5229f79580af -https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.24.1-hc5aa10d_0.tar.bz2#56ee94e34b71742bbdfa832c974e47a8 -https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-h0f59acf_0.conda#3914f7ac1761dce57102c72ca7c35d01 +https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-hba22ea6_2.conda#df359c09c41cd186fffb93a2d87aa6f5 https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 https://conda.anaconda.org/conda-forge/linux-64/pugixml-1.14-h59595ed_0.conda#2c97dd90633508b422c11bd3018206ab +https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda#353823361b1d27eb3960efb076dfcaf6 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.1-ha2e4443_0.conda#6b7dcc7349efd123d493d2dbe85a045f -https://conda.anaconda.org/conda-forge/linux-64/svt-av1-2.1.2-hac33072_0.conda#06c5dec4ebb47213b648a6c4dc8400d6 -https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc -https://conda.anaconda.org/conda-forge/linux-64/wayland-1.23.0-h5291e77_0.conda#c13ca0abd5d1d31d0eebcf86d51da8a4 +https://conda.anaconda.org/conda-forge/linux-64/svt-av1-2.2.1-h5888daf_0.conda#0d9c441855be3d8dfdb2e800fe755059 +https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-h40f5838_3.conda#6bb8deb138f87c9d48320ac21b87e7a1 +https://conda.anaconda.org/conda-forge/linux-64/wayland-1.23.1-h3e06ad9_0.conda#0a732427643ae5e0486a727927791da1 https://conda.anaconda.org/conda-forge/linux-64/x265-3.5-h924138e_3.tar.bz2#e7f6ed84d4623d52ee581325c1587a6b -https://conda.anaconda.org/conda-forge/linux-64/xorg-fixesproto-5.0-h7f98852_1002.tar.bz2#65ad6e1eb4aed2b0611855aff05e04f6 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-h7391055_0.conda#93ee23f12bc2e684548181256edd2cf6 -https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-h4ab18f5_1.conda#9653f1bf3766164d0e65fa723cabbc54 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-hb711507_2.conda#8637c3e5821654d0edf97e2b0404b443 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.1-hb711507_0.conda#ad748ccca349aec3e91743e08b5e2b50 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.10-hb711507_0.conda#0e0cbe0564d03a99afd5fd7b362feecd +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.2-hb711507_0.conda#608e0ef8256b81d04456e8d211eee3e8 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-he73a12e_1.conda#05a8ea5f446de33006171a7afe6ae857 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_0.conda#0b666058a179b744a622d0a4a0c56353 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda#4d056880988120e29d75bfff282e0f45 https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-hef167b5_0.conda#54fe76ab3d0189acaef95156874db7f9 -https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hd590300_1.conda#39f910d205726805a958da408ca194ba -https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-h267a509_2.conda#9ae35c3d96db2c94ce0cef86efdfa2cb -https://conda.anaconda.org/conda-forge/linux-64/gl2ps-1.4.2-hae5d5c5_1.conda#00e642ec191a19bf806a3915800e9524 +https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_2.conda#98514fe74548d768907ce7a13f680e8f +https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda#3f43953b7d3fb3aaa1d0d0723d91e368 -https://conda.anaconda.org/conda-forge/linux-64/libasprintf-devel-0.22.5-h661eb56_2.conda#02e41ab5834dcdcc8590cf29d9526f50 -https://conda.anaconda.org/conda-forge/linux-64/libglib-2.80.3-h8a4344b_1.conda#6ea440297aacee4893f02ad759e6ffbc -https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.27-pthreads_hac2b453_1.conda#ae05ece66d3924ac3d48b4aa3fa96cec -https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-4.25.3-h08a7969_0.conda#6945825cebd2aeb16af4c69d97c32c13 +https://conda.anaconda.org/conda-forge/linux-64/libglib-2.82.2-h2ff4ddf_0.conda#13e8e54035ddd2b91875ba399f0f7c04 +https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_1.conda#80a57756c545ad11f9847835aa21e6b2 +https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.28-pthreads_h94d23a6_0.conda#9ebc9aedafaa2515ab247ff6bb509458 https://conda.anaconda.org/conda-forge/linux-64/libtheora-1.1.1-h4ab18f5_1006.conda#553281a034e9cf8693c9df49f6c78ea1 -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.6.0-h1dd3fc0_3.conda#66f03896ffbe1a110ffda05c7a856504 -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.7-h4c95cb1_3.conda#0ac9aff6010a7751961c8e4b863a40e7 -https://conda.anaconda.org/conda-forge/linux-64/python-3.10.14-hd12c33a_0_cpython.conda#2b4ba962994e8bd4be9ff5b64b75aff2 -https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.46.0-h6d4b2fc_0.conda#77ea8dff5cf8550cc8f5629a6af56323 -https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-h40f5838_3.conda#6bb8deb138f87c9d48320ac21b87e7a1 -https://conda.anaconda.org/conda-forge/noarch/wayland-protocols-1.36-hd8ed1ab_0.conda#c6f690e7d4abf562161477f14533cfd8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.9-hb711507_1.conda#4a6d410296d7e39f00bacdee7df046e9 -https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda#def531a3ac77b7fb8c21d17bb5d0badb +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-he137b08_1.conda#63872517c98aa305da58a757c443698e +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.7-he7c6b58_4.conda#08a9265c637230c37cb1be4a6cad4536 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_2.conda#57a9e7ee3c0840d3c8c9012473978629 +https://conda.anaconda.org/conda-forge/linux-64/python-3.10.15-h4a871b0_2_cpython.conda#98059097f62e97be9aed7ec904055825 +https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.47.0-h9eae976_0.conda#c4cb444844615e1cd4c9d989f770bcc5 +https://conda.anaconda.org/conda-forge/noarch/wayland-protocols-1.37-hd8ed1ab_0.conda#73ec79a77d31eb7e4a3276cd246b776c +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda#a0901183f08b6c7107aab109733a3c91 +https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.43-hb9d3cd8_0.conda#f725c7425d6d7c15e31f3b99a88ea02f +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda#febbab7d15033c913d53c7a2c102309d +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda#4bdb303603e9821baf5fe5fdff1dc8f8 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hb9d3cd8_1.conda#a7a49a8b85122b49214798321e2e96b4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxt-1.3.0-hb9d3cd8_2.conda#d8602724ac0d276c380b97e9eb0f814b +https://conda.anaconda.org/conda-forge/noarch/aiohappyeyeballs-2.4.3-pyhd8ed1ab_0.conda#ec763b0a58960558ca0ad7255a51a237 +https://conda.anaconda.org/conda-forge/noarch/alabaster-1.0.0-pyhd8ed1ab_0.conda#7d78a232029458d0077ede6cda30ed0c https://conda.anaconda.org/conda-forge/noarch/antlr-python-runtime-4.11.1-pyhd8ed1ab_0.tar.bz2#15109c4977d39ad7aa3423f57243e286 https://conda.anaconda.org/conda-forge/linux-64/atk-1.0-2.38.0-h04ea711_2.conda#f730d54ba9cd543666d7220c9f7ed563 -https://conda.anaconda.org/conda-forge/noarch/attrs-23.2.0-pyh71513ae_0.conda#5e4c0743c70186509d1412e03c2d8dfa -https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hd590300_1.conda#f27a24d46e3ea7b70a1f98e50c62508f -https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py310hc6cd4ac_1.conda#1f95722c94f00b69af69a066c7433714 -https://conda.anaconda.org/conda-forge/noarch/certifi-2024.7.4-pyhd8ed1ab_0.conda#24e7fd6ca65997938fff9e5ab6f653e4 +https://conda.anaconda.org/conda-forge/noarch/attrs-24.2.0-pyh71513ae_0.conda#6732fa52eb8e66e5afeb32db8701a791 +https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py310hf71b8c6_2.conda#bf502c169c71e3c6ac0d6175addfacc2 +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-hebfffa5_3.conda#fceaedf1cdbcb02df9699a0d9b005292 +https://conda.anaconda.org/conda-forge/noarch/certifi-2024.8.30-pyhd8ed1ab_0.conda#12f7d00853807b0531775e9be891cb11 https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_0.tar.bz2#ebb5f5f7dc4f1a3780ef7ea7738db08c -https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1ab_0.conda#7f4a9e3fcff3f6356ae99244a014da6a +https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.0-pyhd8ed1ab_0.conda#a374efa97290b8799046df7c5ca17164 https://conda.anaconda.org/conda-forge/noarch/click-8.1.7-unix_pyh707e725_0.conda#f3ad426304898027fc619827ff428eca -https://conda.anaconda.org/conda-forge/noarch/cloudpickle-3.0.0-pyhd8ed1ab_0.conda#753d29fe41bb881e4b9c004f0abf973f +https://conda.anaconda.org/conda-forge/noarch/cloudpickle-3.1.0-pyhd8ed1ab_1.conda#c88ca2bb7099167912e3b26463fff079 https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 https://conda.anaconda.org/conda-forge/noarch/colorcet-3.1.0-pyhd8ed1ab_0.conda#4d155b600b63bc6ba89d91fab74238f8 https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_0.conda#5cd86562580f274031ede6aa6aa24441 -https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.10-py310hc6cd4ac_0.conda#bd1d71ee240be36f1d85c86177d6964f -https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.8-pyhd8ed1ab_0.conda#db16c66b759a64dc5183d69cc3745a52 +https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.27-h54b06d7_7.conda#dce22f70b4e5a407ce88f2be046f4ceb +https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.11-py310h5b1441d_3.conda#f1dd2d9a5c782683c28918f44ba547a8 +https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d +https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.9-pyhd8ed1ab_0.conda#fe521c1608280cc2803ebd26dc252212 https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda#e8cd5d629f65bdf0f3bb312cde14659e https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda#d02ae936e42063ca46af6cdad2dbd1e0 https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda#15dda3cdbf330abfe9f555d22f66db46 -https://conda.anaconda.org/conda-forge/noarch/filelock-3.15.4-pyhd8ed1ab_0.conda#0e7e4388e9d5283e22b35a9443bdbcc9 -https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d -https://conda.anaconda.org/conda-forge/linux-64/frozenlist-1.4.1-py310h2372a71_0.conda#f20cd4d9c1f4a8377d0818c819918bbb -https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.6.1-pyhff2d567_0.conda#996bf792cdb8c0ac38ff54b9fde56841 +https://conda.anaconda.org/conda-forge/noarch/filelock-3.16.1-pyhd8ed1ab_0.conda#916f8ec5dd4128cd5f207a3c4c07b2c6 +https://conda.anaconda.org/conda-forge/linux-64/frozenlist-1.5.0-py310ha75aee5_0.conda#8aac4068f272b6bdeb0aa0f29d8e516f +https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.10.0-pyhff2d567_0.conda#816dbc4679a64e4417cd1385d661bb31 https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.12-hb9ae30d_0.conda#201db6c2d9a3c5e46573ac4cb2e92f4f -https://conda.anaconda.org/conda-forge/linux-64/gettext-0.22.5-h59595ed_2.conda#219ba82e95d7614cf7140d2a4afc0926 https://conda.anaconda.org/conda-forge/linux-64/gts-0.7.6-h977cf35_4.conda#4d8df0b0db060d33c9a702ada998a8fe https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyh9f0ad1d_0.tar.bz2#914d6646c4dbb1fd3ff539830a12fd71 https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_0.tar.bz2#9f765cbfab6870c8435b9eefecd7a1f4 -https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda#c0cc1420498b17414d8617d0b9f506ca +https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_0.conda#7ba2ede0e7c795ff95088daf0dc59753 https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 -https://conda.anaconda.org/conda-forge/noarch/iris-sample-data-2.4.0-pyhd8ed1ab_0.tar.bz2#18ee9c07cf945a33f92caf1ee3d23ad9 -https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.5-py310hd41b1e2_1.conda#b8d67603d43b23ce7e988a5d81a7ab79 +https://conda.anaconda.org/conda-forge/noarch/iris-sample-data-2.5.1-pyhd8ed1ab_0.conda#faf232274689aa60da5a63e7cc5faeb7 +https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.7-py310h3788b33_0.conda#4186d9b4d004b0fe0de6aa62496fb48a https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.16-hb7c19ff_0.conda#51bb7010fc86f70eee639b4bb7a894f5 -https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.7.4-hfca40fe_0.conda#32ddb97f897740641d8d46a829ce1704 -https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-22_linux64_openblas.conda#1a2a0cd3153464fee6646f3dd6dad9b8 -https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.8.0-hca28451_1.conda#b8afb3e3cb3423cc445cf611ab95fdb0 +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-25_linux64_openblas.conda#8ea26d42ca88ec5258802715fe1ee10b +https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h4637d8d_4.conda#d4529f4dff3057982a7617c7ac58fde3 +https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.10.1-hbbe4b11_0.conda#6e801c50a40301f6978c53976917b277 +https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-hd3e95f3_10.conda#30ee3a29c84cf7b842a8c5828c4b7c13 +https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_1.conda#204892bce2e44252b5cf272712f10bdd +https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.0-ha6d2627_1004.conda#df069bea331c8486ac21814969301c1f https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.11.1-default_hecaa2ac_1000.conda#f54aeebefb5c5ff84eca4fb05ca8aa3a -https://conda.anaconda.org/conda-forge/linux-64/libllvm18-18.1.8-h8b73ec9_1.conda#16d94b3586ef3558e5a583598524deb4 -https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.4.0-h2c329e2_0.conda#80030debaa84cfc31755d53742df3ca6 +https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.2-ha7bfdaf_0.conda#128e74a4f8f4fef4dc5130a8bbccc15d +https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.7.0-h2c5496b_1.conda#e2eaefa4de2b7237af7c907b8bbc760a https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2#91e27ef3d05cc772ce627e51cff111c4 -https://conda.anaconda.org/conda-forge/linux-64/loguru-0.7.2-py310hff52083_1.conda#157e6221a079a60c7f6f6fcb87c722aa -https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.5-py310h2372a71_0.conda#f6703fa0214a00bf49d1bef6dc7672d0 -https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.0.8-py310h25c7140_0.conda#ad681a3290620ca6196bcd46ed3101cd -https://conda.anaconda.org/conda-forge/linux-64/multidict-6.0.5-py310h2372a71_0.conda#d4c91d19e4f2f18b64753ac660edad79 +https://conda.anaconda.org/conda-forge/linux-64/loguru-0.7.2-py310hff52083_2.conda#4e8b2a2851668c8ad4d5360845281be9 +https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py310h89163eb_0.conda#5415555830a54d9b4a1307e3e9d942c7 +https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.0-py310h3788b33_0.conda#6b586fb03d84e5bfbb1a8a3d9e2c9b60 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.2-h488ebb8_0.conda#7f2e286780f072ed750df46dc2631138 https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda#cbe1bb1f21567018ce595d9c2be0f0db -https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.2-pyhd8ed1ab_0.conda#6f6cf28bf8e021933869bae3f84b8fc9 +https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.6-pyhd8ed1ab_0.conda#fd8f2b18b65bbf62e8f653100690c8d2 https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda#d3483c8fc2dc2cc3f5cf43e26d60cabf -https://conda.anaconda.org/conda-forge/linux-64/psutil-6.0.0-py310hc51659f_0.conda#b04405826f96f4eb2f502e642d121bb5 +https://conda.anaconda.org/conda-forge/linux-64/propcache-0.2.0-py310ha75aee5_2.conda#d38aa9579b7210c646e6faef1aed5bbb +https://conda.anaconda.org/conda-forge/linux-64/psutil-6.1.0-py310ha75aee5_0.conda#a42a2ed94df11c5cfa5348a317e1f197 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda#844d9eb3b43095b031874477f7d70088 https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda#b7f5c092b8f9800150d998a71b76d5a1 -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.1.2-pyhd8ed1ab_0.conda#b9a4dacf97241704529131a0dfc0494f +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.0-pyhd8ed1ab_1.conda#035c17fbf099f50ff60bf2eb303b0a83 https://conda.anaconda.org/conda-forge/noarch/pyshp-2.3.1-pyhd8ed1ab_0.tar.bz2#92a889dc236a5197612bc85bee6d7174 https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 -https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.1-pyhd8ed1ab_0.conda#98206ea9954216ee7540f0c773f2104d -https://conda.anaconda.org/conda-forge/linux-64/python-xxhash-3.4.1-py310h2372a71_0.conda#b631b889b0b4bc2fca7b8b977ca484b2 +https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.2-pyhd8ed1ab_0.conda#986287f89929b2d629bd6ef6497dc307 +https://conda.anaconda.org/conda-forge/linux-64/python-xxhash-3.5.0-py310ha75aee5_1.conda#8b430470d53744289cb5499bc99a6485 https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda#3eeeeb9e4827ace8c0c1419c85d590ad -https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.1-py310h2372a71_1.conda#bb010e368de4940771368bc3dc4c63e7 +https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.2-py310ha75aee5_1.conda#0d4c5c76ae5f5aac6f0be419963a19dd https://conda.anaconda.org/conda-forge/noarch/scooby-0.10.0-pyhd8ed1ab_0.conda#9e57330f431abbb4c88a5f898a4ba223 -https://conda.anaconda.org/conda-forge/noarch/setuptools-71.0.3-pyhd8ed1ab_0.conda#d4b6e6ce2f7bcaec484b81c447df1028 +https://conda.anaconda.org/conda-forge/noarch/setuptools-75.1.0-pyhd8ed1ab_0.conda#d5cd48392c67fb6849ba459c2c2b671f https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2#4d22a9315e78c6827f806065957d566e https://conda.anaconda.org/conda-forge/noarch/sortedcontainers-2.4.0-pyhd8ed1ab_0.tar.bz2#6d6552722448103793743dabfbda532d @@ -200,130 +208,133 @@ https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.5-pyhd8ed1ab_1.conda#3 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda#da1d979339e2714c30a8e806a33ec087 https://conda.anaconda.org/conda-forge/noarch/tblib-3.0.0-pyhd8ed1ab_0.conda#04eedddeb68ad39871c8127dd1c21f4f https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 -https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 -https://conda.anaconda.org/conda-forge/noarch/toolz-0.12.1-pyhd8ed1ab_0.conda#2fcb582444635e2c402e8569bb94e039 -https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py310hc51659f_0.conda#c5a6aac4a1e0989986d9f06b3c2be2a0 +https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.2-pyhd8ed1ab_0.conda#e977934e00b355ff55ed154904044727 +https://conda.anaconda.org/conda-forge/noarch/toolz-1.0.0-pyhd8ed1ab_0.conda#34feccdd4177f2d3d53c73fc44fd9a37 +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py310ha75aee5_1.conda#260c9ae4b2d9af7d5cce7b721cba6132 https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda#ebe6952715e1d5eb567eeebf25250fa7 -https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-15.1.0-py310h2372a71_0.conda#72637c58d36d9475fda24700c9796f19 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.43.0-pyhd8ed1ab_1.conda#0b5293a157c2b5cd513dd1b03d8d3aae -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h0b41bf4_2.conda#82b6df12252e6f32402b96dacc656fec -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-5.0.3-h7f98852_1004.tar.bz2#e9a21aa4d5e3e5f1aed71e8cefd46b6a -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hd590300_0.conda#ed67c36f215b310412b2af935bf3e530 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxt-1.3.0-hd590300_1.conda#ae92aab42726eb29d16488924f7312cb +https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-15.1.0-py310ha75aee5_1.conda#ee18e67b0bd283f6a75369936451d6ac +https://conda.anaconda.org/conda-forge/noarch/wheel-0.44.0-pyhd8ed1ab_0.conda#d44e3b085abcaef02983c6305b84b584 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.5-hb9d3cd8_0.conda#eb44b3b6deb1cab08d72cb61686fe64c +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda#d3c295b50f092ab525ffe3c2aa4b7413 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.2-hb9d3cd8_0.conda#bb2638cd7fbdd980b1cff9a99a6c1fa8 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda#b5fcc7172d22516e1f965490e65e33a4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda#17dcc85db3c7886650b8908b183d6876 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.4-hb9d3cd8_0.conda#2de7f99d6581a4a7adbff607b5c278ca +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.5-hb9d3cd8_4.conda#7da9007c0582712c4bad4131f89c8372 https://conda.anaconda.org/conda-forge/noarch/zict-3.0.0-pyhd8ed1ab_0.conda#cf30c2c15b82aacb07f9c09e28ff2275 -https://conda.anaconda.org/conda-forge/noarch/zipp-3.19.2-pyhd8ed1ab_0.conda#49808e59df5535116f6878b2a820d6f4 +https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.2-pyhd8ed1ab_0.conda#4daaed111c05672ae669f7036ee5bba3 https://conda.anaconda.org/conda-forge/noarch/accessible-pygments-0.0.5-pyhd8ed1ab_0.conda#1bb1ef9806a9a20872434f58b3e7fc1a https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.3.1-pyhd8ed1ab_0.tar.bz2#d1e1eb7e21a9e2c74279d87dafb68156 https://conda.anaconda.org/conda-forge/noarch/babel-2.14.0-pyhd8ed1ab_0.conda#9669586875baeced8fc30c0826c3270e https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.12.3-pyha770c72_0.conda#332493000404d8411859539a5a630865 -https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-hbb29018_2.conda#b6d90276c5aee9b4407dd94eb0cd40a8 -https://conda.anaconda.org/conda-forge/linux-64/cffi-1.16.0-py310h2fee648_0.conda#45846a970e71ac98fd327da5d40a0a2c +https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.1-py310h8deb56e_0.conda#1fc24a3196ad5ede2a68148be61894f4 https://conda.anaconda.org/conda-forge/noarch/click-default-group-1.2.4-pyhd8ed1ab_0.conda#7c2b6931f9b3548ed78478332095c3e9 -https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.0-py310h5b4e0ec_0.conda#a13d72c877b47870042897a0e667cd3a -https://conda.anaconda.org/conda-forge/linux-64/cytoolz-0.12.3-py310h2372a71_0.conda#21362970a6fea90ca507c253c20465f2 -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.53.1-py310h5b4e0ec_0.conda#2c5257cb35d1946f5e80a0cfd69ed7ec +https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.4-py310h89163eb_0.conda#5222543cdb180f0fecc0d4b9f6b4a225 +https://conda.anaconda.org/conda-forge/linux-64/cytoolz-1.0.0-py310ha75aee5_1.conda#81bbbb02f3664a012ce65c4fa8e8ca35 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.54.1-py310h89163eb_1.conda#d30cf58ede43135249a18c5926a96d3f +https://conda.anaconda.org/conda-forge/linux-64/glew-2.1.0-h9c3ff4c_2.tar.bz2#fb05eb5c47590b247658243d27fc32f1 https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_0.tar.bz2#b748fbf7060927a6e82df7cb5ee8f097 -https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.3-nompi_hdf9ad27_105.conda#7e1729554e209627636a0f6fabcdd115 -https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.0.0-pyha770c72_0.conda#3286556cdd99048d198f72c3f6f69103 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-9.0.0-hda332d3_1.conda#76b32dcf243444aea9c6b804bcfa40b8 +https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.4-nompi_h2d575fe_101.conda#09967792ea2191a0bdb461f9c889e510 +https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.5.0-pyha770c72_0.conda#54198435fce4d64d8a89af22573012a8 https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda#7b86ecb7d3557821c649b3c31e3eb9f2 -https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-22_linux64_openblas.conda#4b31699e0ec5de64d5896e580389c9a1 -https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-h119a65a_9.conda#cfebc557e54905dadc355c0e9f003004 -https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.7-hd590300_0.conda#2b7b0d827c6447cc1d85dc06d5b5de46 -https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-22_linux64_openblas.conda#b083767b6c877e24ee597d93b87ab838 -https://conda.anaconda.org/conda-forge/linux-64/libva-2.22.0-hb711507_0.conda#d12f659072132c9d16e497073fc1f68b +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-25_linux64_openblas.conda#5dbd1b0fc0d01ec5e0e1fbe667281a11 +https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.2-default_hb5137d0_1.conda#7e574c7499bc41f92537634a23fed79a +https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.2-default_h9c6a7e4_1.conda#cb5c5ff12b37aded00d9aaa7b9a86a78 +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-25_linux64_openblas.conda#4dc03a53fc69371a6158d0ed37214cd3 +https://conda.anaconda.org/conda-forge/linux-64/libva-2.22.0-h8a09558_1.conda#139262125a3eac8ff6eef898598745a3 https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.9.1-pyhd8ed1ab_0.conda#dfe0528d0f1c16c1f7c528ea5536ab30 +https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.8-hedd0468_0.conda#dcd0ed5147d8876b0848a552b416ce76 https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda#0badf9c54e24cecfb0ad2f99d680c163 -https://conda.anaconda.org/conda-forge/linux-64/pillow-10.4.0-py310hebfe307_0.conda#89d70dfe2d59edcefc3881be6bff33a6 -https://conda.anaconda.org/conda-forge/noarch/pip-24.0-pyhd8ed1ab_0.conda#f586ac1e56c8638b64f9c8122a7b8a67 -https://conda.anaconda.org/conda-forge/linux-64/proj-9.3.1-h1d62c97_0.conda#44ec51d0857d9be26158bb85caa74fdb -https://conda.anaconda.org/conda-forge/noarch/pytest-8.2.2-pyhd8ed1ab_0.conda#0f3f49c22c7ef3a1195fa61dad3c43be +https://conda.anaconda.org/conda-forge/linux-64/pillow-11.0.0-py310hfeaa1f3_0.conda#1947280342c7259b82a707e38ebc212e +https://conda.anaconda.org/conda-forge/noarch/pip-24.2-pyh8b19718_1.conda#6c78fbb8ddfd64bcb55b5cbafd2d2c43 +https://conda.anaconda.org/conda-forge/linux-64/proj-9.5.0-h12925eb_0.conda#8c29983ebe50cc7e0998c34bc7614222 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda#c03d61f31f38fdb9facf70c29958bf7a https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda#2cf4264fffb9e6eff6031c5b6884d61c -https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.12.0-h434a139_3.conda#c667c11d1e488a38220ede8a34441bff +https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.13.0-h84d6215_0.conda#ee6f7fd1e76061ef1fa307d41fa86a96 https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.12.2-hd8ed1ab_0.conda#52d648bd608f5737b123f510bb5514b5 -https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.26.3-pyhd8ed1ab_0.conda#284008712816c64c85bf2b7fa9f3b264 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.5-h7f98852_1.tar.bz2#bebd3814ec2355fab6a474b07ed73093 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.2-h7f98852_1.tar.bz2#5b0f7da25a4556c9619c3e4b4a98ab07 -https://conda.anaconda.org/conda-forge/linux-64/yarl-1.9.4-py310h2372a71_0.conda#4ad35c8f6a64a6ab708780dad603aef4 +https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.27.0-pyhd8ed1ab_0.conda#a6ed1227ba6ec37cfc2b25e6512f729f +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda#7bbe9a0cc0df0ac5f5a8ad6d6a11af2f https://conda.anaconda.org/conda-forge/noarch/asv_runner-0.2.1-pyhd8ed1ab_0.conda#fdcbeb072c80c805a2ededaa5f91cd79 https://conda.anaconda.org/conda-forge/noarch/async-timeout-4.0.3-pyhd8ed1ab_0.conda#3ce482ec3066e6d809dbbb1d1679f215 -https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.7.9-hb077bed_0.conda#33eded89024f21659b1975886a4acf70 -https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-9.0.0-hfac3d4d_0.conda#c7b47c64af53e8ecee01d101eeab2342 -https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-8.0.0-hd8ed1ab_0.conda#5f8c8ebbe6413a7838cf6ecf14d5d31b -https://conda.anaconda.org/conda-forge/noarch/lazy_loader-0.4-pyhd8ed1ab_0.conda#a284ff318fbdb0dd83928275b4b6087c -https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.2-nompi_h135f659_114.conda#a908e463c710bd6b10a9eaa89fdf003c -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-2024.2.0-h2da1b83_1.conda#9511859bf5221238a2d3fb5322af01d5 -https://conda.anaconda.org/conda-forge/linux-64/numpy-1.26.4-py310hb13e2d6_0.conda#6593de64c935768b6bad3e19b3e978be -https://conda.anaconda.org/conda-forge/noarch/pbr-6.0.0-pyhd8ed1ab_0.conda#8dbab5ba746ed14aa32cb232dc437f8f -https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.6.1-py310hd5c30f3_5.conda#dc2ee770a2299307f3c127af79160d25 +https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-8.5.0-hd8ed1ab_0.conda#2a92e152208121afadf85a5e1f3a5f4d +https://conda.anaconda.org/conda-forge/noarch/lazy-loader-0.4-pyhd8ed1ab_1.conda#4809b9f4c6ce106d443c3f90b8e10db2 +https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.3-h1dc1e6a_0.conda#2a66267ba586dadd110cc991063cfff7 +https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.2-nompi_h2564987_115.conda#c5ce70b76c77a6c9a3107be8d8e8ab0b +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-2024.4.0-hac27bb2_2.conda#ba5ac0bb9ec5aec38dec37c230b12d64 +https://conda.anaconda.org/conda-forge/linux-64/libpq-17.0-h04577a9_4.conda#392cae2a58fbcb9db8c2147c6d6d1620 +https://conda.anaconda.org/conda-forge/linux-64/multidict-6.1.0-py310h89163eb_1.conda#4e13be3228db4b8e1349483e821b6046 +https://conda.anaconda.org/conda-forge/linux-64/numpy-2.1.2-py310hd6e36ab_0.conda#d64ac80cd7861e079770982204d4673b +https://conda.anaconda.org/conda-forge/linux-64/pango-1.54.0-h4c5309f_1.conda#7df02e445367703cd87a574046e3a6f0 +https://conda.anaconda.org/conda-forge/noarch/pbr-6.1.0-pyhd8ed1ab_0.conda#5a166b998fd17cdaaaadaccdd71a363f +https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.7.0-py310h2e9f774_0.conda#42a3ea3c283d930ae6d156b97ffe4740 https://conda.anaconda.org/conda-forge/noarch/pytest-cov-5.0.0-pyhd8ed1ab_0.conda#c54c0107057d67ddf077751339ec2c63 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_0.conda#b39568655c127a9c4a44d178ac99b6d0 https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-8.1.0-pyhd8ed1ab_0.conda#ba9f7f0ec4f2a18de3e7bce67c4a431e -https://conda.anaconda.org/conda-forge/linux-64/tbb-devel-2021.12.0-hfcbfbdb_3.conda#dd410ed856f34c994f1549079ff601bf -https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py310hd41b1e2_4.conda#35e87277fba9944b8a975113538bb5df -https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py310h64cae3c_0.conda#b527de1849629f2635dafc77745b015a -https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.9.5-py310h2372a71_0.conda#00b6dda5bb36ac4226a051db2d406d22 -https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.4-py310h261611a_0.conda#5c0e2cd80ceab2ac5201459cc016b88b +https://conda.anaconda.org/conda-forge/linux-64/tbb-devel-2021.13.0-h94b29a5_0.conda#4431bd4ace17dd09b97caf68509b016b +https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py310h3788b33_5.conda#e05b0475166b68c9dc4d7937e0315654 +https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py310ha39cb0e_1.conda#f49de34fb99934bf49ab330b5caffd64 +https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.4-py310hf462985_1.conda#c2d5289e6cbcecf2c549e01772fe5274 https://conda.anaconda.org/conda-forge/noarch/colorspacious-1.1.2-pyh24bf2e0_0.tar.bz2#b73afa0d009a51cabd3ec99c4d2ef4f3 -https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.2.1-py310hd41b1e2_0.conda#60ee50b1968f802f2a487ba36d4cce0d -https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.7.0-pyhd8ed1ab_0.conda#755e47653ae38f5c50f1435af756e844 -https://conda.anaconda.org/conda-forge/noarch/identify-2.6.0-pyhd8ed1ab_0.conda#f80cc5989f445f23b1622d6c455896d9 -https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.1-h39113c1_2.conda#25db2ea6b8fefce451369e2cc826f6f4 -https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.1-h97afed2_0.conda#00bd7406d24d6574f2de3839b60e0925 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-batch-plugin-2024.2.0-hb045406_1.conda#70d82a64e6d07f4d6e07cae6b0bd4bd1 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-plugin-2024.2.0-hb045406_1.conda#f1e2a8ded23cef03804c4edb2edfb986 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-hetero-plugin-2024.2.0-h5c03a75_1.conda#95d2d3baaa1e456ef65c713a5d99b815 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-cpu-plugin-2024.2.0-h2da1b83_1.conda#9e49f87d8f99dc9724f52b3fac904106 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-gpu-plugin-2024.2.0-h2da1b83_1.conda#a9712fae44d01d906e228c49235e3b89 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-npu-plugin-2024.2.0-he02047a_1.conda#5c2d064181e686cf5cfac6f1a1ee4e91 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-ir-frontend-2024.2.0-h5c03a75_1.conda#89addf0fc0f489fa0c076f1c8c0d62bf -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-onnx-frontend-2024.2.0-h07e8aee_1.conda#9b0a13989b35302e47da13842683804d -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-paddle-frontend-2024.2.0-h07e8aee_1.conda#7b3680d3fd00e1f91d5faf9c97c7ae78 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-pytorch-frontend-2024.2.0-he02047a_1.conda#ac43b516c128411f84f1e19c875998f1 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-frontend-2024.2.0-h39126c6_1.conda#11acf52cac790edcf087b89e83834f7d -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-lite-frontend-2024.2.0-he02047a_1.conda#e7f91b35e3aa7abe880fc9192a761fc0 -https://conda.anaconda.org/conda-forge/linux-64/mo_pack-0.3.0-py310h2372a71_1.conda#dfcf64f67961eb9686676f96fdb4b4d1 -https://conda.anaconda.org/conda-forge/linux-64/netcdf-fortran-4.6.1-nompi_h228c76a_104.conda#91bc3ac73308181d55a09d9e4aeb4496 -https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.2-py310hf9f9076_1.conda#18100768350158f1795ab9ad7d06d5ca -https://conda.anaconda.org/conda-forge/linux-64/pango-1.54.0-h4c5309f_1.conda#7df02e445367703cd87a574046e3a6f0 -https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.3.12-py310h261611a_1.conda#d524e0873c62fcfcc154708772d014df -https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.6.0-py310h261611a_0.conda#04a405ee0bccb4de8d1ed0c87704f5f6 -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.14.0-py310h93e2701_1.conda#c6b2a8134aa49940afe552f69bdef957 -https://conda.anaconda.org/conda-forge/linux-64/shapely-2.0.5-py310h019a838_0.conda#2902ec08257b19d75d08a375cdc37c2c -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-apidoc-0.3.0-py_1.tar.bz2#855b087883443abb10f5faf6eef40860 -https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.2-pyhd8ed1ab_1.conda#e804c43f58255e977093a2298e442bb8 -https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.2.0-py310h261611a_5.conda#643414a9f73226b2a6a43a4800734d3b -https://conda.anaconda.org/conda-forge/noarch/distributed-2024.7.0-pyhd8ed1ab_0.conda#2ae917b0098f286f63f69ec9365fb0b1 -https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.191-h924a536_0.conda#73d050766060acd2b3a289f27d857090 -https://conda.anaconda.org/conda-forge/linux-64/esmf-8.6.1-nompi_h0a5817f_2.conda#e23c62f75f67166cf4ca137fc8bcdce7 -https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-7.0.1-gpl_h9be9148_104.conda#107fd9222d9f628608b07b69abba9420 +https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.0-py310h3788b33_2.conda#de92ea39a4d3afe19b6ee56701ebfa05 +https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.10.0-pyhd8ed1ab_0.conda#7823092a3cf14e98a52d2a2875c47c80 https://conda.anaconda.org/conda-forge/linux-64/gtk2-2.24.33-h6470451_5.conda#1483ba046164be27df7f6eddbcec3a12 +https://conda.anaconda.org/conda-forge/noarch/identify-2.6.1-pyhd8ed1ab_0.conda#43f629202f9eec21be5f71171fb5daf8 +https://conda.anaconda.org/conda-forge/noarch/lazy_loader-0.4-pyhd8ed1ab_1.conda#ec6f70b8a5242936567d4f886726a372 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-batch-plugin-2024.4.0-h4d9b6c2_2.conda#1d05a25da36ba5f98291d7237fc6b8ce +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-plugin-2024.4.0-h4d9b6c2_2.conda#838b2db868f9ab69a7bad9c065a3362d +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-hetero-plugin-2024.4.0-h3f63f65_2.conda#00a6127960a3f41d4bfcabd35d5fbeec +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-cpu-plugin-2024.4.0-hac27bb2_2.conda#6cfc840bc39c17d92fb25e5a35789e5b +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-gpu-plugin-2024.4.0-hac27bb2_2.conda#9e9814b40d8fdfd8485451e3fa2f1719 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-npu-plugin-2024.4.0-hac27bb2_2.conda#724719ce97feb6f310f88ae8dbb40afd +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-ir-frontend-2024.4.0-h3f63f65_2.conda#8908f31eab30f65636eb61ab9cb1f3ad +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-onnx-frontend-2024.4.0-h5c8f2c3_2.conda#e098caa87868e8dcc7ed5d011981207d +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-paddle-frontend-2024.4.0-h5c8f2c3_2.conda#59bb8c3502cb9d35f1fb26691730288c +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-pytorch-frontend-2024.4.0-h5888daf_2.conda#e0b88fd64dc95f715ef52e607a9af89b +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-frontend-2024.4.0-h6481b9d_2.conda#12bf831b85f17368bc71a26ac93a8493 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-lite-frontend-2024.4.0-h5888daf_2.conda#d48c774c40ea2047adbff043e9076e7a +https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.58.4-hc0ffecb_0.conda#83f045969988f5c7a65f3950b95a8b35 +https://conda.anaconda.org/conda-forge/linux-64/mo_pack-0.3.1-py310ha75aee5_1.conda#48781b625a5c7701e04d222752cb2f62 +https://conda.anaconda.org/conda-forge/linux-64/netcdf-fortran-4.6.1-nompi_ha5d1325_107.conda#5bd5042289ef82196bae48948314cdf9 +https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.3-py310h5eaa309_1.conda#e67778e1cac3bca3b3300f6164f7ffb9 +https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.3.13-py310hf462985_1.conda#4f1c137b6ea5e8c7ce95c28b053843cc +https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.7.0-py310hf462985_2.conda#bb603a9ffd8f7e97c93c74a5e3c3febd +https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.7.3-h6e8976b_1.conda#f3234422a977b5d400ccf503ad55c5d1 +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.14.1-py310hfcf56fc_1.conda#d9b1b75a227dbc42f3fe0e8bc852b805 +https://conda.anaconda.org/conda-forge/linux-64/shapely-2.0.6-py310had3dfd6_2.conda#a4166b41e54d22e794859641b7cae2d0 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-apidoc-0.3.0-py_1.tar.bz2#855b087883443abb10f5faf6eef40860 +https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.3-pyhd8ed1ab_0.conda#6b55867f385dd762ed99ea687af32a69 +https://conda.anaconda.org/conda-forge/linux-64/yarl-1.16.0-py310ha75aee5_0.conda#f0734f65184577c08c9f1ba92cd9f57f +https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.10.10-py310h89163eb_0.conda#cdc075f4328556adf4dde97b4f4a0532 +https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.2.0-py310hf462985_6.conda#b8ad2d561f4e0db4f09d06cc0e73e0b0 +https://conda.anaconda.org/conda-forge/noarch/distributed-2024.10.0-pyhd8ed1ab_0.conda#b3b498f7bcc9a2543ad72a3501f3d87b +https://conda.anaconda.org/conda-forge/linux-64/esmf-8.6.1-nompi_h6063b07_4.conda#3108bfa76cd8a3ebc5546797106946e5 +https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-6.1.2-gpl_h8657690_705.conda#bba34ade586dc53222d5e0387f7733c2 +https://conda.anaconda.org/conda-forge/linux-64/graphviz-12.0.0-hba01fac_0.conda#953e31ea00d46beb7e64a79fc291ec44 https://conda.anaconda.org/conda-forge/noarch/imagehash-4.3.1-pyhd8ed1ab_0.tar.bz2#132ad832787a2156be1f1b309835001a -https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.58.2-h9564881_1.conda#c6a47e6f551890e82e92e4c1b84be353 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.8.4-py310hef631a5_2.conda#b3fa3fc2a0fa8b53b913c94297b12e27 -https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.1-nompi_py310hf3005e6_101.conda#409736627835306542425033e2a41dd2 -https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.7.1-pyha770c72_0.conda#724bc4489c1174fc8e3233b0624fa51f -https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.3.0-py310h261611a_2.conda#62de771a916e107222348d9ae612b0c5 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.2-py310h68603db_1.conda#989ef368e7b81b6c28e608e651a2a7d8 +https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.2-nompi_py310h5146f0f_100.conda#82a474392c02d35a969aaad569cbbca8 +https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.0.1-pyha770c72_0.conda#5971cc64048943605f352f7f8612de6c +https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.3.0-py310hf462985_3.conda#7fd2a4e83e8ff3a760984300dad6297c https://conda.anaconda.org/conda-forge/noarch/requests-2.32.3-pyhd8ed1ab_0.conda#5ede4753180c7a550a443c430dc8ab52 -https://conda.anaconda.org/conda-forge/noarch/wslink-2.1.1-pyhd8ed1ab_0.conda#6b1aef9c878c58baa7bb9f0d44457174 -https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.23.0-py310hf9f9076_1.conda#dd5c97834c12bae782b35261e0bea7b4 +https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.24.0-py310h5eaa309_0.conda#ca4d935c1715f95b6e86846ad1675a2b https://conda.anaconda.org/conda-forge/noarch/cmocean-4.0.3-pyhd8ed1ab_0.conda#53df00540de0348ed1b2a62684dd912b https://conda.anaconda.org/conda-forge/noarch/esmpy-8.6.1-pyhc1e730c_0.conda#25a9661177fd68bfdb4314fd658e5c3b -https://conda.anaconda.org/conda-forge/linux-64/graphviz-11.0.0-hc68bbd7_0.conda#52a531ef95358086a56086c45d97ab75 -https://conda.anaconda.org/conda-forge/linux-64/mesalib-24.1.4-h3ac77ca_0.conda#083464147e4169cf088522070964e0cf https://conda.anaconda.org/conda-forge/noarch/nc-time-axis-1.4.1-pyhd8ed1ab_0.tar.bz2#281b58948bf60a2582de9e548bcc5369 https://conda.anaconda.org/conda-forge/noarch/pooch-1.8.2-pyhd8ed1ab_0.conda#8dab97d8a9616e07d779782995710aed -https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.3.1-osmesa_py310ha0fd742_101.conda#b9addfb3506a4e2d831f1c7a66d06fe7 -https://conda.anaconda.org/conda-forge/linux-64/vtk-io-ffmpeg-9.3.1-osmesa_py310hd1cd433_101.conda#bd12505efaf8ce18d23fe74721b3e186 -https://conda.anaconda.org/conda-forge/linux-64/vtk-9.3.1-osmesa_py310h7c0142d_101.conda#4e64cbf6d1c4d0eb1d8d86d12c4b777c -https://conda.anaconda.org/conda-forge/noarch/pyvista-0.44.0-pyhd8ed1ab_0.conda#16270d42141769c8342e067d25acc6ce -https://conda.anaconda.org/conda-forge/noarch/geovista-0.5.1-pyhd8ed1ab_0.conda#22958696ccc609071ba40867090bfd3a -https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.15.4-pyhd8ed1ab_0.conda#c7c50dd5192caa58a05e6a4248a27acb +https://conda.anaconda.org/conda-forge/noarch/wslink-2.2.1-pyhd8ed1ab_0.conda#74674b93806167c26da4eca7613bc225 +https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.3.1-qt_py310h9617cfe_209.conda#1989896d5ae944eced08372bda5676a5 +https://conda.anaconda.org/conda-forge/linux-64/vtk-io-ffmpeg-9.3.1-qt_py310hc8241c7_209.conda#063eb6107225478aa00f283b102f3ec8 +https://conda.anaconda.org/conda-forge/linux-64/vtk-9.3.1-qt_py310he5e186c_209.conda#03fd79331809ea4812c5430e47c04723 +https://conda.anaconda.org/conda-forge/noarch/pyvista-0.44.1-pyhd8ed1ab_0.conda#0731b45087c0358ca8b7d9fe855dec1a +https://conda.anaconda.org/conda-forge/noarch/geovista-0.5.3-pyhd8ed1ab_0.conda#4b12a3321889056bf9a000be9a0763b3 +https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.16.0-pyhd8ed1ab_0.conda#344261b0e77f5d2faaffb4eac225eeb7 https://conda.anaconda.org/conda-forge/noarch/sphinx-copybutton-0.5.2-pyhd8ed1ab_0.conda#ac832cc43adc79118cf6e23f1f9b8995 -https://conda.anaconda.org/conda-forge/noarch/sphinx-design-0.6.0-pyhd8ed1ab_0.conda#b04f3c04e4f7939c6207dc0c0355f468 -https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.16.0-pyhd8ed1ab_0.conda#add28691ee89e875b190eda07929d5d4 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd8ed1ab_0.conda#611a35a27914fac3aa37611a6fe40bb5 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.6-pyhd8ed1ab_0.conda#d7e4954df0d3aea2eacc7835ad12671d -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.5-pyhd8ed1ab_0.conda#7e1e7437273682ada2ed5e9e9714b140 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.7-pyhd8ed1ab_0.conda#26acae54b06f178681bfb551760f5dd1 -https://conda.anaconda.org/conda-forge/noarch/sphinx-7.4.5-pyhd8ed1ab_0.conda#98a3e9786dd637216c6a028f5061cd71 +https://conda.anaconda.org/conda-forge/noarch/sphinx-design-0.6.1-pyhd8ed1ab_1.conda#db0f1eb28b6df3a11e89437597309009 +https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.18.0-pyhd8ed1ab_0.conda#dc78276cbf5ec23e4b959d1bbd9caadb +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-2.0.0-pyhd8ed1ab_0.conda#9075bd8c033f0257122300db914e49c9 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-2.0.0-pyhd8ed1ab_0.conda#b3bcc38c471ebb738854f52a36059b48 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.1.0-pyhd8ed1ab_0.conda#e25640d692c02e8acfff0372f547e940 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-2.0.0-pyhd8ed1ab_0.conda#d6e5ea5fe00164ac6c2dcc5d76a42192 +https://conda.anaconda.org/conda-forge/noarch/sphinx-8.1.3-pyhd8ed1ab_0.conda#05706dd5a145a9c91861495cd435409a https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda#e507335cb4ca9cff4c3d0fa9cdab255e diff --git a/requirements/locks/py311-linux-64.lock b/requirements/locks/py311-linux-64.lock index 9ef2aa51f7..60a47736e4 100644 --- a/requirements/locks/py311-linux-64.lock +++ b/requirements/locks/py311-linux-64.lock @@ -1,198 +1,207 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 68bd288d5cf8db4a84a47fd6676db6b9710bd88e4fdb0b2228991b72ac3d4336 +# input_hash: 58de0176aff465b8a68544e32553b8c5648f581ece5d2c4df0d333dd456ea851 @EXPLICIT https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 -https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.7.4-hbcca054_0.conda#23ab7665c5f63cfb9f1f6195256daac6 +https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda#c27d1c142233b5bc9ca570c6e2e0c244 https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb -https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_2.conda#cbbe59391138ea5ad3658c76912e147f -https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-hf3520f5_7.conda#b80f2f396ca2c28b8c14c437a4ed1e74 -https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.11.3-h59595ed_0.conda#df9ae69b85e0cab9bde23eff1e87f183 -https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.11-4_cp311.conda#d786502c97404c94d7d58d258a445a65 -https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda#161081fc7cec0bfda0d86d7cb595f8d8 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda#49023d73832ef61042f6a237cb2687e7 +https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.11-5_cp311.conda#139a8d40c8a2f430df31048949e450de +https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda#8ac3367aafb1cc0a068483c580af8015 https://conda.anaconda.org/conda-forge/linux-64/utfcpp-4.0.5-ha770c72_0.conda#25965c1d1d5fc00ce2b663b73008e3b7 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 -https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.1.0-h77fa898_0.conda#ae061a5ed5f05818acdf9adab72c146d +https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_2.conda#048b02e3962f066da18efe3a21b77672 +https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_1.conda#1ece2ccb1dc8c68639712b05e0fae070 +https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h77fa898_1.conda#cc3573974587f12dda90d96e3e55a702 https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#73aaf86a425cc6e73fcf236a5a46396d https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab -https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.1.0-h77fa898_0.conda#ca0fad6a41ddaef54a153b78eccb5037 +https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_1.conda#38a5cd3be5fb620b48069e27285f1a44 +https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h77fa898_1.conda#3cb76c3f10d3bc7f1105b2fc9db984df +https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.2-heb4867d_0.conda#2b780c0338fc0ffa678ac82c54af51fd +https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb9d3cd8_2.conda#41b599ed2b02abcfdd84302bff174b23 +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.22-hb9d3cd8_0.conda#b422943d5d772b7cc858b36ad2a92db5 +https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.3-h5888daf_0.conda#59f4c43bb1b5ef1c71946ff2cbf59524 +https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_1.conda#e39480b9ca41323497b05492a63bc35b +https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hd5240d6_1.conda#9822b874ea29af082e5d36098d25427d +https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-hc0a3c3a_1.conda#234a5554c53625688d51062645337328 +https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda#edb0dca6bc32e4f4789199455a1dbeb8 +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.2-hb9d3cd8_0.conda#4d638782050ab6faa27275bed57e9b4e +https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda#b3c17d95b5a10c6e64a21fa17573e70e +https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.1-hb9d3cd8_1.conda#19608a9656912805b2b9a2f6bd257b04 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hb9d3cd8_1.conda#77cbc488235ebbaab2b6e912d3934bae +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda#8035c64cb77ed555e3f150b7b3972480 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-hb9d3cd8_1004.conda#bc4cd53a083b6720d61a1519a1900878 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xorgproto-2024.1-hb9d3cd8_1.conda#7c21106b851ec72c037b162c216d8f05 +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.12-h4ab18f5_0.conda#7ed427f0871fd41cb1d9c17727c17589 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda#62ee74e96c5ebb0af99386de58cf9553 -https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.32.2-h4bc722e_0.conda#8024af1ee7078e37fa3101c0a0296af2 https://conda.anaconda.org/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda#418c6ca5929a611cbd69204907a83995 +https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.3-h5888daf_0.conda#6595440079bed734b113de44ffd3cd0a https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.10-h36c2ea0_0.tar.bz2#ac7bc6a654f8f41b352b38f4051135f8 -https://conda.anaconda.org/conda-forge/linux-64/gettext-tools-0.22.5-h59595ed_2.conda#985f2f453fb72408d6b6f1be0f324033 -https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda#3bf7b9fd5a7136126e0234db4b87c8b6 +https://conda.anaconda.org/conda-forge/linux-64/geos-3.13.0-h5888daf_0.conda#40b4ab956c90390e407bb177f8a58bab +https://conda.anaconda.org/conda-forge/linux-64/jsoncpp-1.9.6-h84d6215_0.conda#1190da4988807db89b31e2173128892f https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2#a8832b479f93521a9e7b5b743803be51 -https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hd590300_1.conda#aec6c91c7371c26392a06708a73c70e5 -https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.20-hd590300_0.conda#8e88f9389f1165d7c0936fe40d9a9a79 +https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240722.0-cxx17_h5888daf_1.conda#e1f604644fe8d78e22660e2fec6756bc +https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hb9d3cd8_2.conda#9566f0bd264fbd463002e759b8a82401 +https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hb9d3cd8_2.conda#06f70867945ea6a84d35836af780f1de https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda#172bf1cd1ff8629f2b1179945ed45055 -https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.2-h59595ed_0.conda#e7ba12deb7020dd080c6c70e7b6f6a3d https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 -https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-0.22.5-h59595ed_2.conda#172bcc51059416e7ce99e7b528cede83 -https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.1.0-hc5f4f2c_0.conda#6456c2620c990cd8dde2428a27ba0bc5 +https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_1.conda#f1fd30127802683586f768875127a987 https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda#d66573916ffcf376178462f1b61c941e https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.0.0-hd590300_1.conda#ea25936bb4080d843790b586850f82b8 https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda#30fd6e37fe21f86f4bd26d6ee73eeec7 +https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.4-h7f98852_1002.tar.bz2#e728e874159b042d92b90238a3cb0dc2 https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.5-h4ab18f5_0.conda#601bfb4b3c6f0b844443bb81a56651e0 https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hd590300_0.conda#48f4330bfcd959c3cfb704d424903c82 -https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.1.0-hc0a3c3a_0.conda#1cb187a157136398ddbaae90713e2498 -https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.19.0-h166bdaf_0.tar.bz2#93840744a8552e9ebf6bb1a5dffc125a -https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2#7245a044b4a1980ed83196176b78b73a +https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.44-hadc24fc_0.conda#f4cc49d7aa68316213e4b12be35308d1 +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.0-hadc24fc_0.conda#540296f0ce9d3352188c15a89b30b9ac +https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.0-h0841786_0.conda#1f5a58e686b13bcfde88b93f547d23fe +https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_1.conda#8371ac6457591af2cf6159439c1fd051 +https://conda.anaconda.org/conda-forge/linux-64/libudunits2-2.2.28-h40f5838_3.conda#4bdace082e911a3e1f1f0b721bed5b56 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.4.0-hd590300_0.conda#b26e8aa824079e1be0294e7152ca4559 +https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda#92ed62436b625154323d40d5f2f11dd7 https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda#5aa797f8787fe7a17d1b0821485b5adc -https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-h4ab18f5_1.conda#57d7dc60e9325e3de37ff8dffd18e814 -https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hd590300_1001.conda#ec7398d21e2651e0dcb0044d03b9a339 -https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h59595ed_0.conda#fcea371545eda051b6deafb24889fc69 -https://conda.anaconda.org/conda-forge/linux-64/nettle-3.9.1-h7ab15ed_0.conda#2bf1915cc107738811368afcb0993a59 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_2.conda#85c0dc0bcd110c998b01856975486ee7 +https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda#70caf8bb6cf39a0b6b7efc885f51c0fe https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.2-hd590300_1.conda#c66f837ac65e4d1cdeb80e2a1d5fcc3d -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.1-h4bc722e_2.conda#e1b454497f9f7c1147fdde4b53f1b512 -https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 +https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc https://conda.anaconda.org/conda-forge/linux-64/x264-1!164.3095-h166bdaf_2.tar.bz2#6c99772d483f566d59e25037fea2c4b1 -https://conda.anaconda.org/conda-forge/linux-64/xorg-damageproto-1.2.1-h7f98852_1002.tar.bz2#58c9bb067637c5a13a045a7124eeb027 -https://conda.anaconda.org/conda-forge/linux-64/xorg-glproto-1.4.17-h7f98852_1002.tar.bz2#e41bf01f80d46be87dcae2333a766e75 -https://conda.anaconda.org/conda-forge/linux-64/xorg-kbproto-1.0.7-h7f98852_1002.tar.bz2#4b230e8381279d76131116660f5a241a -https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.1-hd590300_0.conda#b462a33c0be1421532f28bfe8f4a7514 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hd590300_0.conda#2c80dc38fface310c9bd81b17037fee5 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.3-h7f98852_0.tar.bz2#be93aabceefa2fac576e971aef407908 -https://conda.anaconda.org/conda-forge/linux-64/xorg-randrproto-1.5.0-h7f98852_1001.tar.bz2#68cce654461713977dac6f9ac1bce89a -https://conda.anaconda.org/conda-forge/linux-64/xorg-renderproto-0.11.1-h7f98852_1002.tar.bz2#06feff3d2634e3097ce2fe681474b534 -https://conda.anaconda.org/conda-forge/linux-64/xorg-util-macros-1.19.3-h7f98852_0.tar.bz2#b1780cc89cf3949f670d6ca2aa6a7e42 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-h0b41bf4_1003.conda#bce9f945da8ad2ae9b1d7165a64d0f87 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xf86vidmodeproto-2.3.1-h7f98852_1002.tar.bz2#3ceea9668625c18f19530de98b15d5b0 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007.tar.bz2#b4a4381d54784606820704f7b5f05a15 https://conda.anaconda.org/conda-forge/linux-64/xxhash-0.8.2-hd590300_0.conda#f08fb5c89edfc4aadee1c81d4cfb1fa1 https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2#4cb3ad778ec2d5a7acbdf254eb1c42ae +https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda#c9f075ab2f33b3bbee9e62d4ad0a6cd8 https://conda.anaconda.org/conda-forge/linux-64/aom-3.9.1-hac33072_0.conda#346722a0be40f6edc53f12640d301338 +https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb9d3cd8_2.conda#c63b5e52939e795ba8d26e35d767a843 https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.3.0-h59595ed_0.conda#c2f83a5ddadadcdb08fe05863295ee97 https://conda.anaconda.org/conda-forge/linux-64/eigen-3.4.0-h00ab1b0_0.conda#b1b879d6d093f55dd40d58b5eb2f0699 -https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.2-h59595ed_0.conda#53fb86322bdb89496d7579fe3f02fd61 -https://conda.anaconda.org/conda-forge/linux-64/geos-3.12.2-hac33072_0.conda#621d814955342209dc8e7f87c41f1ba0 +https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-h267a509_2.conda#9ae35c3d96db2c94ce0cef86efdfa2cb +https://conda.anaconda.org/conda-forge/linux-64/gl2ps-1.4.2-hae5d5c5_1.conda#00e642ec191a19bf806a3915800e9524 https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hac33072_2.conda#c94a5994ef49749880a8139cf9afcbe1 https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.conda#f87c7b7c2cb45f323ffbce941c78ab7c https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda#bd77f8da987968ec3927990495dc22e4 -https://conda.anaconda.org/conda-forge/linux-64/icu-73.2-h59595ed_0.conda#cc47e1facc155f91abd89b11e48e72ff -https://conda.anaconda.org/conda-forge/linux-64/jsoncpp-1.9.5-h4bd325d_1.tar.bz2#ae7f50dd1e78c7e78b5d2cf7062e559d +https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda#8b189310083baabfb622af68fd9d3ae3 https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f -https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240116.2-cxx17_he02047a_1.conda#c48fc56ec03229f294176923c3265c05 https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.3-h59595ed_0.conda#5e97e271911b8b2001a8b71860c32faa -https://conda.anaconda.org/conda-forge/linux-64/libasprintf-0.22.5-h661eb56_2.conda#dd197c968bf9760bba0031888d431ede -https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hd590300_1.conda#f07002e225d7a60a694d42a7bf5ff53f -https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hd590300_1.conda#5fc11c6020d421960607d821310fcd4d -https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.122-h4ab18f5_0.conda#bbfc4dbe5e97b385ef088f354d65e563 +https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.123-hb9d3cd8_0.conda#ee605e794bdc14e2b7f84c4faa0d8c2c https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 -https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-devel-0.22.5-h59595ed_2.conda#b63d9b6da3653179a278077f0de20014 -https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.1.0-h69a702a_0.conda#f4ca84fbd6d06b0a052fb2d5b96dde41 +https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.2.0-h69a702a_1.conda#0a7f4cd238267c88e5d69f7826a407eb https://conda.anaconda.org/conda-forge/linux-64/libmo_unpack-3.1.2-hf484d3e_1001.tar.bz2#95f32a6a5a666d33886ca5627239f03d -https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.58.0-h47da74e_1.conda#700ac6ea6d53d5510591c4344d5c989a -https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.43-h2797004_0.conda#009981dd9cfcaa4dbfa25ffaed86bcae -https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.46.0-hde9e2c9_0.conda#18aa975d2094c34aef978060ae7da7d8 -https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.0-h0841786_0.conda#1f5a58e686b13bcfde88b93f547d23fe -https://conda.anaconda.org/conda-forge/linux-64/libudunits2-2.2.28-h40f5838_3.conda#4bdace082e911a3e1f1f0b721bed5b56 +https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.64.0-h161d5f1_0.conda#19e57602824042dfd0446292ef90488b +https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-5.28.2-h5b01275_0.conda#ab0bff36363bec94720275a681af8b83 https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libvpx-1.14.1-hac33072_0.conda#cde393f461e0c169d9ffb2fc70f81c33 -https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.16-hd590300_0.conda#151cba22b85a989c2d6ef9633ffee1e4 -https://conda.anaconda.org/conda-forge/linux-64/libzip-1.10.1-h2629f0a_3.conda#ac79812548e7e8cf61f7b0abdef01d3b +https://conda.anaconda.org/conda-forge/linux-64/libzip-1.11.1-hf83b1b0_0.conda#e8536ec89df2aec5f65fefcf4ccd58ba https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 +https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.11.3-he02047a_1.conda#e46f7ac4917215b49df2ea09a694a3fa https://conda.anaconda.org/conda-forge/linux-64/openh264-2.4.1-h59595ed_0.conda#3dfcf61b8e78af08110f5229f79580af -https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.24.1-hc5aa10d_0.tar.bz2#56ee94e34b71742bbdfa832c974e47a8 -https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-h0f59acf_0.conda#3914f7ac1761dce57102c72ca7c35d01 +https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-hba22ea6_2.conda#df359c09c41cd186fffb93a2d87aa6f5 https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 https://conda.anaconda.org/conda-forge/linux-64/pugixml-1.14-h59595ed_0.conda#2c97dd90633508b422c11bd3018206ab +https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda#353823361b1d27eb3960efb076dfcaf6 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.1-ha2e4443_0.conda#6b7dcc7349efd123d493d2dbe85a045f -https://conda.anaconda.org/conda-forge/linux-64/svt-av1-2.1.2-hac33072_0.conda#06c5dec4ebb47213b648a6c4dc8400d6 -https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc -https://conda.anaconda.org/conda-forge/linux-64/wayland-1.23.0-h5291e77_0.conda#c13ca0abd5d1d31d0eebcf86d51da8a4 +https://conda.anaconda.org/conda-forge/linux-64/svt-av1-2.2.1-h5888daf_0.conda#0d9c441855be3d8dfdb2e800fe755059 +https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-h40f5838_3.conda#6bb8deb138f87c9d48320ac21b87e7a1 +https://conda.anaconda.org/conda-forge/linux-64/wayland-1.23.1-h3e06ad9_0.conda#0a732427643ae5e0486a727927791da1 https://conda.anaconda.org/conda-forge/linux-64/x265-3.5-h924138e_3.tar.bz2#e7f6ed84d4623d52ee581325c1587a6b -https://conda.anaconda.org/conda-forge/linux-64/xorg-fixesproto-5.0-h7f98852_1002.tar.bz2#65ad6e1eb4aed2b0611855aff05e04f6 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-h7391055_0.conda#93ee23f12bc2e684548181256edd2cf6 -https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-h4ab18f5_1.conda#9653f1bf3766164d0e65fa723cabbc54 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-hb711507_2.conda#8637c3e5821654d0edf97e2b0404b443 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.1-hb711507_0.conda#ad748ccca349aec3e91743e08b5e2b50 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.10-hb711507_0.conda#0e0cbe0564d03a99afd5fd7b362feecd +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.2-hb711507_0.conda#608e0ef8256b81d04456e8d211eee3e8 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-he73a12e_1.conda#05a8ea5f446de33006171a7afe6ae857 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_0.conda#0b666058a179b744a622d0a4a0c56353 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda#4d056880988120e29d75bfff282e0f45 https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-hef167b5_0.conda#54fe76ab3d0189acaef95156874db7f9 -https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hd590300_1.conda#39f910d205726805a958da408ca194ba -https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-h267a509_2.conda#9ae35c3d96db2c94ce0cef86efdfa2cb -https://conda.anaconda.org/conda-forge/linux-64/gl2ps-1.4.2-hae5d5c5_1.conda#00e642ec191a19bf806a3915800e9524 +https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_2.conda#98514fe74548d768907ce7a13f680e8f +https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda#3f43953b7d3fb3aaa1d0d0723d91e368 -https://conda.anaconda.org/conda-forge/linux-64/libasprintf-devel-0.22.5-h661eb56_2.conda#02e41ab5834dcdcc8590cf29d9526f50 -https://conda.anaconda.org/conda-forge/linux-64/libglib-2.80.3-h8a4344b_1.conda#6ea440297aacee4893f02ad759e6ffbc -https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.27-pthreads_hac2b453_1.conda#ae05ece66d3924ac3d48b4aa3fa96cec -https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-4.25.3-h08a7969_0.conda#6945825cebd2aeb16af4c69d97c32c13 +https://conda.anaconda.org/conda-forge/linux-64/libglib-2.82.2-h2ff4ddf_0.conda#13e8e54035ddd2b91875ba399f0f7c04 +https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_1.conda#80a57756c545ad11f9847835aa21e6b2 +https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.28-pthreads_h94d23a6_0.conda#9ebc9aedafaa2515ab247ff6bb509458 https://conda.anaconda.org/conda-forge/linux-64/libtheora-1.1.1-h4ab18f5_1006.conda#553281a034e9cf8693c9df49f6c78ea1 -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.6.0-h1dd3fc0_3.conda#66f03896ffbe1a110ffda05c7a856504 -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.7-h4c95cb1_3.conda#0ac9aff6010a7751961c8e4b863a40e7 -https://conda.anaconda.org/conda-forge/linux-64/python-3.11.9-hb806964_0_cpython.conda#ac68acfa8b558ed406c75e98d3428d7b -https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.46.0-h6d4b2fc_0.conda#77ea8dff5cf8550cc8f5629a6af56323 -https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-h40f5838_3.conda#6bb8deb138f87c9d48320ac21b87e7a1 -https://conda.anaconda.org/conda-forge/noarch/wayland-protocols-1.36-hd8ed1ab_0.conda#c6f690e7d4abf562161477f14533cfd8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.9-hb711507_1.conda#4a6d410296d7e39f00bacdee7df046e9 -https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda#def531a3ac77b7fb8c21d17bb5d0badb +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-he137b08_1.conda#63872517c98aa305da58a757c443698e +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.7-he7c6b58_4.conda#08a9265c637230c37cb1be4a6cad4536 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_2.conda#57a9e7ee3c0840d3c8c9012473978629 +https://conda.anaconda.org/conda-forge/linux-64/python-3.11.10-hc5c86c4_3_cpython.conda#9e1ad55c87368e662177661a998feed5 +https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.47.0-h9eae976_0.conda#c4cb444844615e1cd4c9d989f770bcc5 +https://conda.anaconda.org/conda-forge/noarch/wayland-protocols-1.37-hd8ed1ab_0.conda#73ec79a77d31eb7e4a3276cd246b776c +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda#a0901183f08b6c7107aab109733a3c91 +https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.43-hb9d3cd8_0.conda#f725c7425d6d7c15e31f3b99a88ea02f +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda#febbab7d15033c913d53c7a2c102309d +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda#4bdb303603e9821baf5fe5fdff1dc8f8 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hb9d3cd8_1.conda#a7a49a8b85122b49214798321e2e96b4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxt-1.3.0-hb9d3cd8_2.conda#d8602724ac0d276c380b97e9eb0f814b +https://conda.anaconda.org/conda-forge/noarch/aiohappyeyeballs-2.4.3-pyhd8ed1ab_0.conda#ec763b0a58960558ca0ad7255a51a237 +https://conda.anaconda.org/conda-forge/noarch/alabaster-1.0.0-pyhd8ed1ab_0.conda#7d78a232029458d0077ede6cda30ed0c https://conda.anaconda.org/conda-forge/noarch/antlr-python-runtime-4.11.1-pyhd8ed1ab_0.tar.bz2#15109c4977d39ad7aa3423f57243e286 https://conda.anaconda.org/conda-forge/linux-64/atk-1.0-2.38.0-h04ea711_2.conda#f730d54ba9cd543666d7220c9f7ed563 -https://conda.anaconda.org/conda-forge/noarch/attrs-23.2.0-pyh71513ae_0.conda#5e4c0743c70186509d1412e03c2d8dfa -https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hd590300_1.conda#f27a24d46e3ea7b70a1f98e50c62508f -https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py311hb755f60_1.conda#cce9e7c3f1c307f2a5fb08a2922d6164 -https://conda.anaconda.org/conda-forge/noarch/certifi-2024.7.4-pyhd8ed1ab_0.conda#24e7fd6ca65997938fff9e5ab6f653e4 +https://conda.anaconda.org/conda-forge/noarch/attrs-24.2.0-pyh71513ae_0.conda#6732fa52eb8e66e5afeb32db8701a791 +https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py311hfdbb021_2.conda#d21daab070d76490cb39a8f1d1729d79 +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-hebfffa5_3.conda#fceaedf1cdbcb02df9699a0d9b005292 +https://conda.anaconda.org/conda-forge/noarch/certifi-2024.8.30-pyhd8ed1ab_0.conda#12f7d00853807b0531775e9be891cb11 https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_0.tar.bz2#ebb5f5f7dc4f1a3780ef7ea7738db08c -https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1ab_0.conda#7f4a9e3fcff3f6356ae99244a014da6a +https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.0-pyhd8ed1ab_0.conda#a374efa97290b8799046df7c5ca17164 https://conda.anaconda.org/conda-forge/noarch/click-8.1.7-unix_pyh707e725_0.conda#f3ad426304898027fc619827ff428eca -https://conda.anaconda.org/conda-forge/noarch/cloudpickle-3.0.0-pyhd8ed1ab_0.conda#753d29fe41bb881e4b9c004f0abf973f +https://conda.anaconda.org/conda-forge/noarch/cloudpickle-3.1.0-pyhd8ed1ab_1.conda#c88ca2bb7099167912e3b26463fff079 https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 https://conda.anaconda.org/conda-forge/noarch/colorcet-3.1.0-pyhd8ed1ab_0.conda#4d155b600b63bc6ba89d91fab74238f8 https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_0.conda#5cd86562580f274031ede6aa6aa24441 -https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.10-py311hb755f60_0.conda#f3a8a500a2e743ff92f418f0eaf9bf71 -https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.8-pyhd8ed1ab_0.conda#db16c66b759a64dc5183d69cc3745a52 +https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.27-h54b06d7_7.conda#dce22f70b4e5a407ce88f2be046f4ceb +https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.11-py311h55d416d_3.conda#d21db006755203fe890596d3eae992ce +https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d +https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.9-pyhd8ed1ab_0.conda#fe521c1608280cc2803ebd26dc252212 https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda#e8cd5d629f65bdf0f3bb312cde14659e https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda#d02ae936e42063ca46af6cdad2dbd1e0 https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda#15dda3cdbf330abfe9f555d22f66db46 -https://conda.anaconda.org/conda-forge/noarch/filelock-3.15.4-pyhd8ed1ab_0.conda#0e7e4388e9d5283e22b35a9443bdbcc9 -https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d -https://conda.anaconda.org/conda-forge/linux-64/frozenlist-1.4.1-py311h459d7ec_0.conda#b267e553a337e1878512621e374845c5 -https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.6.1-pyhff2d567_0.conda#996bf792cdb8c0ac38ff54b9fde56841 +https://conda.anaconda.org/conda-forge/noarch/filelock-3.16.1-pyhd8ed1ab_0.conda#916f8ec5dd4128cd5f207a3c4c07b2c6 +https://conda.anaconda.org/conda-forge/linux-64/frozenlist-1.5.0-py311h9ecbd09_0.conda#75424a18fb275a18b288c099b869c3bc +https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.10.0-pyhff2d567_0.conda#816dbc4679a64e4417cd1385d661bb31 https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.12-hb9ae30d_0.conda#201db6c2d9a3c5e46573ac4cb2e92f4f -https://conda.anaconda.org/conda-forge/linux-64/gettext-0.22.5-h59595ed_2.conda#219ba82e95d7614cf7140d2a4afc0926 https://conda.anaconda.org/conda-forge/linux-64/gts-0.7.6-h977cf35_4.conda#4d8df0b0db060d33c9a702ada998a8fe https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyh9f0ad1d_0.tar.bz2#914d6646c4dbb1fd3ff539830a12fd71 https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_0.tar.bz2#9f765cbfab6870c8435b9eefecd7a1f4 -https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda#c0cc1420498b17414d8617d0b9f506ca +https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_0.conda#7ba2ede0e7c795ff95088daf0dc59753 https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 -https://conda.anaconda.org/conda-forge/noarch/iris-sample-data-2.4.0-pyhd8ed1ab_0.tar.bz2#18ee9c07cf945a33f92caf1ee3d23ad9 -https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.5-py311h9547e67_1.conda#2c65bdf442b0d37aad080c8a4e0d452f +https://conda.anaconda.org/conda-forge/noarch/iris-sample-data-2.5.1-pyhd8ed1ab_0.conda#faf232274689aa60da5a63e7cc5faeb7 +https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.7-py311hd18a35c_0.conda#be34c90cce87090d24da64a7c239ca96 https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.16-hb7c19ff_0.conda#51bb7010fc86f70eee639b4bb7a894f5 -https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.7.4-hfca40fe_0.conda#32ddb97f897740641d8d46a829ce1704 -https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-22_linux64_openblas.conda#1a2a0cd3153464fee6646f3dd6dad9b8 -https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.8.0-hca28451_1.conda#b8afb3e3cb3423cc445cf611ab95fdb0 +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-25_linux64_openblas.conda#8ea26d42ca88ec5258802715fe1ee10b +https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h4637d8d_4.conda#d4529f4dff3057982a7617c7ac58fde3 +https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.10.1-hbbe4b11_0.conda#6e801c50a40301f6978c53976917b277 +https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-hd3e95f3_10.conda#30ee3a29c84cf7b842a8c5828c4b7c13 +https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_1.conda#204892bce2e44252b5cf272712f10bdd +https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.0-ha6d2627_1004.conda#df069bea331c8486ac21814969301c1f https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.11.1-default_hecaa2ac_1000.conda#f54aeebefb5c5ff84eca4fb05ca8aa3a -https://conda.anaconda.org/conda-forge/linux-64/libllvm18-18.1.8-h8b73ec9_1.conda#16d94b3586ef3558e5a583598524deb4 -https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.4.0-h2c329e2_0.conda#80030debaa84cfc31755d53742df3ca6 +https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.2-ha7bfdaf_0.conda#128e74a4f8f4fef4dc5130a8bbccc15d +https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.7.0-h2c5496b_1.conda#e2eaefa4de2b7237af7c907b8bbc760a https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2#91e27ef3d05cc772ce627e51cff111c4 -https://conda.anaconda.org/conda-forge/linux-64/loguru-0.7.2-py311h38be061_1.conda#94a4521bd7933a66d76b0274dbf8d2dd -https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.5-py311h459d7ec_0.conda#a322b4185121935c871d201ae00ac143 -https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.0.8-py311h52f7536_0.conda#f33f59b8130753174992f409a41e112e -https://conda.anaconda.org/conda-forge/linux-64/multidict-6.0.5-py311h459d7ec_0.conda#4288ea5cbe686d1b18fc3efb36c009a5 +https://conda.anaconda.org/conda-forge/linux-64/loguru-0.7.2-py311h38be061_2.conda#733b481d20ff260a34f2b0003ff4fbb3 +https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py311h2dc5d0c_0.conda#15e4dadd59e93baad7275249f10b9472 +https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.0-py311hd18a35c_0.conda#682f76920687f7d9283039eb542fdacf +https://conda.anaconda.org/conda-forge/linux-64/multidict-6.1.0-py311h2dc5d0c_1.conda#5384f857bd8b0fc3a62ce1ece858c89f https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.2-h488ebb8_0.conda#7f2e286780f072ed750df46dc2631138 https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda#cbe1bb1f21567018ce595d9c2be0f0db -https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.2-pyhd8ed1ab_0.conda#6f6cf28bf8e021933869bae3f84b8fc9 +https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.6-pyhd8ed1ab_0.conda#fd8f2b18b65bbf62e8f653100690c8d2 https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda#d3483c8fc2dc2cc3f5cf43e26d60cabf -https://conda.anaconda.org/conda-forge/linux-64/psutil-6.0.0-py311h331c9d8_0.conda#f1cbef9236edde98a811ba5a98975f2e +https://conda.anaconda.org/conda-forge/linux-64/propcache-0.2.0-py311h9ecbd09_2.conda#85a56dd3b692fb5435de1e901354b5b8 +https://conda.anaconda.org/conda-forge/linux-64/psutil-6.1.0-py311h9ecbd09_0.conda#0ffc1f53106a38f059b151c465891ed3 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda#844d9eb3b43095b031874477f7d70088 https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda#b7f5c092b8f9800150d998a71b76d5a1 -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.1.2-pyhd8ed1ab_0.conda#b9a4dacf97241704529131a0dfc0494f +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.0-pyhd8ed1ab_1.conda#035c17fbf099f50ff60bf2eb303b0a83 https://conda.anaconda.org/conda-forge/noarch/pyshp-2.3.1-pyhd8ed1ab_0.tar.bz2#92a889dc236a5197612bc85bee6d7174 https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 -https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.1-pyhd8ed1ab_0.conda#98206ea9954216ee7540f0c773f2104d -https://conda.anaconda.org/conda-forge/linux-64/python-xxhash-3.4.1-py311h459d7ec_0.conda#60b5332b3989fda37884b92c7afd6a91 +https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.2-pyhd8ed1ab_0.conda#986287f89929b2d629bd6ef6497dc307 +https://conda.anaconda.org/conda-forge/linux-64/python-xxhash-3.5.0-py311h9ecbd09_1.conda#b1796d741ca619dbacb79917b20e5a05 https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda#3eeeeb9e4827ace8c0c1419c85d590ad -https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.1-py311h459d7ec_1.conda#52719a74ad130de8fb5d047dc91f247a +https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.2-py311h9ecbd09_1.conda#abeb54d40f439b86f75ea57045ab8496 https://conda.anaconda.org/conda-forge/noarch/scooby-0.10.0-pyhd8ed1ab_0.conda#9e57330f431abbb4c88a5f898a4ba223 -https://conda.anaconda.org/conda-forge/noarch/setuptools-71.0.3-pyhd8ed1ab_0.conda#d4b6e6ce2f7bcaec484b81c447df1028 +https://conda.anaconda.org/conda-forge/noarch/setuptools-75.1.0-pyhd8ed1ab_0.conda#d5cd48392c67fb6849ba459c2c2b671f https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2#4d22a9315e78c6827f806065957d566e https://conda.anaconda.org/conda-forge/noarch/sortedcontainers-2.4.0-pyhd8ed1ab_0.tar.bz2#6d6552722448103793743dabfbda532d @@ -200,128 +209,131 @@ https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.5-pyhd8ed1ab_1.conda#3 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda#da1d979339e2714c30a8e806a33ec087 https://conda.anaconda.org/conda-forge/noarch/tblib-3.0.0-pyhd8ed1ab_0.conda#04eedddeb68ad39871c8127dd1c21f4f https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 -https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 -https://conda.anaconda.org/conda-forge/noarch/toolz-0.12.1-pyhd8ed1ab_0.conda#2fcb582444635e2c402e8569bb94e039 -https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py311h331c9d8_0.conda#e29e451c96bf8e81a5760b7565c6ed2c +https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.2-pyhd8ed1ab_0.conda#e977934e00b355ff55ed154904044727 +https://conda.anaconda.org/conda-forge/noarch/toolz-1.0.0-pyhd8ed1ab_0.conda#34feccdd4177f2d3d53c73fc44fd9a37 +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py311h9ecbd09_1.conda#616fed0b6f5c925250be779b05d1d7f7 https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda#ebe6952715e1d5eb567eeebf25250fa7 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.43.0-pyhd8ed1ab_1.conda#0b5293a157c2b5cd513dd1b03d8d3aae -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h0b41bf4_2.conda#82b6df12252e6f32402b96dacc656fec -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-5.0.3-h7f98852_1004.tar.bz2#e9a21aa4d5e3e5f1aed71e8cefd46b6a -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hd590300_0.conda#ed67c36f215b310412b2af935bf3e530 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxt-1.3.0-hd590300_1.conda#ae92aab42726eb29d16488924f7312cb +https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-15.1.0-py311h9ecbd09_1.conda#00895577e2b4c24dca76675ab1862551 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.44.0-pyhd8ed1ab_0.conda#d44e3b085abcaef02983c6305b84b584 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.5-hb9d3cd8_0.conda#eb44b3b6deb1cab08d72cb61686fe64c +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda#d3c295b50f092ab525ffe3c2aa4b7413 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.2-hb9d3cd8_0.conda#bb2638cd7fbdd980b1cff9a99a6c1fa8 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda#b5fcc7172d22516e1f965490e65e33a4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda#17dcc85db3c7886650b8908b183d6876 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.4-hb9d3cd8_0.conda#2de7f99d6581a4a7adbff607b5c278ca +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.5-hb9d3cd8_4.conda#7da9007c0582712c4bad4131f89c8372 https://conda.anaconda.org/conda-forge/noarch/zict-3.0.0-pyhd8ed1ab_0.conda#cf30c2c15b82aacb07f9c09e28ff2275 -https://conda.anaconda.org/conda-forge/noarch/zipp-3.19.2-pyhd8ed1ab_0.conda#49808e59df5535116f6878b2a820d6f4 +https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.2-pyhd8ed1ab_0.conda#4daaed111c05672ae669f7036ee5bba3 https://conda.anaconda.org/conda-forge/noarch/accessible-pygments-0.0.5-pyhd8ed1ab_0.conda#1bb1ef9806a9a20872434f58b3e7fc1a https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.3.1-pyhd8ed1ab_0.tar.bz2#d1e1eb7e21a9e2c74279d87dafb68156 https://conda.anaconda.org/conda-forge/noarch/babel-2.14.0-pyhd8ed1ab_0.conda#9669586875baeced8fc30c0826c3270e https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.12.3-pyha770c72_0.conda#332493000404d8411859539a5a630865 -https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-hbb29018_2.conda#b6d90276c5aee9b4407dd94eb0cd40a8 -https://conda.anaconda.org/conda-forge/linux-64/cffi-1.16.0-py311hb3a22ac_0.conda#b3469563ac5e808b0cd92810d0697043 +https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.1-py311hf29c0ef_0.conda#55553ecd5328336368db611f350b7039 https://conda.anaconda.org/conda-forge/noarch/click-default-group-1.2.4-pyhd8ed1ab_0.conda#7c2b6931f9b3548ed78478332095c3e9 -https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.0-py311h61187de_0.conda#88eac8e0e69d850b235824f87e5cfd1b -https://conda.anaconda.org/conda-forge/linux-64/cytoolz-0.12.3-py311h459d7ec_0.conda#13d385f635d7fbe9acc93600f67a6cb4 -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.53.1-py311h61187de_0.conda#bcbe6c9db1c25900c3808b8974e1bb90 +https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.4-py311h2dc5d0c_0.conda#4d74dedf541d0f87fce0b5797b66e425 +https://conda.anaconda.org/conda-forge/linux-64/cytoolz-1.0.0-py311h9ecbd09_1.conda#765c19c0b6df9c143ac8f959d1a1a238 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.54.1-py311h2dc5d0c_1.conda#7336fc1b2ead4cbdda1268dd6b7a6c38 +https://conda.anaconda.org/conda-forge/linux-64/glew-2.1.0-h9c3ff4c_2.tar.bz2#fb05eb5c47590b247658243d27fc32f1 https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_0.tar.bz2#b748fbf7060927a6e82df7cb5ee8f097 -https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.3-nompi_hdf9ad27_105.conda#7e1729554e209627636a0f6fabcdd115 -https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.0.0-pyha770c72_0.conda#3286556cdd99048d198f72c3f6f69103 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-9.0.0-hda332d3_1.conda#76b32dcf243444aea9c6b804bcfa40b8 +https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.4-nompi_h2d575fe_101.conda#09967792ea2191a0bdb461f9c889e510 +https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.5.0-pyha770c72_0.conda#54198435fce4d64d8a89af22573012a8 https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda#7b86ecb7d3557821c649b3c31e3eb9f2 -https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-22_linux64_openblas.conda#4b31699e0ec5de64d5896e580389c9a1 -https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-h119a65a_9.conda#cfebc557e54905dadc355c0e9f003004 -https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.7-hd590300_0.conda#2b7b0d827c6447cc1d85dc06d5b5de46 -https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-22_linux64_openblas.conda#b083767b6c877e24ee597d93b87ab838 -https://conda.anaconda.org/conda-forge/linux-64/libva-2.22.0-hb711507_0.conda#d12f659072132c9d16e497073fc1f68b +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-25_linux64_openblas.conda#5dbd1b0fc0d01ec5e0e1fbe667281a11 +https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.2-default_hb5137d0_1.conda#7e574c7499bc41f92537634a23fed79a +https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.2-default_h9c6a7e4_1.conda#cb5c5ff12b37aded00d9aaa7b9a86a78 +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-25_linux64_openblas.conda#4dc03a53fc69371a6158d0ed37214cd3 +https://conda.anaconda.org/conda-forge/linux-64/libva-2.22.0-h8a09558_1.conda#139262125a3eac8ff6eef898598745a3 https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.9.1-pyhd8ed1ab_0.conda#dfe0528d0f1c16c1f7c528ea5536ab30 +https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.8-hedd0468_0.conda#dcd0ed5147d8876b0848a552b416ce76 https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda#0badf9c54e24cecfb0ad2f99d680c163 -https://conda.anaconda.org/conda-forge/linux-64/pillow-10.4.0-py311h82a398c_0.conda#b9e0ac1f5564b6572a6d702c04207be8 -https://conda.anaconda.org/conda-forge/noarch/pip-24.0-pyhd8ed1ab_0.conda#f586ac1e56c8638b64f9c8122a7b8a67 -https://conda.anaconda.org/conda-forge/linux-64/proj-9.3.1-h1d62c97_0.conda#44ec51d0857d9be26158bb85caa74fdb -https://conda.anaconda.org/conda-forge/noarch/pytest-8.2.2-pyhd8ed1ab_0.conda#0f3f49c22c7ef3a1195fa61dad3c43be +https://conda.anaconda.org/conda-forge/linux-64/pillow-11.0.0-py311h49e9ac3_0.conda#2bd3d0f839ec0d1eaca817c9d1feb7c2 +https://conda.anaconda.org/conda-forge/noarch/pip-24.2-pyh8b19718_1.conda#6c78fbb8ddfd64bcb55b5cbafd2d2c43 +https://conda.anaconda.org/conda-forge/linux-64/proj-9.5.0-h12925eb_0.conda#8c29983ebe50cc7e0998c34bc7614222 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda#c03d61f31f38fdb9facf70c29958bf7a https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda#2cf4264fffb9e6eff6031c5b6884d61c -https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.12.0-h434a139_3.conda#c667c11d1e488a38220ede8a34441bff +https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.13.0-h84d6215_0.conda#ee6f7fd1e76061ef1fa307d41fa86a96 https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.12.2-hd8ed1ab_0.conda#52d648bd608f5737b123f510bb5514b5 -https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.26.3-pyhd8ed1ab_0.conda#284008712816c64c85bf2b7fa9f3b264 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.5-h7f98852_1.tar.bz2#bebd3814ec2355fab6a474b07ed73093 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.2-h7f98852_1.tar.bz2#5b0f7da25a4556c9619c3e4b4a98ab07 -https://conda.anaconda.org/conda-forge/linux-64/yarl-1.9.4-py311h459d7ec_0.conda#fff0f2058e9d86c8bf5848ee93917a8d -https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.9.5-py311h459d7ec_0.conda#0175d2636cc41dc019b51462c13ce225 +https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.27.0-pyhd8ed1ab_0.conda#a6ed1227ba6ec37cfc2b25e6512f729f +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda#7bbe9a0cc0df0ac5f5a8ad6d6a11af2f +https://conda.anaconda.org/conda-forge/linux-64/yarl-1.16.0-py311h9ecbd09_0.conda#d9c23163e7ac5f8926372c7d792a996f +https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.10.10-py311h2dc5d0c_0.conda#4f0fa0019a6e7be77db3609a707a4581 https://conda.anaconda.org/conda-forge/noarch/asv_runner-0.2.1-pyhd8ed1ab_0.conda#fdcbeb072c80c805a2ededaa5f91cd79 -https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.7.9-hb077bed_0.conda#33eded89024f21659b1975886a4acf70 -https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-9.0.0-hfac3d4d_0.conda#c7b47c64af53e8ecee01d101eeab2342 -https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-8.0.0-hd8ed1ab_0.conda#5f8c8ebbe6413a7838cf6ecf14d5d31b -https://conda.anaconda.org/conda-forge/noarch/lazy_loader-0.4-pyhd8ed1ab_0.conda#a284ff318fbdb0dd83928275b4b6087c -https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.2-nompi_h135f659_114.conda#a908e463c710bd6b10a9eaa89fdf003c -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-2024.2.0-h2da1b83_1.conda#9511859bf5221238a2d3fb5322af01d5 -https://conda.anaconda.org/conda-forge/linux-64/numpy-1.26.4-py311h64a7726_0.conda#a502d7aad449a1206efb366d6a12c52d -https://conda.anaconda.org/conda-forge/noarch/pbr-6.0.0-pyhd8ed1ab_0.conda#8dbab5ba746ed14aa32cb232dc437f8f -https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.6.1-py311hca0b8b9_5.conda#cac429fcb9126d5e6f02c8ba61c2a811 +https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-8.5.0-hd8ed1ab_0.conda#2a92e152208121afadf85a5e1f3a5f4d +https://conda.anaconda.org/conda-forge/noarch/lazy-loader-0.4-pyhd8ed1ab_1.conda#4809b9f4c6ce106d443c3f90b8e10db2 +https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.3-h1dc1e6a_0.conda#2a66267ba586dadd110cc991063cfff7 +https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.2-nompi_h2564987_115.conda#c5ce70b76c77a6c9a3107be8d8e8ab0b +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-2024.4.0-hac27bb2_2.conda#ba5ac0bb9ec5aec38dec37c230b12d64 +https://conda.anaconda.org/conda-forge/linux-64/libpq-17.0-h04577a9_4.conda#392cae2a58fbcb9db8c2147c6d6d1620 +https://conda.anaconda.org/conda-forge/linux-64/numpy-2.1.2-py311h71ddf71_0.conda#4e72b55892331ada8fbcf5954df582f2 +https://conda.anaconda.org/conda-forge/linux-64/pango-1.54.0-h4c5309f_1.conda#7df02e445367703cd87a574046e3a6f0 +https://conda.anaconda.org/conda-forge/noarch/pbr-6.1.0-pyhd8ed1ab_0.conda#5a166b998fd17cdaaaadaccdd71a363f +https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.7.0-py311h0f98d5a_0.conda#22531205a97c116251713008d65dfefd https://conda.anaconda.org/conda-forge/noarch/pytest-cov-5.0.0-pyhd8ed1ab_0.conda#c54c0107057d67ddf077751339ec2c63 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_0.conda#b39568655c127a9c4a44d178ac99b6d0 https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-8.1.0-pyhd8ed1ab_0.conda#ba9f7f0ec4f2a18de3e7bce67c4a431e -https://conda.anaconda.org/conda-forge/linux-64/tbb-devel-2021.12.0-hfcbfbdb_3.conda#dd410ed856f34c994f1549079ff601bf -https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py311h9547e67_4.conda#586da7df03b68640de14dc3e8bcbf76f -https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py311h5cd10c7_0.conda#8efe4fe2396281627b3450af8357b190 -https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.4-py311h18e1886_0.conda#0eb1e6c7d10285ec12e01f73d1896d93 +https://conda.anaconda.org/conda-forge/linux-64/tbb-devel-2021.13.0-h94b29a5_0.conda#4431bd4ace17dd09b97caf68509b016b +https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py311hd18a35c_5.conda#4e8447ca8558a203ec0577b4730073f3 +https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py311hbc35293_1.conda#aec590674ba365e50ae83aa2d6e1efae +https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.4-py311h9f3472d_1.conda#2c3c4f115d28ed9e001a271d5d8585aa https://conda.anaconda.org/conda-forge/noarch/colorspacious-1.1.2-pyh24bf2e0_0.tar.bz2#b73afa0d009a51cabd3ec99c4d2ef4f3 -https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.2.1-py311h9547e67_0.conda#74ad0ae64f1ef565e27eda87fa749e84 -https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.7.0-pyhd8ed1ab_0.conda#755e47653ae38f5c50f1435af756e844 -https://conda.anaconda.org/conda-forge/noarch/identify-2.6.0-pyhd8ed1ab_0.conda#f80cc5989f445f23b1622d6c455896d9 -https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.1-h39113c1_2.conda#25db2ea6b8fefce451369e2cc826f6f4 -https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.1-h97afed2_0.conda#00bd7406d24d6574f2de3839b60e0925 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-batch-plugin-2024.2.0-hb045406_1.conda#70d82a64e6d07f4d6e07cae6b0bd4bd1 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-plugin-2024.2.0-hb045406_1.conda#f1e2a8ded23cef03804c4edb2edfb986 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-hetero-plugin-2024.2.0-h5c03a75_1.conda#95d2d3baaa1e456ef65c713a5d99b815 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-cpu-plugin-2024.2.0-h2da1b83_1.conda#9e49f87d8f99dc9724f52b3fac904106 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-gpu-plugin-2024.2.0-h2da1b83_1.conda#a9712fae44d01d906e228c49235e3b89 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-npu-plugin-2024.2.0-he02047a_1.conda#5c2d064181e686cf5cfac6f1a1ee4e91 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-ir-frontend-2024.2.0-h5c03a75_1.conda#89addf0fc0f489fa0c076f1c8c0d62bf -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-onnx-frontend-2024.2.0-h07e8aee_1.conda#9b0a13989b35302e47da13842683804d -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-paddle-frontend-2024.2.0-h07e8aee_1.conda#7b3680d3fd00e1f91d5faf9c97c7ae78 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-pytorch-frontend-2024.2.0-he02047a_1.conda#ac43b516c128411f84f1e19c875998f1 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-frontend-2024.2.0-h39126c6_1.conda#11acf52cac790edcf087b89e83834f7d -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-lite-frontend-2024.2.0-he02047a_1.conda#e7f91b35e3aa7abe880fc9192a761fc0 -https://conda.anaconda.org/conda-forge/linux-64/mo_pack-0.3.0-py311h459d7ec_1.conda#45b8d355bbcdd27588c2d266bcfdff84 -https://conda.anaconda.org/conda-forge/linux-64/netcdf-fortran-4.6.1-nompi_h228c76a_104.conda#91bc3ac73308181d55a09d9e4aeb4496 -https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.2-py311h14de704_1.conda#84e2dd379d4edec4dd6382861486104d -https://conda.anaconda.org/conda-forge/linux-64/pango-1.54.0-h4c5309f_1.conda#7df02e445367703cd87a574046e3a6f0 -https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.3.12-py311h18e1886_1.conda#62b842b69b2ccd337be298406591c18c -https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.6.0-py311h18e1886_0.conda#f43c7f60c7b1e7a7cc4234d28520b06a -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.14.0-py311h517d4fd_1.conda#481fd009b2d863f526f60ca19cb7880b -https://conda.anaconda.org/conda-forge/linux-64/shapely-2.0.5-py311h5925939_0.conda#105ce0d9e7aa0324031a3abaf9ec71f7 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-apidoc-0.3.0-py_1.tar.bz2#855b087883443abb10f5faf6eef40860 -https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.2-pyhd8ed1ab_1.conda#e804c43f58255e977093a2298e442bb8 -https://conda.anaconda.org/conda-forge/noarch/wslink-2.1.1-pyhd8ed1ab_0.conda#6b1aef9c878c58baa7bb9f0d44457174 -https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.2.0-py311h18e1886_5.conda#6cd3facab7a79de14abb1a86a2d830fa -https://conda.anaconda.org/conda-forge/noarch/distributed-2024.7.0-pyhd8ed1ab_0.conda#2ae917b0098f286f63f69ec9365fb0b1 -https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.191-h924a536_0.conda#73d050766060acd2b3a289f27d857090 -https://conda.anaconda.org/conda-forge/linux-64/esmf-8.6.1-nompi_h0a5817f_2.conda#e23c62f75f67166cf4ca137fc8bcdce7 -https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-7.0.1-gpl_h9be9148_104.conda#107fd9222d9f628608b07b69abba9420 +https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.0-py311hd18a35c_2.conda#66266cd4f20e47dc1de458c93fb4d2a9 +https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.10.0-pyhd8ed1ab_0.conda#7823092a3cf14e98a52d2a2875c47c80 https://conda.anaconda.org/conda-forge/linux-64/gtk2-2.24.33-h6470451_5.conda#1483ba046164be27df7f6eddbcec3a12 +https://conda.anaconda.org/conda-forge/noarch/identify-2.6.1-pyhd8ed1ab_0.conda#43f629202f9eec21be5f71171fb5daf8 +https://conda.anaconda.org/conda-forge/noarch/lazy_loader-0.4-pyhd8ed1ab_1.conda#ec6f70b8a5242936567d4f886726a372 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-batch-plugin-2024.4.0-h4d9b6c2_2.conda#1d05a25da36ba5f98291d7237fc6b8ce +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-plugin-2024.4.0-h4d9b6c2_2.conda#838b2db868f9ab69a7bad9c065a3362d +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-hetero-plugin-2024.4.0-h3f63f65_2.conda#00a6127960a3f41d4bfcabd35d5fbeec +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-cpu-plugin-2024.4.0-hac27bb2_2.conda#6cfc840bc39c17d92fb25e5a35789e5b +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-gpu-plugin-2024.4.0-hac27bb2_2.conda#9e9814b40d8fdfd8485451e3fa2f1719 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-npu-plugin-2024.4.0-hac27bb2_2.conda#724719ce97feb6f310f88ae8dbb40afd +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-ir-frontend-2024.4.0-h3f63f65_2.conda#8908f31eab30f65636eb61ab9cb1f3ad +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-onnx-frontend-2024.4.0-h5c8f2c3_2.conda#e098caa87868e8dcc7ed5d011981207d +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-paddle-frontend-2024.4.0-h5c8f2c3_2.conda#59bb8c3502cb9d35f1fb26691730288c +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-pytorch-frontend-2024.4.0-h5888daf_2.conda#e0b88fd64dc95f715ef52e607a9af89b +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-frontend-2024.4.0-h6481b9d_2.conda#12bf831b85f17368bc71a26ac93a8493 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-lite-frontend-2024.4.0-h5888daf_2.conda#d48c774c40ea2047adbff043e9076e7a +https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.58.4-hc0ffecb_0.conda#83f045969988f5c7a65f3950b95a8b35 +https://conda.anaconda.org/conda-forge/linux-64/mo_pack-0.3.1-py311h9ecbd09_1.conda#28d6b63784b350a2906dc264ad8c7f2a +https://conda.anaconda.org/conda-forge/linux-64/netcdf-fortran-4.6.1-nompi_ha5d1325_107.conda#5bd5042289ef82196bae48948314cdf9 +https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.3-py311h7db5c69_1.conda#643f8cb35133eb1be4919fb953f0a25f +https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.3.13-py311h9f3472d_1.conda#87b04d34d110ea5ff945f1949b7436be +https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.7.0-py311h9f3472d_2.conda#bd9c3ff46028eec017bc78377f9e0fb6 +https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.7.3-h6e8976b_1.conda#f3234422a977b5d400ccf503ad55c5d1 +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.14.1-py311he9a78e4_1.conda#49ba89bf4d8a995efb99517d1c7aeb1e +https://conda.anaconda.org/conda-forge/linux-64/shapely-2.0.6-py311h2fdb869_2.conda#4c78235905053663d1c9e23df3f11b65 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-apidoc-0.3.0-py_1.tar.bz2#855b087883443abb10f5faf6eef40860 +https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.3-pyhd8ed1ab_0.conda#6b55867f385dd762ed99ea687af32a69 +https://conda.anaconda.org/conda-forge/noarch/wslink-2.2.1-pyhd8ed1ab_0.conda#74674b93806167c26da4eca7613bc225 +https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.2.0-py311h9f3472d_6.conda#ac7dc7f70f8d2c1d96ecb7e4cb196498 +https://conda.anaconda.org/conda-forge/noarch/distributed-2024.10.0-pyhd8ed1ab_0.conda#b3b498f7bcc9a2543ad72a3501f3d87b +https://conda.anaconda.org/conda-forge/linux-64/esmf-8.6.1-nompi_h6063b07_4.conda#3108bfa76cd8a3ebc5546797106946e5 +https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-6.1.2-gpl_h8657690_705.conda#bba34ade586dc53222d5e0387f7733c2 +https://conda.anaconda.org/conda-forge/linux-64/graphviz-12.0.0-hba01fac_0.conda#953e31ea00d46beb7e64a79fc291ec44 https://conda.anaconda.org/conda-forge/noarch/imagehash-4.3.1-pyhd8ed1ab_0.tar.bz2#132ad832787a2156be1f1b309835001a -https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.58.2-h9564881_1.conda#c6a47e6f551890e82e92e4c1b84be353 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.8.4-py311ha4ca890_2.conda#0848e2084cbb57014f232f48568561af -https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.1-nompi_py311h25b3b55_101.conda#936afeddfa3704eb834d0887b0838826 -https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.7.1-pyha770c72_0.conda#724bc4489c1174fc8e3233b0624fa51f -https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.3.0-py311h18e1886_2.conda#b1e90d33ae504ac06a3928a2dc5654ba +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.2-py311h2b939e6_1.conda#db431da3476c884ef08d9f42a32913b6 +https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.2-nompi_py311h7c29e4f_100.conda#11395670c4eeda7a60c13c313a83727f +https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.0.1-pyha770c72_0.conda#5971cc64048943605f352f7f8612de6c +https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.3.0-py311h9f3472d_3.conda#a7c4169b1c920361597ddacb461350fd https://conda.anaconda.org/conda-forge/noarch/requests-2.32.3-pyhd8ed1ab_0.conda#5ede4753180c7a550a443c430dc8ab52 -https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.23.0-py311h14de704_1.conda#27e5956e552c6e71f56cb1ec042617a8 +https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.3.1-qt_py311h7158b74_209.conda#011801a68c022cf9692a4567d84678ca +https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.24.0-py311h7db5c69_0.conda#20ba399d57a2b5de789a5b24341481a1 https://conda.anaconda.org/conda-forge/noarch/cmocean-4.0.3-pyhd8ed1ab_0.conda#53df00540de0348ed1b2a62684dd912b https://conda.anaconda.org/conda-forge/noarch/esmpy-8.6.1-pyhc1e730c_0.conda#25a9661177fd68bfdb4314fd658e5c3b -https://conda.anaconda.org/conda-forge/linux-64/graphviz-11.0.0-hc68bbd7_0.conda#52a531ef95358086a56086c45d97ab75 -https://conda.anaconda.org/conda-forge/linux-64/mesalib-24.1.4-h3ac77ca_0.conda#083464147e4169cf088522070964e0cf https://conda.anaconda.org/conda-forge/noarch/nc-time-axis-1.4.1-pyhd8ed1ab_0.tar.bz2#281b58948bf60a2582de9e548bcc5369 https://conda.anaconda.org/conda-forge/noarch/pooch-1.8.2-pyhd8ed1ab_0.conda#8dab97d8a9616e07d779782995710aed -https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.3.1-osmesa_py311h530c62d_101.conda#44a9e14d9b8b37da5c3ed16e322fe1b9 -https://conda.anaconda.org/conda-forge/linux-64/vtk-io-ffmpeg-9.3.1-osmesa_py311hd1cd433_101.conda#76155b70563f6b760be46a48c28ecdb1 -https://conda.anaconda.org/conda-forge/linux-64/vtk-9.3.1-osmesa_py311h7c0142d_101.conda#5ee9d2a935edb5bfe706687dcd63ad3c -https://conda.anaconda.org/conda-forge/noarch/pyvista-0.44.0-pyhd8ed1ab_0.conda#16270d42141769c8342e067d25acc6ce -https://conda.anaconda.org/conda-forge/noarch/geovista-0.5.1-pyhd8ed1ab_0.conda#22958696ccc609071ba40867090bfd3a -https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.15.4-pyhd8ed1ab_0.conda#c7c50dd5192caa58a05e6a4248a27acb +https://conda.anaconda.org/conda-forge/linux-64/vtk-io-ffmpeg-9.3.1-qt_py311hc8241c7_209.conda#13fdaae5c7c5c76089ca76f63b287ef5 +https://conda.anaconda.org/conda-forge/linux-64/vtk-9.3.1-qt_py311he5e186c_209.conda#54a9526336ff06739344f87726cbc61e +https://conda.anaconda.org/conda-forge/noarch/pyvista-0.44.1-pyhd8ed1ab_0.conda#0731b45087c0358ca8b7d9fe855dec1a +https://conda.anaconda.org/conda-forge/noarch/geovista-0.5.3-pyhd8ed1ab_0.conda#4b12a3321889056bf9a000be9a0763b3 +https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.16.0-pyhd8ed1ab_0.conda#344261b0e77f5d2faaffb4eac225eeb7 https://conda.anaconda.org/conda-forge/noarch/sphinx-copybutton-0.5.2-pyhd8ed1ab_0.conda#ac832cc43adc79118cf6e23f1f9b8995 -https://conda.anaconda.org/conda-forge/noarch/sphinx-design-0.6.0-pyhd8ed1ab_0.conda#b04f3c04e4f7939c6207dc0c0355f468 -https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.16.0-pyhd8ed1ab_0.conda#add28691ee89e875b190eda07929d5d4 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd8ed1ab_0.conda#611a35a27914fac3aa37611a6fe40bb5 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.6-pyhd8ed1ab_0.conda#d7e4954df0d3aea2eacc7835ad12671d -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.5-pyhd8ed1ab_0.conda#7e1e7437273682ada2ed5e9e9714b140 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.7-pyhd8ed1ab_0.conda#26acae54b06f178681bfb551760f5dd1 -https://conda.anaconda.org/conda-forge/noarch/sphinx-7.4.5-pyhd8ed1ab_0.conda#98a3e9786dd637216c6a028f5061cd71 +https://conda.anaconda.org/conda-forge/noarch/sphinx-design-0.6.1-pyhd8ed1ab_1.conda#db0f1eb28b6df3a11e89437597309009 +https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.18.0-pyhd8ed1ab_0.conda#dc78276cbf5ec23e4b959d1bbd9caadb +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-2.0.0-pyhd8ed1ab_0.conda#9075bd8c033f0257122300db914e49c9 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-2.0.0-pyhd8ed1ab_0.conda#b3bcc38c471ebb738854f52a36059b48 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.1.0-pyhd8ed1ab_0.conda#e25640d692c02e8acfff0372f547e940 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-2.0.0-pyhd8ed1ab_0.conda#d6e5ea5fe00164ac6c2dcc5d76a42192 +https://conda.anaconda.org/conda-forge/noarch/sphinx-8.1.3-pyhd8ed1ab_0.conda#05706dd5a145a9c91861495cd435409a https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda#e507335cb4ca9cff4c3d0fa9cdab255e diff --git a/requirements/locks/py312-linux-64.lock b/requirements/locks/py312-linux-64.lock index ccf1c78c28..99dc274e80 100644 --- a/requirements/locks/py312-linux-64.lock +++ b/requirements/locks/py312-linux-64.lock @@ -1,198 +1,207 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 7a4a6d9e72f2080d74f07a6f99d51fc689c72fca556a978061ea868b4369610d +# input_hash: c193458a42ce9c0214cd77bd4813343270edb438eceaf46d40cf7ea29a433b56 @EXPLICIT https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 -https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.7.4-hbcca054_0.conda#23ab7665c5f63cfb9f1f6195256daac6 +https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda#c27d1c142233b5bc9ca570c6e2e0c244 https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb -https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_2.conda#cbbe59391138ea5ad3658c76912e147f -https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-hf3520f5_7.conda#b80f2f396ca2c28b8c14c437a4ed1e74 -https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.11.3-h59595ed_0.conda#df9ae69b85e0cab9bde23eff1e87f183 -https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-4_cp312.conda#dccc2d142812964fcc6abdc97b672dff -https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda#161081fc7cec0bfda0d86d7cb595f8d8 +https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda#49023d73832ef61042f6a237cb2687e7 +https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-5_cp312.conda#0424ae29b104430108f5218a66db7260 +https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda#8ac3367aafb1cc0a068483c580af8015 https://conda.anaconda.org/conda-forge/linux-64/utfcpp-4.0.5-ha770c72_0.conda#25965c1d1d5fc00ce2b663b73008e3b7 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 -https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.1.0-h77fa898_0.conda#ae061a5ed5f05818acdf9adab72c146d +https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_2.conda#048b02e3962f066da18efe3a21b77672 +https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_1.conda#1ece2ccb1dc8c68639712b05e0fae070 +https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h77fa898_1.conda#cc3573974587f12dda90d96e3e55a702 https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#73aaf86a425cc6e73fcf236a5a46396d https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab -https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.1.0-h77fa898_0.conda#ca0fad6a41ddaef54a153b78eccb5037 +https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_1.conda#38a5cd3be5fb620b48069e27285f1a44 +https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h77fa898_1.conda#3cb76c3f10d3bc7f1105b2fc9db984df +https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.2-heb4867d_0.conda#2b780c0338fc0ffa678ac82c54af51fd +https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb9d3cd8_2.conda#41b599ed2b02abcfdd84302bff174b23 +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.22-hb9d3cd8_0.conda#b422943d5d772b7cc858b36ad2a92db5 +https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.3-h5888daf_0.conda#59f4c43bb1b5ef1c71946ff2cbf59524 +https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_1.conda#e39480b9ca41323497b05492a63bc35b +https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hd5240d6_1.conda#9822b874ea29af082e5d36098d25427d +https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-hc0a3c3a_1.conda#234a5554c53625688d51062645337328 +https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda#edb0dca6bc32e4f4789199455a1dbeb8 +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.2-hb9d3cd8_0.conda#4d638782050ab6faa27275bed57e9b4e +https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda#b3c17d95b5a10c6e64a21fa17573e70e +https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.1-hb9d3cd8_1.conda#19608a9656912805b2b9a2f6bd257b04 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hb9d3cd8_1.conda#77cbc488235ebbaab2b6e912d3934bae +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda#8035c64cb77ed555e3f150b7b3972480 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-hb9d3cd8_1004.conda#bc4cd53a083b6720d61a1519a1900878 +https://conda.anaconda.org/conda-forge/linux-64/xorg-xorgproto-2024.1-hb9d3cd8_1.conda#7c21106b851ec72c037b162c216d8f05 +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.12-h4ab18f5_0.conda#7ed427f0871fd41cb1d9c17727c17589 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda#62ee74e96c5ebb0af99386de58cf9553 -https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.32.2-h4bc722e_0.conda#8024af1ee7078e37fa3101c0a0296af2 https://conda.anaconda.org/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda#418c6ca5929a611cbd69204907a83995 +https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.3-h5888daf_0.conda#6595440079bed734b113de44ffd3cd0a https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.10-h36c2ea0_0.tar.bz2#ac7bc6a654f8f41b352b38f4051135f8 -https://conda.anaconda.org/conda-forge/linux-64/gettext-tools-0.22.5-h59595ed_2.conda#985f2f453fb72408d6b6f1be0f324033 -https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda#3bf7b9fd5a7136126e0234db4b87c8b6 +https://conda.anaconda.org/conda-forge/linux-64/geos-3.13.0-h5888daf_0.conda#40b4ab956c90390e407bb177f8a58bab +https://conda.anaconda.org/conda-forge/linux-64/jsoncpp-1.9.6-h84d6215_0.conda#1190da4988807db89b31e2173128892f https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2#a8832b479f93521a9e7b5b743803be51 -https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hd590300_1.conda#aec6c91c7371c26392a06708a73c70e5 -https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.20-hd590300_0.conda#8e88f9389f1165d7c0936fe40d9a9a79 +https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240722.0-cxx17_h5888daf_1.conda#e1f604644fe8d78e22660e2fec6756bc +https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hb9d3cd8_2.conda#9566f0bd264fbd463002e759b8a82401 +https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hb9d3cd8_2.conda#06f70867945ea6a84d35836af780f1de https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda#172bf1cd1ff8629f2b1179945ed45055 -https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.2-h59595ed_0.conda#e7ba12deb7020dd080c6c70e7b6f6a3d https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 -https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-0.22.5-h59595ed_2.conda#172bcc51059416e7ce99e7b528cede83 -https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.1.0-hc5f4f2c_0.conda#6456c2620c990cd8dde2428a27ba0bc5 +https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_1.conda#f1fd30127802683586f768875127a987 https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda#d66573916ffcf376178462f1b61c941e https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.0.0-hd590300_1.conda#ea25936bb4080d843790b586850f82b8 https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda#30fd6e37fe21f86f4bd26d6ee73eeec7 +https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.4-h7f98852_1002.tar.bz2#e728e874159b042d92b90238a3cb0dc2 https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.5-h4ab18f5_0.conda#601bfb4b3c6f0b844443bb81a56651e0 https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hd590300_0.conda#48f4330bfcd959c3cfb704d424903c82 -https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.1.0-hc0a3c3a_0.conda#1cb187a157136398ddbaae90713e2498 -https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.19.0-h166bdaf_0.tar.bz2#93840744a8552e9ebf6bb1a5dffc125a -https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2#7245a044b4a1980ed83196176b78b73a +https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.44-hadc24fc_0.conda#f4cc49d7aa68316213e4b12be35308d1 +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.0-hadc24fc_0.conda#540296f0ce9d3352188c15a89b30b9ac +https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.0-h0841786_0.conda#1f5a58e686b13bcfde88b93f547d23fe +https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_1.conda#8371ac6457591af2cf6159439c1fd051 +https://conda.anaconda.org/conda-forge/linux-64/libudunits2-2.2.28-h40f5838_3.conda#4bdace082e911a3e1f1f0b721bed5b56 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.4.0-hd590300_0.conda#b26e8aa824079e1be0294e7152ca4559 +https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda#92ed62436b625154323d40d5f2f11dd7 https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda#5aa797f8787fe7a17d1b0821485b5adc -https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-h4ab18f5_1.conda#57d7dc60e9325e3de37ff8dffd18e814 -https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hd590300_1001.conda#ec7398d21e2651e0dcb0044d03b9a339 -https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h59595ed_0.conda#fcea371545eda051b6deafb24889fc69 -https://conda.anaconda.org/conda-forge/linux-64/nettle-3.9.1-h7ab15ed_0.conda#2bf1915cc107738811368afcb0993a59 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_2.conda#85c0dc0bcd110c998b01856975486ee7 +https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda#70caf8bb6cf39a0b6b7efc885f51c0fe https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.2-hd590300_1.conda#c66f837ac65e4d1cdeb80e2a1d5fcc3d -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.1-h4bc722e_2.conda#e1b454497f9f7c1147fdde4b53f1b512 -https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2#22dad4df6e8630e8dff2428f6f6a7036 +https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc https://conda.anaconda.org/conda-forge/linux-64/x264-1!164.3095-h166bdaf_2.tar.bz2#6c99772d483f566d59e25037fea2c4b1 -https://conda.anaconda.org/conda-forge/linux-64/xorg-damageproto-1.2.1-h7f98852_1002.tar.bz2#58c9bb067637c5a13a045a7124eeb027 -https://conda.anaconda.org/conda-forge/linux-64/xorg-glproto-1.4.17-h7f98852_1002.tar.bz2#e41bf01f80d46be87dcae2333a766e75 -https://conda.anaconda.org/conda-forge/linux-64/xorg-kbproto-1.0.7-h7f98852_1002.tar.bz2#4b230e8381279d76131116660f5a241a -https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.1-hd590300_0.conda#b462a33c0be1421532f28bfe8f4a7514 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hd590300_0.conda#2c80dc38fface310c9bd81b17037fee5 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.3-h7f98852_0.tar.bz2#be93aabceefa2fac576e971aef407908 -https://conda.anaconda.org/conda-forge/linux-64/xorg-randrproto-1.5.0-h7f98852_1001.tar.bz2#68cce654461713977dac6f9ac1bce89a -https://conda.anaconda.org/conda-forge/linux-64/xorg-renderproto-0.11.1-h7f98852_1002.tar.bz2#06feff3d2634e3097ce2fe681474b534 -https://conda.anaconda.org/conda-forge/linux-64/xorg-util-macros-1.19.3-h7f98852_0.tar.bz2#b1780cc89cf3949f670d6ca2aa6a7e42 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-h0b41bf4_1003.conda#bce9f945da8ad2ae9b1d7165a64d0f87 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xf86vidmodeproto-2.3.1-h7f98852_1002.tar.bz2#3ceea9668625c18f19530de98b15d5b0 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007.tar.bz2#b4a4381d54784606820704f7b5f05a15 https://conda.anaconda.org/conda-forge/linux-64/xxhash-0.8.2-hd590300_0.conda#f08fb5c89edfc4aadee1c81d4cfb1fa1 https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2#4cb3ad778ec2d5a7acbdf254eb1c42ae +https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda#c9f075ab2f33b3bbee9e62d4ad0a6cd8 https://conda.anaconda.org/conda-forge/linux-64/aom-3.9.1-hac33072_0.conda#346722a0be40f6edc53f12640d301338 +https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb9d3cd8_2.conda#c63b5e52939e795ba8d26e35d767a843 https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.3.0-h59595ed_0.conda#c2f83a5ddadadcdb08fe05863295ee97 https://conda.anaconda.org/conda-forge/linux-64/eigen-3.4.0-h00ab1b0_0.conda#b1b879d6d093f55dd40d58b5eb2f0699 -https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.2-h59595ed_0.conda#53fb86322bdb89496d7579fe3f02fd61 -https://conda.anaconda.org/conda-forge/linux-64/geos-3.12.2-hac33072_0.conda#621d814955342209dc8e7f87c41f1ba0 +https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-h267a509_2.conda#9ae35c3d96db2c94ce0cef86efdfa2cb +https://conda.anaconda.org/conda-forge/linux-64/gl2ps-1.4.2-hae5d5c5_1.conda#00e642ec191a19bf806a3915800e9524 https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hac33072_2.conda#c94a5994ef49749880a8139cf9afcbe1 https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.conda#f87c7b7c2cb45f323ffbce941c78ab7c https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda#bd77f8da987968ec3927990495dc22e4 -https://conda.anaconda.org/conda-forge/linux-64/icu-73.2-h59595ed_0.conda#cc47e1facc155f91abd89b11e48e72ff -https://conda.anaconda.org/conda-forge/linux-64/jsoncpp-1.9.5-h4bd325d_1.tar.bz2#ae7f50dd1e78c7e78b5d2cf7062e559d +https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda#8b189310083baabfb622af68fd9d3ae3 https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f -https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240116.2-cxx17_he02047a_1.conda#c48fc56ec03229f294176923c3265c05 https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.3-h59595ed_0.conda#5e97e271911b8b2001a8b71860c32faa -https://conda.anaconda.org/conda-forge/linux-64/libasprintf-0.22.5-h661eb56_2.conda#dd197c968bf9760bba0031888d431ede -https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hd590300_1.conda#f07002e225d7a60a694d42a7bf5ff53f -https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hd590300_1.conda#5fc11c6020d421960607d821310fcd4d -https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.122-h4ab18f5_0.conda#bbfc4dbe5e97b385ef088f354d65e563 +https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.123-hb9d3cd8_0.conda#ee605e794bdc14e2b7f84c4faa0d8c2c https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 -https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-devel-0.22.5-h59595ed_2.conda#b63d9b6da3653179a278077f0de20014 -https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.1.0-h69a702a_0.conda#f4ca84fbd6d06b0a052fb2d5b96dde41 +https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.2.0-h69a702a_1.conda#0a7f4cd238267c88e5d69f7826a407eb https://conda.anaconda.org/conda-forge/linux-64/libmo_unpack-3.1.2-hf484d3e_1001.tar.bz2#95f32a6a5a666d33886ca5627239f03d -https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.58.0-h47da74e_1.conda#700ac6ea6d53d5510591c4344d5c989a -https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.43-h2797004_0.conda#009981dd9cfcaa4dbfa25ffaed86bcae -https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.46.0-hde9e2c9_0.conda#18aa975d2094c34aef978060ae7da7d8 -https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.0-h0841786_0.conda#1f5a58e686b13bcfde88b93f547d23fe -https://conda.anaconda.org/conda-forge/linux-64/libudunits2-2.2.28-h40f5838_3.conda#4bdace082e911a3e1f1f0b721bed5b56 +https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.64.0-h161d5f1_0.conda#19e57602824042dfd0446292ef90488b +https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-5.28.2-h5b01275_0.conda#ab0bff36363bec94720275a681af8b83 https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libvpx-1.14.1-hac33072_0.conda#cde393f461e0c169d9ffb2fc70f81c33 -https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.16-hd590300_0.conda#151cba22b85a989c2d6ef9633ffee1e4 -https://conda.anaconda.org/conda-forge/linux-64/libzip-1.10.1-h2629f0a_3.conda#ac79812548e7e8cf61f7b0abdef01d3b +https://conda.anaconda.org/conda-forge/linux-64/libzip-1.11.1-hf83b1b0_0.conda#e8536ec89df2aec5f65fefcf4ccd58ba https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 +https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.11.3-he02047a_1.conda#e46f7ac4917215b49df2ea09a694a3fa https://conda.anaconda.org/conda-forge/linux-64/openh264-2.4.1-h59595ed_0.conda#3dfcf61b8e78af08110f5229f79580af -https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.24.1-hc5aa10d_0.tar.bz2#56ee94e34b71742bbdfa832c974e47a8 -https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-h0f59acf_0.conda#3914f7ac1761dce57102c72ca7c35d01 +https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-hba22ea6_2.conda#df359c09c41cd186fffb93a2d87aa6f5 https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 https://conda.anaconda.org/conda-forge/linux-64/pugixml-1.14-h59595ed_0.conda#2c97dd90633508b422c11bd3018206ab +https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda#353823361b1d27eb3960efb076dfcaf6 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.1-ha2e4443_0.conda#6b7dcc7349efd123d493d2dbe85a045f -https://conda.anaconda.org/conda-forge/linux-64/svt-av1-2.1.2-hac33072_0.conda#06c5dec4ebb47213b648a6c4dc8400d6 -https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc -https://conda.anaconda.org/conda-forge/linux-64/wayland-1.23.0-h5291e77_0.conda#c13ca0abd5d1d31d0eebcf86d51da8a4 +https://conda.anaconda.org/conda-forge/linux-64/svt-av1-2.2.1-h5888daf_0.conda#0d9c441855be3d8dfdb2e800fe755059 +https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-h40f5838_3.conda#6bb8deb138f87c9d48320ac21b87e7a1 +https://conda.anaconda.org/conda-forge/linux-64/wayland-1.23.1-h3e06ad9_0.conda#0a732427643ae5e0486a727927791da1 https://conda.anaconda.org/conda-forge/linux-64/x265-3.5-h924138e_3.tar.bz2#e7f6ed84d4623d52ee581325c1587a6b -https://conda.anaconda.org/conda-forge/linux-64/xorg-fixesproto-5.0-h7f98852_1002.tar.bz2#65ad6e1eb4aed2b0611855aff05e04f6 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-h7391055_0.conda#93ee23f12bc2e684548181256edd2cf6 -https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-h4ab18f5_1.conda#9653f1bf3766164d0e65fa723cabbc54 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-hb711507_2.conda#8637c3e5821654d0edf97e2b0404b443 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.1-hb711507_0.conda#ad748ccca349aec3e91743e08b5e2b50 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.10-hb711507_0.conda#0e0cbe0564d03a99afd5fd7b362feecd +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.2-hb711507_0.conda#608e0ef8256b81d04456e8d211eee3e8 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-he73a12e_1.conda#05a8ea5f446de33006171a7afe6ae857 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_0.conda#0b666058a179b744a622d0a4a0c56353 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda#4d056880988120e29d75bfff282e0f45 https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-hef167b5_0.conda#54fe76ab3d0189acaef95156874db7f9 -https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hd590300_1.conda#39f910d205726805a958da408ca194ba -https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-h267a509_2.conda#9ae35c3d96db2c94ce0cef86efdfa2cb -https://conda.anaconda.org/conda-forge/linux-64/gl2ps-1.4.2-hae5d5c5_1.conda#00e642ec191a19bf806a3915800e9524 +https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_2.conda#98514fe74548d768907ce7a13f680e8f +https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda#3f43953b7d3fb3aaa1d0d0723d91e368 -https://conda.anaconda.org/conda-forge/linux-64/libasprintf-devel-0.22.5-h661eb56_2.conda#02e41ab5834dcdcc8590cf29d9526f50 -https://conda.anaconda.org/conda-forge/linux-64/libglib-2.80.3-h8a4344b_1.conda#6ea440297aacee4893f02ad759e6ffbc -https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.27-pthreads_hac2b453_1.conda#ae05ece66d3924ac3d48b4aa3fa96cec -https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-4.25.3-h08a7969_0.conda#6945825cebd2aeb16af4c69d97c32c13 +https://conda.anaconda.org/conda-forge/linux-64/libglib-2.82.2-h2ff4ddf_0.conda#13e8e54035ddd2b91875ba399f0f7c04 +https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_1.conda#80a57756c545ad11f9847835aa21e6b2 +https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.28-pthreads_h94d23a6_0.conda#9ebc9aedafaa2515ab247ff6bb509458 https://conda.anaconda.org/conda-forge/linux-64/libtheora-1.1.1-h4ab18f5_1006.conda#553281a034e9cf8693c9df49f6c78ea1 -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.6.0-h1dd3fc0_3.conda#66f03896ffbe1a110ffda05c7a856504 -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.7-h4c95cb1_3.conda#0ac9aff6010a7751961c8e4b863a40e7 -https://conda.anaconda.org/conda-forge/linux-64/python-3.12.4-h194c7f8_0_cpython.conda#d73490214f536cccb5819e9873048c92 -https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.46.0-h6d4b2fc_0.conda#77ea8dff5cf8550cc8f5629a6af56323 -https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-h40f5838_3.conda#6bb8deb138f87c9d48320ac21b87e7a1 -https://conda.anaconda.org/conda-forge/noarch/wayland-protocols-1.36-hd8ed1ab_0.conda#c6f690e7d4abf562161477f14533cfd8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.9-hb711507_1.conda#4a6d410296d7e39f00bacdee7df046e9 -https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda#def531a3ac77b7fb8c21d17bb5d0badb +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-he137b08_1.conda#63872517c98aa305da58a757c443698e +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.7-he7c6b58_4.conda#08a9265c637230c37cb1be4a6cad4536 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_2.conda#57a9e7ee3c0840d3c8c9012473978629 +https://conda.anaconda.org/conda-forge/linux-64/python-3.12.7-hc5c86c4_0_cpython.conda#0515111a9cdf69f83278f7c197db9807 +https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.47.0-h9eae976_0.conda#c4cb444844615e1cd4c9d989f770bcc5 +https://conda.anaconda.org/conda-forge/noarch/wayland-protocols-1.37-hd8ed1ab_0.conda#73ec79a77d31eb7e4a3276cd246b776c +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda#a0901183f08b6c7107aab109733a3c91 +https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.43-hb9d3cd8_0.conda#f725c7425d6d7c15e31f3b99a88ea02f +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda#febbab7d15033c913d53c7a2c102309d +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda#4bdb303603e9821baf5fe5fdff1dc8f8 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hb9d3cd8_1.conda#a7a49a8b85122b49214798321e2e96b4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxt-1.3.0-hb9d3cd8_2.conda#d8602724ac0d276c380b97e9eb0f814b +https://conda.anaconda.org/conda-forge/noarch/aiohappyeyeballs-2.4.3-pyhd8ed1ab_0.conda#ec763b0a58960558ca0ad7255a51a237 +https://conda.anaconda.org/conda-forge/noarch/alabaster-1.0.0-pyhd8ed1ab_0.conda#7d78a232029458d0077ede6cda30ed0c https://conda.anaconda.org/conda-forge/noarch/antlr-python-runtime-4.11.1-pyhd8ed1ab_0.tar.bz2#15109c4977d39ad7aa3423f57243e286 https://conda.anaconda.org/conda-forge/linux-64/atk-1.0-2.38.0-h04ea711_2.conda#f730d54ba9cd543666d7220c9f7ed563 -https://conda.anaconda.org/conda-forge/noarch/attrs-23.2.0-pyh71513ae_0.conda#5e4c0743c70186509d1412e03c2d8dfa -https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hd590300_1.conda#f27a24d46e3ea7b70a1f98e50c62508f -https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py312h30efb56_1.conda#45801a89533d3336a365284d93298e36 -https://conda.anaconda.org/conda-forge/noarch/certifi-2024.7.4-pyhd8ed1ab_0.conda#24e7fd6ca65997938fff9e5ab6f653e4 +https://conda.anaconda.org/conda-forge/noarch/attrs-24.2.0-pyh71513ae_0.conda#6732fa52eb8e66e5afeb32db8701a791 +https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py312h2ec8cdc_2.conda#b0b867af6fc74b2a0aa206da29c0f3cf +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-hebfffa5_3.conda#fceaedf1cdbcb02df9699a0d9b005292 +https://conda.anaconda.org/conda-forge/noarch/certifi-2024.8.30-pyhd8ed1ab_0.conda#12f7d00853807b0531775e9be891cb11 https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_0.tar.bz2#ebb5f5f7dc4f1a3780ef7ea7738db08c -https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1ab_0.conda#7f4a9e3fcff3f6356ae99244a014da6a +https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.0-pyhd8ed1ab_0.conda#a374efa97290b8799046df7c5ca17164 https://conda.anaconda.org/conda-forge/noarch/click-8.1.7-unix_pyh707e725_0.conda#f3ad426304898027fc619827ff428eca -https://conda.anaconda.org/conda-forge/noarch/cloudpickle-3.0.0-pyhd8ed1ab_0.conda#753d29fe41bb881e4b9c004f0abf973f +https://conda.anaconda.org/conda-forge/noarch/cloudpickle-3.1.0-pyhd8ed1ab_1.conda#c88ca2bb7099167912e3b26463fff079 https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 https://conda.anaconda.org/conda-forge/noarch/colorcet-3.1.0-pyhd8ed1ab_0.conda#4d155b600b63bc6ba89d91fab74238f8 https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_0.conda#5cd86562580f274031ede6aa6aa24441 -https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.10-py312h30efb56_0.conda#b119273bff37284cbcb9281c1e85e67d -https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.8-pyhd8ed1ab_0.conda#db16c66b759a64dc5183d69cc3745a52 +https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.27-h54b06d7_7.conda#dce22f70b4e5a407ce88f2be046f4ceb +https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.11-py312h8fd2918_3.conda#21e433caf1bb1e4c95832f8bb731d64c +https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d +https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.9-pyhd8ed1ab_0.conda#fe521c1608280cc2803ebd26dc252212 https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda#e8cd5d629f65bdf0f3bb312cde14659e https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda#d02ae936e42063ca46af6cdad2dbd1e0 https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda#15dda3cdbf330abfe9f555d22f66db46 -https://conda.anaconda.org/conda-forge/noarch/filelock-3.15.4-pyhd8ed1ab_0.conda#0e7e4388e9d5283e22b35a9443bdbcc9 -https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d -https://conda.anaconda.org/conda-forge/linux-64/frozenlist-1.4.1-py312h98912ed_0.conda#2715764dfa5fb00343e03d5a59b64582 -https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.6.1-pyhff2d567_0.conda#996bf792cdb8c0ac38ff54b9fde56841 +https://conda.anaconda.org/conda-forge/noarch/filelock-3.16.1-pyhd8ed1ab_0.conda#916f8ec5dd4128cd5f207a3c4c07b2c6 +https://conda.anaconda.org/conda-forge/linux-64/frozenlist-1.5.0-py312h66e93f0_0.conda#f98e36c96b2c66d9043187179ddb04f4 +https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.10.0-pyhff2d567_0.conda#816dbc4679a64e4417cd1385d661bb31 https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.12-hb9ae30d_0.conda#201db6c2d9a3c5e46573ac4cb2e92f4f -https://conda.anaconda.org/conda-forge/linux-64/gettext-0.22.5-h59595ed_2.conda#219ba82e95d7614cf7140d2a4afc0926 https://conda.anaconda.org/conda-forge/linux-64/gts-0.7.6-h977cf35_4.conda#4d8df0b0db060d33c9a702ada998a8fe https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyh9f0ad1d_0.tar.bz2#914d6646c4dbb1fd3ff539830a12fd71 https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_0.tar.bz2#9f765cbfab6870c8435b9eefecd7a1f4 -https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda#c0cc1420498b17414d8617d0b9f506ca +https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_0.conda#7ba2ede0e7c795ff95088daf0dc59753 https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 -https://conda.anaconda.org/conda-forge/noarch/iris-sample-data-2.4.0-pyhd8ed1ab_0.tar.bz2#18ee9c07cf945a33f92caf1ee3d23ad9 -https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.5-py312h8572e83_1.conda#c1e71f2bc05d8e8e033aefac2c490d05 +https://conda.anaconda.org/conda-forge/noarch/iris-sample-data-2.5.1-pyhd8ed1ab_0.conda#faf232274689aa60da5a63e7cc5faeb7 +https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.7-py312h68727a3_0.conda#444266743652a4f1538145e9362f6d3b https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.16-hb7c19ff_0.conda#51bb7010fc86f70eee639b4bb7a894f5 -https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.7.4-hfca40fe_0.conda#32ddb97f897740641d8d46a829ce1704 -https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-22_linux64_openblas.conda#1a2a0cd3153464fee6646f3dd6dad9b8 -https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.8.0-hca28451_1.conda#b8afb3e3cb3423cc445cf611ab95fdb0 +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-25_linux64_openblas.conda#8ea26d42ca88ec5258802715fe1ee10b +https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h4637d8d_4.conda#d4529f4dff3057982a7617c7ac58fde3 +https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.10.1-hbbe4b11_0.conda#6e801c50a40301f6978c53976917b277 +https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-hd3e95f3_10.conda#30ee3a29c84cf7b842a8c5828c4b7c13 +https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_1.conda#204892bce2e44252b5cf272712f10bdd +https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.0-ha6d2627_1004.conda#df069bea331c8486ac21814969301c1f https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.11.1-default_hecaa2ac_1000.conda#f54aeebefb5c5ff84eca4fb05ca8aa3a -https://conda.anaconda.org/conda-forge/linux-64/libllvm18-18.1.8-h8b73ec9_1.conda#16d94b3586ef3558e5a583598524deb4 -https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.4.0-h2c329e2_0.conda#80030debaa84cfc31755d53742df3ca6 +https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.2-ha7bfdaf_0.conda#128e74a4f8f4fef4dc5130a8bbccc15d +https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.7.0-h2c5496b_1.conda#e2eaefa4de2b7237af7c907b8bbc760a https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2#91e27ef3d05cc772ce627e51cff111c4 -https://conda.anaconda.org/conda-forge/linux-64/loguru-0.7.2-py312h7900ff3_1.conda#507696b7c888a8b872b50f24ac860089 -https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.5-py312h98912ed_0.conda#6ff0b9582da2d4a74a1f9ae1f9ce2af6 -https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.0.8-py312h2492b07_0.conda#0df463266eaaa1b8a35f8fd26368c1a1 -https://conda.anaconda.org/conda-forge/linux-64/multidict-6.0.5-py312h98912ed_0.conda#d0d2cab29d6c33c47f719d7a1879e08b +https://conda.anaconda.org/conda-forge/linux-64/loguru-0.7.2-py312h7900ff3_2.conda#fddd3092f921be8e01b18f2a0266d98f +https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py312h178313f_0.conda#a755704ea0e2503f8c227d84829a8e81 +https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.0-py312h68727a3_0.conda#5c9b020a3f86799cdc6115e55df06146 +https://conda.anaconda.org/conda-forge/linux-64/multidict-6.1.0-py312h178313f_1.conda#e397d9b841c37fc3180b73275ce7e990 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.2-h488ebb8_0.conda#7f2e286780f072ed750df46dc2631138 https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda#cbe1bb1f21567018ce595d9c2be0f0db -https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.2-pyhd8ed1ab_0.conda#6f6cf28bf8e021933869bae3f84b8fc9 +https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.6-pyhd8ed1ab_0.conda#fd8f2b18b65bbf62e8f653100690c8d2 https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda#d3483c8fc2dc2cc3f5cf43e26d60cabf -https://conda.anaconda.org/conda-forge/linux-64/psutil-6.0.0-py312h9a8786e_0.conda#1aeffa86c55972ca4e88ac843eccedf2 +https://conda.anaconda.org/conda-forge/linux-64/propcache-0.2.0-py312h66e93f0_2.conda#2c6c0c68f310bc33972e7c83264d7786 +https://conda.anaconda.org/conda-forge/linux-64/psutil-6.1.0-py312h66e93f0_0.conda#0524eb91d3d78d76d671c6e3cd7cee82 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda#844d9eb3b43095b031874477f7d70088 https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda#b7f5c092b8f9800150d998a71b76d5a1 -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.1.2-pyhd8ed1ab_0.conda#b9a4dacf97241704529131a0dfc0494f +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.0-pyhd8ed1ab_1.conda#035c17fbf099f50ff60bf2eb303b0a83 https://conda.anaconda.org/conda-forge/noarch/pyshp-2.3.1-pyhd8ed1ab_0.tar.bz2#92a889dc236a5197612bc85bee6d7174 https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 -https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.1-pyhd8ed1ab_0.conda#98206ea9954216ee7540f0c773f2104d -https://conda.anaconda.org/conda-forge/linux-64/python-xxhash-3.4.1-py312h98912ed_0.conda#a8f9739e0ada2320148c92ddd608864f +https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.2-pyhd8ed1ab_0.conda#986287f89929b2d629bd6ef6497dc307 +https://conda.anaconda.org/conda-forge/linux-64/python-xxhash-3.5.0-py312h66e93f0_1.conda#39aed2afe4d0cf76ab3d6b09eecdbea7 https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda#3eeeeb9e4827ace8c0c1419c85d590ad -https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.1-py312h98912ed_1.conda#e3fd78d8d490af1d84763b9fe3f2e552 +https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.2-py312h66e93f0_1.conda#549e5930e768548a89c23f595dac5a95 https://conda.anaconda.org/conda-forge/noarch/scooby-0.10.0-pyhd8ed1ab_0.conda#9e57330f431abbb4c88a5f898a4ba223 -https://conda.anaconda.org/conda-forge/noarch/setuptools-71.0.3-pyhd8ed1ab_0.conda#d4b6e6ce2f7bcaec484b81c447df1028 +https://conda.anaconda.org/conda-forge/noarch/setuptools-75.1.0-pyhd8ed1ab_0.conda#d5cd48392c67fb6849ba459c2c2b671f https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2#4d22a9315e78c6827f806065957d566e https://conda.anaconda.org/conda-forge/noarch/sortedcontainers-2.4.0-pyhd8ed1ab_0.tar.bz2#6d6552722448103793743dabfbda532d @@ -200,128 +209,131 @@ https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.5-pyhd8ed1ab_1.conda#3 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda#da1d979339e2714c30a8e806a33ec087 https://conda.anaconda.org/conda-forge/noarch/tblib-3.0.0-pyhd8ed1ab_0.conda#04eedddeb68ad39871c8127dd1c21f4f https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 -https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96 -https://conda.anaconda.org/conda-forge/noarch/toolz-0.12.1-pyhd8ed1ab_0.conda#2fcb582444635e2c402e8569bb94e039 -https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py312h9a8786e_0.conda#fd9c83fde763b494f07acee1404c280e +https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.2-pyhd8ed1ab_0.conda#e977934e00b355ff55ed154904044727 +https://conda.anaconda.org/conda-forge/noarch/toolz-1.0.0-pyhd8ed1ab_0.conda#34feccdd4177f2d3d53c73fc44fd9a37 +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py312h66e93f0_1.conda#af648b62462794649066366af4ecd5b0 https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda#ebe6952715e1d5eb567eeebf25250fa7 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.43.0-pyhd8ed1ab_1.conda#0b5293a157c2b5cd513dd1b03d8d3aae -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h0b41bf4_2.conda#82b6df12252e6f32402b96dacc656fec -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-5.0.3-h7f98852_1004.tar.bz2#e9a21aa4d5e3e5f1aed71e8cefd46b6a -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hd590300_0.conda#ed67c36f215b310412b2af935bf3e530 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxt-1.3.0-hd590300_1.conda#ae92aab42726eb29d16488924f7312cb +https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-15.1.0-py312h66e93f0_1.conda#588486a61153f94c7c13816f7069e440 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.44.0-pyhd8ed1ab_0.conda#d44e3b085abcaef02983c6305b84b584 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.5-hb9d3cd8_0.conda#eb44b3b6deb1cab08d72cb61686fe64c +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda#d3c295b50f092ab525ffe3c2aa4b7413 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.2-hb9d3cd8_0.conda#bb2638cd7fbdd980b1cff9a99a6c1fa8 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda#b5fcc7172d22516e1f965490e65e33a4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda#17dcc85db3c7886650b8908b183d6876 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.4-hb9d3cd8_0.conda#2de7f99d6581a4a7adbff607b5c278ca +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.5-hb9d3cd8_4.conda#7da9007c0582712c4bad4131f89c8372 https://conda.anaconda.org/conda-forge/noarch/zict-3.0.0-pyhd8ed1ab_0.conda#cf30c2c15b82aacb07f9c09e28ff2275 -https://conda.anaconda.org/conda-forge/noarch/zipp-3.19.2-pyhd8ed1ab_0.conda#49808e59df5535116f6878b2a820d6f4 +https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.2-pyhd8ed1ab_0.conda#4daaed111c05672ae669f7036ee5bba3 https://conda.anaconda.org/conda-forge/noarch/accessible-pygments-0.0.5-pyhd8ed1ab_0.conda#1bb1ef9806a9a20872434f58b3e7fc1a https://conda.anaconda.org/conda-forge/noarch/aiosignal-1.3.1-pyhd8ed1ab_0.tar.bz2#d1e1eb7e21a9e2c74279d87dafb68156 https://conda.anaconda.org/conda-forge/noarch/babel-2.14.0-pyhd8ed1ab_0.conda#9669586875baeced8fc30c0826c3270e https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.12.3-pyha770c72_0.conda#332493000404d8411859539a5a630865 -https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-hbb29018_2.conda#b6d90276c5aee9b4407dd94eb0cd40a8 -https://conda.anaconda.org/conda-forge/linux-64/cffi-1.16.0-py312hf06ca03_0.conda#56b0ca764ce23cc54f3f7e2a7b970f6d +https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.1-py312h06ac9bb_0.conda#a861504bbea4161a9170b85d4d2be840 https://conda.anaconda.org/conda-forge/noarch/click-default-group-1.2.4-pyhd8ed1ab_0.conda#7c2b6931f9b3548ed78478332095c3e9 -https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.0-py312h41a817b_0.conda#66c68c204a3eaabc3b4221f1c4bcebbe -https://conda.anaconda.org/conda-forge/linux-64/cytoolz-0.12.3-py312h98912ed_0.conda#a4fbffb84a54767266c69e3699078a00 -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.53.1-py312h41a817b_0.conda#da921c56bcf69a8b97216ecec0cc4015 +https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.4-py312h178313f_0.conda#a32fbd2322865ac80c7db74c553f5306 +https://conda.anaconda.org/conda-forge/linux-64/cytoolz-1.0.0-py312h66e93f0_1.conda#a921e2fe122e7f38417b9b17c7a13343 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.54.1-py312h178313f_1.conda#bbbf5fa5cab622c33907bc8d7eeea9f7 +https://conda.anaconda.org/conda-forge/linux-64/glew-2.1.0-h9c3ff4c_2.tar.bz2#fb05eb5c47590b247658243d27fc32f1 https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_0.tar.bz2#b748fbf7060927a6e82df7cb5ee8f097 -https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.3-nompi_hdf9ad27_105.conda#7e1729554e209627636a0f6fabcdd115 -https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.0.0-pyha770c72_0.conda#3286556cdd99048d198f72c3f6f69103 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-9.0.0-hda332d3_1.conda#76b32dcf243444aea9c6b804bcfa40b8 +https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.4-nompi_h2d575fe_101.conda#09967792ea2191a0bdb461f9c889e510 +https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.5.0-pyha770c72_0.conda#54198435fce4d64d8a89af22573012a8 https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda#7b86ecb7d3557821c649b3c31e3eb9f2 -https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-22_linux64_openblas.conda#4b31699e0ec5de64d5896e580389c9a1 -https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-h119a65a_9.conda#cfebc557e54905dadc355c0e9f003004 -https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.7-hd590300_0.conda#2b7b0d827c6447cc1d85dc06d5b5de46 -https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-22_linux64_openblas.conda#b083767b6c877e24ee597d93b87ab838 -https://conda.anaconda.org/conda-forge/linux-64/libva-2.22.0-hb711507_0.conda#d12f659072132c9d16e497073fc1f68b +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-25_linux64_openblas.conda#5dbd1b0fc0d01ec5e0e1fbe667281a11 +https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.2-default_hb5137d0_1.conda#7e574c7499bc41f92537634a23fed79a +https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.2-default_h9c6a7e4_1.conda#cb5c5ff12b37aded00d9aaa7b9a86a78 +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-25_linux64_openblas.conda#4dc03a53fc69371a6158d0ed37214cd3 +https://conda.anaconda.org/conda-forge/linux-64/libva-2.22.0-h8a09558_1.conda#139262125a3eac8ff6eef898598745a3 https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.9.1-pyhd8ed1ab_0.conda#dfe0528d0f1c16c1f7c528ea5536ab30 +https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.8-hedd0468_0.conda#dcd0ed5147d8876b0848a552b416ce76 https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda#0badf9c54e24cecfb0ad2f99d680c163 -https://conda.anaconda.org/conda-forge/linux-64/pillow-10.4.0-py312h287a98d_0.conda#59ea71eed98aee0bebbbdd3b118167c7 -https://conda.anaconda.org/conda-forge/noarch/pip-24.0-pyhd8ed1ab_0.conda#f586ac1e56c8638b64f9c8122a7b8a67 -https://conda.anaconda.org/conda-forge/linux-64/proj-9.3.1-h1d62c97_0.conda#44ec51d0857d9be26158bb85caa74fdb -https://conda.anaconda.org/conda-forge/noarch/pytest-8.2.2-pyhd8ed1ab_0.conda#0f3f49c22c7ef3a1195fa61dad3c43be +https://conda.anaconda.org/conda-forge/linux-64/pillow-11.0.0-py312h7b63e92_0.conda#385f46a4df6f97892503a841121a9acf +https://conda.anaconda.org/conda-forge/noarch/pip-24.2-pyh8b19718_1.conda#6c78fbb8ddfd64bcb55b5cbafd2d2c43 +https://conda.anaconda.org/conda-forge/linux-64/proj-9.5.0-h12925eb_0.conda#8c29983ebe50cc7e0998c34bc7614222 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda#c03d61f31f38fdb9facf70c29958bf7a https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda#2cf4264fffb9e6eff6031c5b6884d61c -https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.12.0-h434a139_3.conda#c667c11d1e488a38220ede8a34441bff +https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.13.0-h84d6215_0.conda#ee6f7fd1e76061ef1fa307d41fa86a96 https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.12.2-hd8ed1ab_0.conda#52d648bd608f5737b123f510bb5514b5 -https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.26.3-pyhd8ed1ab_0.conda#284008712816c64c85bf2b7fa9f3b264 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.5-h7f98852_1.tar.bz2#bebd3814ec2355fab6a474b07ed73093 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.2-h7f98852_1.tar.bz2#5b0f7da25a4556c9619c3e4b4a98ab07 -https://conda.anaconda.org/conda-forge/linux-64/yarl-1.9.4-py312h98912ed_0.conda#ec3eb4803df33e90a41bc216a68d02f1 -https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.9.5-py312h98912ed_0.conda#edc01db954d139fe398a5f378f96ab4d +https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.27.0-pyhd8ed1ab_0.conda#a6ed1227ba6ec37cfc2b25e6512f729f +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda#7bbe9a0cc0df0ac5f5a8ad6d6a11af2f +https://conda.anaconda.org/conda-forge/linux-64/yarl-1.16.0-py312h66e93f0_0.conda#c3f4a6b56026c22319bf31514662b283 +https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.10.10-py312h178313f_0.conda#d2f9e490ab2eae3e661b281346618a82 https://conda.anaconda.org/conda-forge/noarch/asv_runner-0.2.1-pyhd8ed1ab_0.conda#fdcbeb072c80c805a2ededaa5f91cd79 -https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.7.9-hb077bed_0.conda#33eded89024f21659b1975886a4acf70 -https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-9.0.0-hfac3d4d_0.conda#c7b47c64af53e8ecee01d101eeab2342 -https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-8.0.0-hd8ed1ab_0.conda#5f8c8ebbe6413a7838cf6ecf14d5d31b -https://conda.anaconda.org/conda-forge/noarch/lazy_loader-0.4-pyhd8ed1ab_0.conda#a284ff318fbdb0dd83928275b4b6087c -https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.2-nompi_h135f659_114.conda#a908e463c710bd6b10a9eaa89fdf003c -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-2024.2.0-h2da1b83_1.conda#9511859bf5221238a2d3fb5322af01d5 -https://conda.anaconda.org/conda-forge/linux-64/numpy-1.26.4-py312heda63a1_0.conda#d8285bea2a350f63fab23bf460221f3f -https://conda.anaconda.org/conda-forge/noarch/pbr-6.0.0-pyhd8ed1ab_0.conda#8dbab5ba746ed14aa32cb232dc437f8f -https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.6.1-py312h38f1c37_5.conda#867baf2a7c5c6147e05ecc90f6c52a0c +https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-8.5.0-hd8ed1ab_0.conda#2a92e152208121afadf85a5e1f3a5f4d +https://conda.anaconda.org/conda-forge/noarch/lazy-loader-0.4-pyhd8ed1ab_1.conda#4809b9f4c6ce106d443c3f90b8e10db2 +https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.3-h1dc1e6a_0.conda#2a66267ba586dadd110cc991063cfff7 +https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.2-nompi_h2564987_115.conda#c5ce70b76c77a6c9a3107be8d8e8ab0b +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-2024.4.0-hac27bb2_2.conda#ba5ac0bb9ec5aec38dec37c230b12d64 +https://conda.anaconda.org/conda-forge/linux-64/libpq-17.0-h04577a9_4.conda#392cae2a58fbcb9db8c2147c6d6d1620 +https://conda.anaconda.org/conda-forge/linux-64/numpy-2.1.2-py312h58c1407_0.conda#b7e9a46277a1ee0afc6311e7760df0c3 +https://conda.anaconda.org/conda-forge/linux-64/pango-1.54.0-h4c5309f_1.conda#7df02e445367703cd87a574046e3a6f0 +https://conda.anaconda.org/conda-forge/noarch/pbr-6.1.0-pyhd8ed1ab_0.conda#5a166b998fd17cdaaaadaccdd71a363f +https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.7.0-py312he630544_0.conda#427799f15b36751761941f4cbd7d780f https://conda.anaconda.org/conda-forge/noarch/pytest-cov-5.0.0-pyhd8ed1ab_0.conda#c54c0107057d67ddf077751339ec2c63 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_0.conda#b39568655c127a9c4a44d178ac99b6d0 https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-8.1.0-pyhd8ed1ab_0.conda#ba9f7f0ec4f2a18de3e7bce67c4a431e -https://conda.anaconda.org/conda-forge/linux-64/tbb-devel-2021.12.0-hfcbfbdb_3.conda#dd410ed856f34c994f1549079ff601bf -https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py312h8572e83_4.conda#52c9e25ee0a32485a102eeecdb7eef52 -https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py312h3483029_0.conda#eab52e88c858d87cf5a069f79d10bb50 -https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.4-py312h085067d_0.conda#864d9e92f012bcc49650428d5343c98a +https://conda.anaconda.org/conda-forge/linux-64/tbb-devel-2021.13.0-h94b29a5_0.conda#4431bd4ace17dd09b97caf68509b016b +https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py312h68727a3_5.conda#f9664ee31aed96c85b7319ab0a693341 +https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py312hef9b889_1.conda#8b7069e9792ee4e5b4919a7a306d2e67 +https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.4-py312hc0a28a1_1.conda#990033147b0a998e756eaaed6b28f48d https://conda.anaconda.org/conda-forge/noarch/colorspacious-1.1.2-pyh24bf2e0_0.tar.bz2#b73afa0d009a51cabd3ec99c4d2ef4f3 -https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.2.1-py312h8572e83_0.conda#12c6a831ef734f0b2dd4caff514cbb7f -https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.7.0-pyhd8ed1ab_0.conda#755e47653ae38f5c50f1435af756e844 -https://conda.anaconda.org/conda-forge/noarch/identify-2.6.0-pyhd8ed1ab_0.conda#f80cc5989f445f23b1622d6c455896d9 -https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.1-h39113c1_2.conda#25db2ea6b8fefce451369e2cc826f6f4 -https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.1-h97afed2_0.conda#00bd7406d24d6574f2de3839b60e0925 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-batch-plugin-2024.2.0-hb045406_1.conda#70d82a64e6d07f4d6e07cae6b0bd4bd1 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-plugin-2024.2.0-hb045406_1.conda#f1e2a8ded23cef03804c4edb2edfb986 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-hetero-plugin-2024.2.0-h5c03a75_1.conda#95d2d3baaa1e456ef65c713a5d99b815 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-cpu-plugin-2024.2.0-h2da1b83_1.conda#9e49f87d8f99dc9724f52b3fac904106 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-gpu-plugin-2024.2.0-h2da1b83_1.conda#a9712fae44d01d906e228c49235e3b89 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-npu-plugin-2024.2.0-he02047a_1.conda#5c2d064181e686cf5cfac6f1a1ee4e91 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-ir-frontend-2024.2.0-h5c03a75_1.conda#89addf0fc0f489fa0c076f1c8c0d62bf -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-onnx-frontend-2024.2.0-h07e8aee_1.conda#9b0a13989b35302e47da13842683804d -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-paddle-frontend-2024.2.0-h07e8aee_1.conda#7b3680d3fd00e1f91d5faf9c97c7ae78 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-pytorch-frontend-2024.2.0-he02047a_1.conda#ac43b516c128411f84f1e19c875998f1 -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-frontend-2024.2.0-h39126c6_1.conda#11acf52cac790edcf087b89e83834f7d -https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-lite-frontend-2024.2.0-he02047a_1.conda#e7f91b35e3aa7abe880fc9192a761fc0 -https://conda.anaconda.org/conda-forge/linux-64/mo_pack-0.3.0-py312h98912ed_1.conda#d5273d1e67b7b3a871a0a711c6532a2f -https://conda.anaconda.org/conda-forge/linux-64/netcdf-fortran-4.6.1-nompi_h228c76a_104.conda#91bc3ac73308181d55a09d9e4aeb4496 -https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.2-py312h1d6d2e6_1.conda#ae00b61f3000d2284d1f2584d4dfafa8 -https://conda.anaconda.org/conda-forge/linux-64/pango-1.54.0-h4c5309f_1.conda#7df02e445367703cd87a574046e3a6f0 -https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.3.12-py312h085067d_1.conda#7aeadf26294d5e86c0d40d0f960f5366 -https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.6.0-py312h085067d_0.conda#092b4c0b822e36ed686010d2578953f1 -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.14.0-py312hc2bc53b_1.conda#eae80145f63aa04a02dda456d4883b46 -https://conda.anaconda.org/conda-forge/linux-64/shapely-2.0.5-py312h8413631_0.conda#3e67354b24c7ee057ddee367f310ad3e -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-apidoc-0.3.0-py_1.tar.bz2#855b087883443abb10f5faf6eef40860 -https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.2-pyhd8ed1ab_1.conda#e804c43f58255e977093a2298e442bb8 -https://conda.anaconda.org/conda-forge/noarch/wslink-2.1.1-pyhd8ed1ab_0.conda#6b1aef9c878c58baa7bb9f0d44457174 -https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.2.0-py312h085067d_5.conda#b40cdf87aee69ccf162022579cb99afb -https://conda.anaconda.org/conda-forge/noarch/distributed-2024.7.0-pyhd8ed1ab_0.conda#2ae917b0098f286f63f69ec9365fb0b1 -https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.191-h924a536_0.conda#73d050766060acd2b3a289f27d857090 -https://conda.anaconda.org/conda-forge/linux-64/esmf-8.6.1-nompi_h0a5817f_2.conda#e23c62f75f67166cf4ca137fc8bcdce7 -https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-6.1.1-gpl_h9be9148_116.conda#b89791728e73df731d1560f936147a01 +https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.0-py312h68727a3_2.conda#ff28f374b31937c048107521c814791e +https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.10.0-pyhd8ed1ab_0.conda#7823092a3cf14e98a52d2a2875c47c80 https://conda.anaconda.org/conda-forge/linux-64/gtk2-2.24.33-h6470451_5.conda#1483ba046164be27df7f6eddbcec3a12 +https://conda.anaconda.org/conda-forge/noarch/identify-2.6.1-pyhd8ed1ab_0.conda#43f629202f9eec21be5f71171fb5daf8 +https://conda.anaconda.org/conda-forge/noarch/lazy_loader-0.4-pyhd8ed1ab_1.conda#ec6f70b8a5242936567d4f886726a372 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-batch-plugin-2024.4.0-h4d9b6c2_2.conda#1d05a25da36ba5f98291d7237fc6b8ce +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-plugin-2024.4.0-h4d9b6c2_2.conda#838b2db868f9ab69a7bad9c065a3362d +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-hetero-plugin-2024.4.0-h3f63f65_2.conda#00a6127960a3f41d4bfcabd35d5fbeec +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-cpu-plugin-2024.4.0-hac27bb2_2.conda#6cfc840bc39c17d92fb25e5a35789e5b +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-gpu-plugin-2024.4.0-hac27bb2_2.conda#9e9814b40d8fdfd8485451e3fa2f1719 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-npu-plugin-2024.4.0-hac27bb2_2.conda#724719ce97feb6f310f88ae8dbb40afd +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-ir-frontend-2024.4.0-h3f63f65_2.conda#8908f31eab30f65636eb61ab9cb1f3ad +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-onnx-frontend-2024.4.0-h5c8f2c3_2.conda#e098caa87868e8dcc7ed5d011981207d +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-paddle-frontend-2024.4.0-h5c8f2c3_2.conda#59bb8c3502cb9d35f1fb26691730288c +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-pytorch-frontend-2024.4.0-h5888daf_2.conda#e0b88fd64dc95f715ef52e607a9af89b +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-frontend-2024.4.0-h6481b9d_2.conda#12bf831b85f17368bc71a26ac93a8493 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-lite-frontend-2024.4.0-h5888daf_2.conda#d48c774c40ea2047adbff043e9076e7a +https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.58.4-hc0ffecb_0.conda#83f045969988f5c7a65f3950b95a8b35 +https://conda.anaconda.org/conda-forge/linux-64/mo_pack-0.3.1-py312h66e93f0_1.conda#5fef67f50126f40f5966a9451661280d +https://conda.anaconda.org/conda-forge/linux-64/netcdf-fortran-4.6.1-nompi_ha5d1325_107.conda#5bd5042289ef82196bae48948314cdf9 +https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.3-py312hf9745cd_1.conda#8bce4f6caaf8c5448c7ac86d87e26b4b +https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.3.13-py312hc0a28a1_1.conda#b4fa8eafe923ac2733001fef8531026f +https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.7.0-py312hc0a28a1_2.conda#8300d634adec4a6aed35a87e90e9cb07 +https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.7.3-h6e8976b_1.conda#f3234422a977b5d400ccf503ad55c5d1 +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.14.1-py312h62794b6_1.conda#b43233a9e2f62fb94affe5607ea79473 +https://conda.anaconda.org/conda-forge/linux-64/shapely-2.0.6-py312h391bc85_2.conda#eb476b4975ea28ac12ff469063a71f5d +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-apidoc-0.3.0-py_1.tar.bz2#855b087883443abb10f5faf6eef40860 +https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.3-pyhd8ed1ab_0.conda#6b55867f385dd762ed99ea687af32a69 +https://conda.anaconda.org/conda-forge/noarch/wslink-2.2.1-pyhd8ed1ab_0.conda#74674b93806167c26da4eca7613bc225 +https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.2.0-py312hc0a28a1_6.conda#fa4853d25b6fbfef5eb7b3e1b5616dd5 +https://conda.anaconda.org/conda-forge/noarch/distributed-2024.10.0-pyhd8ed1ab_0.conda#b3b498f7bcc9a2543ad72a3501f3d87b +https://conda.anaconda.org/conda-forge/linux-64/esmf-8.6.1-nompi_h6063b07_4.conda#3108bfa76cd8a3ebc5546797106946e5 +https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-6.1.2-gpl_h8657690_705.conda#bba34ade586dc53222d5e0387f7733c2 +https://conda.anaconda.org/conda-forge/linux-64/graphviz-12.0.0-hba01fac_0.conda#953e31ea00d46beb7e64a79fc291ec44 https://conda.anaconda.org/conda-forge/noarch/imagehash-4.3.1-pyhd8ed1ab_0.tar.bz2#132ad832787a2156be1f1b309835001a -https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.58.2-h9564881_1.conda#c6a47e6f551890e82e92e4c1b84be353 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.8.4-py312h20ab3a6_2.conda#fbfe798f83f0d66410903ad8f40d5283 -https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.1-nompi_py312h1ef7fb6_101.conda#c67cc8e3a34c5cb8920c79918112e96f -https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.7.1-pyha770c72_0.conda#724bc4489c1174fc8e3233b0624fa51f -https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.3.0-py312h085067d_2.conda#1e88f5023d2af511e48e4489b45b9f9b +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.2-py312hd3ec401_1.conda#2f4f3854f23be30de29e9e4d39758349 +https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.7.2-nompi_py312ha728dd9_100.conda#8e932f27c4339835563f42d73b158d53 +https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.0.1-pyha770c72_0.conda#5971cc64048943605f352f7f8612de6c +https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.3.0-py312hc0a28a1_3.conda#81bbcb20ea4a53b05a8cf51f31496038 https://conda.anaconda.org/conda-forge/noarch/requests-2.32.3-pyhd8ed1ab_0.conda#5ede4753180c7a550a443c430dc8ab52 -https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.23.0-py312h1d6d2e6_1.conda#6392d3ce615ab0f32bc39b07f8f4c300 +https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.3.1-qt_py312hc73667e_209.conda#e2967eddf4ea06a8b645da9967f370be +https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.24.0-py312hf9745cd_0.conda#ea213e31805199cb7d0da457b879ceed https://conda.anaconda.org/conda-forge/noarch/cmocean-4.0.3-pyhd8ed1ab_0.conda#53df00540de0348ed1b2a62684dd912b https://conda.anaconda.org/conda-forge/noarch/esmpy-8.6.1-pyhc1e730c_0.conda#25a9661177fd68bfdb4314fd658e5c3b -https://conda.anaconda.org/conda-forge/linux-64/graphviz-11.0.0-hc68bbd7_0.conda#52a531ef95358086a56086c45d97ab75 -https://conda.anaconda.org/conda-forge/linux-64/mesalib-24.1.4-h3ac77ca_0.conda#083464147e4169cf088522070964e0cf https://conda.anaconda.org/conda-forge/noarch/nc-time-axis-1.4.1-pyhd8ed1ab_0.tar.bz2#281b58948bf60a2582de9e548bcc5369 https://conda.anaconda.org/conda-forge/noarch/pooch-1.8.2-pyhd8ed1ab_0.conda#8dab97d8a9616e07d779782995710aed -https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.3.1-osmesa_py312hb25cddc_101.conda#503f5be16a4df665d9a068ce9588c2a1 -https://conda.anaconda.org/conda-forge/linux-64/vtk-io-ffmpeg-9.3.1-osmesa_py312hde2fd57_101.conda#eef52b2d6c8c72871bd16858eecc7d1a -https://conda.anaconda.org/conda-forge/linux-64/vtk-9.3.1-osmesa_py312h7c0142d_101.conda#2f6fe962f2b2e2986bbed13a78e6aa3f -https://conda.anaconda.org/conda-forge/noarch/pyvista-0.44.0-pyhd8ed1ab_0.conda#16270d42141769c8342e067d25acc6ce -https://conda.anaconda.org/conda-forge/noarch/geovista-0.5.1-pyhd8ed1ab_0.conda#22958696ccc609071ba40867090bfd3a -https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.15.4-pyhd8ed1ab_0.conda#c7c50dd5192caa58a05e6a4248a27acb +https://conda.anaconda.org/conda-forge/linux-64/vtk-io-ffmpeg-9.3.1-qt_py312hc8241c7_209.conda#1354402d09a8614821d6d3c13d826863 +https://conda.anaconda.org/conda-forge/linux-64/vtk-9.3.1-qt_py312he5e186c_209.conda#c6aba64b606a07b20b345b1e4146494b +https://conda.anaconda.org/conda-forge/noarch/pyvista-0.44.1-pyhd8ed1ab_0.conda#0731b45087c0358ca8b7d9fe855dec1a +https://conda.anaconda.org/conda-forge/noarch/geovista-0.5.3-pyhd8ed1ab_0.conda#4b12a3321889056bf9a000be9a0763b3 +https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.16.0-pyhd8ed1ab_0.conda#344261b0e77f5d2faaffb4eac225eeb7 https://conda.anaconda.org/conda-forge/noarch/sphinx-copybutton-0.5.2-pyhd8ed1ab_0.conda#ac832cc43adc79118cf6e23f1f9b8995 -https://conda.anaconda.org/conda-forge/noarch/sphinx-design-0.6.0-pyhd8ed1ab_0.conda#b04f3c04e4f7939c6207dc0c0355f468 -https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.16.0-pyhd8ed1ab_0.conda#add28691ee89e875b190eda07929d5d4 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd8ed1ab_0.conda#611a35a27914fac3aa37611a6fe40bb5 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.6-pyhd8ed1ab_0.conda#d7e4954df0d3aea2eacc7835ad12671d -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.5-pyhd8ed1ab_0.conda#7e1e7437273682ada2ed5e9e9714b140 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.7-pyhd8ed1ab_0.conda#26acae54b06f178681bfb551760f5dd1 -https://conda.anaconda.org/conda-forge/noarch/sphinx-7.4.5-pyhd8ed1ab_0.conda#98a3e9786dd637216c6a028f5061cd71 +https://conda.anaconda.org/conda-forge/noarch/sphinx-design-0.6.1-pyhd8ed1ab_1.conda#db0f1eb28b6df3a11e89437597309009 +https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.18.0-pyhd8ed1ab_0.conda#dc78276cbf5ec23e4b959d1bbd9caadb +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-2.0.0-pyhd8ed1ab_0.conda#9075bd8c033f0257122300db914e49c9 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-2.0.0-pyhd8ed1ab_0.conda#b3bcc38c471ebb738854f52a36059b48 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.1.0-pyhd8ed1ab_0.conda#e25640d692c02e8acfff0372f547e940 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-2.0.0-pyhd8ed1ab_0.conda#d6e5ea5fe00164ac6c2dcc5d76a42192 +https://conda.anaconda.org/conda-forge/noarch/sphinx-8.1.3-pyhd8ed1ab_0.conda#05706dd5a145a9c91861495cd435409a https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda#e507335cb4ca9cff4c3d0fa9cdab255e diff --git a/requirements/py310.yml b/requirements/py310.yml index 309f8aa9a2..f7285938f6 100644 --- a/requirements/py310.yml +++ b/requirements/py310.yml @@ -14,11 +14,11 @@ dependencies: - cartopy >=0.21 - cf-units >=3.1 - cftime >=1.5 - - dask-core >=2022.9.0 + - dask-core >=2022.9.0,!=2024.8.0 - libnetcdf !=4.9.1 - matplotlib-base >=3.5, !=3.9.1 - netcdf4 - - numpy >=1.24, !=1.24.3, <2 + - numpy >=1.24, !=1.24.3 - python-xxhash - pyproj - scipy diff --git a/requirements/py311.yml b/requirements/py311.yml index 58d71ddd52..e6f5e62a2b 100644 --- a/requirements/py311.yml +++ b/requirements/py311.yml @@ -14,11 +14,11 @@ dependencies: - cartopy >=0.21 - cf-units >=3.1 - cftime >=1.5 - - dask-core >=2022.9.0 + - dask-core >=2022.9.0,!=2024.8.0 - libnetcdf !=4.9.1 - matplotlib-base >=3.5, !=3.9.1 - netcdf4 - - numpy >=1.24, !=1.24.3, <2 + - numpy >=1.24, !=1.24.3 - python-xxhash - pyproj - scipy diff --git a/requirements/py312.yml b/requirements/py312.yml index e1e62e52d9..b16f25b501 100644 --- a/requirements/py312.yml +++ b/requirements/py312.yml @@ -14,11 +14,11 @@ dependencies: - cartopy >=0.21 - cf-units >=3.1 - cftime >=1.5 - - dask-core >=2022.9.0 + - dask-core >=2022.9.0,!=2024.8.0 - libnetcdf !=4.9.1 - matplotlib-base >=3.5, !=3.9.1 - netcdf4 - - numpy >=1.24, !=1.24.3, <2 + - numpy >=1.24, !=1.24.3 - python-xxhash - pyproj - scipy diff --git a/requirements/pypi-core.txt b/requirements/pypi-core.txt index e3a5323da5..208ef7f413 100644 --- a/requirements/pypi-core.txt +++ b/requirements/pypi-core.txt @@ -1,11 +1,11 @@ cartopy>=0.21 cf-units>=3.1 cftime>=1.5.0 -dask[array]>=2022.9.0 +dask[array]>=2022.9.0,!=2024.8.0 # libnetcdf!=4.9.1 (not available on PyPI) matplotlib>=3.5 netcdf4 -numpy>=1.24,!=1.24.3,<2 +numpy>=1.24,!=1.24.3 pyproj scipy shapely!=1.8.3