Skip to content

Commit b1a8b35

Browse files
committed
dev
2 parents f0e74b3 + e3bc06c commit b1a8b35

File tree

10 files changed

+107
-36
lines changed

10 files changed

+107
-36
lines changed

Changelog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ version 3.17.0
77
(https://github.com/NCAS-CMS/cf-python/issues/843)
88
* Replace dataset aggregation functionality (CFA) with that imported
99
from `cfdm` (https://github.com/NCAS-CMS/cf-python/issues/841)
10+
* New keyword parameter to `cf.Field.compute_vertical_coordinates`:
11+
``key`` (https://github.com/NCAS-CMS/cf-python/issues/802)
1012
* Changed dependency: ``Python>=3.9.0``
1113
* Changed dependency: ``numpy>=2.0.0``
1214
* Changed dependency: ``cfdm>=1.12.0.0, <1.12.1.0``
@@ -17,6 +19,7 @@ version 3.17.0
1719

1820
----
1921

22+
2023
version 3.16.3
2124
--------------
2225

DOCUMENTATION.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
* The generation of recipes using Sphinx-Gallery requires:
1+
* The generation of recipes using Sphinx-Gallery requires `Python<3.12.0` and:
22

33
```txt
44
pip install sphinx-gallery==0.11.0
@@ -10,6 +10,7 @@
1010
pip install sphinxcontrib-devhelp==1.0.2
1111
pip install sphinxcontrib-serializinghtml==1.1.3
1212
pip install sphinxcontrib-qthelp==1.0.3
13+
pip install sphinxcontrib.applehelp==1.0.4
1314
pip install alabaster==0.7.13
1415
pip install sphinx==2.4.5
1516
```

cf/aggregate.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4732,7 +4732,7 @@ def _aggregate_2_fields(
47324732
anc0["hash_value"] = hash_value0 + hash_value1
47334733

47344734
# The result of aggregating a promoted amd non-promoted
4735-
# field ancillary is a non-promoted fierld ancillary
4735+
# field ancillary is a non-promoted field ancillary
47364736
if (
47374737
key0 in m0.promoted_field_ancillaries
47384738
and key1 not in m1.promoted_field_ancillaries
@@ -5011,7 +5011,7 @@ def _fix_promoted_field_ancillaries(output_meta, axes_aggregated):
50115011
50125012
output_meta: `list`
50135013
The list of `_Meta` objects. If any include promoted field
5014-
ancillaries then thses will be updated in-place.
5014+
ancillaries then these will be updated in-place.
50155015
50165016
:Returns:
50175017

cf/data/data.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2804,7 +2804,7 @@ def _concatenate_conform_units(cls, data1, units0, relaxed_units, copy):
28042804
"""Check and conform the units of data prior to concatenation.
28052805
28062806
This is a helper function for `concatenate` that may be easily
2807-
overridden in sublcasses, to allow for customisation of the
2807+
overridden in subclasses, to allow for customisation of the
28082808
concatenation process.
28092809
28102810
.. versionadded:: NEXTVERSION
@@ -2853,7 +2853,7 @@ def _concatenate_conform_units(cls, data1, units0, relaxed_units, copy):
28532853
else:
28542854
raise ValueError(
28552855
"Can't concatenate: All the input arrays must have "
2856-
"equivalent units. Got {units0!r} and {units1!r}"
2856+
f"equivalent units. Got {units0!r} and {units1!r}"
28572857
)
28582858

28592859
return data1
@@ -2865,7 +2865,7 @@ def _concatenate_post_process(
28652865
"""Post-process concatenated data.
28662866
28672867
This is a helper function for `concatenate` that may be easily
2868-
overridden in sublcasses, to allow for customisation of the
2868+
overridden in subclasses, to allow for customisation of the
28692869
concatenation process.
28702870
28712871
.. versionadded:: NEXTVERSION
@@ -2905,15 +2905,6 @@ def _concatenate_post_process(
29052905
)
29062906
concatenated_data.cyclic(axes=axis, iscyclic=False)
29072907

2908-
# # Set whether or not the concatenated name is deterministic
2909-
# deterministic = True
2910-
# for d in conformed_data:
2911-
# if not d.has_deterministic_name():
2912-
# deterministic = False
2913-
# break#
2914-
#
2915-
# concatenated_data._update_deterministic(deterministic)
2916-
29172908
return concatenated_data
29182909

29192910
@_inplace_enabled(default=False)

cf/field.py

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9141,7 +9141,12 @@ def domain_mask(self, **kwargs):
91419141
@_inplace_enabled(default=False)
91429142
@_manage_log_level_via_verbosity
91439143
def compute_vertical_coordinates(
9144-
self, default_to_zero=True, strict=True, inplace=False, verbose=None
9144+
self,
9145+
default_to_zero=True,
9146+
strict=True,
9147+
key=False,
9148+
inplace=False,
9149+
verbose=None,
91459150
):
91469151
"""Compute non-parametric vertical coordinates.
91479152

@@ -9176,7 +9181,7 @@ def compute_vertical_coordinates(
91769181
{{default_to_zero: `bool`, optional}}
91779182

91789183
strict: `bool`
9179-
If False then allow the computation to occur when
9184+
If False then allow the computation to occur when:
91809185

91819186
* A domain ancillary construct has no standard name, but
91829187
the corresponding term has a standard name that is
@@ -9195,15 +9200,30 @@ def compute_vertical_coordinates(
91959200
names, then an exception is raised regardless of the value
91969201
of *strict*.
91979202

9203+
key: `bool`
9204+
If True, return alongside the field construct the key
9205+
identifying the auxiliary coordinate of the field with
9206+
the newly-computed vertical coordinates, as a 2-tuple
9207+
of field and then key. If False, the default, then only
9208+
return the field construct.
9209+
9210+
If no coordinates were computed, `None` will be
9211+
returned in the key (second) position of the 2-tuple.
9212+
9213+
.. versionadded:: 3.17.0
9214+
91989215
{{inplace: `bool`, optional}}
91999216

92009217
{{verbose: `int` or `str` or `None`, optional}}
92019218

92029219
:Returns:
92039220

9204-
`Field` or `None`
9221+
`Field`, 2-tuple, or `None`
92059222
The field construct with the new non-parametric vertical
9206-
coordinates, or `None` if the operation was in-place.
9223+
coordinates, or a 2-tuple of this field construct along
9224+
with the key of the new auxiliary coordinate with the
9225+
computed vertical coordinates, or `None` if the operation
9226+
was in-place.
92079227

92089228
**Examples**
92099229

@@ -9230,7 +9250,7 @@ def compute_vertical_coordinates(
92309250
>>> print(f.auxiliary_coordinate('altitude', default=None))
92319251
None
92329252
>>> g = f.compute_vertical_coordinates()
9233-
>>> print(g.auxiliary_coordinates)
9253+
>>> print(g.auxiliary_coordinates())
92349254
Constructs:
92359255
{'auxiliarycoordinate0': <CF AuxiliaryCoordinate: latitude(10, 9) degrees_N>,
92369256
'auxiliarycoordinate1': <CF AuxiliaryCoordinate: longitude(9, 10) degrees_E>,
@@ -9246,12 +9266,35 @@ def compute_vertical_coordinates(
92469266
Bounds:units = 'm'
92479267
Bounds:Data(1, 10, 9, 2) = [[[[5.0, ..., 5415.0]]]] m
92489268

9269+
>>> g, key = f.compute_vertical_coordinates(key=True)
9270+
>>> g
9271+
<CF Field: air_temperature(atmosphere_hybrid_height_coordinate(1), grid_latitude(10), grid_longitude(9)) K>
9272+
>>> key
9273+
'auxiliarycoordinate3'
9274+
9275+
>>> i = f.compute_vertical_coordinates(inplace=True)
9276+
>>> print(i)
9277+
None
9278+
>>> print(f.auxiliary_coordinates())
9279+
Constructs:
9280+
{'auxiliarycoordinate0': <CF AuxiliaryCoordinate: latitude(10, 9) degrees_N>,
9281+
'auxiliarycoordinate1': <CF AuxiliaryCoordinate: longitude(9, 10) degrees_E>,
9282+
'auxiliarycoordinate2': <CF AuxiliaryCoordinate: long_name=Grid latitude name(10) >,
9283+
'auxiliarycoordinate3': <CF AuxiliaryCoordinate: altitude(1, 10, 9) m>}
9284+
92499285
"""
92509286
f = _inplace_enabled_define_and_cleanup(self)
92519287

9288+
if inplace and key:
9289+
raise ValueError(
9290+
"Can't set both key=True and inplace=True, since inplace "
9291+
"will always do the operation in-place and return None."
9292+
)
9293+
92529294
detail = is_log_level_detail(logger)
92539295
debug = is_log_level_debug(logger)
92549296

9297+
return_key = None # in case there are no vertical coords to compute
92559298
for cr in f.coordinate_references(todict=True).values():
92569299
# --------------------------------------------------------
92579300
# Compute the non-parametric vertical coordinates, if
@@ -9293,20 +9336,25 @@ def compute_vertical_coordinates(
92939336
f"{c.dump(display=False, _level=1)}"
92949337
) # pragma: no cover
92959338

9296-
key = f.set_construct(c, axes=computed_axes, copy=False)
9339+
return_key = f.set_construct(c, axes=computed_axes, copy=False)
92979340

92989341
# Reference the new coordinates from the coordinate
92999342
# reference construct
9300-
cr.set_coordinate(key)
9343+
cr.set_coordinate(return_key)
93019344

93029345
if debug:
93039346
logger.debug(
9304-
f"Non-parametric coordinates construct key: {key!r}\n"
9347+
"Non-parametric coordinates construct key: "
9348+
f"{return_key!r}\n"
93059349
"Updated coordinate reference construct:\n"
93069350
f"{cr.dump(display=False, _level=1)}"
93079351
) # pragma: no cover
93089352

9309-
return f
9353+
if key:
9354+
# 2-tuple, where return_key will be None if nothing was computed
9355+
return f, return_key
9356+
else:
9357+
return f
93109358

93119359
def match_by_construct(self, *identities, OR=False, **conditions):
93129360
"""Whether or not there are particular metadata constructs.

cf/functions.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2754,6 +2754,11 @@ def dirname(path, normalise=False, uri=None, isdir=False, sep=False):
27542754

27552755
dirname.__doc__ = cfdm.dirname.__doc__.replace("cfdm.", "cf.")
27562756

2757+
from functools import partial
2758+
2759+
dirname2 = partial(cfdm.dirname)
2760+
dirname2.__doc__ = cfdm.dirname.__doc__.replace("cfdm.", "cf.")
2761+
27572762

27582763
def pathjoin(path1, path2):
27592764
"""Join two file path components intelligently.

cf/read_write/read.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -848,8 +848,8 @@ def __new__(
848848
if nfields is not None and len(out) != nfields:
849849
raise ValueError(
850850
f"{nfields} field{cls._plural(nfields)} requested but "
851-
f"{len(out)} field/domain constucts found in "
852-
f"file{cls._plural(file_counter)}"
851+
f"{len(out)} field/domain constuct{cls._plural(len(out))}"
852+
f" found in file{cls._plural(file_counter)}"
853853
)
854854

855855
return out

cf/read_write/um/umread.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ def __init__(
567567
Unpacking is determined by netCDF conventions for the
568568
following variable attributes ``add_offset`` and
569569
``scale_factor``, as applied to lookup header entries
570-
BDATUM and BMKS repectively.
570+
BDATUM and BMKS respectively.
571571
572572
.. versionadded:: NEXTVERSION
573573
@@ -3499,7 +3499,7 @@ def read(
34993499
Unpacking is determined by netCDF conventions for the
35003500
following variable attributes ``add_offset`` and
35013501
``scale_factor``, as applied to lookup header entries
3502-
BDATUM and BMKS repectively.
3502+
BDATUM and BMKS respectively.
35033503
35043504
.. versionadded:: NEXTVERSION
35053505

cf/test/test_docstring.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,21 @@ def test_docstring(self):
8787
if name.startswith("__") and not inspect.isfunction(f):
8888
continue
8989

90-
if f.__doc__ is not None:
91-
self.assertNotIn(
92-
"{{",
93-
f.__doc__,
94-
f"\nCLASS: {klass}"
95-
f"\nMETHOD NAME: {name}"
96-
f"\nMETHOD: {f}",
97-
)
90+
self.assertIsNotNone(
91+
f.__doc__,
92+
f"\nCLASS: {klass}"
93+
f"\nMETHOD NAME: {name}"
94+
f"\nMETHOD: {f}"
95+
f"\n__doc__: {f.__doc__}",
96+
)
97+
98+
self.assertNotIn(
99+
"{{",
100+
f.__doc__,
101+
f"\nCLASS: {klass}"
102+
f"\nMETHOD NAME: {name}"
103+
f"\nMETHOD: {f}",
104+
)
98105

99106
def test_docstring_package(self):
100107
string = f">>> f = {self.package}."

cf/test/test_formula_terms.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,17 @@ def test_compute_vertical_coordinates(self):
757757
g = f.compute_vertical_coordinates(verbose=None)
758758
altitude = g.auxiliary_coordinate("altitude")
759759

760+
# Test the 'key' parameter
761+
k = f.compute_vertical_coordinates(key=True, verbose=None)
762+
self.assertEqual(len(k), 2) # expect a 2-tuple of field then key
763+
self.assertTrue(k[0].equals(g)) # field result, same as above
764+
self.assertEqual(k[1], "auxiliarycoordinate3") # i.e. key for altitude
765+
# key=True and inplace=True are incompatible inputs
766+
with self.assertRaises(ValueError):
767+
k = f.compute_vertical_coordinates(
768+
key=True, inplace=True, verbose=None
769+
)
770+
760771
self.assertTrue(altitude)
761772
self.assertTrue(altitude.has_bounds())
762773
self.assertEqual(altitude.shape, (1,) + orog.shape)
@@ -881,6 +892,11 @@ def test_compute_vertical_coordinates(self):
881892
f = cf.example_field(0)
882893
g = f.compute_vertical_coordinates()
883894
self.assertTrue(g.equals(f))
895+
# With key=True, expect the key (second in return 2-tuple) to be None
896+
k = f.compute_vertical_coordinates(key=True)
897+
self.assertEqual(len(k), 2)
898+
self.assertTrue(k[0].equals(f))
899+
self.assertEqual(k[1], None)
884900

885901
# ------------------------------------------------------------
886902
# Check other types

0 commit comments

Comments
 (0)