-
Notifications
You must be signed in to change notification settings - Fork 85
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
Expose xgetattr and xsetattr in traits API #1239
Comments
This is similar to #1236. And as with #1236, this isn't particularly Traits-related code, and in my opinion, Traits really isn't the place for this sort of general-purpose code. If we expose this in one of the I'm strongly opposed to Traits becoming a dumping ground for general utilities purely because it sits at the bottom of the ETS stack. In this case, I think both of (a) having a copy in Pyface which can be adapted to Pyface's own needs, or (b) importing from a non-api module in Traits and accepting the risk that Traits might stop supporting this one day (and that then it'll need to be fixed in Pyface) are better options. |
The use-case in enthought/pyface#543 is satisfied by a four-line function: def xgetattr(object, xname):
for name in xname.split("."):
object = getattr(object, name, None)
return object That seems simple enough that duplicating in Pyface isn't much of a cost. And I'm not sure it even really counts as duplication: it's not clear that the actual need of Traits matches that of Pyface now, or that those needs will continue to match in the future. |
Thank you. Closing. |
I disagree about this: it is very annoying to have multiple definitions of the same function scattered around the codebases. Duplicating in Pyface would also imply duplicating in TraitsUI and possibly other places as well. Maybe traits isn't the place for this sort of core utility routines, but we need somewhere for them. |
Maybe, maybe not. So far, the things that have come up have been tiny enough that the duplication isn't a real cost; moreover, there's a potential cost to removing the duplication - if the utilities turn out to have slightly different needs, or need to change for different reasons or at different times, then the duplication is better than removal of a fake duplication. DRY is one of the more evil / misapplied rules in software design. And if we do decide that we need a common place for those utilities, it's still a big leap from there to "they should go in Traits". Traits is absolutely not the place for utilities that have nothing to do with Traits. We have too many examples of that sort of thing already in Traits, and those examples have already had a cost in maintenance. (For example, the |
Part of the problem is that as soon as you put something in one of the A halfway option is to treat Pyface and TraitsUI as "friend" packages, that are permitted to import from places in Traits other than the In contrast, if we put something in one of the |
It's also worth noting that:
So we don't actually need any duplication at all! The functions can be simply removed from Traits, implemented in Pyface, and imported from Pyface by TraitsUI. |
I guess I don't particularly care about whether these functions are exposed in the But I also think that there may be should be a place for some of these sorts of things where they can happily live in a Once upon a time, these were in their own library, but when we got rid of the top-level |
No, traits uses |
True. (Four places, to be precise.) I had the 5.2.0 tag checked out, for some reason. So independently of this issue, |
We're talking about something that's essentially three simple lines: value = object
for piece in name.split("."):
value = getattr(value, piece) At least, the above is the form that's used in Traits. The Pyface usage is different (which is a sign that we probably actually want two different functions): value = object
for piece in name.split("."):
value = getattr(value, piece, None) This isn't code that's easy to get wrong, or encodes some special domain-specific logic, or has ad-hoc decisions or constants that might be changed. It's barely at the level that it's worth abstracting it out into a function in a module, let alone putting it into another package so that it can be imported from that package. This is DRY at its worst: it makes little sense to incur the overhead of implementing, documenting, testing, maintaining and exporting something this simple (as well as importing it where it's needed) versus just writing those three lines of code inline, or in a local function. |
(Just in case the initial text failed to come across as being impartial.) For the record, despite being the person opening the issue in the first place, I am not in favour of exposing |
There's one other point here: there's no good reason to expect people on other projects to look in Traits in particular for this sort of thing, given that it's not Traits-related. It's not the natural place to look for random utilities. Users should think of the Traits library as providing Traits and related things; not as providing Traits and various random utilities. |
Slightly sideways suggestion about naming conventions for ETS projects coming from this discussion:
|
Mostly agreed, but I think we should define "friendly projects". If taken too broadly, it could mean any projects within the enthought organization, and I don't think that was the intention. I think these "friendly projects" should only include projects with a CI job that is tested with |
For my comment:
I am afraid I have to take back the "mostly agreed" part.
Suppose we took on this "protected" notion, the implication for, e.g. Traits, is that if its "protected" function is used by another ETS package, e.g. TraitsUI, then traits will have to keep backward compatibility of this protected function. The fact that ETS distributions are released at different time means these protected functions are just as rigid to change as if they were public to everybody. In order to be able to change these "protected" functions, all ETS distributions will have to be released at the same time, which defeat the purpose of having separate distribution in the first place. |
There are really two separate discussions going on in this issue; one about For For the wider discussion, maybe we should open a new issue? |
Yes please.
Agreed. The |
Yep, that seems like a good place for this discussion. |
If not Traits, then we need a place for these utilities, and soon. What I very strongly do not want is subtly different implementations of these sorts of utilities - that's very bad for user expectations. |
I'd like to focus this issue on
Maybe better naming / documentation is the answer here? Sometimes different packages have subtly different needs. |
Sorry; that came out wrong. What I meant was that the sharing is dangerous, not the duplication. |
Opened #1321 for this. |
Opened enthought/ets#51 for the wider discussion. Closing this issue. |
I'd argue quite the converse - lack of sharing, in particular with How you do chained lookup is part of the "UI" of traits as a library and ETS more generally, and the strings being parsed by So from my point of view:
|
Yes, I could see value in codifying the "right way" to look up an extended trait name on a But Fixing |
Another aspect of this: I think it would be hard in practice to enforce the separation. It seems likely that we'll have people diving into the ETS source, finding a snippet of code that does what they need, and copying it to their own project code, without thinking about the "friendly" versus "everyone else" distinction.
I think it's not that bad. We'd just have to be careful to go through the usual deprecation / eventual removal dance - i.e., treat the function in the same way as a public one. |
I agree. Along this line of "not thinking about the friendly vs everyone else", I don't know if the convention of treating |
This is off-topic, but there is such a function ( |
Yes, I'm well aware. :-) The Traits version of that function uses |
TraitsUI uses this
xgetattr
andxsetattr
a lot. A pending PR in Pyface is introducing an example usingxgetattr
andxsetattr
, imported fromtraits.trait_base
(see enthought/pyface#543).This issue is to propose exposing and therefore maintaining these two functions in traits's public API, making it more obvious to traits developers that these functions are used downstream.
Alternatively, traits can decide not to maintain these functions in the public API. Then pyface and traitsui will need to maintain their own or risk breakages if they are advertising these functions publicly.
Related to #1213
The text was updated successfully, but these errors were encountered: