Android sys img picker#2843
Conversation
|
The approach was revised during the PyCon sprint after a discussion with @mhsmith. |
… and no system image.
…rmed versions in list_available_system_images
…e across platforms
|
Are the 3 CI failures pre-existing or am I goofing something here?
I checked recent CI runs on main and found some of these issues crop up there. |
|
Yes, the failures aren't related to this PR, so you don't need to worry about them. Thanks for the updates, I'll look at this in a couple of days. |
|
|
||
| def list_available_system_images( | ||
| self, min_version: int = ANDROID_MIN_OS_VERSION | ||
| ) -> list[str]: |
There was a problem hiding this comment.
There's no need to declare a default argument which is never used in production code; this only obscures the actual source of the default.
On the other hand, the test code should test the behavior of the argument; it looks like it currently doesn't.
| from briefcase.integrations.subprocess import SubprocessArgT | ||
|
|
||
| DEVICE_NOT_FOUND = re.compile(r"^error: device '[^']*' not found") | ||
| ANDROID_MIN_OS_VERSION = 26 |
There was a problem hiding this comment.
Got it. I chose 26 because of a comment Russell made in issue #737: #737 (comment)
Would you recommend I stick with the template default of 24?
There was a problem hiding this comment.
That's a typo on my part - we should definitely stick to the 24 minimum.
| :param min_version: The minimum Android version to include. Defaults to | ||
| ``ANDROID_MIN_OS_VERSION``. | ||
| e.g., ``["system-images;android-31;default;x86_64", "system- | ||
| images;android-34;default;x86_64", "system- | ||
| images;android-34;google_apis;x86_64"]`` |
There was a problem hiding this comment.
If the default argument is removed, it should be removed from the docstring as well.
Our docstrings now use Markdown, so code should be marked with single backquotes. The spacing and line breaking in the code probably won't render correctly either, but RTD obviously has a problem with the current commit, so we can't see for sure. If you merge from the main branch, that will probably fix the current error.
Also, if you intend the "e.g." paragraph to be part of the main docstring, then it should go before the param list, not after.
| for line in output.splitlines(): | ||
| package = line.split("|")[0].strip() | ||
| if not package.startswith("system-images"): | ||
| continue |
There was a problem hiding this comment.
The code above this point could be replaced with a call to list_installed_system_images.
There was a problem hiding this comment.
Sorry, not replaced exactly, but the duplicate code should be factored out.
| system_image = self.DEFAULT_SYSTEM_IMAGE | ||
| # Get available images, raise an error if none found. | ||
| available_images = self.list_available_system_images( | ||
| min_version=getattr(app, "min_os_version", ANDROID_MIN_OS_VERSION) |
There was a problem hiding this comment.
Recommend factoring out this getattr expression into a function, and using it in output_format_template_context. That would eliminate any risk of the two locations going out of sync.
| ) | ||
|
|
||
| # Ask the user to select an Android version. | ||
| versions = sorted({img.split(";")[1].split("-")[1] for img in available_images}) |
There was a problem hiding this comment.
The split expressions in this function are difficult to understand. Suggest creating a parsing function which converts a system image name into an object with fields for Android version, image type and ABI. Then we can either use that function both here and in list_available_system_images, or maybe even make list_available_system_images return the parsed objects.
| versions = sorted({img.split(";")[1].split("-")[1] for img in available_images}) | ||
| version = self.tools.console.selection_question( | ||
| intro="Select the Android version for the emulator:", | ||
| description="Android version", |
There was a problem hiding this comment.
To avoid confusion, should say "API level" rather than "Android version".
| { | ||
| f"{img.split(';')[1]};{img.split(';')[2]}" | ||
| for img in available_images | ||
| if img.split(";")[1].startswith(f"android-{version}") |
There was a problem hiding this comment.
Why is the version included in the type here, and why are we using startswith? I thought it might be because of decimal versions, but that doesn't quite seem right either. For example, if the version question has choices for 36 and 36.1, and the user chose 36, the second question will still include the images for 36.1. It's probably better not to do anything clever about that, and treat every version independently.
| skin = self.DEFAULT_DEVICE_SKIN | ||
|
|
||
| # TODO: Provide a list of options for system images. | ||
| system_image = self.DEFAULT_SYSTEM_IMAGE |
There was a problem hiding this comment.
DEFAULT_SYSTEM_IMAGE is still used in one other place, but it should be updated to make sure it's consistent with the default Android version and image type used in this function. This would probably involve creating DEFAULT properties for those two things, and using them in both locations.
|
|
||
| # Create a mock app | ||
| app = MagicMock() | ||
| del app.min_os_version # ensure getattr fallback is used |
There was a problem hiding this comment.
There should be at least one test of the attribute being present.
|
Thanks for the detailed feedback. I'll work through each point. |
Added two step selection flow that fetches all available compatible images from
sdkmanager --list.Hard coded version is set if default is selected.
This enables the user to select an android version when creating a new emulator.
Fixes #737
PR Checklist:
Assisted-by: Claude Sonnet 4.6