-
-
Notifications
You must be signed in to change notification settings - Fork 19
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
Changed to updated Pack.layout() signature (without node) #244
Conversation
Well I'd tested it from both versions of Toga, that is. Hadn't thought to try Travertino's tests. 🤣 While I don't know of a good way to directly test this "in" both Toga 0.4.8 and beeware/toga#3061, we can at least test here that it works with style classes with both |
For that matter, any reason not to make it an ABC with abstract methods? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mechanically, this looks fine; my concern is that this is in the refresh()
method, which is a potentially hot part of the layout process, and the compatibility check will be invoked on every invocation.
Would it not be better to invoke self.style.layout(viewport)
, and catch the TypeError if the argument isn't there? That optimises for the "expected" case, and avoids the need to check for a Toga-specific argument name. It also means the "backwards compatibility" comments can be wrapped around just the parts that need to be deleted (which is a minor thing, but I'll guarantee will take at least 2 attempts to get right when the time comes to finalise the deprecation :-) )
The main reason is the runtime overhead of an ABC for a class that most people won't be implementing. For my money, an the overhead of an ABC makes sense when the class is something you expect end-users to implement; but in this case, it's a class that will be implemented by probably 2 projects (and both of them are us :-) ). I could go either way on an empty/NotImplemented "layout" method; I guess it doesn't hurt to add (and there's a lower overhead, because it's an entry in the |
I keep forgetting that there's runtime overhead, yeah that makes sense.
I think I'd like to add one, just as a little bit of internal reminder documentation for our future selves. Or at least my future self.
That was my first thought, but I worried that could potentially mask other TypeErrors on down the stack, the way that the But I take your point about optimizing such a frequently called thing. What if I only make the check once, and cache the "which version to use" result? |
…we count on having the style._applicator.node link
The old So uh... let me know if you think my "caching" mechanism is too hacky. The first time any node's I've made one other change to control flow here: I've put the call to |
I've thought better of my previous approach, and pushed a less-sorcerous method of checking and caching; instead of a method that's called once and then alters its own attribute name to point to a different method, now it's a straightforward boolean stored on the class and used if present. Either version should work — and I imagine this version will technically be slightly slower, since this patch now introduces one additional conditional check in each call to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can see what you're going for here - but is this actually sufficient? At least in theory, you can have different Style
instances, each of which could have different layout()
prototypes. I agree that's unlikely, but it is possible.
On top of that, while this is caching the value as a property, it's accessing that property via a function call, which is essentially a version of the overhead we were trying to avoid in the first place.
I agree that catching TypeError is prone to catching the nested errors - my inclination for addressing this would be to use try/catch, and in the case that a TypeError raised, invoke signature a that point to try and determine if the problem is the signature of the method being invoked (looking for 2 non-underscore prefixed arguments). If it's a "new style" layout method and it raised a TypeError internally, that error can be re-raised; but if it's an old-style layout method, even if it does raise a TypeError internally (which is less likely as it's a pre-existing method), the signature of the layout method is something that needs to be updated.
I realize that's technically possible, but it could never happen with Toga unless one somehow had two different versions installed, and if anyone is for some reason defining their own style classes with different layout signatures, I think that would be asking for trouble. However, that's a moot point because...
I don't know why it didn't occur to me to inspect the error raised, that makes perfect sense. |
I'm really looking forward to 3.9 EOL and the across-the-board availability of |
5caabf7
to
6bd400b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. I've tweaked the release note - although layout()
wasn't formally defined previously, the fact that there's a deprecation path means we should warn anyone using that API. I've also slightly broadened the exception check so that it isn't dependent on a specific argument name; I think the risk of a false positive is less of a concern than the false negative.
Once beeware/toga#3061 is merged, Toga's Pack.layout() will expect a single argument (the viewport), and doesn't need to be passed the node.
Since Toga 0.4.8 doesn't have an upward cap on Travertino version used, it's always possible someone could update to Travertino 0.4.0 while not having updated yet to Toga 0.5.0. So this checks what parameters the method expects, and adapts accordingly. I've tested this locally... not sure if there's any good way to verify this in CI.
PR Checklist: