NCAS-CMS / cf-python

A CF-compliant Earth Science data analysis library
http://ncas-cms.github.io/cf-python
MIT License
125 stars 19 forks source link

f.construct and f.dimension_coordinate raise ValueErrors instead of None when the requested axis doesn't exist. #815

Closed bnlawrence closed 1 month ago

bnlawrence commented 1 month ago

(This problem exists for any of X,Y,Z,T, but this one example suffices)

Consider the following field:

 f=<CF Field: northward_transformed_eulerian_mean_air_velocity(time(780), air_pressure(36), latitude(325)) m s-1>

If you try and do either an x=f.construct('X') or an x=f.dimension_coordinate('X') cf-python raises a ValueError

I think it would be far more natural to return None, not raise an error - especially for the second formalism.

(This is cf.version = 3.17.0, but I think this is probably independent of version)

Strictly of course this isn't a bug, but it feels like one :-)

davidhassell commented 1 month ago

Hi Bryan,

If you want None returned: f.construct('X', default=None). Definitely not a bug, but a choice - the default default has to be something :)

You can also do things like f.construct('X', default=MyException("what, no X?")) to raise a different sort of trapable error.

bnlawrence commented 1 month ago

Fair enough. Me, I would have thought the default for the absence of something that says get_something should be None if there is no something.

bnlawrence commented 1 month ago

I can live with this.

davidhassell commented 1 month ago

Just explaining my thumbs down :)

It depends on whether you interpret None as nothing. For instance, in standard Python if you as for a non-existent attribute (f.bad) you get an exception, unless you ask for a different default (getattr(f, 'bad', None)).

If None were returned as the default default in the case above then you'd either have to test the result every time to see if was None, or else run the risk of some sort of other other error occurring downstream that could be hard to connect back to the cause:

>>> c = f.dimension_coordinate('x')
>>> # loads of code
>>> d = c[...]
IndexError: can't index None