Refactor handling of user input in new/convert commands.#2115
Refactor handling of user input in new/convert commands.#2115freakboy3742 merged 10 commits intobeeware:mainfrom
Conversation
9f0b85d to
00997b6
Compare
There was a problem hiding this comment.
I agree with this refactor; it is eerily reminiscent of something I attempted early in my journey with BeeWare....but I was too overzealous and unfocused at the time 😅 😆
I do wonder, though, if this should be its final form...
If we consider Console at a time before I started mucking in it so much, its purpose was much clearer: manage basic interaction with the user. In that way, it made much more sense then for why it was attached to the Command with the name input.
At this point, Console has transformed from something that manages user input to something that actually manages the user's console.
So, I wonder if we shouldn't recreate something more akin to what Console was originally; basically, move all the user interaction bits to a new Input class and attach that to the Command as input. Then, Console could become a separate entity on the Command as console, for instance.
This way, invoking the Wait Bar wouldn't require going through command.input (which always felt a bit awkward to me tbh).
Another approach might still create Input but it is attached to Console as input and Console is attached to Command as console. In this way, the Wait bar is available via command.console.wait_bar() and user input is available via command.console.input.text_question().
Additionally, with all these abstractions for soliciting user feedback, should we get rid of input.__call__()? More generally, should we make this primitive method to get input private and instead only use (and advertise) the higher abstractions for use in Briefcase and plugins?
Thoughts?
Co-authored-by: Russell Martin <russell@rjm.li>
Great minds, etc? 🤣
Completely agreed that this corner of the API is a little confusing.
If I understand what you're describing here, then I think it might make sense. For me, there's essentially four problems to solve here:
So - what you're proposing is to create a new The constructor for input would take a logger and a console; that way an input handler could raise warnings if needed. Commands would be constructed with a Console and a Logger; but then build an Input() wrapper around those two. The Bootstrap API could then be modified to only take an instance of input - the logger and console can be extract from that. There's 3 downsides I see to this approach. The first is that there's another class involved - I'm not necessarily convinced another namespace is improving things here. The second is that the distinction between Logger and Console is a bit vague. Is there a meaningful distinction why you'd say The third is that the relationship between Console, Logger, and Printer just got more complicated. We've now got four classes. The Printer has a
Definitely agreed on this -
True - but
I'm not 100% sure about this. As I see it, the intention for this method is to retain an analog of the builtin |
|
There's a lot of organic growth here... I kinda feel like your points (and past times we've touched on this) are leaning towards just consolidating all of this. My view of the current state:
Given this, I could definitely see an argument to combine With that said, this is one big class... I think part of what was pushing me towards moving the user interaction bits in to a So, do you have a preference in direction in mind? I''m not sure I can tell which way you're leaning...if any way :) |
Oh - completely agreed. Each of the individual steps that we've taken to get here made sense - it's only when steps back and look at where we've arrived (and how what we've got satisfies a new use case) that it makes less sense.
That's definitely true... but why does that matter? It might make sense to break it up if it made testing or usage easier - if, for example, there was a context where we needed a Logger but not a Console, or if testing a Logger was easier if it wasn't attached to a Console. But in this case, the thing that needs to be mocked is the underlying pieces of Printer (which could equally be the underlying pieces of a combined Printer/Logger/Console class); and while there is some conceptual separation between the APIs offered by Logger and Console, they're all "communicating with the user" APIs, I'm not sure we gain anything by breaking them up - especially if we need to pass 2 or 3 objects around everywhere... and especially if there's internal links between them (so that input classes can write to the log, for example). Yes, we're going to end up with a single 1000 line class. But that's going to be made up of a dozen or so public API methods, and a dozen or so internal utility methods. That's an entirely testable interface, IMHO; and I'm not sure that some additional language-level classes gives us any organisational clarity that we couldn't get with some inline banner comments separating "sections" of code.
At least for now, my "strong opinion weakly held" position is that merging everything into a Console class, and modifying usage to use That said - I'm also open to be convinced otherwise on this. |
|
I'm not familiar with this code, so I'll remove myself as a reviewer for now. Feel free to add me back if necessary. |
I think it just makes the code easier to reason about and prevents unnecessary inter-dependence when it's separated in to logical pieces. It also think it makes the code more approachable by newer contributors. I remember trying to take in
I'd support that. Another implementation strategy could be mix-in classes; right now, each of these things are really only dependent on a |
rmartin16
left a comment
There was a problem hiding this comment.
Took an initial review and left some comments.
As for potentially extending this refactor, just let me know if you'd like to do that here in this PR....or use this as an incremental step to unblock your other work.
|
@rmartin16 I've addressed those initial review comments. In terms of the larger consolidation/refactor - it's going to be a big set of changes; I can't see any way adding those changes to this PR would make it easier to review :-) On that basis, I'd suggest wrapping up the review and feedback process on this PR, and following up quickly with the consolidation PR (I've already started work on it). |
Co-authored-by: Russell Martin <russell@rjm.li>
2ab1311 to
7da7d19
Compare
The bulk of prompted user input in Briefcase occurs in the New command, which is inherited by the Convert command. However, there are a handful of other places in Briefcase where the user is asked for an option - and each of these uses has a very slightly different set of semantics around how questions behave.
This PR moves all the user input handling into the Console class, providing a common interface for "asking questions". The New and Convert commands have been refactored to use this common "question asking" interface; as have the uses in macOS (selecting signing identity) iOS and Android (selecting the simulator to use).
As a result of #2114, this interface would also be available for custom bootstraps to use - ensuring that questions asked by custom bootstraps follow the same UX conventions as the rest of Briefcase.
This refactor also provides the opportunity to do some general housekeeping, dramatically simplifying some implementations, and renaming some interfaces so that the public API (or, at least, the API that we encourage people to use) is hopefully a little more clear and consistent, and avoids repetition in naming.
As a result of this change, there may be some cosmetic changes to the order in which options are presented. Previously selection options would be automatically sorted; the new implementation drops that sorting in favor of using provided dictionary order, allowing the user of the API to determine if sorting is appropriate.
PR Checklist: