Skip to content
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

Should standard attributes such as 'standard_name' always be present, even if their value is None? #478

Open
bnlawrence opened this issue Nov 1, 2022 · 9 comments
Labels
enhancement New feature or request

Comments

@bnlawrence
Copy link

If I have a field, f, which has no standard_name, then

f.standard_name

currently returns

AttributeError: 'Field' has no 'standard_name' property

Shouldn't the correct answer be None, and if not, why not?

@bnlawrence bnlawrence added the enhancement New feature or request label Nov 1, 2022
@davidhassell
Copy link
Collaborator

Hi Bryan, making it behave like a "normal" Python attribute provides much more flexibility, and is, I think, less surprising.

If it always returned None when there isn't a name, then if you did want it to fail when there is no standard name, then you'd have to do

    sn = f.standard_name  # assuming that it returns None if unset
    if sn is None:
        raise ValueError("create a nice message")

    print(sn)

If you want a default value, then why pin it down to None? With the current behaviour you can always specify you're own default with the getattr built-in :

    sn = getattr(f, "standard_name", None)
    sn = getattr(f, "standard_name", "time")

The standard_name attribute is in fact just a convenience way to use the get_property method, which also allows you to define a default that is user-defined value, or raise a user defined exception:

>>> f = cf.example_field(0)
>>> f.get_property("standard_name")
'specific_humidity'
>>> del f.standard_name  # or f.del_property(...)
>>> f.get_property("standard_name")
Traceback
    ...
ValueError: 'Field' has no 'standard_name' property
>>> f.get_property("standard_name", None)
None
>>> f.get_property("standard_name",  ValueError("My message"))
Traceback
    ...
ValueError: My message
>>> f.get_property("standard_name", NotImplementedError("why this type of error?"))
Traceback
    ...
NotImplementedError: why this type of error?

Hope that makes sense.

@bnlawrence
Copy link
Author

I was very careful to suggest that this should be the behaviour for the "standard" CF things (not everything, so this isn't a "normal" Python thing). So, if there is no standard_name, then the standard. name is None. This is not the same as looking for any old name (or indeed any other arbitrary property), which is a different issue.

I can't actually think of a use-case where this is not what you'd want to happen. What is the use-case where you'd want to have it unset, as opposed to None? It's just bizarre to force software to trap errors instead of handling what will be a very normal case using "the way we think" ...

@bnlawrence
Copy link
Author

(But this is not a hill for me to die on.)

@davidhassell
Copy link
Collaborator

Hi Bryan, perhaps it comes down to what you'd want hasattr(f, 'standard_name') to return ... Always True even when the standard name doesn't exist, or False when the standard name is not set? I certainly would prefer the latter :)

@bnlawrence
Copy link
Author

bnlawrence commented Nov 1, 2022

I think a field always has the notion of a standard name, it does not always have the notion of an attribute called Fred, so I expect the behaviour of hasattr to differ for standard_name and fred. It is entirely sensible for me to ask for standard name, and to be told it is None. I shouldn't expect to ask for Fred and be told None, I expect to be told "go away, we have no such attribute" ...

If we don't do this, then any code parsing fields for standard attributes has to to do getattr(x,y,None) for every standard x attribute instead of x.y ... it just increases the workload. It's not convenient, and doesn't reflect the way (some of us) think. I appreciate why you suggest what you have above, and I suspect we should do a poll of folks. My guess is that software engineers would (rightly) want the behaviour you espouse, and scientists (at least some) the behaviour I espouse. What we would do with that knowledge (were it to be true), would be about deciding on who cf-python is for ... :-). I guess we could tag this as "apifutures" and come back to it "one-day".

@davidhassell
Copy link
Collaborator

Hi Bryan,

A few unordered thoughts:

One thing to consider is f.standard_name == g.standard_name. If they're both None then this would be True, which it clearly isn't.

If we defaulted the attribute to None then any code more involved than, say [f.standard_name for f in fields], would need to test on the results being None.

Python users of any sort expect AttributeErrors from "missing" python object attributes.

Cheers,
David

@bnlawrence
Copy link
Author

The bottom line is: how do we expect to implement this:
simple

For me, an empty instance of A has an attribute of name:None, and values:[]. It would appear you think it should have no attributes? I expect to have some benefit from the data model having name even if the value is currently None.

@davidhassell
Copy link
Collaborator

Hi Bryan - the name is not part of the data model, put properties in general are, and a Field, and most other constructs, always has a "properties" dictionary, even if it is {}

@bnlawrence
Copy link
Author

bnlawrence commented Nov 1, 2022

Hi Bryan - the name is not part of the data model, put properties in general are, and a Field, and most other constructs, always has a "properties" dictionary, even if it is {}

But a "standard_name" is a CF property. I agree wrt arbitrary properties, but this isn't arbitrary! The distinction is even clearly made in the CF-python documentation, e.g. https://cfpython.bitbucket.io/docs/latest/classes/cf.Variable.html where I'd argue that the things that are cf-properties should have value None, if they are not set. The rest should not exist and return a ValueError if accessed with no value.

(I am hoping by updating this, rather than adding a new comment, this will hide here unseen til next week)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants