Skip to content

Generalise support for netcdf load+save of "special" attributes #6566

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

pp-mo
Copy link
Member

@pp-mo pp-mo commented Jul 16, 2025

Closes SciTools/iris-grib#596 and SciTools/iris-grib#674

Ties together the handling of STASH, GRIB_PARAM and "ukmo__process_flags" attributes,
which all require special handling on netcdf load+save.

By design, should preserve existing behaviour.
But I have tried to generalise the handling,
( and also rationalise behaviour a wee bit, at least for "ukmo__process_flags" -- though that one is quite obscure ).

TODO:

  • ?probably? ditch the @staticmethod + use self more
  • make sure all types also support the "plain" string formats (as found in the files) inside Iris, as well as the 'convenience' forms
    • e.g. in place of a STASH object, can have just the string like "m01s02i123" (str form) or "STASH(model=...)" (repr form) .
    • ... and similar for the other 2 types
  • testing (TBD) ...

(but first, just let's see if it breaks anything I haven't already tried)

Copy link

codecov bot commented Jul 16, 2025

Codecov Report

Attention: Patch coverage is 89.91597% with 12 lines in your changes missing coverage. Please review.

Project coverage is 89.93%. Comparing base (41876b4) to head (b086066).

Files with missing lines Patch % Lines
lib/iris/fileformats/netcdf/_attribute_handlers.py 84.41% 12 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6566      +/-   ##
==========================================
- Coverage   89.94%   89.93%   -0.02%     
==========================================
  Files          90       91       +1     
  Lines       24302    24385      +83     
  Branches     4546     4554       +8     
==========================================
+ Hits        21859    21930      +71     
- Misses       1674     1686      +12     
  Partials      769      769              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@pp-mo pp-mo added the benchmark_this Request that this pull request be benchmarked to check if it introduces performance shifts label Jul 16, 2025
Copy link
Contributor

⏱️ Performance Benchmark Report: 71c7bc4

Performance shifts

Full benchmark results

Benchmarks that have stayed the same:

| Change   | Before [13e3d9f3]    | After [71c7bc41]    |   Ratio | Benchmark (Parameter)                                                                       |
|----------|----------------------|---------------------|---------|---------------------------------------------------------------------------------------------|
|          | 20.8±0.2ms           | 21.0±0.3ms          |    1.01 | aggregate_collapse.Aggregation.time_aggregated_by_COUNT(False)                              |
|          | 52.7±0.5ms           | 52.4±0.9ms          |    0.99 | aggregate_collapse.Aggregation.time_aggregated_by_COUNT(True)                               |
|          | 35.3±0.6ms           | 35.0±0.5ms          |    0.99 | aggregate_collapse.Aggregation.time_aggregated_by_FAST_PERCENTILE(False)                    |
|          | 170±3ms              | 167±1ms             |    0.98 | aggregate_collapse.Aggregation.time_aggregated_by_FAST_PERCENTILE(True)                     |
|          | 22.8±0.3ms           | 22.9±0.3ms          |    1    | aggregate_collapse.Aggregation.time_aggregated_by_GMEAN(False)                              |
|          | 31.9±0.3ms           | 32.0±0.5ms          |    1.01 | aggregate_collapse.Aggregation.time_aggregated_by_GMEAN(True)                               |
|          | 23.2±0.3ms           | 23.0±0.4ms          |    0.99 | aggregate_collapse.Aggregation.time_aggregated_by_HMEAN(False)                              |
|          | 31.8±0.2ms           | 31.9±0.2ms          |    1    | aggregate_collapse.Aggregation.time_aggregated_by_HMEAN(True)                               |
|          | 20.8±0.3ms           | 20.7±0.4ms          |    0.99 | aggregate_collapse.Aggregation.time_aggregated_by_MAX(False)                                |
|          | 44.7±0.9ms           | 44.7±0.6ms          |    1    | aggregate_collapse.Aggregation.time_aggregated_by_MAX(True)                                 |
|          | 126±1ms              | 125±0.8ms           |    0.99 | aggregate_collapse.Aggregation.time_aggregated_by_MAX_RUN(False)                            |
|          | 127±2ms              | 127±2ms             |    1    | aggregate_collapse.Aggregation.time_aggregated_by_MAX_RUN(True)                             |
|          | 22.0±0.3ms           | 21.9±0.3ms          |    1    | aggregate_collapse.Aggregation.time_aggregated_by_MEAN(False)                               |
|          | 48.8±0.8ms           | 47.9±0.7ms          |    0.98 | aggregate_collapse.Aggregation.time_aggregated_by_MEAN(True)                                |
|          | 23.5±0.2ms           | 23.0±0.2ms          |    0.98 | aggregate_collapse.Aggregation.time_aggregated_by_MEDIAN(False)                             |
|          | 58.6±1ms             | 57.6±0.7ms          |    0.98 | aggregate_collapse.Aggregation.time_aggregated_by_MEDIAN(True)                              |
|          | 21.2±0.2ms           | 20.6±0.1ms          |    0.97 | aggregate_collapse.Aggregation.time_aggregated_by_MIN(False)                                |
|          | 44.7±0.8ms           | 44.9±0.5ms          |    1    | aggregate_collapse.Aggregation.time_aggregated_by_MIN(True)                                 |
|          | 1.07±0.01s           | 1.07±0.01s          |    1    | aggregate_collapse.Aggregation.time_aggregated_by_PEAK(False)                               |
|          | 1.06±0.01s           | 1.06±0.01s          |    1    | aggregate_collapse.Aggregation.time_aggregated_by_PEAK(True)                                |
|          | 209±2ms              | 206±3ms             |    0.99 | aggregate_collapse.Aggregation.time_aggregated_by_PERCENTILE(False)                         |
|          | 341±6ms              | 340±8ms             |    1    | aggregate_collapse.Aggregation.time_aggregated_by_PERCENTILE(True)                          |
|          | 22.2±0.1ms           | 21.8±0.3ms          |    0.98 | aggregate_collapse.Aggregation.time_aggregated_by_PROPORTION(False)                         |
|          | 30.4±0.4ms           | 30.2±0.4ms          |    0.99 | aggregate_collapse.Aggregation.time_aggregated_by_PROPORTION(True)                          |
|          | 22.6±0.1ms           | 22.2±0.2ms          |    0.98 | aggregate_collapse.Aggregation.time_aggregated_by_RMS(False)                                |
|          | 59.5±1ms             | 59.6±1ms            |    1    | aggregate_collapse.Aggregation.time_aggregated_by_RMS(True)                                 |
|          | 22.9±0.2ms           | 22.7±0.3ms          |    1    | aggregate_collapse.Aggregation.time_aggregated_by_STD_DEV(False)                            |
|          | 61.7±0.7ms           | 61.8±1ms            |    1    | aggregate_collapse.Aggregation.time_aggregated_by_STD_DEV(True)                             |
|          | 23.0±0.2ms           | 22.7±0.2ms          |    0.99 | aggregate_collapse.Aggregation.time_aggregated_by_VARIANCE(False)                           |
|          | 57.8±1ms             | 58.1±1ms            |    1.01 | aggregate_collapse.Aggregation.time_aggregated_by_VARIANCE(True)                            |
|          | 7.88±0.07ms          | 7.80±0.07ms         |    0.99 | aggregate_collapse.Aggregation.time_collapsed_by_COUNT(False)                               |
|          | 22.0±0.7ms           | 22.1±0.6ms          |    1    | aggregate_collapse.Aggregation.time_collapsed_by_COUNT(True)                                |
|          | 19.9±0.2ms           | 20.2±0.2ms          |    1.02 | aggregate_collapse.Aggregation.time_collapsed_by_FAST_PERCENTILE(False)                     |
|          | 124±2ms              | 126±1ms             |    1.01 | aggregate_collapse.Aggregation.time_collapsed_by_FAST_PERCENTILE(True)                      |
|          | 8.26±0.1ms           | 8.21±0.1ms          |    0.99 | aggregate_collapse.Aggregation.time_collapsed_by_GMEAN(False)                               |
|          | 20.4±0.7ms           | 19.9±0.6ms          |    0.98 | aggregate_collapse.Aggregation.time_collapsed_by_GMEAN(True)                                |
|          | 8.29±0.09ms          | 8.26±0.08ms         |    1    | aggregate_collapse.Aggregation.time_collapsed_by_HMEAN(False)                               |
|          | 20.7±0.6ms           | 20.7±0.6ms          |    1    | aggregate_collapse.Aggregation.time_collapsed_by_HMEAN(True)                                |
|          | 7.76±0.1ms           | 7.73±0.09ms         |    1    | aggregate_collapse.Aggregation.time_collapsed_by_MAX(False)                                 |
|          | 20.7±0.6ms           | 20.9±0.6ms          |    1.01 | aggregate_collapse.Aggregation.time_collapsed_by_MAX(True)                                  |
|          | 24.3±0.3ms           | 24.4±0.3ms          |    1    | aggregate_collapse.Aggregation.time_collapsed_by_MAX_RUN(False)                             |
|          | 34.6±0.5ms           | 34.8±0.6ms          |    1.01 | aggregate_collapse.Aggregation.time_collapsed_by_MAX_RUN(True)                              |
|          | 8.16±0.2ms           | 8.07±0.2ms          |    0.99 | aggregate_collapse.Aggregation.time_collapsed_by_MEAN(False)                                |
|          | 21.0±0.6ms           | 21.3±0.5ms          |    1.02 | aggregate_collapse.Aggregation.time_collapsed_by_MEAN(True)                                 |
|          | 9.22±0.07ms          | 9.06±0.1ms          |    0.98 | aggregate_collapse.Aggregation.time_collapsed_by_MEDIAN(False)                              |
|          | 23.1±0.5ms           | 23.5±0.7ms          |    1.02 | aggregate_collapse.Aggregation.time_collapsed_by_MEDIAN(True)                               |
|          | 7.70±0.06ms          | 7.74±0.08ms         |    1.01 | aggregate_collapse.Aggregation.time_collapsed_by_MIN(False)                                 |
|          | 20.4±0.6ms           | 20.9±0.4ms          |    1.02 | aggregate_collapse.Aggregation.time_collapsed_by_MIN(True)                                  |
|          | 532±2ms              | 531±4ms             |    1    | aggregate_collapse.Aggregation.time_collapsed_by_PEAK(False)                                |
|          | 545±5ms              | 543±3ms             |    1    | aggregate_collapse.Aggregation.time_collapsed_by_PEAK(True)                                 |
|          | 45.4±0.5ms           | 44.6±0.5ms          |    0.98 | aggregate_collapse.Aggregation.time_collapsed_by_PERCENTILE(False)                          |
|          | 133±0.9ms            | 133±0.6ms           |    1    | aggregate_collapse.Aggregation.time_collapsed_by_PERCENTILE(True)                           |
|          | 8.03±0.1ms           | 8.21±0.07ms         |    1.02 | aggregate_collapse.Aggregation.time_collapsed_by_PROPORTION(False)                          |
|          | 20.2±0.4ms           | 19.8±0.7ms          |    0.98 | aggregate_collapse.Aggregation.time_collapsed_by_PROPORTION(True)                           |
|          | 8.11±0.08ms          | 8.15±0.08ms         |    1.01 | aggregate_collapse.Aggregation.time_collapsed_by_RMS(False)                                 |
|          | 22.5±0.6ms           | 22.6±0.7ms          |    1    | aggregate_collapse.Aggregation.time_collapsed_by_RMS(True)                                  |
|          | 8.30±0.05ms          | 8.27±0.1ms          |    1    | aggregate_collapse.Aggregation.time_collapsed_by_STD_DEV(False)                             |
|          | 22.2±0.6ms           | 22.4±0.6ms          |    1.01 | aggregate_collapse.Aggregation.time_collapsed_by_STD_DEV(True)                              |
|          | 8.37±0.06ms          | 8.38±0.1ms          |    1    | aggregate_collapse.Aggregation.time_collapsed_by_VARIANCE(False)                            |
|          | 21.8±0.6ms           | 22.0±0.4ms          |    1.01 | aggregate_collapse.Aggregation.time_collapsed_by_VARIANCE(True)                             |
|          | 22.7±0.3ms           | 22.8±0.2ms          |    1    | aggregate_collapse.WeightedAggregation.time_w_aggregated_by_MEAN(False)                     |
|          | 82.2±1ms             | 82.3±0.8ms          |    1    | aggregate_collapse.WeightedAggregation.time_w_aggregated_by_MEAN(True)                      |
|          | 22.5±0.2ms           | 22.3±0.3ms          |    0.99 | aggregate_collapse.WeightedAggregation.time_w_aggregated_by_RMS(False)                      |
|          | 95.8±1ms             | 93.5±1ms            |    0.98 | aggregate_collapse.WeightedAggregation.time_w_aggregated_by_RMS(True)                       |
|          | 21.4±0.2ms           | 21.2±0.3ms          |    0.99 | aggregate_collapse.WeightedAggregation.time_w_aggregated_by_SUM(False)                      |
|          | 55.9±0.8ms           | 55.4±0.6ms          |    0.99 | aggregate_collapse.WeightedAggregation.time_w_aggregated_by_SUM(True)                       |
|          | 8.42±0.2ms           | 8.45±0.1ms          |    1    | aggregate_collapse.WeightedAggregation.time_w_collapsed_by_MEAN(False)                      |
|          | 27.4±0.6ms           | 27.1±0.8ms          |    0.99 | aggregate_collapse.WeightedAggregation.time_w_collapsed_by_MEAN(True)                       |
|          | 8.26±0.1ms           | 8.22±0.1ms          |    0.99 | aggregate_collapse.WeightedAggregation.time_w_collapsed_by_RMS(False)                       |
|          | 28.6±0.7ms           | 29.3±0.8ms          |    1.02 | aggregate_collapse.WeightedAggregation.time_w_collapsed_by_RMS(True)                        |
|          | 8.05±0.1ms           | 8.07±0.09ms         |    1    | aggregate_collapse.WeightedAggregation.time_w_collapsed_by_SUM(False)                       |
|          | 23.1±0.8ms           | 22.6±0.7ms          |    0.98 | aggregate_collapse.WeightedAggregation.time_w_collapsed_by_SUM(True)                        |
|          | 220±3ms              | 217±2ms             |    0.98 | aggregate_collapse.WeightedAggregation.time_w_collapsed_by_WPERCENTILE(False)               |
|          | 276±3ms              | 278±3ms             |    1.01 | aggregate_collapse.WeightedAggregation.time_w_collapsed_by_WPERCENTILE(True)                |
|          | 1.14±0.02ms          | 1.14±0.01ms         |    1    | cube.CubeCreation.time_create(False, 'construct')                                           |
|          | 398±9μs              | 394±3μs             |    0.99 | cube.CubeCreation.time_create(False, 'instantiate')                                         |
|          | 1.97±0.03ms          | 1.94±0.02ms         |    0.99 | cube.CubeCreation.time_create(True, 'construct')                                            |
|          | 1.36±0.01ms          | 1.37±0.01ms         |    1.01 | cube.CubeCreation.time_create(True, 'instantiate')                                          |
|          | 91.1±1ms             | 92.6±0.9ms          |    1.02 | cube.CubeEquality.time_equality(False, False, 'all_equal')                                  |
|          | 25.0±1ms             | 24.6±2ms            |    0.98 | cube.CubeEquality.time_equality(False, False, 'coord_inequality')                           |
|          | 106±2ms              | 105±1ms             |    0.99 | cube.CubeEquality.time_equality(False, False, 'data_inequality')                            |
|          | 17.5±0.2μs           | 17.3±0.2μs          |    0.99 | cube.CubeEquality.time_equality(False, False, 'metadata_inequality')                        |
|          | 97.1±0.8ms           | 95.0±0.9ms          |    0.98 | cube.CubeEquality.time_equality(False, True, 'all_equal')                                   |
|          | 27.8±0.5ms           | 27.5±0.3ms          |    0.99 | cube.CubeEquality.time_equality(False, True, 'coord_inequality')                            |
|          | 109±2ms              | 108±1ms             |    0.99 | cube.CubeEquality.time_equality(False, True, 'data_inequality')                             |
|          | 17.5±0.3μs           | 17.5±0.2μs          |    1    | cube.CubeEquality.time_equality(False, True, 'metadata_inequality')                         |
|          | 178±1ms              | 176±2ms             |    0.99 | cube.CubeEquality.time_equality(True, False, 'all_equal')                                   |
|          | 66.5±1ms             | 66.5±0.9ms          |    1    | cube.CubeEquality.time_equality(True, False, 'coord_inequality')                            |
|          | 206±1ms              | 207±2ms             |    1.01 | cube.CubeEquality.time_equality(True, False, 'data_inequality')                             |
|          | 52.1±0.2μs           | 52.1±0.5μs          |    1    | cube.CubeEquality.time_equality(True, False, 'metadata_inequality')                         |
|          | 254±5ms              | 253±3ms             |    0.99 | cube.CubeEquality.time_equality(True, True, 'all_equal')                                    |
|          | 142±3ms              | 140±2ms             |    0.98 | cube.CubeEquality.time_equality(True, True, 'coord_inequality')                             |
|          | 285±2ms              | 283±4ms             |    0.99 | cube.CubeEquality.time_equality(True, True, 'data_inequality')                              |
|          | 361±4μs              | 366±3μs             |    1.01 | cube.CubeEquality.time_equality(True, True, 'metadata_inequality')                          |
|          | 782±20μs             | 776±4μs             |    0.99 | import_iris.Iris.time__concatenate                                                          |
|          | 181±3μs              | 183±2μs             |    1.01 | import_iris.Iris.time__constraints                                                          |
|          | 114±4μs              | 115±1μs             |    1    | import_iris.Iris.time__data_manager                                                         |
|          | 91.0±0.8μs           | 92.1±0.4μs          |    1.01 | import_iris.Iris.time__deprecation                                                          |
|          | 165±2μs              | 161±2μs             |    0.98 | import_iris.Iris.time__lazy_data                                                            |
|          | 881±6μs              | 881±20μs            |    1    | import_iris.Iris.time__merge                                                                |
|          | 74.6±0.4μs           | 74.3±2μs            |    1    | import_iris.Iris.time__representation                                                       |
|          | 606±7μs              | 609±6μs             |    1    | import_iris.Iris.time_analysis                                                              |
|          | 139±0.7μs            | 140±2μs             |    1.01 | import_iris.Iris.time_analysis__area_weighted                                               |
|          | 107±2μs              | 106±1μs             |    0.99 | import_iris.Iris.time_analysis__grid_angles                                                 |
|          | 247±3μs              | 246±3μs             |    1    | import_iris.Iris.time_analysis__interpolation                                               |
|          | 190±5μs              | 190±1μs             |    1    | import_iris.Iris.time_analysis__regrid                                                      |
|          | 110±2μs              | 111±2μs             |    1.01 | import_iris.Iris.time_analysis__scipy_interpolate                                           |
|          | 136±2μs              | 134±2μs             |    0.99 | import_iris.Iris.time_analysis_calculus                                                     |
|          | 322±1μs              | 319±4μs             |    0.99 | import_iris.Iris.time_analysis_cartography                                                  |
|          | 89.9±1μs             | 92.1±0.7μs          |    1.02 | import_iris.Iris.time_analysis_geomerty                                                     |
|          | 209±2μs              | 210±1μs             |    1    | import_iris.Iris.time_analysis_maths                                                        |
|          | 92.6±0.9μs           | 94.2±2μs            |    1.02 | import_iris.Iris.time_analysis_stats                                                        |
|          | 172±2μs              | 171±0.9μs           |    1    | import_iris.Iris.time_analysis_trajectory                                                   |
|          | 313±3μs              | 314±2μs             |    1    | import_iris.Iris.time_aux_factory                                                           |
|          | 79.9±2μs             | 80.7±1μs            |    1.01 | import_iris.Iris.time_common                                                                |
|          | 165±2μs              | 161±2μs             |    0.98 | import_iris.Iris.time_common_lenient                                                        |
|          | 1.33±0.02ms          | 1.34±0.01ms         |    1.01 | import_iris.Iris.time_common_metadata                                                       |
|          | 168±2μs              | 168±1μs             |    1    | import_iris.Iris.time_common_mixin                                                          |
|          | 1.15±0ms             | 1.15±0.02ms         |    1.01 | import_iris.Iris.time_common_resolve                                                        |
|          | 196±2μs              | 197±0.8μs           |    1.01 | import_iris.Iris.time_config                                                                |
|          | 125±1μs              | 127±0.9μs           |    1.02 | import_iris.Iris.time_coord_categorisation                                                  |
|          | 373±2μs              | 374±7μs             |    1    | import_iris.Iris.time_coord_systems                                                         |
|          | 746±4μs              | 750±3μs             |    1.01 | import_iris.Iris.time_coords                                                                |
|          | 674±4μs              | 676±5μs             |    1    | import_iris.Iris.time_cube                                                                  |
|          | 235±1μs              | 237±2μs             |    1.01 | import_iris.Iris.time_exceptions                                                            |
|          | 74.9±0.8μs           | 74.7±1μs            |    1    | import_iris.Iris.time_experimental                                                          |
|          | 181±1μs              | 181±2μs             |    1    | import_iris.Iris.time_fileformats                                                           |
|          | 251±3μs              | 253±3μs             |    1.01 | import_iris.Iris.time_fileformats__ff                                                       |
|          | 2.56±0.03ms          | 2.58±0.04ms         |    1.01 | import_iris.Iris.time_fileformats__ff_cross_references                                      |
|          | 75.1±0.8μs           | 75.3±2μs            |    1    | import_iris.Iris.time_fileformats__pp_lbproc_pairs                                          |
|          | 112±1μs              | 112±1μs             |    1.01 | import_iris.Iris.time_fileformats_abf                                                       |
|          | 424±5μs              | 423±4μs             |    1    | import_iris.Iris.time_fileformats_cf                                                        |
|          | 4.68±0.03ms          | 4.71±0.04ms         |    1.01 | import_iris.Iris.time_fileformats_dot                                                       |
|          | 71.3±0.2μs           | 71.2±0.7μs          |    1    | import_iris.Iris.time_fileformats_name                                                      |
|          | 248±2μs              | 247±1μs             |    0.99 | import_iris.Iris.time_fileformats_name_loaders                                              |
|          | 114±1μs              | 114±0.8μs           |    1    | import_iris.Iris.time_fileformats_netcdf                                                    |
|          | 119±0.6μs            | 121±0.7μs           |    1.01 | import_iris.Iris.time_fileformats_nimrod                                                    |
|          | 209±1μs              | 209±2μs             |    1    | import_iris.Iris.time_fileformats_nimrod_load_rules                                         |
|          | 804±10μs             | 779±4μs             |    0.97 | import_iris.Iris.time_fileformats_pp                                                        |
|          | 174±2μs              | 177±3μs             |    1.01 | import_iris.Iris.time_fileformats_pp_load_rules                                             |
|          | 136±2μs              | 136±0.6μs           |    1    | import_iris.Iris.time_fileformats_pp_save_rules                                             |
|          | 534±5μs              | 540±8μs             |    1.01 | import_iris.Iris.time_fileformats_rules                                                     |
|          | 221±5μs              | 221±4μs             |    1    | import_iris.Iris.time_fileformats_structured_array_identification                           |
|          | 79.8±0.1μs           | 81.9±0.3μs          |    1.03 | import_iris.Iris.time_fileformats_um                                                        |
|          | 154±3μs              | 155±5μs             |    1    | import_iris.Iris.time_fileformats_um__fast_load                                             |
|          | 139±3μs              | 136±2μs             |    0.98 | import_iris.Iris.time_fileformats_um__fast_load_structured_fields                           |
|          | 71.7±0.7μs           | 73.5±1μs            |    1.03 | import_iris.Iris.time_fileformats_um__ff_replacement                                        |
|          | 77.5±0.3μs           | 78.2±2μs            |    1.01 | import_iris.Iris.time_fileformats_um__optimal_array_structuring                             |
|          | 941±9μs              | 940±5μs             |    1    | import_iris.Iris.time_fileformats_um_cf_map                                                 |
|          | 135±1μs              | 138±2μs             |    1.02 | import_iris.Iris.time_io                                                                    |
|          | 173±2μs              | 172±3μs             |    0.99 | import_iris.Iris.time_io_format_picker                                                      |
|          | 209±2μs              | 209±2μs             |    1    | import_iris.Iris.time_iris                                                                  |
|          | 125±0.7μs            | 126±0.4μs           |    1    | import_iris.Iris.time_iterate                                                               |
|          | 8.02±0.07ms          | 7.99±0.06ms         |    1    | import_iris.Iris.time_palette                                                               |
|          | 1.74±0.02ms          | 1.75±0.01ms         |    1.01 | import_iris.Iris.time_plot                                                                  |
|          | 217±1μs              | 216±1μs             |    1    | import_iris.Iris.time_quickplot                                                             |
|          | 2.09±0.05ms          | 2.13±0.03ms         |    1.02 | import_iris.Iris.time_std_names                                                             |
|          | 1.80±0.01ms          | 1.81±0.01ms         |    1    | import_iris.Iris.time_symbols                                                               |
|          | 261±9ms              | 262±9ms             |    1.01 | import_iris.Iris.time_tests                                                                 |
|          | 249±1μs              | 251±4μs             |    1.01 | import_iris.Iris.time_third_party_cartopy                                                   |
|          | 5.08±0.05ms          | 5.03±0.02ms         |    0.99 | import_iris.Iris.time_third_party_cf_units                                                  |
|          | 118±1μs              | 117±1μs             |    1    | import_iris.Iris.time_third_party_cftime                                                    |
|          | 2.71±0.01ms          | 2.71±0.01ms         |    1    | import_iris.Iris.time_third_party_matplotlib                                                |
|          | 1.30±0ms             | 1.30±0.01ms         |    1    | import_iris.Iris.time_third_party_numpy                                                     |
|          | 168±2μs              | 167±2μs             |    1    | import_iris.Iris.time_third_party_scipy                                                     |
|          | 98.8±0.7μs           | 98.6±0.5μs          |    1    | import_iris.Iris.time_time                                                                  |
|          | 345±8μs              | 347±2μs             |    1    | import_iris.Iris.time_util                                                                  |
|          | 71.9±1μs             | 71.4±0.9μs          |    0.99 | iterate.IZip.time_izip                                                                      |
|          | 9.92±0.03ms          | 10.0±0.06ms         |    1.01 | load.LoadAndRealise.time_load((1280, 960, 5), False, 'FF')                                  |
|          | 16.2±0.8ms           | 16.0±0.2ms          |    0.99 | load.LoadAndRealise.time_load((1280, 960, 5), False, 'NetCDF')                              |
|          | 9.94±0.06ms          | 9.94±0.04ms         |    1    | load.LoadAndRealise.time_load((1280, 960, 5), False, 'PP')                                  |
|          | 9.85±0.04ms          | 9.93±0.05ms         |    1.01 | load.LoadAndRealise.time_load((1280, 960, 5), True, 'FF')                                   |
|          | 13.4±0.2ms           | 13.3±0.1ms          |    0.99 | load.LoadAndRealise.time_load((1280, 960, 5), True, 'NetCDF')                               |
|          | 9.89±0.06ms          | 9.96±0.06ms         |    1.01 | load.LoadAndRealise.time_load((1280, 960, 5), True, 'PP')                                   |
|          | 1.49±0.01s           | 1.48±0.01s          |    0.99 | load.LoadAndRealise.time_load((2, 2, 1000), False, 'FF')                                    |
|          | 12.2±0.1ms           | 12.3±0.1ms          |    1.01 | load.LoadAndRealise.time_load((2, 2, 1000), False, 'NetCDF')                                |
|          | 1.52±0.01s           | 1.51±0.01s          |    0.99 | load.LoadAndRealise.time_load((2, 2, 1000), False, 'PP')                                    |
|          | 1.51±0.01s           | 1.49±0.01s          |    0.99 | load.LoadAndRealise.time_load((2, 2, 1000), True, 'FF')                                     |
|          | 12.2±0.08ms          | 12.1±0.1ms          |    1    | load.LoadAndRealise.time_load((2, 2, 1000), True, 'NetCDF')                                 |
|          | 1.51±0s              | 1.51±0.01s          |    1    | load.LoadAndRealise.time_load((2, 2, 1000), True, 'PP')                                     |
|          | 5.26±0.02ms          | 5.32±0.03ms         |    1.01 | load.LoadAndRealise.time_load((50, 50, 2), False, 'FF')                                     |
|          | 12.0±0.07ms          | 11.9±0.09ms         |    0.99 | load.LoadAndRealise.time_load((50, 50, 2), False, 'NetCDF')                                 |
|          | 5.25±0.02ms          | 5.33±0.04ms         |    1.01 | load.LoadAndRealise.time_load((50, 50, 2), False, 'PP')                                     |
|          | 5.32±0.04ms          | 5.27±0.02ms         |    0.99 | load.LoadAndRealise.time_load((50, 50, 2), True, 'FF')                                      |
|          | 12.0±0.1ms           | 12.0±0.08ms         |    1    | load.LoadAndRealise.time_load((50, 50, 2), True, 'NetCDF')                                  |
|          | 5.26±0.08ms          | 5.42±0.1ms          |    1.03 | load.LoadAndRealise.time_load((50, 50, 2), True, 'PP')                                      |
|          | 22.8±2ms             | 22.9±1ms            |    1.01 | load.LoadAndRealise.time_realise((1280, 960, 5), False, 'FF')                               |
|          | 23.6±0.5ms           | 23.9±0.5ms          |    1.01 | load.LoadAndRealise.time_realise((1280, 960, 5), False, 'NetCDF')                           |
|          | 12.1±1ms             | 11.3±1ms            |    0.93 | load.LoadAndRealise.time_realise((1280, 960, 5), False, 'PP')                               |
|          | 28.4±1ms             | 28.5±1ms            |    1    | load.LoadAndRealise.time_realise((1280, 960, 5), True, 'FF')                                |
|          | 83.1±0.8ms           | 83.0±0.5ms          |    1    | load.LoadAndRealise.time_realise((1280, 960, 5), True, 'NetCDF')                            |
|          | 28.0±1ms             | 27.8±1ms            |    0.99 | load.LoadAndRealise.time_realise((1280, 960, 5), True, 'PP')                                |
|          | 598±2ms              | 603±4ms             |    1.01 | load.LoadAndRealise.time_realise((2, 2, 1000), False, 'FF')                                 |
|          | 3.27±0.07ms          | 3.38±0.09ms         |    1.03 | load.LoadAndRealise.time_realise((2, 2, 1000), False, 'NetCDF')                             |
|          | 602±3ms              | 603±3ms             |    1    | load.LoadAndRealise.time_realise((2, 2, 1000), False, 'PP')                                 |
|          | 608±2ms              | 611±2ms             |    1    | load.LoadAndRealise.time_realise((2, 2, 1000), True, 'FF')                                  |
|          | 3.34±0.08ms          | 3.48±0.1ms          |    1.04 | load.LoadAndRealise.time_realise((2, 2, 1000), True, 'NetCDF')                              |
|          | 603±2ms              | 610±2ms             |    1.01 | load.LoadAndRealise.time_realise((2, 2, 1000), True, 'PP')                                  |
|          | 2.11±0.03ms          | 2.04±0.04ms         |    0.96 | load.LoadAndRealise.time_realise((50, 50, 2), False, 'FF')                                  |
|          | 3.37±0.1ms           | 3.40±0.09ms         |    1.01 | load.LoadAndRealise.time_realise((50, 50, 2), False, 'NetCDF')                              |
|          | 2.01±0.07ms          | 2.01±0.08ms         |    1    | load.LoadAndRealise.time_realise((50, 50, 2), False, 'PP')                                  |
|          | 2.08±0.07ms          | 2.02±0.03ms         |    0.97 | load.LoadAndRealise.time_realise((50, 50, 2), True, 'FF')                                   |
|          | 3.40±0.1ms           | 3.41±0.1ms          |    1    | load.LoadAndRealise.time_realise((50, 50, 2), True, 'NetCDF')                               |
|          | 2.00±0.06ms          | 2.03±0.07ms         |    1.01 | load.LoadAndRealise.time_realise((50, 50, 2), True, 'PP')                                   |
|          | 337±2ms              | 337±1ms             |    1    | load.ManyCubes.time_many_cube_load                                                          |
|          | 89.4±1ms             | 88.9±1ms            |    0.99 | load.ManyVars.time_many_var_load                                                            |
|          | 9.97±0.02ms          | 10.0±0.04ms         |    1    | load.STASHConstraint.time_stash_constraint((1280, 960, 5), 'FF')                            |
|          | 10.0±0.06ms          | 10.1±0.08ms         |    1.01 | load.STASHConstraint.time_stash_constraint((1280, 960, 5), 'PP')                            |
|          | 1.51±0.01s           | 1.51±0.01s          |    1    | load.STASHConstraint.time_stash_constraint((2, 2, 1000), 'FF')                              |
|          | 1.52±0.01s           | 1.52±0.01s          |    1    | load.STASHConstraint.time_stash_constraint((2, 2, 1000), 'PP')                              |
|          | 5.33±0.02ms          | 5.35±0.02ms         |    1    | load.STASHConstraint.time_stash_constraint((2, 2, 2), 'FF')                                 |
|          | 5.32±0.06ms          | 5.32±0.03ms         |    1    | load.STASHConstraint.time_stash_constraint((2, 2, 2), 'PP')                                 |
|          | 8.95±0.02ms          | 8.95±0.1ms          |    1    | load.StructuredFF.time_structured_load((1280, 960, 5), False)                               |
|          | 5.58±0.03ms          | 5.59±0.02ms         |    1    | load.StructuredFF.time_structured_load((1280, 960, 5), True)                                |
|          | 1.47±0.01s           | 1.48±0.01s          |    1.01 | load.StructuredFF.time_structured_load((2, 2, 1000), False)                                 |
|          | 415±3ms              | 415±3ms             |    1    | load.StructuredFF.time_structured_load((2, 2, 1000), True)                                  |
|          | 4.36±0.07ms          | 4.39±0.06ms         |    1.01 | load.StructuredFF.time_structured_load((2, 2, 2), False)                                    |
|          | 4.21±0.02ms          | 4.24±0.05ms         |    1.01 | load.StructuredFF.time_structured_load((2, 2, 2), True)                                     |
|          | 163±1ms              | 168±2ms             |    1.03 | load.TimeConstraint.time_time_constraint(20, 'FF')                                          |
|          | 15.1±0.2ms           | 15.4±0.2ms          |    1.02 | load.TimeConstraint.time_time_constraint(20, 'NetCDF')                                      |
|          | 165±0.5ms            | 165±1ms             |    1    | load.TimeConstraint.time_time_constraint(20, 'PP')                                          |
|          | 32.8±0.1ms           | 32.7±0.3ms          |    1    | load.TimeConstraint.time_time_constraint(3, 'FF')                                           |
|          | 14.8±0.1ms           | 15.1±0.1ms          |    1.02 | load.TimeConstraint.time_time_constraint(3, 'NetCDF')                                       |
|          | 32.8±0.2ms           | 32.7±0.6ms          |    1    | load.TimeConstraint.time_time_constraint(3, 'PP')                                           |
|          | 18.9±0.4ms           | 18.2±0.2ms          |    0.96 | load.ugrid.BasicLoading.time_load_file(1)                                                   |
|          | 48.5±0.5ms           | 48.2±0.7ms          |    0.99 | load.ugrid.BasicLoading.time_load_file(200000)                                              |
|          | 8.91±0.1ms           | 8.89±0.2ms          |    1    | load.ugrid.BasicLoading.time_load_mesh(1)                                                   |
|          | 16.8±0.4ms           | 16.5±0.4ms          |    0.98 | load.ugrid.BasicLoading.time_load_mesh(200000)                                              |
|          | 18.6±0.5ms           | 18.9±0.3ms          |    1.02 | load.ugrid.BasicLoadingTime.time_load_file(1)                                               |
|          | 19.2±0.6ms           | 19.0±0.4ms          |    0.99 | load.ugrid.BasicLoadingTime.time_load_file(200000)                                          |
|          | 8.74±0.1ms           | 8.83±0.3ms          |    1.01 | load.ugrid.BasicLoadingTime.time_load_mesh(1)                                               |
|          | 11.5±0.2ms           | 11.5±0.3ms          |    1    | load.ugrid.BasicLoadingTime.time_load_mesh(200000)                                          |
|          | 20.6±0.2ms           | 20.9±0.2ms          |    1.02 | load.ugrid.Callback.time_load_file_callback(1)                                              |
|          | 59.7±0.3ms           | 60.3±0.4ms          |    1.01 | load.ugrid.Callback.time_load_file_callback(200000)                                         |
|          | 20.3±0.5ms           | 20.7±0.3ms          |    1.02 | load.ugrid.CallbackTime.time_load_file_callback(1)                                          |
|          | 22.1±0.2ms           | 22.1±0.4ms          |    1    | load.ugrid.CallbackTime.time_load_file_callback(200000)                                     |
|          | 3.52±0.1ms           | 3.48±0.1ms          |    0.99 | load.ugrid.DataRealisation.time_realise_data(10000)                                         |
|          | 6.63±0.2ms           | 6.40±0.1ms          |    0.96 | load.ugrid.DataRealisation.time_realise_data(200000)                                        |
|          | 39.6±2ms             | 37.0±0.9ms          |    0.93 | load.ugrid.DataRealisationTime.time_realise_data(10000)                                     |
|          | 761±9ms              | 763±5ms             |    1    | load.ugrid.DataRealisationTime.time_realise_data(200000)                                    |
|          | 1.39±0.02s           | 1.37±0.03s          |    0.98 | merge_concat.Concatenate.time_concatenate(False)                                            |
|          | 427±10ms             | 422±7ms             |    0.99 | merge_concat.Concatenate.time_concatenate(True)                                             |
|          | 2.42±0G              | 2.42±0G             |    1    | merge_concat.Concatenate.tracemalloc_concatenate(False)                                     |
|          | 110±2M               | 110±5M              |    1    | merge_concat.Concatenate.tracemalloc_concatenate(True)                                      |
|          | 39.2±3ms             | 39.4±2ms            |    1    | merge_concat.Merge.time_merge                                                               |
|          | 126±0.03M            | 126±0.03M           |    1    | merge_concat.Merge.tracemalloc_merge                                                        |
|          | 366±4ns              | 369±1ns             |    1.01 | mesh.utils.regions_combine.CombineRegionsComputeRealData.time_compute_data(50)              |
|          | 194±1ms              | 195±1ms             |    1.01 | mesh.utils.regions_combine.CombineRegionsComputeRealData.time_compute_data(500)             |
|          | 771±0.5k             | 771±0.4k            |    1    | mesh.utils.regions_combine.CombineRegionsComputeRealData.tracemalloc_compute_data(50)       |
|          | 60.2±0M              | 60.2±0M             |    1    | mesh.utils.regions_combine.CombineRegionsComputeRealData.tracemalloc_compute_data(500)      |
|          | 18.4±0.2ms           | 18.9±0.2ms          |    1.03 | mesh.utils.regions_combine.CombineRegionsCreateCube.time_create_combined_cube(50)           |
|          | 21.8±0.5ms           | 21.7±0.3ms          |    1    | mesh.utils.regions_combine.CombineRegionsCreateCube.time_create_combined_cube(500)          |
|          | 1.27±0.04M           | 1.27±0.04M          |    1    | mesh.utils.regions_combine.CombineRegionsCreateCube.tracemalloc_create_combined_cube(50)    |
|          | 25±0.04M             | 25±0.04M            |    1    | mesh.utils.regions_combine.CombineRegionsCreateCube.tracemalloc_create_combined_cube(500)   |
|          | 119±0.7ms            | 118±1ms             |    1    | mesh.utils.regions_combine.CombineRegionsFileStreamedCalc.time_stream_file2file(50)         |
|          | 577±7ms              | 578±3ms             |    1    | mesh.utils.regions_combine.CombineRegionsFileStreamedCalc.time_stream_file2file(500)        |
|          | 1.46±0.03M           | 1.48±0.02M          |    1.01 | mesh.utils.regions_combine.CombineRegionsFileStreamedCalc.tracemalloc_stream_file2file(50)  |
|          | 96.5±0.02M           | 96.5±0.03M          |    1    | mesh.utils.regions_combine.CombineRegionsFileStreamedCalc.tracemalloc_stream_file2file(500) |
|          | 78.4±0.7ms           | 77.1±0.5ms          |    0.98 | mesh.utils.regions_combine.CombineRegionsSaveData.time_save(50)                             |
|          | 534±3ms              | 534±2ms             |    1    | mesh.utils.regions_combine.CombineRegionsSaveData.time_save(500)                            |
|          | 1.41±0.04M           | 1.41±0.02M          |    1    | mesh.utils.regions_combine.CombineRegionsSaveData.tracemalloc_save(50)                      |
|          | 96.4±0.03M           | 96.5±0.02M          |    1    | mesh.utils.regions_combine.CombineRegionsSaveData.tracemalloc_save(500)                     |
|          | 2.1752849999999997   | 2.1752849999999997  |    1    | mesh.utils.regions_combine.CombineRegionsSaveData.track_filesize_saved(50)                  |
|          | 216.01528499999998   | 216.01528499999998  |    1    | mesh.utils.regions_combine.CombineRegionsSaveData.track_filesize_saved(500)                 |
|          | 6.67±0.03ms          | 6.84±0.1ms          |    1.03 | plot.AuxSort.time_aux_sort                                                                  |
|          | 79.0±1ms             | 77.1±4ms            |    0.98 | regridding.CurvilinearRegridding.time_regrid_pic                                            |
|          | 136±3M               | 136±3M              |    1    | regridding.CurvilinearRegridding.tracemalloc_regrid_pic                                     |
|          | 105±6ms              | 104±6ms             |    0.99 | regridding.HorizontalChunkedRegridding.time_regrid_area_w                                   |
|          | 62.9±5ms             | 63.3±1ms            |    1.01 | regridding.HorizontalChunkedRegridding.time_regrid_area_w_new_grid                          |
|          | 107±0.08M            | 107±0.09M           |    1    | regridding.HorizontalChunkedRegridding.tracemalloc_regrid_area_w                            |
|          | 147±0.04M            | 147±0.04M           |    1    | regridding.HorizontalChunkedRegridding.tracemalloc_regrid_area_w_new_grid                   |
|          | 4.65±0.03ms          | 4.62±0.08ms         |    0.99 | save.NetcdfSave.time_netcdf_save_cube(50, False)                                            |
|          | 83.9±1ms             | 84.3±0.5ms          |    1    | save.NetcdfSave.time_netcdf_save_cube(50, True)                                             |
|          | 41.1±0.5ms           | 41.2±0.3ms          |    1    | save.NetcdfSave.time_netcdf_save_cube(600, False)                                           |
|          | 473±4ms              | 477±3ms             |    1.01 | save.NetcdfSave.time_netcdf_save_cube(600, True)                                            |
|          | 86.3±0.9ns           | 86.4±0.8ns          |    1    | save.NetcdfSave.time_netcdf_save_mesh(50, False)                                            |
|          | 64.0±1ms             | 63.9±0.9ms          |    1    | save.NetcdfSave.time_netcdf_save_mesh(50, True)                                             |
|          | 87.7±0.7ns           | 88.3±1ns            |    1.01 | save.NetcdfSave.time_netcdf_save_mesh(600, False)                                           |
|          | 414±3ms              | 415±3ms             |    1    | save.NetcdfSave.time_netcdf_save_mesh(600, True)                                            |
|          | 31.7±0.3k            | 31.8±0.4k           |    1    | save.NetcdfSave.tracemalloc_netcdf_save(50, False)                                          |
|          | 1.86±0.2M            | 1.9±0.2M            |    1.02 | save.NetcdfSave.tracemalloc_netcdf_save(50, True)                                           |
|          | 31.6±0.3k            | 31.8±0.3k           |    1.01 | save.NetcdfSave.tracemalloc_netcdf_save(600, False)                                         |
|          | 225±20M              | 208±20M             |    0.92 | save.NetcdfSave.tracemalloc_netcdf_save(600, True)                                          |
|          | 38.9±0.2ms           | 38.8±0.4ms          |    1    | stats.PearsonR.time_lazy                                                                    |
|          | 9.33±0.1ms           | 9.26±0.2ms          |    0.99 | stats.PearsonR.time_real                                                                    |
|          | 29.4±0.8M            | 29.4±1M             |    1    | stats.PearsonR.tracemalloc_lazy                                                             |
|          | 18.3±0.01M           | 18.3±0.01M          |    1    | stats.PearsonR.tracemalloc_real                                                             |
|          | 25.1±0.3ms           | 25.2±0.5ms          |    1    | trajectory.TrajectoryInterpolation.time_trajectory_linear                                   |
|          | 61.0±0.5ms           | 61.6±0.3ms          |    1.01 | trajectory.TrajectoryInterpolation.time_trajectory_nearest                                  |
|          | 17.6±0.02M           | 17.6±0.02M          |    1    | trajectory.TrajectoryInterpolation.tracemalloc_trajectory_linear                            |
|          | 7.75±0.02M           | 7.75±0.02M          |    1    | trajectory.TrajectoryInterpolation.tracemalloc_trajectory_nearest                           |

Generated by GHA run 16323043207

@pp-mo pp-mo force-pushed the nc_attribute_handlers branch from afa11e5 to 9d90853 Compare July 21, 2025 14:13
@pp-mo
Copy link
Member Author

pp-mo commented Jul 22, 2025

Review Notes : changes to consider

The code changes here provoked review of some older behaviour decisions.
As a result there are some small corners where I decided it was worth it to change behaviour slightly.

Here's a summary, which may not be entirely complete:

overall

  • suitable string values are now supported as well as objects, for GRIB_PARAM and STASH (stash already was)
  • GRIB_PARAM now reads+writes to netcdf (this was the main goal)
  • invalid (i.e. untranslatable) attributes in iris now all give warnings on write -- but a value is always written
  • invalid (i.e. untranslatable) attributes in file now all give warnings on read -- but a value is always read

STASH

  • an MSI string is also accepted (as before)
  • a warning is now issued if the STASH string is invalid on write (but it doesn't stop you).
    • a failed translation on write creates a file "STASH" attribute == does not translate to "um_stash_source"
    • [[a failed translation on read creates an iris "um_stash_source" attribute -- N.B. THIS IS NOT A CHANGE, but it might be a problem?]]

ukmo__process_flags

  • only a tuple of strings is now accepted, anything else gives an error on write
    • Previously, a string would be accepted, and broken into characters on save, and reconstructed as a tuple of single-char strings.
      • E.G. "abc" (iris) --> "a b c" (file) --> ("a", "b", "c") (iris again)
  • an empty string (file attribute) now produces an empty tuple (iris attribute) and vice versa
    • I.E. "" <--> () : Previously "" <-> ("",)
  • a string section of "<EMPTY>" (in file) now translates to/from an empty string (in iris).
    • E.G. "a <EMPTY> b" <-> ("a", "", "b")
    • [[this is really just for completeness, and could be removed]]

GRIB_PARAM

  • now saves the repr form of the GRIBCode to netcdf, and retrieves
  • string also works
    • (the translation is very free, just expects 4 decimals)

@pp-mo
Copy link
Member Author

pp-mo commented Jul 22, 2025

Uncertainty remaining

  • include iris_grib in testing : this now seems hard to avoid
  • not now sure that STASH behaviours on failure (new or old) quite make sense
    • because in these cases we can write a STASH and/or read a um_stash_source,
      when read- or written-back there is possibility of conflct (not allowed for in present code)

@pp-mo pp-mo force-pushed the nc_attribute_handlers branch from 78d96e8 to 7226b36 Compare July 22, 2025 00:22
@pp-mo pp-mo marked this pull request as ready for review July 22, 2025 10:32
@bjlittle bjlittle self-requested a review July 22, 2025 10:57
@bjlittle bjlittle self-assigned this Jul 22, 2025
@bjlittle bjlittle moved this to 🚀 In Progress in 🦋 Iris 3.13.0 Jul 22, 2025
@pp-mo
Copy link
Member Author

pp-mo commented Jul 22, 2025

Update:

include iris_grib in testing : this now seems hard to avoid

I'm now thinking that, without any further changes here, I can just import the tests which are here skipped due to iris-grib not being installed, and run them in the iris-grib repo instead.
See : SciTools/iris-grib#677

Does that sound like a good plan ?

Copy link
Member

@bjlittle bjlittle left a comment

Choose a reason for hiding this comment

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

@pp-mo Looks good.

You've had to grapple with some serious sketchy historical code that's evolved over time. Unifying it should make it more understandable and maintainable.

I can't see any obvious behaviour changes that will upset users, so I'm happy to roll with what you've suggested and we can see whether there are any user edge cases that may require a patch or rebuffing.

Thanks for adding the additional test coverage 🤩💯

Only a few minors to service 👍

"""

from abc import ABCMeta, abstractmethod
from typing import Any, Dict, List, Tuple
Copy link
Member

Choose a reason for hiding this comment

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

@pp-mo As from >=py39 (PEP585) you now no longer need to import Dict, List or Tuple. It's safe to use the built-in equivalents i.e., dict, list and tuple 👍

NetcdfIdentifyingNames: List[str] = []

@abstractmethod
def encode_object(self, content) -> Tuple[str, str]:
Copy link
Member

Choose a reason for hiding this comment

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

@pp-mo Do you we have a type annotation for content?

There are other various missing annotations below ...

Not too sure how strict you want to be on type annotations just yet in iris ... the coverage and adoption is patchy at best.

I'd err on the side of either typing everything new or not at all. Your call.

pass

@abstractmethod
def decode_attribute(self, attr_name: str, attr_value) -> Any:
Copy link
Member

Choose a reason for hiding this comment

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

@pp-mo attr_name is never used in any the subclass methods, so why is it part of the abstract method?

Is there something I've misunderstood?

)
warnings.warn(msg, category=_WarnComboLoadIgnoring)

if len(matches) > 0:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if len(matches) > 0:
if len(matches) == 1:

var = engine.cf_var
for handler in ATTRIBUTE_HANDLERS.values():
# Each handler can have several match names, but ideally only 0 or 1 appears !
iris_name = handler.IrisIdentifyingName
Copy link
Member

Choose a reason for hiding this comment

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

@pp-mo Super minor, but you could offer a read-only property, for example, on the handler that allows the user of the instance to get the iris or netcdf name without having to know the name of the class property that they're stored in e.g., handler.iris_name and handler.netcdf_name

Happy for you not to do this, just an observation/suggestion.

@github-project-automation github-project-automation bot moved this from 🚀 In Progress to 👀 In Review in 🦋 Iris 3.13.0 Jul 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
benchmark_this Request that this pull request be benchmarked to check if it introduces performance shifts
Projects
Status: No status
Status: 👀 In Review
Development

Successfully merging this pull request may close these issues.

"GRIB_PARAM" attributes are not saving to netcdf
2 participants