Skip to content
Merged
Show file tree
Hide file tree
Changes from 101 commits
Commits
Show all changes
141 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
8843ab3
change from dynamic creation of debugger-support packages to a static…
timrid Jun 25, 2025
7772c79
Added Windows debugging support
timrid Jun 25, 2025
6ffb51c
Added macOS debugging support
timrid Jun 26, 2025
57d1d76
Update docs
timrid Jun 26, 2025
6eaacd1
Added detection if briefcase is installed as editable
timrid Jul 9, 2025
2cddf89
Added restriction hint for macOS.
timrid Jul 10, 2025
3aa88bf
typo
timrid Jul 10, 2025
5add24b
Merge remote-tracking branch 'origin/main' into feature/debugger-support
timrid Aug 5, 2025
456c373
more docstring optimizations
timrid Aug 5, 2025
46a88cf
remove restriction to min. macOS 14
timrid Aug 5, 2025
202d15e
correct changelog
timrid Aug 5, 2025
183c311
added missing unittests
timrid Aug 5, 2025
92da289
added missing test
timrid Aug 5, 2025
5a70721
fixed tests for windows
timrid Aug 5, 2025
c7f14c5
moved editable check logic to debuggers folder
timrid Aug 8, 2025
2a1dc1b
added hints and cosmetic changes
timrid Aug 8, 2025
0b879d5
removed "-debuger-support" from name
timrid Aug 13, 2025
dacf7ea
fixed unit tests
timrid Aug 13, 2025
84ee166
renamed packages
timrid Aug 13, 2025
3c5ab10
added unittests, tox-config and ci for briefcase-debugpy and briefcas…
timrid Aug 13, 2025
9828dba
clarified default parameter of --debug
timrid Aug 15, 2025
1a812bb
added testcase for os.__file__ bugfix
timrid Aug 15, 2025
73b6028
Merge remote-tracking branch 'remotes/origin/main' into ci-test
timrid Aug 15, 2025
68f22c6
Add how-to for debugging support
timrid Jun 24, 2025
17f2a93
"justMyCode" has to be set to false
timrid Aug 17, 2025
c4e0ed0
added hint to build and run, that the selected debuggers has to match.
timrid Aug 17, 2025
27af64e
added warning to packaging
timrid Aug 17, 2025
4c8a4f0
removed reference to android
timrid Aug 17, 2025
5224177
removed test ci branch used for testing in my fork
timrid Aug 17, 2025
42554e9
add verbose debugpy output
timrid Sep 1, 2025
d06f45c
correct comment
timrid Sep 1, 2025
17df334
merged "briefcase-debugpy" and "briefcase-pdb" to "briefcase-debugger"
timrid Sep 1, 2025
b9ebbee
fixed unit tests
timrid Sep 2, 2025
db57422
remove build folder
timrid Sep 3, 2025
58cb41b
add missing test in briefcase
timrid Sep 3, 2025
1d2f50f
whe a regex is not found in path this should be an error instead of s…
timrid Sep 3, 2025
550a3d1
REMOTE_DEBUGGER_STARTED is unnecessary
timrid Sep 3, 2025
304b531
add code coverage
timrid Sep 2, 2025
462d1b6
no german
timrid Sep 3, 2025
dbf3ac5
Merge remote-tracking branch 'remotes/origin/main' into feature/debug…
timrid Sep 3, 2025
e260e98
modifications because 3.9 is not supported any longer
timrid Sep 3, 2025
092f356
remove ci-test branch
timrid Sep 3, 2025
abd042d
update documentation, add comments, correct formating
timrid Sep 4, 2025
deae895
fixed licens badge
timrid Sep 4, 2025
16ae953
added more docs
timrid Sep 4, 2025
296f7d2
moved tox debugger config
timrid Sep 4, 2025
caf9f5e
use dependency groups
timrid Sep 4, 2025
535d49e
start debugger in the .pth file and not on import
timrid Sep 4, 2025
673dbf0
reorderd sections in pyproject.toml
timrid Sep 4, 2025
88ba809
parameterized path mapping tests with additional cases for andorid on…
timrid Sep 8, 2025
aa9b600
fixed path mapping test on posix
timrid Sep 8, 2025
f57abfd
remove "if verbose" inside test cases
timrid Sep 8, 2025
b1ef9a0
rename "debugger-support" folder to just "debugger"
timrid Sep 8, 2025
ba8c990
actually rename the folder "debugger-support" to "debugger"
timrid Sep 8, 2025
5a560c9
moved "debugger-host" and "debugger-port" arguments to "_add_debug_op…
timrid Sep 16, 2025
07b56e2
moved "debugger_host" and "debugger_port" to AppConfig
timrid Sep 18, 2025
886b3c6
fixed "debugger_port" type to int
timrid Sep 18, 2025
c039165
moved "debugger_config" to "BaseDebugger"
timrid Sep 18, 2025
6c60d3c
use `nc` instead of `rlwrap socat` and make hints platform aware.
timrid Sep 19, 2025
e658d85
fixed unit tests
timrid Sep 19, 2025
4c9c81b
debugpy v1.8.17 fixed the os.__file__ handling. So this workaround is…
timrid Sep 19, 2025
b60c0c5
remove "PureWindowsPath" from tests
timrid Sep 19, 2025
1218a6a
fixed unit tests
timrid Sep 19, 2025
9657c95
updated docs
timrid Oct 23, 2025
56623bd
simplify help msg creation
timrid Oct 23, 2025
1800212
refactored commands to variable and removed host os hint.
timrid Oct 23, 2025
ea66f50
use "artifact-basename" in ci.yml
timrid Oct 25, 2025
cfe33c9
updated release.yml
timrid Oct 25, 2025
d072152
Merge branch 'main' into feature/debugger-support
timrid Oct 25, 2025
90f3f4c
converted docs from .rst to .md
timrid Oct 25, 2025
f648508
environments created with tox_uv dont have pip preinstalled
timrid Oct 25, 2025
8b13a6c
fixed ruff errors
timrid Oct 25, 2025
35907f2
fixed spelling issues
timrid Oct 25, 2025
0342efc
fix ci
timrid Oct 28, 2025
3aa81ed
Merge branch 'main' into feature/debugger-support
timrid Oct 28, 2025
2db8449
Merge branch 'main' into feature/debugger-support
mhsmith Nov 3, 2025
e6c4138
Documentation cleanups
mhsmith Nov 3, 2025
f1f11b6
Rename 2147.feature.rst to 2147.feature.md and reword
mhsmith Nov 3, 2025
5e74fef
Update docs URLs; use `%(default)s` in argparse help
mhsmith Nov 3, 2025
234195e
add hint that you have to define `breakpoint()` somewhere when using …
timrid Nov 7, 2025
4b123ba
Add missing comma
mhsmith Nov 11, 2025
c917269
Fix long line
mhsmith Nov 11, 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
24 changes: 22 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ jobs:
with:
attest: ${{ inputs.attest-package }}

package-debugger:
name: Package Debugger
permissions:
id-token: write
contents: read
attestations: write
uses: beeware/.github/.github/workflows/python-package-create.yml@main
with:
build-subdirectory: "debugger-support"

package-automation:
name: Package Automation
permissions:
Expand All @@ -58,7 +68,7 @@ jobs:

unit-tests:
name: Unit tests
needs: [ pre-commit, towncrier, package ]
needs: [ pre-commit, towncrier, package, package-debugger ]
runs-on: ${{ matrix.platform }}
continue-on-error: ${{ matrix.experimental || false }}
strategy:
Expand Down Expand Up @@ -101,7 +111,7 @@ jobs:
requirements: tox
extra: dev

- name: Test
- name: Test Briefcase
id: test
run: |
RUNNER_OS=$(cut -d- -f1 <<< ${{ matrix.platform }})
Expand All @@ -124,6 +134,16 @@ jobs:
# coverage reporting must use the same Python version used to produce coverage
run: tox -qe coverage$(tr -dc "0-9" <<< "${{ matrix.python-version }}")

- name: Get Debugger Package
uses: actions/[email protected]
with:
name: ${{ needs.package-debugger.outputs.artifact-name }}
path: dist

- name: Test Debugger
run: |
tox -e py-debugger --installpkg dist/briefcase_debugger-*.whl

coverage:
name: Project coverage
runs-on: ubuntu-24.04
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
/dist
/build
automation/build
debugger-support/build
docs/_build/
distribute-*
.DS_Store
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 for Windows and macOS.
7 changes: 7 additions & 0 deletions debugger-support/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Briefcase Debugger Support
This package contains the debugger support package for the `pdb` and `debugpy` debuggers.

It starts the remote debugger automatically at startup through an .pth file, if a `BRIEFCASE_DEBUGGER` environment variable is set.

## Installation
Normally you do not need to install this package manually, because it is done automatically by briefcase using the `--debug=pdb` or `--debug=debugpy` option.
50 changes: 50 additions & 0 deletions debugger-support/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[build-system]
requires = [
# keep versions in sync with automation/pyproject.toml and ../pyproject.toml
"setuptools==80.9.0",
"setuptools_scm==8.3.1",
]
build-backend = "setuptools.build_meta"

[project]
name = "briefcase-debugger"
description = "Add-on for briefcase to add remote debugging."
readme = "README.md"
license = "BSD-3-Clause"
dependencies = [
# see "pdb" or "debugpy" optional dependencies below
]
dynamic = ["version"]

[tool.setuptools_scm]
root = "../"

[project.optional-dependencies]
dev = [
"pytest == 8.4.1",
"coverage[toml] == 7.10.2",
]
pdb = [
"remote-pdb>=2.1.0,<3.0.0"
]
debugpy = [
"debugpy>=1.8.14,<2.0.0"
]

[tool.coverage.run]
parallel = true
branch = true
relative_files = true
source_pkgs = ["briefcase_debugger"]

[tool.coverage.paths]
source = [
"src",
"**/site-packages",
]

[tool.coverage.report]
show_missing = true
skip_covered = true
skip_empty = true
precision = 1
42 changes: 42 additions & 0 deletions debugger-support/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import os

import setuptools
from setuptools.command.install import install


# Copied from setuptools:
# (https://github.com/pypa/setuptools/blob/7c859e017368360ba66c8cc591279d8964c031bc/setup.py#L40C6-L82)
class install_with_pth(install):
"""Custom install command to install a .pth file for distutils patching.
This hack is necessary because there's no standard way to install behavior
on startup (and it's debatable if there should be one). This hack (ab)uses
the `extra_path` behavior in Setuptools to install a `.pth` file with
implicit behavior on startup to give higher precedence to the local version
of `distutils` over the version from the standard library.
Please do not replicate this behavior.
"""

_pth_name = "briefcase_debugger"
_pth_contents = "import briefcase_debugger"

def initialize_options(self):
install.initialize_options(self)
self.extra_path = self._pth_name, self._pth_contents

def finalize_options(self):
install.finalize_options(self)
self._restore_install_lib()

def _restore_install_lib(self):
"""Undo secondary effect of `extra_path` adding to `install_lib`"""
suffix = os.path.relpath(self.install_lib, self.install_libbase)

if suffix.strip() == self._pth_contents.strip():
self.install_lib = self.install_libbase


setuptools.setup(
cmdclass={"install": install_with_pth},
)
47 changes: 47 additions & 0 deletions debugger-support/src/briefcase_debugger/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import json
import os
import sys
import traceback


def start_remote_debugger():
try:
# check verbose output
verbose = os.environ.get("BRIEFCASE_DEBUG", "0") == "1"

# reading config
config_str = os.environ.get("BRIEFCASE_DEBUGGER", None)

# skip debugger if no config is set
if config_str is None:
if verbose:
print(
"No 'BRIEFCASE_DEBUGGER' environment variable found. Debugger not starting."
)
return # If BRIEFCASE_DEBUGGER is not set, this packages does nothing...

if verbose:
print(f"'BRIEFCASE_DEBUGGER'={config_str}")

# Parsing config json
config = json.loads(config_str)

# start debugger
print("Starting remote debugger...")
if config["debugger"] == "debugpy":
from briefcase_debugger.debugpy import start_debugpy

start_debugpy(config, verbose)
elif config["debugger"] == "pdb":
from briefcase_debugger.pdb import start_pdb

start_pdb(config, verbose)
else:
raise ValueError(f"Unknown debugger '{config['debugger']}'")
except Exception:
# Show exception and stop the whole application when an error occurs
print(traceback.format_exc())
sys.exit(-1)


start_remote_debugger()
20 changes: 20 additions & 0 deletions debugger-support/src/briefcase_debugger/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import TypedDict


class AppPathMappings(TypedDict):
device_sys_path_regex: str
device_subfolders: list[str]
host_folders: list[str]


class AppPackagesPathMappings(TypedDict):
sys_path_regex: str
host_folder: str


class DebuggerConfig(TypedDict):
debugger: str
host: str
port: int
app_path_mappings: AppPathMappings | None
app_packages_path_mappings: AppPackagesPathMappings | None
116 changes: 116 additions & 0 deletions debugger-support/src/briefcase_debugger/debugpy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import os
import re
import sys
from pathlib import Path

import debugpy

from briefcase_debugger.config import DebuggerConfig


def find_first_matching_path(regex: str) -> str:
"""Returns the first element of sys.paths that matches regex, otherwise None."""
for p in sys.path:
if re.search(regex, p):
return p
raise ValueError(f"No sys.path entry matches regex '{regex}'")


def load_path_mappings(config: DebuggerConfig, verbose: bool) -> list[tuple[str, str]]:
app_path_mappings = config.get("app_path_mappings", None)
app_packages_path_mappings = config.get("app_packages_path_mappings", None)

mappings_list = []
if app_path_mappings:
device_app_folder = find_first_matching_path(
app_path_mappings["device_sys_path_regex"]
)
for app_subfolder_device, app_subfolder_host in zip(
app_path_mappings["device_subfolders"],
app_path_mappings["host_folders"],
strict=False,
):
mappings_list.append(
(
app_subfolder_host,
str(Path(device_app_folder) / app_subfolder_device),
)
)
if app_packages_path_mappings:
device_app_packages_folder = find_first_matching_path(
app_packages_path_mappings["sys_path_regex"]
)
mappings_list.append(
(
app_packages_path_mappings["host_folder"],
str(Path(device_app_packages_folder)),
)
)

if verbose:
print("Extracted path mappings:")
for idx, p in enumerate(mappings_list):
print(f"[{idx}] host = {p[0]}")
print(f"[{idx}] device = {p[1]}")

return mappings_list


def start_debugpy(config: DebuggerConfig, verbose: bool):
host = config["host"]
port = config["port"]
path_mappings = load_path_mappings(config, verbose)

# There is a bug in debugpy that has to be handled until there is a new
# debugpy release, see https://github.com/microsoft/debugpy/issues/1943
if not hasattr(os, "__file__"):
if verbose:
print("'os.__file__' not available. Patching it...")
os.__file__ = ""

# Starting remote debugger...
print(f"Starting debugpy in server mode at {host}:{port}...")
debugpy.listen((host, port), in_process_debug_adapter=True)

if verbose:
# pydevd is dynamically loaded and only available after debugpy is started
import pydevd

pydevd.DebugInfoHolder.DEBUG_TRACE_LEVEL = 3

if len(path_mappings) > 0:
if verbose:
print("Adding path mappings...")

# pydevd is dynamically loaded and only available after a debugger has connected
import pydevd_file_utils

pydevd_file_utils.setup_client_server_paths(path_mappings)

print("The debugpy server started. Waiting for debugger to attach...")
print(
f"""
To connect to debugpy using VSCode add the following configuration to '.vscode/launch.json':
{{
"version": "0.2.0",
"configurations": [
{{
"name": "Briefcase: Attach (Connect)",
"type": "debugpy",
"request": "attach",
"connect": {{
"host": "{host}",
"port": {port}
}},
"justMyCode": false
}}
]
}}
For more information see: https://briefcase.readthedocs.io/en/stable/how-to/debugging/vscode.html#bundled-app
"""
)
debugpy.wait_for_client()

print("Debugger attached.")
print("-" * 75)
33 changes: 33 additions & 0 deletions debugger-support/src/briefcase_debugger/pdb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import sys

from remote_pdb import RemotePdb

from briefcase_debugger.config import DebuggerConfig


def start_pdb(config: DebuggerConfig, verbose: bool):
"""Start remote PDB server."""
# Parsing host/port
host = config["host"]
port = config["port"]

print(
f"""
Remote PDB server opened at {host}:{port}.
Waiting for debugger to attach...
To connect to remote PDB use eg.:
- telnet {host} {port} (Windows)
- rlwrap socat - tcp:{host}:{port} (Linux, macOS)
For more information see: https://briefcase.readthedocs.io/en/stable/how-to/debugging/console.html#bundled-app
"""
)

# Create a RemotePdb instance
remote_pdb = RemotePdb(host, port, quiet=True)

# Connect the remote PDB with the "breakpoint()" function
sys.breakpointhook = remote_pdb.set_trace

print("Debugger client attached.")
print("-" * 75)
Loading
Loading