Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
c19ea84
Added initial remote debugging support
timrid Feb 23, 2025
f138e7a
- added plugin system for debugger
timrid Mar 10, 2025
fb79869
some cleanups
timrid Mar 15, 2025
70b290e
added "pth_folder_path" for iOS and Linux
timrid Mar 16, 2025
8746452
- use `BRIEFCASE_MAIN_MODULE` environment variable to start the remot…
timrid Mar 19, 2025
aad7565
fix for linux flatpak
timrid Mar 19, 2025
6d86c6c
change "_briefcase_launcher" approach to an approach with an separate…
timrid Mar 24, 2025
dd28eff
add enviroment variable on android
timrid Mar 27, 2025
1946e31
set environment variables on ios
timrid Mar 28, 2025
bb238d6
fix path mapping for android
timrid Mar 29, 2025
aa1df93
add remote debug support via environment variable for flatpak
timrid Mar 29, 2025
ea5f3f7
revert unnesessary changes on xcode
timrid Mar 30, 2025
5d0232a
changed "org.beeware.ENV" to "org.beeware.ENVIRON"
timrid Mar 30, 2025
dc3eb35
add BRIEFCASE_DEBUG to android
timrid Mar 30, 2025
97b9a9b
Add sources to the extract_packages so that the debugger can get the …
timrid Mar 30, 2025
e6b5167
remove port forwarding on android when "briefcase run" stops
timrid Mar 30, 2025
14fec61
removed unnessesary output to the console
timrid Mar 31, 2025
cf137bf
- Added option "--debug" for build, run and update command.
timrid May 17, 2025
2c14a4c
make android working and remove unnecessary code
timrid May 17, 2025
cd99d80
fixed all unit tests
timrid May 18, 2025
e612e45
Differentiate between "debug_mode" and "debugger". The selected debug…
timrid May 18, 2025
4446968
make android debugging working again
timrid May 18, 2025
88b71a7
Only forward port on android when "debugger_host" is "localhost"
timrid May 18, 2025
e7fe385
added documentation
timrid May 18, 2025
3d1e776
add a small how to for debugging with vscode
timrid May 18, 2025
fbb0c33
fixed a few pytest errors
timrid May 19, 2025
ddaf6a1
debug_mode is bool
timrid May 19, 2025
b67ac3f
env is not needed for adb forward/reverse
timrid May 20, 2025
21463e9
added unittests
timrid May 20, 2025
32337d8
Merge branch 'beeware:main' into feature/debugger-support
timrid May 22, 2025
84ec2b0
fixed test case and corrected changelog entry
timrid May 22, 2025
68128ab
fixed typo
timrid May 22, 2025
f5242f7
remove iOS environment variables when stopped
timrid May 22, 2025
e5ef27a
Merge branch 'main' into feature/debugger-support
timrid Jun 5, 2025
5c80cf5
fixed some unit tests
timrid Jun 5, 2025
9314998
added `debug_mode` in `AppConfig` and fixed unit tests
timrid Jun 5, 2025
cb5a32e
add context manager for android debugging connection
timrid Jun 5, 2025
b9d9d4b
add context manager for iOS environment variables
timrid Jun 8, 2025
478eb56
removed "debug_requires" and "debug_mode".
timrid Jun 10, 2025
1a7cd37
embed debugger support package into briefcase
timrid Jun 12, 2025
ec47b9f
"pdb" is now the default if no debugger is specified
timrid Jun 14, 2025
823edd7
Merge branch 'main' into feature/debugger-support
timrid Jun 14, 2025
f9198eb
corrected formatting
timrid Jun 14, 2025
123e932
use "remote-pdb"
timrid Jun 14, 2025
1786d7a
removed duplicate code
timrid Jun 14, 2025
4372e21
telnet is also available on linux
timrid Jun 14, 2025
582b57d
fixed unit tests
timrid Jun 14, 2025
ca55ef7
fixed more unit tests
timrid Jun 14, 2025
5bd4257
fixed docs
timrid Jun 14, 2025
d59b2ff
removed unnecessary branch
timrid Jun 15, 2025
4259f4a
fixed more CI errors
timrid Jun 15, 2025
68179ec
corrected the docs a little
timrid Jun 15, 2025
a382fbb
- removed all platform specific code
timrid Jun 15, 2025
40b3e88
fixed unit tests
timrid Jun 22, 2025
00c9376
Merge branch 'main' into feature/debugger-support
timrid Jun 22, 2025
87e675a
fixed unit tests in python 3.9 & 3.10
timrid Jun 22, 2025
7eb8e4b
Updated docs
timrid Jun 22, 2025
a3d15f3
removed how-to guides, as they are not working yet.
timrid Jun 22, 2025
5ff73ea
corrected changelog
timrid Jun 22, 2025
f23077d
Add how-to for debugging support
timrid Jun 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ distribute-*
.coverage.*
coverage.xml
venv*/
.venv*/
.vscode/
.eggs/
.tox/
Expand Down
1 change: 1 addition & 0 deletions changes/2147.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added basic functions for an ``--debug <debugger>`` option.
74 changes: 74 additions & 0 deletions docs/how-to/debugging/console.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
=================
Debug via Console
=================

Debugging an app on the console is normally done via `PDB <https://docs.python.org/3/library/pdb.html>`_.
It is possible to debug a briefcase app at different stages in your development
process. You can debug a development app via ``briefcase dev``, but also an bundled
app that is build via ``briefcase build`` and run via ``briefcase run``.


Development
-----------
Debugging an development app is quiet easy. Just add ``breakpoint()`` inside
your code and start the app via ``briefcase dev``. When the breakpoint got hit
the pdb console opens on your console and you can debug your app.


Bundled App
-----------
It is also possible to debug a bundled app. This is the only way to debug your
app on a mobile device (iOS/Android). Note that there are some :ref:`limitations <debugging_limitations>`
when debugging an bundled app.

For this you need to embed a remote debugger into your app. This is done via:

.. code-block:: console

$ briefcase build --debug pdb

This will build your app in debug mode and add `remote-pdb <https://pypi.org/project/remote-pdb/>`_
together with a package that automatically starts ``remote-pdb`` at the
startup of your bundled app. Additionally it will optimize the app for
debugging. This means e.g. that all ``.py`` files are accessible on the device.

Then it is time to run your app. You can do this via:

.. code-block:: console

$ briefcase run --debug pdb

Running the app in debug mode will automatically start the ``remote-pdb`` debugger
and wait for incoming connections. By default it will listen on ``localhost``
and port ``5678``.

Then it is time to create a new console window on your host system and connect
to your bundled app by calling:

.. tabs::

.. group-tab:: Windows

.. code-block:: console

$ telnet localhost 5678

.. group-tab:: Linux

.. code-block:: console

$ telnet localhost 5678

or

.. code-block:: console

$ rlwrap socat - tcp:localhost:5678

.. group-tab:: macOS

.. code-block:: console

$ rlwrap socat - tcp:localhost:5678

The app will start after the connection is established.
25 changes: 25 additions & 0 deletions docs/how-to/debugging/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
==============
Debug your app
==============

If you get stuck when programming your app, it is time to debug your app. The
following sections describe how you can debug your app with or without an IDE.

.. toctree::
:maxdepth: 1

console
vscode


.. _debugging_limitations:

Limitations when debugging bundled apps
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To debug an bundle app you need an network connection from your host system to
the device your are trying to debug. If your bundled app is also running on
your host system this is no problem. But when debugging a mobile device your
app is running on another device. Running an iOS app in simulator is also no
problem, because the simulator shares the same network stack as your host.
But on Android there is a separate network stack. That's why briefcase will
automatically forward the port from your host to the Android device via ADB.
83 changes: 83 additions & 0 deletions docs/how-to/debugging/vscode.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
================
Debug via VSCode
================

Debugging is possible at different stages in your development process. It is
different to debug a development app via ``briefcase dev`` than an bundled app
that is build via ``briefcase build`` and run via ``briefcase run``.

Development
-----------
During development on your host system you should use ``briefcase dev``. To
attach VSCode debugger you can simply create a configuration like this,
that runs ``briefcase dev`` for you and attaches a debugger.

.. code-block:: JSON

{
"version": "0.2.0",
"configurations": [
{
"name": "Briefcase: Dev",
"type": "debugpy",
"request": "launch",
"module": "briefcase",
"args": [
"dev",
],
"justMyCode": false
},
]
}


Bundled App
-----------
It is also possible to debug a bundled app. This is the only way to debug your
app on a mobile device (iOS/Android). Note that there are some :ref:`limitations <debugging_limitations>`
when debugging an bundled app.

For this you need to embed a remote debugger into your app. This is done via:

.. code-block:: console

$ briefcase build --debug debugpy

This will build your app in debug mode and add the `debugpy <https://code.visualstudio.com/docs/debugtest/debugging#_debug-console-repl>`_ together with a
package that automatically starts ``debugpy`` at the startup of your bundled app.
Additionally it will optimize the app for debugging. This means e.g. that all
``.py`` files are accessible on the device.

Then it is time to run your app. You can do this via:

.. code-block:: console

$ briefcase run --debug debugpy

Running the app in debug mode will automatically start the ``debugpy`` debugger
and listen for incoming connections. By default it will listen on ``localhost``
and port ``5678``. You can then connect your VSCode debugger to the app by
creating a configuration like this in the ``launch.json`` file:

.. code-block:: JSON

{
"version": "0.2.0",
"configurations": [
{
"name": "Briefcase: Attach",
"type": "debugpy",
"request": "attach",
"connect": {
"host": "localhost",
"port": 5678
}
}
]
}

The app will not start until you attach the debugger. Once you attached the
VSCode debugger you are ready to debug your app. You can set `breakpoints <https://code.visualstudio.com/docs/debugtest/debugging#_breakpoints>`_
, use the `data inspection <https://code.visualstudio.com/docs/debugtest/debugging#_data-inspection>`_
, use the `debug console REPL <https://code.visualstudio.com/docs/debugtest/debugging#_debug-console-repl>`_
and all other debugging features of VSCode :)
1 change: 1 addition & 0 deletions docs/how-to/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ stand alone.
ci
cli-apps
x11passthrough
debugging/index
external-apps
publishing/index
contribute/index
Expand Down
18 changes: 18 additions & 0 deletions docs/reference/commands/build.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,24 @@ If you have previously run the app in "normal" mode, you may need to pass ``-r``
/ ``--update-requirements`` the first time you build in test mode to ensure that
your testing requirements are present in the test app.

``--debug <debugger>``
----------------------

Build the app in debug mode in the bundled app environment and establish an
debugger connection via a socket. This installs the selected debugger in the
bundled app.

Currently the following debuggers are supported (default is ``pdb``):

- ``pdb``: This is used for debugging via console (see :doc:`Debug via Console </how-to/debugging/console>`)
- ``debugpy``: This is used for debugging via VSCode (see :doc:`Debug via VSCode </how-to/debugging/vscode>`)

It also optimizes the app for debugging. E.g. on Android it ensures, that all
`.py` files are extracted from the APK and are accessible for the debugger.

This option may slow down the app a little bit.


``--no-update``
---------------

Expand Down
33 changes: 33 additions & 0 deletions docs/reference/commands/run.rst
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,39 @@ contains the most recent test code. To prevent this update and build, use the
Prevent the automated update and build of app code that is performed when
specifying by the ``--test`` option.

``--debug <debugger>``
----------------------

Run the app in debug mode in the bundled app environment and establish an
debugger connection via a socket.

Currently the following debuggers are supported (default is ``pdb``):

- ``pdb``: This is used for debugging via console (see :doc:`Debug via Console </how-to/debugging/console>`)
- ``debugpy``: This is used for debugging via VSCode (see :doc:`Debug via VSCode </how-to/debugging/vscode>`)

For ``debugpy`` there is also a mapping of the source code from your bundled
app to your local copy of the apps source code in the ``build`` folder. This
is useful for devices like iOS and Android, where the running source code is
not available on the host system.

``--debugger-host <host>``
--------------------------

Specifies the host of the socket connection for the debugger. This
option is only used when the ``--debug <debugger>`` option is specified. The
default value is ``localhost``.

``--debugger-port <port>``
--------------------------

Specifies the port of the socket connection for the debugger. This
option is only used when the ``--debug <debugger>`` option is specified. The
default value is ``5678``.

On Android this also forwards the port from the Android device to the host pc
via ADB if the port is ``localhost``.

Passthrough arguments
---------------------

Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ Console = "briefcase.bootstraps.console:ConsoleBootstrap"
PySide6 = "briefcase.bootstraps.pyside6:PySide6GuiBootstrap"
Pygame = "briefcase.bootstraps.pygame:PygameGuiBootstrap"

[project.entry-points."briefcase.debuggers"]
pdb = "briefcase.debuggers.pdb:PdbDebugger"
debugpy = "briefcase.debuggers.debugpy:DebugpyDebugger"

[project.entry-points."briefcase.platforms"]
android = "briefcase.platforms.android"
iOS = "briefcase.platforms.iOS"
Expand Down
46 changes: 45 additions & 1 deletion src/briefcase/commands/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
from packaging.version import Version
from platformdirs import PlatformDirs

from briefcase.debuggers import get_debugger, get_debuggers

if sys.version_info >= (3, 11): # pragma: no-cover-if-lt-py311
import tomllib
else: # pragma: no-cover-if-gte-py311
Expand Down Expand Up @@ -134,6 +136,8 @@ class BaseCommand(ABC):
output_format: str
# supports passing extra command line arguments to subprocess
allows_passthrough = False
# supports remote debugging
supports_debugger = False
# if specified for a platform, then any template for that platform must declare
# compatibility with that version epoch. An epoch begins when a breaking change is
# introduced for a platform such that older versions of a template are incompatible
Expand Down Expand Up @@ -681,7 +685,12 @@ def finalize_app_config(self, app: AppConfig):
:param app: The app configuration to finalize.
"""

def finalize(self, app: AppConfig | None = None, test_mode: bool = False):
def finalize(
self,
app: AppConfig | None = None,
test_mode: bool = False,
debugger: str | None = None,
):
"""Finalize Briefcase configuration.

This will:
Expand All @@ -701,6 +710,7 @@ def finalize(self, app: AppConfig | None = None, test_mode: bool = False):
apps = self.apps.values() if app is None else [app]
for app in apps:
if hasattr(app, "__draft__"):
self.finalize_debugger(app, debugger)
app.test_mode = test_mode
self.finalize_app_config(app)
delattr(app, "__draft__")
Expand All @@ -726,6 +736,18 @@ def finalize(self, app: AppConfig | None = None, test_mode: bool = False):
f"{app.app_name!r} defines 'external_package_executable_path', but not 'external_package_path'."
)

def finalize_debugger(self, app: AppConfig, debugger_name: str | None = None):
"""Finalize the debugger configuration.

This will ensure that the debugger is available and that the app
configuration is valid.

:param app: The app configuration to finalize.
"""
if debugger_name and debugger_name != "":
debugger = get_debugger(debugger_name)
app.debugger = debugger

def verify_app(self, app: AppConfig):
"""Verify the app is compatible and the app tools are available.

Expand Down Expand Up @@ -982,6 +1004,28 @@ def _add_test_options(self, parser, context_label):
help=f"{context_label} the app in test mode",
)

def _add_debug_options(self, parser, context_label):
"""Internal utility method for adding common debug-related options.

:param parser: The parser to which options should be added.
:param context_label: Label text for commands; the capitalized action being
performed (e.g., "Build", "Run",...)
"""
debuggers = get_debuggers()
debugger_names = list(reversed(debuggers.keys()))
choices_help = [f"'{choice}'" for choice in debugger_names]

parser.add_argument(
"--debug",
dest="debugger",
nargs="?",
default=None,
const="pdb",
choices=debugger_names,
metavar="DEBUGGER",
help=f"{context_label} the app with the specified debugger. One of {', '.join(choices_help)} (default: pdb)",
)

def add_options(self, parser):
"""Add any options that this command needs to parse from the command line.

Expand Down
Loading