-
Notifications
You must be signed in to change notification settings - Fork 300
Splitattrs ncsave redo commonmeta #5538
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
Merged
trexfeathers
merged 11 commits into
SciTools:FEATURE_split_attrs
from
pp-mo:splitattrs_ncsave_redo_commonmeta
Nov 15, 2023
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
d168a89
Define common-metadata operartions on split attribute dictionaries.
pp-mo c6c3d71
Tests for split-attributes handling in CubeMetadata operations.
pp-mo 0d9a4e4
Small tidy and clarify.
pp-mo 9d17da4
Common metadata ops support mixed split/unsplit attribute dicts.
pp-mo 28ebcbb
Clarify with better naming, comments, docstrings.
pp-mo 8d61d9b
Remove split-attrs handling to own sourcefile, and implement as a dec…
pp-mo fb52624
Remove redundant tests duplicated by matrix testcases.
pp-mo 2cd51cd
Newstyle split-attrs matrix testing, with fewer testcases.
pp-mo 07ed579
Small improvements to comments + docstrings.
pp-mo dca5dce
Fix logic for equals expectation; expand primary/secondary independen…
pp-mo b00b37f
Clarify result testing in metadata operations decorator.
pp-mo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| # Copyright Iris contributors | ||
| # | ||
| # This file is part of Iris and is released under the LGPL license. | ||
| # See COPYING and COPYING.LESSER in the root of the repository for full | ||
| # licensing details. | ||
| """ | ||
| Dictionary operations for dealing with the CubeAttrsDict "split"-style attribute | ||
| dictionaries. | ||
|
|
||
| The idea here is to convert a split-dictionary into a "plain" one for calculations, | ||
| whose keys are all pairs of the form ('global', <keyname>) or ('local', <keyname>). | ||
| And to convert back again after the operation, if the result is a dictionary. | ||
|
|
||
| For "strict" operations this clearly does all that is needed. For lenient ones, | ||
| we _might_ want for local+global attributes of the same name to interact. | ||
| However, on careful consideration, it seems that this is not actually desirable for | ||
| any of the common-metadata operations. | ||
| 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 | ||
|
|
||
|
|
||
| def _convert_splitattrs_to_pairedkeys_dict(dic): | ||
| """ | ||
| Convert a split-attributes dictionary to a "normal" dict. | ||
|
|
||
| Transform a :class:`~iris.cube.CubeAttributesDict` "split" attributes dictionary | ||
| into a 'normal' :class:`dict`, with paired keys of the form ('global', name) or | ||
| ('local', name). | ||
| """ | ||
|
|
||
| def _global_then_local_items(dic): | ||
| # Routine to produce global, then local 'items' in order, and with all keys | ||
| # "labelled" as local or global type, to ensure they are all unique. | ||
| for key, value in dic.globals.items(): | ||
| yield ("global", key), value | ||
| for key, value in dic.locals.items(): | ||
| yield ("local", key), value | ||
|
|
||
| return dict(_global_then_local_items(dic)) | ||
|
|
||
|
|
||
| def _convert_pairedkeys_dict_to_splitattrs(dic): | ||
| """ | ||
| Convert an input with global/local paired keys back into a split-attrs dict. | ||
|
|
||
| For now, this is always and only a :class:`iris.cube.CubeAttrsDict`. | ||
| """ | ||
| from iris.cube import CubeAttrsDict | ||
|
|
||
| result = CubeAttrsDict() | ||
| for key, value in dic.items(): | ||
| keytype, keyname = key | ||
| if keytype == "global": | ||
| result.globals[keyname] = value | ||
| else: | ||
| assert keytype == "local" | ||
| result.locals[keyname] = value | ||
| return result | ||
|
|
||
|
|
||
| def adjust_for_split_attribute_dictionaries(operation): | ||
| """ | ||
| Decorator to make a function of attribute-dictionaries work with split attributes. | ||
|
|
||
| The wrapped function of attribute-dictionaries is currently always one of "equals", | ||
| "combine" or "difference", with signatures like : | ||
| equals(left: dict, right: dict) -> bool | ||
| combine(left: dict, right: dict) -> dict | ||
| difference(left: dict, right: dict) -> None | (dict, dict) | ||
|
|
||
| The results of the wrapped operation are either : | ||
| * for "equals" (or "__eq__") : a boolean | ||
| * for "combine" : a (converted) attributes-dictionary | ||
| * for "difference" : a list of (None or "pair"), where a pair contains two | ||
| dictionaries | ||
|
|
||
| Before calling the wrapped operation, its inputs (left, right) are modified by | ||
| converting any "split" dictionaries to a form where the keys are pairs | ||
| of the form ("global", name) or ("local", name). | ||
|
|
||
| After calling the wrapped operation, for "combine" or "difference", the result can | ||
| contain a dictionary or dictionaries. These are then transformed back from the | ||
| 'converted' form to split-attribute dictionaries, before returning. | ||
|
|
||
| "Split" dictionaries are all of class :class:`~iris.cube.CubeAttrsDict`, since | ||
| the only usage of 'split' attribute dictionaries is in Cubes (i.e. they are not | ||
| used for cube components). | ||
| """ | ||
|
|
||
| @wraps(operation) | ||
| def _inner_function(*args, **kwargs): | ||
| from iris.cube import CubeAttrsDict | ||
|
|
||
| # First make all inputs into CubeAttrsDict, if not already. | ||
| args = [ | ||
| arg if isinstance(arg, CubeAttrsDict) else CubeAttrsDict(arg) | ||
| for arg in args | ||
| ] | ||
| # Convert all inputs into 'pairedkeys' type dicts | ||
| args = [_convert_splitattrs_to_pairedkeys_dict(arg) for arg in args] | ||
|
|
||
| result = operation(*args, **kwargs) | ||
|
|
||
| # Convert known specific cases of 'pairedkeys' dicts in the result, and convert | ||
| # those back into split-attribute dictionaries. | ||
| if isinstance(result, Mapping): | ||
| # Fix a result which is a single dictionary -- for "combine" | ||
| result = _convert_pairedkeys_dict_to_splitattrs(result) | ||
| elif isinstance(result, Sequence) and len(result) == 2: | ||
| # Fix a result which is a pair of dictionaries -- for "difference" | ||
| left, right = result | ||
| left, right = ( | ||
| _convert_pairedkeys_dict_to_splitattrs(left), | ||
| _convert_pairedkeys_dict_to_splitattrs(right), | ||
| ) | ||
| result = result.__class__([left, right]) | ||
| # ELSE: leave other types of result unchanged. E.G. None, bool | ||
|
|
||
| return result | ||
|
|
||
| return _inner_function | ||
trexfeathers marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.