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

Add --debug option to briefcase run #2147

Open
timrid opened this issue Feb 5, 2025 · 3 comments
Open

Add --debug option to briefcase run #2147

timrid opened this issue Feb 5, 2025 · 3 comments
Labels
enhancement New features, or improvements to existing features.

Comments

@timrid
Copy link

timrid commented Feb 5, 2025

What is the problem or limitation you are having?

It is inconvenient to debug an packaged applications that was created with briefcase run. For Windows und Android I showed the nessesary steps in #1393 (comment).

Describe the solution you'd like

To simplify the debugging of packaged versions of the application code, we could extend the briefcase run command with an additional parameter --debug <debugger-name> and debugger specific options.

In VSCode the debugger is called debugpy. PyCharm is using the package pydevd-pycharm. I have not tested PyCharm, but the workflow should be pretty similar to VSCode. So it would make sense to specify the <debugger-name> in the command line.

For --debug debugpy it would make sense, to add two more parameters:

  • --debug-debugpy-version <debugpy-version>: Version that should be added to the requirements (optional, if not set use the latest version)
  • --debug-debugpy-port <debugpy-port>: Specify the Port to use for debugging (under android this port would be forwared by adb)

This new command line parameter would:

  1. Internally add debugpy to the requirements (without adding it explicitly to pyproject.toml).
  2. Inject debugpy.listen(...) to the app (without adding it explicitly to the source code)
  3. On android: Copy not only the .pyc but also all .py Files to the .apk. (When Provide option for PYC-only distribution #2073 is implemented this would be nessesary on all platforms)
  4. On android: Forward the port via ADB before starting the app.
  5. Output the paths that are needed for pathMappings in launch.json, so that the user dont have to search them manually

That would simplify the debugging process to only run briefcase run android --debug debugpy --debug-debugpy-port 5678 and add the VSCode configuration to launch.json.

Describe alternatives you've considered

Leave the steps nessesary to debug an packaged application as decribed in #1393 (comment).

Additional context

This command line option could also be useful later for implementing a VSCode/PyCharm extension, as suggested here.

@timrid timrid added the enhancement New features, or improvements to existing features. label Feb 5, 2025
@freakboy3742
Copy link
Member

Thanks for the investigation work on this - this is all extremely thorough! I'm especially impressed by the android debugging work - I had pretty much assumed that wouldn't be possible without major effort, so I'm very much pleasantly surprised you've got that to work. It makes me wonder if the same approach will work on iOS as well..

Broadly, I agree that this (or something similar to it) would be worth pursing. It's not a small task... but it would definitely be a huge value-add.

A couple of high level things that stood out to me as questions/issues to be resolved:

  1. The need to inject specific debug code into an app is problematic - because if anything is injected, it needs to be possible to remove it before publication, is completely reversible and repeatable. I can think of a couple of ways around this - the first would be a convention around Briefcase's __main__ importing a __debug__.py module in the same folder, with a documented expectation that this file will install any required debug handlers, and that Briefcase will re-write this file as required. The second would be to utilise a .pth file in the site packages folder, to much the same effect. The latter has the benefit that we don't need to document an additional entry point.

  2. "I have not tested PyCharm, but the workflow should be pretty similar to VSCode" is a... load bearing assumption :-) Having some confirmation that the assertions made about the needs of the debug interface are even nominally correct would seem critical to moving this forward. I know @wsvincent recently joined JetBrains as a developer advocate; I don't know if he might be able to shed some light on what might be required here.

  3. The fact that the debugging process is IDE-specific is problematic. This makes me think that what is needed is a plugin interface that can be satisfied by different IDEs. We might only provide a "bare PDB" implementation, but out of the box, with other IDE plugins being provided as extension packages that the user can install as required (e.g., pip install briefcase[vscode] or pip install briefcase-vscode).

  4. In terms of the end-user experience, there's also an extent to which it requires the user to be explicit every time they debug. In practice, if I'm using VSCode, I'm always using VSCode. Needing to specify "Debug with VSCode" every time seems awkward. If there's no way to automatically identify that code is running in a VSCode environment, having the ability to specify project-level and global-level user defaults would seem beneficial here. This could also be used for other features like the signing certificate for an app, the default simulator image to use, and so on. Having a top level "briefcase config (--global)...option that writes to a.briefcase.toml` config file would seem potentially useful here.

  5. I'm also going to stare wistfully into the distance at BeeWare's long neglected Bugjar project... 😢

@timrid
Copy link
Author

timrid commented Feb 9, 2025

iOS Debugging

I have now also tested debugging an iOS app in the iOS Simulator and this works without any problems. For the iOS Simulator it is not even necessary to execute an equivalent to adb forward, because iOS Simulator and macOS share the same network. So iOS is even a bit easier to debug than Android. I couldn't test it with a physical iPhone because I don't have one. But as long as you know the IP address of the iPhone it should work. And even if not, the iOS simulator helps a lot.

PyCharm

I also took a look at PyCharm. Remote debugging is only possible with PyCharm Professional, unfortunately PyCharm Community does not support it. But thanks to the 30 day trial I was able to try it out. Basically it works similar to VSCode, except that pydevd-pycharm is used instead of debugpy. However, the installation of pydevd-pycharm currently does not work correctly with briefcase. See #2152.

But if you work with the workaround described in #2152 (remove --upgrade as pip parameter) and pydevd-pycharm is installed correctly, it is also possible to debug via PyCharm. However, there are principal differences between VSCode and PyCharm. VSCode supports the “App as Debug Server” and “App as Debug Client” options. PyCharm only supports “App as Debug Client”, which I find a bit more difficult to use.

App as Debug Server (only VSCode):

+-----------------+--------+-----------------+
|      IDE        |  ----> |      App        |
| (Socket Client) |        |  (Socket Server) |
+-----------------+--------+-----------------+
  1. start app (internally the app starts the socket server permanently via debugpy.listen(...))
  2. IDE connects to app (connection can also be established and terminated again)

(Under Android, adb forward is required.)

In principle, I find this approach easier to use, as you can simply start the app and attach the debugger later. You can even restart the debugger.

App as Debug Client (VSCode and PyCharm):

+-----------------+--------+-----------------+
|      IDE        |  <---- |      App        |
| (Socket Server) |        | (Socket Client) |
+-----------------+--------+-----------------+
  1. start IDE debugger (it waits until the app connects)
  2. start the app (the connection to the IDE is established internally (debugpy.connect(...) or pydevd_pycharm.settrace(...))

(Under Android, adb reverse is required).

This approach is sometimes a bit difficult if you have already started the app but have forgotten to start the debugger in the IDE. Then you have to restart the App.

Setting path mappings from app

What I also found out is that you can also set the pathMappings, so far defined in launch.json, using the following command from within the packaged application. This is the same for VSCode and PyCharm, because both are based on pydevd.

path_mappings = [(host_path_1, device_path_1),(host_path_2, device_path_2)]
import pydevd_file_utils
pydevd_file_utils.setup_client_server_paths(path_mappings)

This makes setting up the IDE much easier, as the end user does not have to deal with the different paths of Windows/iOS/Android and does not have to have different debug configurations for the different operating systems in the launch.json. The app can identify the device paths itself, but the paths to the host system have to be passed to the app somehow. Maybe automattically via briefcase?

To identify the correct path i currently use this code:

path_mappings = []
if sys.platform == "android":
	host_app_path = f"{host_workspace}/src"
	device_app_path = list(filter(lambda p: True if "AssetFinder/app" in p else False, sys.path))
	if len(device_app_path) > 0:
		path_mappings.append((host_app_path, device_app_path[0]))     

	host_requirements_path = f"{host_workspace}/build/{app_name}/android/gradle/app/build/python/pip/debug/common"
	device_requirements_path = list(filter(lambda p: True if "AssetFinder/requirements" in p else False, sys.path))
	if len(device_requirements_path) > 0:
		path_mappings.append((host_requirements_path, device_requirements_path[0]))

elif sys.platform == "win32":
	# Normally app & requirements are automatically found. But the app path is pointing to a copy of the source in some temporary folder, so we redirect it to the original source.
	host_app_path = f"{host_workspace}/src"
	device_app_path = list(filter(lambda p: True if p.endswith("app") else False, sys.path))
	if len(device_app_path) > 0:
		path_mappings.append((host_app_path, device_app_path[0]))

Integration in briefcase

I completely agree with you on your point 4. So it would make sense to configure the debugging via pyproject.toml and only activate it via command line. So I change my proposal to:

  1. Add --debug command line parameter, for activation of the debug mode.
  2. Add debug_requires to pyproject.toml. Here you can define debugpy or pydevd-pycharm.

These two points are pretty obvious and comparable to the --test and the test_requires

However, it becomes more complicated when inserting the debug code. Maybe we could add a debug_file option to the pyproject.toml, in which the user can define a file that is executed via a mechanism as you describe in your point 1. This proposal is not fixed to VSCode / PyCharm and can in principle also support other debuggers. The IP/port could also be stored directly in the script and no further options are required for this are required in the pyproject.toml. But as I mentioned before, it would be good if briefcase could also pass the paths of the host system to the debug_file to make the setup easier. So we would have to create a mechanism to pass parameters from briefcase to the debug_file.

@freakboy3742
Copy link
Member

Thanks for that update - very comprehensive.

Regarding launch.json specifically - I agree that is something that Briefcase should be able to generate; the only question is how/where to make the use of that mapping file easy.

I completely agree with you on your point 4. So it would make sense to configure the debugging via pyproject.toml and only activate it via command line.

I'm not 100% sure whether pyproject.toml is correct - since debugging may include user-specific properties. For example, you might be able to use port 5678, but I can't because I've got something else on that port. Or, even more likely - you use pycharm, and I use VSCode. We may need to add user-level configuration (which is also where the options for signing certificates and simulator preferences would go).

So I change my proposal to:

  1. Add --debug command line parameter, for activation of the debug mode.
  2. Add debug_requires to pyproject.toml. Here you can define debugpy or pydevd-pycharm.

If we're going down the path of another "requires" setting, my inclination would be to use this as an opportunity to move to a better embrace of PEP 621, and adopt the use of [project.optional-dependencies].

However, I'm also not convinced we necessarily need that. The set of dependencies needed by VSCode debugging will be known; as will the set of dependencies need by PyCharm debugging. If you've specified --debug, and my local configuration indicates that I want to use VSCode, then the VSCode plugin interface can specify what packages need to be installed.

As for debug_file - again, this should be something that is boilerplate for any given IDE plugin - it shouldn't need explicit configuration. The only setting we should need is a per-user setting for the preferred debugging backend, with a pdb backend being the default (since that's the only one we can guarantee exists - although pdb on iOS/Android is likely a non-starter).

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

No branches or pull requests

2 participants