diff --git a/.github/workflows/ci-manifest.yml b/.github/workflows/ci-manifest.yml index 8f3c82859d..a7785a1c50 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.03.1 + uses: scitools/workflows/.github/workflows/ci-manifest.yml@2024.04.0 diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 5f1b2397ef..52e45f41f5 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -35,18 +35,18 @@ jobs: fail-fast: false matrix: os: ["ubuntu-latest"] - python-version: ["3.11"] + python-version: ["3.12"] session: ["doctest", "gallery", "linkcheck"] include: - os: "ubuntu-latest" - python-version: "3.11" + python-version: "3.12" session: "tests" coverage: "--coverage" - os: "ubuntu-latest" - python-version: "3.10" + python-version: "3.11" session: "tests" - os: "ubuntu-latest" - python-version: "3.9" + python-version: "3.10" session: "tests" env: @@ -136,6 +136,8 @@ jobs: - name: "iris ${{ matrix.session }}" env: PY_VER: ${{ matrix.python-version }} + # Force coloured output on GitHub Actions. + PY_COLORS: "1" run: | nox --session ${{ matrix.session }} -- --verbose ${{ matrix.coverage }} diff --git a/.github/workflows/ci-wheels.yml b/.github/workflows/ci-wheels.yml index 35dda2e0a6..9c53673481 100644 --- a/.github/workflows/ci-wheels.yml +++ b/.github/workflows/ci-wheels.yml @@ -52,7 +52,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.10", "3.11", "3.12"] session: ["wheel"] env: ENV_NAME: "ci-wheels" diff --git a/.github/workflows/refresh-lockfiles.yml b/.github/workflows/refresh-lockfiles.yml index 1d055942c0..b16bd72690 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.03.1 + uses: scitools/workflows/.github/workflows/refresh-lockfiles.yml@2024.04.0 secrets: inherit diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 100eae0ac8..7735f193db 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.5.0 + rev: v4.6.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.2.1" + rev: "v0.3.5" hooks: - id: ruff types: [file, python] @@ -63,7 +63,7 @@ repos: types: [file, python] - repo: https://github.com/numpy/numpydoc - rev: v1.6.0 + rev: v1.7.0 hooks: - id: numpydoc-validation exclude: "^lib/iris/tests/|docs/gallery_code/" diff --git a/benchmarks/asv.conf.json b/benchmarks/asv.conf.json index 51983ec04d..6547556ab4 100644 --- a/benchmarks/asv.conf.json +++ b/benchmarks/asv.conf.json @@ -23,7 +23,7 @@ // * No build-time environment variables. // * Is run in the same environment as the ASV install itself. "delegated_env_commands": [ - "PY_VER=3.11 nox --envdir={conf_dir}/.asv/env/nox01 --session=tests --install-only --no-error-on-external-run --verbose" + "PY_VER=3.12 nox --envdir={conf_dir}/.asv/env/nox01 --session=tests --install-only --no-error-on-external-run --verbose" ], // The parent directory of the above environment. // The most recently modified environment in the directory will be used. diff --git a/benchmarks/benchmarks/__init__.py b/benchmarks/benchmarks/__init__.py index e969b1f23e..14b28b3070 100644 --- a/benchmarks/benchmarks/__init__.py +++ b/benchmarks/benchmarks/__init__.py @@ -3,6 +3,7 @@ # 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. """Common code for benchmarks.""" + from os import environ import resource diff --git a/benchmarks/benchmarks/cperf/__init__.py b/benchmarks/benchmarks/cperf/__init__.py index eaff9cf5e0..df28a66265 100644 --- a/benchmarks/benchmarks/cperf/__init__.py +++ b/benchmarks/benchmarks/cperf/__init__.py @@ -9,6 +9,7 @@ Files available from the UK Met Office: moo ls moose:/adhoc/projects/avd/asv/data_for_nightly_tests/ """ + import numpy as np from iris import load_cube diff --git a/benchmarks/benchmarks/cperf/equality.py b/benchmarks/benchmarks/cperf/equality.py index 16f8c10aab..ffe61ef938 100644 --- a/benchmarks/benchmarks/cperf/equality.py +++ b/benchmarks/benchmarks/cperf/equality.py @@ -3,6 +3,7 @@ # 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. """Equality benchmarks for the CPerf scheme of the UK Met Office's NG-VAT project.""" + from .. import on_demand_benchmark from . import SingleDiagnosticMixin diff --git a/benchmarks/benchmarks/cperf/load.py b/benchmarks/benchmarks/cperf/load.py index cafc4631c0..07c2de9e79 100644 --- a/benchmarks/benchmarks/cperf/load.py +++ b/benchmarks/benchmarks/cperf/load.py @@ -3,6 +3,7 @@ # 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. """File loading benchmarks for the CPerf scheme of the UK Met Office's NG-VAT project.""" + from .. import on_demand_benchmark from . import SingleDiagnosticMixin diff --git a/benchmarks/benchmarks/experimental/ugrid/regions_combine.py b/benchmarks/benchmarks/experimental/ugrid/regions_combine.py index f589620aea..6657e70056 100644 --- a/benchmarks/benchmarks/experimental/ugrid/regions_combine.py +++ b/benchmarks/benchmarks/experimental/ugrid/regions_combine.py @@ -16,6 +16,7 @@ run-time that scale with data size. """ + import os import dask.array as da diff --git a/benchmarks/benchmarks/generate_data/__init__.py b/benchmarks/benchmarks/generate_data/__init__.py index 4d80429889..bb53e26b2f 100644 --- a/benchmarks/benchmarks/generate_data/__init__.py +++ b/benchmarks/benchmarks/generate_data/__init__.py @@ -14,6 +14,7 @@ benchmark sequence runs over two different Python versions. """ + from contextlib import contextmanager from inspect import getsource from os import environ diff --git a/benchmarks/benchmarks/generate_data/ugrid.py b/benchmarks/benchmarks/generate_data/ugrid.py index 713e5dc7df..de76d63798 100644 --- a/benchmarks/benchmarks/generate_data/ugrid.py +++ b/benchmarks/benchmarks/generate_data/ugrid.py @@ -3,6 +3,7 @@ # 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. """Scripts for generating supporting data for UGRID-related benchmarking.""" + from iris import load_cube as iris_loadcube from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD diff --git a/benchmarks/benchmarks/iterate.py b/benchmarks/benchmarks/iterate.py index 9353cf42ee..3716602be1 100644 --- a/benchmarks/benchmarks/iterate.py +++ b/benchmarks/benchmarks/iterate.py @@ -3,6 +3,7 @@ # 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. """Iterate benchmark tests.""" + import numpy as np from iris import coords, cube, iterate diff --git a/benchmarks/benchmarks/plot.py b/benchmarks/benchmarks/plot.py index 9b008ec41c..681d8ef9dd 100644 --- a/benchmarks/benchmarks/plot.py +++ b/benchmarks/benchmarks/plot.py @@ -3,6 +3,7 @@ # 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. """Plot benchmark tests.""" + import matplotlib as mpl import numpy as np diff --git a/benchmarks/benchmarks/save.py b/benchmarks/benchmarks/save.py index 0c5f79947d..f2a2611eae 100644 --- a/benchmarks/benchmarks/save.py +++ b/benchmarks/benchmarks/save.py @@ -11,6 +11,7 @@ run-time that scale with data size. """ + from iris import save from iris.experimental.ugrid import save_mesh diff --git a/benchmarks/benchmarks/sperf/__init__.py b/benchmarks/benchmarks/sperf/__init__.py index 0a87dbb25c..e51bef5ca2 100644 --- a/benchmarks/benchmarks/sperf/__init__.py +++ b/benchmarks/benchmarks/sperf/__init__.py @@ -7,6 +7,7 @@ SPerf = assessing performance against a series of increasingly large LFRic datasets. """ + from iris import load_cube # TODO: remove uses of PARSE_UGRID_ON_LOAD once UGRID parsing is core behaviour. diff --git a/benchmarks/benchmarks/sperf/combine_regions.py b/benchmarks/benchmarks/sperf/combine_regions.py index d5572c58ea..d375f44719 100644 --- a/benchmarks/benchmarks/sperf/combine_regions.py +++ b/benchmarks/benchmarks/sperf/combine_regions.py @@ -3,6 +3,7 @@ # 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. """Region combine benchmarks for the SPerf scheme of the UK Met Office's NG-VAT project.""" + import os.path from dask import array as da diff --git a/benchmarks/benchmarks/sperf/equality.py b/benchmarks/benchmarks/sperf/equality.py index 339687a22c..3f70c6fd7f 100644 --- a/benchmarks/benchmarks/sperf/equality.py +++ b/benchmarks/benchmarks/sperf/equality.py @@ -3,6 +3,7 @@ # 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. """Equality benchmarks for the SPerf scheme of the UK Met Office's NG-VAT project.""" + from .. import on_demand_benchmark from . import FileMixin diff --git a/benchmarks/benchmarks/sperf/load.py b/benchmarks/benchmarks/sperf/load.py index f3c5ef1136..d304a30c82 100644 --- a/benchmarks/benchmarks/sperf/load.py +++ b/benchmarks/benchmarks/sperf/load.py @@ -3,6 +3,7 @@ # 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. """File loading benchmarks for the SPerf scheme of the UK Met Office's NG-VAT project.""" + from .. import on_demand_benchmark from . import FileMixin diff --git a/benchmarks/benchmarks/sperf/save.py b/benchmarks/benchmarks/sperf/save.py index 3fb8133659..8d9a90f7cf 100644 --- a/benchmarks/benchmarks/sperf/save.py +++ b/benchmarks/benchmarks/sperf/save.py @@ -3,6 +3,7 @@ # 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. """File saving benchmarks for the SPerf scheme of the UK Met Office's NG-VAT project.""" + import os.path from iris import save diff --git a/benchmarks/bm_runner.py b/benchmarks/bm_runner.py index f2883f079c..2c18de4a41 100644 --- a/benchmarks/bm_runner.py +++ b/benchmarks/bm_runner.py @@ -67,7 +67,7 @@ def _check_requirements(package: str) -> None: def _prep_data_gen_env() -> None: """Create or access a separate, unchanging environment for generating test data.""" - python_version = "3.11" + python_version = "3.12" data_gen_var = "DATA_GEN_PYTHON" if data_gen_var in environ: echo("Using existing data generation environment.") diff --git a/docs/gallery_code/oceanography/plot_load_nemo.py b/docs/gallery_code/oceanography/plot_load_nemo.py index 36ff363a15..aac89fec0e 100644 --- a/docs/gallery_code/oceanography/plot_load_nemo.py +++ b/docs/gallery_code/oceanography/plot_load_nemo.py @@ -45,11 +45,11 @@ def main(): # Include the point's position in the plot's title lat_point = cube.coord("latitude").points[y_point_index, x_point_index] - lat_string = "{:.3f}\u00B0 {}".format( + lat_string = "{:.3f}\u00b0 {}".format( abs(lat_point), "N" if lat_point > 0.0 else "S" ) lon_point = cube.coord("longitude").points[y_point_index, x_point_index] - lon_string = "{:.3f}\u00B0 {}".format( + lon_string = "{:.3f}\u00b0 {}".format( abs(lon_point), "E" if lon_point > 0.0 else "W" ) plt.title("{} at {} {}".format(cube.long_name.capitalize(), lat_string, lon_string)) diff --git a/docs/src/conf.py b/docs/src/conf.py index 28e12abbeb..3ada7c3510 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -272,6 +272,8 @@ def _dotv(version): "pandas": ("https://pandas.pydata.org/docs/", None), "dask": ("https://docs.dask.org/en/stable/", None), "xarray": ("https://docs.xarray.dev/en/stable/", None), + "geovista": ("https://geovista.readthedocs.io/en/latest/", None), + "pyvista": ("https://docs.pyvista.org/", None), } # The name of the Pygments (syntax highlighting) style to use. @@ -397,16 +399,6 @@ def _dotv(version): html_static_path = ["_static"] html_style = "theme_override.css" -# this allows for using datatables: https://datatables.net/. -# the version can be manually upgraded by changing the urls below. -html_css_files = [ - "https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css", -] - -html_js_files = [ - "https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js", -] - # url link checker. Some links work but report as broken, lets ignore them. # See https://www.sphinx-doc.org/en/1.2/config.html#options-for-the-linkcheck-builder linkcheck_ignore = [ @@ -428,6 +420,7 @@ def _dotv(version): "https://stickler-ci.com/", "https://twitter.com/scitools_iris", "https://stackoverflow.com/questions/tagged/python-iris", + "https://www.flaticon.com/", ] # list of sources to exclude from the build. diff --git a/docs/src/further_topics/missing_data_handling.rst b/docs/src/further_topics/missing_data_handling.rst index 13b00d3424..a461a44456 100644 --- a/docs/src/further_topics/missing_data_handling.rst +++ b/docs/src/further_topics/missing_data_handling.rst @@ -22,6 +22,7 @@ On load, any fill-value or missing data value defined in the loaded dataset should be used as the ``fill_value`` of the NumPy masked array data attribute of the :class:`~iris.cube.Cube`. This will only appear when the cube's data is realised. +.. _missing_data_saving: Saving ------ @@ -37,7 +38,8 @@ For example:: .. note:: Not all savers accept the ``fill_value`` keyword argument. -Iris will check for and issue warnings of fill-value 'collisions'. +Iris will check for and issue warnings of fill-value 'collisions' (exception: +**NetCDF**, see the heading below). This basically means that whenever there are unmasked values that would read back as masked, we issue a warning and suggest a workaround. @@ -51,6 +53,8 @@ This will occur in the following cases: NetCDF ~~~~~~ +:term:`NetCDF Format` + NetCDF is a special case, because all ordinary variable data is "potentially masked", owing to the use of default fill values. The default fill-value used depends on the type of the variable data. @@ -64,6 +68,16 @@ The exceptions to this are: * Small integers create problems by *not* having the exemption applied to byte data. Thus, in principle, ``int32`` data cannot use the full range of 2**16 valid values. +Warnings are not issued for NetCDF fill value collisions. Increasingly large +and complex parallel I/O operations unfortunately made this feature +un-maintainable and it was retired in Iris 3.9 (:pull:`5833`). + +If you need to know about collisions then you can perform your own checks ahead +of saving. Such operations can be run lazily (:term:`Lazy Data`). Here is an +example:: + + >>> default_fill = netCDF4.default_fillvals[my_cube.dtype.str[1:]] + >>> fill_present = (my_cube.lazy_data() == default_fill).any().compute() Merging ------- diff --git a/docs/src/further_topics/ugrid/images/plotting.png b/docs/src/further_topics/ugrid/images/plotting.png new file mode 100644 index 0000000000..6e7d570ba2 Binary files /dev/null and b/docs/src/further_topics/ugrid/images/plotting.png differ diff --git a/docs/src/further_topics/ugrid/images/plotting_basic.png b/docs/src/further_topics/ugrid/images/plotting_basic.png deleted file mode 100644 index ba2b0b3329..0000000000 Binary files a/docs/src/further_topics/ugrid/images/plotting_basic.png and /dev/null differ diff --git a/docs/src/further_topics/ugrid/images/plotting_global.png b/docs/src/further_topics/ugrid/images/plotting_global.png deleted file mode 100644 index 62fb56d974..0000000000 Binary files a/docs/src/further_topics/ugrid/images/plotting_global.png and /dev/null differ diff --git a/docs/src/further_topics/ugrid/operations.rst b/docs/src/further_topics/ugrid/operations.rst index a088b588e1..8c01b8eae5 100644 --- a/docs/src/further_topics/ugrid/operations.rst +++ b/docs/src/further_topics/ugrid/operations.rst @@ -469,14 +469,18 @@ SEM microscopy), so there is a wealth of tooling available, which :ref:`ugrid geovista` harnesses for cartographic plotting. GeoVista's default behaviour is to convert lat-lon information into full XYZ -coordinates so the data is visualised on the surface of a 3D globe. The plots -are interactive by default, so it's easy to explore the data in detail. +coordinates so the data is visualised on the surface of a 3D globe; 2D +projections are also supported. The plots are interactive by default, so it's +easy to explore the data in detail. -2D projections have also been demonstrated in proofs of concept, and will -be added to API in the near future. +Performing GeoVista operations on your :class:`~iris.cube.Cube` is made +easy via this convenience: +:func:`iris.experimental.geovista.cube_to_polydata`. -This first example uses GeoVista to plot the ``face_cube`` that we created -earlier: +Below is an example of using GeoVista to plot a low-res +sample :attr:`~iris.cube.Cube.mesh` based :class:`~iris.cube.Cube`. For +some truly spectacular visualisations of high-res data please see the +GeoVista :external+geovista:doc:`generated/gallery/index`. .. dropdown:: Code :icon: code @@ -484,130 +488,48 @@ earlier: .. code-block:: python >>> from geovista import GeoPlotter, Transform - >>> from geovista.common import to_xyz + >>> from geovista.common import to_cartesian + >>> import matplotlib.pyplot as plt + >>> from iris import load_cube, sample_data_path + >>> from iris.experimental.geovista import cube_to_polydata + >>> from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD - # We'll re-use this to plot some real global data later. - >>> def cube_faces_to_polydata(cube): - ... lons, lats = cube.mesh.node_coords - ... face_node = cube.mesh.face_node_connectivity - ... indices = face_node.indices_by_location() - ... - ... mesh = Transform.from_unstructured( - ... lons.points, - ... lats.points, - ... indices, - ... data=cube.data, - ... name=f"{cube.name()} / {cube.units}", - ... start_index=face_node.start_index, - ... ) - ... return mesh - - >>> print(face_cube) - face_data / (K) (-- : 2; height: 3) - Dimension coordinates: - height - x + >>> with PARSE_UGRID_ON_LOAD.context(): + ... sample_mesh_cube = load_cube(sample_data_path("mesh_C4_synthetic_float.nc")) + >>> print(sample_mesh_cube) + synthetic / (1) (-- : 96) Mesh coordinates: - latitude x - - longitude x - + latitude x + longitude x + Mesh: + name Topology data of 2D unstructured mesh + location face Attributes: - Conventions 'CF-1.7' + 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 # Convert our mesh+data to a PolyData object. - # Just plotting a single height level. - >>> face_polydata = cube_faces_to_polydata(face_cube[:, 0]) + >>> face_polydata = cube_to_polydata(sample_mesh_cube) >>> print(face_polydata) - PolyData (0x7ff4861ff4c0) - N Cells: 2 - N Points: 5 - X Bounds: 9.903e-01, 1.000e+00 - Y Bounds: 0.000e+00, 1.392e-01 - Z Bounds: 6.123e-17, 5.234e-02 - N Arrays: 2 + PolyData (... + N Cells: 96 + N Points: 98 + N Strips: 0 + X Bounds: -1.000e+00, 1.000e+00 + Y Bounds: -1.000e+00, 1.000e+00 + Z Bounds: -1.000e+00, 1.000e+00 + N Arrays: 4 # Create the GeoVista plotter and add our mesh+data to it. - >>> my_plotter = GeoPlotter() - >>> my_plotter.add_coastlines(color="black") - >>> my_plotter.add_base_layer(color="grey") - >>> my_plotter.add_mesh(face_polydata) - - # Centre the camera on the data. - >>> camera_region = to_xyz( - ... face_cube.coord("longitude").points, - ... face_cube.coord("latitude").points, - ... radius=3, - ... ) - >>> camera_pos = camera_region.mean(axis=0) - >>> my_plotter.camera.position = camera_pos - - >>> my_plotter.show() - - .. image:: images/plotting_basic.png - :alt: A GeoVista plot of the basic example Mesh. - - This artificial data makes West Africa rather chilly! - -Here's another example using a global cubed-sphere data set: - -.. dropdown:: Code - :icon: code - - .. code-block:: python - - >>> from iris import load_cube - >>> from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD - - # Demonstrating with a global data set. - # You could also download this file from github.com/SciTools/iris-test-data. - >>> from iris.tests import get_data_path - >>> file_path = get_data_path( - ... [ - ... "NetCDF", - ... "unstructured_grid", - ... "lfric_surface_mean.nc", - ... ] - ... ) - >>> with PARSE_UGRID_ON_LOAD.context(): - ... global_cube = load_cube(file_path, "tstar_sea") - >>> print(global_cube) - sea_surface_temperature / (K) (-- : 1; -- : 13824) - Mesh coordinates: - latitude - x - longitude - x - Auxiliary coordinates: - time x - - Cell methods: - 0 time: mean (interval: 300 s) - 1 time_counter: mean - Attributes: - Conventions UGRID - description Created by xios - interval_operation 300 s - interval_write 1 d - name lfric_surface - online_operation average - timeStamp 2020-Feb-07 16:23:14 GMT - title Created by xios - uuid 489bcef5-3d1c-4529-be42-4ab5f8c8497b - - >>> global_polydata = cube_faces_to_polydata(global_cube) - >>> print(global_polydata) - PolyData (0x7f761b536160) - N Cells: 13824 - N Points: 13826 - X Bounds: -1.000e+00, 1.000e+00 - Y Bounds: -1.000e+00, 1.000e+00 - Z Bounds: -1.000e+00, 1.000e+00 - N Arrays: 2 - >>> my_plotter = GeoPlotter() >>> my_plotter.add_coastlines() - >>> my_plotter.add_mesh(global_polydata, show_edges=True) - + >>> my_plotter.add_mesh(face_polydata) >>> my_plotter.show() - .. image:: images/plotting_global.png - :alt: A GeoVista plot of a global sea surface temperature Mesh. + .. image:: images/plotting.png + :alt: A GeoVista plot of low-res sample data. Region Extraction ----------------- @@ -656,118 +578,59 @@ position of the data points before they can be analysed as inside/outside the selected region. The recommended way to do this is using tools provided by :ref:`ugrid geovista`, which is optimised for performant mesh analysis. -This approach centres around using :meth:`geovista.geodesic.BBox.enclosed` to -get the subset of the original mesh that is inside the -:class:`~geovista.geodesic.BBox`. This subset :class:`pyvista.PolyData` object -includes the original indices of each datapoint - the ``vtkOriginalCellIds`` -array, which can be used to index the original :class:`~iris.cube.Cube`. Since -we **know** that this subset :class:`~iris.cube.Cube` represents a regional -mesh, we then reconstruct a :class:`~iris.experimental.ugrid.Mesh` from the -:class:`~iris.cube.Cube`\'s :attr:`~iris.cube.Cube.aux_coords` using -:meth:`iris.experimental.ugrid.Mesh.from_coords`: +Performing GeoVista operations on your :class:`~iris.cube.Cube` is made +easy via this convenience: +:func:`iris.experimental.geovista.cube_to_polydata`. + +An Iris convenience for regional extraction is also provided: +:func:`iris.experimental.geovista.extract_unstructured_region`; demonstrated +below: -.. - Not using doctest here as want to keep GeoVista as optional dependency. .. dropdown:: Code :icon: code - .. code-block:: python + .. doctest:: ugrid_operations - >>> from geovista import Transform >>> from geovista.geodesic import BBox - >>> from iris import load_cube - >>> from iris.experimental.ugrid import Mesh, PARSE_UGRID_ON_LOAD - - # Need a larger dataset to demonstrate this operation. - # You could also download this file from github.com/SciTools/iris-test-data. - >>> from iris.tests import get_data_path - >>> file_path = get_data_path( - ... [ - ... "NetCDF", - ... "unstructured_grid", - ... "lfric_ngvat_2D_72t_face_half_levels_main_conv_rain.nc", - ... ] - ... ) + >>> from iris import load_cube, sample_data_path + >>> from iris.experimental.geovista import cube_to_polydata, extract_unstructured_region + >>> from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD >>> with PARSE_UGRID_ON_LOAD.context(): - ... global_cube = load_cube(file_path, "conv_rain") - >>> print(global_cube) - surface_convective_rainfall_rate / (kg m-2 s-1) (-- : 72; -- : 864) + ... sample_mesh_cube = load_cube(sample_data_path("mesh_C4_synthetic_float.nc")) + >>> print(sample_mesh_cube) + synthetic / (1) (-- : 96) Mesh coordinates: - latitude - x - longitude - x - Auxiliary coordinates: - time x - - Cell methods: - 0 time: point + latitude x + longitude x + Mesh: + name Topology data of 2D unstructured mesh + location face Attributes: - Conventions UGRID - description Created by xios - interval_operation 300 s - interval_write 300 s - name lfric_ngvat_2D_72t_face_half_levels_main_conv_rain - online_operation instant - timeStamp 2020-Oct-18 21:18:35 GMT - title Created by xios - uuid b3dc0fb4-9828-4663-a5ac-2a5763280159 - - # Convert the Mesh to a GeoVista PolyData object. - >>> lons, lats = global_cube.mesh.node_coords - >>> face_node = global_cube.mesh.face_node_connectivity - >>> indices = face_node.indices_by_location() - >>> global_polydata = Transform.from_unstructured( - ... lons.points, lats.points, indices, start_index=face_node.start_index + 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 + + >>> regional_cube = extract_unstructured_region( + ... cube=sample_mesh_cube, + ... polydata=cube_to_polydata(sample_mesh_cube), + ... region=BBox(lons=[0, 70, 70, 0], lats=[-25, -25, 45, 45]), + ... preference="center", ... ) - - # Define a region of 4 corners connected by great circles. - # Specialised sub-classes of BBox are also available e.g. panel/wedge. - >>> region = BBox(lons=[0, 70, 70, 0], lats=[-25, -25, 45, 45]) - # 'Apply' the region to the PolyData object. - >>> region_polydata = region.enclosed(global_polydata, preference="center") - # Get the remaining face indices, to use for indexing the Cube. - >>> indices = region_polydata["vtkOriginalCellIds"] - - >>> print(type(indices)) - - # 101 is smaller than the original 864. - >>> print(len(indices)) - 101 - >>> print(indices[:10]) - [ 6 7 8 9 10 11 18 19 20 21] - - # Use the face indices to subset the global cube. - >>> region_cube = global_cube[:, indices] - - # In this case we **know** the indices correspond to a contiguous - # region, so we will convert the sub-setted Cube back into a - # Cube-with-Mesh. - >>> new_mesh = Mesh.from_coords(*region_cube.coords(dimensions=1)) - >>> new_mesh_coords = new_mesh.to_MeshCoords(global_cube.location) - >>> for coord in new_mesh_coords: - ... region_cube.remove_coord(coord.name()) - ... region_cube.add_aux_coord(coord, 1) - - # A Mesh-Cube with a subset (101) of the original 864 faces. - >>> print(region_cube) - surface_convective_rainfall_rate / (kg m-2 s-1) (-- : 72; -- : 101) + >>> print(regional_cube) + synthetic / (1) (-- : 11) Mesh coordinates: - latitude - x - longitude - x - Auxiliary coordinates: - time x - - Cell methods: - 0 time: point + latitude x + longitude x + Mesh: + name unknown + location face Attributes: - Conventions UGRID - description Created by xios - interval_operation 300 s - interval_write 300 s - name lfric_ngvat_2D_72t_face_half_levels_main_conv_rain - online_operation instant - timeStamp 2020-Oct-18 21:18:35 GMT - title Created by xios - uuid b3dc0fb4-9828-4663-a5ac-2a5763280159 + 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 + Regridding ---------- @@ -1029,4 +892,4 @@ data content. .. |new| replace:: ✨ New .. |unchanged| replace:: ♻️ Unchanged .. |different| replace:: ⚠️ Different -.. |pending| replace:: 🚧 Support Pending \ No newline at end of file +.. |pending| replace:: 🚧 Support Pending diff --git a/docs/src/userguide/plotting_examples/cube_contour.py b/docs/src/userguide/plotting_examples/cube_contour.py index 0d8c1e02aa..e338d395ff 100644 --- a/docs/src/userguide/plotting_examples/cube_contour.py +++ b/docs/src/userguide/plotting_examples/cube_contour.py @@ -3,6 +3,7 @@ Can use iris.plot.contour() or iris.quicplot.contour(). """ + import matplotlib.pyplot as plt import iris diff --git a/docs/src/userguide/plotting_examples/cube_contourf.py b/docs/src/userguide/plotting_examples/cube_contourf.py index 531dd45d25..b76645b380 100644 --- a/docs/src/userguide/plotting_examples/cube_contourf.py +++ b/docs/src/userguide/plotting_examples/cube_contourf.py @@ -3,6 +3,7 @@ Can use iris.plot.contour() or iris.quickplot.contour(). """ + import matplotlib.pyplot as plt import iris diff --git a/docs/src/userguide/plotting_examples/masking_brazil_plot.py b/docs/src/userguide/plotting_examples/masking_brazil_plot.py index 3dc521d451..d1a75a700f 100644 --- a/docs/src/userguide/plotting_examples/masking_brazil_plot.py +++ b/docs/src/userguide/plotting_examples/masking_brazil_plot.py @@ -1,4 +1,5 @@ """Global cube masked to Brazil and plotted with quickplot.""" + import cartopy.io.shapereader as shpreader import matplotlib.pyplot as plt diff --git a/docs/src/voted_issues.rst b/docs/src/voted_issues.rst index 33d1982a7b..116c997f33 100644 --- a/docs/src/voted_issues.rst +++ b/docs/src/voted_issues.rst @@ -20,6 +20,12 @@ the below table. .. raw:: html + + + + + + diff --git a/docs/src/whatsnew/3.7.rst b/docs/src/whatsnew/3.7.rst index bfc224bf04..928b83effc 100644 --- a/docs/src/whatsnew/3.7.rst +++ b/docs/src/whatsnew/3.7.rst @@ -36,6 +36,21 @@ This document explains the changes made to Iris for this release any issues or feature requests for improving Iris. Enjoy! +v3.7.1 (04 Mar 2024) +==================== + +.. dropdown:: v3.7.1 Patches + :color: primary + :icon: alert + :animate: fade-in + + The patches in this release of Iris include: + + #. `@stephenworsley`_ fixed a potential memory leak for Iris uses of + :func:`dask.array.map_blocks`; known specifically to be a problem in the + :class:`iris.analysis.AreaWeighted` regridder. (:pull:`5767`) + + 📢 Announcements ================ diff --git a/docs/src/whatsnew/3.8.rst b/docs/src/whatsnew/3.8.rst index 5687b25cc7..9fa87a9337 100644 --- a/docs/src/whatsnew/3.8.rst +++ b/docs/src/whatsnew/3.8.rst @@ -42,6 +42,22 @@ This document explains the changes made to Iris for this release any issues or feature requests for improving Iris. Enjoy! +v3.8.1 (04 Mar 2024) +==================== + +.. dropdown:: v3.8.1 Patches + :color: primary + :icon: alert + :animate: fade-in + :open: + + The patches in this release of Iris include: + + #. `@stephenworsley`_ fixed a potential memory leak for Iris uses of + :func:`dask.array.map_blocks`; known specifically to be a problem in the + :class:`iris.analysis.AreaWeighted` regridder. (:pull:`5767`) + + 📢 Announcements ================ diff --git a/docs/src/whatsnew/3.9.rst b/docs/src/whatsnew/3.9.rst new file mode 100644 index 0000000000..9f5ad90fef --- /dev/null +++ b/docs/src/whatsnew/3.9.rst @@ -0,0 +1,130 @@ +.. include:: ../common_links.inc + +v3.9 (03 Apr 2024) [release candidate] +************************************** + +This document explains the changes made to Iris for this release +(:doc:`View all changes `.) + + +.. dropdown:: v3.9 Release Highlights + :color: primary + :icon: info + :animate: fade-in + :open: + + This is a small release to make two important changes available as soon as + possible: + + * The :mod:`iris.experimental.geovista` module. + * Removal of fill value collision warnings in NetCDF saving, which + significantly improves Iris' performance when parallel processing. + + See below for more detail on these changes. + + And finally, get in touch with us on :issue:`GitHub` if you have + any issues or feature requests for improving Iris. Enjoy! + + +📢 Announcements +================ + +#. ⏱️ Performance benchmarking has shown that loading + :term:`Fields File (FF) Format` with a large number of fields via + :func:`iris.fileformats.um.structured_um_loading` has become ~30% slower + since `Dask version 2024.2.1`_. + + +✨ Features +=========== + +#. `@HGWright`_ and `@trexfeathers`_ added the + :mod:`iris.experimental.geovista` module, providing conveniences for using + :ref:`ugrid geovista` with Iris. To see some of this in action, check out + :ref:`ugrid operations`. Note that GeoVista is an **optional** dependency + so you will need to explicitly install it into your environment. + (:pull:`5740`) + + +🐛 Bugs Fixed +============= + +#. `@pp-mo`_ prevented the CHUNK_CONTROL feature from hitting an error when loading + from a NetCDF v3 file. (:pull:`5897`) + + +💣 Incompatible Changes +======================= + +#. Warnings are no longer produced for fill value 'collisions' in NetCDF + saving. :ref:`Read more `. (:pull:`5833`) + + +🚀 Performance Enhancements +=========================== + +#. `@bouweandela`_ made :func:`iris.util.rolling_window` work with lazy arrays. + (:pull:`5775`) + +#. `@stephenworsley`_ fixed a potential memory leak for Iris uses of + :func:`dask.array.map_blocks`; known specifically to be a problem in the + :class:`iris.analysis.AreaWeighted` regridder. (:pull:`5767`) + +#. `@fnattino`_ and `@pp-mo`_ prevented cube printout from showing the values of lazy + scalar coordinates, since this can involve a lengthy computation that must be + re-computed each time. (:pull:`5896`) + + +🔥 Deprecations +=============== + +#. N/A + + +🔗 Dependencies +=============== + +#. `@bjlittle`_ dropped support for ``py39`` and adopted support for ``py312`` as per + the `NEP-29`_ schedule. (:pull:`5894`) + + +📚 Documentation +================ + +#. N/A + + +💼 Internal +=========== + +#. `@trexfeathers`_ setup automatic benchmarking on pull requests that modify + files likely to affect performance or performance testing. Such pull + requests are also labelled using the `Pull Request Labeler Github action`_ + to increase visibility. (:pull:`5763`, :pull:`5776`) + +#. `@tkknight`_ updated codebase to comply with a new enforced rule `NPY002`_ for + `ruff`_. (:pull:`5786`) + +#. `@tkknight`_ enabled `numpydoc validation`_ via the pre-commit hook. The docstrings + have been updated to comply and some rules have been ignored for now. + (:pull:`5762`) + +#. `@jfrost-mo`_ enabled colour output for pytest on GitHub Actions. (:pull:`5895`) + + +.. comment + Whatsnew author names (@github name) in alphabetical order. Note that, + core dev names are automatically included by the common_links.inc: + +.. _@jfrost-mo: https://github.com/jfrost-mo +.. _@fnattino: https://github.com/fnattino + + +.. comment + Whatsnew resources in alphabetical order: + +.. _Pull Request Labeler GitHub action: https://github.com/actions/labeler +.. _NPY002: https://docs.astral.sh/ruff/rules/numpy-legacy-random/ +.. _numpydoc validation: https://numpydoc.readthedocs.io/en/latest/validation.html# +.. _Dask version 2024.2.1: https://docs.dask.org/en/stable/changelog.html#v2024-2-1 +.. _NEP-29: https://numpy.org/neps/nep-0029-deprecation_policy.html#drop-schedule diff --git a/docs/src/whatsnew/index.rst b/docs/src/whatsnew/index.rst index 23cd022f52..012e0b4498 100644 --- a/docs/src/whatsnew/index.rst +++ b/docs/src/whatsnew/index.rst @@ -1,3 +1,4 @@ + .. include:: ../common_links.inc .. _iris_whatsnew: @@ -12,6 +13,7 @@ What's New in Iris :hidden: latest.rst + 3.9.rst 3.8.rst 3.7.rst 3.6.rst diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 9150568316..fc189a4495 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -42,18 +42,22 @@ This document explains the changes made to Iris for this release 💣 Incompatible Changes ======================= -#. N/A +#. `@rcomer`_ removed the *target* parameter from + :func:`~iris.fileformats.pp.as_fields` and + :func:`~iris.fileformats.pp.save_pairs_from_cube` because it had no effect. + (:pull:`5783`) 🚀 Performance Enhancements =========================== -#. `@bouweandela`_ made :func:`iris.util.rolling_window` work with lazy arrays. - (:pull:`5775`) +#. N/A + +#. `@bouweandela`_ added the option to specify the Dask chunks of the target + array in :func:`iris.util.broadcast_to_shape`. (:pull:`5620`) -#. `@stephenworsley`_ fixed a potential memory leak for Iris uses of - :func:`dask.array.map_blocks`; known specifically to be a problem in the - :class:`iris.analysis.AreaWeighted` regridder. (:pull:`5767`) +#. `@schlunma`_ allowed :func:`iris.analysis.cartography.area_weights` to + return dask arrays with arbitrary chunks. (:pull:`5658`) 🔥 Deprecations @@ -65,7 +69,9 @@ This document explains the changes made to Iris for this release 🔗 Dependencies =============== -#. N/A +#. `@tkknight`_ removed the pin for ``sphinx <=5.3``, so the latest should + now be used, currently being v7.2.6. + (:pull:`5901`) 📚 Documentation @@ -77,17 +83,8 @@ This document explains the changes made to Iris for this release 💼 Internal =========== -#. `@trexfeathers`_ setup automatic benchmarking on pull requests that modify - files likely to affect performance or performance testing. Such pull - requests are also labelled using the `Pull Request Labeler Github action`_ - to increase visibility. (:pull:`5763`, :pull:`5776`) - -#. `@tkknight`_ updated codebase to comply with a new enforced rule `NPY002`_ for - `ruff`_. (:pull:`5786`) +#. N/A -#. `@tkknight`_ enabled `numpydoc validation`_ via the pre-commit hook. The docstrings - have been updated to comply and some rules have been ignored for now. - (:pull:`5762`) .. comment Whatsnew author names (@github name) in alphabetical order. Note that, @@ -98,7 +95,3 @@ This document explains the changes made to Iris for this release .. comment Whatsnew resources in alphabetical order: - -.. _Pull Request Labeler GitHub action: https://github.com/actions/labeler -.. _NPY002: https://docs.astral.sh/ruff/rules/numpy-legacy-random/ -.. _numpydoc validation: https://numpydoc.readthedocs.io/en/latest/validation.html# \ No newline at end of file diff --git a/docs/src/whatsnew/latest.rst.template b/docs/src/whatsnew/latest.rst.template index 966a91e976..80bf48dadd 100644 --- a/docs/src/whatsnew/latest.rst.template +++ b/docs/src/whatsnew/latest.rst.template @@ -104,4 +104,4 @@ NOTE: section ABOVE is a template for bugfix patches .. comment - Whatsnew resources in alphabetical order: + Whatsnew resources in alphabetical order: \ No newline at end of file diff --git a/lib/iris/_representation/cube_printout.py b/lib/iris/_representation/cube_printout.py index 3c418bde64..1e648b25f6 100644 --- a/lib/iris/_representation/cube_printout.py +++ b/lib/iris/_representation/cube_printout.py @@ -3,6 +3,7 @@ # 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. """Provides text printouts of Iris cubes.""" + from copy import deepcopy from iris._representation.cube_summary import CubeSummary diff --git a/lib/iris/_representation/cube_summary.py b/lib/iris/_representation/cube_summary.py index 64a6aadbf3..a28bfc549a 100644 --- a/lib/iris/_representation/cube_summary.py +++ b/lib/iris/_representation/cube_summary.py @@ -3,8 +3,12 @@ # 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. """Provides objects describing cube summaries.""" + import re +import numpy as np + +import iris._lazy_data as _lazy from iris.common.metadata import hexdigest import iris.util @@ -148,25 +152,61 @@ def __init__(self, cube, coord): self.unit = "" else: self.unit = " {!s}".format(coord.units) - coord_cell = coord.cell(0) - if isinstance(coord_cell.point, str): + + # Don't print values of lazy coords, as computing them could cost a lot. + safe_to_print = not _lazy.is_lazy_data(coord.core_points()) + if not safe_to_print: + # However there is a special case: If it is a *factory* coord, then those + # are generally lazy. If all the dependencies are real, then it is useful + # (and safe) to compute + print the value. + for factory in cube._aux_factories: + # Note : a factory doesn't have a ".metadata" which can be matched + # against a coord. For now, just assume that it has a 'standard_name' + # property (also not actually guaranteed), and require them to match. + if coord.standard_name == factory.standard_name: + all_deps_real = True + for dependency_coord in factory.dependencies.values(): + if ( + dependency_coord.has_lazy_points() + or dependency_coord.has_lazy_bounds() + ): + all_deps_real = False + + if all_deps_real: + safe_to_print = True + + if safe_to_print: + coord_cell = coord.cell(0) + else: + coord_cell = None + + if coord.dtype.type is np.str_: self.string_type = True - # 'lines' is value split on '\n', and _each one_ length-clipped. - self.lines = [ - iris.util.clip_string(str(item)) - for item in coord_cell.point.split("\n") - ] + if coord_cell is not None: + # 'lines' is value split on '\n', and _each one_ length-clipped. + self.lines = [ + iris.util.clip_string(str(item)) + for item in coord_cell.point.split("\n") + ] + # 'content' contains a one-line printable version of the string, + content = string_repr(coord_cell.point) + content = iris.util.clip_string(content) + else: + content = "" + self.lines = [content] self.point = None self.bound = None - # 'content' contains a one-line printable version of the string, - content = string_repr(coord_cell.point) - content = iris.util.clip_string(content) self.content = content else: self.string_type = False self.lines = None - self.point = "{!s}".format(coord_cell.point) - coord_cell_cbound = coord_cell.bound + coord_cell_cbound = None + if coord_cell is not None: + self.point = "{!s}".format(coord_cell.point) + coord_cell_cbound = coord_cell.bound + else: + self.point = "" + if coord_cell_cbound is not None: self.bound = "({})".format( ", ".join(str(val) for val in coord_cell_cbound) @@ -174,6 +214,9 @@ def __init__(self, cube, coord): self.content = "{}{}, bound={}{}".format( self.point, self.unit, self.bound, self.unit ) + elif coord.has_bounds(): + self.bound = "+bound" + self.content = "{}{}".format(self.point, self.bound) else: self.bound = None self.content = "{}{}".format(self.point, self.unit) diff --git a/lib/iris/analysis/cartography.py b/lib/iris/analysis/cartography.py index 854347839d..2e7c3a3677 100644 --- a/lib/iris/analysis/cartography.py +++ b/lib/iris/analysis/cartography.py @@ -376,7 +376,7 @@ def _quadrant_area(radian_lat_bounds, radian_lon_bounds, radius_of_earth): return np.abs(areas) -def area_weights(cube, normalize=False): +def area_weights(cube, normalize=False, compute=True, chunks=None): r"""Return an array of area weights, with the same dimensions as the cube. This is a 2D lat/lon area weights array, repeated over the non lat/lon @@ -401,6 +401,13 @@ def area_weights(cube, normalize=False): normalize : bool, default=False If False, weights are grid cell areas. If True, weights are grid cell areas divided by the total grid area. + compute : bool, default=True + If False, return a lazy dask array. If True, return a numpy array. + chunks : tuple, optional + If compute is False and a value is provided, then the result will use + these chunks instead of the same chunks as the cube data. The values + provided here will only be used along dimensions that are not latitude + or longitude. Returns ------- @@ -476,7 +483,13 @@ def area_weights(cube, normalize=False): # Create 2D weights from bounds. # Use the geographical area as the weight for each cell - ll_weights = _quadrant_area(lat.bounds, lon.bounds, radius_of_earth) + if compute: + lat_bounds = lat.bounds + lon_bounds = lon.bounds + else: + lat_bounds = lat.lazy_bounds() + lon_bounds = lon.lazy_bounds() + ll_weights = _quadrant_area(lat_bounds, lon_bounds, radius_of_earth) # Normalize the weights if necessary. if normalize: @@ -491,7 +504,9 @@ def area_weights(cube, normalize=False): if dim is not None: wshape.append(ll_weights.shape[idim]) ll_weights = ll_weights.reshape(wshape) - broad_weights = iris.util.broadcast_to_shape(ll_weights, cube.shape, broadcast_dims) + broad_weights = iris.util.broadcast_to_shape( + ll_weights, cube.shape, broadcast_dims, chunks=chunks + ) return broad_weights diff --git a/lib/iris/common/_split_attribute_dicts.py b/lib/iris/common/_split_attribute_dicts.py index 17b3014fb1..3e9c74cea9 100644 --- a/lib/iris/common/_split_attribute_dicts.py +++ b/lib/iris/common/_split_attribute_dicts.py @@ -15,6 +15,7 @@ So, we simply treat "global" and "local" attributes of the same name as entirely independent. Which happily is also the easiest to code, and to explain. """ + from collections.abc import Mapping, Sequence from functools import wraps diff --git a/lib/iris/common/metadata.py b/lib/iris/common/metadata.py index 3a5f4deede..9b0edf6532 100644 --- a/lib/iris/common/metadata.py +++ b/lib/iris/common/metadata.py @@ -4,7 +4,6 @@ # See LICENSE in the root of the repository for full licensing details. """Provides the infrastructure to support the common metadata API.""" - from abc import ABCMeta from collections import namedtuple from collections.abc import Iterable, Mapping diff --git a/lib/iris/experimental/geovista.py b/lib/iris/experimental/geovista.py new file mode 100644 index 0000000000..26bfa2e703 --- /dev/null +++ b/lib/iris/experimental/geovista.py @@ -0,0 +1,339 @@ +# 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. +"""Experimental module for using some GeoVista operations with Iris cubes.""" + +from geovista import Transform +from geovista.common import VTK_CELL_IDS, VTK_POINT_IDS + +from iris.exceptions import CoordinateNotFoundError +from iris.experimental.ugrid import Mesh + + +def _get_coord(cube, axis): + """Get the axis coordinates from the cube.""" + try: + coord = cube.coord(axis=axis, dim_coords=True) + except CoordinateNotFoundError: + coord = cube.coord(axis=axis) + return coord + + +def cube_to_polydata(cube, **kwargs): + r"""Create a :class:`pyvista.PolyData` object from a :class:`~iris.cube.Cube`. + + The resulting :class:`~pyvista.PolyData` object can be plotted using + a :class:`geovista.geoplotter.GeoPlotter`. + + Uses :class:`geovista.bridge.Transform` to parse the cube's information - one + of: :meth:`~geovista.bridge.Transform.from_1d` / + :meth:`~geovista.bridge.Transform.from_2d` / + :meth:`~geovista.bridge.Transform.from_unstructured`. + + Parameters + ---------- + cube : :class:`~iris.cube.Cube` + The Cube containing the spatial information and data for creating the + class:`~pyvista.PolyData`. + + **kwargs : dict, optional + Additional keyword arguments to be passed to the relevant + :class:`~geovista.bridge.Transform` method (e.g ``zlevel``). + + Returns + ------- + :class:`~pyvista.PolyData` + The PolyData object representing the cube's spatial information and data. + + Raises + ------ + NotImplementedError + If a :class:`~iris.cube.Cube` with too many dimensions is passed. Only + the horizontal data can be represented, meaning a 2D Cube, or 1D Cube + if the horizontal space is described by + :class:`~iris.experimental.ugrid.MeshCoord`\ s. + + Examples + -------- + .. testsetup:: + + from iris import load_cube, sample_data_path + from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD + + cube = load_cube(sample_data_path("air_temp.pp")) + cube_w_time = load_cube(sample_data_path("A1B_north_america.nc")) + with PARSE_UGRID_ON_LOAD.context(): + cube_mesh = load_cube(sample_data_path("mesh_C4_synthetic_float.nc")) + + >>> from iris.experimental.geovista import cube_to_polydata + + Converting a standard 2-dimensional :class:`~iris.cube.Cube` with + 1-dimensional coordinates: + + >>> print(cube.summary(shorten=True)) + air_temperature / (K) (latitude: 73; longitude: 96) + >>> print(cube_to_polydata(cube)) + PolyData (... + N Cells: 7008 + N Points: 7178 + N Strips: 0 + X Bounds: -9.992e-01, 9.992e-01 + Y Bounds: -9.992e-01, 9.992e-01 + Z Bounds: -1.000e+00, 1.000e+00 + N Arrays: 4 + + Configure the conversion by passing additional keyword arguments: + + >>> print(cube_to_polydata(cube, radius=2)) + PolyData (... + N Cells: 7008 + N Points: 7178 + N Strips: 0 + X Bounds: -1.998e+00, 1.998e+00 + Y Bounds: -1.998e+00, 1.998e+00 + Z Bounds: -2.000e+00, 2.000e+00 + N Arrays: 4 + + Converting a :class:`~iris.cube.Cube` that has a + :attr:`~iris.cube.Cube.mesh` describing its horizontal space: + + >>> print(cube_mesh.summary(shorten=True)) + synthetic / (1) (-- : 96) + >>> print(cube_to_polydata(cube_mesh)) + PolyData (... + N Cells: 96 + N Points: 98 + N Strips: 0 + X Bounds: -1.000e+00, 1.000e+00 + Y Bounds: -1.000e+00, 1.000e+00 + Z Bounds: -1.000e+00, 1.000e+00 + N Arrays: 4 + + Remember to reduce the dimensionality of your :class:`~iris.cube.Cube` to + just be the horizontal space: + + >>> print(cube_w_time.summary(shorten=True)) + air_temperature / (K) (time: 240; latitude: 37; longitude: 49) + >>> print(cube_to_polydata(cube_w_time[0, :, :])) + PolyData (... + N Cells: 1813 + N Points: 1900 + N Strips: 0 + X Bounds: -6.961e-01, 6.961e-01 + Y Bounds: -9.686e-01, -3.411e-01 + Z Bounds: 2.483e-01, 8.714e-01 + N Arrays: 4 + + """ + if cube.mesh: + if cube.ndim != 1: + raise NotImplementedError("Cubes with a mesh must be one dimensional") + lons, lats = cube.mesh.node_coords + face_node = cube.mesh.face_node_connectivity + indices = face_node.indices_by_location() + + polydata = Transform.from_unstructured( + xs=lons.points, + ys=lats.points, + connectivity=indices, + data=cube.data, + name=f"{cube.name()} / ({cube.units})", + start_index=face_node.start_index, + **kwargs, + ) + # TODO: Add support for point clouds + elif cube.ndim == 2: + x_coord = _get_coord(cube, "X") + y_coord = _get_coord(cube, "Y") + transform_kwargs = dict( + xs=x_coord.contiguous_bounds(), + ys=y_coord.contiguous_bounds(), + data=cube.data, + name=f"{cube.name()} / ({cube.units})", + **kwargs, + ) + coord_system = cube.coord_system() + if coord_system: + transform_kwargs["crs"] = coord_system.as_cartopy_crs().proj4_init + + if x_coord.ndim == 2 and y_coord.ndim == 2: + polydata = Transform.from_2d(**transform_kwargs) + + elif x_coord.ndim == 1 and y_coord.ndim == 1: + polydata = Transform.from_1d(**transform_kwargs) + + else: + raise NotImplementedError("Only 1D and 2D coordinates are supported") + else: + raise NotImplementedError("Cube must have a mesh or have 2 dimensions") + + return polydata + + +def extract_unstructured_region(cube, polydata, region, **kwargs): + """Index a :class:`~iris.cube.Cube` with a :attr:`~iris.cube.Cube.mesh` to a specific region. + + Uses :meth:`geovista.geodesic.BBox.enclosed` to identify the `cube` indices + that are within the specified region (`region` being a + :class:`~geovista.geodesic.BBox` class). + + Parameters + ---------- + cube : :class:`~iris.cube.Cube` + The cube to be indexed (must have a :attr:`~iris.cube.Cube.mesh`). + polydata : :class:`pyvista.PolyData` + A :class:`~pyvista.PolyData` representing the same horizontal space as + `cube`. The region extraction is first applied to `polydata`, with the + resulting indices then applied to `cube`. In many cases `polydata` can + be created by applying :func:`cube_to_polydata` to `cube`. + region : :class:`geovista.geodesic.BBox` + A :class:`~geovista.geodesic.BBox` representing the region to be + extracted. + **kwargs : dict, optional + Additional keyword arguments to be passed to the + :meth:`geovista.geodesic.BBox.enclosed` method (e.g ``preference``). + + Returns + ------- + :class:`~iris.cube.Cube` + The region extracted cube. + + Raises + ------ + ValueError + If `polydata` and the :attr:`~iris.cube.Cube.mesh` on `cube` do not + have the same shape. + + Examples + -------- + .. testsetup:: + + from iris import load_cube, sample_data_path + from iris.coords import AuxCoord + from iris.cube import CubeList + from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD + + file_path = sample_data_path("mesh_C4_synthetic_float.nc") + with PARSE_UGRID_ON_LOAD.context(): + cube_w_mesh = load_cube(file_path) + + level_cubes = CubeList() + for height_level in range(72): + height_coord = AuxCoord([height_level], standard_name="height") + level_cube = cube_w_mesh.copy() + level_cube.add_aux_coord(height_coord) + level_cubes.append(level_cube) + + cube_w_mesh = level_cubes.merge_cube() + other_cube_w_mesh = cube_w_mesh[:20, :] + + The parameters of :func:`extract_unstructured_region` have been designed with + flexibility and reuse in mind. This is demonstrated below. + + >>> from geovista import BBox + >>> from iris.experimental.geovista import cube_to_polydata, extract_unstructured_region + >>> print(cube_w_mesh.shape) + (72, 96) + >>> # The mesh dimension represents the horizontal space of the cube. + >>> print(cube_w_mesh.shape[cube_w_mesh.mesh_dim()]) + 96 + >>> cube_polydata = cube_to_polydata(cube_w_mesh[0, :]) + >>> extracted_cube = extract_unstructured_region( + ... cube=cube_w_mesh, + ... polydata=cube_polydata, + ... region=BBox(lons=[0, 70, 70, 0], lats=[-25, -25, 45, 45]), + ... ) + >>> print(extracted_cube.shape) + (72, 11) + + Now reuse the same `cube` and `polydata` to extract a different region: + + >>> new_region = BBox(lons=[0, 35, 35, 0], lats=[-25, -25, 45, 45]) + >>> extracted_cube = extract_unstructured_region( + ... cube=cube_w_mesh, + ... polydata=cube_polydata, + ... region=new_region, + ... ) + >>> print(extracted_cube.shape) + (72, 6) + + Now apply the same region extraction to a different `cube` that has the + same horizontal shape: + + >>> print(other_cube_w_mesh.shape) + (20, 96) + >>> extracted_cube = extract_unstructured_region( + ... cube=other_cube_w_mesh, + ... polydata=cube_polydata, + ... region=new_region, + ... ) + >>> print(extracted_cube.shape) + (20, 6) + + Arbitrary keywords can be passed down to + :meth:`geovista.geodesic.BBox.enclosed` (``outside`` in this example): + + >>> extracted_cube = extract_unstructured_region( + ... cube=other_cube_w_mesh, + ... polydata=cube_polydata, + ... region=new_region, + ... outside=True, + ... ) + >>> print(extracted_cube.shape) + (20, 90) + + """ + if cube.mesh: + # Find what dimension the mesh is in on the cube + mesh_dim = cube.mesh_dim() + recreate_mesh = False + + if cube.location == "face": + polydata_length = polydata.GetNumberOfCells() + indices_key = VTK_CELL_IDS + recreate_mesh = True + elif cube.location == "node": + polydata_length = polydata.GetNumberOfPoints() + indices_key = VTK_POINT_IDS + else: + raise NotImplementedError( + f"cube.location must be `face` or `node`. Found: {cube.location}." + ) + + if cube.shape[mesh_dim] != polydata_length: + raise ValueError( + f"The mesh on the cube and the polydata" + f"must have the same shape." + f" Found Mesh: {cube.shape[mesh_dim]}," + f" Polydata: {polydata_length}." + ) + + region_polydata = region.enclosed(polydata, **kwargs) + indices = region_polydata[indices_key] + if len(indices) == 0: + raise IndexError("No part of `polydata` falls within `region`.") + + my_tuple = tuple( + [slice(None) if i != mesh_dim else indices for i in range(cube.ndim)] + ) + + region_cube = cube[my_tuple] + + if recreate_mesh: + coords_on_mesh_dim = region_cube.coords(dimensions=mesh_dim) + new_mesh = Mesh.from_coords( + *[c for c in coords_on_mesh_dim if c.has_bounds()] + ) + + new_mesh_coords = new_mesh.to_MeshCoords(cube.location) + + for coord in new_mesh_coords: + region_cube.remove_coord(coord.name()) + region_cube.add_aux_coord(coord, mesh_dim) + + # TODO: Support unstructured point based data without a mesh + else: + raise ValueError("Cube must have a mesh") + + return region_cube diff --git a/lib/iris/experimental/regrid.py b/lib/iris/experimental/regrid.py index 835aa51368..4ffad43a2c 100644 --- a/lib/iris/experimental/regrid.py +++ b/lib/iris/experimental/regrid.py @@ -16,6 +16,7 @@ discuss how to replace it or to retain it. """ + import copy import functools import warnings diff --git a/lib/iris/experimental/ugrid/__init__.py b/lib/iris/experimental/ugrid/__init__.py index ccdf05a387..f92cf670c4 100644 --- a/lib/iris/experimental/ugrid/__init__.py +++ b/lib/iris/experimental/ugrid/__init__.py @@ -13,6 +13,7 @@ definition at :const:`iris.experimental.ugrid.load.PARSE_UGRID_ON_LOAD`. """ + from ...config import get_logger from .load import PARSE_UGRID_ON_LOAD, load_mesh, load_meshes from .mesh import Connectivity, Mesh, MeshCoord diff --git a/lib/iris/experimental/ugrid/cf.py b/lib/iris/experimental/ugrid/cf.py index 6897b4ca67..9a56045e67 100644 --- a/lib/iris/experimental/ugrid/cf.py +++ b/lib/iris/experimental/ugrid/cf.py @@ -8,6 +8,7 @@ Eventual destination: :mod:`iris.fileformats.cf`. """ + import warnings from ...fileformats import cf diff --git a/lib/iris/experimental/ugrid/load.py b/lib/iris/experimental/ugrid/load.py index 630c179fd9..c9d66f5276 100644 --- a/lib/iris/experimental/ugrid/load.py +++ b/lib/iris/experimental/ugrid/load.py @@ -11,6 +11,7 @@ Eventual destination: :mod:`iris.fileformats.netcdf`. """ + from contextlib import contextmanager from itertools import groupby from pathlib import Path diff --git a/lib/iris/experimental/ugrid/mesh.py b/lib/iris/experimental/ugrid/mesh.py index db000b5c73..a798f7af77 100644 --- a/lib/iris/experimental/ugrid/mesh.py +++ b/lib/iris/experimental/ugrid/mesh.py @@ -8,6 +8,7 @@ Eventual destination: dedicated module in :mod:`iris` root. """ + from abc import ABC, abstractmethod from collections import namedtuple from collections.abc import Container @@ -862,6 +863,7 @@ def check_shape(array_name): ##### # TODO: remove axis assignment once Mesh supports arbitrary coords. + # TODO: consider filtering coords as the first action in this method. axes_present = [guess_coord_axis(coord) for coord in coords] axes_required = ("X", "Y") if all([req in axes_present for req in axes_required]): diff --git a/lib/iris/experimental/ugrid/metadata.py b/lib/iris/experimental/ugrid/metadata.py index 8969ab72a1..bc7cc677f7 100644 --- a/lib/iris/experimental/ugrid/metadata.py +++ b/lib/iris/experimental/ugrid/metadata.py @@ -8,6 +8,7 @@ Eventual destination: :mod:`iris.common.metadata`. """ + from functools import wraps from ...common import BaseMetadata diff --git a/lib/iris/experimental/ugrid/save.py b/lib/iris/experimental/ugrid/save.py index 40d1c42e90..8cfa6ba97a 100644 --- a/lib/iris/experimental/ugrid/save.py +++ b/lib/iris/experimental/ugrid/save.py @@ -8,6 +8,7 @@ Eventual destination: :mod:`iris.fileformats.netcdf`. """ + from collections.abc import Iterable from ...fileformats import netcdf diff --git a/lib/iris/experimental/ugrid/utils.py b/lib/iris/experimental/ugrid/utils.py index fce1036c6d..dcf5462ad5 100644 --- a/lib/iris/experimental/ugrid/utils.py +++ b/lib/iris/experimental/ugrid/utils.py @@ -4,6 +4,7 @@ # See LICENSE in the root of the repository for full licensing details. """Utility operations specific to unstructured data.""" + from typing import AnyStr, Iterable, Union import dask.array as da diff --git a/lib/iris/fileformats/_nc_load_rules/engine.py b/lib/iris/fileformats/_nc_load_rules/engine.py index 111e8320b6..48092508a4 100644 --- a/lib/iris/fileformats/_nc_load_rules/engine.py +++ b/lib/iris/fileformats/_nc_load_rules/engine.py @@ -18,6 +18,7 @@ used in :meth:`iris.fileformats.netcdf._actions_activation_stats`. """ + from .actions import run_actions diff --git a/lib/iris/fileformats/_nc_load_rules/helpers.py b/lib/iris/fileformats/_nc_load_rules/helpers.py index f6e3985e37..43eed96fd5 100644 --- a/lib/iris/fileformats/_nc_load_rules/helpers.py +++ b/lib/iris/fileformats/_nc_load_rules/helpers.py @@ -13,6 +13,7 @@ build routines, and which it does not use. """ + from __future__ import annotations import re diff --git a/lib/iris/fileformats/netcdf/__init__.py b/lib/iris/fileformats/netcdf/__init__.py index 61b6f74cc6..e92b0ed4f8 100644 --- a/lib/iris/fileformats/netcdf/__init__.py +++ b/lib/iris/fileformats/netcdf/__init__.py @@ -10,6 +10,7 @@ Also : `CF Conventions `_. """ + import iris.config # Note: *must* be done before importing from submodules, as they also use this ! diff --git a/lib/iris/fileformats/netcdf/_dask_locks.py b/lib/iris/fileformats/netcdf/_dask_locks.py index eb60afcf8a..64d094e060 100644 --- a/lib/iris/fileformats/netcdf/_dask_locks.py +++ b/lib/iris/fileformats/netcdf/_dask_locks.py @@ -49,6 +49,7 @@ 'distributed.Lock', which requires a distributed scheduler to function. """ + import threading import dask.array diff --git a/lib/iris/fileformats/netcdf/_thread_safe_nc.py b/lib/iris/fileformats/netcdf/_thread_safe_nc.py index b87ffde145..675a151868 100644 --- a/lib/iris/fileformats/netcdf/_thread_safe_nc.py +++ b/lib/iris/fileformats/netcdf/_thread_safe_nc.py @@ -7,6 +7,7 @@ Intention is that no other Iris module should import the netCDF4 module. """ + from abc import ABC from threading import Lock import typing diff --git a/lib/iris/fileformats/netcdf/loader.py b/lib/iris/fileformats/netcdf/loader.py index ca2d830281..16fe567c9b 100644 --- a/lib/iris/fileformats/netcdf/loader.py +++ b/lib/iris/fileformats/netcdf/loader.py @@ -10,6 +10,7 @@ Also : `CF Conventions `_. """ + from collections.abc import Iterable, Mapping from contextlib import contextmanager from copy import deepcopy @@ -242,6 +243,9 @@ def _get_cf_var_data(cf_var, filename): result = as_lazy_data(proxy, chunks=None, dask_chunking=True) else: chunks = cf_var.cf_data.chunking() + if chunks is None: + # Occurs for non-version-4 netcdf + chunks = "contiguous" # In the "contiguous" case, pass chunks=None to 'as_lazy_data'. if chunks == "contiguous": if ( diff --git a/lib/iris/fileformats/netcdf/saver.py b/lib/iris/fileformats/netcdf/saver.py index 7c24be0a6d..8d53a4d5be 100644 --- a/lib/iris/fileformats/netcdf/saver.py +++ b/lib/iris/fileformats/netcdf/saver.py @@ -13,13 +13,14 @@ Also : `CF Conventions `_. """ + import collections from itertools import repeat, zip_longest import os import os.path import re import string -from typing import List +import typing import warnings import cf_units @@ -161,15 +162,6 @@ } -class _WarnComboMaskSave( - iris.warnings.IrisMaskValueMatchWarning, - iris.warnings.IrisSaveWarning, -): - """One-off combination of warning classes - enhances user filtering.""" - - pass - - class CFNameCoordMap: """Provide a simple CF name to CF coordinate mapping.""" @@ -284,41 +276,6 @@ def _setncattr(variable, name, attribute): MESH_ELEMENTS = ("node", "edge", "face") -_FillvalueCheckInfo = collections.namedtuple( - "_FillvalueCheckInfo", ["user_value", "check_value", "dtype", "varname"] -) - - -def _data_fillvalue_check(arraylib, data, check_value): - """Check whether an array is masked, and whether it contains a fill-value. - - Parameters - ---------- - arraylib : module - Either numpy or dask.array : When dask, results are lazy computations. - data : array-like - Array to check (numpy or dask). - check_value : number or None - If not None, fill-value to check for existence in the array. - If None, do not do value-in-array check. - - Returns - ------- - is_masked : bool - True if array has any masked points. - contains_value : bool - True if array contains check_value. - Always False if check_value is None. - - """ - is_masked = arraylib.any(arraylib.ma.getmaskarray(data)) - if check_value is None: - contains_value = False - else: - contains_value = arraylib.any(data == check_value) - return is_masked, contains_value - - class SaverFillValueWarning(iris.warnings.IrisSaverFillValueWarning): """Backwards compatible form of :class:`iris.warnings.IrisSaverFillValueWarning`.""" @@ -326,59 +283,16 @@ class SaverFillValueWarning(iris.warnings.IrisSaverFillValueWarning): pass -def _fillvalue_report(fill_info, is_masked, contains_fill_value, warn=False): - """Work out whether there was a possible or actual fill-value collision. +class VariableEmulator(typing.Protocol): + """Duck-type-hinting for a ncdata object. - From the given information, work out whether there was a possible or actual - fill-value collision, and if so construct a warning. + https://github.com/pp-mo/ncdata + """ - Parameters - ---------- - fill_info : _FillvalueCheckInfo - A named-tuple containing the context of the fill-value check. - is_masked : bool - Whether the data array was masked. - contains_fill_value : bool - Whether the data array contained the fill-value. - warn : bool, default=False - If True, also issue any resulting warning immediately. + _data_array: np.typing.ArrayLike - Returns - ------- - None or :class:`Warning` - If not None, indicates a known or possible problem with filling. - """ - varname = fill_info.varname - user_value = fill_info.user_value - check_value = fill_info.check_value - is_byte_data = fill_info.dtype.itemsize == 1 - result = None - if is_byte_data and is_masked and user_value is None: - result = SaverFillValueWarning( - f"CF var '{varname}' contains byte data with masked points, but " - "no fill_value keyword was given. As saved, these " - "points will read back as valid values. To save as " - "masked byte data, `_FillValue` needs to be explicitly " - "set. For Cube data this can be done via the 'fill_value' " - "keyword during saving, otherwise use ncedit/equivalent." - ) - elif contains_fill_value: - result = SaverFillValueWarning( - f"CF var '{varname}' contains unmasked data points equal to the " - f"fill-value, {check_value}. As saved, these points will read back " - "as missing data. To save these as normal values, " - "`_FillValue` needs to be set to not equal any valid data " - "points. For Cube data this can be done via the 'fill_value' " - "keyword during saving, otherwise use ncedit/equivalent." - ) - - if warn and result is not None: - warnings.warn( - result, - category=_WarnComboMaskSave, - ) - return result +CFVariable = typing.Union[_thread_safe_nc.VariableWrapper, VariableEmulator] class Saver: @@ -453,7 +367,7 @@ def __init__(self, filename, netcdf_format, compute=True): self._formula_terms_cache = {} #: Target filepath self.filepath = None # this line just for the API page -- value is set later - #: Whether to complete delayed saves on exit (and raise associated warnings). + #: Whether to complete delayed saves on exit. self.compute = compute # N.B. the file-write-lock *type* actually depends on the dask scheduler type. #: A per-file write lock to prevent dask attempting overlapping writes. @@ -462,7 +376,7 @@ def __init__(self, filename, netcdf_format, compute=True): ) # A list of delayed writes for lazy saving - # a list of triples (source, target, fill-info). + # a list of couples (source, target). self._delayed_writes = [] # Detect if we were passed a pre-opened dataset (or something like one) @@ -1543,12 +1457,7 @@ def _create_cf_bounds(self, coord, cf_var, cf_name): bounds.dtype.newbyteorder("="), cf_var.dimensions + (bounds_dimension_name,), ) - self._lazy_stream_data( - data=bounds, - fill_value=None, - fill_warn=True, - cf_var=cf_var_bounds, - ) + self._lazy_stream_data(data=bounds, cf_var=cf_var_bounds) def _get_cube_variable_name(self, cube): """Return a CF-netCDF variable name for the given cube. @@ -1881,9 +1790,7 @@ def _create_generic_cf_array_var( self._create_cf_bounds(element, cf_var, cf_name) # Add the data to the CF-netCDF variable. - self._lazy_stream_data( - data=data, fill_value=fill_value, fill_warn=True, cf_var=cf_var - ) + self._lazy_stream_data(data=data, cf_var=cf_var) # Add names + units self._set_cf_var_attributes(cf_var, element) @@ -2288,12 +2195,7 @@ def set_packing_ncattrs(cfvar): ) set_packing_ncattrs(cf_var) - self._lazy_stream_data( - data=data, - fill_value=fill_value, - fill_warn=(not packing), - cf_var=cf_var, - ) + self._lazy_stream_data(data=data, cf_var=cf_var) if cube.standard_name: _setncattr(cf_var, "standard_name", cube.standard_name) @@ -2386,7 +2288,11 @@ def _increment_name(self, varname): return "{}_{}".format(varname, num) - def _lazy_stream_data(self, data, fill_value, fill_warn, cf_var): + def _lazy_stream_data( + self, + data: np.typing.ArrayLike, + cf_var: CFVariable, + ) -> None: if hasattr(data, "shape") and data.shape == (1,) + cf_var.shape: # (Don't do this check for string data). # Reduce dimensionality where the data array has an extra dimension @@ -2402,72 +2308,36 @@ def _lazy_stream_data(self, data, fill_value, fill_warn, cf_var): # data to/from netcdf data container objects in other packages, such as # xarray. # See https://github.com/SciTools/iris/issues/4994 "Xarray bridge". - # N.B. also, in this case there is no need for fill-value checking as the - # data is not being translated to an in-file representation. cf_var._data_array = data - else: - # Decide whether we are checking for fill-value collisions. - dtype = cf_var.dtype - # fill_warn allows us to skip warning if packing attributes have been - # specified. It would require much more complex operations to work out - # what the values and fill_value _would_ be in such a case. - if fill_warn: - if fill_value is not None: - fill_value_to_check = fill_value - else: - # Retain 'fill_value == None', to show that no specific value was given. - # But set 'fill_value_to_check' to a calculated value - fill_value_to_check = _thread_safe_nc.default_fillvals[ - dtype.str[1:] - ] - # Cast the check-value to the correct dtype. - # NOTE: In the case of 'S1' dtype (at least), the default (Python) value - # does not have a compatible type. This causes a deprecation warning at - # numpy 1.24, *and* was preventing correct fill-value checking of character - # data, since they are actually bytes (dtype 'S1'). - fill_value_to_check = np.array(fill_value_to_check, dtype=dtype) - else: - # A None means we will NOT check for collisions. - fill_value_to_check = None - - fill_info = _FillvalueCheckInfo( - user_value=fill_value, - check_value=fill_value_to_check, - dtype=dtype, - varname=cf_var.name, - ) + else: doing_delayed_save = is_lazy_data(data) if doing_delayed_save: # save lazy data with a delayed operation. For now, we just record the # necessary information -- a single, complete delayed action is constructed # later by a call to delayed_completion(). - def store(data, cf_var, fill_info): + def store( + data: np.typing.ArrayLike, + cf_var: CFVariable, + ) -> None: # Create a data-writeable object that we can stream into, which # encapsulates the file to be opened + variable to be written. write_wrapper = _thread_safe_nc.NetCDFWriteProxy( self.filepath, cf_var, self.file_write_lock ) # Add to the list of delayed writes, used in delayed_completion(). - self._delayed_writes.append((data, write_wrapper, fill_info)) - # In this case, fill-value checking is done later. But return 2 dummy - # values, to be consistent with the non-streamed "store" signature. - is_masked, contains_value = False, False - return is_masked, contains_value + self._delayed_writes.append((data, write_wrapper)) else: # Real data is always written directly, i.e. not via lazy save. - # We also check it immediately for any fill-value problems. - def store(data, cf_var, fill_info): + def store( + data: np.typing.ArrayLike, + cf_var: CFVariable, + ) -> None: cf_var[:] = data - return _data_fillvalue_check(np, data, fill_info.check_value) - - # Store the data and check if it is masked and contains the fill value. - is_masked, contains_fill_value = store(data, cf_var, fill_info) - if not doing_delayed_save: - # Issue a fill-value warning immediately, if appropriate. - _fillvalue_report(fill_info, is_masked, contains_fill_value, warn=True) + # Store the data. + store(data, cf_var) def delayed_completion(self) -> Delayed: """Perform file completion for delayed saves. @@ -2475,11 +2345,6 @@ def delayed_completion(self) -> Delayed: Create and return a :class:`dask.delayed.Delayed` to perform file completion for delayed saves. - This contains all the delayed writes, which complete the file by - filling out the data of variables initially created empty, and also the - checks for potential fill-value collisions. When computed, it returns - a list of any warnings which were generated in the save operation. - Returns ------- :class:`dask.delayed.Delayed` @@ -2491,68 +2356,24 @@ def delayed_completion(self) -> Delayed: """ if self._delayed_writes: # Create a single delayed da.store operation to complete the file. - sources, targets, fill_infos = zip(*self._delayed_writes) - store_op = da.store(sources, targets, compute=False, lock=False) - - # Construct a delayed fill-check operation for each (lazy) source array. - delayed_fillvalue_checks = [ - # NB with arraylib=dask.array, this routine does lazy array computation - _data_fillvalue_check(da, source, fillinfo.check_value) - for source, fillinfo in zip(sources, fill_infos) - ] - - # Return a single delayed object which completes the delayed saves and - # returns a list of any fill-value warnings. - @dask.delayed - def compute_and_return_warnings(store_op, fv_infos, fv_checks): - # Note: we don't actually *do* anything with the 'store_op' argument, - # but including it here ensures that dask will compute it (thus - # performing all the delayed saves), before calling this function. - results = [] - # Pair each fill_check result (is_masked, contains_value) with its - # fillinfo and construct a suitable Warning if needed. - for fillinfo, (is_masked, contains_value) in zip(fv_infos, fv_checks): - fv_warning = _fillvalue_report( - fill_info=fillinfo, - is_masked=is_masked, - contains_fill_value=contains_value, - ) - if fv_warning is not None: - # Collect the warnings and return them. - results.append(fv_warning) - return results - - result = compute_and_return_warnings( - store_op, - fv_infos=fill_infos, - fv_checks=delayed_fillvalue_checks, - ) + sources, targets = zip(*self._delayed_writes) + result = da.store(sources, targets, compute=False, lock=False) else: - # Return a delayed, which returns an empty list, for usage consistency. + # Return a do-nothing delayed, for usage consistency. @dask.delayed def no_op(): - return [] + return None result = no_op() return result - def complete(self, issue_warnings=True) -> List[Warning]: + def complete(self) -> None: """Complete file by computing any delayed variable saves. This requires that the Saver has closed the dataset (exited its context). - Parameters - ---------- - issue_warnings : bool, default = True - If true, issue all the resulting warnings with :func:`warnings.warn`. - - Returns - ------- - list of Warning - Any warnings that were raised while writing delayed data. - """ if self._dataset.isopen(): msg = ( @@ -2561,15 +2382,8 @@ def complete(self, issue_warnings=True) -> List[Warning]: ) raise ValueError(msg) - delayed_write = self.delayed_completion() - # Complete the saves now, and handle any delayed warnings that occurred - result_warnings = delayed_write.compute() - if issue_warnings: - # Issue any delayed warnings from the compute. - for delayed_warning in result_warnings: - warnings.warn(delayed_warning, category=iris.warnings.IrisSaveWarning) - - return result_warnings + # Complete the saves now + self.delayed_completion().compute() def save( @@ -2721,11 +2535,6 @@ def save( Several such data saves can be performed in parallel, by passing a list of them into a :func:`dask.compute` call. - .. note:: - when computed, the returned :class:`dask.delayed.Delayed` object returns - a list of :class:`Warning` : These are any warnings which *would* have - been issued in the save call, if ``compute`` had been ``True``. - .. note:: If saving to an open dataset instead of a filepath, then the caller **must** specify ``compute=False``, and complete delayed saves **after diff --git a/lib/iris/fileformats/pp.py b/lib/iris/fileformats/pp.py index e40b71eff5..0a159b46b6 100644 --- a/lib/iris/fileformats/pp.py +++ b/lib/iris/fileformats/pp.py @@ -2177,15 +2177,12 @@ def save(cube, target, append=False, field_coords=None): of cubes to be saved to a PP file. """ - fields = as_fields(cube, field_coords, target) + fields = as_fields(cube, field_coords) save_fields(fields, target, append=append) -def save_pairs_from_cube(cube, field_coords=None, target=None): - """Use the PP saving rules to convert a cube. - - Use the PP saving rules to convert a cube or - iterable of cubes to an iterable of (2D cube, PP field) pairs. +def save_pairs_from_cube(cube, field_coords=None): + """Use the PP saving rules to generate (2D cube, PP field) pairs from a cube. Parameters ---------- @@ -2196,8 +2193,11 @@ def save_pairs_from_cube(cube, field_coords=None, target=None): reducing the given cube into 2d slices, which will ultimately determine the x and y coordinates of the resulting fields. If None, the final two dimensions are chosen for slicing. - target : optional - A filename or open file handle. + + Yields + ------ + :class:`iris.cube.Cube`, :class:`iris.fileformats.pp.PPField`. + 2-dimensional slices of the input cube together with their associated pp-fields. """ # Open issues @@ -2298,7 +2298,7 @@ def save_pairs_from_cube(cube, field_coords=None, target=None): yield (slice2D, pp_field) -def as_fields(cube, field_coords=None, target=None): +def as_fields(cube, field_coords=None): """Use the PP saving rules to convert a cube to an iterable of PP fields. Use the PP saving rules (and any user rules) to convert a cube to @@ -2312,16 +2312,9 @@ def as_fields(cube, field_coords=None, target=None): reducing the given cube into 2d slices, which will ultimately determine the x and y coordinates of the resulting fields. If None, the final two dimensions are chosen for slicing. - target : optional - A filename or open file handle. """ - return ( - field - for cube, field in save_pairs_from_cube( - cube, field_coords=field_coords, target=target - ) - ) + return (field for _, field in save_pairs_from_cube(cube, field_coords=field_coords)) def save_fields(fields, target, append: bool = False): diff --git a/lib/iris/fileformats/um/_optimal_array_structuring.py b/lib/iris/fileformats/um/_optimal_array_structuring.py index 7d006ebeff..f4e0328a42 100644 --- a/lib/iris/fileformats/um/_optimal_array_structuring.py +++ b/lib/iris/fileformats/um/_optimal_array_structuring.py @@ -4,7 +4,6 @@ # See LICENSE in the root of the repository for full licensing details. """A module to provide an optimal array structure calculation.""" - from iris.fileformats._structured_array_identification import GroupStructure diff --git a/lib/iris/pandas.py b/lib/iris/pandas.py index 2efad54613..434e415f2d 100644 --- a/lib/iris/pandas.py +++ b/lib/iris/pandas.py @@ -7,6 +7,7 @@ See also: https://pandas.pydata.org/ """ + import datetime from itertools import chain, combinations import warnings diff --git a/lib/iris/tests/integration/experimental/geovista/__init__.py b/lib/iris/tests/integration/experimental/geovista/__init__.py new file mode 100644 index 0000000000..6a56e09db4 --- /dev/null +++ b/lib/iris/tests/integration/experimental/geovista/__init__.py @@ -0,0 +1,5 @@ +# 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 the :mod:`iris.experimental.geovista` module.""" diff --git a/lib/iris/tests/integration/experimental/geovista/test_cube_to_poly.py b/lib/iris/tests/integration/experimental/geovista/test_cube_to_poly.py new file mode 100644 index 0000000000..582c216a44 --- /dev/null +++ b/lib/iris/tests/integration/experimental/geovista/test_cube_to_poly.py @@ -0,0 +1,67 @@ +# 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 the `iris.experimental.geovista.cube_to_polydata` function.""" + +import numpy as np + +from iris import load_cube +from iris.experimental.geovista import cube_to_polydata +from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD +from iris.tests import get_data_path + + +def test_integration_2d(): + file_path = get_data_path( + [ + "NetCDF", + "ORCA2", + "votemper.nc", + ] + ) + + cube = load_cube(file_path, "votemper") + + polydata = cube_to_polydata(cube[0, 1, :]) + # This is a known good output, we have plotted the result and checked it. + assert polydata.GetNumberOfCells() == 26640 + assert polydata.GetNumberOfPoints() == 26969 + np.testing.assert_array_equal(cube[0, 1, :].data.flatten(), polydata.active_scalars) + + +def test_integration_1d(): + file_path = get_data_path( + [ + "NetCDF", + "global", + "xyt", + "SMALL_hires_wind_u_for_ipcc4.nc", + ] + ) + cube = load_cube(file_path) + + polydata = cube_to_polydata(cube[0, :]) + # This is a known good output, we have plotted the result and checked it. + assert polydata.GetNumberOfCells() == 51200 + assert polydata.GetNumberOfPoints() == 51681 + np.testing.assert_array_equal(cube[0, :].data.flatten(), polydata.active_scalars) + + +def test_integration_mesh(): + file_path = get_data_path( + [ + "NetCDF", + "unstructured_grid", + "lfric_ngvat_2D_72t_face_half_levels_main_conv_rain.nc", + ] + ) + + with PARSE_UGRID_ON_LOAD.context(): + cube = load_cube(file_path, "conv_rain") + + polydata = cube_to_polydata(cube[0, :]) + # This is a known good output, we have plotted the result and checked it. + assert polydata.GetNumberOfCells() == 864 + assert polydata.GetNumberOfPoints() == 866 + np.testing.assert_array_equal(polydata.active_scalars, cube[0, :].data) diff --git a/lib/iris/tests/integration/experimental/geovista/test_extract_unstructured_region.py b/lib/iris/tests/integration/experimental/geovista/test_extract_unstructured_region.py new file mode 100644 index 0000000000..47024dc1cd --- /dev/null +++ b/lib/iris/tests/integration/experimental/geovista/test_extract_unstructured_region.py @@ -0,0 +1,36 @@ +# 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 the `iris.experimental.geovista.extract_unstructured_region` function.""" + +from geovista.geodesic import BBox + +from iris import load_cube +from iris.experimental.geovista import cube_to_polydata, extract_unstructured_region +from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD +from iris.tests import get_data_path + + +def test_face_region_extraction(): + file_path = get_data_path( + [ + "NetCDF", + "unstructured_grid", + "lfric_ngvat_2D_72t_face_half_levels_main_conv_rain.nc", + ] + ) + + with PARSE_UGRID_ON_LOAD.context(): + global_cube = load_cube(file_path, "conv_rain") + polydata = cube_to_polydata(global_cube[0, :]) + region = BBox(lons=[0, 70, 70, 0], lats=[-25, -25, 45, 45]) + + extracted_cube = extract_unstructured_region( + global_cube, polydata, region, preference="center" + ) + + assert extracted_cube.ndim == 2 + assert extracted_cube.shape == (72, 101) + assert global_cube.shape == (72, 864) + assert global_cube.ndim == 2 diff --git a/lib/iris/tests/integration/experimental/test_ugrid_load.py b/lib/iris/tests/integration/experimental/test_ugrid_load.py index d513d02497..5735d6b2c1 100644 --- a/lib/iris/tests/integration/experimental/test_ugrid_load.py +++ b/lib/iris/tests/integration/experimental/test_ugrid_load.py @@ -8,6 +8,7 @@ standard behaviour. """ + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/integration/experimental/test_ugrid_save.py b/lib/iris/tests/integration/experimental/test_ugrid_save.py index 8350a2004f..85f6024b93 100644 --- a/lib/iris/tests/integration/experimental/test_ugrid_save.py +++ b/lib/iris/tests/integration/experimental/test_ugrid_save.py @@ -3,6 +3,7 @@ # 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 NetCDF-UGRID file saving.""" + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/integration/netcdf/test__dask_locks.py b/lib/iris/tests/integration/netcdf/test__dask_locks.py index 6e1026b29f..1aee902195 100644 --- a/lib/iris/tests/integration/netcdf/test__dask_locks.py +++ b/lib/iris/tests/integration/netcdf/test__dask_locks.py @@ -11,6 +11,7 @@ and (b) mock-ist testing of the implementation code in isolation would not add anything of much value. """ + import dask import dask.config import distributed diff --git a/lib/iris/tests/integration/netcdf/test_aux_factories.py b/lib/iris/tests/integration/netcdf/test_aux_factories.py index a0c2ec5992..4b4976bd18 100644 --- a/lib/iris/tests/integration/netcdf/test_aux_factories.py +++ b/lib/iris/tests/integration/netcdf/test_aux_factories.py @@ -75,9 +75,10 @@ def test_save_load_loop(self): # Tests an issue where the variable names in the formula # terms changed to the standard_names instead of the variable names # when loading a previously saved cube. - with self.temp_filename(suffix=".nc") as filename, self.temp_filename( - suffix=".nc" - ) as other_filename: + with ( + self.temp_filename(suffix=".nc") as filename, + self.temp_filename(suffix=".nc") as other_filename, + ): iris.save(self.cube, filename) cube = iris.load_cube(filename, "air_potential_temperature") iris.save(cube, other_filename) @@ -117,8 +118,9 @@ def test_shared_primary(self): ) factory.rename("another altitude") cube.add_aux_factory(factory) - with self.temp_filename(suffix=".nc") as filename, self.assertRaisesRegex( - ValueError, "multiple aux factories" + with ( + self.temp_filename(suffix=".nc") as filename, + self.assertRaisesRegex(ValueError, "multiple aux factories"), ): iris.save(cube, filename) @@ -141,8 +143,9 @@ def test_hybrid_height_cubes_on_dimension_coordinate(self): sa = hh2.coord("surface_altitude") sa.points = sa.points * 10 emsg = "Unable to create dimensonless vertical coordinate." - with self.temp_filename(".nc") as fname, self.assertRaisesRegex( - ValueError, emsg + with ( + self.temp_filename(".nc") as fname, + self.assertRaisesRegex(ValueError, emsg), ): iris.save([hh1, hh2], fname) diff --git a/lib/iris/tests/integration/netcdf/test_delayed_save.py b/lib/iris/tests/integration/netcdf/test_delayed_save.py index cb375cc592..2869924dce 100644 --- a/lib/iris/tests/integration/netcdf/test_delayed_save.py +++ b/lib/iris/tests/integration/netcdf/test_delayed_save.py @@ -3,7 +3,7 @@ # 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 delayed saving.""" -import re + import warnings from cf_units import Unit @@ -18,7 +18,6 @@ from iris.fileformats.netcdf._thread_safe_nc import default_fillvals import iris.tests from iris.tests.stock import realistic_4d -from iris.warnings import IrisSaverFillValueWarning class Test__lazy_stream_data: @@ -184,39 +183,12 @@ def test_scheduler_types(self, output_path, scheduler_type, save_is_delayed): cube = self.make_testcube( include_lazy_content=True, ensure_fillvalue_collision=True ) - with warnings.catch_warnings(record=True) as logged_warnings: - result = iris.save(cube, output_path, compute=not save_is_delayed) + result = iris.save(cube, output_path, compute=not save_is_delayed) if not save_is_delayed: assert result is None - issued_warnings = [log.message for log in logged_warnings] else: - assert result is not None - assert len(logged_warnings) == 0 - with warnings.catch_warnings(record=True) as logged_warnings: - # The compute *returns* warnings from the delayed operations. - issued_warnings = result.compute() - issued_warnings = [log.message for log in logged_warnings] + issued_warnings - - warning_messages = [warning.args[0] for warning in issued_warnings] - if scheduler_type == "DistributedScheduler": - # Ignore any "large data transfer" messages generated, - # specifically when testing with the Distributed scheduler. - # These may not always occur and don't reflect something we want to - # test for. - large_transfer_message_regex = re.compile( - "Sending large graph.* may cause some slowdown", re.DOTALL - ) - warning_messages = [ - message - for message in warning_messages - if not large_transfer_message_regex.search(message) - ] - - # In all cases, should get 2 fill value warnings overall. - assert len(warning_messages) == 2 - expected_msg = "contains unmasked data points equal to the fill-value" - assert all(expected_msg in message for message in warning_messages) + assert isinstance(result, Delayed) def test_time_of_writing(self, save_is_delayed, output_path, scheduler_type): # Check when lazy data is *actually* written : @@ -289,49 +261,6 @@ def fetch_masks(): assert np.all(~ancil_mask) assert np.all(~cm_mask) - @pytest.mark.parametrize( - "warning_type", ["WarnMaskedBytes", "WarnFillvalueCollision"] - ) - def test_fill_warnings(self, warning_type, output_path, save_is_delayed): - # Test collision warnings for data with fill-value collisions, or for masked - # byte data. - if warning_type == "WarnFillvalueCollision": - make_fv_collide = True - make_maskedbytes = False - expected_msg = "contains unmasked data points equal to the fill-value" - else: - assert warning_type == "WarnMaskedBytes" - make_fv_collide = False - make_maskedbytes = True - expected_msg = "contains byte data with masked points" - - cube = self.make_testcube( - include_lazy_content=True, - ensure_fillvalue_collision=make_fv_collide, - data_is_maskedbytes=make_maskedbytes, - ) - with warnings.catch_warnings(record=True) as logged_warnings: - result = iris.save(cube, output_path, compute=not save_is_delayed) - - result_warnings = [ - log.message - for log in logged_warnings - if isinstance(log.message, IrisSaverFillValueWarning) - ] - - if save_is_delayed: - # Should have had *no* fill-warnings in the initial save. - assert len(result_warnings) == 0 - # Complete the operation now - with warnings.catch_warnings(): - # NOTE: warnings should *not* be issued here, instead they are returned. - warnings.simplefilter("error", category=IrisSaverFillValueWarning) - result_warnings = result.compute() - - # Either way, we should now have 2 similar warnings. - assert len(result_warnings) == 2 - assert all(expected_msg in warning.args[0] for warning in result_warnings) - def test_no_delayed_writes(self, output_path): # Just check that a delayed save returns a usable 'delayed' object, even when # there is no lazy content = no delayed writes to perform. @@ -339,4 +268,3 @@ def test_no_delayed_writes(self, output_path): warnings.simplefilter("error") result = iris.save(cube, output_path, compute=False) assert isinstance(result, Delayed) - assert result.compute() == [] diff --git a/lib/iris/tests/integration/netcdf/test_general.py b/lib/iris/tests/integration/netcdf/test_general.py index 1020ddbb96..c505a21af5 100644 --- a/lib/iris/tests/integration/netcdf/test_general.py +++ b/lib/iris/tests/integration/netcdf/test_general.py @@ -3,6 +3,7 @@ # 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 and saving netcdf files.""" + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/integration/netcdf/test_thread_safety.py b/lib/iris/tests/integration/netcdf/test_thread_safety.py index b2319364c2..53b40dbe85 100644 --- a/lib/iris/tests/integration/netcdf/test_thread_safety.py +++ b/lib/iris/tests/integration/netcdf/test_thread_safety.py @@ -17,6 +17,7 @@ a thread safety problem, as this seems to be good testing practice. """ + from pathlib import Path import dask diff --git a/lib/iris/tests/integration/test_netcdf__loadsaveattrs.py b/lib/iris/tests/integration/test_netcdf__loadsaveattrs.py index 226babc9fb..991f0431a1 100644 --- a/lib/iris/tests/integration/test_netcdf__loadsaveattrs.py +++ b/lib/iris/tests/integration/test_netcdf__loadsaveattrs.py @@ -17,6 +17,7 @@ might be recorded either globally or locally. """ + import inspect import json import os diff --git a/lib/iris/tests/integration/test_pp.py b/lib/iris/tests/integration/test_pp.py index 1ed9dca853..1e71da623a 100644 --- a/lib/iris/tests/integration/test_pp.py +++ b/lib/iris/tests/integration/test_pp.py @@ -280,9 +280,10 @@ def test_hybrid_pressure_with_duplicate_references(self): return_value=iter([data_field, pressure_field, pressure_field]) ) msg = "Multiple reference cubes for surface_air_pressure" - with mock.patch("iris.fileformats.pp.load", new=load) as load, mock.patch( - "warnings.warn" - ) as warn: + with ( + mock.patch("iris.fileformats.pp.load", new=load) as load, + mock.patch("warnings.warn") as warn, + ): _, _, _ = iris.fileformats.pp.load_cubes("DUMMY") warn.assert_called_with(msg, category=IrisUserWarning) @@ -396,9 +397,10 @@ def test_hybrid_height_round_trip_no_reference(self): # Convert field to a cube. load = mock.Mock(return_value=iter([data_field])) - with mock.patch("iris.fileformats.pp.load", new=load) as load, mock.patch( - "warnings.warn" - ) as warn: + with ( + mock.patch("iris.fileformats.pp.load", new=load) as load, + mock.patch("warnings.warn") as warn, + ): (data_cube,) = iris.fileformats.pp.load_cubes("DUMMY") msg = ( diff --git a/lib/iris/tests/stock/__init__.py b/lib/iris/tests/stock/__init__.py index 8c1154af72..ea513b967f 100644 --- a/lib/iris/tests/stock/__init__.py +++ b/lib/iris/tests/stock/__init__.py @@ -3,6 +3,7 @@ # 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. """A collection of routines which create standard Cubes/files for test purposes.""" + import iris.tests as tests # isort:skip from datetime import datetime diff --git a/lib/iris/tests/stock/mesh.py b/lib/iris/tests/stock/mesh.py index 3520436f66..4d0e8ae658 100644 --- a/lib/iris/tests/stock/mesh.py +++ b/lib/iris/tests/stock/mesh.py @@ -4,7 +4,6 @@ # See LICENSE in the root of the repository for full licensing details. """Helper functions making objects for unstructured mesh testing.""" - import numpy as np from iris.coords import AuxCoord, DimCoord diff --git a/lib/iris/tests/test_analysis.py b/lib/iris/tests/test_analysis.py index 6ed02b8ad4..a8446034be 100644 --- a/lib/iris/tests/test_analysis.py +++ b/lib/iris/tests/test_analysis.py @@ -1116,6 +1116,8 @@ def test_rotate_1d(self): @tests.skip_data class TestAreaWeights(tests.IrisTest): + # Note: chunks is simply ignored for non-lazy data + @pytest.mark.parametrize("chunks", [None, (2, 3)]) def test_area_weights(self): small_cube = iris.tests.stock.simple_pp() # Get offset, subsampled region: small enough to test against literals @@ -1155,6 +1157,47 @@ def test_area_weights(self): ) +@tests.skip_data +class TestLazyAreaWeights: + @pytest.mark.parametrize("normalize", [True, False]) + @pytest.mark.parametrize("chunks", [None, (2, 3, 4), (2, 2, 2)]) + def test_lazy_area_weights(self, chunks, normalize): + small_cube = iris.tests.stock.simple_3d()[[0, 0, 0, 0], :, :] + small_cube.coord("latitude").guess_bounds() + small_cube.coord("longitude").guess_bounds() + + area_weights = iris.analysis.cartography.area_weights( + small_cube, + normalize=normalize, + compute=False, + chunks=chunks, + ) + + assert isinstance(area_weights, da.Array) + + # Check that chunksizes are as expected + if chunks is None: + assert area_weights.chunksize == (4, 3, 4) + else: + assert area_weights.chunksize == (2, 3, 4) + + # Check that actual weights are as expected (known good output) + if normalize: + expected_2d = [ + [0.03661165, 0.03661165, 0.03661165, 0.03661165], + [0.1767767, 0.1767767, 0.1767767, 0.1767767], + [0.03661165, 0.03661165, 0.03661165, 0.03661165], + ] + else: + expected_2d = [ + [1.86536150e13, 1.86536150e13, 1.86536150e13, 1.86536150e13], + [9.00676206e13, 9.00676206e13, 9.00676206e13, 9.00676206e13], + [1.86536150e13, 1.86536150e13, 1.86536150e13, 1.86536150e13], + ] + expected = np.broadcast_to(expected_2d, (4, 3, 4)) + np.testing.assert_allclose(area_weights.compute(), expected) + + @tests.skip_data class TestAreaWeightGeneration(tests.IrisTest): def setUp(self): diff --git a/lib/iris/tests/test_coding_standards.py b/lib/iris/tests/test_coding_standards.py index 2f14ea703e..9bb26a426a 100644 --- a/lib/iris/tests/test_coding_standards.py +++ b/lib/iris/tests/test_coding_standards.py @@ -69,8 +69,8 @@ def test_python_versions(): Test is designed to fail whenever Iris' supported Python versions are updated, insisting that versions are updated EVERYWHERE in-sync. """ - latest_supported = "3.11" - all_supported = ["3.9", "3.10", latest_supported] + latest_supported = "3.12" + all_supported = ["3.10", "3.11", latest_supported] root_dir = Path(__file__).parents[3] workflows_dir = root_dir / ".github" / "workflows" diff --git a/lib/iris/tests/unit/common/metadata/test__NamedTupleMeta.py b/lib/iris/tests/unit/common/metadata/test__NamedTupleMeta.py index 5099645082..63d700e53e 100644 --- a/lib/iris/tests/unit/common/metadata/test__NamedTupleMeta.py +++ b/lib/iris/tests/unit/common/metadata/test__NamedTupleMeta.py @@ -45,7 +45,7 @@ def _members(self): self.assertEqual(self.names(Metadata.__bases__), expected) expected = ["Metadata", "object"] self.assertEqual(self.names(Metadata.__mro__), expected) - emsg = "Can't instantiate abstract class .* with abstract method.* _members" + emsg = "Can't instantiate abstract class" with self.assertRaisesRegex(TypeError, emsg): _ = Metadata() diff --git a/lib/iris/tests/unit/conftest.py b/lib/iris/tests/unit/conftest.py index a4ddb89294..524ca53ce8 100644 --- a/lib/iris/tests/unit/conftest.py +++ b/lib/iris/tests/unit/conftest.py @@ -3,6 +3,7 @@ # 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 fixture infra-structure.""" + import pytest import iris diff --git a/lib/iris/tests/unit/coords/test_Coord.py b/lib/iris/tests/unit/coords/test_Coord.py index c0accfe071..3740b17f22 100644 --- a/lib/iris/tests/unit/coords/test_Coord.py +++ b/lib/iris/tests/unit/coords/test_Coord.py @@ -1124,7 +1124,7 @@ def test_copy_coord(self, ignore_axis, copy_or_from, result, sample_coord): class Test___init____abstractmethod(tests.IrisTest): def test(self): - emsg = "Can't instantiate abstract class Coord with abstract method.* __init__" + emsg = "Can't instantiate abstract class Coord" with self.assertRaisesRegex(TypeError, emsg): _ = Coord(points=[0, 1]) diff --git a/lib/iris/tests/unit/coords/test__DimensionalMetadata.py b/lib/iris/tests/unit/coords/test__DimensionalMetadata.py index caff08fb66..da0dccd873 100644 --- a/lib/iris/tests/unit/coords/test__DimensionalMetadata.py +++ b/lib/iris/tests/unit/coords/test__DimensionalMetadata.py @@ -28,10 +28,7 @@ class Test___init____abstractmethod(tests.IrisTest): def test(self): - emsg = ( - "Can't instantiate abstract class _DimensionalMetadata with " - "abstract methods __init__" - ) + emsg = "Can't instantiate abstract class _DimensionalMetadata" with self.assertRaisesRegex(TypeError, emsg): _ = _DimensionalMetadata(0) diff --git a/lib/iris/tests/unit/experimental/geovista/__init__.py b/lib/iris/tests/unit/experimental/geovista/__init__.py new file mode 100644 index 0000000000..b2024ce97d --- /dev/null +++ b/lib/iris/tests/unit/experimental/geovista/__init__.py @@ -0,0 +1,5 @@ +# 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.experimental.geovista` module.""" diff --git a/lib/iris/tests/unit/experimental/geovista/test_cube_to_polydata.py b/lib/iris/tests/unit/experimental/geovista/test_cube_to_polydata.py new file mode 100644 index 0000000000..1394465fb4 --- /dev/null +++ b/lib/iris/tests/unit/experimental/geovista/test_cube_to_polydata.py @@ -0,0 +1,190 @@ +# 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.experimental.geovista.cube_to_polydata` function.""" + +from unittest.mock import Mock + +from geovista import Transform +import numpy as np +import pytest + +import iris.analysis.cartography +import iris.coord_systems +from iris.experimental.geovista import cube_to_polydata +from iris.tests.stock import lat_lon_cube, sample_2d_latlons +from iris.tests.stock.mesh import sample_mesh_cube + + +@pytest.fixture() +def cube_mesh(): + return sample_mesh_cube() + + +@pytest.fixture() +def cube_1d(): + sample_1d_cube = lat_lon_cube() + for coord in sample_1d_cube.dim_coords: + coord.coord_system = None + return sample_1d_cube + + +@pytest.fixture() +def cube_2d(): + return sample_2d_latlons() + + +@pytest.fixture() +def default_cs(): + return iris.coord_systems.GeogCS( + iris.analysis.cartography.DEFAULT_SPHERICAL_EARTH_RADIUS + ) + + +class ParentClass: + MOCKED_OPERATION = NotImplemented + + @pytest.fixture() + def expected(self): + pass + + @pytest.fixture() + def operation(self): + pass + + @pytest.fixture() + def cube(self): + pass + + @pytest.fixture() + def cube_with_crs(self, default_cs, cube): + cube_crs = cube.copy() + for coord in cube_crs.coords(): + coord.coord_system = default_cs + return cube_crs + + @pytest.fixture() + def mocked_operation(self): + mocking = Mock() + setattr(Transform, self.MOCKED_OPERATION, mocking) + return mocking + + @staticmethod + def test_to_poly(expected, mocked_operation, cube): + cube_to_polydata(cube) + actual = mocked_operation.call_args.kwargs + for key, expected_value in expected.items(): + if hasattr(expected_value, "shape"): + np.testing.assert_array_equal(actual[key], expected_value) + else: + assert actual[key] == expected_value + + @staticmethod + def test_to_poly_crs(mocked_operation, default_cs, cube_with_crs): + cube_to_polydata(cube_with_crs) + actual = mocked_operation.call_args.kwargs + assert actual["crs"] == default_cs.as_cartopy_crs().proj4_init + + @staticmethod + def test_to_poly_kwargs(mocked_operation, cube): + kwargs = {"test": "test"} + cube_to_polydata(cube, **kwargs) + actual = mocked_operation.call_args.kwargs + assert actual["test"] == "test" + + +class Test2dToPoly(ParentClass): + MOCKED_OPERATION = "from_2d" + + @pytest.fixture() + def expected(self, cube_2d): + return { + "xs": cube_2d.coord(axis="X").contiguous_bounds(), + "ys": cube_2d.coord(axis="Y").contiguous_bounds(), + "data": cube_2d.data, + "name": f"{cube_2d.name()} / ({cube_2d.units})", + } + + @pytest.fixture() + def cube(self, cube_2d): + return cube_2d + + +class Test1dToPoly(ParentClass): + MOCKED_OPERATION = "from_1d" + + @pytest.fixture() + def expected(self, cube_1d): + return { + "xs": cube_1d.coord(axis="X").contiguous_bounds(), + "ys": cube_1d.coord(axis="Y").contiguous_bounds(), + "data": cube_1d.data, + "name": f"{cube_1d.name()} / ({cube_1d.units})", + } + + @pytest.fixture() + def cube(self, cube_1d): + return cube_1d + + +class TestMeshToPoly(ParentClass): + MOCKED_OPERATION = "from_unstructured" + + @pytest.fixture() + def expected(self, cube_mesh): + return { + "xs": cube_mesh.mesh.node_coords[0].points, + "ys": cube_mesh.mesh.node_coords[1].points, + "connectivity": cube_mesh.mesh.face_node_connectivity.indices_by_location(), + "data": cube_mesh.data[0], + "name": cube_mesh.name() + " / " + "(" + str(cube_mesh.units) + ")", + "start_index": 0, + } + + def test_if_1d(self, cube_mesh): + with pytest.raises( + NotImplementedError, + match=r"Cubes with a mesh must be one dimensional", + ): + cube_to_polydata(cube_mesh) + + @pytest.fixture() + def operation(self): + return "from_unstructured" + + @pytest.fixture() + def cube(self, cube_mesh): + return cube_mesh[0] + + @pytest.mark.skip(reason="Meshes do not support crs currently") + def test_to_poly_crs(self, expected, actual): + return NotImplemented + + +class TestExtras: + @pytest.fixture() + def cube_1d_2d(self, cube_2d): + my_cube = cube_2d.copy() + lat_coord = my_cube.aux_coords[0] + lat_coord_small = lat_coord[0] + lat_coord_small.bounds = None + lat_coord_small.points = np.arange(len(lat_coord_small.points)) + my_cube.remove_coord(lat_coord) + my_cube.add_aux_coord(lat_coord_small, 1) + return my_cube + + def test_not_1d_or_2d(self, cube_1d_2d): + with pytest.raises( + NotImplementedError, + match=r"Only 1D and 2D coordinates are supported", + ): + cube_to_polydata(cube_1d_2d) + + def test_no_mesh_or_2d(self, cube_1d): + cube = cube_1d[0] + with pytest.raises( + NotImplementedError, + match=r"Cube must have a mesh or have 2 dimensions", + ): + cube_to_polydata(cube) diff --git a/lib/iris/tests/unit/experimental/geovista/test_extract_unstructured_region.py b/lib/iris/tests/unit/experimental/geovista/test_extract_unstructured_region.py new file mode 100644 index 0000000000..57babfc764 --- /dev/null +++ b/lib/iris/tests/unit/experimental/geovista/test_extract_unstructured_region.py @@ -0,0 +1,153 @@ +# 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.experimental.geovista.extract_unstructured_region` function.""" + +from unittest.mock import MagicMock, Mock + +from geovista.common import VTK_CELL_IDS, VTK_POINT_IDS +import numpy as np +import pytest + +from iris.experimental.geovista import extract_unstructured_region +from iris.tests.stock import sample_2d_latlons +from iris.tests.stock.mesh import sample_mesh_cube + + +class TestRegionExtraction: + @pytest.fixture() + def cube_2d(self): + return sample_2d_latlons() + + @pytest.fixture(params=["face", "node"], autouse=True) + def cube_mesh(self, request): + self.cube_mesh = sample_mesh_cube(location=request.param, n_z=10) + + @pytest.fixture() + def cube_mesh_edge(self): + return sample_mesh_cube(location="edge") + + @pytest.fixture(autouse=True) + def mocked_polydata(self): + mock_polydata_scalars = { + VTK_CELL_IDS: np.arange(2), + VTK_POINT_IDS: np.arange(14), + } + polydata = MagicMock() + polydata.__getitem__.side_effect = mock_polydata_scalars.__getitem__ + polydata.GetNumberOfCells.return_value = 3 + polydata.GetNumberOfPoints.return_value = 15 + self.mocked_polydata = polydata + + @pytest.fixture(autouse=True) + def mocked_region(self): + region = Mock() + region.enclosed.return_value = self.mocked_polydata + self.mocked_region = region + + def test_called_with(self): + extract_unstructured_region( + self.cube_mesh, self.mocked_polydata, self.mocked_region + ) + self.mocked_region.enclosed.assert_called_with(self.mocked_polydata) + + def test_kwarg(self): + extract_unstructured_region( + self.cube_mesh, + self.mocked_polydata, + self.mocked_region, + test="test", + ) + actual = self.mocked_region.enclosed.call_args.kwargs + assert actual["test"] == "test" + + @pytest.mark.parametrize( + "transpose_cube", [True, False], ids=["Transposed", "Not Transposed"] + ) + def test_indices(self, transpose_cube): + if transpose_cube: + self.cube_mesh.transpose() + extracted_region = extract_unstructured_region( + self.cube_mesh, self.mocked_polydata, self.mocked_region + ) + if self.cube_mesh.location == "face": + expected_length = len(self.mocked_polydata[VTK_CELL_IDS]) + else: + assert self.cube_mesh.location == "node" + expected_length = len(self.mocked_polydata[VTK_POINT_IDS]) + mesh_dim = self.cube_mesh.mesh_dim() + assert extracted_region.shape[mesh_dim] == expected_length + + def test_empty_indices(self): + mock_polydata_scalars = { + VTK_CELL_IDS: np.arange(0), + VTK_POINT_IDS: np.arange(0), + } + self.mocked_polydata.__getitem__.side_effect = mock_polydata_scalars.__getitem__ + with pytest.raises( + IndexError, match="No part of `polydata` falls within `region`." + ): + extract_unstructured_region( + self.cube_mesh, self.mocked_polydata, self.mocked_region + ) + + def test_recreate_mesh(self): + extracted_region = extract_unstructured_region( + self.cube_mesh, self.mocked_polydata, self.mocked_region + ) + if self.cube_mesh.location == "face": + assert extracted_region.mesh is not None + else: + assert extracted_region.mesh is None + + def test_new_mesh_coords(self): + extracted_region = extract_unstructured_region( + self.cube_mesh, self.mocked_polydata, self.mocked_region + ) + if self.cube_mesh.location == "face": + mesh_coords = extracted_region.coords(mesh_coords=True) + np.testing.assert_array_equal( + mesh_coords[0].bounds, + [[1200, 1201, 1202, 1203], [1204, 1205, 1206, 1207]], + ) + np.testing.assert_array_equal(mesh_coords[0].points, [3200, 3201]) + np.testing.assert_array_equal( + mesh_coords[1].bounds, + [[1100, 1101, 1102, 1103], [1104, 1105, 1106, 1107]], + ) + np.testing.assert_array_equal(mesh_coords[1].points, [3100, 3101]) + + def test_no_mesh(self, cube_2d): + cube = cube_2d + with pytest.raises(ValueError, match="Cube must have a mesh"): + extract_unstructured_region(cube, self.mocked_polydata, self.mocked_region) + + def test_edge_location(self, cube_mesh_edge): + with pytest.raises( + NotImplementedError, + match=f"cube.location must be `face` or `node`." + f" Found: {cube_mesh_edge.location}.", + ): + extract_unstructured_region( + cube_mesh_edge, self.mocked_polydata, self.mocked_region + ) + + def test_cube_and_poly_shapes_mismatch(self): + self.mocked_polydata.GetNumberOfCells.return_value = 4 + self.mocked_polydata.GetNumberOfPoints.return_value = 16 + polydata_length = () + if self.cube_mesh.location == "face": + polydata_length = self.mocked_polydata.GetNumberOfCells() + elif self.cube_mesh.location == "node": + polydata_length = self.mocked_polydata.GetNumberOfPoints() + with pytest.raises( + ValueError, + match=f"The mesh on the cube and the polydata" + f"must have the same shape." + f" Found Mesh: {self.cube_mesh.shape[self.cube_mesh.mesh_dim()]}," + f" Polydata: {polydata_length}.", + ): + extract_unstructured_region( + self.cube_mesh, self.mocked_polydata, self.mocked_region + ) diff --git a/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridAuxiliaryCoordinateVariable.py b/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridAuxiliaryCoordinateVariable.py index 4a45e9a4df..f283dd22db 100644 --- a/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridAuxiliaryCoordinateVariable.py +++ b/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridAuxiliaryCoordinateVariable.py @@ -8,6 +8,7 @@ standard behaviour. """ + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridConnectivityVariable.py b/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridConnectivityVariable.py index 5144729c7f..d412b8838a 100644 --- a/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridConnectivityVariable.py +++ b/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridConnectivityVariable.py @@ -8,6 +8,7 @@ standard behaviour. """ + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridGroup.py b/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridGroup.py index 9577955f97..6db067fe25 100644 --- a/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridGroup.py +++ b/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridGroup.py @@ -8,6 +8,7 @@ standard behaviour. """ + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridMeshVariable.py b/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridMeshVariable.py index ef5447382a..32c96cacbc 100644 --- a/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridMeshVariable.py +++ b/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridMeshVariable.py @@ -8,6 +8,7 @@ standard behaviour. """ + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridReader.py b/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridReader.py index cb2ae41d72..14278d3dff 100644 --- a/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridReader.py +++ b/lib/iris/tests/unit/experimental/ugrid/cf/test_CFUGridReader.py @@ -8,6 +8,7 @@ standard behaviour. """ + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/experimental/ugrid/load/test_ParseUgridOnLoad.py b/lib/iris/tests/unit/experimental/ugrid/load/test_ParseUgridOnLoad.py index 7ccdeee08b..8f85699037 100644 --- a/lib/iris/tests/unit/experimental/ugrid/load/test_ParseUgridOnLoad.py +++ b/lib/iris/tests/unit/experimental/ugrid/load/test_ParseUgridOnLoad.py @@ -7,6 +7,7 @@ todo: remove this module when experimental.ugrid is folded into standard behaviour. """ + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/experimental/ugrid/load/test_load_mesh.py b/lib/iris/tests/unit/experimental/ugrid/load/test_load_mesh.py index 382a36fa71..54ca5b8fcf 100644 --- a/lib/iris/tests/unit/experimental/ugrid/load/test_load_mesh.py +++ b/lib/iris/tests/unit/experimental/ugrid/load/test_load_mesh.py @@ -3,6 +3,7 @@ # 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.experimental.ugrid.load.load_mesh` function.""" + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip @@ -23,7 +24,8 @@ def test_calls_load_meshes(self): args = [("file_1", "file_2"), "my_var_name"] with PARSE_UGRID_ON_LOAD.context(): _ = load_mesh(args) - self.assertTrue(self.load_meshes_mock.called_with(args)) + assert self.load_meshes_mock.call_count == 1 + assert self.load_meshes_mock.call_args == ((args, None),) def test_returns_mesh(self): with PARSE_UGRID_ON_LOAD.context(): diff --git a/lib/iris/tests/unit/experimental/ugrid/load/test_load_meshes.py b/lib/iris/tests/unit/experimental/ugrid/load/test_load_meshes.py index 8932989252..cef142b424 100644 --- a/lib/iris/tests/unit/experimental/ugrid/load/test_load_meshes.py +++ b/lib/iris/tests/unit/experimental/ugrid/load/test_load_meshes.py @@ -3,6 +3,7 @@ # 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.experimental.ugrid.load.load_meshes` function.""" + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/experimental/ugrid/mesh/test_MeshCoord.py b/lib/iris/tests/unit/experimental/ugrid/mesh/test_MeshCoord.py index 2282bc07b9..78fa39060e 100644 --- a/lib/iris/tests/unit/experimental/ugrid/mesh/test_MeshCoord.py +++ b/lib/iris/tests/unit/experimental/ugrid/mesh/test_MeshCoord.py @@ -3,6 +3,7 @@ # 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 :class:`iris.experimental.ugrid.mesh.MeshCoord`.""" + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/experimental/ugrid/mesh/test_Mesh__from_coords.py b/lib/iris/tests/unit/experimental/ugrid/mesh/test_Mesh__from_coords.py index 31c5dbfcc0..aa45e0be70 100644 --- a/lib/iris/tests/unit/experimental/ugrid/mesh/test_Mesh__from_coords.py +++ b/lib/iris/tests/unit/experimental/ugrid/mesh/test_Mesh__from_coords.py @@ -3,6 +3,7 @@ # 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 :meth:`iris.experimental.ugrid.mesh.Mesh.from_coords`.""" + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/experimental/ugrid/metadata/test_ConnectivityMetadata.py b/lib/iris/tests/unit/experimental/ugrid/metadata/test_ConnectivityMetadata.py index fa62a9f7e2..91637ad20b 100644 --- a/lib/iris/tests/unit/experimental/ugrid/metadata/test_ConnectivityMetadata.py +++ b/lib/iris/tests/unit/experimental/ugrid/metadata/test_ConnectivityMetadata.py @@ -3,6 +3,7 @@ # 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 :class:`iris.experimental.ugrid.metadata.ConnectivityMetadata`.""" + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/experimental/ugrid/metadata/test_MeshCoordMetadata.py b/lib/iris/tests/unit/experimental/ugrid/metadata/test_MeshCoordMetadata.py index fc9242a8f9..0434149674 100644 --- a/lib/iris/tests/unit/experimental/ugrid/metadata/test_MeshCoordMetadata.py +++ b/lib/iris/tests/unit/experimental/ugrid/metadata/test_MeshCoordMetadata.py @@ -3,6 +3,7 @@ # 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 :class:`iris.experimental.ugrid.metadata.MeshCoordMetadata`.""" + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/experimental/ugrid/metadata/test_MeshMetadata.py b/lib/iris/tests/unit/experimental/ugrid/metadata/test_MeshMetadata.py index 080d94c188..abbb4c0304 100644 --- a/lib/iris/tests/unit/experimental/ugrid/metadata/test_MeshMetadata.py +++ b/lib/iris/tests/unit/experimental/ugrid/metadata/test_MeshMetadata.py @@ -3,6 +3,7 @@ # 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 :class:`iris.experimental.ugrid.metadata.MeshMetadata`.""" + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/experimental/ugrid/utils/test_recombine_submeshes.py b/lib/iris/tests/unit/experimental/ugrid/utils/test_recombine_submeshes.py index f01dc345fa..1c0fafdfc9 100644 --- a/lib/iris/tests/unit/experimental/ugrid/utils/test_recombine_submeshes.py +++ b/lib/iris/tests/unit/experimental/ugrid/utils/test_recombine_submeshes.py @@ -3,6 +3,7 @@ # 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 :func:`iris.experimental.ugrid.utils.recombine_submeshes`.""" + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/fileformats/cf/test_CFReader.py b/lib/iris/tests/unit/fileformats/cf/test_CFReader.py index 667c679bfb..80338ea71e 100644 --- a/lib/iris/tests/unit/fileformats/cf/test_CFReader.py +++ b/lib/iris/tests/unit/fileformats/cf/test_CFReader.py @@ -301,10 +301,13 @@ def test_promote_reference(self): def test_formula_terms_ignore(self): self.orography.dimensions = ["lat", "wibble"] - with mock.patch( - "iris.fileformats.netcdf._thread_safe_nc.DatasetWrapper", - return_value=self.dataset, - ), mock.patch("warnings.warn") as warn: + with ( + mock.patch( + "iris.fileformats.netcdf._thread_safe_nc.DatasetWrapper", + return_value=self.dataset, + ), + mock.patch("warnings.warn") as warn, + ): cf_group = CFReader("dummy").cf_group group = cf_group.promoted self.assertEqual(list(group.keys()), ["orography"]) @@ -313,10 +316,13 @@ def test_formula_terms_ignore(self): def test_auxiliary_ignore(self): self.x.dimensions = ["lat", "wibble"] - with mock.patch( - "iris.fileformats.netcdf._thread_safe_nc.DatasetWrapper", - return_value=self.dataset, - ), mock.patch("warnings.warn") as warn: + with ( + mock.patch( + "iris.fileformats.netcdf._thread_safe_nc.DatasetWrapper", + return_value=self.dataset, + ), + mock.patch("warnings.warn") as warn, + ): cf_group = CFReader("dummy").cf_group promoted = ["x", "orography"] group = cf_group.promoted @@ -329,10 +335,13 @@ def test_promoted_auxiliary_ignore(self): self.wibble = netcdf_variable("wibble", "lat wibble", np.float64) self.variables["wibble"] = self.wibble self.orography.coordinates = "wibble" - with mock.patch( - "iris.fileformats.netcdf._thread_safe_nc.DatasetWrapper", - return_value=self.dataset, - ), mock.patch("warnings.warn") as warn: + with ( + mock.patch( + "iris.fileformats.netcdf._thread_safe_nc.DatasetWrapper", + return_value=self.dataset, + ), + mock.patch("warnings.warn") as warn, + ): cf_group = CFReader("dummy").cf_group.promoted promoted = ["wibble", "orography"] self.assertEqual(set(cf_group.keys()), set(promoted)) diff --git a/lib/iris/tests/unit/fileformats/ff/test_FF2PP.py b/lib/iris/tests/unit/fileformats/ff/test_FF2PP.py index 4d031ac4a6..c21fc39821 100644 --- a/lib/iris/tests/unit/fileformats/ff/test_FF2PP.py +++ b/lib/iris/tests/unit/fileformats/ff/test_FF2PP.py @@ -85,13 +85,13 @@ def mock_for_extract_field(self, fields, x=None, y=None): ff2pp._ff_header.grid = mock.Mock(return_value=grid) open_func = "builtins.open" - with mock.patch( - "iris.fileformats._ff._parse_binary_stream", return_value=[0] - ), mock.patch(open_func), mock.patch( - "struct.unpack_from", return_value=[4] - ), mock.patch( - "iris.fileformats.pp.make_pp_field", side_effect=fields - ), mock.patch("iris.fileformats._ff.FF2PP._payload", return_value=(0, 0)): + with ( + mock.patch("iris.fileformats._ff._parse_binary_stream", return_value=[0]), + mock.patch(open_func), + mock.patch("struct.unpack_from", return_value=[4]), + mock.patch("iris.fileformats.pp.make_pp_field", side_effect=fields), + mock.patch("iris.fileformats._ff.FF2PP._payload", return_value=(0, 0)), + ): yield ff2pp def _mock_lbc(self, **kwargs): 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 845b88536a..9d1c1d742a 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 @@ -3,6 +3,7 @@ # 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 module :mod:`iris.fileformats._nc_load_rules.actions`.""" + from pathlib import Path import shutil import tempfile diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__grid_mappings.py b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__grid_mappings.py index 72e9448255..8c2e30a902 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__grid_mappings.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__grid_mappings.py @@ -8,6 +8,7 @@ Here, *specifically* testcases relating to grid-mappings and dim-coords. """ + import iris.tests as tests # isort: skip import iris.coord_systems as ics diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__hybrid_formulae.py b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__hybrid_formulae.py index 5af6d6fa1d..65b0ecd94e 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__hybrid_formulae.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__hybrid_formulae.py @@ -8,6 +8,7 @@ Test rules activation relating to hybrid vertical coordinates. """ + import iris.tests as tests # isort: skip import iris.fileformats._nc_load_rules.helpers as hh 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 e6a2c203b7..499088a802 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 @@ -9,6 +9,7 @@ rotated and non-rotated. """ + import iris.tests as tests # isort: skip from iris.coord_systems import GeogCS, RotatedGeogCS diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__miscellaneous.py b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__miscellaneous.py index a7d5a10e73..15d8afe880 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__miscellaneous.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__miscellaneous.py @@ -12,6 +12,7 @@ * ancillary variables """ + import iris.tests as tests # isort: skip from iris.coords import AncillaryVariable, AuxCoord, CellMeasure diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__time_coords.py b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__time_coords.py index b3c2fe9b0b..c19dffd6e2 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__time_coords.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/actions/test__time_coords.py @@ -8,6 +8,7 @@ Tests for rules activation relating to 'time' and 'time_period' coords. """ + import iris.tests as tests # isort: skip from iris.coords import AuxCoord, DimCoord diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/engine/test_engine.py b/lib/iris/tests/unit/fileformats/nc_load_rules/engine/test_engine.py index 7aaca67326..71280e5f60 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/engine/test_engine.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/engine/test_engine.py @@ -3,6 +3,7 @@ # 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.fileformats._nc_load_rules.engine` module.""" + from unittest import mock from iris.fileformats._nc_load_rules.engine import Engine, FactEntity diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_build_auxiliary_coordinate.py b/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_build_auxiliary_coordinate.py index 73533a9c33..b43317901f 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_build_auxiliary_coordinate.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_build_auxiliary_coordinate.py @@ -6,6 +6,7 @@ build_auxilliary_coordinate`. """ + # import iris tests first so that some things can be initialised before # importing anything else import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_build_oblique_mercator_coordinate_system.py b/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_build_oblique_mercator_coordinate_system.py index 3e12e33762..50b171655e 100644 --- a/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_build_oblique_mercator_coordinate_system.py +++ b/lib/iris/tests/unit/fileformats/nc_load_rules/helpers/test_build_oblique_mercator_coordinate_system.py @@ -3,6 +3,7 @@ # 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 function :func:`iris.fileformats._nc_load_rules.helpers.build_oblique_mercator_coordinate_system`.""" + from typing import List, NamedTuple, Type from unittest import mock diff --git a/lib/iris/tests/unit/fileformats/netcdf/loader/test__chunk_control.py b/lib/iris/tests/unit/fileformats/netcdf/loader/test__chunk_control.py index bc7911578a..d4c813502f 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/loader/test__chunk_control.py +++ b/lib/iris/tests/unit/fileformats/netcdf/loader/test__chunk_control.py @@ -76,6 +76,15 @@ def test_default(tmp_filepath, save_cubelist_with_sigma): assert sigma.lazy_bounds().chunksize == (4, 2) +def test_netcdf_v3(): + # Just check that it does not fail when loading NetCDF v3 data + path = iris.tests.get_data_path( + ["NetCDF", "global", "xyt", "SMALL_total_column_co2.nc.k2"] + ) + with CHUNK_CONTROL.set(time=-1): + iris.load(path) + + def test_control_global(tmp_filepath, save_cubelist_with_sigma): cube_varname, _ = save_cubelist_with_sigma with CHUNK_CONTROL.set(model_level_number=2): @@ -133,8 +142,9 @@ def test_invalid_var_name(tmp_filepath, save_cubelist_with_sigma): def test_control_multiple(tmp_filepath, save_cubelist_with_sigma): cube_varname, sigma_varname = save_cubelist_with_sigma - with CHUNK_CONTROL.set(cube_varname, model_level_number=2), CHUNK_CONTROL.set( - sigma_varname, model_level_number=3 + with ( + CHUNK_CONTROL.set(cube_varname, model_level_number=2), + CHUNK_CONTROL.set(sigma_varname, model_level_number=3), ): cubes = CubeList(loader.load_cubes(tmp_filepath)) cube = cubes.extract_cube(cube_varname) diff --git a/lib/iris/tests/unit/fileformats/netcdf/loader/test__get_cf_var_data.py b/lib/iris/tests/unit/fileformats/netcdf/loader/test__get_cf_var_data.py index 9aa696bccd..92cb93496e 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/loader/test__get_cf_var_data.py +++ b/lib/iris/tests/unit/fileformats/netcdf/loader/test__get_cf_var_data.py @@ -3,6 +3,7 @@ # 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.fileformats.netcdf._get_cf_var_data` function.""" + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver.py b/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver.py index 744051f02d..f067993bed 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver.py +++ b/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver.py @@ -34,7 +34,6 @@ from iris.cube import Cube from iris.fileformats.netcdf import Saver, _thread_safe_nc import iris.tests.stock as stock -from iris.warnings import IrisMaskValueMatchWarning class Test_write(tests.IrisTest): @@ -548,76 +547,6 @@ def test_mask_default_fill_value(self): self.assertNotIn("_FillValue", var.ncattrs()) self.assertTrue(var[index].mask) - def test_contains_fill_value_passed(self): - # Test that a warning is raised if the data contains the fill value. - cube = self._make_cube(">f4") - fill_value = 1 - with self.assertWarnsRegex( - IrisMaskValueMatchWarning, - "contains unmasked data points equal to the fill-value", - ): - with self._netCDF_var(cube, fill_value=fill_value): - pass - - def test_contains_fill_value_byte(self): - # Test that a warning is raised if the data contains the fill value - # when it is of a byte type. - cube = self._make_cube(">i1") - fill_value = 1 - with self.assertWarnsRegex( - IrisMaskValueMatchWarning, - "contains unmasked data points equal to the fill-value", - ): - with self._netCDF_var(cube, fill_value=fill_value): - pass - - def test_contains_default_fill_value(self): - # Test that a warning is raised if the data contains the default fill - # value if no fill_value argument is supplied. - cube = self._make_cube(">f4") - cube.data[0, 0] = _thread_safe_nc.default_fillvals["f4"] - with self.assertWarnsRegex( - IrisMaskValueMatchWarning, - "contains unmasked data points equal to the fill-value", - ): - with self._netCDF_var(cube): - pass - - def test_contains_default_fill_value_byte(self): - # Test that no warning is raised if the data contains the default fill - # value if no fill_value argument is supplied when the data is of a - # byte type. - cube = self._make_cube(">i1") - with self.assertNoWarningsRegexp(r"\(fill\|mask\)"): - with self._netCDF_var(cube): - pass - - def test_contains_masked_fill_value(self): - # Test that no warning is raised if the data contains the fill_value at - # a masked point. - fill_value = 1 - cube = self._make_cube(">f4", masked_value=fill_value) - with self.assertNoWarningsRegexp(r"\(fill\|mask\)"): - with self._netCDF_var(cube, fill_value=fill_value): - pass - - def test_masked_byte_default_fill_value(self): - # Test that a warning is raised when saving masked byte data with no - # fill value supplied. - cube = self._make_cube(">i1", masked_value=1) - with self.assertNoWarningsRegexp(r"\(fill\|mask\)"): - with self._netCDF_var(cube): - pass - - def test_masked_byte_fill_value_passed(self): - # Test that no warning is raised when saving masked byte data with a - # fill value supplied if the the data does not contain the fill_value. - fill_value = 100 - cube = self._make_cube(">i1", masked_value=2) - with self.assertNoWarningsRegexp(r"\(fill\|mask\)"): - with self._netCDF_var(cube, fill_value=fill_value): - pass - class Test_cf_valid_var_name(tests.IrisTest): def test_no_replacement(self): diff --git a/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver__lazy_stream_data.py b/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver__lazy_stream_data.py index c1bc411564..e02f6b16c8 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver__lazy_stream_data.py +++ b/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver__lazy_stream_data.py @@ -9,16 +9,15 @@ integration tests. """ + from unittest import mock -import warnings import dask.array as da import numpy as np import pytest import iris.fileformats.netcdf._thread_safe_nc as threadsafe_nc -from iris.fileformats.netcdf.saver import Saver, _FillvalueCheckInfo -from iris.warnings import IrisMaskValueMatchWarning +from iris.fileformats.netcdf.saver import Saver class Test__lazy_stream_data: @@ -88,10 +87,7 @@ def test_data_save(self, compute, data_form): cf_var = self.mock_var( data.shape, with_data_array=(data_form == "emulateddata") ) - fill_value = -1.0 # not occurring in data - saver._lazy_stream_data( - data=data, fill_value=fill_value, fill_warn=True, cf_var=cf_var - ) + saver._lazy_stream_data(data=data, cf_var=cf_var) if data_form == "lazydata": expect_n_setitem = 0 expect_n_delayed = 1 @@ -107,73 +103,11 @@ def test_data_save(self, compute, data_form): assert len(saver._delayed_writes) == expect_n_delayed if data_form == "lazydata": - result_data, result_writer, fill_info = saver._delayed_writes[0] + result_data, result_writer = saver._delayed_writes[0] assert result_data is data assert isinstance(result_writer, threadsafe_nc.NetCDFWriteProxy) - assert isinstance(fill_info, _FillvalueCheckInfo) elif data_form == "realdata": cf_var.__setitem__.assert_called_once_with(slice(None), data) else: assert data_form == "emulateddata" cf_var._data_array == mock.sentinel.exact_data_array - - def test_warnings(self, compute, data_form): - """For real data, fill-value warnings are issued immediately. - For lazy data, warnings are returned from computing a delayed completion. - For 'emulated' data (direct array transfer), no checks + no warnings ever. - - N.B. The 'compute' keyword has **no effect** on this : It only causes delayed - writes to be automatically actioned on exiting a Saver context. - Streaming *always* creates delayed writes for lazy data, since this is required - to make dask distributed operation work. - """ - saver = self.saver(compute=compute) - - data = np.arange(5.0) - if data_form == "lazydata": - data = da.from_array(data) - - fill_value = 2.0 # IS occurring in data - cf_var = self.mock_var( - data.shape, with_data_array=(data_form == "emulateddata") - ) - - # Do initial save. When compute=True, this issues warnings - with warnings.catch_warnings(record=True) as logged_warnings: - saver._lazy_stream_data( - data=data, fill_value=fill_value, fill_warn=True, cf_var=cf_var - ) - - # Check warnings issued by initial call. - issued_warnings = [log.message for log in logged_warnings] - if data_form == "lazydata": - n_expected_warnings = 0 - elif data_form == "realdata": - n_expected_warnings = 1 - else: - # No checks in the emulated case - assert data_form == "emulateddata" - n_expected_warnings = 0 - assert len(issued_warnings) == n_expected_warnings - - # Complete the write : any delayed warnings should be *returned*. - # NOTE: - # (1) this still works when there are no delayed writes. - # (2) the Saver 'compute' keyword makes no difference to this usage, as it - # *only* affects what happens when the saver context exits. - result2 = saver.delayed_completion().compute() - issued_warnings += list(result2) - - # Check warnings issued during 'completion'. - if data_form == "emulateddata": - # No checks in this case, ever. - n_expected_warnings = 0 - else: - # Otherwise, either way, a suitable warning should now have been produced. - n_expected_warnings = 1 - assert len(issued_warnings) == n_expected_warnings - if n_expected_warnings > 0: - warning = issued_warnings[0] - msg = "contains unmasked data points equal to the fill-value, 2.0" - assert isinstance(warning, IrisMaskValueMatchWarning) - assert msg in warning.args[0] diff --git a/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver__ugrid.py b/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver__ugrid.py index 241ff5a5cc..14da76ded8 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver__ugrid.py +++ b/lib/iris/tests/unit/fileformats/netcdf/saver/test_Saver__ugrid.py @@ -8,6 +8,7 @@ :mod:`iris.tests.unit.fileformats.netcdf.test_Saver__lazy.` """ + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/fileformats/netcdf/saver/test__data_fillvalue_check.py b/lib/iris/tests/unit/fileformats/netcdf/saver/test__data_fillvalue_check.py deleted file mode 100644 index 9fb7485734..0000000000 --- a/lib/iris/tests/unit/fileformats/netcdf/saver/test__data_fillvalue_check.py +++ /dev/null @@ -1,105 +0,0 @@ -# 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 :func:`iris.fileformats.netcdf.saver._data_fillvalue_check`. - -Note: now runs all testcases on both real + lazy data. - -""" - -# Import iris.tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests # isort:skip -import collections - -import dask.array as da -import numpy as np - -from iris.fileformats.netcdf.saver import _data_fillvalue_check - - -class Check__fillvalueandmasking: - def _call_target(self, fill_value, keys, vals): - data = np.zeros(20, dtype=np.float32) - if any(np.ma.isMaskedArray(val) for val in vals): - # N.B. array is masked if "vals" is, but has no masked points initially. - data = np.ma.masked_array(data, mask=np.zeros_like(data)) - - for key, val in zip(keys, vals): - data[key] = val - - if hasattr(self.arraylib, "compute"): - data = da.from_array(data, chunks=-1) - - results = _data_fillvalue_check( - arraylib=self.arraylib, data=data, check_value=fill_value - ) - - if hasattr(results, "compute"): - results = results.compute() - - # Return a named tuple, for named-property access to the 2 result values. - result = collections.namedtuple("_", ["is_masked", "contains_value"])(*results) - return result - - def test_no_fill_value_not_masked(self): - # Test when the fill value is not present and the data is not masked - keys = [slice(0, 10), slice(10, 15)] - vals = [np.arange(10), np.arange(5)] - fill_value = 16 - target = self._call_target(fill_value, keys, vals) - self.assertFalse(target.contains_value) - self.assertFalse(target.is_masked) - - def test_contains_fill_value_not_masked(self): - # Test when the fill value is present and the data is not masked - keys = [slice(0, 10), slice(10, 15)] - vals = [np.arange(10), np.arange(5)] - fill_value = 5 - target = self._call_target(fill_value, keys, vals) - self.assertTrue(target.contains_value) - self.assertFalse(target.is_masked) - - def test_no_fill_value_masked(self): - # Test when the fill value is not present and the data is masked - keys = [slice(0, 10), slice(10, 15)] - vals = [np.arange(10), np.ma.masked_equal(np.arange(5), 3)] - fill_value = 16 - target = self._call_target(fill_value, keys, vals) - self.assertFalse(target.contains_value) - self.assertTrue(target.is_masked) - - def test_contains_fill_value_masked(self): - # Test when the fill value is present and the data is masked - keys = [slice(0, 10), slice(10, 15)] - vals = [np.arange(10), np.ma.masked_equal(np.arange(5), 3)] - fill_value = 5 - target = self._call_target(fill_value, keys, vals) - self.assertTrue(target.contains_value) - self.assertTrue(target.is_masked) - - def test_fill_value_None(self): - # Test when the fill value is None - keys = [slice(0, 10), slice(10, 15)] - vals = [np.arange(10), np.arange(5)] - fill_value = None - target = self._call_target(fill_value, keys, vals) - self.assertFalse(target.contains_value) - - def test_contains_masked_fill_value(self): - # Test when the fill value is present but masked the data is masked - keys = [slice(0, 10), slice(10, 15)] - vals = [np.arange(10), np.ma.masked_equal(np.arange(10, 15), 13)] - fill_value = 13 - target = self._call_target(fill_value, keys, vals) - self.assertFalse(target.contains_value) - self.assertTrue(target.is_masked) - - -class Test__real(Check__fillvalueandmasking, tests.IrisTest): - arraylib = np - - -class Test__lazy(Check__fillvalueandmasking, tests.IrisTest): - arraylib = da diff --git a/lib/iris/tests/unit/fileformats/netcdf/saver/test__fillvalue_report.py b/lib/iris/tests/unit/fileformats/netcdf/saver/test__fillvalue_report.py deleted file mode 100644 index 0b37070241..0000000000 --- a/lib/iris/tests/unit/fileformats/netcdf/saver/test__fillvalue_report.py +++ /dev/null @@ -1,113 +0,0 @@ -# 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 :func:`iris.fileformats.netcdf.saver._fillvalue_report`.""" -import warnings - -import numpy as np -import pytest - -from iris.fileformats.netcdf._thread_safe_nc import default_fillvals -from iris.fileformats.netcdf.saver import _fillvalue_report, _FillvalueCheckInfo -from iris.warnings import IrisSaverFillValueWarning - - -class Test__fillvaluereport: - @pytest.mark.parametrize("is_bytes", [True, False], ids=["ByteData", "NonbyteData"]) - @pytest.mark.parametrize( - "is_masked", [True, False], ids=["MaskedData", "NonmaskedData"] - ) - @pytest.mark.parametrize( - "contains_fv", [True, False], ids=["FillInData", "NofillInData"] - ) - @pytest.mark.parametrize( - "given_user_fv", [True, False], ids=["WithUserfill", "NoUserfill"] - ) - def test_fillvalue_checking(self, is_bytes, is_masked, contains_fv, given_user_fv): - dtype_code = "u1" if is_bytes else "f4" - dtype = np.dtype(dtype_code) - if given_user_fv: - user_fill = 123 if is_bytes else 1.234 - check_value = user_fill - else: - user_fill = None - check_value = default_fillvals[dtype_code] - - fill_info = _FillvalueCheckInfo( - user_value=user_fill, - check_value=check_value, - dtype=dtype, - varname="", - ) - - # Work out expected action, according to intended logic. - if is_bytes and is_masked and not given_user_fv: - msg_fragment = "'' contains byte data with masked points" - elif contains_fv: - msg_fragment = ( - "'' contains unmasked data points equal to the fill-value" - ) - else: - msg_fragment = None - - # Trial the action - result = _fillvalue_report( - fill_info, - is_masked=is_masked, - contains_fill_value=contains_fv, - warn=False, - ) - - # Check the result - if msg_fragment is None: - assert result is None - else: - assert isinstance(result, Warning) - assert msg_fragment in result.args[0] - - @pytest.mark.parametrize( - "has_collision", - [True, False], - ids=["WithFvCollision", "NoFvCollision"], - ) - def test_warn(self, has_collision): - fill_info = _FillvalueCheckInfo( - user_value=1.23, - check_value=1.23, - dtype=np.float32, - varname="", - ) - - # Check results - if has_collision: - # Check that we get the expected warning - expected_msg = ( - "'' contains unmasked data points equal to the fill-value" - ) - # Enter a warnings context that checks for the error. - warning_context = pytest.warns( - IrisSaverFillValueWarning, match=expected_msg - ) - warning_context.__enter__() - else: - # Check that we get NO warning of the expected type. - warnings.filterwarnings("error", category=IrisSaverFillValueWarning) - - # Do call: it should raise AND return a warning, ONLY IF there was a collision. - result = _fillvalue_report( - fill_info, - is_masked=True, - contains_fill_value=has_collision, - warn=True, - ) - - # Check result - if has_collision: - # Fail if no warning was raised .. - warning_context.__exit__(None, None, None) - # .. or result does not have the expected message content - assert expected_msg in result.args[0] - else: - # Fail if any warning result was produced. - assert result is None diff --git a/lib/iris/tests/unit/fileformats/netcdf/saver/test_save.py b/lib/iris/tests/unit/fileformats/netcdf/saver/test_save.py index 1f0a39f050..ae85dc1aab 100644 --- a/lib/iris/tests/unit/fileformats/netcdf/saver/test_save.py +++ b/lib/iris/tests/unit/fileformats/netcdf/saver/test_save.py @@ -3,6 +3,7 @@ # 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.fileformats.netcdf.save` function.""" + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/fileformats/pp/test__field_gen.py b/lib/iris/tests/unit/fileformats/pp/test__field_gen.py index 80b90fc8d2..f1018d8df4 100644 --- a/lib/iris/tests/unit/fileformats/pp/test__field_gen.py +++ b/lib/iris/tests/unit/fileformats/pp/test__field_gen.py @@ -34,11 +34,14 @@ def make_pp_field_override(*args): return result open_func = "builtins.open" - with mock.patch("numpy.fromfile", return_value=[0]), mock.patch( - open_func - ), mock.patch("struct.unpack_from", return_value=[4]), mock.patch( - "iris.fileformats.pp.make_pp_field", - side_effect=make_pp_field_override, + with ( + mock.patch("numpy.fromfile", return_value=[0]), + mock.patch(open_func), + mock.patch("struct.unpack_from", return_value=[4]), + mock.patch( + "iris.fileformats.pp.make_pp_field", + side_effect=make_pp_field_override, + ), ): yield diff --git a/lib/iris/tests/unit/plot/test_hist.py b/lib/iris/tests/unit/plot/test_hist.py index feef8f1062..9c1740587c 100644 --- a/lib/iris/tests/unit/plot/test_hist.py +++ b/lib/iris/tests/unit/plot/test_hist.py @@ -3,6 +3,7 @@ # 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.plot.hist` function.""" + # Import iris.tests first so that some things can be initialised before # importing anything else. import iris.tests as tests # isort:skip diff --git a/lib/iris/tests/unit/representation/cube_printout/test_CubePrintout.py b/lib/iris/tests/unit/representation/cube_printout/test_CubePrintout.py index d7b617d848..e3ee535346 100644 --- a/lib/iris/tests/unit/representation/cube_printout/test_CubePrintout.py +++ b/lib/iris/tests/unit/representation/cube_printout/test_CubePrintout.py @@ -3,6 +3,7 @@ # 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 :class:`iris._representation.cube_printout.CubePrintout`.""" + import iris.tests as tests # isort:skip import numpy as np @@ -124,9 +125,9 @@ def test_columns_long_coordname(self): def test_columns_long_attribute(self): cube = Cube([0], long_name="short", units=1) - cube.attributes[ - "very_very_very_very_very_long_name" - ] = "longish string extends beyond dim columns" + cube.attributes["very_very_very_very_very_long_name"] = ( + "longish string extends beyond dim columns" + ) rep = cube_replines(cube) expected = [ "short / (1) (-- : 1)", diff --git a/lib/iris/tests/unit/representation/cube_printout/test_Table.py b/lib/iris/tests/unit/representation/cube_printout/test_Table.py index 0e00da7c42..6c765516b1 100644 --- a/lib/iris/tests/unit/representation/cube_printout/test_Table.py +++ b/lib/iris/tests/unit/representation/cube_printout/test_Table.py @@ -3,6 +3,7 @@ # 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 :class:`iris._representation.cube_printout.Table`.""" + from iris._representation.cube_printout import Table import iris.tests as tests diff --git a/lib/iris/tests/unit/representation/cube_summary/test_CubeSummary.py b/lib/iris/tests/unit/representation/cube_summary/test_CubeSummary.py index 74b24899b1..ec568ed13d 100644 --- a/lib/iris/tests/unit/representation/cube_summary/test_CubeSummary.py +++ b/lib/iris/tests/unit/representation/cube_summary/test_CubeSummary.py @@ -4,13 +4,12 @@ # See LICENSE in the root of the repository for full licensing details. """Unit tests for :class:`iris._representation.cube_summary.CubeSummary`.""" -# Import iris.tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests # isort:skip - +import dask.array as da import numpy as np +import pytest from iris._representation.cube_summary import CubeSummary +from iris.aux_factory import HybridHeightFactory from iris.coords import AncillaryVariable, AuxCoord, CellMeasure, CellMethod, DimCoord from iris.cube import Cube from iris.tests.stock.mesh import sample_mesh_cube @@ -29,8 +28,9 @@ def example_cube(): return cube -class Test_CubeSummary(tests.IrisTest): - def setUp(self): +class Test_CubeSummary: + @pytest.fixture(autouse=True) + def _setup(self): self.cube = example_cube() def test_header(self): @@ -38,15 +38,15 @@ def test_header(self): header_left = rep.header.nameunit header_right = rep.header.dimension_header.contents - self.assertEqual(header_left, "air_temperature / (K)") - self.assertEqual(header_right, ["latitude: 3", "-- : 2"]) + assert header_left == "air_temperature / (K)" + assert header_right == ["latitude: 3", "-- : 2"] def test_blank_cube(self): cube = Cube([1, 2]) rep = CubeSummary(cube) - self.assertEqual(rep.header.nameunit, "unknown / (unknown)") - self.assertEqual(rep.header.dimension_header.contents, ["-- : 2"]) + assert rep.header.nameunit == "unknown / (unknown)" + assert rep.header.dimension_header.contents == ["-- : 2"] expected_vector_sections = [ "Dimension coordinates:", @@ -56,11 +56,11 @@ def test_blank_cube(self): "Cell measures:", "Ancillary variables:", ] - self.assertEqual(list(rep.vector_sections.keys()), expected_vector_sections) + assert list(rep.vector_sections.keys()) == expected_vector_sections for title in expected_vector_sections: vector_section = rep.vector_sections[title] - self.assertEqual(vector_section.contents, []) - self.assertTrue(vector_section.is_empty()) + assert vector_section.contents == [] + assert vector_section.is_empty() expected_scalar_sections = [ "Mesh:", @@ -71,18 +71,18 @@ def test_blank_cube(self): "Attributes:", ] - self.assertEqual(list(rep.scalar_sections.keys()), expected_scalar_sections) + assert list(rep.scalar_sections.keys()) == expected_scalar_sections for title in expected_scalar_sections: scalar_section = rep.scalar_sections[title] - self.assertEqual(scalar_section.contents, []) - self.assertTrue(scalar_section.is_empty()) + assert scalar_section.contents == [] + assert scalar_section.is_empty() def test_vector_coord(self): rep = CubeSummary(self.cube) dim_section = rep.vector_sections["Dimension coordinates:"] - self.assertEqual(len(dim_section.contents), 1) - self.assertFalse(dim_section.is_empty()) + assert len(dim_section.contents) == 1 + assert not dim_section.is_empty() dim_summary = dim_section.contents[0] @@ -90,9 +90,9 @@ def test_vector_coord(self): dim_chars = dim_summary.dim_chars extra = dim_summary.extra - self.assertEqual(name, "latitude") - self.assertEqual(dim_chars, ["x", "-"]) - self.assertEqual(extra, "") + assert name == "latitude" + assert dim_chars == ["x", "-"] + assert extra == "" def test_scalar_coord(self): cube = self.cube @@ -114,30 +114,83 @@ def test_scalar_coord(self): scalar_section = rep.scalar_sections["Scalar coordinates:"] - self.assertEqual(len(scalar_section.contents), 4) + assert len(scalar_section.contents) == 4 no_bounds_summary = scalar_section.contents[0] bounds_summary = scalar_section.contents[1] text_summary_simple = scalar_section.contents[2] text_summary_awkward = scalar_section.contents[3] - self.assertEqual(no_bounds_summary.name, "bar") - self.assertEqual(no_bounds_summary.content, "10 K") - self.assertEqual(no_bounds_summary.extra, "") + assert no_bounds_summary.name == "bar" + assert no_bounds_summary.content == "10 K" + assert no_bounds_summary.extra == "" + + assert bounds_summary.name == "foo" + assert bounds_summary.content == "10 K, bound=(5, 15) K" + assert bounds_summary.extra == "" + + assert text_summary_simple.name == "foo" + assert text_summary_simple.content == "this and that" + assert text_summary_simple.lines == ["this and that"] + assert text_summary_simple.extra == "key=42, key2='value-str'" + + assert text_summary_awkward.name == "foo_2" + assert text_summary_awkward.content == r"'a is\nb\n and c'" + assert text_summary_awkward.lines == ["a is", "b", " and c"] + assert text_summary_awkward.extra == "" + + @pytest.mark.parametrize("bounds", ["withbounds", "nobounds"]) + def test_lazy_scalar_coord(self, bounds): + """Check when we print 'lazy' instead of values for a lazy scalar coord.""" + coord = AuxCoord(da.ones((), dtype=float), long_name="foo") + if bounds == "withbounds": + # These might be real or lazy -- it makes no difference. + coord.bounds = np.arange(2.0) + cube = Cube([0.0], aux_coords_and_dims=[(coord, ())]) + + rep = CubeSummary(cube) - self.assertEqual(bounds_summary.name, "foo") - self.assertEqual(bounds_summary.content, "10 K, bound=(5, 15) K") - self.assertEqual(bounds_summary.extra, "") + summary = rep.scalar_sections["Scalar coordinates:"].contents[0] + assert summary.name == "foo" + expect_content = "" + if bounds == "withbounds": + expect_content += "+bound" + assert summary.content == expect_content + + @pytest.mark.parametrize("deps", ["deps_all_real", "deps_some_lazy"]) + def test_hybrid_scalar_coord(self, deps): + """Check whether we print a value or '', for a hybrid scalar coord.""" + # NOTE: hybrid coords are *always* lazy (at least for now). However, as long as + # no dependencies are lazy, then we print a value rather than "". + + # Construct a test hybrid coord, using HybridHeight as a template because that + # is both a common case and a fairly simple one (only 3 dependencies). + # Note: *not* testing with bounds, since lazy bounds always print the same way. + all_deps_real = deps == "deps_all_real" + aux_coords = [ + AuxCoord(1.0, long_name=name, units=units) + for name, units in (("delta", "m"), ("sigma", "1"), ("orography", "m")) + ] + if not all_deps_real: + # Make one dependency lazy + aux_coords[0].points = aux_coords[0].lazy_points() + + cube = Cube( + [0.0], + aux_coords_and_dims=[(co, ()) for co in aux_coords], + aux_factories=[HybridHeightFactory(*aux_coords)], + ) - self.assertEqual(text_summary_simple.name, "foo") - self.assertEqual(text_summary_simple.content, "this and that") - self.assertEqual(text_summary_simple.lines, ["this and that"]) - self.assertEqual(text_summary_simple.extra, "key=42, key2='value-str'") + rep = CubeSummary(cube) - self.assertEqual(text_summary_awkward.name, "foo_2") - self.assertEqual(text_summary_awkward.content, r"'a is\nb\n and c'") - self.assertEqual(text_summary_awkward.lines, ["a is", "b", " and c"]) - self.assertEqual(text_summary_awkward.extra, "") + summary = rep.scalar_sections["Scalar coordinates:"].contents[0] + assert summary.name == "altitude" + # Check that the result shows lazy with lazy deps, or value when all real + if all_deps_real: + expect_content = "2.0 m" + else: + expect_content = " m" + assert summary.content == expect_content def test_cell_measure(self): cube = self.cube @@ -146,11 +199,11 @@ def test_cell_measure(self): rep = CubeSummary(cube) cm_section = rep.vector_sections["Cell measures:"] - self.assertEqual(len(cm_section.contents), 1) + assert len(cm_section.contents) == 1 cm_summary = cm_section.contents[0] - self.assertEqual(cm_summary.name, "foo") - self.assertEqual(cm_summary.dim_chars, ["x", "-"]) + assert cm_summary.name == "foo" + assert cm_summary.dim_chars == ["x", "-"] def test_ancillary_variable(self): cube = self.cube @@ -159,11 +212,11 @@ def test_ancillary_variable(self): rep = CubeSummary(cube) av_section = rep.vector_sections["Ancillary variables:"] - self.assertEqual(len(av_section.contents), 1) + assert len(av_section.contents) == 1 av_summary = av_section.contents[0] - self.assertEqual(av_summary.name, "foo") - self.assertEqual(av_summary.dim_chars, ["x", "-"]) + assert av_summary.name == "foo" + assert av_summary.dim_chars == ["x", "-"] def test_attributes(self): cube = self.cube @@ -180,7 +233,7 @@ def test_attributes(self): # Note: a string with \n or \t in it gets "repr-d". # Other strings don't (though in coord 'extra' lines, they do.) - self.assertEqual(attribute_contents, expected_contents) + assert attribute_contents == expected_contents def test_cell_methods(self): cube = self.cube @@ -194,25 +247,25 @@ def test_cell_methods(self): rep = CubeSummary(cube) cell_method_section = rep.scalar_sections["Cell methods:"] expected_contents = ["0: x: y: mean", "1: x: mean"] - self.assertEqual(cell_method_section.contents, expected_contents) + assert cell_method_section.contents == expected_contents def test_scalar_cube(self): cube = self.cube while cube.ndim > 0: cube = cube[0] rep = CubeSummary(cube) - self.assertEqual(rep.header.nameunit, "air_temperature / (K)") - self.assertTrue(rep.header.dimension_header.scalar) - self.assertEqual(rep.header.dimension_header.dim_names, []) - self.assertEqual(rep.header.dimension_header.shape, []) - self.assertEqual(rep.header.dimension_header.contents, ["scalar cube"]) - self.assertEqual(len(rep.vector_sections), 6) - self.assertTrue(all(sect.is_empty() for sect in rep.vector_sections.values())) - self.assertEqual(len(rep.scalar_sections), 6) - self.assertEqual(len(rep.scalar_sections["Scalar coordinates:"].contents), 1) - self.assertTrue(rep.scalar_sections["Scalar cell measures:"].is_empty()) - self.assertTrue(rep.scalar_sections["Attributes:"].is_empty()) - self.assertTrue(rep.scalar_sections["Cell methods:"].is_empty()) + assert rep.header.nameunit == "air_temperature / (K)" + assert rep.header.dimension_header.scalar + assert rep.header.dimension_header.dim_names == [] + assert rep.header.dimension_header.shape == [] + assert rep.header.dimension_header.contents == ["scalar cube"] + assert len(rep.vector_sections) == 6 + assert all(sect.is_empty() for sect in rep.vector_sections.values()) + assert len(rep.scalar_sections) == 6 + assert len(rep.scalar_sections["Scalar coordinates:"].contents) == 1 + assert rep.scalar_sections["Scalar cell measures:"].is_empty() + assert rep.scalar_sections["Attributes:"].is_empty() + assert rep.scalar_sections["Cell methods:"].is_empty() def test_coord_attributes(self): cube = self.cube @@ -225,8 +278,8 @@ def test_coord_attributes(self): co1_summ = rep.vector_sections["Dimension coordinates:"].contents[0] co2_summ = rep.vector_sections["Auxiliary coordinates:"].contents[0] # Notes: 'b' is same so does not appear; sorted order; quoted strings. - self.assertEqual(co1_summ.extra, "a=1") - self.assertEqual(co2_summ.extra, "a=7, text='ok', text2='multi\\nline', z=77") + assert co1_summ.extra == "a=1" + assert co2_summ.extra == "a=7, text='ok', text2='multi\\nline', z=77" def test_array_attributes(self): cube = self.cube @@ -238,8 +291,8 @@ def test_array_attributes(self): rep = CubeSummary(cube) co1_summ = rep.vector_sections["Dimension coordinates:"].contents[0] co2_summ = rep.vector_sections["Auxiliary coordinates:"].contents[0] - self.assertEqual(co1_summ.extra, "array=array([1.2, 3. ])") - self.assertEqual(co2_summ.extra, "array=array([3.2, 1. ]), b=2") + assert co1_summ.extra == "array=array([1.2, 3. ])" + assert co2_summ.extra == "array=array([3.2, 1. ]), b=2" def test_attributes_subtle_differences(self): cube = Cube([0]) @@ -281,14 +334,14 @@ def test_attributes_subtle_differences(self): rep = CubeSummary(cube) co_summs = rep.scalar_sections["Scalar coordinates:"].contents co1a_summ, co1b_summ = co_summs[0:2] - self.assertEqual(co1a_summ.extra, "arr2=array([1, 2])") - self.assertEqual(co1b_summ.extra, "arr2=[1, 2]") + assert co1a_summ.extra == "arr2=array([1, 2])" + assert co1b_summ.extra == "arr2=[1, 2]" co2a_summ, co2b_summ = co_summs[2:4] - self.assertEqual(co2a_summ.extra, "arr2=array([3, 4])") - self.assertEqual(co2b_summ.extra, "arr2=array([3., 4.])") + assert co2a_summ.extra == "arr2=array([3, 4])" + assert co2b_summ.extra == "arr2=array([3., 4.])" co3a_summ, co3b_summ = co_summs[4:6] - self.assertEqual(co3a_summ.extra, "arr1=array([5, 6])") - self.assertEqual(co3b_summ.extra, "arr1=array([[5], [6]])") + assert co3a_summ.extra == "arr1=array([5, 6])" + assert co3b_summ.extra == "arr1=array([[5], [6]])" def test_unstructured_cube(self): cube = sample_mesh_cube() @@ -297,10 +350,6 @@ def test_unstructured_cube(self): dim_section = rep.vector_sections["Dimension coordinates:"] mesh_section = rep.vector_sections["Mesh coordinates:"] aux_section = rep.vector_sections["Auxiliary coordinates:"] - self.assertEqual(len(dim_section.contents), 2) - self.assertEqual(len(mesh_section.contents), 2) - self.assertEqual(len(aux_section.contents), 1) - - -if __name__ == "__main__": - tests.main() + assert len(dim_section.contents) == 2 + assert len(mesh_section.contents) == 2 + assert len(aux_section.contents) == 1 diff --git a/lib/iris/tests/unit/util/test_broadcast_to_shape.py b/lib/iris/tests/unit/util/test_broadcast_to_shape.py index 503d0669de..183f6f8d93 100644 --- a/lib/iris/tests/unit/util/test_broadcast_to_shape.py +++ b/lib/iris/tests/unit/util/test_broadcast_to_shape.py @@ -81,6 +81,31 @@ def test_lazy_masked(self, mocked_compute): for j in range(4): self.assertMaskedArrayEqual(b[i, :, j, :].compute().T, m.compute()) + @mock.patch.object(dask.base, "compute", wraps=dask.base.compute) + def test_lazy_chunks(self, mocked_compute): + # chunks can be specified along with the target shape and are only used + # along new dimensions or on dimensions that have size 1 in the source + # array. + m = da.ma.masked_array( + data=[[1, 2, 3, 4, 5]], + mask=[[0, 1, 0, 0, 0]], + ).rechunk((1, 2)) + b = broadcast_to_shape( + m, + dim_map=(1, 2), + shape=(3, 4, 5), + chunks=( + 1, # used because target is new dim + 2, # used because input size 1 + 3, # not used because broadcast does not rechunk + ), + ) + mocked_compute.assert_not_called() + for i in range(3): + for j in range(4): + self.assertMaskedArrayEqual(b[i, j, :].compute(), m[0].compute()) + assert b.chunks == ((1, 1, 1), (2, 2), (2, 2, 1)) + def test_masked_degenerate(self): # masked arrays can have degenerate masks too rng = np.random.default_rng() diff --git a/lib/iris/util.py b/lib/iris/util.py index c63743bae5..7d64754234 100644 --- a/lib/iris/util.py +++ b/lib/iris/util.py @@ -3,6 +3,7 @@ # 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. """Miscellaneous utility functions.""" + from __future__ import annotations from abc import ABCMeta, abstractmethod @@ -27,7 +28,7 @@ import iris.exceptions -def broadcast_to_shape(array, shape, dim_map): +def broadcast_to_shape(array, shape, dim_map, chunks=None): """Broadcast an array to a given shape. Each dimension of the array must correspond to a dimension in the @@ -48,6 +49,14 @@ def broadcast_to_shape(array, shape, dim_map): the index in *shape* which the dimension of *array* corresponds to, so the first element of *dim_map* gives the index of *shape* that corresponds to the first dimension of *array* etc. + chunks : :class:`tuple`, optional + If the source array is a :class:`dask.array.Array` and a value is + provided, then the result will use these chunks instead of the same + chunks as the source array. Setting chunks explicitly as part of + broadcast_to_shape is more efficient than rechunking afterwards. See + also :func:`dask.array.broadcast_to`. Note that the values provided + here will only be used along dimensions that are new on the result or + have size 1 on the source array. Examples -------- @@ -70,13 +79,25 @@ def broadcast_to_shape(array, shape, dim_map): See more at :doc:`/userguide/real_and_lazy_data`. """ + if isinstance(array, da.Array): + if chunks is not None: + chunks = list(chunks) + for src_idx, tgt_idx in enumerate(dim_map): + # Only use the specified chunks along new dimensions or on + # dimensions that have size 1 in the source array. + if array.shape[src_idx] != 1: + chunks[tgt_idx] = array.chunks[src_idx] + broadcast = functools.partial(da.broadcast_to, shape=shape, chunks=chunks) + else: + broadcast = functools.partial(np.broadcast_to, shape=shape) + n_orig_dims = len(array.shape) n_new_dims = len(shape) - n_orig_dims array = array.reshape(array.shape + (1,) * n_new_dims) # Get dims in required order. array = np.moveaxis(array, range(n_orig_dims), dim_map) - new_array = np.broadcast_to(array, shape) + new_array = broadcast(array) if ma.isMA(array): # broadcast_to strips masks so we need to handle them explicitly. @@ -84,13 +105,13 @@ def broadcast_to_shape(array, shape, dim_map): if mask is ma.nomask: new_mask = ma.nomask else: - new_mask = np.broadcast_to(mask, shape) + new_mask = broadcast(mask) new_array = ma.array(new_array, mask=new_mask) elif is_lazy_masked_data(array): # broadcast_to strips masks so we need to handle them explicitly. mask = da.ma.getmaskarray(array) - new_mask = da.broadcast_to(mask, shape) + new_mask = broadcast(mask) new_array = da.ma.masked_array(new_array, new_mask) return new_array diff --git a/noxfile.py b/noxfile.py index 81c8b02fef..2eb46de349 100644 --- a/noxfile.py +++ b/noxfile.py @@ -15,7 +15,7 @@ nox.options.reuse_existing_virtualenvs = True #: Python versions we can run sessions under -_PY_VERSIONS_ALL = ["3.9", "3.10", "3.11"] +_PY_VERSIONS_ALL = ["3.10", "3.11", "3.12"] _PY_VERSION_LATEST = _PY_VERSIONS_ALL[-1] #: One specific python version for docs builds diff --git a/pyproject.toml b/pyproject.toml index f55a77cfdf..82f7017f59 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,9 +22,9 @@ classifiers = [ "Operating System :: Unix", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Atmospheric Science", @@ -50,7 +50,7 @@ keywords = [ ] license = {text = "BSD-3-Clause"} name = "scitools-iris" -requires-python = ">=3.9" +requires-python = ">=3.10" [project.urls] Code = "https://github.com/SciTools/iris" @@ -73,7 +73,6 @@ src = [ "lib", "docs/src", ] -target-version = "py39" [tool.ruff.format] preview = false diff --git a/requirements/iris.yml b/requirements/iris.yml index b0c50b8bfd..331a25f10d 120000 --- a/requirements/iris.yml +++ b/requirements/iris.yml @@ -1 +1 @@ -py311.yml \ No newline at end of file +py312.yml \ No newline at end of file diff --git a/requirements/locks/py310-linux-64.lock b/requirements/locks/py310-linux-64.lock index 3cbf8fb510..ad0599da50 100644 --- a/requirements/locks/py310-linux-64.lock +++ b/requirements/locks/py310-linux-64.lock @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 808932859f70a640fcdd10a6b3c7fb545b14087d3a6db4e60bf79e05a4272c0a +# input_hash: 7b9e397b762637f1bcebfdc117c9431d3c450c7626a34f05a5c57825d448507b @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.2.2-hbcca054_0.conda#2f4327a1cbe7f022401b236e915a5fef @@ -10,26 +10,38 @@ https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77 https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_1.conda#6185f640c43843e5ad6fd1c5372c3f80 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda#7aca3059a1729aa76c597603f10b0dd3 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-13.2.0-h7e041cc_5.conda#f6f6600d18a4047b54f803cf708b868a +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/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-13.2.0-h807b86a_5.conda#d211c42b9ce49aee3734fdc828731689 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-13.2.0-h807b86a_5.conda#d4ff227c46917d3b4565302a2bbb276b +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.11-hd590300_1.conda#0bb492cca54017ea314b809b1ee3a176 +https://conda.anaconda.org/conda-forge/linux-64/aom-3.8.2-h59595ed_0.conda#625e1fed28a5139aed71b3a76117ef84 +https://conda.anaconda.org/conda-forge/linux-64/attr-2.5.1-h166bdaf_1.tar.bz2#d9c69a24ad678ffce24c6543a0176b00 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hd590300_5.conda#69b8b6202a07720f448be700e300ccf4 -https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.26.0-hd590300_0.conda#a86d90025198fd411845fc245ebc06c8 +https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.28.1-hd590300_0.conda#dcde58ff9a1f30b0037a2315d1846d1f +https://conda.anaconda.org/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda#418c6ca5929a611cbd69204907a83995 +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/fribidi-1.0.10-h36c2ea0_0.tar.bz2#ac7bc6a654f8f41b352b38f4051135f8 https://conda.anaconda.org/conda-forge/linux-64/geos-3.12.1-h59595ed_0.conda#8c0f4f71f5a59ceb0c6fa9f51501066d https://conda.anaconda.org/conda-forge/linux-64/gettext-0.21.1-h27087fc_0.tar.bz2#14947d8770185e5153fdd04d4673ed37 https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.1-h0b41bf4_3.conda#96f3b11872ef6fad973eac856cd2624f -https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h58526e2_1001.tar.bz2#8c54672728e8ec6aa6db90cf2806d220 +https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-h59595ed_1.conda#e358c7c5f6824c272b5034b3816438a7 +https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.conda#f87c7b7c2cb45f323ffbce941c78ab7c 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/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/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f -https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.2-h59595ed_1.conda#127b0be54c1c90760d7fe02ea7a56426 +https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240116.1-cxx17_h59595ed_2.conda#75648bc5dd3b8eab22406876c24d81ec +https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.3-h59595ed_0.conda#5e97e271911b8b2001a8b71860c32faa 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.19-hd590300_0.conda#1635570038840ee3f9c71d22aa5b8b6d +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.20-hd590300_0.conda#8e88f9389f1165d7c0936fe40d9a9a79 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.5.0-hcb278e6_1.conda#6305a3dd2752c76335295da4e581f2fd https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 @@ -38,22 +50,38 @@ https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda#d 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/libmo_unpack-3.1.2-hf484d3e_1001.tar.bz2#95f32a6a5a666d33886ca5627239f03d https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda#30fd6e37fe21f86f4bd26d6ee73eeec7 +https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2#6e8cc2173440d77708196c5b93771680 +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/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/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b +https://conda.anaconda.org/conda-forge/linux-64/libvpx-1.14.0-h59595ed_0.conda#01c76c6d71097a0f3bd8683a8f255123 https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.2-hd590300_0.conda#30de3fd9b3b602f7473f30e684eeea8c 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.2.13-hd590300_5.conda#f36c115f1ee199da648e0597ec2047ad 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/ncurses-6.4-h59595ed_2.conda#7dbaa197d7ba6032caf7ae7f32c1efa0 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.2.1-hd590300_0.conda#51a753e64a3027bd7e23a189b1f6e91e +https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.32.6-h59595ed_0.conda#9160cdeb523a1b20cf8d2a0bf821f45d +https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.4.20240210-h59595ed_0.conda#97da8860a0da5413c7c98a3b3838a645 +https://conda.anaconda.org/conda-forge/linux-64/nettle-3.9.1-h7ab15ed_0.conda#2bf1915cc107738811368afcb0993a59 +https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda#da0ec11a6454ae19bff5b02ed881a2b1 +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/openh264-2.4.1-h59595ed_0.conda#3dfcf61b8e78af08110f5229f79580af +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.2.1-hd590300_1.conda#9d731343cff6ee2e5a25c4a091bf8e2a https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 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/pugixml-1.14-h59595ed_0.conda#2c97dd90633508b422c11bd3018206ab https://conda.anaconda.org/conda-forge/linux-64/snappy-1.1.10-h9fff704_0.conda#e6d228cd0bb74a51dd18f5bfce0b4115 +https://conda.anaconda.org/conda-forge/linux-64/svt-av1-2.0.0-h59595ed_0.conda#207e01ffa0eb2d2efb83fb6f46365a21 +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/x265-3.5-h924138e_3.tar.bz2#e7f6ed84d4623d52ee581325c1587a6b 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-renderproto-0.11.1-h7f98852_1002.tar.bz2#06feff3d2634e3097ce2fe681474b534 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 @@ -62,37 +90,61 @@ https://conda.anaconda.org/conda-forge/linux-64/expat-2.5.0-hcb278e6_1.conda#8b9 https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda#bd77f8da987968ec3927990495dc22e4 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/libcap-2.69-h0f662aa_0.conda#25cb5999faa414e5ccb2c1388f62d3d5 +https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.120-hd590300_0.conda#7c3071bdf1d28b331a06bda6e85ab607 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/libevent-2.1.12-hf998b51_1.conda#a1cfcc585f0c42bf8d5546bb1dfb668d +https://conda.anaconda.org/conda-forge/linux-64/libflac-1.4.3-h59595ed_0.conda#ee48bf17cc83a00f59ca1494d5646869 https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-13.2.0-h69a702a_5.conda#e73e9cfd1191783392131e6238bdb3e9 +https://conda.anaconda.org/conda-forge/linux-64/libgpg-error-1.48-h71f35ed_0.conda#4d18d86916705d352d5f4adfb7f0edd3 +https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.7-hd590300_0.conda#2b7b0d827c6447cc1d85dc06d5b5de46 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.42-h2797004_0.conda#d67729828dc6ff7ba44a61062ad79880 -https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.45.1-h2797004_0.conda#fc4ccadfbf6d4784de88c41704792562 +https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.43-h2797004_0.conda#009981dd9cfcaa4dbfa25ffaed86bcae +https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-4.25.3-h08a7969_0.conda#6945825cebd2aeb16af4c69d97c32c13 +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.45.2-h2797004_0.conda#866983a220e27a80cb75e85cb30466a1 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/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.15-h0b41bf4_0.conda#33277193f5b92bad9fdd230eb700929c -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.5-h232c23b_0.conda#c442ebfda7a475f5e78f1c8e45f1e919 +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.6-h232c23b_1.conda#6853448e9ca1cfd5f15382afd2a6d123 https://conda.anaconda.org/conda-forge/linux-64/libzip-1.10.1-h2629f0a_3.conda#ac79812548e7e8cf61f7b0abdef01d3b -https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.42-hcad00b1_0.conda#679c8961826aa4b50653bce17ee52abe +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.33-hf1915f5_6.conda#80bf3b277c120dd294b51d404b931a75 +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.43-hcad00b1_0.conda#8292dea9e022d9610a11fce5e0896ed8 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 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/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.2.13-hd590300_5.conda#68c34ec6149623be41a1933ab996a209 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.5-hfc55251_0.conda#04b88013080254850d6c01ed54810589 https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.5-h0f2a231_0.conda#009521b7ed97cca25f8f997f9e745976 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-h0708190_0.tar.bz2#438718bf8921ac70956d919d0e2cc487 +https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.7.9-hb077bed_0.conda#33eded89024f21659b1975886a4acf70 https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.2-h659d440_0.conda#cd95826dbd331ed1be26bdf401432844 -https://conda.anaconda.org/conda-forge/linux-64/libglib-2.78.3-h783c2da_0.conda#9bd06b12bbfa6fd1740fd23af4b0f0c7 +https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.10.3-hd590300_0.conda#32d16ad533c59bb0a3c5ffaf16110829 +https://conda.anaconda.org/conda-forge/linux-64/libglib-2.80.0-hf2295e7_1.conda#0725f6081030c29b109088639824ff90 +https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.9.3-default_h554bfaf_1009.conda#f36ddc11ca46958197a45effdd286e45 +https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hb3ce162_4.conda#8a35df3cbc0c8b12cc8af9473ae75eef https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.26-pthreads_h413a1c8_0.conda#760ae35415f5ba8b15d09df5afe8b23a -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.6.0-ha9c0a0a_2.conda#55ed21669b2015f77c180feb1dd41930 -https://conda.anaconda.org/conda-forge/linux-64/python-3.10.13-hd12c33a_1_cpython.conda#ed38140af93f81319ebc472fbcf16cca -https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.45.1-h2c6b66d_0.conda#93acf31b379acebada263b9bce3dc6ed +https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.2-hc60ed4a_1.conda#ef1910918dd895516a769ed36b5b3a4e +https://conda.anaconda.org/conda-forge/linux-64/libtheora-1.1.1-h7f98852_1005.tar.bz2#1a7c35f56343b7e9e8db20b296c7566c +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.6.0-h1dd3fc0_3.conda#66f03896ffbe1a110ffda05c7a856504 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.33-hca2cd23_6.conda#e87530d1b12dd7f4e0f856dc07358d60 +https://conda.anaconda.org/conda-forge/linux-64/nss-3.98-h1d7d5a4_0.conda#54b56c2fdf973656b748e0378900ec13 +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.45.2-h2c6b66d_0.conda#1423efca06ed343c1da0fc429bae0779 https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-h40f5838_3.conda#6bb8deb138f87c9d48320ac21b87e7a1 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-hd590300_1.conda#9bfac7ccd94d54fd21a0501296d60424 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.0-h8ee46fc_1.conda#632413adcd8bc16b515cab87a2932913 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.9-hd590300_1.conda#e995b155d938b6779da6ace6c6b13816 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.1-h8ee46fc_1.conda#90108a432fb5c6150ccfee3f03388656 https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.7-h8ee46fc_0.conda#49e482d882669206653b095f5206c05b https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda#def531a3ac77b7fb8c21d17bb5d0badb https://conda.anaconda.org/conda-forge/noarch/antlr-python-runtime-4.11.1-pyhd8ed1ab_0.tar.bz2#15109c4977d39ad7aa3423f57243e286 -https://conda.anaconda.org/conda-forge/noarch/asv_runner-0.1.0-pyhd8ed1ab_0.conda#0e8715bef534217eae333c53f645c9ed https://conda.anaconda.org/conda-forge/linux-64/atk-1.0-2.38.0-hd4edc92_1.tar.bz2#6c72ec3e660a51736913ef6ea68c454b +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.2.2-pyhd8ed1ab_0.conda#0876280e409658fc6f9e75d035960333 @@ -101,16 +153,20 @@ https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1a 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/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.8-py310hc6cd4ac_0.conda#e533f96945907b2e81c6b604f578b69c +https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.10-py310hc6cd4ac_0.conda#bd1d71ee240be36f1d85c86177d6964f +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.8-pyhd8ed1ab_0.conda#db16c66b759a64dc5183d69cc3745a52 -https://conda.anaconda.org/conda-forge/linux-64/docutils-0.19-py310hff52083_1.tar.bz2#21b8fa2179290505e607f5ccd65b01b0 +https://conda.anaconda.org/conda-forge/linux-64/docutils-0.20.1-py310hff52083_3.conda#c159dcd29bbd80b187b1c5d5f73cc971 https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_2.conda#8d652ea2ee8eaee02ed8dc820bc794aa -https://conda.anaconda.org/conda-forge/noarch/execnet-2.0.2-pyhd8ed1ab_0.conda#67de0d8241e1060a479e3c37793e26f9 -https://conda.anaconda.org/conda-forge/noarch/filelock-3.13.1-pyhd8ed1ab_0.conda#0c1729b74a8152fde6a38ba0a2ab9f45 +https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.0-pyhd8ed1ab_0.conda#7a4b32fbe5442e46841ec77695e36d96 +https://conda.anaconda.org/conda-forge/noarch/filelock-3.13.3-pyhd8ed1ab_0.conda#ff15f46b0d34308f4d40c1c51df07592 https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d -https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.2.0-pyhca7485f_0.conda#fad86b90138cf5d82c6f5a2ed6e683d9 -https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.10-h829c605_4.conda#252a696860674caf7a855e16f680d63a +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.3.1-pyhca7485f_0.conda#b7f0662ef2c9d4404f0af9eef5ed2fde +https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.10-h829c605_5.conda#8fdb82e5d9694dd8e9ed9ac8fdf48a26 +https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.80.0-hde27a5a_1.conda#939ddd853b1d98bf6fd22cc0adeda317 https://conda.anaconda.org/conda-forge/linux-64/gts-0.7.6-h977cf35_4.conda#4d8df0b0db060d33c9a702ada998a8fe https://conda.anaconda.org/conda-forge/noarch/idna-3.6-pyhd8ed1ab_0.conda#1a76f09108576397c41c0b0c5bd84134 https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 @@ -119,105 +175,158 @@ https://conda.anaconda.org/conda-forge/noarch/iris-sample-data-2.4.0-pyhd8ed1ab_ https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.5-py310hd41b1e2_1.conda#b8d67603d43b23ce7e988a5d81a7ab79 https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.16-hb7c19ff_0.conda#51bb7010fc86f70eee639b4bb7a894f5 https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-21_linux64_openblas.conda#0ac9f44fc096772b0aa092119b00c3ca -https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.5.0-hca28451_0.conda#7144d5a828e2cae218e0e3c98d8a0aeb +https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h5d6823c_5.conda#2d694a9ffdcc30e89dea34a8dcdab6ae +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.7.1-hca28451_0.conda#755c7f876815003337d2c61ff5d047e5 +https://conda.anaconda.org/conda-forge/linux-64/libpq-16.2-h33b98f1_1.conda#9e49ec2a61d02623b379dc332eb6889d +https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-255-h3516f8a_1.conda#3366af27f0b593544a6cd453c7932ac5 https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.3.2-h658648e_1.conda#0ebb65e8d86843865796c7c95a941f34 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.7-py310hd41b1e2_0.conda#dc5263dcaa1347e5a456ead3537be27d +https://conda.anaconda.org/conda-forge/linux-64/multidict-6.0.5-py310h2372a71_0.conda#d4c91d19e4f2f18b64753ac660edad79 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.0-h488ebb8_3.conda#128c25b7fe6a25286a48f3a6a9b5b6f3 -https://conda.anaconda.org/conda-forge/noarch/packaging-23.2-pyhd8ed1ab_0.conda#79002079284aa895f883c6b7f3f88fd6 +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.0-pyhd8ed1ab_0.conda#248f521b64ce055e7feae3105e7abeb8 https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.0-pyhd8ed1ab_0.conda#a0bc3eec34b0fab84be6b2da94e98e20 https://conda.anaconda.org/conda-forge/noarch/pluggy-1.4.0-pyhd8ed1ab_0.conda#139e9feb65187e916162917bb2484976 https://conda.anaconda.org/conda-forge/linux-64/psutil-5.9.8-py310h2372a71_0.conda#bd19b3096442ea342c4a5208379660b1 -https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff +https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda#844d9eb3b43095b031874477f7d70088 https://conda.anaconda.org/conda-forge/noarch/pygments-2.17.2-pyhd8ed1ab_0.conda#140a7f159396547e9799aa98f9f0742e -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.1.1-pyhd8ed1ab_0.conda#176f7d56f0cfe9008bdf1bccd7de02fb +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.1.2-pyhd8ed1ab_0.conda#b9a4dacf97241704529131a0dfc0494f 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-2023.4-pyhd8ed1ab_0.conda#c79cacf8a06a51552fc651652f170208 +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/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/noarch/setuptools-69.0.3-pyhd8ed1ab_0.conda#40695fdfd15a92121ed2922900d0308b +https://conda.anaconda.org/conda-forge/noarch/scooby-0.9.2-pyhd8ed1ab_0.conda#66dc03353b88f5f2db8c630854174a3f +https://conda.anaconda.org/conda-forge/noarch/setuptools-69.2.0-pyhd8ed1ab_0.conda#da214ecd521a720a9d521c68047682dc 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 https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.5-pyhd8ed1ab_1.conda#3f144b2c34f8cb5a9abd9ed23a39c561 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda#da1d979339e2714c30a8e806a33ec087 +https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.11.0-h00ab1b0_1.conda#4531d2927578e7e254ff3bcf6457518c 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.3.3-py310h2372a71_1.conda#b23e0147fa5f7a9380e06334c7266ad5 -https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.9.0-pyha770c72_0.conda#a92a6440c3fe7052d63244f3aba2a4a7 +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4-py310h2372a71_0.conda#48f39c24349d9ae5c8e8873c42fb6170 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.11.0-pyha770c72_0.conda#6ef2fc37559256cf682d8b3375e89b80 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.42.0-pyhd8ed1ab_0.conda#1cdea58981c5cbc17b51973bcaddcea7 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.43.0-pyhd8ed1ab_1.conda#0b5293a157c2b5cd513dd1b03d8d3aae +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-h8ee46fc_1.conda#9d7bcddf49cbf727730af10e71022c73 +https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.41-hd590300_0.conda#81f740407b45e3f9047b3174fa94eb9e 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/noarch/zict-3.0.0-pyhd8ed1ab_0.conda#cf30c2c15b82aacb07f9c09e28ff2275 https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda#2e4d6bc0b14e10f895fc6791a7d9b26a https://conda.anaconda.org/conda-forge/noarch/accessible-pygments-0.0.4-pyhd8ed1ab_0.conda#46a2e6e3dfa718ce3492018d5a110dd6 +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-h3faef2a_0.conda#f907bb958910dc404647326ca80c263e https://conda.anaconda.org/conda-forge/linux-64/cffi-1.16.0-py310h2fee648_0.conda#45846a970e71ac98fd327da5d40a0a2c -https://conda.anaconda.org/conda-forge/linux-64/coverage-7.4.1-py310h2372a71_0.conda#b2de1af90e44849451c9808312f964ae +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.4.4-py310h2372a71_0.conda#2d948842110ae68e4f2e7738f92bf7e1 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.48.1-py310h2372a71_0.conda#480ff621e839c5f80a52975b167500d2 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.51.0-py310h2372a71_0.conda#1a4773624145c15b92820fe6c87c5fcd +https://conda.anaconda.org/conda-forge/linux-64/glib-2.80.0-hf2295e7_1.conda#d3bcc5c186f78feba6f39ea047c35950 https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.3-nompi_h4f84152_100.conda#d471a5c3abc984b662d9bae3bb7fd8a5 -https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.0.1-pyha770c72_0.conda#746623a787e06191d80a2133e5daff17 +https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.1.0-pyha770c72_0.conda#0896606848b2dc5cebdf111b6543aa04 https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.3-pyhd8ed1ab_0.conda#e7d8df6509ba635247ff9aea31134262 https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-21_linux64_openblas.conda#4a3816d06451c4946e2db26b86472cb6 +https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_h127d8a8_5.conda#09b94dd3a7e304df5b83176239347920 https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-h119a65a_9.conda#cfebc557e54905dadc355c0e9f003004 +https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.0-hac7e632_1003.conda#50c389a09b6b7babaef531eb7cb5e0ca https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-21_linux64_openblas.conda#1a42f305615c3867684e049e85927531 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-2024.0.0-h2e90f83_4.conda#126a2a61d276c4268f71adeef25bfc33 +https://conda.anaconda.org/conda-forge/linux-64/libva-2.21.0-hd590300_0.conda#e50a2609159a3e336fe4092738c00687 +https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.7.0-h662e7e4_0.conda#b32c0da42b1f24a98577bb3d7fc0b995 https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.8.0-pyhd8ed1ab_0.conda#2a75b296096adabbabadd5e9782e5fcc https://conda.anaconda.org/conda-forge/noarch/partd-1.4.1-pyhd8ed1ab_0.conda#acf4b7c0bcd5fa3b0e05801c4d2accd6 -https://conda.anaconda.org/conda-forge/linux-64/pillow-10.2.0-py310h01dd4db_0.conda#9ec32d0d90f7670eb29bbba18299cf29 +https://conda.anaconda.org/conda-forge/linux-64/pillow-10.3.0-py310hf73ecf8_0.conda#1de56cf017dfd02aa84093206a0141a8 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.0.0-pyhd8ed1ab_0.conda#5ba1cc5b924226349d4a49fb547b7579 -https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 -https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.9.0-hd8ed1ab_0.conda#c16524c1b7227dc80b36b4fa6f77cc86 -https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.0-pyhd8ed1ab_0.conda#6a7e0694921f668a030d52f0c47baebd -https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.25.0-pyhd8ed1ab_0.conda#c119653cba436d8183c27bf6d190e587 +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-client-16.1-hb77b528_5.conda#ac902ff3c1c6d750dd0dfc93a974ab74 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.1.1-pyhd8ed1ab_0.conda#94ff09cdedcb7b17e9cd5097ee2cfcff +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-devel-2021.11.0-h5ccd973_1.conda#9dd2dc16536b2839b8f895f716c0366c +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.11.0-hd8ed1ab_0.conda#471e3988f8ca5e9eb3ce6be7eac3bcee +https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda#08807a87fa7af10754d46f63b368e016 +https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.25.1-pyhd8ed1ab_0.conda#8797a4e26be36880a603aba29c785352 +https://conda.anaconda.org/conda-forge/linux-64/yarl-1.9.4-py310h2372a71_0.conda#4ad35c8f6a64a6ab708780dad603aef4 +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/glew-2.1.0-h9c3ff4c_2.tar.bz2#fb05eb5c47590b247658243d27fc32f1 +https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.22.9-h98fc4e7_0.conda#bcc7157b06fce7f5e055402a8135dfd8 https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-8.3.0-h3d44ed6_0.conda#5a6f6c00ef982a9bc83558d9ac8f64a0 -https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-7.0.1-hd8ed1ab_0.conda#4a2f43a20fa404b998859c6a470ba316 +https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-7.1.0-hd8ed1ab_0.conda#6ef2b72d291b39e479d7694efa2b2b98 https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.2-nompi_h9612171_113.conda#b2414908e43c442ddc68e6148774a304 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-batch-plugin-2024.0.0-hd5fc58b_4.conda#de9c380fea8634540db5fc8422888df1 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-plugin-2024.0.0-hd5fc58b_4.conda#de1cbf145ecdc1d29af18e14eb267bca +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-hetero-plugin-2024.0.0-h3ecfda7_4.conda#016b763e4776b4c2c536420a7e6a2349 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-cpu-plugin-2024.0.0-h2e90f83_4.conda#d866cc8dc37f101505e65a4372794631 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-gpu-plugin-2024.0.0-h2e90f83_4.conda#6ebefdc74cb700ec82cd6702125cc422 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-ir-frontend-2024.0.0-h3ecfda7_4.conda#6397395a4677d59bbd32c4f05bb8fa63 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-onnx-frontend-2024.0.0-h757c851_4.conda#24c9cf1dd8f6d6189102a136a731758c +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-paddle-frontend-2024.0.0-h757c851_4.conda#259bd0c788f447fe78aab69895365528 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-pytorch-frontend-2024.0.0-h59595ed_4.conda#ec121a4195acadad086f84719cc91430 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-frontend-2024.0.0-hca94c1a_4.conda#bdbf11f760f1a3b35d766e03cebd9c42 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-lite-frontend-2024.0.0-h59595ed_4.conda#4354ea9f30a8c5111403fa4b24a2ad66 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/pytest-cov-4.1.0-pyhd8ed1ab_0.conda#06eb685a3a0b146347a58dda979485da +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.5.0-pyhd8ed1ab_0.conda#d5f595da2daead898ca958ac62f0307b https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda#a30144e4156cdbb236f99ebb49828f8b -https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-8.0.4-pyhd8ed1ab_0.conda#3b8ef3a2d80f3d89d0ae7e3c975e6c57 +https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-8.0.4-pyhd8ed1ab_1.conda#a1986ad21c766ff22f7bae93f0641020 https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py310hd41b1e2_4.conda#35e87277fba9944b8a975113538bb5df +https://conda.anaconda.org/conda-forge/linux-64/aiohttp-3.9.3-py310h2372a71_1.conda#dd21c88dfec3253cb9888c0e93fa5cd1 https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.3-py310h1f7b6fc_0.conda#31beda75384647959d5792a1a7dc571a +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.0-py310hd41b1e2_0.conda#85d2aaa7af046528d339da1e813c3a9f -https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.1.1-pyhd8ed1ab_0.conda#1a92a5bd77b2430796696e25c3d8dbcb -https://conda.anaconda.org/conda-forge/noarch/identify-2.5.33-pyhd8ed1ab_0.conda#93c8f8ceb83827d88deeba796f07fba7 +https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.4.1-pyhd8ed1ab_0.conda#52387f00fee8dcd5cf75f8886025293f +https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.22.9-h8e1006c_0.conda#614b81f8ed66c56b640faee7076ad14a +https://conda.anaconda.org/conda-forge/noarch/identify-2.5.35-pyhd8ed1ab_0.conda#9472bfd206a2b7bb8143835e37667054 +https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.1-h8fe9dca_1.conda#c306fd9cc90c0585171167d09135a827 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_hacb5139_103.conda#50f05f98d084805642d24dff910e11e8 -https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.0-py310hcc13569_0.conda#514c836161e8b2e43e7d8fb7a28a92c4 -https://conda.anaconda.org/conda-forge/linux-64/pango-1.50.14-ha41ecd1_2.conda#1a66c10f6a0da3dbd2f3a68127e7f6a0 +https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.1-py310hcc13569_0.conda#cf5d315e3601a6a2931f63aa9a84dc40 +https://conda.anaconda.org/conda-forge/linux-64/pango-1.52.2-ha41ecd1_0.conda#a658eeabf188c3040da36b0763de2bfd +https://conda.anaconda.org/conda-forge/noarch/pooch-1.8.1-pyhd8ed1ab_0.conda#d15917f33140f8d2ac9ca44db7ec8a25 +https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.3.11-py310h1f7b6fc_0.conda#25ede13c92af9a12712dc33fdc3adc11 https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.4.1-py310h1f7b6fc_1.conda#be6f0382440ccbf9fb01bb19ab1f1fc0 -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.12.0-py310hb13e2d6_2.conda#cd3baec470071490bc5ab05da64c52b5 -https://conda.anaconda.org/conda-forge/linux-64/shapely-2.0.2-py310hc3e127f_1.conda#fdaca8d27b3af78d617521eb37b1d055 +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.13.0-py310hb13e2d6_0.conda#512cfc0369e247e3993a76030671cce0 +https://conda.anaconda.org/conda-forge/linux-64/shapely-2.0.3-py310hc3e127f_0.conda#fbc825d13cbcb2d5d3fbba22c83fd203 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-apidoc-0.3.0-py_1.tar.bz2#855b087883443abb10f5faf6eef40860 https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.2.0-py310h1f7b6fc_4.conda#0ca55ca20891d393846695354b32ebc5 -https://conda.anaconda.org/conda-forge/noarch/distributed-2024.1.1-pyhd8ed1ab_0.conda#81039f39690f341dcb0a68bf62e812be -https://conda.anaconda.org/conda-forge/linux-64/esmf-8.4.2-nompi_h9e768e6_3.conda#c330e87e698bae8e7381c0315cf25dd0 -https://conda.anaconda.org/conda-forge/linux-64/gtk2-2.24.33-h7f000aa_3.conda#0abfa7f9241a0f4fd732bc15773cfb0c +https://conda.anaconda.org/conda-forge/noarch/distributed-2024.4.1-pyhd8ed1ab_0.conda#822b8d8216764941bb099fea588127ad +https://conda.anaconda.org/conda-forge/linux-64/esmf-8.6.0-nompi_h7b237b1_0.conda#a5f1925a75d9fcf0bffd07a194f83895 +https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-6.1.1-gpl_hee4b679_107.conda#a9865c001fa2e03272895e23b10bc55f +https://conda.anaconda.org/conda-forge/linux-64/gtk2-2.24.33-h280cfa0_4.conda#410f86e58e880dcc7b0e910a8e89c05c 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.56.3-he3f83f7_1.conda#03bd1ddcc942867a19528877143b9852 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.8.2-py310h62c0568_0.conda#3cbbc7d0b54df02c9a006d3de14911d9 +https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.58.0-hce6bd6c_0.conda#0891de8980ee29828542dbf9578838b9 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.8.3-py310h62c0568_0.conda#4a7296c0273eb01dfbed728dd6a6725a https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.6.5-nompi_py310hba70d50_100.conda#e19392760c7e4da3b9cb0ee5bf61bc4b -https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.6.0-pyha770c72_0.conda#473a7cfca197da0a10cff3f6dded7d4b +https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.7.0-pyha770c72_0.conda#846ba0877cda9c4f11e13720cacd1968 https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.3.0-py310h1f7b6fc_1.conda#857b828a13cdddf568958f7575b25b22 +https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.8-h5810be5_19.conda#54866f708d43002a514d0b9b0f84bc11 +https://conda.anaconda.org/conda-forge/noarch/wslink-1.12.4-pyhd8ed1ab_0.conda#9c8a6235a36aaf096be3118daba08a7b https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.22.0-py310hcc13569_1.conda#31ef447724fb19066a9d00a660dab1bd -https://conda.anaconda.org/conda-forge/noarch/esmpy-8.4.2-pyhc1e730c_4.conda#ddcf387719b2e44df0cc4dd467643951 +https://conda.anaconda.org/conda-forge/noarch/cmocean-3.1.3-pyhd8ed1ab_0.conda#671543f081d6be0b6b3e99b586386b44 +https://conda.anaconda.org/conda-forge/noarch/esmpy-8.6.0-pyhc1e730c_0.conda#60404b48ef1ccfb92cfd055f8844b700 https://conda.anaconda.org/conda-forge/linux-64/graphviz-9.0.0-h78e8752_1.conda#a3f4cd4a512ec5db35ffbf25ba11f537 https://conda.anaconda.org/conda-forge/noarch/nc-time-axis-1.4.1-pyhd8ed1ab_0.tar.bz2#281b58948bf60a2582de9e548bcc5369 +https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.2.6-qt_py310h1234567_220.conda#665737e30e12e5c1e20a8a3426df73f2 +https://conda.anaconda.org/conda-forge/linux-64/vtk-io-ffmpeg-9.2.6-qt_py310h1234567_220.conda#5611464975f4d2bd8c5beeab80ead9a0 +https://conda.anaconda.org/conda-forge/linux-64/vtk-9.2.6-qt_py310h1234567_220.conda#1c1089c9dc15089da0b1b3a24dff32d1 +https://conda.anaconda.org/conda-forge/noarch/pyvista-0.43.4-pyhd8ed1ab_0.conda#21e567168518369ce3f1c51e69b8ac0e +https://conda.anaconda.org/conda-forge/noarch/geovista-0.4.1-pyhd8ed1ab_0.conda#8dbe5526321fa7f1cb4dbc4f1644dcb3 https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.15.2-pyhd8ed1ab_0.conda#ce99859070b0e17ccc63234ca58f3ed8 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.5.0-pyhd8ed1ab_0.conda#264b3c697fa9cdade87eb0abe4440d54 @@ -226,5 +335,5 @@ https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd 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-5.3.0-pyhd8ed1ab_0.tar.bz2#f9e1fcfe235d655900bfeb6aee426472 +https://conda.anaconda.org/conda-forge/noarch/sphinx-7.2.6-pyhd8ed1ab_0.conda#bbfd1120d1824d2d073bc65935f0e4c0 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 053251b045..0823ffba42 100644 --- a/requirements/locks/py311-linux-64.lock +++ b/requirements/locks/py311-linux-64.lock @@ -1,6 +1,6 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 9f4d0f3ce6f3f0d7af7672fdc6f449b404e067882f805f0b3c416eb77ae0f4c0 +# input_hash: 6b92e6452b3174cffc5c890bcc0e9d97687ce8fc56c704029c2694d301418d9d @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.2.2-hbcca054_0.conda#2f4327a1cbe7f022401b236e915a5fef @@ -10,26 +10,38 @@ https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77 https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_1.conda#6185f640c43843e5ad6fd1c5372c3f80 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda#7aca3059a1729aa76c597603f10b0dd3 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-13.2.0-h7e041cc_5.conda#f6f6600d18a4047b54f803cf708b868a +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/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-13.2.0-h807b86a_5.conda#d211c42b9ce49aee3734fdc828731689 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-13.2.0-h807b86a_5.conda#d4ff227c46917d3b4565302a2bbb276b +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.11-hd590300_1.conda#0bb492cca54017ea314b809b1ee3a176 +https://conda.anaconda.org/conda-forge/linux-64/aom-3.8.2-h59595ed_0.conda#625e1fed28a5139aed71b3a76117ef84 +https://conda.anaconda.org/conda-forge/linux-64/attr-2.5.1-h166bdaf_1.tar.bz2#d9c69a24ad678ffce24c6543a0176b00 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hd590300_5.conda#69b8b6202a07720f448be700e300ccf4 -https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.26.0-hd590300_0.conda#a86d90025198fd411845fc245ebc06c8 +https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.28.1-hd590300_0.conda#dcde58ff9a1f30b0037a2315d1846d1f +https://conda.anaconda.org/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda#418c6ca5929a611cbd69204907a83995 +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/fribidi-1.0.10-h36c2ea0_0.tar.bz2#ac7bc6a654f8f41b352b38f4051135f8 https://conda.anaconda.org/conda-forge/linux-64/geos-3.12.1-h59595ed_0.conda#8c0f4f71f5a59ceb0c6fa9f51501066d https://conda.anaconda.org/conda-forge/linux-64/gettext-0.21.1-h27087fc_0.tar.bz2#14947d8770185e5153fdd04d4673ed37 https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.1-h0b41bf4_3.conda#96f3b11872ef6fad973eac856cd2624f -https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h58526e2_1001.tar.bz2#8c54672728e8ec6aa6db90cf2806d220 +https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-h59595ed_1.conda#e358c7c5f6824c272b5034b3816438a7 +https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.conda#f87c7b7c2cb45f323ffbce941c78ab7c 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/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/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f -https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.2-h59595ed_1.conda#127b0be54c1c90760d7fe02ea7a56426 +https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240116.1-cxx17_h59595ed_2.conda#75648bc5dd3b8eab22406876c24d81ec +https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.3-h59595ed_0.conda#5e97e271911b8b2001a8b71860c32faa 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.19-hd590300_0.conda#1635570038840ee3f9c71d22aa5b8b6d +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.20-hd590300_0.conda#8e88f9389f1165d7c0936fe40d9a9a79 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.5.0-hcb278e6_1.conda#6305a3dd2752c76335295da4e581f2fd https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 @@ -38,22 +50,38 @@ https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda#d 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/libmo_unpack-3.1.2-hf484d3e_1001.tar.bz2#95f32a6a5a666d33886ca5627239f03d https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda#30fd6e37fe21f86f4bd26d6ee73eeec7 +https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2#6e8cc2173440d77708196c5b93771680 +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/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/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b +https://conda.anaconda.org/conda-forge/linux-64/libvpx-1.14.0-h59595ed_0.conda#01c76c6d71097a0f3bd8683a8f255123 https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.2-hd590300_0.conda#30de3fd9b3b602f7473f30e684eeea8c 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.2.13-hd590300_5.conda#f36c115f1ee199da648e0597ec2047ad 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/ncurses-6.4-h59595ed_2.conda#7dbaa197d7ba6032caf7ae7f32c1efa0 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.2.1-hd590300_0.conda#51a753e64a3027bd7e23a189b1f6e91e +https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.32.6-h59595ed_0.conda#9160cdeb523a1b20cf8d2a0bf821f45d +https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.4.20240210-h59595ed_0.conda#97da8860a0da5413c7c98a3b3838a645 +https://conda.anaconda.org/conda-forge/linux-64/nettle-3.9.1-h7ab15ed_0.conda#2bf1915cc107738811368afcb0993a59 +https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda#da0ec11a6454ae19bff5b02ed881a2b1 +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/openh264-2.4.1-h59595ed_0.conda#3dfcf61b8e78af08110f5229f79580af +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.2.1-hd590300_1.conda#9d731343cff6ee2e5a25c4a091bf8e2a https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 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/pugixml-1.14-h59595ed_0.conda#2c97dd90633508b422c11bd3018206ab https://conda.anaconda.org/conda-forge/linux-64/snappy-1.1.10-h9fff704_0.conda#e6d228cd0bb74a51dd18f5bfce0b4115 +https://conda.anaconda.org/conda-forge/linux-64/svt-av1-2.0.0-h59595ed_0.conda#207e01ffa0eb2d2efb83fb6f46365a21 +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/x265-3.5-h924138e_3.tar.bz2#e7f6ed84d4623d52ee581325c1587a6b 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-renderproto-0.11.1-h7f98852_1002.tar.bz2#06feff3d2634e3097ce2fe681474b534 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 @@ -62,37 +90,61 @@ https://conda.anaconda.org/conda-forge/linux-64/expat-2.5.0-hcb278e6_1.conda#8b9 https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda#bd77f8da987968ec3927990495dc22e4 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/libcap-2.69-h0f662aa_0.conda#25cb5999faa414e5ccb2c1388f62d3d5 +https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.120-hd590300_0.conda#7c3071bdf1d28b331a06bda6e85ab607 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/libevent-2.1.12-hf998b51_1.conda#a1cfcc585f0c42bf8d5546bb1dfb668d +https://conda.anaconda.org/conda-forge/linux-64/libflac-1.4.3-h59595ed_0.conda#ee48bf17cc83a00f59ca1494d5646869 https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-13.2.0-h69a702a_5.conda#e73e9cfd1191783392131e6238bdb3e9 +https://conda.anaconda.org/conda-forge/linux-64/libgpg-error-1.48-h71f35ed_0.conda#4d18d86916705d352d5f4adfb7f0edd3 +https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.7-hd590300_0.conda#2b7b0d827c6447cc1d85dc06d5b5de46 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.42-h2797004_0.conda#d67729828dc6ff7ba44a61062ad79880 -https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.45.1-h2797004_0.conda#fc4ccadfbf6d4784de88c41704792562 +https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.43-h2797004_0.conda#009981dd9cfcaa4dbfa25ffaed86bcae +https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-4.25.3-h08a7969_0.conda#6945825cebd2aeb16af4c69d97c32c13 +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.45.2-h2797004_0.conda#866983a220e27a80cb75e85cb30466a1 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/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.15-h0b41bf4_0.conda#33277193f5b92bad9fdd230eb700929c -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.5-h232c23b_0.conda#c442ebfda7a475f5e78f1c8e45f1e919 +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.6-h232c23b_1.conda#6853448e9ca1cfd5f15382afd2a6d123 https://conda.anaconda.org/conda-forge/linux-64/libzip-1.10.1-h2629f0a_3.conda#ac79812548e7e8cf61f7b0abdef01d3b -https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.42-hcad00b1_0.conda#679c8961826aa4b50653bce17ee52abe +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.33-hf1915f5_6.conda#80bf3b277c120dd294b51d404b931a75 +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.43-hcad00b1_0.conda#8292dea9e022d9610a11fce5e0896ed8 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 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/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.2.13-hd590300_5.conda#68c34ec6149623be41a1933ab996a209 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.5-hfc55251_0.conda#04b88013080254850d6c01ed54810589 https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.5-h0f2a231_0.conda#009521b7ed97cca25f8f997f9e745976 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-h0708190_0.tar.bz2#438718bf8921ac70956d919d0e2cc487 +https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.7.9-hb077bed_0.conda#33eded89024f21659b1975886a4acf70 https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.2-h659d440_0.conda#cd95826dbd331ed1be26bdf401432844 -https://conda.anaconda.org/conda-forge/linux-64/libglib-2.78.3-h783c2da_0.conda#9bd06b12bbfa6fd1740fd23af4b0f0c7 +https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.10.3-hd590300_0.conda#32d16ad533c59bb0a3c5ffaf16110829 +https://conda.anaconda.org/conda-forge/linux-64/libglib-2.80.0-hf2295e7_1.conda#0725f6081030c29b109088639824ff90 +https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.9.3-default_h554bfaf_1009.conda#f36ddc11ca46958197a45effdd286e45 +https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hb3ce162_4.conda#8a35df3cbc0c8b12cc8af9473ae75eef https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.26-pthreads_h413a1c8_0.conda#760ae35415f5ba8b15d09df5afe8b23a -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.6.0-ha9c0a0a_2.conda#55ed21669b2015f77c180feb1dd41930 -https://conda.anaconda.org/conda-forge/linux-64/python-3.11.7-hab00c5b_1_cpython.conda#27cf681282c11dba7b0b1fd266e8f289 -https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.45.1-h2c6b66d_0.conda#93acf31b379acebada263b9bce3dc6ed +https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.2-hc60ed4a_1.conda#ef1910918dd895516a769ed36b5b3a4e +https://conda.anaconda.org/conda-forge/linux-64/libtheora-1.1.1-h7f98852_1005.tar.bz2#1a7c35f56343b7e9e8db20b296c7566c +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.6.0-h1dd3fc0_3.conda#66f03896ffbe1a110ffda05c7a856504 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.33-hca2cd23_6.conda#e87530d1b12dd7f4e0f856dc07358d60 +https://conda.anaconda.org/conda-forge/linux-64/nss-3.98-h1d7d5a4_0.conda#54b56c2fdf973656b748e0378900ec13 +https://conda.anaconda.org/conda-forge/linux-64/python-3.11.8-hab00c5b_0_cpython.conda#2fdc314ee058eda0114738a9309d3683 +https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.45.2-h2c6b66d_0.conda#1423efca06ed343c1da0fc429bae0779 https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-h40f5838_3.conda#6bb8deb138f87c9d48320ac21b87e7a1 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-hd590300_1.conda#9bfac7ccd94d54fd21a0501296d60424 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.0-h8ee46fc_1.conda#632413adcd8bc16b515cab87a2932913 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.9-hd590300_1.conda#e995b155d938b6779da6ace6c6b13816 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.1-h8ee46fc_1.conda#90108a432fb5c6150ccfee3f03388656 https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.7-h8ee46fc_0.conda#49e482d882669206653b095f5206c05b https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda#def531a3ac77b7fb8c21d17bb5d0badb https://conda.anaconda.org/conda-forge/noarch/antlr-python-runtime-4.11.1-pyhd8ed1ab_0.tar.bz2#15109c4977d39ad7aa3423f57243e286 -https://conda.anaconda.org/conda-forge/noarch/asv_runner-0.1.0-pyhd8ed1ab_0.conda#0e8715bef534217eae333c53f645c9ed https://conda.anaconda.org/conda-forge/linux-64/atk-1.0-2.38.0-hd4edc92_1.tar.bz2#6c72ec3e660a51736913ef6ea68c454b +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.2.2-pyhd8ed1ab_0.conda#0876280e409658fc6f9e75d035960333 @@ -101,16 +153,20 @@ https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1a 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/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.8-py311hb755f60_0.conda#28778bfea41b0f34141208783882649b +https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.10-py311hb755f60_0.conda#f3a8a500a2e743ff92f418f0eaf9bf71 +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.8-pyhd8ed1ab_0.conda#db16c66b759a64dc5183d69cc3745a52 -https://conda.anaconda.org/conda-forge/linux-64/docutils-0.19-py311h38be061_1.tar.bz2#599159b0740e9b82e7eef0e8471be3c2 +https://conda.anaconda.org/conda-forge/linux-64/docutils-0.20.1-py311h38be061_3.conda#1c33f55e5cdcc2a2b973c432b5225bfe https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_2.conda#8d652ea2ee8eaee02ed8dc820bc794aa -https://conda.anaconda.org/conda-forge/noarch/execnet-2.0.2-pyhd8ed1ab_0.conda#67de0d8241e1060a479e3c37793e26f9 -https://conda.anaconda.org/conda-forge/noarch/filelock-3.13.1-pyhd8ed1ab_0.conda#0c1729b74a8152fde6a38ba0a2ab9f45 +https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.0-pyhd8ed1ab_0.conda#7a4b32fbe5442e46841ec77695e36d96 +https://conda.anaconda.org/conda-forge/noarch/filelock-3.13.3-pyhd8ed1ab_0.conda#ff15f46b0d34308f4d40c1c51df07592 https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d -https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.2.0-pyhca7485f_0.conda#fad86b90138cf5d82c6f5a2ed6e683d9 -https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.10-h829c605_4.conda#252a696860674caf7a855e16f680d63a +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.3.1-pyhca7485f_0.conda#b7f0662ef2c9d4404f0af9eef5ed2fde +https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.10-h829c605_5.conda#8fdb82e5d9694dd8e9ed9ac8fdf48a26 +https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.80.0-hde27a5a_1.conda#939ddd853b1d98bf6fd22cc0adeda317 https://conda.anaconda.org/conda-forge/linux-64/gts-0.7.6-h977cf35_4.conda#4d8df0b0db060d33c9a702ada998a8fe https://conda.anaconda.org/conda-forge/noarch/idna-3.6-pyhd8ed1ab_0.conda#1a76f09108576397c41c0b0c5bd84134 https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 @@ -119,104 +175,156 @@ https://conda.anaconda.org/conda-forge/noarch/iris-sample-data-2.4.0-pyhd8ed1ab_ https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.5-py311h9547e67_1.conda#2c65bdf442b0d37aad080c8a4e0d452f https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.16-hb7c19ff_0.conda#51bb7010fc86f70eee639b4bb7a894f5 https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-21_linux64_openblas.conda#0ac9f44fc096772b0aa092119b00c3ca -https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.5.0-hca28451_0.conda#7144d5a828e2cae218e0e3c98d8a0aeb +https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h5d6823c_5.conda#2d694a9ffdcc30e89dea34a8dcdab6ae +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.7.1-hca28451_0.conda#755c7f876815003337d2c61ff5d047e5 +https://conda.anaconda.org/conda-forge/linux-64/libpq-16.2-h33b98f1_1.conda#9e49ec2a61d02623b379dc332eb6889d +https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-255-h3516f8a_1.conda#3366af27f0b593544a6cd453c7932ac5 https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.3.2-h658648e_1.conda#0ebb65e8d86843865796c7c95a941f34 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.7-py311h9547e67_0.conda#3ac85c6c226e2a2e4b17864fc2ca88ff +https://conda.anaconda.org/conda-forge/linux-64/multidict-6.0.5-py311h459d7ec_0.conda#4288ea5cbe686d1b18fc3efb36c009a5 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.0-h488ebb8_3.conda#128c25b7fe6a25286a48f3a6a9b5b6f3 -https://conda.anaconda.org/conda-forge/noarch/packaging-23.2-pyhd8ed1ab_0.conda#79002079284aa895f883c6b7f3f88fd6 +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.0-pyhd8ed1ab_0.conda#248f521b64ce055e7feae3105e7abeb8 https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.0-pyhd8ed1ab_0.conda#a0bc3eec34b0fab84be6b2da94e98e20 https://conda.anaconda.org/conda-forge/noarch/pluggy-1.4.0-pyhd8ed1ab_0.conda#139e9feb65187e916162917bb2484976 https://conda.anaconda.org/conda-forge/linux-64/psutil-5.9.8-py311h459d7ec_0.conda#9bc62d25dcf64eec484974a3123c9d57 -https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff +https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda#844d9eb3b43095b031874477f7d70088 https://conda.anaconda.org/conda-forge/noarch/pygments-2.17.2-pyhd8ed1ab_0.conda#140a7f159396547e9799aa98f9f0742e -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.1.1-pyhd8ed1ab_0.conda#176f7d56f0cfe9008bdf1bccd7de02fb +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.1.2-pyhd8ed1ab_0.conda#b9a4dacf97241704529131a0dfc0494f 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-2023.4-pyhd8ed1ab_0.conda#c79cacf8a06a51552fc651652f170208 +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/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/noarch/setuptools-69.0.3-pyhd8ed1ab_0.conda#40695fdfd15a92121ed2922900d0308b +https://conda.anaconda.org/conda-forge/noarch/scooby-0.9.2-pyhd8ed1ab_0.conda#66dc03353b88f5f2db8c630854174a3f +https://conda.anaconda.org/conda-forge/noarch/setuptools-69.2.0-pyhd8ed1ab_0.conda#da214ecd521a720a9d521c68047682dc 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 https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.5-pyhd8ed1ab_1.conda#3f144b2c34f8cb5a9abd9ed23a39c561 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda#da1d979339e2714c30a8e806a33ec087 +https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.11.0-h00ab1b0_1.conda#4531d2927578e7e254ff3bcf6457518c 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.3.3-py311h459d7ec_1.conda#a700fcb5cedd3e72d0c75d095c7a6eda -https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.9.0-pyha770c72_0.conda#a92a6440c3fe7052d63244f3aba2a4a7 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.42.0-pyhd8ed1ab_0.conda#1cdea58981c5cbc17b51973bcaddcea7 +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4-py311h459d7ec_0.conda#cc7727006191b8f3630936b339a76cd0 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.11.0-pyha770c72_0.conda#6ef2fc37559256cf682d8b3375e89b80 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.43.0-pyhd8ed1ab_1.conda#0b5293a157c2b5cd513dd1b03d8d3aae +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-h8ee46fc_1.conda#9d7bcddf49cbf727730af10e71022c73 +https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.41-hd590300_0.conda#81f740407b45e3f9047b3174fa94eb9e 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/noarch/zict-3.0.0-pyhd8ed1ab_0.conda#cf30c2c15b82aacb07f9c09e28ff2275 https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda#2e4d6bc0b14e10f895fc6791a7d9b26a https://conda.anaconda.org/conda-forge/noarch/accessible-pygments-0.0.4-pyhd8ed1ab_0.conda#46a2e6e3dfa718ce3492018d5a110dd6 +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-h3faef2a_0.conda#f907bb958910dc404647326ca80c263e https://conda.anaconda.org/conda-forge/linux-64/cffi-1.16.0-py311hb3a22ac_0.conda#b3469563ac5e808b0cd92810d0697043 -https://conda.anaconda.org/conda-forge/linux-64/coverage-7.4.1-py311h459d7ec_0.conda#9caf3270065a2d40fd9a443ba1568e96 +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.4.4-py311h459d7ec_0.conda#1aa22cb84e68841ec206ee066457bdf0 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.48.1-py311h459d7ec_0.conda#36363685b6e56682b1b256eb0ad503f6 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.51.0-py311h459d7ec_0.conda#17e1997cc17c571d5ad27bd0159f616c +https://conda.anaconda.org/conda-forge/linux-64/glib-2.80.0-hf2295e7_1.conda#d3bcc5c186f78feba6f39ea047c35950 https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.3-nompi_h4f84152_100.conda#d471a5c3abc984b662d9bae3bb7fd8a5 -https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.0.1-pyha770c72_0.conda#746623a787e06191d80a2133e5daff17 +https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.1.0-pyha770c72_0.conda#0896606848b2dc5cebdf111b6543aa04 https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.3-pyhd8ed1ab_0.conda#e7d8df6509ba635247ff9aea31134262 https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-21_linux64_openblas.conda#4a3816d06451c4946e2db26b86472cb6 +https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_h127d8a8_5.conda#09b94dd3a7e304df5b83176239347920 https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-h119a65a_9.conda#cfebc557e54905dadc355c0e9f003004 +https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.0-hac7e632_1003.conda#50c389a09b6b7babaef531eb7cb5e0ca https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-21_linux64_openblas.conda#1a42f305615c3867684e049e85927531 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-2024.0.0-h2e90f83_4.conda#126a2a61d276c4268f71adeef25bfc33 +https://conda.anaconda.org/conda-forge/linux-64/libva-2.21.0-hd590300_0.conda#e50a2609159a3e336fe4092738c00687 +https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.7.0-h662e7e4_0.conda#b32c0da42b1f24a98577bb3d7fc0b995 https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.8.0-pyhd8ed1ab_0.conda#2a75b296096adabbabadd5e9782e5fcc https://conda.anaconda.org/conda-forge/noarch/partd-1.4.1-pyhd8ed1ab_0.conda#acf4b7c0bcd5fa3b0e05801c4d2accd6 -https://conda.anaconda.org/conda-forge/linux-64/pillow-10.2.0-py311ha6c5da5_0.conda#a5ccd7f2271f28b7d2de0b02b64e3796 +https://conda.anaconda.org/conda-forge/linux-64/pillow-10.3.0-py311h18e6fac_0.conda#6c520a9d36c9d7270988c7a6c360d6d4 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.0.0-pyhd8ed1ab_0.conda#5ba1cc5b924226349d4a49fb547b7579 -https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 -https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.9.0-hd8ed1ab_0.conda#c16524c1b7227dc80b36b4fa6f77cc86 -https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.0-pyhd8ed1ab_0.conda#6a7e0694921f668a030d52f0c47baebd -https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.25.0-pyhd8ed1ab_0.conda#c119653cba436d8183c27bf6d190e587 +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-client-16.1-hb77b528_5.conda#ac902ff3c1c6d750dd0dfc93a974ab74 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.1.1-pyhd8ed1ab_0.conda#94ff09cdedcb7b17e9cd5097ee2cfcff +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-devel-2021.11.0-h5ccd973_1.conda#9dd2dc16536b2839b8f895f716c0366c +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.11.0-hd8ed1ab_0.conda#471e3988f8ca5e9eb3ce6be7eac3bcee +https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda#08807a87fa7af10754d46f63b368e016 +https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.25.1-pyhd8ed1ab_0.conda#8797a4e26be36880a603aba29c785352 +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.3-py311h459d7ec_1.conda#7fd17e8947afbddd2855720d643a48f0 +https://conda.anaconda.org/conda-forge/noarch/asv_runner-0.2.1-pyhd8ed1ab_0.conda#fdcbeb072c80c805a2ededaa5f91cd79 +https://conda.anaconda.org/conda-forge/linux-64/glew-2.1.0-h9c3ff4c_2.tar.bz2#fb05eb5c47590b247658243d27fc32f1 +https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.22.9-h98fc4e7_0.conda#bcc7157b06fce7f5e055402a8135dfd8 https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-8.3.0-h3d44ed6_0.conda#5a6f6c00ef982a9bc83558d9ac8f64a0 -https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-7.0.1-hd8ed1ab_0.conda#4a2f43a20fa404b998859c6a470ba316 +https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-7.1.0-hd8ed1ab_0.conda#6ef2b72d291b39e479d7694efa2b2b98 https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.2-nompi_h9612171_113.conda#b2414908e43c442ddc68e6148774a304 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-batch-plugin-2024.0.0-hd5fc58b_4.conda#de9c380fea8634540db5fc8422888df1 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-plugin-2024.0.0-hd5fc58b_4.conda#de1cbf145ecdc1d29af18e14eb267bca +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-hetero-plugin-2024.0.0-h3ecfda7_4.conda#016b763e4776b4c2c536420a7e6a2349 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-cpu-plugin-2024.0.0-h2e90f83_4.conda#d866cc8dc37f101505e65a4372794631 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-gpu-plugin-2024.0.0-h2e90f83_4.conda#6ebefdc74cb700ec82cd6702125cc422 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-ir-frontend-2024.0.0-h3ecfda7_4.conda#6397395a4677d59bbd32c4f05bb8fa63 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-onnx-frontend-2024.0.0-h757c851_4.conda#24c9cf1dd8f6d6189102a136a731758c +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-paddle-frontend-2024.0.0-h757c851_4.conda#259bd0c788f447fe78aab69895365528 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-pytorch-frontend-2024.0.0-h59595ed_4.conda#ec121a4195acadad086f84719cc91430 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-frontend-2024.0.0-hca94c1a_4.conda#bdbf11f760f1a3b35d766e03cebd9c42 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-lite-frontend-2024.0.0-h59595ed_4.conda#4354ea9f30a8c5111403fa4b24a2ad66 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/pytest-cov-4.1.0-pyhd8ed1ab_0.conda#06eb685a3a0b146347a58dda979485da +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.5.0-pyhd8ed1ab_0.conda#d5f595da2daead898ca958ac62f0307b https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda#a30144e4156cdbb236f99ebb49828f8b -https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-8.0.4-pyhd8ed1ab_0.conda#3b8ef3a2d80f3d89d0ae7e3c975e6c57 +https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-8.0.4-pyhd8ed1ab_1.conda#a1986ad21c766ff22f7bae93f0641020 https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py311h9547e67_4.conda#586da7df03b68640de14dc3e8bcbf76f https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.3-py311h1f0f07a_0.conda#b7e6d52b39e199238c3400cafaabafb3 +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.0-py311h9547e67_0.conda#40828c5b36ef52433e21f89943e09f33 -https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.1.1-pyhd8ed1ab_0.conda#1a92a5bd77b2430796696e25c3d8dbcb -https://conda.anaconda.org/conda-forge/noarch/identify-2.5.33-pyhd8ed1ab_0.conda#93c8f8ceb83827d88deeba796f07fba7 +https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.4.1-pyhd8ed1ab_0.conda#52387f00fee8dcd5cf75f8886025293f +https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.22.9-h8e1006c_0.conda#614b81f8ed66c56b640faee7076ad14a +https://conda.anaconda.org/conda-forge/noarch/identify-2.5.35-pyhd8ed1ab_0.conda#9472bfd206a2b7bb8143835e37667054 +https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.1-h8fe9dca_1.conda#c306fd9cc90c0585171167d09135a827 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_hacb5139_103.conda#50f05f98d084805642d24dff910e11e8 -https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.0-py311h320fe9a_0.conda#b9e7a2cb2c47bbb99c05d1892500be45 -https://conda.anaconda.org/conda-forge/linux-64/pango-1.50.14-ha41ecd1_2.conda#1a66c10f6a0da3dbd2f3a68127e7f6a0 +https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.1-py311h320fe9a_0.conda#aac8d7137fedc2fd5f8320bf50e4204c +https://conda.anaconda.org/conda-forge/linux-64/pango-1.52.2-ha41ecd1_0.conda#a658eeabf188c3040da36b0763de2bfd +https://conda.anaconda.org/conda-forge/noarch/pooch-1.8.1-pyhd8ed1ab_0.conda#d15917f33140f8d2ac9ca44db7ec8a25 +https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.3.11-py311h1f0f07a_0.conda#8a18202ff25c26a81a230e3eaf657b3c https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.4.1-py311h1f0f07a_1.conda#86b71ff85f3e4c8a98b5bace6d9c4565 -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.12.0-py311h64a7726_2.conda#24ca5107ab75c5521067b8ba505dfae5 -https://conda.anaconda.org/conda-forge/linux-64/shapely-2.0.2-py311h2032efe_1.conda#4ba860ff851768615b1a25b788022750 +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.13.0-py311h64a7726_0.conda#d443c70b4a05f50236c70b9c79beff64 +https://conda.anaconda.org/conda-forge/linux-64/shapely-2.0.3-py311h2032efe_0.conda#e982956906078eeac9feb3b8db10d011 https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-apidoc-0.3.0-py_1.tar.bz2#855b087883443abb10f5faf6eef40860 +https://conda.anaconda.org/conda-forge/noarch/wslink-1.12.4-pyhd8ed1ab_0.conda#9c8a6235a36aaf096be3118daba08a7b https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.2.0-py311h1f0f07a_4.conda#1e105c1a8ea2163507726144b401eb1b -https://conda.anaconda.org/conda-forge/noarch/distributed-2024.1.1-pyhd8ed1ab_0.conda#81039f39690f341dcb0a68bf62e812be -https://conda.anaconda.org/conda-forge/linux-64/esmf-8.4.2-nompi_h9e768e6_3.conda#c330e87e698bae8e7381c0315cf25dd0 -https://conda.anaconda.org/conda-forge/linux-64/gtk2-2.24.33-h7f000aa_3.conda#0abfa7f9241a0f4fd732bc15773cfb0c +https://conda.anaconda.org/conda-forge/noarch/distributed-2024.4.1-pyhd8ed1ab_0.conda#822b8d8216764941bb099fea588127ad +https://conda.anaconda.org/conda-forge/linux-64/esmf-8.6.0-nompi_h7b237b1_0.conda#a5f1925a75d9fcf0bffd07a194f83895 +https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-6.1.1-gpl_hee4b679_107.conda#a9865c001fa2e03272895e23b10bc55f +https://conda.anaconda.org/conda-forge/linux-64/gtk2-2.24.33-h280cfa0_4.conda#410f86e58e880dcc7b0e910a8e89c05c 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.56.3-he3f83f7_1.conda#03bd1ddcc942867a19528877143b9852 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.8.2-py311h54ef318_0.conda#9f80753bc008bfc9b95f39d9ff9f1694 +https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.58.0-hce6bd6c_0.conda#0891de8980ee29828542dbf9578838b9 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.8.3-py311h54ef318_0.conda#014c115be880802d2372ac6ed665f526 https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.6.5-nompi_py311he8ad708_100.conda#597b1ad6cb7011b7561c20ea30295cae -https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.6.0-pyha770c72_0.conda#473a7cfca197da0a10cff3f6dded7d4b +https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.7.0-pyha770c72_0.conda#846ba0877cda9c4f11e13720cacd1968 https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.3.0-py311h1f0f07a_1.conda#cd36a89a048ad2bcc6d8b43f648fb1d0 +https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.8-h5810be5_19.conda#54866f708d43002a514d0b9b0f84bc11 https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.22.0-py311h320fe9a_1.conda#10d1806e20da040c58c36deddf51c70c -https://conda.anaconda.org/conda-forge/noarch/esmpy-8.4.2-pyhc1e730c_4.conda#ddcf387719b2e44df0cc4dd467643951 +https://conda.anaconda.org/conda-forge/noarch/cmocean-3.1.3-pyhd8ed1ab_0.conda#671543f081d6be0b6b3e99b586386b44 +https://conda.anaconda.org/conda-forge/noarch/esmpy-8.6.0-pyhc1e730c_0.conda#60404b48ef1ccfb92cfd055f8844b700 https://conda.anaconda.org/conda-forge/linux-64/graphviz-9.0.0-h78e8752_1.conda#a3f4cd4a512ec5db35ffbf25ba11f537 https://conda.anaconda.org/conda-forge/noarch/nc-time-axis-1.4.1-pyhd8ed1ab_0.tar.bz2#281b58948bf60a2582de9e548bcc5369 +https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.2.6-qt_py311h1234567_220.conda#bbfafb0cc0483c89ea2289381dc157a5 +https://conda.anaconda.org/conda-forge/linux-64/vtk-io-ffmpeg-9.2.6-qt_py311h1234567_220.conda#0e894286dd36bdc569d7fd4e8033f8d9 +https://conda.anaconda.org/conda-forge/linux-64/vtk-9.2.6-qt_py311h1234567_220.conda#bd6689b3212fc662bd6cbc57e29ec0dc +https://conda.anaconda.org/conda-forge/noarch/pyvista-0.43.4-pyhd8ed1ab_0.conda#21e567168518369ce3f1c51e69b8ac0e +https://conda.anaconda.org/conda-forge/noarch/geovista-0.4.1-pyhd8ed1ab_0.conda#8dbe5526321fa7f1cb4dbc4f1644dcb3 https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.15.2-pyhd8ed1ab_0.conda#ce99859070b0e17ccc63234ca58f3ed8 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.5.0-pyhd8ed1ab_0.conda#264b3c697fa9cdade87eb0abe4440d54 @@ -225,5 +333,5 @@ https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd 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-5.3.0-pyhd8ed1ab_0.tar.bz2#f9e1fcfe235d655900bfeb6aee426472 +https://conda.anaconda.org/conda-forge/noarch/sphinx-7.2.6-pyhd8ed1ab_0.conda#bbfd1120d1824d2d073bc65935f0e4c0 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 new file mode 100644 index 0000000000..f20fd59dbc --- /dev/null +++ b/requirements/locks/py312-linux-64.lock @@ -0,0 +1,337 @@ +# Generated by conda-lock. +# platform: linux-64 +# input_hash: 6f31914101be564e474e4b447f6aa652860ada16e5b9c1f301b61cfbac5bf442 +@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.2.2-hbcca054_0.conda#2f4327a1cbe7f022401b236e915a5fef +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_1.conda#6185f640c43843e5ad6fd1c5372c3f80 +https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda#7aca3059a1729aa76c597603f10b0dd3 +https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-13.2.0-h7e041cc_5.conda#f6f6600d18a4047b54f803cf708b868a +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/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-13.2.0-h807b86a_5.conda#d211c42b9ce49aee3734fdc828731689 +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-13.2.0-h807b86a_5.conda#d4ff227c46917d3b4565302a2bbb276b +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.11-hd590300_1.conda#0bb492cca54017ea314b809b1ee3a176 +https://conda.anaconda.org/conda-forge/linux-64/aom-3.8.2-h59595ed_0.conda#625e1fed28a5139aed71b3a76117ef84 +https://conda.anaconda.org/conda-forge/linux-64/attr-2.5.1-h166bdaf_1.tar.bz2#d9c69a24ad678ffce24c6543a0176b00 +https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hd590300_5.conda#69b8b6202a07720f448be700e300ccf4 +https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.28.1-hd590300_0.conda#dcde58ff9a1f30b0037a2315d1846d1f +https://conda.anaconda.org/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda#418c6ca5929a611cbd69204907a83995 +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/fribidi-1.0.10-h36c2ea0_0.tar.bz2#ac7bc6a654f8f41b352b38f4051135f8 +https://conda.anaconda.org/conda-forge/linux-64/geos-3.12.1-h59595ed_0.conda#8c0f4f71f5a59ceb0c6fa9f51501066d +https://conda.anaconda.org/conda-forge/linux-64/gettext-0.21.1-h27087fc_0.tar.bz2#14947d8770185e5153fdd04d4673ed37 +https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.1-h0b41bf4_3.conda#96f3b11872ef6fad973eac856cd2624f +https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-h59595ed_1.conda#e358c7c5f6824c272b5034b3816438a7 +https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.conda#f87c7b7c2cb45f323ffbce941c78ab7c +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/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/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f +https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240116.1-cxx17_h59595ed_2.conda#75648bc5dd3b8eab22406876c24d81ec +https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.3-h59595ed_0.conda#5e97e271911b8b2001a8b71860c32faa +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/libev-4.33-hd590300_2.conda#172bf1cd1ff8629f2b1179945ed45055 +https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.5.0-hcb278e6_1.conda#6305a3dd2752c76335295da4e581f2fd +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/libgfortran5-13.2.0-ha4646dd_5.conda#7a6bd7a12a4bd359e2afe6c0fa1acace +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/libmo_unpack-3.1.2-hf484d3e_1001.tar.bz2#95f32a6a5a666d33886ca5627239f03d +https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda#30fd6e37fe21f86f4bd26d6ee73eeec7 +https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2#6e8cc2173440d77708196c5b93771680 +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/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/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b +https://conda.anaconda.org/conda-forge/linux-64/libvpx-1.14.0-h59595ed_0.conda#01c76c6d71097a0f3bd8683a8f255123 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.3.2-hd590300_0.conda#30de3fd9b3b602f7473f30e684eeea8c +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.2.13-hd590300_5.conda#f36c115f1ee199da648e0597ec2047ad +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/mpg123-1.32.6-h59595ed_0.conda#9160cdeb523a1b20cf8d2a0bf821f45d +https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.4.20240210-h59595ed_0.conda#97da8860a0da5413c7c98a3b3838a645 +https://conda.anaconda.org/conda-forge/linux-64/nettle-3.9.1-h7ab15ed_0.conda#2bf1915cc107738811368afcb0993a59 +https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda#da0ec11a6454ae19bff5b02ed881a2b1 +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/openh264-2.4.1-h59595ed_0.conda#3dfcf61b8e78af08110f5229f79580af +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.2.1-hd590300_1.conda#9d731343cff6ee2e5a25c4a091bf8e2a +https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 +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/pugixml-1.14-h59595ed_0.conda#2c97dd90633508b422c11bd3018206ab +https://conda.anaconda.org/conda-forge/linux-64/snappy-1.1.10-h9fff704_0.conda#e6d228cd0bb74a51dd18f5bfce0b4115 +https://conda.anaconda.org/conda-forge/linux-64/svt-av1-2.0.0-h59595ed_0.conda#207e01ffa0eb2d2efb83fb6f46365a21 +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/x265-3.5-h924138e_3.tar.bz2#e7f6ed84d4623d52ee581325c1587a6b +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-renderproto-0.11.1-h7f98852_1002.tar.bz2#06feff3d2634e3097ce2fe681474b534 +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/expat-2.5.0-hcb278e6_1.conda#8b9b5aca60558d02ddaa09d599e55920 +https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda#bd77f8da987968ec3927990495dc22e4 +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/libcap-2.69-h0f662aa_0.conda#25cb5999faa414e5ccb2c1388f62d3d5 +https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.120-hd590300_0.conda#7c3071bdf1d28b331a06bda6e85ab607 +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/libevent-2.1.12-hf998b51_1.conda#a1cfcc585f0c42bf8d5546bb1dfb668d +https://conda.anaconda.org/conda-forge/linux-64/libflac-1.4.3-h59595ed_0.conda#ee48bf17cc83a00f59ca1494d5646869 +https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-13.2.0-h69a702a_5.conda#e73e9cfd1191783392131e6238bdb3e9 +https://conda.anaconda.org/conda-forge/linux-64/libgpg-error-1.48-h71f35ed_0.conda#4d18d86916705d352d5f4adfb7f0edd3 +https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.7-hd590300_0.conda#2b7b0d827c6447cc1d85dc06d5b5de46 +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/libprotobuf-4.25.3-h08a7969_0.conda#6945825cebd2aeb16af4c69d97c32c13 +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.45.2-h2797004_0.conda#866983a220e27a80cb75e85cb30466a1 +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/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 +https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.15-h0b41bf4_0.conda#33277193f5b92bad9fdd230eb700929c +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.6-h232c23b_1.conda#6853448e9ca1cfd5f15382afd2a6d123 +https://conda.anaconda.org/conda-forge/linux-64/libzip-1.10.1-h2629f0a_3.conda#ac79812548e7e8cf61f7b0abdef01d3b +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.0.33-hf1915f5_6.conda#80bf3b277c120dd294b51d404b931a75 +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.43-hcad00b1_0.conda#8292dea9e022d9610a11fce5e0896ed8 +https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 +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/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.2.13-hd590300_5.conda#68c34ec6149623be41a1933ab996a209 +https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.5-hfc55251_0.conda#04b88013080254850d6c01ed54810589 +https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.5-h0f2a231_0.conda#009521b7ed97cca25f8f997f9e745976 +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-h0708190_0.tar.bz2#438718bf8921ac70956d919d0e2cc487 +https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.7.9-hb077bed_0.conda#33eded89024f21659b1975886a4acf70 +https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.2-h659d440_0.conda#cd95826dbd331ed1be26bdf401432844 +https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.10.3-hd590300_0.conda#32d16ad533c59bb0a3c5ffaf16110829 +https://conda.anaconda.org/conda-forge/linux-64/libglib-2.80.0-hf2295e7_1.conda#0725f6081030c29b109088639824ff90 +https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.9.3-default_h554bfaf_1009.conda#f36ddc11ca46958197a45effdd286e45 +https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hb3ce162_4.conda#8a35df3cbc0c8b12cc8af9473ae75eef +https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.26-pthreads_h413a1c8_0.conda#760ae35415f5ba8b15d09df5afe8b23a +https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.2-hc60ed4a_1.conda#ef1910918dd895516a769ed36b5b3a4e +https://conda.anaconda.org/conda-forge/linux-64/libtheora-1.1.1-h7f98852_1005.tar.bz2#1a7c35f56343b7e9e8db20b296c7566c +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.6.0-h1dd3fc0_3.conda#66f03896ffbe1a110ffda05c7a856504 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.0.33-hca2cd23_6.conda#e87530d1b12dd7f4e0f856dc07358d60 +https://conda.anaconda.org/conda-forge/linux-64/nss-3.98-h1d7d5a4_0.conda#54b56c2fdf973656b748e0378900ec13 +https://conda.anaconda.org/conda-forge/linux-64/python-3.12.2-hab00c5b_0_cpython.conda#ad7b68400f3a6ebe72b00be093c7f301 +https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.45.2-h2c6b66d_0.conda#1423efca06ed343c1da0fc429bae0779 +https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-h40f5838_3.conda#6bb8deb138f87c9d48320ac21b87e7a1 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-hd590300_1.conda#9bfac7ccd94d54fd21a0501296d60424 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.0-h8ee46fc_1.conda#632413adcd8bc16b515cab87a2932913 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.9-hd590300_1.conda#e995b155d938b6779da6ace6c6b13816 +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.1-h8ee46fc_1.conda#90108a432fb5c6150ccfee3f03388656 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.7-h8ee46fc_0.conda#49e482d882669206653b095f5206c05b +https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda#def531a3ac77b7fb8c21d17bb5d0badb +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-hd4edc92_1.tar.bz2#6c72ec3e660a51736913ef6ea68c454b +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.2.2-pyhd8ed1ab_0.conda#0876280e409658fc6f9e75d035960333 +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/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/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/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d +https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.8-pyhd8ed1ab_0.conda#db16c66b759a64dc5183d69cc3745a52 +https://conda.anaconda.org/conda-forge/linux-64/docutils-0.20.1-py312h7900ff3_3.conda#1b90835ae26b9b8250b302649359a989 +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_2.conda#8d652ea2ee8eaee02ed8dc820bc794aa +https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.0-pyhd8ed1ab_0.conda#7a4b32fbe5442e46841ec77695e36d96 +https://conda.anaconda.org/conda-forge/noarch/filelock-3.13.3-pyhd8ed1ab_0.conda#ff15f46b0d34308f4d40c1c51df07592 +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.3.1-pyhca7485f_0.conda#b7f0662ef2c9d4404f0af9eef5ed2fde +https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.10-h829c605_5.conda#8fdb82e5d9694dd8e9ed9ac8fdf48a26 +https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.80.0-hde27a5a_1.conda#939ddd853b1d98bf6fd22cc0adeda317 +https://conda.anaconda.org/conda-forge/linux-64/gts-0.7.6-h977cf35_4.conda#4d8df0b0db060d33c9a702ada998a8fe +https://conda.anaconda.org/conda-forge/noarch/idna-3.6-pyhd8ed1ab_0.conda#1a76f09108576397c41c0b0c5bd84134 +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/linux-64/lcms2-2.16-hb7c19ff_0.conda#51bb7010fc86f70eee639b4bb7a894f5 +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-21_linux64_openblas.conda#0ac9f44fc096772b0aa092119b00c3ca +https://conda.anaconda.org/conda-forge/linux-64/libclang13-15.0.7-default_h5d6823c_5.conda#2d694a9ffdcc30e89dea34a8dcdab6ae +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.7.1-hca28451_0.conda#755c7f876815003337d2c61ff5d047e5 +https://conda.anaconda.org/conda-forge/linux-64/libpq-16.2-h33b98f1_1.conda#9e49ec2a61d02623b379dc332eb6889d +https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-255-h3516f8a_1.conda#3366af27f0b593544a6cd453c7932ac5 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.3.2-h658648e_1.conda#0ebb65e8d86843865796c7c95a941f34 +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.7-py312h8572e83_0.conda#1ae83e30fae86320e888cb4b1f2d3b47 +https://conda.anaconda.org/conda-forge/linux-64/multidict-6.0.5-py312h98912ed_0.conda#d0d2cab29d6c33c47f719d7a1879e08b +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.0-pyhd8ed1ab_0.conda#248f521b64ce055e7feae3105e7abeb8 +https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.0-pyhd8ed1ab_0.conda#a0bc3eec34b0fab84be6b2da94e98e20 +https://conda.anaconda.org/conda-forge/noarch/pluggy-1.4.0-pyhd8ed1ab_0.conda#139e9feb65187e916162917bb2484976 +https://conda.anaconda.org/conda-forge/linux-64/psutil-5.9.8-py312h98912ed_0.conda#3facaca6cc0f7988df3250efccd32da3 +https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda#844d9eb3b43095b031874477f7d70088 +https://conda.anaconda.org/conda-forge/noarch/pygments-2.17.2-pyhd8ed1ab_0.conda#140a7f159396547e9799aa98f9f0742e +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.1.2-pyhd8ed1ab_0.conda#b9a4dacf97241704529131a0dfc0494f +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/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/noarch/scooby-0.9.2-pyhd8ed1ab_0.conda#66dc03353b88f5f2db8c630854174a3f +https://conda.anaconda.org/conda-forge/noarch/setuptools-69.2.0-pyhd8ed1ab_0.conda#da214ecd521a720a9d521c68047682dc +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 +https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.5-pyhd8ed1ab_1.conda#3f144b2c34f8cb5a9abd9ed23a39c561 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda#da1d979339e2714c30a8e806a33ec087 +https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.11.0-h00ab1b0_1.conda#4531d2927578e7e254ff3bcf6457518c +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-py312h98912ed_0.conda#e8332e534dca8c5c12c8352e0a23501c +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.11.0-pyha770c72_0.conda#6ef2fc37559256cf682d8b3375e89b80 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.43.0-pyhd8ed1ab_1.conda#0b5293a157c2b5cd513dd1b03d8d3aae +https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-h8ee46fc_1.conda#9d7bcddf49cbf727730af10e71022c73 +https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.41-hd590300_0.conda#81f740407b45e3f9047b3174fa94eb9e +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/noarch/zict-3.0.0-pyhd8ed1ab_0.conda#cf30c2c15b82aacb07f9c09e28ff2275 +https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda#2e4d6bc0b14e10f895fc6791a7d9b26a +https://conda.anaconda.org/conda-forge/noarch/accessible-pygments-0.0.4-pyhd8ed1ab_0.conda#46a2e6e3dfa718ce3492018d5a110dd6 +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-h3faef2a_0.conda#f907bb958910dc404647326ca80c263e +https://conda.anaconda.org/conda-forge/linux-64/cffi-1.16.0-py312hf06ca03_0.conda#56b0ca764ce23cc54f3f7e2a7b970f6d +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.4.4-py312h98912ed_0.conda#7002151fcfe55ded0595fc7c3f5e1209 +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.51.0-py312h98912ed_0.conda#f0cd0e54adf65aaa976f5731b7a3f383 +https://conda.anaconda.org/conda-forge/linux-64/glib-2.80.0-hf2295e7_1.conda#d3bcc5c186f78feba6f39ea047c35950 +https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.3-nompi_h4f84152_100.conda#d471a5c3abc984b662d9bae3bb7fd8a5 +https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.1.0-pyha770c72_0.conda#0896606848b2dc5cebdf111b6543aa04 +https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.3-pyhd8ed1ab_0.conda#e7d8df6509ba635247ff9aea31134262 +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-21_linux64_openblas.conda#4a3816d06451c4946e2db26b86472cb6 +https://conda.anaconda.org/conda-forge/linux-64/libclang-15.0.7-default_h127d8a8_5.conda#09b94dd3a7e304df5b83176239347920 +https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-h119a65a_9.conda#cfebc557e54905dadc355c0e9f003004 +https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.0-hac7e632_1003.conda#50c389a09b6b7babaef531eb7cb5e0ca +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-21_linux64_openblas.conda#1a42f305615c3867684e049e85927531 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-2024.0.0-h2e90f83_4.conda#126a2a61d276c4268f71adeef25bfc33 +https://conda.anaconda.org/conda-forge/linux-64/libva-2.21.0-hd590300_0.conda#e50a2609159a3e336fe4092738c00687 +https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.7.0-h662e7e4_0.conda#b32c0da42b1f24a98577bb3d7fc0b995 +https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.8.0-pyhd8ed1ab_0.conda#2a75b296096adabbabadd5e9782e5fcc +https://conda.anaconda.org/conda-forge/noarch/partd-1.4.1-pyhd8ed1ab_0.conda#acf4b7c0bcd5fa3b0e05801c4d2accd6 +https://conda.anaconda.org/conda-forge/linux-64/pillow-10.3.0-py312hdcec9eb_0.conda#425bb325f970e57a047ac57c4586489d +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/linux-64/pulseaudio-client-16.1-hb77b528_5.conda#ac902ff3c1c6d750dd0dfc93a974ab74 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.1.1-pyhd8ed1ab_0.conda#94ff09cdedcb7b17e9cd5097ee2cfcff +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-devel-2021.11.0-h5ccd973_1.conda#9dd2dc16536b2839b8f895f716c0366c +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.11.0-hd8ed1ab_0.conda#471e3988f8ca5e9eb3ce6be7eac3bcee +https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda#08807a87fa7af10754d46f63b368e016 +https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.25.1-pyhd8ed1ab_0.conda#8797a4e26be36880a603aba29c785352 +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.3-py312h98912ed_1.conda#defaa0b8dea3553ca6ee750626a06e87 +https://conda.anaconda.org/conda-forge/noarch/asv_runner-0.2.1-pyhd8ed1ab_0.conda#fdcbeb072c80c805a2ededaa5f91cd79 +https://conda.anaconda.org/conda-forge/linux-64/glew-2.1.0-h9c3ff4c_2.tar.bz2#fb05eb5c47590b247658243d27fc32f1 +https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.22.9-h98fc4e7_0.conda#bcc7157b06fce7f5e055402a8135dfd8 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-8.3.0-h3d44ed6_0.conda#5a6f6c00ef982a9bc83558d9ac8f64a0 +https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-7.1.0-hd8ed1ab_0.conda#6ef2b72d291b39e479d7694efa2b2b98 +https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.2-nompi_h9612171_113.conda#b2414908e43c442ddc68e6148774a304 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-batch-plugin-2024.0.0-hd5fc58b_4.conda#de9c380fea8634540db5fc8422888df1 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-plugin-2024.0.0-hd5fc58b_4.conda#de1cbf145ecdc1d29af18e14eb267bca +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-hetero-plugin-2024.0.0-h3ecfda7_4.conda#016b763e4776b4c2c536420a7e6a2349 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-cpu-plugin-2024.0.0-h2e90f83_4.conda#d866cc8dc37f101505e65a4372794631 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-gpu-plugin-2024.0.0-h2e90f83_4.conda#6ebefdc74cb700ec82cd6702125cc422 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-ir-frontend-2024.0.0-h3ecfda7_4.conda#6397395a4677d59bbd32c4f05bb8fa63 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-onnx-frontend-2024.0.0-h757c851_4.conda#24c9cf1dd8f6d6189102a136a731758c +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-paddle-frontend-2024.0.0-h757c851_4.conda#259bd0c788f447fe78aab69895365528 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-pytorch-frontend-2024.0.0-h59595ed_4.conda#ec121a4195acadad086f84719cc91430 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-frontend-2024.0.0-hca94c1a_4.conda#bdbf11f760f1a3b35d766e03cebd9c42 +https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-lite-frontend-2024.0.0-h59595ed_4.conda#4354ea9f30a8c5111403fa4b24a2ad66 +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/pytest-cov-5.0.0-pyhd8ed1ab_0.conda#c54c0107057d67ddf077751339ec2c63 +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.5.0-pyhd8ed1ab_0.conda#d5f595da2daead898ca958ac62f0307b +https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda#a30144e4156cdbb236f99ebb49828f8b +https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-8.0.4-pyhd8ed1ab_1.conda#a1986ad21c766ff22f7bae93f0641020 +https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py312h8572e83_4.conda#52c9e25ee0a32485a102eeecdb7eef52 +https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.3-py312hc7c0aa3_0.conda#bd11505f0fe9bd8bcec01ce1220f63c7 +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.0-py312h8572e83_0.conda#b6249daaaf4577e6f72d95fc4ab767c6 +https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.4.1-pyhd8ed1ab_0.conda#52387f00fee8dcd5cf75f8886025293f +https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.22.9-h8e1006c_0.conda#614b81f8ed66c56b640faee7076ad14a +https://conda.anaconda.org/conda-forge/noarch/identify-2.5.35-pyhd8ed1ab_0.conda#9472bfd206a2b7bb8143835e37667054 +https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.1-h8fe9dca_1.conda#c306fd9cc90c0585171167d09135a827 +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_hacb5139_103.conda#50f05f98d084805642d24dff910e11e8 +https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.1-py312hfb8ada1_0.conda#e8fcd9179004edd4fb1bcd888d0aeb47 +https://conda.anaconda.org/conda-forge/linux-64/pango-1.52.2-ha41ecd1_0.conda#a658eeabf188c3040da36b0763de2bfd +https://conda.anaconda.org/conda-forge/noarch/pooch-1.8.1-pyhd8ed1ab_0.conda#d15917f33140f8d2ac9ca44db7ec8a25 +https://conda.anaconda.org/conda-forge/linux-64/pykdtree-1.3.11-py312hc7c0aa3_0.conda#38b3ec047cefe673613dd406f605e009 +https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.4.1-py312hc7c0aa3_1.conda#b91ccda9d16e7016efd831c7d8f97a9e +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.13.0-py312heda63a1_0.conda#c53b9f319cafc679476f5613599857e8 +https://conda.anaconda.org/conda-forge/linux-64/shapely-2.0.3-py312h9e6bd2c_0.conda#5e0580a84d702cda52c8b0245e4c14d2 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-apidoc-0.3.0-py_1.tar.bz2#855b087883443abb10f5faf6eef40860 +https://conda.anaconda.org/conda-forge/noarch/wslink-1.12.4-pyhd8ed1ab_0.conda#9c8a6235a36aaf096be3118daba08a7b +https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.2.0-py312hc7c0aa3_4.conda#d9c9fa64fdf4e57d7f8957b957d784a0 +https://conda.anaconda.org/conda-forge/noarch/distributed-2024.4.1-pyhd8ed1ab_0.conda#822b8d8216764941bb099fea588127ad +https://conda.anaconda.org/conda-forge/linux-64/esmf-8.6.0-nompi_h7b237b1_0.conda#a5f1925a75d9fcf0bffd07a194f83895 +https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-6.1.1-gpl_hee4b679_107.conda#a9865c001fa2e03272895e23b10bc55f +https://conda.anaconda.org/conda-forge/linux-64/gtk2-2.24.33-h280cfa0_4.conda#410f86e58e880dcc7b0e910a8e89c05c +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.0-hce6bd6c_0.conda#0891de8980ee29828542dbf9578838b9 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.8.3-py312he5832f3_0.conda#3b0545901b09b1376b9c0e0ec72409de +https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.6.5-nompi_py312h26027e0_100.conda#2d7b4954dc5a090796e0ba89c325d09b +https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.7.0-pyha770c72_0.conda#846ba0877cda9c4f11e13720cacd1968 +https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.3.0-py312hc7c0aa3_1.conda#81789bd582b389e77ff709f6b27300fb +https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.8-h5810be5_19.conda#54866f708d43002a514d0b9b0f84bc11 +https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.22.0-py312hfb8ada1_1.conda#17e09fffccc807ef2d2644f21883d64f +https://conda.anaconda.org/conda-forge/noarch/cmocean-3.1.3-pyhd8ed1ab_0.conda#671543f081d6be0b6b3e99b586386b44 +https://conda.anaconda.org/conda-forge/noarch/esmpy-8.6.0-pyhc1e730c_0.conda#60404b48ef1ccfb92cfd055f8844b700 +https://conda.anaconda.org/conda-forge/linux-64/graphviz-9.0.0-h78e8752_1.conda#a3f4cd4a512ec5db35ffbf25ba11f537 +https://conda.anaconda.org/conda-forge/noarch/nc-time-axis-1.4.1-pyhd8ed1ab_0.tar.bz2#281b58948bf60a2582de9e548bcc5369 +https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.2.6-qt_py312h1234567_220.conda#1dc0327554f77b69e50dd7e000bcb466 +https://conda.anaconda.org/conda-forge/linux-64/vtk-io-ffmpeg-9.2.6-qt_py312h1234567_220.conda#dd89b6944ac4f761f20825b51bbc891d +https://conda.anaconda.org/conda-forge/linux-64/vtk-9.2.6-qt_py312h1234567_220.conda#db449dc60b613f7835293890a0f5a8d1 +https://conda.anaconda.org/conda-forge/noarch/pyvista-0.43.4-pyhd8ed1ab_0.conda#21e567168518369ce3f1c51e69b8ac0e +https://conda.anaconda.org/conda-forge/noarch/geovista-0.4.1-pyhd8ed1ab_0.conda#8dbe5526321fa7f1cb4dbc4f1644dcb3 +https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.15.2-pyhd8ed1ab_0.conda#ce99859070b0e17ccc63234ca58f3ed8 +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.5.0-pyhd8ed1ab_0.conda#264b3c697fa9cdade87eb0abe4440d54 +https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.15.0-pyhd8ed1ab_0.conda#1a49ca9515ef9a96edff2eea06143dc6 +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.2.6-pyhd8ed1ab_0.conda#bbfd1120d1824d2d073bc65935f0e4c0 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda#e507335cb4ca9cff4c3d0fa9cdab255e diff --git a/requirements/locks/py39-linux-64.lock b/requirements/locks/py39-linux-64.lock deleted file mode 100644 index f68198c664..0000000000 --- a/requirements/locks/py39-linux-64.lock +++ /dev/null @@ -1,229 +0,0 @@ -# Generated by conda-lock. -# platform: linux-64 -# input_hash: 86ffb93b06ad756fa46d24f8877077b64c3a7cd8bda0399560525e53fed33f99 -@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.2.2-hbcca054_0.conda#2f4327a1cbe7f022401b236e915a5fef -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_1.conda#6185f640c43843e5ad6fd1c5372c3f80 -https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda#7aca3059a1729aa76c597603f10b0dd3 -https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-13.2.0-h7e041cc_5.conda#f6f6600d18a4047b54f803cf708b868a -https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.9-4_cp39.conda#bfe4b3259a8ac6cdf0037752904da6a7 -https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda#161081fc7cec0bfda0d86d7cb595f8d8 -https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 -https://conda.anaconda.org/conda-forge/linux-64/libgomp-13.2.0-h807b86a_5.conda#d211c42b9ce49aee3734fdc828731689 -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-13.2.0-h807b86a_5.conda#d4ff227c46917d3b4565302a2bbb276b -https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hd590300_5.conda#69b8b6202a07720f448be700e300ccf4 -https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.26.0-hd590300_0.conda#a86d90025198fd411845fc245ebc06c8 -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/geos-3.12.1-h59595ed_0.conda#8c0f4f71f5a59ceb0c6fa9f51501066d -https://conda.anaconda.org/conda-forge/linux-64/gettext-0.21.1-h27087fc_0.tar.bz2#14947d8770185e5153fdd04d4673ed37 -https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.1-h0b41bf4_3.conda#96f3b11872ef6fad973eac856cd2624f -https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h58526e2_1001.tar.bz2#8c54672728e8ec6aa6db90cf2806d220 -https://conda.anaconda.org/conda-forge/linux-64/icu-73.2-h59595ed_0.conda#cc47e1facc155f91abd89b11e48e72ff -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/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f -https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.2-h59595ed_1.conda#127b0be54c1c90760d7fe02ea7a56426 -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.19-hd590300_0.conda#1635570038840ee3f9c71d22aa5b8b6d -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.5.0-hcb278e6_1.conda#6305a3dd2752c76335295da4e581f2fd -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/libgfortran5-13.2.0-ha4646dd_5.conda#7a6bd7a12a4bd359e2afe6c0fa1acace -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/libmo_unpack-3.1.2-hf484d3e_1001.tar.bz2#95f32a6a5a666d33886ca5627239f03d -https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda#30fd6e37fe21f86f4bd26d6ee73eeec7 -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.3.2-hd590300_0.conda#30de3fd9b3b602f7473f30e684eeea8c -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.2.13-hd590300_5.conda#f36c115f1ee199da648e0597ec2047ad -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/ncurses-6.4-h59595ed_2.conda#7dbaa197d7ba6032caf7ae7f32c1efa0 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.2.1-hd590300_0.conda#51a753e64a3027bd7e23a189b1f6e91e -https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 -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/snappy-1.1.10-h9fff704_0.conda#e6d228cd0bb74a51dd18f5bfce0b4115 -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-renderproto-0.11.1-h7f98852_1002.tar.bz2#06feff3d2634e3097ce2fe681474b534 -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-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/expat-2.5.0-hcb278e6_1.conda#8b9b5aca60558d02ddaa09d599e55920 -https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda#bd77f8da987968ec3927990495dc22e4 -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/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 -https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-13.2.0-h69a702a_5.conda#e73e9cfd1191783392131e6238bdb3e9 -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.42-h2797004_0.conda#d67729828dc6ff7ba44a61062ad79880 -https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.45.1-h2797004_0.conda#fc4ccadfbf6d4784de88c41704792562 -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/libxcb-1.15-h0b41bf4_0.conda#33277193f5b92bad9fdd230eb700929c -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.5-h232c23b_0.conda#c442ebfda7a475f5e78f1c8e45f1e919 -https://conda.anaconda.org/conda-forge/linux-64/libzip-1.10.1-h2629f0a_3.conda#ac79812548e7e8cf61f7b0abdef01d3b -https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.42-hcad00b1_0.conda#679c8961826aa4b50653bce17ee52abe -https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 -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/xorg-libsm-1.2.4-h7391055_0.conda#93ee23f12bc2e684548181256edd2cf6 -https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-hd590300_5.conda#68c34ec6149623be41a1933ab996a209 -https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.5-hfc55251_0.conda#04b88013080254850d6c01ed54810589 -https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.5-h0f2a231_0.conda#009521b7ed97cca25f8f997f9e745976 -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/krb5-1.21.2-h659d440_0.conda#cd95826dbd331ed1be26bdf401432844 -https://conda.anaconda.org/conda-forge/linux-64/libglib-2.78.3-h783c2da_0.conda#9bd06b12bbfa6fd1740fd23af4b0f0c7 -https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.26-pthreads_h413a1c8_0.conda#760ae35415f5ba8b15d09df5afe8b23a -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.6.0-ha9c0a0a_2.conda#55ed21669b2015f77c180feb1dd41930 -https://conda.anaconda.org/conda-forge/linux-64/python-3.9.18-h0755675_1_cpython.conda#255a7002aeec7a067ff19b545aca6328 -https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.45.1-h2c6b66d_0.conda#93acf31b379acebada263b9bce3dc6ed -https://conda.anaconda.org/conda-forge/linux-64/udunits2-2.2.28-h40f5838_3.conda#6bb8deb138f87c9d48320ac21b87e7a1 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.7-h8ee46fc_0.conda#49e482d882669206653b095f5206c05b -https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda#def531a3ac77b7fb8c21d17bb5d0badb -https://conda.anaconda.org/conda-forge/noarch/antlr-python-runtime-4.11.1-pyhd8ed1ab_0.tar.bz2#15109c4977d39ad7aa3423f57243e286 -https://conda.anaconda.org/conda-forge/noarch/asv_runner-0.1.0-pyhd8ed1ab_0.conda#0e8715bef534217eae333c53f645c9ed -https://conda.anaconda.org/conda-forge/linux-64/atk-1.0-2.38.0-hd4edc92_1.tar.bz2#6c72ec3e660a51736913ef6ea68c454b -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-py39h3d6467e_1.conda#c48418c8b35f1d59ae9ae1174812b40a -https://conda.anaconda.org/conda-forge/noarch/certifi-2024.2.2-pyhd8ed1ab_0.conda#0876280e409658fc6f9e75d035960333 -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/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/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 -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.8-py39h3d6467e_0.conda#0261e43a0b124d1ced1e1af085e8bc3c -https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.8-pyhd8ed1ab_0.conda#db16c66b759a64dc5183d69cc3745a52 -https://conda.anaconda.org/conda-forge/linux-64/docutils-0.19-py39hf3d152e_1.tar.bz2#adb733ec2ee669f6d010758d054da60f -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_2.conda#8d652ea2ee8eaee02ed8dc820bc794aa -https://conda.anaconda.org/conda-forge/noarch/execnet-2.0.2-pyhd8ed1ab_0.conda#67de0d8241e1060a479e3c37793e26f9 -https://conda.anaconda.org/conda-forge/noarch/filelock-3.13.1-pyhd8ed1ab_0.conda#0c1729b74a8152fde6a38ba0a2ab9f45 -https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda#0f69b688f52ff6da70bccb7ff7001d1d -https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.2.0-pyhca7485f_0.conda#fad86b90138cf5d82c6f5a2ed6e683d9 -https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.42.10-h829c605_4.conda#252a696860674caf7a855e16f680d63a -https://conda.anaconda.org/conda-forge/linux-64/gts-0.7.6-h977cf35_4.conda#4d8df0b0db060d33c9a702ada998a8fe -https://conda.anaconda.org/conda-forge/noarch/idna-3.6-pyhd8ed1ab_0.conda#1a76f09108576397c41c0b0c5bd84134 -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-py39h7633fee_1.conda#c9f74d717e5a2847a9f8b779c54130f2 -https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.16-hb7c19ff_0.conda#51bb7010fc86f70eee639b4bb7a894f5 -https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-21_linux64_openblas.conda#0ac9f44fc096772b0aa092119b00c3ca -https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.5.0-hca28451_0.conda#7144d5a828e2cae218e0e3c98d8a0aeb -https://conda.anaconda.org/conda-forge/linux-64/libwebp-1.3.2-h658648e_1.conda#0ebb65e8d86843865796c7c95a941f34 -https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2#91e27ef3d05cc772ce627e51cff111c4 -https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.5-py39hd1e30aa_0.conda#9a9a22eb1f83c44953319ee3b027769f -https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.0.7-py39h7633fee_0.conda#f668e146a2ed03a4e62ffbb98b3115fb -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.0-h488ebb8_3.conda#128c25b7fe6a25286a48f3a6a9b5b6f3 -https://conda.anaconda.org/conda-forge/noarch/packaging-23.2-pyhd8ed1ab_0.conda#79002079284aa895f883c6b7f3f88fd6 -https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.0-pyhd8ed1ab_0.conda#a0bc3eec34b0fab84be6b2da94e98e20 -https://conda.anaconda.org/conda-forge/noarch/pluggy-1.4.0-pyhd8ed1ab_0.conda#139e9feb65187e916162917bb2484976 -https://conda.anaconda.org/conda-forge/linux-64/psutil-5.9.8-py39hd1e30aa_0.conda#ec86403fde8793ac1c36f8afa3d15902 -https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff -https://conda.anaconda.org/conda-forge/noarch/pygments-2.17.2-pyhd8ed1ab_0.conda#140a7f159396547e9799aa98f9f0742e -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.1.1-pyhd8ed1ab_0.conda#176f7d56f0cfe9008bdf1bccd7de02fb -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-2023.4-pyhd8ed1ab_0.conda#c79cacf8a06a51552fc651652f170208 -https://conda.anaconda.org/conda-forge/linux-64/python-xxhash-3.4.1-py39hd1e30aa_0.conda#756cb152772a225587a05ca0ec68fc08 -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-py39hd1e30aa_1.conda#37218233bcdc310e4fde6453bc1b40d8 -https://conda.anaconda.org/conda-forge/noarch/setuptools-69.0.3-pyhd8ed1ab_0.conda#40695fdfd15a92121ed2922900d0308b -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 -https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.5-pyhd8ed1ab_1.conda#3f144b2c34f8cb5a9abd9ed23a39c561 -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/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.3.3-py39hd1e30aa_1.conda#cbe186eefb0bcd91e8f47c3908489874 -https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.9.0-pyha770c72_0.conda#a92a6440c3fe7052d63244f3aba2a4a7 -https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-15.1.0-py39hd1e30aa_0.conda#1da984bbb6e765743e13388ba7b7b2c8 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.42.0-pyhd8ed1ab_0.conda#1cdea58981c5cbc17b51973bcaddcea7 -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-libxrender-0.9.11-hd590300_0.conda#ed67c36f215b310412b2af935bf3e530 -https://conda.anaconda.org/conda-forge/noarch/zict-3.0.0-pyhd8ed1ab_0.conda#cf30c2c15b82aacb07f9c09e28ff2275 -https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda#2e4d6bc0b14e10f895fc6791a7d9b26a -https://conda.anaconda.org/conda-forge/noarch/accessible-pygments-0.0.4-pyhd8ed1ab_0.conda#46a2e6e3dfa718ce3492018d5a110dd6 -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-h3faef2a_0.conda#f907bb958910dc404647326ca80c263e -https://conda.anaconda.org/conda-forge/linux-64/cffi-1.16.0-py39h7a31438_0.conda#ac992767d7f8ed2cb27e71e78f0fb2d7 -https://conda.anaconda.org/conda-forge/linux-64/cytoolz-0.12.3-py39hd1e30aa_0.conda#dc0fb8e157c7caba4c98f1e1f9d2e5f4 -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.48.1-py39hd1e30aa_0.conda#402ef3d9608c7653187a3fd6fd45b445 -https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.3-nompi_h4f84152_100.conda#d471a5c3abc984b662d9bae3bb7fd8a5 -https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.0.1-pyha770c72_0.conda#746623a787e06191d80a2133e5daff17 -https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.1.1-pyhd8ed1ab_0.conda#3d5fa25cf42f3f32a12b2d874ace8574 -https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.3-pyhd8ed1ab_0.conda#e7d8df6509ba635247ff9aea31134262 -https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-21_linux64_openblas.conda#4a3816d06451c4946e2db26b86472cb6 -https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-h119a65a_9.conda#cfebc557e54905dadc355c0e9f003004 -https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-21_linux64_openblas.conda#1a42f305615c3867684e049e85927531 -https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.8.0-pyhd8ed1ab_0.conda#2a75b296096adabbabadd5e9782e5fcc -https://conda.anaconda.org/conda-forge/noarch/partd-1.4.1-pyhd8ed1ab_0.conda#acf4b7c0bcd5fa3b0e05801c4d2accd6 -https://conda.anaconda.org/conda-forge/linux-64/pillow-10.2.0-py39had0adad_0.conda#2972754dc054bb079d1d121918b5126f -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.0.0-pyhd8ed1ab_0.conda#5ba1cc5b924226349d4a49fb547b7579 -https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984 -https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.9.0-hd8ed1ab_0.conda#c16524c1b7227dc80b36b4fa6f77cc86 -https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.0-pyhd8ed1ab_0.conda#6a7e0694921f668a030d52f0c47baebd -https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.25.0-pyhd8ed1ab_0.conda#c119653cba436d8183c27bf6d190e587 -https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-8.3.0-h3d44ed6_0.conda#5a6f6c00ef982a9bc83558d9ac8f64a0 -https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.1.1-pyhd8ed1ab_0.conda#d04bd1b5bed9177dd7c3cef15e2b6710 -https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-7.0.1-hd8ed1ab_0.conda#4a2f43a20fa404b998859c6a470ba316 -https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.2-nompi_h9612171_113.conda#b2414908e43c442ddc68e6148774a304 -https://conda.anaconda.org/conda-forge/linux-64/numpy-1.26.4-py39h474f0d3_0.conda#aa265f5697237aa13cc10f53fa8acc4f -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-py39h15b0fa6_5.conda#85e186c7ff673b0d0026782ec353fb2a -https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.5.0-pyhd8ed1ab_0.conda#d5f595da2daead898ca958ac62f0307b -https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda#a30144e4156cdbb236f99ebb49828f8b -https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-8.0.4-pyhd8ed1ab_0.conda#3b8ef3a2d80f3d89d0ae7e3c975e6c57 -https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py39h7633fee_4.conda#b66595fbda99771266f042f42c7457be -https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.3-py39h44dd56e_0.conda#baea2f5dfb3ab7b1c836385d2e1daca7 -https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.2.0-py39h7633fee_0.conda#ed71ad3e30eb03da363fb797419cce98 -https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.1.1-pyhd8ed1ab_0.conda#1a92a5bd77b2430796696e25c3d8dbcb -https://conda.anaconda.org/conda-forge/noarch/identify-2.5.33-pyhd8ed1ab_0.conda#93c8f8ceb83827d88deeba796f07fba7 -https://conda.anaconda.org/conda-forge/linux-64/mo_pack-0.3.0-py39hd1e30aa_1.conda#ca63612907462c8e36edcc9bbacc253e -https://conda.anaconda.org/conda-forge/linux-64/netcdf-fortran-4.6.1-nompi_hacb5139_103.conda#50f05f98d084805642d24dff910e11e8 -https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.0-py39hddac248_0.conda#95aaa7baa61432a1ce85dedb7b86d2dd -https://conda.anaconda.org/conda-forge/linux-64/pango-1.50.14-ha41ecd1_2.conda#1a66c10f6a0da3dbd2f3a68127e7f6a0 -https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.4.1-py39h44dd56e_1.conda#d037c20e3da2e85f03ebd20ad480c359 -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.12.0-py39h474f0d3_2.conda#6ab241b2023730f6b41712dc1b503afa -https://conda.anaconda.org/conda-forge/linux-64/shapely-2.0.2-py39h6404dd3_1.conda#05623249055d99c51cde021b525611db -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-apidoc-0.3.0-py_1.tar.bz2#855b087883443abb10f5faf6eef40860 -https://conda.anaconda.org/conda-forge/linux-64/cf-units-3.2.0-py39h44dd56e_4.conda#81310d21bf9d91754c1220c585bb72d6 -https://conda.anaconda.org/conda-forge/noarch/distributed-2024.1.1-pyhd8ed1ab_0.conda#81039f39690f341dcb0a68bf62e812be -https://conda.anaconda.org/conda-forge/linux-64/esmf-8.4.2-nompi_h9e768e6_3.conda#c330e87e698bae8e7381c0315cf25dd0 -https://conda.anaconda.org/conda-forge/linux-64/gtk2-2.24.33-h7f000aa_3.conda#0abfa7f9241a0f4fd732bc15773cfb0c -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.56.3-he3f83f7_1.conda#03bd1ddcc942867a19528877143b9852 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.8.2-py39he9076e7_0.conda#6085411aa2f0b2b801d3b46e1d3b83c5 -https://conda.anaconda.org/conda-forge/linux-64/netcdf4-1.6.5-nompi_py39h4282601_100.conda#d2809fbf0d8ae7b8ca92c456cb44a7d4 -https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.6.0-pyha770c72_0.conda#473a7cfca197da0a10cff3f6dded7d4b -https://conda.anaconda.org/conda-forge/linux-64/python-stratify-0.3.0-py39h44dd56e_1.conda#90c5165691fdcb5a9f43907e32ea48b4 -https://conda.anaconda.org/conda-forge/linux-64/cartopy-0.22.0-py39hddac248_1.conda#8dd2eb1e7aa9a33a92a75bdcea3f0dd0 -https://conda.anaconda.org/conda-forge/noarch/esmpy-8.4.2-pyhc1e730c_4.conda#ddcf387719b2e44df0cc4dd467643951 -https://conda.anaconda.org/conda-forge/linux-64/graphviz-9.0.0-h78e8752_1.conda#a3f4cd4a512ec5db35ffbf25ba11f537 -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/pydata-sphinx-theme-0.15.2-pyhd8ed1ab_0.conda#ce99859070b0e17ccc63234ca58f3ed8 -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.5.0-pyhd8ed1ab_0.conda#264b3c697fa9cdade87eb0abe4440d54 -https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.15.0-pyhd8ed1ab_0.conda#1a49ca9515ef9a96edff2eea06143dc6 -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-5.3.0-pyhd8ed1ab_0.tar.bz2#f9e1fcfe235d655900bfeb6aee426472 -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 f0f8f97eea..f465c58250 100644 --- a/requirements/py310.yml +++ b/requirements/py310.yml @@ -26,6 +26,7 @@ dependencies: # Optional dependencies. - esmpy >=7.0 + - geovista - graphviz - iris-sample-data >=2.4.0 - mo_pack @@ -47,7 +48,7 @@ dependencies: - requests # Documentation dependencies. - - sphinx <=5.3 + - sphinx - sphinxcontrib-apidoc - sphinx-copybutton - sphinx-gallery >=0.11.0 diff --git a/requirements/py311.yml b/requirements/py311.yml index 8b4d5068d0..a55f1e18a3 100644 --- a/requirements/py311.yml +++ b/requirements/py311.yml @@ -26,6 +26,7 @@ dependencies: # Optional dependencies. - esmpy >=7.0 + - geovista - graphviz - iris-sample-data >=2.4.0 - mo_pack @@ -48,7 +49,7 @@ dependencies: # Documentation dependencies. - numpydoc - - sphinx <=5.3 + - sphinx - sphinxcontrib-apidoc - sphinx-copybutton - sphinx-gallery >=0.11.0 diff --git a/requirements/py39.yml b/requirements/py312.yml similarity index 94% rename from requirements/py39.yml rename to requirements/py312.yml index 884c568575..b5d2043d6c 100644 --- a/requirements/py39.yml +++ b/requirements/py312.yml @@ -4,7 +4,7 @@ channels: - conda-forge dependencies: - - python =3.9 + - python =3.12 # Setup dependencies. - setuptools >=64 @@ -26,6 +26,7 @@ dependencies: # Optional dependencies. - esmpy >=7.0 + - geovista - graphviz - iris-sample-data >=2.4.0 - mo_pack @@ -42,11 +43,12 @@ dependencies: - pre-commit - psutil - pytest + - pytest-cov - pytest-xdist - requests # Documentation dependencies. - - sphinx <=5.3 + - sphinx - sphinxcontrib-apidoc - sphinx-copybutton - sphinx-gallery >=0.11.0