Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
2d54399
#32: Basic prototype callback addition
mo-tgeddes Oct 23, 2025
116ddb2
#32: update pytest tempdir config
mo-tgeddes Nov 12, 2025
ab3f3cc
#32: Working prototype
mo-tgeddes Nov 13, 2025
9af1590
#32: Working prototype with improved logic
mo-tgeddes Nov 13, 2025
dff558e
#32: Update argument handler to correctly pass in user callback
mo-tgeddes Nov 18, 2025
de3d650
#32: revert changes to the ancil loading
mo-tgeddes Nov 18, 2025
877a88e
#32: Add etsts for new loading functionality
mo-tgeddes Nov 18, 2025
fa39ac1
#32: Revert changes to ancil/__init__.py
mo-tgeddes Nov 18, 2025
4c354b7
#32: Revert pp tests
mo-tgeddes Nov 18, 2025
3dc860b
#32: Remove unused imports
mo-tgeddes Nov 18, 2025
e9a30f3
Merge branch 'main' of github.com:MetOffice/ANTS into 32_add_ancil_lo…
mo-tgeddes Dec 9, 2025
da8e951
#32: Commit to save work on adding new load functionality to command …
mo-tgeddes Dec 10, 2025
36148d5
Merge branch 'main' of github.com:MetOffice/ANTS into 32_add_ancil_lo…
mo-tgeddes Jan 5, 2026
79793ee
#32: Working rose stem with new load functionality
mo-tgeddes Jan 5, 2026
119dfcf
#32: Run black
mo-tgeddes Jan 5, 2026
04b3f9c
#32: Remove unneeded argument flag
mo-tgeddes Jan 5, 2026
abcdeae
#32: Fix to work with unittests
mo-tgeddes Jan 6, 2026
212dd0b
#32: Add working tests
mo-tgeddes Jan 8, 2026
ae8aab8
#32: Run stylechecks
mo-tgeddes Jan 13, 2026
2c00cd4
#32: remove print statements
mo-tgeddes Jan 29, 2026
1519caa
add more unit tests
mo-tgeddes Jan 29, 2026
0af2ece
remove unused import
mo-tgeddes Jan 29, 2026
8f49436
Update iris punctuation
mo-tgeddes Mar 31, 2026
95538de
Update docstring in _add_callback()
mo-tgeddes Apr 2, 2026
8b33349
Add speechmarks around license
mo-tgeddes Apr 2, 2026
077b0db
Update _CallbackMetadata docstring
mo-tgeddes Apr 2, 2026
4bbb166
Remove checks for misspelling
mo-tgeddes Apr 7, 2026
feac1b3
Merge callback_metadata_subbranch
mo-tgeddes Apr 8, 2026
1761aee
Changes implementing the loading of metadata
mo-tgeddes Apr 8, 2026
23f56ef
Run black
mo-tgeddes Apr 8, 2026
03bf800
fix flake8 line lengths
mo-tgeddes Apr 8, 2026
8dc2919
#2 Implementing the load
mo-tgeddes Apr 20, 2026
106714d
Add command line support
mo-tgeddes Apr 22, 2026
1835b26
Update extra argument to be correct
mo-tgeddes Apr 22, 2026
3d37136
Add full command parse integration and test
mo-tgeddes Apr 22, 2026
8b5447e
partial commit to save work on adding rose stem test
mo-tgeddes Jun 8, 2026
b808ac9
update rose stem
mo-tgeddes Jun 11, 2026
d9c6d05
Clean up rose stem to only have general regrid additions
mo-tgeddes Jun 11, 2026
d71456b
remove whitespcae
mo-tgeddes Jun 24, 2026
886ff24
Add loading metadata command line option
mo-tgeddes Jun 24, 2026
4ec679b
add functionality for checking for multiple attributes to be saved
mo-tgeddes Jun 24, 2026
f79cc0d
Fix spelling
mo-tgeddes Jun 24, 2026
9b71d8f
Fix variable spelling
mo-tgeddes Jun 24, 2026
7fcbbc3
Add handling for one single cube being passed in
mo-tgeddes Jun 24, 2026
f1e4f8c
Add checking for multiple metadata attributes
mo-tgeddes Jun 24, 2026
9e7e27a
add the ability to write metadata to sidecar files
mo-tgeddes Jun 29, 2026
a0e13e8
Update rose stem source for roseana
mo-tgeddes Jun 29, 2026
e1b0595
Apply suggestions from code review
mo-tgeddes Jun 29, 2026
5e70363
Change name of variable for turning off the save option
mo-tgeddes Jun 29, 2026
8480857
Clarify variable name
mo-tgeddes Jun 29, 2026
acbf778
Remove print statement
mo-tgeddes Jun 29, 2026
f1d7906
Update name and docstring of function
mo-tgeddes Jun 29, 2026
3ef2e61
change docstring syntax
mo-tgeddes Jun 29, 2026
7c5d69c
Update unittest to use mock
mo-tgeddes Jun 30, 2026
7453293
Update warning to log info
mo-tgeddes Jun 30, 2026
67301b0
Update code comment to be more clear
mo-tgeddes Jun 30, 2026
cc97f9f
Rewrite check_and_sort_metadata to use a dictionary
mo-tgeddes Jun 30, 2026
9abe77c
Change save behaviour to add newlines
mo-tgeddes Jun 30, 2026
df08391
Rename test__write_metadata.py to test__check_and_sort_metadata_attri…
mo-tgeddes Jun 30, 2026
ccce4db
Clean up unittests
mo-tgeddes Jun 30, 2026
84362b5
Add support for other attributes to be written out
mo-tgeddes Jul 1, 2026
cc84db7
Change test placeholder reference
mo-tgeddes Jul 1, 2026
ae88f57
Update comment
mo-tgeddes Jul 13, 2026
a159bc7
Remove print statement
mo-tgeddes Jul 13, 2026
7df8ca4
Update spelling
mo-tgeddes Jul 13, 2026
0e14c70
Merge pull request #5 from mo-tgeddes/add_writing_metadata
mo-tgeddes Jul 13, 2026
fe9c9bd
Merge branch 'load_save_feature_branch' into updated_load_save_featur…
mo-tgeddes Jul 13, 2026
cff3f66
Merge pull request #6 from mo-tgeddes/updated_load_save_feature_branch
mo-tgeddes Jul 14, 2026
d0478ec
remove merging artifacts
mo-tgeddes Jul 14, 2026
296fce1
Merge pull request #7 from mo-tgeddes/updated_load_save_feature_branch
mo-tgeddes Jul 14, 2026
f3b85fb
Add fix for netcdf saving error
mo-tgeddes Jul 15, 2026
e3aea7e
Update unittests with new load format
mo-tgeddes Jul 15, 2026
98813d8
Merge pull request #8 from mo-tgeddes/updated_load_save_feature_branch
mo-tgeddes Jul 15, 2026
fcf45a4
Cleanup and add fix for using constraints
mo-tgeddes Jul 20, 2026
d9294f8
Add tests for _add_callback()
mo-tgeddes Jul 22, 2026
a672626
Merge pull request #9 from mo-tgeddes/update_for_constraints
arjclark Aug 4, 2026
5676e05
Add copy metadata attributes
mo-tgeddes Aug 10, 2026
209b4c6
Add tests for copying metadata
mo-tgeddes Aug 10, 2026
c0e3128
Add check for licence spelling when saving
mo-tgeddes Aug 10, 2026
37ccb13
Add test for licence key change
mo-tgeddes Aug 10, 2026
5db76c4
Merge pull request #11 from mo-tgeddes/add_check_for_misspelt_license
mo-tgeddes Aug 10, 2026
1a95458
Update attribute name
mo-tgeddes Aug 17, 2026
7cff684
add test for changing metadata list
mo-tgeddes Aug 17, 2026
8910d4a
Add parameter to docstring
mo-tgeddes Aug 17, 2026
39e5229
Add logic comments
mo-tgeddes Aug 17, 2026
288ef80
Add logic comments
mo-tgeddes Aug 17, 2026
bedd16c
add whitespace stripping
mo-tgeddes Aug 17, 2026
d1163ea
Update lib/ants/utils/cube.py
mo-tgeddes Aug 20, 2026
30c68ae
Merge pull request #10 from mo-tgeddes/add_copy_metadata
arjclark Aug 20, 2026
fd98e00
Merge branch 'MetOffice:main' into load_save_feature_branch
mo-tgeddes Aug 27, 2026
8b299c8
#32: Add more accepted metadata attributes to load
mo-tgeddes Sep 7, 2026
f1f4f3e
#32: Add documentation on handling metadata
mo-tgeddes Sep 7, 2026
fd5cec4
#33: add metadata rose stem
mo-tgeddes Sep 7, 2026
64152eb
#32: Add documentation on turning off metadata load
mo-tgeddes Sep 7, 2026
1239cf3
#32: Add whitepsace
mo-tgeddes Sep 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions docs/source/tutorial_metadata.rst

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I really like this documentation, but I do wonder if it is really a tutorial as such, maybe it would make sense somewhere else? Perhaps under Ancillary Generation Pipeline? Alternatively, it could be made into a tutorial with some more examples

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
.. meta::
:description lang=en: Tutorial on managing metadata
:keywords: metadata, license, licensing, attribution, references, development, tutorial
:property=og:locale: en_GB

.. include:: common.txt


Managing Metadata
=================

Metadata in this tutorial refers to information about the data in a file, that does not
directly affect that data. For example, licensing information or attributions.

Some ancillary file formats cannot include metadata. Metadata can be very important to
keep alongside the data as often data will have rome form of requirement or restriction

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
keep alongside the data as often data will have rome form of requirement or restriction
keep alongside the data as often data will have some form of requirement or restriction

on it. Because of this, ANTS can handle in external metadata files, provided they match
the naming convention of `filename.attribute.accepted-metadata`. The current accepted

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

As discussed, can this be clarified a bit? It would be good to have a concrete example here, e.g. for file.pp, a license will be loaded from file.pp.license.

Suggested change
the naming convention of `filename.attribute.accepted-metadata`. The current accepted
the naming convention of `filename.extension.accepted-metadata`. The current accepted

metadata attributes are "license", "attribution", "restrictions", "institution",
"acknowledgement", and "references".

This functionality can be turned off through the use of the argument
``--ignore-metadata-files`` on the command line or when calling the ANTS load:

.. code-block:: python

cube = ants.io.load('data', ignore_metadata_files=True)


.. note::
Any attributes or files referencing licensing should use the 'license' spelling for
consistency.

Loading Metadata
----------------

ANTS can load in external metadata files or 'sidecar' files, if they are kept in the
same directory as the data files, and have the same name (including the extension).
Metadata can be loaded alongside all files, including NetCDF files, however ANTS will
not allow you to load a file with a metadata attribute and a sidecar file with the same
attribute. This is to prevent unintentional loss or overwriting of metadata information.

.. note::
When using wildcards for loading with sidecar files, add the file extension to the
end to prevent issues with ANTS attempting to load the sidecar files. E.g.
`data*.pp` rather than `data*`.


Saving Metadata
---------------

Metadata will only be saved to a sidecar file, if the ancil loader is used. This is

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just to check, should it be the ancil saver rather than loader that determines whether sidecar files are saved?

Suggested change
Metadata will only be saved to a sidecar file, if the ancil loader is used. This is
Metadata will only be saved to a sidecar file, if the ancil saver is used. This is

because NetCDF files will include the attributes within the file.

The sidecar files produced by ANTS follow the same naming covenstions at those loaded in

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
The sidecar files produced by ANTS follow the same naming covenstions at those loaded in
The sidecar files produced by ANTS follow the same naming coventions at those loaded in

`filename.attribute.accepted-metadata`. Only accepted metadata will be written out.
1 change: 1 addition & 0 deletions docs/source/tutorials.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ Tutorials
tutorial_KGO.rst
tutorial_sources.rst
tutorial_rose_stem.rst
tutorial_metadata.rst
15 changes: 10 additions & 5 deletions lib/ants/cli/ancil_2anc.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,16 @@
import iris


def load_data(source):
def load_data(source, ignore_metadata_files):
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore", "NetCDF default loading", iris._deprecation.IrisDeprecation
)
cubes = ants.io.load.load(source)
cubes = ants.io.load.load(source, ignore_metadata_files=ignore_metadata_files)
return cubes


def main(source_path, output_path, grid_staggering, netcdf_only):
def main(source_path, output_path, grid_staggering, netcdf_only, ignore_metadata_files):
"""
Convert specified source file to an ancillary.

Expand All @@ -66,13 +66,17 @@ def main(source_path, output_path, grid_staggering, netcdf_only):
written to an ancillary.

"""
source_cubes = load_data(source_path)
source_cubes = load_data(source_path, ignore_metadata_files)
if grid_staggering is not None:
for source_cube in source_cubes:
source_cube.attributes["grid_staggering"] = grid_staggering

if not netcdf_only:
save.ancil(source_cubes, output_path)
save.ancil(
source_cubes,
output_path,
ignore_writing_metadata_files=ignore_metadata_files,
)
save.netcdf(source_cubes, output_path)

return source_cubes
Expand All @@ -98,6 +102,7 @@ def cli_interface():
args.output,
args.grid_staggering,
args.netcdf_only,
args.ignore_metadata_files,
)


Expand Down
20 changes: 17 additions & 3 deletions lib/ants/cli/ancil_fill_n_merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def load_data(
land_fraction_threshold=None,
begin=None,
end=None,
ignore_metadata_files=None,
):
"""
Load the necessary data for performing a merge and fill operation.
Expand All @@ -45,6 +46,9 @@ def load_data(
Datetime to start the processing.
end: :obj:`datetime`, optional
Datetime to end the processing.
ignore_metadata_files : :obj:`bool`, optional
When set to True, files containing metadata will not be loaded alongside data
and added as attributes to the cube.


Returns
Expand All @@ -56,12 +60,16 @@ def load_data(
respectively.

"""
primary_cubes = ants.io.load.load(primary_source)
primary_cubes = ants.io.load.load(
primary_source, ignore_metadata_files=ignore_metadata_files
)
if begin is not None:
primary_cubes = create_time_constrained_cubes(primary_cubes, begin, end)
alternate_cubes = None
if alternate_source:
alternate_cubes = ants.io.load.load(alternate_source)
alternate_cubes = ants.io.load.load(
alternate_source, ignore_metadata_files=ignore_metadata_files
)
if begin is not None:
alternate_cubes = create_time_constrained_cubes(alternate_cubes, begin, end)

Expand Down Expand Up @@ -97,6 +105,7 @@ def main(
netcdf_only,
search_method,
blending_distance,
ignore_metadata_files,
):
"""
Perform merge and fill operation on the provided sources.
Expand Down Expand Up @@ -152,6 +161,9 @@ def main(
is applied. Note that this is in units of grid cells, not a physical distance.
If ``None``, no blending is applied, and there will be a hard edge between
the two sources.
ignore_metadata_files : :obj:`bool`, optional
When set to True, files containing metadata will not be loaded alongside data
and added as attributes to the cube.

Returns
-------
Expand All @@ -171,6 +183,7 @@ def main(
land_fraction_threshold,
begin,
end,
ignore_metadata_files,
)

result = primary_cubes
Expand All @@ -182,7 +195,7 @@ def main(
ants.analysis.make_consistent_with_lsm(result, lbm, invert_mask, search_method)

if not netcdf_only:
save.ancil(result, output)
save.ancil(result, output, ignore_writing_metadata_files=ignore_metadata_files)
save.netcdf(result, output)

return result
Expand Down Expand Up @@ -271,6 +284,7 @@ def cli_interface():
netcdf_only=args.netcdf_only,
search_method=args.search_method,
blending_distance=args.blending_distance,
ignore_metadata_files=args.ignore_metadata_files,
)


Expand Down
21 changes: 18 additions & 3 deletions lib/ants/cli/ancil_general_regrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,17 @@ def load_data(
land_fraction_threshold=None,
begin=None,
end=None,
ignore_metadata_files=None,
):
source_cubes = ants.io.load.load(source)
source_cubes = ants.io.load.load(
source, ignore_metadata_files=ignore_metadata_files
)
if begin is not None:
source_cubes = create_time_constrained_cubes(source_cubes, begin, end)
if target_grid:
target_cube = ants.io.load.load_grid(target_grid)
target_cube = ants.io.load.load_grid(
target_grid, ignore_metadata_files=ignore_metadata_files
)
else:
target_cube = ants.io.load.load_landsea_mask(
target_landseamask, land_fraction_threshold
Expand Down Expand Up @@ -76,6 +81,7 @@ def main(
save_ukca,
netcdf_only,
search_method,
ignore_metadata_files,
):
"""
General regrid application top level call function.
Expand Down Expand Up @@ -118,6 +124,9 @@ def main(
provided source(s) consistent with the provided land sea mask.
This should only be provided if a target land sea mask is also
provided via target_lsm_path.
ignore_metadata_files : :obj:`bool`, optional
When set to True, files containing metadata will not be loaded alongside data
and added as attributes to the cube.

Returns
-------
Expand All @@ -132,6 +141,7 @@ def main(
land_fraction_threshold,
begin,
end,
ignore_metadata_files,
)
if ants.utils.cube._is_ugrid(target_cube):
raise ValueError(
Expand All @@ -149,7 +159,11 @@ def main(
save.ukca_netcdf(regridded_cubes, output_path)
else:
if not netcdf_only:
save.ancil(regridded_cubes, output_path)
save.ancil(
regridded_cubes,
output_path,
ignore_writing_metadata_files=ignore_metadata_files,
)
save.netcdf(regridded_cubes, output_path)

return regridded_cubes
Expand Down Expand Up @@ -210,6 +224,7 @@ def cli_interface():
args.save_ukca,
args.netcdf_only,
args.search_method,
args.ignore_metadata_files,
)


Expand Down
12 changes: 12 additions & 0 deletions lib/ants/command_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ def __init__(self, target_lsm=False, target_grid=False, time_constraints=False):
sources <SOURCE1> <SOURCE2> ... <SOURCEN> Source data path(s).
--output <OUTPUT>, -o <OUTPUT> Output filepath
--ants-config <ANTS_CONFIG> Configuration path.
--ignore-metadata-files Stops the application from
searching for metadata files
with the same name as the
source and loading them
alongside the source.

Additionally, there are standardised optional arguments and these are
activated by passing the relevant keyword argument. See 'Parameters'
Expand Down Expand Up @@ -171,6 +176,13 @@ def __init__(self, target_lsm=False, target_grid=False, time_constraints=False):
help="Only write out a netCDF file.",
required=False,
)
self.add_argument(
"--ignore-metadata-files",
action="store_true",
help="Stops the application from searching for metadata files with "
"the same name as the source and loading them alongside the source.",
required=False,
)
if time_constraints:
self.add_argument(
"--begin",
Expand Down
Loading
Loading