Skip to main content

Lightweight CPython Debugger

Project description


Dragonfly logo

Lightweight CPython Debugger

GitHub Actions: Tests GitHub Actions: Checks Codecov
PyPI Downloads
LICENSE

Synopsis • Installation • Usage • Compatibility • Documentation • Contribute • Credits

Buy Me A Coffee

Synopsis

Dragonfly is a lightweight CPython debugger designed with speed in mind. Contrary to more traditional debuggers, like pdb, Dragonfly does not rely heavily on tracing, allowing the target application to run at full speed in most cases. Occasionally, tracing might be required, so that the slowdown would be similar to that of pdb in the worst case.

Installation

This package can be installed from PyPI with

pip install --user dfly --upgrade

Usage

To debug a Python script or application, simply prefix the command with dfly. The built-in breakpoint() is replaced with Dragonfly's own implementation, so that you can set breakpoints in your code by simply adding breakpoint() where needed. Alternatively, if you are not using the dfly command, you can simply import dragonfly.bite before any calls to breakpoint to achieve the same effect.

Dragonfly is still in an early stage of development, so it is not yet feature complete. However, it is already usable for the most common debugging tasks, with some initial support for multi-threading.

If you find this tool useful, please consider starring the repository and/or becoming a Sponsor to support the development.

Compatibility

Dragonfly is tested on Linux and macOS with Python 3.8-3.12.

Why Dragonfly

The typical CPython debugger relies heavily, or even exclusively on tracing in their implementation. This technique is very powerful, but it has a few shortcomings:

  • high overhead - tracing is slow, and it can slow down the target application by a factor of 10 or more.

  • limited support for multithreading - supporting multithreading in a tracing-based debugger is difficult, especially in older versions of Python.

Some of these problems have been addressed in PEP 669. But whilst the cost of monitoring has been lowered, some impact still remains. Besides, PEP 669 is only available in Python 3.12 and later.

Dragonfly poses itself as a lightweight alternative to the traditional, and the PEP 669-based debuggers. At its core, Dragonfly uses bytecode transformation to implement traps. These can be injected where breakpoints are requested, and control is then passed to the prompt. When the targeted bytecode is already being executed, Dragonfly turns on tracing to ensure that any breakpoints can still be hit. In this case, the performance impact can be similar to that of tracing-based debuggers. However, this should normally be a transient situation, and the ammortised cost of debugging should be essentially negligible.

To make this clearer, let's look at a simple example. Consider the following code:

def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)


from time import monotonic as time

start = time()
fibonacci(30)
end = time()
print(end - start)

When we run this without any debuggers, the reported time is of the order of 0.1 seconds.

$ python3.12 -m tests.fib
0.11031840229406953

If we run this with pdb, without any breakpoints, the reported time is of the order of over 3 seconds:

$ python3.12 -m pdb -m tests.fib
> /tmp/fib.py(1)<module>()
-> def fibonacci(n):
(Pdb) r
3.2781156906858087
--Return--
> /tmp/fib.py(12)<module>()->None
-> print(end - start)
(Pdb) 

However, if we run it through Dragonfly, again without any breakpoints set, the reported time is essentially the same as without any debugger:

$ dfly -r python -m fib         
0.11001458810642362

Bytecode debugging

Dragonfly can also be used to debug CPython at the bytecode level. When setting trace-opcodes with set trace-opcodes 1, every stepping operation will be performed at the bytecode level. The disassemble command can be used to display the bytecode currently running, along with the values in the stack for the current frame.

Contribute

If you want to help with the development, then have a look at the open issues and have a look at the contributing guidelines before you open a pull request.

You can also contribute to the development by either becoming a Patron on Patreon, by buying me a coffee on BMC or by chipping in a few pennies on PayPal.Me.

Buy Me A Coffee

Credits

Artwork by Antea a.k.a. Aisling.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dfly-0.2.1.tar.gz (8.0 MB view hashes)

Uploaded Source

Built Distributions

dfly-0.2.1-cp312-cp312-musllinux_1_1_x86_64.whl (47.1 kB view hashes)

Uploaded CPython 3.12 musllinux: musl 1.1+ x86-64

dfly-0.2.1-cp312-cp312-musllinux_1_1_s390x.whl (46.9 kB view hashes)

Uploaded CPython 3.12 musllinux: musl 1.1+ s390x

dfly-0.2.1-cp312-cp312-musllinux_1_1_ppc64le.whl (48.0 kB view hashes)

Uploaded CPython 3.12 musllinux: musl 1.1+ ppc64le

dfly-0.2.1-cp312-cp312-musllinux_1_1_aarch64.whl (47.3 kB view hashes)

Uploaded CPython 3.12 musllinux: musl 1.1+ ARM64

dfly-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl (42.2 kB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ s390x

dfly-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (42.9 kB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ ppc64le

dfly-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (42.7 kB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ ARM64

dfly-0.2.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (42.1 kB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.5+ x86-64

dfly-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (41.7 kB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ i686 manylinux: glibc 2.5+ i686

dfly-0.2.1-cp312-cp312-macosx_11_0_arm64.whl (33.4 kB view hashes)

Uploaded CPython 3.12 macOS 11.0+ ARM64

dfly-0.2.1-cp312-cp312-macosx_10_9_x86_64.whl (33.1 kB view hashes)

Uploaded CPython 3.12 macOS 10.9+ x86-64

dfly-0.2.1-cp312-cp312-macosx_10_9_universal2.whl (35.5 kB view hashes)

Uploaded CPython 3.12 macOS 10.9+ universal2 (ARM64, x86-64)

dfly-0.2.1-cp311-cp311-musllinux_1_1_x86_64.whl (65.9 kB view hashes)

Uploaded CPython 3.11 musllinux: musl 1.1+ x86-64

dfly-0.2.1-cp311-cp311-musllinux_1_1_s390x.whl (65.4 kB view hashes)

Uploaded CPython 3.11 musllinux: musl 1.1+ s390x

dfly-0.2.1-cp311-cp311-musllinux_1_1_ppc64le.whl (67.1 kB view hashes)

Uploaded CPython 3.11 musllinux: musl 1.1+ ppc64le

dfly-0.2.1-cp311-cp311-musllinux_1_1_aarch64.whl (66.2 kB view hashes)

Uploaded CPython 3.11 musllinux: musl 1.1+ ARM64

dfly-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl (61.7 kB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ s390x

dfly-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (63.2 kB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ ppc64le

dfly-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (62.7 kB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ ARM64

dfly-0.2.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (62.2 kB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.5+ x86-64

dfly-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (61.8 kB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ i686 manylinux: glibc 2.5+ i686

dfly-0.2.1-cp311-cp311-macosx_11_0_arm64.whl (33.8 kB view hashes)

Uploaded CPython 3.11 macOS 11.0+ ARM64

dfly-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl (33.5 kB view hashes)

Uploaded CPython 3.11 macOS 10.9+ x86-64

dfly-0.2.1-cp311-cp311-macosx_10_9_universal2.whl (36.4 kB view hashes)

Uploaded CPython 3.11 macOS 10.9+ universal2 (ARM64, x86-64)

dfly-0.2.1-cp310-cp310-musllinux_1_1_x86_64.whl (48.3 kB view hashes)

Uploaded CPython 3.10 musllinux: musl 1.1+ x86-64

dfly-0.2.1-cp310-cp310-musllinux_1_1_s390x.whl (48.1 kB view hashes)

Uploaded CPython 3.10 musllinux: musl 1.1+ s390x

dfly-0.2.1-cp310-cp310-musllinux_1_1_ppc64le.whl (49.5 kB view hashes)

Uploaded CPython 3.10 musllinux: musl 1.1+ ppc64le

dfly-0.2.1-cp310-cp310-musllinux_1_1_aarch64.whl (48.5 kB view hashes)

Uploaded CPython 3.10 musllinux: musl 1.1+ ARM64

dfly-0.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl (44.7 kB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ s390x

dfly-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (45.8 kB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ ppc64le

dfly-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (45.4 kB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ ARM64

dfly-0.2.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (44.8 kB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.5+ x86-64

dfly-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (44.4 kB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ i686 manylinux: glibc 2.5+ i686

dfly-0.2.1-cp310-cp310-macosx_11_0_arm64.whl (33.8 kB view hashes)

Uploaded CPython 3.10 macOS 11.0+ ARM64

dfly-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl (33.5 kB view hashes)

Uploaded CPython 3.10 macOS 10.9+ x86-64

dfly-0.2.1-cp310-cp310-macosx_10_9_universal2.whl (36.3 kB view hashes)

Uploaded CPython 3.10 macOS 10.9+ universal2 (ARM64, x86-64)

dfly-0.2.1-cp39-cp39-musllinux_1_1_x86_64.whl (48.0 kB view hashes)

Uploaded CPython 3.9 musllinux: musl 1.1+ x86-64

dfly-0.2.1-cp39-cp39-musllinux_1_1_s390x.whl (47.8 kB view hashes)

Uploaded CPython 3.9 musllinux: musl 1.1+ s390x

dfly-0.2.1-cp39-cp39-musllinux_1_1_ppc64le.whl (49.2 kB view hashes)

Uploaded CPython 3.9 musllinux: musl 1.1+ ppc64le

dfly-0.2.1-cp39-cp39-musllinux_1_1_aarch64.whl (48.2 kB view hashes)

Uploaded CPython 3.9 musllinux: musl 1.1+ ARM64

dfly-0.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl (44.4 kB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ s390x

dfly-0.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (45.5 kB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ ppc64le

dfly-0.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (45.0 kB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ ARM64

dfly-0.2.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (44.4 kB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.5+ x86-64

dfly-0.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (44.0 kB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ i686 manylinux: glibc 2.5+ i686

dfly-0.2.1-cp39-cp39-macosx_11_0_arm64.whl (33.8 kB view hashes)

Uploaded CPython 3.9 macOS 11.0+ ARM64

dfly-0.2.1-cp39-cp39-macosx_10_9_x86_64.whl (33.5 kB view hashes)

Uploaded CPython 3.9 macOS 10.9+ x86-64

dfly-0.2.1-cp39-cp39-macosx_10_9_universal2.whl (36.3 kB view hashes)

Uploaded CPython 3.9 macOS 10.9+ universal2 (ARM64, x86-64)

dfly-0.2.1-cp38-cp38-musllinux_1_1_x86_64.whl (51.9 kB view hashes)

Uploaded CPython 3.8 musllinux: musl 1.1+ x86-64

dfly-0.2.1-cp38-cp38-musllinux_1_1_s390x.whl (51.8 kB view hashes)

Uploaded CPython 3.8 musllinux: musl 1.1+ s390x

dfly-0.2.1-cp38-cp38-musllinux_1_1_ppc64le.whl (53.2 kB view hashes)

Uploaded CPython 3.8 musllinux: musl 1.1+ ppc64le

dfly-0.2.1-cp38-cp38-musllinux_1_1_aarch64.whl (52.2 kB view hashes)

Uploaded CPython 3.8 musllinux: musl 1.1+ ARM64

dfly-0.2.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl (48.5 kB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ s390x

dfly-0.2.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (49.7 kB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ ppc64le

dfly-0.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (49.2 kB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ ARM64

dfly-0.2.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (48.5 kB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.5+ x86-64

dfly-0.2.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (48.1 kB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ i686 manylinux: glibc 2.5+ i686

dfly-0.2.1-cp38-cp38-macosx_11_0_arm64.whl (33.9 kB view hashes)

Uploaded CPython 3.8 macOS 11.0+ ARM64

dfly-0.2.1-cp38-cp38-macosx_10_9_x86_64.whl (33.6 kB view hashes)

Uploaded CPython 3.8 macOS 10.9+ x86-64

dfly-0.2.1-cp38-cp38-macosx_10_9_universal2.whl (36.6 kB view hashes)

Uploaded CPython 3.8 macOS 10.9+ universal2 (ARM64, x86-64)

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page