Coder Social home page Coder Social logo

cifkao / nopdb Goto Github PK

View Code? Open in Web Editor NEW
80.0 5.0 2.0 4.32 MB

NoPdb: Non-interactive Python Debugger

License: BSD 3-Clause "New" or "Revised" License

Python 100.00%
debugger python pdb programmatic developer-tools machine-learning function-hooks tracing intercept-calls debugging-tool debugging-tools

nopdb's Introduction

NoPdb: Non-interactive Python Debugger

PyPI Package Documentation Status Lint Status Lint Status

NoPdb is a programmatic (non-interactive) debugger for Python. This means it gives you access to debugger-like superpowers directly from your code. With NoPdb, you can:

  • capture function calls, including arguments, local variables, return values and stack traces
  • set "breakpoints" that trigger user-defined actions when hit, namely:
    • evaluate expressions to retrieve their values later
    • execute arbitrary code, including modifying local variables
    • enter an interactive debugger like pdb

NoPdb is also a convenient tool for inspecting machine learning model internals. For example, this notebook, this post on Towards Data Science and this notebook (SciPy 2022 virtual poster) show how to use it to visualize Transformer attention in PyTorch.

NoPdb should run at least under CPython and PyPy. Most features should work under any implementation as long as it has sys.settrace().

Note: This project is in its early development stage. Contributions and improvement ideas are welcome.

Capturing function calls

The functions capture_call() and capture_calls() allow capturing useful information about calls to a given function. They are typically used as context managers, e.g.:

with nopdb.capture_calls(fn) as calls:
    some_code_that_calls_fn()

    print(calls)  # see details about how fn() was called

The information we can retrieve includes the function's arguments, return value, local variables and stack trace. For example:

>>> with nopdb.capture_call(f) as call:
...     g(1)
>>> call
CallCapture(name='f', args=OrderedDict(x=1, y=1), return_value=4)
>>> call.print_stack()
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in g
  File "<stdin>", line 1, in f
>>> call.args['x']
1
>>> call.return_value
4
>>> call.locals
{'y': 1, 'x': 1, 'z': 2}

Setting breakpoints

Like conventional debuggers, NoPdb can set breakpoints. However, because NoPdb is a non-interactive debugger, its breakpoints do not actually stop the execution of the program. Instead, they allow executing actions scheduled in advance, such as evaluating expressions.

To set a breakpoint, call the breakpoint() function. A breakpoint object is returned, allowing to schedule actions using its methods such as eval() and exec(). For example:

# Break at line 3 of the file or notebook cell where f is defined
with nopdb.breakpoint(function=f, line=3) as bp:
    x = bp.eval("x")             # Schedule an expression
    type_y = bp.eval("type(y)")  # Another one
    bp.exec("print(y)")          # Schedule a print statement

    some_code_that_calls_f()

print(x, type_y)  # Retrieve the captured values

There are other ways to specify the breakpoint location. For example:

# Break at any line with the given source code in the given file
with nopdb.breakpoint(file="pathlib.py", line="return obj") as bp:
    ...

# Break as soon as any function with the given name is called
with nopdb.breakpoint(function="myfunc") as bp:
    ...

Not only can we capture values, we can also modify them!

>>> with nopdb.breakpoint(function=f, line=3) as bp:
...     # Get the value of x, then increment it, then get the new value
...     x_before = bp.eval('x')
...     bp.exec('x += 1')
...     x_after = bp.eval('x')
...
...     some_code_that_calls_f()
>>> x_before
[2]
>>> x_after
[3]

Planned features

Functionalities that do not exist, but could be added in the future:

  • Breakpoint.callback() for calling a given callback function, passing information about the current frame as an argument.
  • Breakpoint.jump() for jumping to a different line in the same function.

Limitations

  • Like Pdb, NoPdb only works with pure-Python functions. Calls to built-ins and C extensions cannot be captured. This also applies to ML frameworks that compile models into static graphs; for NoPdb to work, this feature needs to be disabled, e.g. with tf.config.run_functions_eagerly(True) in TensorFlow and with the jax.disable_jit() context manager in JAX.
  • Local variable assignment in Breakpoint.exec() is only supported under CPython and PyPy.

nopdb's People

Contributors

cifkao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

sthagen tpt-adasp

nopdb's Issues

Functionality questions

Thanks for making this project. A non-interactive python debugger is exactly what I'm looking for. I'd like to use your project to support the Python probe for Source++. I've been able to successfully implement some portions of the functionality, but I'm having some trouble understanding some Python debugging relating things. I think some of this trouble might be alleviated with new functionality for nopdb and I'm more than willing to implement that functionality. My background is with JVM languages so I'm just looking for a bit of guidance on how things work the Python way.

Breakpoint doesn't hit on Flask app

I don't think this issue is a nopdb issue as I'm unable to hit the breakpoint using import pdb; pdb.set_trace() in the main method either. I believe this issue is because of either compiled code within Flask or pdb is not hitting because of separate threads. Either way, I'm able to set breakpoints via PyCharm so it appears to be possible in some way. Hopefully, it's just a threading thing and breakpoints can be placed for every thread. Do you know how this functionality could be implemented with nopdb?

Here is some code that shows a breakpoint that's never hit:

import os

from flask import Flask
from nopdb import nopdb

app = Flask(__name__)


@app.route('/')
def hello():
    provider = str(os.environ.get('PROVIDER', 'world'))
    return 'Hello ' + provider + '!'


if __name__ == '__main__':
    with nopdb.breakpoint(file="FlaskTest.py", line=12) as bp:
        bp.exec("print(\"provider: \" + provider)")
        port = int(os.environ.get('PORT', 5000))
        app.run(host='0.0.0.0', port=port)

Ability to add breakpoints without calling code via context manager

This might be related to the issue above, but how do you add breakpoints to code that you don't want to call via the context manager? As in, code that is already running or that will run by itself sometime in the future? I have a small example here where I want to set a breakpoint before a function is called in the future via a delay. Can nopdb address this type of scenario?

Code which shows a breakpoint that's never hit:

import threading

from nopdb import nopdb


def fun():
    x = 5
    y = x


if __name__ == '__main__':
    start_time = threading.Timer(10, fun)
    start_time.start()

   # I'd like to set the breakpoint ahead of time and just output x once it's hit
    with nopdb.breakpoint(file="SeparateThread.py", line=8) as bp:
        bp.exec("print(\"x: \" + str(x))")

Does cpdb make sense to extend?

This might be a bit off-topic, but while looking into Python debuggers I ran across https://pypi.org/project/CPdb/. Does this project make sense to extend for nopdb? The reason I ask is because of the claim cpdb makes about "long-running" applications running better with it. I would like to use nopdb in "long-running" applications so I'm curious if it makes sense to integrate the technologies.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.