Hunter is a flexible code tracing toolkit.

Overview

Overview

docs Documentation Status
tests
Travis-CI Build Status AppVeyor Build Status Requirements Status
Coverage Status
package

Hunter is a flexible code tracing toolkit, not for measuring coverage, but for debugging, logging, inspection and other nefarious purposes. It has a simple Python API, a convenient terminal API and a CLI tool to attach to processes.

  • Free software: BSD 2-Clause License

Installation

pip install hunter

Documentation

https://python-hunter.readthedocs.io/

Overview

Basic use involves passing various filters to the trace option. An example:

import hunter
hunter.trace(module='posixpath', action=hunter.CallPrinter)

import os
os.path.join('a', 'b')

That would result in:

>>> os.path.join('a', 'b')
         /usr/lib/python3.6/posixpath.py:75    call      => join(a='a')
         /usr/lib/python3.6/posixpath.py:80    line         a = os.fspath(a)
         /usr/lib/python3.6/posixpath.py:81    line         sep = _get_sep(a)
         /usr/lib/python3.6/posixpath.py:41    call         => _get_sep(path='a')
         /usr/lib/python3.6/posixpath.py:42    line            if isinstance(path, bytes):
         /usr/lib/python3.6/posixpath.py:45    line            return '/'
         /usr/lib/python3.6/posixpath.py:45    return       <= _get_sep: '/'
         /usr/lib/python3.6/posixpath.py:82    line         path = a
         /usr/lib/python3.6/posixpath.py:83    line         try:
         /usr/lib/python3.6/posixpath.py:84    line         if not p:
         /usr/lib/python3.6/posixpath.py:86    line         for b in map(os.fspath, p):
         /usr/lib/python3.6/posixpath.py:87    line         if b.startswith(sep):
         /usr/lib/python3.6/posixpath.py:89    line         elif not path or path.endswith(sep):
         /usr/lib/python3.6/posixpath.py:92    line         path += sep + b
         /usr/lib/python3.6/posixpath.py:86    line         for b in map(os.fspath, p):
         /usr/lib/python3.6/posixpath.py:96    line         return path
         /usr/lib/python3.6/posixpath.py:96    return    <= join: 'a/b'
'a/b'

In a terminal it would look like:

https://raw.githubusercontent.com/ionelmc/python-hunter/master/docs/code-trace.png

Actions

Output format can be controlled with "actions". There's an alternative CodePrinter action that doesn't handle nesting (it was the default action until Hunter 2.0).

If filters match then action will be run. Example:

import hunter
hunter.trace(module='posixpath', action=hunter.CodePrinter)

import os
os.path.join('a', 'b')

That would result in:

>>> os.path.join('a', 'b')
         /usr/lib/python3.6/posixpath.py:75    call      def join(a, *p):
         /usr/lib/python3.6/posixpath.py:80    line          a = os.fspath(a)
         /usr/lib/python3.6/posixpath.py:81    line          sep = _get_sep(a)
         /usr/lib/python3.6/posixpath.py:41    call      def _get_sep(path):
         /usr/lib/python3.6/posixpath.py:42    line          if isinstance(path, bytes):
         /usr/lib/python3.6/posixpath.py:45    line              return '/'
         /usr/lib/python3.6/posixpath.py:45    return            return '/'
                                               ...       return value: '/'
         /usr/lib/python3.6/posixpath.py:82    line          path = a
         /usr/lib/python3.6/posixpath.py:83    line          try:
         /usr/lib/python3.6/posixpath.py:84    line              if not p:
         /usr/lib/python3.6/posixpath.py:86    line              for b in map(os.fspath, p):
         /usr/lib/python3.6/posixpath.py:87    line                  if b.startswith(sep):
         /usr/lib/python3.6/posixpath.py:89    line                  elif not path or path.endswith(sep):
         /usr/lib/python3.6/posixpath.py:92    line                      path += sep + b
         /usr/lib/python3.6/posixpath.py:86    line              for b in map(os.fspath, p):
         /usr/lib/python3.6/posixpath.py:96    line          return path
         /usr/lib/python3.6/posixpath.py:96    return        return path
                                               ...       return value: 'a/b'
'a/b'
  • or in a terminal:

https://raw.githubusercontent.com/ionelmc/python-hunter/master/docs/simple-trace.png


Another useful action is the VarsPrinter:

import hunter
# note that this kind of invocation will also use the default `CallPrinter` action
hunter.trace(hunter.Q(module='posixpath', action=hunter.VarsPrinter('path')))

import os
os.path.join('a', 'b')

That would result in:

>>> os.path.join('a', 'b')
     /usr/lib/python3.6/posixpath.py:75    call      => join(a='a')
     /usr/lib/python3.6/posixpath.py:80    line         a = os.fspath(a)
     /usr/lib/python3.6/posixpath.py:81    line         sep = _get_sep(a)
     /usr/lib/python3.6/posixpath.py:41    call      [path => 'a']
     /usr/lib/python3.6/posixpath.py:41    call         => _get_sep(path='a')
     /usr/lib/python3.6/posixpath.py:42    line      [path => 'a']
     /usr/lib/python3.6/posixpath.py:42    line            if isinstance(path, bytes):
     /usr/lib/python3.6/posixpath.py:45    line      [path => 'a']
     /usr/lib/python3.6/posixpath.py:45    line            return '/'
     /usr/lib/python3.6/posixpath.py:45    return    [path => 'a']
     /usr/lib/python3.6/posixpath.py:45    return       <= _get_sep: '/'
     /usr/lib/python3.6/posixpath.py:82    line         path = a
     /usr/lib/python3.6/posixpath.py:83    line      [path => 'a']
     /usr/lib/python3.6/posixpath.py:83    line         try:
     /usr/lib/python3.6/posixpath.py:84    line      [path => 'a']
     /usr/lib/python3.6/posixpath.py:84    line         if not p:
     /usr/lib/python3.6/posixpath.py:86    line      [path => 'a']
     /usr/lib/python3.6/posixpath.py:86    line         for b in map(os.fspath, p):
     /usr/lib/python3.6/posixpath.py:87    line      [path => 'a']
     /usr/lib/python3.6/posixpath.py:87    line         if b.startswith(sep):
     /usr/lib/python3.6/posixpath.py:89    line      [path => 'a']
     /usr/lib/python3.6/posixpath.py:89    line         elif not path or path.endswith(sep):
     /usr/lib/python3.6/posixpath.py:92    line      [path => 'a']
     /usr/lib/python3.6/posixpath.py:92    line         path += sep + b
     /usr/lib/python3.6/posixpath.py:86    line      [path => 'a/b']
     /usr/lib/python3.6/posixpath.py:86    line         for b in map(os.fspath, p):
     /usr/lib/python3.6/posixpath.py:96    line      [path => 'a/b']
     /usr/lib/python3.6/posixpath.py:96    line         return path
     /usr/lib/python3.6/posixpath.py:96    return    [path => 'a/b']
     /usr/lib/python3.6/posixpath.py:96    return    <= join: 'a/b'
'a/b'

In a terminal it would look like:

https://raw.githubusercontent.com/ionelmc/python-hunter/master/docs/vars-trace.png


You can give it a tree-like configuration where you can optionally configure specific actions for parts of the tree (like dumping variables or a pdb set_trace):

from hunter import trace, Q, Debugger
from pdb import Pdb

trace(
    # drop into a Pdb session if ``foo.bar()`` is called
    Q(module="foo", function="bar", kind="call", action=Debugger(klass=Pdb))
    |  # or
    Q(
        # show code that contains "mumbo.jumbo" on the current line
        lambda event: event.locals.get("mumbo") == "jumbo",
        # and it's not in Python's stdlib
        stdlib=False,
        # and it contains "mumbo" on the current line
        source__contains="mumbo"
    )
)

import foo
foo.func()

With a foo.py like this:

def bar():
    execution_will_get_stopped  # cause we get a Pdb session here

def func():
    mumbo = 1
    mumbo = "jumbo"
    print("not shown in trace")
    print(mumbo)
    mumbo = 2
    print(mumbo) # not shown in trace
    bar()

We get:

>>> foo.func()
not shown in trace
    /home/ionel/osp/python-hunter/foo.py:8     line          print(mumbo)
jumbo
    /home/ionel/osp/python-hunter/foo.py:9     line          mumbo = 2
2
    /home/ionel/osp/python-hunter/foo.py:1     call      def bar():
> /home/ionel/osp/python-hunter/foo.py(2)bar()
-> execution_will_get_stopped  # cause we get a Pdb session here
(Pdb)

In a terminal it would look like:

https://raw.githubusercontent.com/ionelmc/python-hunter/master/docs/tree-trace.png

Tracing processes

In similar fashion to strace Hunter can trace other processes, eg:

hunter-trace --gdb -p 123

If you wanna play it safe (no messy GDB) then add this in your code:

from hunter import remote
remote.install()

Then you can do:

hunter-trace -p 123

See docs on the remote feature.

Note: Windows ain't supported.

Environment variable activation

For your convenience environment variable activation is available. Just run your app like this:

PYTHONHUNTER="module='os.path'" python yourapp.py

On Windows you'd do something like:

set PYTHONHUNTER=module='os.path'
python yourapp.py

The activation works with a clever .pth file that checks for that env var presence and before your app runs does something like this:

from hunter import *
trace(<whatever-you-had-in-the-PYTHONHUNTER-env-var>)

Note that Hunter is activated even if the env var is empty, eg: PYTHONHUNTER="".

Environment variable configuration

Sometimes you always use the same options (like stdlib=False or force_colors=True). To save typing you can set something like this in your environment:

PYTHONHUNTERCONFIG="stdlib=False,force_colors=True"

This is the same as PYTHONHUNTER="stdlib=False,action=CallPrinter(force_colors=True)".

Notes:

  • Setting PYTHONHUNTERCONFIG alone doesn't activate hunter.

  • All the options for the builtin actions are supported.

  • Although using predicates is supported it can be problematic. Example of setup that won't trace anything:

    PYTHONHUNTERCONFIG="Q(module_startswith='django')"
    PYTHONHUNTER="Q(module_startswith='celery')"
    

    which is the equivalent of:

    PYTHONHUNTER="Q(module_startswith='django'),Q(module_startswith='celery')"
    

    which is the equivalent of:

    PYTHONHUNTER="Q(module_startswith='django')&Q(module_startswith='celery')"
    

Filtering DSL

Hunter supports a flexible query DSL, see the introduction.

Development

To run the all tests run:

tox

Design notes

Hunter doesn't do everything. As a design goal of this library some things are made intentionally austere and verbose (to avoid complexity, confusion and inconsistency). This has few consequences:

  • There are Operators but there's no negation operator. Instead you're expected to negate a Query object, eg: ~Q(module='re').
  • There are no specialized operators or filters - all filters behave exactly the same. For example:
    • No filter for packages. You're expected to filter by module with an operator.
    • No filter for arguments, return values or variables. You're expected to write your own filter function and deal with the problems of poking into objects.
  • Layering is minimal. There's are some helpers that do some argument processing and conversions to save you some typing but that's about it.
  • The library doesn't try to hide the mechanics of tracing in Python - it's 1:1 regarding what Python sends to a trace function if you'd be using sys.settrace.
  • Doesn't have any storage. You are expected to redirect output to a file.

You should look at it like it's a tool to help you understand and debug big applications, or a framework ridding you of the boring parts of settrace, not something that helps you learn Python.

FAQ

Why not Smiley?

There's some obvious overlap with smiley but there are few fundamental differences:

  • Complexity. Smiley is simply over-engineered:

    • It uses IPC and a SQL database.
    • It has a webserver. Lots of dependencies.
    • It uses threads. Side-effects and subtle bugs are introduced in your code.
    • It records everything. Tries to dump any variable. Often fails and stops working.

    Why do you need all that just to debug some stuff in a terminal? Simply put, it's a nice idea but the design choices work against you when you're already neck-deep into debugging your own code. In my experience Smiley has been very buggy and unreliable. Your mileage may vary of course.

  • Tracing long running code. This will make Smiley record lots of data, making it unusable.

    Now because Smiley records everything, you'd think it's better suited for short programs. But alas, if your program runs quickly then it's pointless to record the execution. You can just run it again.

    It seems there's only one situation where it's reasonable to use Smiley: tracing io-bound apps remotely. Those apps don't execute lots of code, they just wait on network so Smiley's storage won't blow out of proportion and tracing overhead might be acceptable.

  • Use-cases. It seems to me Smiley's purpose is not really debugging code, but more of a "non interactive monitoring" tool.

In contrast, Hunter is very simple:

  • Few dependencies.

  • Low overhead (tracing/filtering code has an optional Cython extension).

  • No storage. This simplifies lots of things.

    The only cost is that you might need to run the code multiple times to get the filtering/actions right. This means Hunter is not really suited for "post-mortem" debugging. If you can't reproduce the problem anymore then Hunter won't be of much help.

Why not pytrace?

Pytrace is another tracer tool. It seems quite similar to Smiley - it uses a sqlite database for the events, threads and IPC, thus it's reasonable to expect the same kind of problems.

Why not PySnooper or snoop?

snoop is a refined version of PySnooper. Both are more suited to tracing small programs or functions as the output is more verbose and less suited to the needs of tracing a big application where Hunter provides more flexible setup, filtering capabilities, speed and brevity.

Why not coverage?

For purposes of debugging coverage is a great tool but only as far as "debugging by looking at what code is (not) run". Checking branch coverage is good but it will only get you as far.

From the other perspective, you'd be wondering if you could use Hunter to measure coverage-like things. You could do it but for that purpose Hunter is very "rough": it has no builtin storage. You'd have to implement your own storage. You can do it but it wouldn't give you any advantage over making your own tracer if you don't need to "pre-filter" whatever you're recording.

In other words, filtering events is the main selling point of Hunter - it's fast (cython implementation) and the query API is flexible enough.

Comments
  • Hunter in long-running processes

    Hunter in long-running processes

    I've got a remote Python (3.5+) app that spawns (and re-spawns if need be) a half-dozen or so child processes. The processes interact tightly with each other thru zmq, so breaking into a running process with RemotePdb is problematic.

    I've got good logging and most of the time that's sufficient to deduce the problem when something goes wrong. For the times when that's not enough, I'm thinking Hunter might be the answer. So here's what I'd like to be able to do:

    • Shell into the remote,
    • Run a bash command to activate hunter in one of my processes.
    • View the trace in stdout (or possibly redirect to a file)
    • Conveniently stop hunter (without killing the process) when I've seen enough.

    The easy bits are:

    1. Import hunter in each process's modules.
    2. Add a USER2 signal handler that toggles hunter.trace/stop

    I'm less clear about how to pass the module and filtering arguments to hunter.

    Any help appreciated! Mike

    opened by Michael-F-Ellis 13
  • Trace `traceback`

    Trace `traceback`

    When an exception is triggered and a Traceback is generated, hunter does not show the calls traceback makes (eg, it shows the opening of the files traceback does to get the lines needed, but does not show what called the open). This normally is not what someone wants, but I've run into the scenario where I need to specifically see what traceback is doing. To be fair, I'm not even sure this is possible --- I don't know whether Python exposes the module.

    opened by DUOLabs333 8
  • Types supported by `safe_repr`

    Types supported by `safe_repr`

    I was wondering what the scope limitations for safe_repr is?

    Often I run into issues with builtin data types that are not rendered in a usable fashion and if having support for that falls within the scope of safe_repr or if the project's opinion is that repr_func should be used.

    Clearly arbitrary and user defined objects should be handled by a repr func but does python builtins also fall in that category?

    opened by GertBurger 8
  • Is it possible to set the depth of tracing and store the execution time of called functions?

    Is it possible to set the depth of tracing and store the execution time of called functions?

    Hi! Great tool! Many thanks!

    I tried to use hunter to dive into the xonsh shell. The code is complex and I want to asking an advice.

    Is there a way to restrict the depth and add time of execution for a functions/constructors?

    For example we have:

    def a():
        time.sleep(2)
        b = 1
    c = 1
    a()
    

    In trace with depth=1 we have:

    c = 1
    a() # 2 sec
    

    In trace with depth=2 we have:

    c = 1
    a()
        time.sleep(2)  # 2 sec
        b=1
    # end a() - 2 sec
    

    The depth could allow to go from whole to the details.

    Is it possible?

    Thanks!

    PS: Meanwhile if you have another advice how to deep dive into the complex code with tracing please feel free to share!

    opened by anki-code 6
  • Flask app failing with

    Flask app failing with "list index out of range" in Python 2.7

    Python Hunter version: 3.2.2 Python Version : 2.7

    When trying a simple Todo Flask app (The code is from https://github.com/mikicaivosevic/flask-simple-todo.git) and running hunter on it (Tried with both hunter-trace and setting env variables), it errors with a

    Traceback (most recent call last):
      File "/Users/raja/projects/virtualenvs/test/lib/python2.7/site-packages/hunter/tracer.py", line 83, in __call__
        self._handler(Event(frame, kind, arg, self))
      File "/Users/raja/projects/virtualenvs/test/lib/python2.7/site-packages/hunter/predicates.py", line 303, in __call__
        action(event)
      File "/Users/raja/projects/virtualenvs/test/lib/python2.7/site-packages/hunter/actions.py", line 483, in __call__
        ) for prefix, var in get_arguments(code)),
      File "/Users/raja/projects/virtualenvs/test/lib/python2.7/site-packages/hunter/actions.py", line 478, in <genexpr>
        ', '.join('{VARS}{0}{VARS-NAME}{1}{VARS}={RESET}{2}'.format(
      File "/Users/raja/projects/virtualenvs/test/lib/python2.7/site-packages/hunter/util.py", line 121, in get_arguments
        arguments = getargs(code)
      File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 800, in getargs
        args[i] = stack[0]
    IndexError: list index out of range
    Disabling tracer because handler When(Query(), CallPrinter(stream=<hunter.vendor.colorama.ansitowin32.AnsiToWin32 object at 0x106be4f10>, force_colors=False, filename_alignment=40, thread_alignment=12, pid_alignment=9 repr_limit=1024, repr_func=<function safe_repr at 0x106af71b8>)) failed (IndexError('list index out of range',)).
    

    Investigating it a bit, it comes from the werkezeug code = compile(module, "<werkzeug routing>", "exec") (https://github.com/pallets/werkzeug/blob/master/src/werkzeug/routing.py#L1069)

    Not sure if its because of the compile from code that its causing a problem in that the inspect.py is not able to get the stack.

    Running the same on Python3 seems to be fine because it looks like inspect isnt used if its Python3 (https://github.com/ionelmc/python-hunter/blob/master/src/hunter/util.py#L101). It worked fine on Python 3 though.

    opened by rajasaur 6
  • Environment variable activation not working: ModuleNotFoundError

    Environment variable activation not working: ModuleNotFoundError

    I'm on arch linux, python 3.6.3, hunter intalled in user directory: pip install --user -U hunter

    Environment variable activation does not work and gives a error message:

    $ PYTHONHUNTER='stdlib=False' python my_script.py
    Failed to load hunter conf 'stdlib=False': ModuleNotFoundError("No module named 'colorama'",)
    

    But I can import colorama normally from python prompt. Manually using hunter in python prompt seems to work, too.

    opened by kawing-chiu 6
  • Hunter doesn't work when using py.io

    Hunter doesn't work when using py.io

    When referencing py.io.TerminalWriter (probably other attributes as well), an exception is raised only when hunter is in use. Example:

    import py.io
    
    py.io.TerminalWriter
    
    test -d .venv || python3 -m venv .venv
    . .venv/bin/activate
    pip install py==1.8.0 hunter==2.2.1
    echo '
    import py.io
    
    py.io.TerminalWriter
    ' > test.py
    python test.py
    

    No exception should appear.

    When running with hunter, like

    PYTHONHUNTER='stdlib=False, action=CallPrinter(stream=open("hunter.log", "w", encoding="utf-8"))' python test.py
    

    the following exception occurs:

    Traceback (most recent call last):
      File ".venv/lib/python3.7/site-packages/py/_vendored_packages/apipkg.py", line 141, in __makeattr
        modpath, attrname = self.__map__[name]
    KeyError: 'TerminalWriter'
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "test.py", line 4, in <module>
        py.io.TerminalWriter
      File ".venv/lib/python3.7/site-packages/py/_vendored_packages/apipkg.py", line 146, in __makeattr
        raise AttributeError(name)
    AttributeError: TerminalWriter
    

    The exception does not occur if we omit stdlib=False.

    The exception does not occur when excluding the py._vendored_packages.apipkg, like:

    PYTHONHUNTER='Q(stdlib=False) & ~Q(module="py._vendored_packages.apipkg"), action=CallPrinter(stream=open("hunter.log", "w", encoding="utf-8"))' python test.py
    

    Doing some debugging around the area in apipkg it looks like the act of introspecting happens at a time that causes the exception to be raised. Maybe the method is not re-entrant, but the printing would require it to be?

    In case there's a fundamental issue that can't be solved, adding documentation to call this out as a limitation would be good.

    Additionally, we could use some documentation on what to watch out for when debugging hunter-related issues. Even basic debugging (e.g. breakpoint(), pdb, intentionally raising exceptions, logging) gives confusing feedback - messages logged at the top of __makeattr are printed twice but unconditional exceptions only visibly raised once, same with breakpoints.

    opened by chrahunt 5
  • `hunter.Event.filename` may be relative

    `hunter.Event.filename` may be relative

    The docs of hunter.Event.filename state that it returns an absolute path

    https://github.com/ionelmc/python-hunter/blob/b3a1310b0593d2c6b6ef430883843896e17d6a81/src/hunter/event.py#L178

    That is not true in all cases.

    Environment

    $ python -V
    Python 3.7.1
    $ pip freeze | grep hunter
    hunter==2.2.1
    $ echo "print(__file__)" > test.py
    $ python test.py
    test.py
    

    Test

    $ PYTHONHUNTER="filename='$PWD/test.py'"  python test.py
    test.py
    $ PYTHONHUNTER="filename='test.py'"  python test.py
                                     test.py:1     call      => <module>()
                                     test.py:1     line         print(__file__)
    test.py
                                     test.py:1     return    <= <module>: None
    

    The expected behavior would be for $PWD/test.py to match and output to be generated - but instead it only works when providing a relative path.

    opened by chrahunt 5
  • Walkthrough of unfamiliar module

    Walkthrough of unfamiliar module

    A cookbook example that would for a given module name create the report of all module's function calls including all argument names plus corresponding argument's and function's return values.

    A real use-case: A newb (me) is for the first time looking at a module/script mkosi. There is a lot of options that would produce different results. Hopefully there are some sensible defaults. I would like to start with a walkthrough and see how it works. Here is an example of accomplishing this task using pytrace:

    ...si/mkosi     --> <module>()
    ...si/mkosi      <-- <module>(exception = ImportError: ImportError("No module named 'argcomplete'",))
    ...si/mkosi      --> OutputFormat()
    ...si/mkosi      <-- OutputFormat(return value = NoneType: None)
    ...si/mkosi      --> Distribution()
    ...si/mkosi      <-- Distribution(return value = NoneType: None)
    ...si/mkosi      --> PackageAction()
    ...si/mkosi      <-- PackageAction(return value = NoneType: None)
    ...si/mkosi      --> main()
    ...si/mkosi       --> load_args()
    ...si/mkosi        --> parse_args()
    ...si/mkosi         <-- parse_args(exception = NameError: NameError("name 'argcomplete' is not defined",))
    ...si/mkosi        <-- parse_args(return value = Namespace: Namespace(bootable=None, build_dir=None, build_packages=None, build_script=None, build_sources=None, cache_path=None, checksum=False, cmdline=[], compress=False, default_path=None,
                 directory=None, distribution='centos', encrypt=None, esp_size=None, extra_trees=None, force_count=0, git_files=None, home_size=None, hostname=None, incremental=False, kernel_commandline=None, key=None, mirror=None,
                 nspawn_settings=None, output=None, output_format=None, packages=None, password=None, postinst_script=None, read_only=False, release=None, repositories=None, root_size=None, secure_boot=False, secure_boot_certificate=None,
                 secure_boot_key=None, sign=False, srv_size=None, swap_size=None, use_git_files=None, verb='build', verity=False, with_docs=False, with_network=False, with_tests=True, xz=False))
    ...si/mkosi        --> load_defaults(args = Namespace: Namespace(bootable=None, build_dir=None, build_packages=None, build_script=None, build_sources=None, cache_path=None, checksum=False, cmdline=[], compress=False, default_path=None,
                 directory=None, distribution='centos', encrypt=None, esp_size=None, extra_trees=None, force_count=0, git_files=None, home_size=None, hostname=None, incremental=False, kernel_commandline=None, key=None, mirror=None,
                 nspawn_settings=None, output=None, output_format=None, packages=None, password=None, postinst_script=None, read_only=False, release=None, repositories=None, root_size=None, secure_boot=False, secure_boot_certificate=None,
                 secure_boot_key=None, sign=False, srv_size=None, swap_size=None, use_git_files=None, verb='build', verity=False, with_docs=False, with_network=False, with_tests=True, xz=False))
    ...si/mkosi         --> load_defaults_file(fname = str: 'mkosi.default', options = dict: {})
    ...si/mkosi          <-- load_defaults_file(exception = FileNotFoundError: FileNotFoundError(2, 'No such file or directory'))
    ...si/mkosi         <-- load_defaults_file(return value = NoneType: None)
    ...si/mkosi        <-- load_defaults(return value = NoneType: None)
    ...si/mkosi        --> find_nspawn_settings(args = Namespace: Namespace(bootable=None, build_dir=None, build_packages=None, build_script=None, build_sources=None, cache_path=None, checksum=False, cmdline=[], compress=False, default_path=None,
                 directory=None, distribution='centos', encrypt=None, esp_size=None, extra_trees=None, force_count=0, git_files=None, home_size=None, hostname=None, incremental=False, kernel_commandline=None, key=None, mirror=None,
                 nspawn_settings=None, output=None, output_format=None, packages=None, password=None, postinst_script=None, read_only=False, release=None, repositories=None, root_size=None, secure_boot=False, secure_boot_certificate=None,
                 secure_boot_key=None, sign=False, srv_size=None, swap_size=None, use_git_files=None, verb='build', verity=False, with_docs=False, with_network=False, with_tests=True, xz=False))
    ...si/mkosi        <-- find_nspawn_settings(return value = NoneType: None)
    ...si/mkosi        --> find_extra(args = Namespace: Namespace(bootable=None, build_dir=None, build_packages=None, build_script=None, build_sources=None, cache_path=None, checksum=False, cmdline=[], compress=False, default_path=None,
                 directory=None, distribution='centos', encrypt=None, esp_size=None, extra_trees=None, force_count=0, git_files=None, home_size=None, hostname=None, incremental=False, kernel_commandline=None, key=None, mirror=None,
                 nspawn_settings=None, output=None, output_format=None, packages=None, password=None, postinst_script=None, read_only=False, release=None, repositories=None, root_size=None, secure_boot=False, secure_boot_certificate=None,
                 secure_boot_key=None, sign=False, srv_size=None, swap_size=None, use_git_files=None, verb='build', verity=False, with_docs=False, with_network=False, with_tests=True, xz=False))
    ...si/mkosi        <-- find_extra(return value = NoneType: None)
    
    opened by nadrimajstor 5
  • WIP: Add datetime, decimal and re to allowed modules list for safe_repr

    WIP: Add datetime, decimal and re to allowed modules list for safe_repr

    RE Issue #83

    Thought I'd create this as a PoC initially before taking it any further, comments are welcome.

    I had a look through the source code of these modules:

    • datetime seems pretty safe but there is a chance that a rogue tzinfo implementation can do weird things. The builtin ones are fine, as well as timezones created by pytz.
    • decimal: checked both _decimal and _pydecimal. looks clear.
    • re: also looks clear but its quite tricky to confirm, there are a lot of modules at play.
    opened by GertBurger 4
  • Calling repr() on objects may affect execution flow

    Calling repr() on objects may affect execution flow

    Here is a reproducible example: https://gist.github.com/borman/f4b347e87ee3a528c6ac94285084293b

    You can see a diff in the execution trace between two runs. Execution flow diverges after client_reqrep.py:875: https://gist.github.com/borman/f4b347e87ee3a528c6ac94285084293b/revisions?diff=unified#diff-3c628d58096772043814ea5c7b40f0b0

    The reason for this behaviour is:

    1. aiohttp authors implemented cached properties (thus reading their value actually mutates the object): https://github.com/aio-libs/aiohttp/blob/master/aiohttp/client_reqrep.py#L685-L687 https://github.com/aio-libs/aiohttp/blob/master/aiohttp/helpers.py#L368-L396
    2. repr() implementation uses these properties: https://github.com/aio-libs/aiohttp/blob/master/aiohttp/client_reqrep.py#L741
    3. the code was written with an assumption that these properties will not be accessed before being initialized
    4. hunter breaks this assumption by calling repr() early after object creation (what is seen in trace as a "failed repr")
    5. some properties (e.g. headers) are cached in their uninitialized state
    opened by borman 4
  • Trace importlib

    Trace importlib

    Importlib is not used from the Python source code, but from a "frozen" variant. The problem is, the module has no source code, so I get NO SOURCE: Source code string for '<frozen importlib._bootstrap_external>' is empty. Is there a way to set hunter to read importlib whenever it encounters its frozen form (or maybe generalize this to any frozen module in the stdlib)?

    opened by DUOLabs333 1
  • Idea: a more powerful trace client

    Idea: a more powerful trace client

    Current trace client is a simple wrapper of eval

    eval('hunter.trace({})'.format(options))
    

    It works for simple or medium complex situations, such as:

    • hunter-trace -p 34313 stdlib=False
    • hunter-trace -p 34313 "hunter.Q(lambda event: event.locals.get(\"msg\") == \"ha\")"

    However, it comes short when import or customization is required before hunter.trace.

    from hunter import trace, Q, Debugger
    from pdb import Pdb
    
    trace(
        Q(
            # show code that contains "mumbo.jumbo" on the current line
            lambda event: event.locals.get("mumbo") == "jumbo",
            # and it's not in Python's stdlib
            stdlib=False,
            # and it contains "mumbo" on the current line
            source__contains="mumbo",
            action=Debugger(klass=Pdb)
        )
    )
    

    With due consideration of safety, it should be allowed to eval a whole snippet of codes.

    opened by vitrun 4
  • 3.4.3: sphins warnings and call trace

    3.4.3: sphins warnings and call trace

    Looks like it is some issue on rendering dosumentation

    + /usr/bin/python3 setup.py build_sphinx -b man --build-dir build/sphinx
    /usr/lib/python3.8/site-packages/pkg_resources/__init__.py:116: PkgResourcesDeprecationWarning: 1.16.0-unknown is an invalid version and will not be supported in a future release
      warnings.warn(
    /usr/lib/python3.8/site-packages/setuptools/installer.py:27: SetuptoolsDeprecationWarning: setuptools.installer is deprecated. Requirements should be satisfied by a PEP 517 installer.
      warnings.warn(
    WARNING: The wheel package is not available.
    running build_sphinx
    Running Sphinx v4.3.2
    /usr/lib/python3.8/site-packages/pkg_resources/__init__.py:116: PkgResourcesDeprecationWarning: 1.16.0-unknown is an invalid version and will not be supported in a future release
      warnings.warn(
    Traceback (most recent call last):
      File "/home/tkloczko/rpmbuild/BUILD/python-hunter-3.4.3/docs/conf.py", line 34, in <module>
        version = release = get_distribution('hunter').version
      File "/usr/lib/python3.8/site-packages/pkg_resources/__init__.py", line 471, in get_distribution
        dist = get_provider(dist)
      File "/usr/lib/python3.8/site-packages/pkg_resources/__init__.py", line 347, in get_provider
        return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0]
      File "/usr/lib/python3.8/site-packages/pkg_resources/__init__.py", line 891, in require
        needed = self.resolve(parse_requirements(requirements))
      File "/usr/lib/python3.8/site-packages/pkg_resources/__init__.py", line 777, in resolve
        raise DistributionNotFound(req, requirers)
    pkg_resources.DistributionNotFound: The 'hunter' distribution was not found and is required by the application
    making output directory... done
    [autosummary] generating autosummary for: authors.rst, changelog.rst, configuration.rst, contributing.rst, cookbook.rst, filtering.rst, index.rst, installation.rst, introduction.rst, readme.rst, reference.rst, remote.rst
    building [mo]: targets for 0 po files that are out of date
    building [man]: all manpages
    updating environment: [new config] 12 added, 0 changed, 0 removed
    reading sources... [100%] remote
    README.rst:79: WARNING: duplicate label readme:overview, other instance in /home/tkloczko/rpmbuild/BUILD/python-hunter-3.4.3/docs/readme.rst
    looking for now-outdated files... none found
    pickling environment... done
    checking consistency... done
    writing... python-hunter.3 { readme installation introduction remote configuration filtering cookbook reference contributing authors changelog } done
    build succeeded, 1 warning.
    
    opened by kloczek 2
  • 3.4.3: pytest is failing

    3.4.3: pytest is failing

    I'm trying to package your module as an rpm package. So I'm using the typical PEP517 based build, install and test cycle used on building packages from non-root account.

    • python3 -sBm build -w
    • install .whl file in </install/prefix>
    • run pytest with PYTHONPATH pointing to sitearch and sitelib inside </install/prefix>

    Here is pytest output:

    + PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-hunter-3.4.3-2.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-hunter-3.4.3-2.fc35.x86_64/usr/lib/python3.8/site-packages
    + /usr/bin/pytest -ra --ignore tests/test_tracer.py
    =========================================================================== test session starts ============================================================================
    platform linux -- Python 3.8.12, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    benchmark: 3.4.1 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
    rootdir: /home/tkloczko/rpmbuild/BUILD/python-hunter-3.4.3, configfile: setup.cfg, testpaths: tests
    plugins: hypothesis-6.34.1, cov-3.0.0, aspectlib-1.5.2, benchmark-3.4.1
    collected 140 items
    
    tests/test_config.py ......................                                                                                                                          [ 15%]
    tests/test_cookbook.py .....                                                                                                                                         [ 19%]
    tests/test_integration.py FFF.....FFFF....FFF........FFFFFF                                                                                                          [ 42%]
    tests/test_predicates.py ..........................................................................                                                                  [ 95%]
    tests/test_remote.py FFFF                                                                                                                                            [ 98%]
    tests/test_util.py ..                                                                                                                                                [100%]
    
    ================================================================================= FAILURES =================================================================================
    ___________________________________________________________________________ test_pth_activation ____________________________________________________________________________
    tests/test_integration.py:63: in test_pth_activation
        assert expected_module.encode() in output
    E   AssertionError: assert b'posixpath.py' in b''
    E    +  where b'posixpath.py' = <built-in method encode of str object at 0x7f922d0e76b0>()
    E    +    where <built-in method encode of str object at 0x7f922d0e76b0> = 'posixpath.py'.encode
    _____________________________________________________________________________ test_pth_sample4 _____________________________________________________________________________
    tests/test_integration.py:76: in test_pth_sample4
        assert output
    E   AssertionError: assert b''
    _____________________________________________________________________________ test_pth_sample2 _____________________________________________________________________________
    tests/test_integration.py:89: in test_pth_sample2
        lm.fnmatch_lines([
    E   Failed: nomatch: '*tests*sample2.py:* call      *'
    E       and: "/home/tkloczko/rpmbuild/BUILD/python-hunter-3.4.3/tests/sample2.py:24: SyntaxWarning: 'NoneType' object is not callable; perhaps you missed a comma?"
    E       and: '  None('
    E   remains unmatched: '*tests*sample2.py:* call      *'
    ____________________________________________________________________ test_pid_prefix[True-CodePrinter] _____________________________________________________________________
    tests/test_integration.py:268: in test_pid_prefix
        main()
    E   Failed: line '[[]*[]] *MainThread  *test_*.py:*  line * a = 1' not found in output
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    OUT [3187735]MainThread  [...].8/site-packages/hunter/__init__.py:384   return    def trace(*predicates, **options):
    [3187735]MainThread                                                 ...       return value: <hunter._tracer.Tracer object at 0x7f922d2575e0>
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:268   line              main()
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:256   call          def main():
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:257   line              a = 1
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:258   line              pid = os.fork()
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:258   line      [a => 1]
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line              if pid:
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line      [a => 1]
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:260   line                  os.waitpid(pid, 0)
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:260   line      [a => 1]
    [3187753]MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line              if pid:
    [3187753]MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line      [a => 1]
    [3187753]MainThread  [...]ter-3.4.3/tests/test_integration.py:262   line                  os._exit(0)  # child
    [3187753]MainThread  [...]ter-3.4.3/tests/test_integration.py:262   line      [a => 1]
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:260   return                os.waitpid(pid, 0)
    [3187735]MainThread                                                 ...       return value: None
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:260   return    [a => 1]
    
    ERR
    ____________________________________________________________________ test_pid_prefix[True-CallPrinter] _____________________________________________________________________
    tests/test_integration.py:268: in test_pid_prefix
        main()
    E   Failed: line '[[]*[]] *MainThread  *test_*.py:*  line * a = 1' not found in output
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    OUT [3187735]MainThread  [...].8/site-packages/hunter/__init__.py:384   return    <= trace: <hunter._tracer.Tracer object at 0x7f922d2bcd00>
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:268   line      main()
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:256   call      => main()
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:257   line         a = 1
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:258   line         pid = os.fork()
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:258   line      [a => 1]
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line         if pid:
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line      [a => 1]
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:260   line         os.waitpid(pid, 0)
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:260   line      [a => 1]
    [3187754]MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line         if pid:
    [3187754]MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line      [a => 1]
    [3187754]MainThread  [...]ter-3.4.3/tests/test_integration.py:262   line         os._exit(0)  # child
    [3187754]MainThread  [...]ter-3.4.3/tests/test_integration.py:262   line      [a => 1]
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:260   return    <= main: None
    [3187735]MainThread  [...]ter-3.4.3/tests/test_integration.py:260   return    [a => 1]
    
    ERR
    ____________________________________________________________________ test_pid_prefix[False-CodePrinter] ____________________________________________________________________
    tests/test_integration.py:268: in test_pid_prefix
        main()
    E   Failed: matched:  'MainThread  *test_*.py:*  line * a = 1'
    E   matched:  'MainThread  *test_*.py:*  line * if pid:'
    E   matched:  'MainThread  *test_*.py:*  line * [[]a => 1[]]'
    E   matched:  'MainThread  *test_*.py:*  line * os.waitpid(pid, 0)'
    E   line '[[]*[]] *MainThread  *test_*.py:*  line * os._exit(0)  # child' not found in output
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    OUT MainThread  [...].8/site-packages/hunter/__init__.py:384   return    def trace(*predicates, **options):
    MainThread                                                 ...       return value: <hunter._tracer.Tracer object at 0x7f922d2bcc40>
    MainThread  [...]ter-3.4.3/tests/test_integration.py:268   line              main()
    MainThread  [...]ter-3.4.3/tests/test_integration.py:256   call          def main():
    MainThread  [...]ter-3.4.3/tests/test_integration.py:257   line              a = 1
    MainThread  [...]ter-3.4.3/tests/test_integration.py:258   line              pid = os.fork()
    MainThread  [...]ter-3.4.3/tests/test_integration.py:258   line      [a => 1]
    MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line              if pid:
    MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line      [a => 1]
    MainThread  [...]ter-3.4.3/tests/test_integration.py:260   line                  os.waitpid(pid, 0)
    MainThread  [...]ter-3.4.3/tests/test_integration.py:260   line      [a => 1]
    [3187755]MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line              if pid:
    [3187755]MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line      [a => 1]
    [3187755]MainThread  [...]ter-3.4.3/tests/test_integration.py:262   line                  os._exit(0)  # child
    [3187755]MainThread  [...]ter-3.4.3/tests/test_integration.py:262   line      [a => 1]
    MainThread  [...]ter-3.4.3/tests/test_integration.py:260   return                os.waitpid(pid, 0)
    MainThread                                                 ...       return value: None
    MainThread  [...]ter-3.4.3/tests/test_integration.py:260   return    [a => 1]
    
    ERR
    ____________________________________________________________________ test_pid_prefix[False-CallPrinter] ____________________________________________________________________
    tests/test_integration.py:268: in test_pid_prefix
        main()
    E   Failed: matched:  'MainThread  *test_*.py:*  line * a = 1'
    E   matched:  'MainThread  *test_*.py:*  line * if pid:'
    E   matched:  'MainThread  *test_*.py:*  line * [[]a => 1[]]'
    E   matched:  'MainThread  *test_*.py:*  line * os.waitpid(pid, 0)'
    E   line '[[]*[]] *MainThread  *test_*.py:*  line * os._exit(0)  # child' not found in output
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    OUT MainThread  [...].8/site-packages/hunter/__init__.py:384   return    <= trace: <hunter._tracer.Tracer object at 0x7f922d2bcdc0>
    MainThread  [...]ter-3.4.3/tests/test_integration.py:268   line      main()
    MainThread  [...]ter-3.4.3/tests/test_integration.py:256   call      => main()
    MainThread  [...]ter-3.4.3/tests/test_integration.py:257   line         a = 1
    MainThread  [...]ter-3.4.3/tests/test_integration.py:258   line         pid = os.fork()
    MainThread  [...]ter-3.4.3/tests/test_integration.py:258   line      [a => 1]
    MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line         if pid:
    MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line      [a => 1]
    MainThread  [...]ter-3.4.3/tests/test_integration.py:260   line         os.waitpid(pid, 0)
    MainThread  [...]ter-3.4.3/tests/test_integration.py:260   line      [a => 1]
    [3187756]MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line         if pid:
    [3187756]MainThread  [...]ter-3.4.3/tests/test_integration.py:259   line      [a => 1]
    [3187756]MainThread  [...]ter-3.4.3/tests/test_integration.py:262   line         os._exit(0)  # child
    [3187756]MainThread  [...]ter-3.4.3/tests/test_integration.py:262   line      [a => 1]
    MainThread  [...]ter-3.4.3/tests/test_integration.py:260   return    <= main: None
    MainThread  [...]ter-3.4.3/tests/test_integration.py:260   return    [a => 1]
    
    ERR
    _________________________________________________________________ test_depth_limit_subprocess[depth_lt=2] __________________________________________________________________
    tests/test_integration.py:362: in test_depth_limit_subprocess
        lm.fnmatch_lines([
    E   Failed: remains unmatched: '* call    * => one()'
    _________________________________________________________________ test_depth_limit_subprocess[depth_lt=3] __________________________________________________________________
    tests/test_integration.py:362: in test_depth_limit_subprocess
        lm.fnmatch_lines([
    E   Failed: remains unmatched: '* call    * => one()'
    _________________________________________________________________ test_depth_limit_subprocess[depth_lt=4] __________________________________________________________________
    tests/test_integration.py:362: in test_depth_limit_subprocess
        lm.fnmatch_lines([
    E   Failed: remains unmatched: '* call    * => one()'
    _________________________________________________________________________ test_pdb[postmortem-pdb] _________________________________________________________________________
    tests/test_integration.py:754: in test_pdb
        wait_for_strings(target.read, TIMEOUT, '-> ')
    /usr/lib/python3.8/site-packages/process_tests.py:247: in wait_for_strings
        raise AssertionError("Waited %0.2fsecs but %s did not appear in output in the given order !" % (
    E   AssertionError: Waited 60.00secs but ['-> '] did not appear in output in the given order !
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    *********** OUTPUT ***********
    /usr/bin/python3: No module named samplepdb
    
    ******************************
    ________________________________________________________________________ test_pdb[postmortem-ipdb] _________________________________________________________________________
    tests/test_integration.py:754: in test_pdb
        wait_for_strings(target.read, TIMEOUT, '-> ')
    /usr/lib/python3.8/site-packages/process_tests.py:247: in wait_for_strings
        raise AssertionError("Waited %0.2fsecs but %s did not appear in output in the given order !" % (
    E   AssertionError: Waited 60.00secs but ['-> '] did not appear in output in the given order !
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    *********** OUTPUT ***********
    /usr/bin/python3: No module named samplepdb
    
    ******************************
    __________________________________________________________________________ test_pdb[settrace-pdb] __________________________________________________________________________
    tests/test_integration.py:754: in test_pdb
        wait_for_strings(target.read, TIMEOUT, '-> ')
    /usr/lib/python3.8/site-packages/process_tests.py:247: in wait_for_strings
        raise AssertionError("Waited %0.2fsecs but %s did not appear in output in the given order !" % (
    E   AssertionError: Waited 60.00secs but ['-> '] did not appear in output in the given order !
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    *********** OUTPUT ***********
    /usr/bin/python3: No module named samplepdb
    
    ******************************
    _________________________________________________________________________ test_pdb[settrace-ipdb] __________________________________________________________________________
    tests/test_integration.py:754: in test_pdb
        wait_for_strings(target.read, TIMEOUT, '-> ')
    /usr/lib/python3.8/site-packages/process_tests.py:247: in wait_for_strings
        raise AssertionError("Waited %0.2fsecs but %s did not appear in output in the given order !" % (
    E   AssertionError: Waited 60.00secs but ['-> '] did not appear in output in the given order !
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    *********** OUTPUT ***********
    /usr/bin/python3: No module named samplepdb
    
    ******************************
    __________________________________________________________________________ test_pdb[debugger-pdb] __________________________________________________________________________
    tests/test_integration.py:754: in test_pdb
        wait_for_strings(target.read, TIMEOUT, '-> ')
    /usr/lib/python3.8/site-packages/process_tests.py:247: in wait_for_strings
        raise AssertionError("Waited %0.2fsecs but %s did not appear in output in the given order !" % (
    E   AssertionError: Waited 60.00secs but ['-> '] did not appear in output in the given order !
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    *********** OUTPUT ***********
    /usr/bin/python3: No module named samplepdb
    
    ******************************
    _________________________________________________________________________ test_pdb[debugger-ipdb] __________________________________________________________________________
    tests/test_integration.py:754: in test_pdb
        wait_for_strings(target.read, TIMEOUT, '-> ')
    /usr/lib/python3.8/site-packages/process_tests.py:247: in wait_for_strings
        raise AssertionError("Waited %0.2fsecs but %s did not appear in output in the given order !" % (
    E   AssertionError: Waited 60.00secs but ['-> '] did not appear in output in the given order !
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    *********** OUTPUT ***********
    /usr/bin/python3: No module named samplepdb
    
    ******************************
    _______________________________________________________________________________ test_manhole _______________________________________________________________________________
    tests/test_remote.py:23: in test_manhole
        wait_for_strings(target.read, TIMEOUT, 'Oneshot activation is done by signal')
    /usr/lib/python3.8/site-packages/process_tests.py:247: in wait_for_strings
        raise AssertionError("Waited %0.2fsecs but %s did not appear in output in the given order !" % (
    E   AssertionError: Waited 60.00secs but ['Oneshot activation is done by signal'] did not appear in output in the given order !
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    *********** OUTPUT ***********
    /usr/bin/python: No module named samplemanhole
    
    ******************************
    _________________________________________________________________________ test_manhole_clean_exit __________________________________________________________________________
    tests/test_remote.py:39: in test_manhole_clean_exit
        wait_for_strings(target.read, TIMEOUT, 'Oneshot activation is done by signal')
    /usr/lib/python3.8/site-packages/process_tests.py:247: in wait_for_strings
        raise AssertionError("Waited %0.2fsecs but %s did not appear in output in the given order !" % (
    E   AssertionError: Waited 60.00secs but ['Oneshot activation is done by signal'] did not appear in output in the given order !
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    *********** OUTPUT ***********
    /usr/bin/python: No module named samplemanhole
    
    ******************************
    _________________________________________________________________________________ test_gdb _________________________________________________________________________________
    tests/test_remote.py:66: in test_gdb
        wait_for_strings(
    /usr/lib/python3.8/site-packages/process_tests.py:247: in wait_for_strings
        raise AssertionError("Waited %0.2fsecs but %s did not appear in output in the given order !" % (
    E   AssertionError: Waited 60.00secs but ['return    <= stuff: None', 'line         time.sleep(1)', 'call      => stuff()', 'Output stream active. Starting tracer'] did not appear in output in the given order !
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    *********** OUTPUT ***********
    warning: process 3188183 is a zombie - the process has already terminated
    ptrace: Operation not permitted.
    No symbol table is loaded.  Use the "file" command.
    WARNING: Using GDB may deadlock the process or create unpredictable results!
    Traceback (most recent call last):
      File "/home/tkloczko/rpmbuild/BUILDROOT/python-hunter-3.4.3-2.fc35.x86_64/usr/bin/hunter-trace", line 8, in <module>
        sys.exit(main())
      File "/home/tkloczko/rpmbuild/BUILDROOT/python-hunter-3.4.3-2.fc35.x86_64/usr/lib64/python3.8/site-packages/hunter/remote.py", line 164, in main
        with bootstrapper(args, payload, 'from hunter import remote; remote.deactivate()'):
      File "/usr/lib64/python3.8/contextlib.py", line 113, in __enter__
        return next(self.gen)
      File "/home/tkloczko/rpmbuild/BUILDROOT/python-hunter-3.4.3-2.fc35.x86_64/usr/lib64/python3.8/site-packages/hunter/remote.py", line 87, in gdb_bootstrap
        check_call(activation_command)
      File "/usr/lib64/python3.8/subprocess.py", line 364, in check_call
        raise CalledProcessError(retcode, cmd)
    subprocess.CalledProcessError: Command '['gdb', '-p', '3188183', '-batch', '-ex', 'call (void)Py_AddPendingCall(PyRun_SimpleString, "from hunter import remote; remote.activate(\'/tmp/hunter-3188184\', False, \'utf-8\', \'stdlib=False\')")']' returned non-zero exit status 1.
    
    ******************************
    *********** OUTPUT ***********
    /usr/bin/python: No module named samplemanhole
    
    ******************************
    ___________________________________________________________________________ test_gdb_clean_exit ____________________________________________________________________________
    tests/test_remote.py:85: in test_gdb_clean_exit
        wait_for_strings(
    /usr/lib/python3.8/site-packages/process_tests.py:247: in wait_for_strings
        raise AssertionError("Waited %0.2fsecs but %s did not appear in output in the given order !" % (
    E   AssertionError: Waited 60.00secs but ['return    <= stuff: None', 'line         time.sleep(1)', 'call      => stuff()', 'Output stream active. Starting tracer'] did not appear in output in the given order !
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    *********** OUTPUT ***********
    warning: process 3188249 is a zombie - the process has already terminated
    ptrace: Operation not permitted.
    No symbol table is loaded.  Use the "file" command.
    WARNING: Using GDB may deadlock the process or create unpredictable results!
    Traceback (most recent call last):
      File "/home/tkloczko/rpmbuild/BUILDROOT/python-hunter-3.4.3-2.fc35.x86_64/usr/bin/hunter-trace", line 8, in <module>
        sys.exit(main())
      File "/home/tkloczko/rpmbuild/BUILDROOT/python-hunter-3.4.3-2.fc35.x86_64/usr/lib64/python3.8/site-packages/hunter/remote.py", line 164, in main
        with bootstrapper(args, payload, 'from hunter import remote; remote.deactivate()'):
      File "/usr/lib64/python3.8/contextlib.py", line 113, in __enter__
        return next(self.gen)
      File "/home/tkloczko/rpmbuild/BUILDROOT/python-hunter-3.4.3-2.fc35.x86_64/usr/lib64/python3.8/site-packages/hunter/remote.py", line 87, in gdb_bootstrap
        check_call(activation_command)
      File "/usr/lib64/python3.8/subprocess.py", line 364, in check_call
        raise CalledProcessError(retcode, cmd)
    subprocess.CalledProcessError: Command '['gdb', '-p', '3188249', '-batch', '-ex', 'call (void)Py_AddPendingCall(PyRun_SimpleString, "from hunter import remote; remote.activate(\'/tmp/hunter-3188250\', False, \'utf-8\', \'stdlib=False\')")']' returned non-zero exit status 1.
    
    ******************************
    *********** OUTPUT ***********
    /usr/bin/python3: No module named samplemanhole
    
    ******************************
    
    ----------------------------------------------------------------------------------------- benchmark: 3 tests ----------------------------------------------------------------------------------------
    Name (time in us)                Min                 Max                Mean             StdDev              Median               IQR            Outliers  OPS (Kops/s)            Rounds  Iterations
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    test_probe[no_probe]         26.7099 (1.0)      110.5189 (1.0)       27.8665 (1.0)       1.1165 (1.0)       27.6831 (1.0)      0.7423 (1.0)       888;882       35.8854 (1.0)       29066           1
    test_probe[fast_probe]      186.0410 (6.97)     396.7280 (3.59)     192.2989 (6.90)      8.9009 (7.97)     190.6899 (6.89)     4.6414 (6.25)       91;114        5.2002 (0.14)       3061           1
    test_probe[brief_probe]     292.4309 (10.95)    655.1051 (5.93)     300.4506 (10.78)    10.9594 (9.82)     298.0419 (10.77)    6.5049 (8.76)        84;69        3.3283 (0.09)       2661           1
    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    Legend:
      Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
      OPS: Operations Per Second, computed as 1 / Mean
    ========================================================================= short test summary info ==========================================================================
    FAILED tests/test_integration.py::test_pth_activation - AssertionError: assert b'posixpath.py' in b''
    FAILED tests/test_integration.py::test_pth_sample4 - AssertionError: assert b''
    FAILED tests/test_integration.py::test_pth_sample2 - Failed: nomatch: '*tests*sample2.py:* call      *'
    FAILED tests/test_integration.py::test_pid_prefix[True-CodePrinter] - Failed: line '[[]*[]] *MainThread  *test_*.py:*  line * a = 1' not found in output
    FAILED tests/test_integration.py::test_pid_prefix[True-CallPrinter] - Failed: line '[[]*[]] *MainThread  *test_*.py:*  line * a = 1' not found in output
    FAILED tests/test_integration.py::test_pid_prefix[False-CodePrinter] - Failed: matched:  'MainThread  *test_*.py:*  line * a = 1'
    FAILED tests/test_integration.py::test_pid_prefix[False-CallPrinter] - Failed: matched:  'MainThread  *test_*.py:*  line * a = 1'
    FAILED tests/test_integration.py::test_depth_limit_subprocess[depth_lt=2] - Failed: remains unmatched: '* call    * => one()'
    FAILED tests/test_integration.py::test_depth_limit_subprocess[depth_lt=3] - Failed: remains unmatched: '* call    * => one()'
    FAILED tests/test_integration.py::test_depth_limit_subprocess[depth_lt=4] - Failed: remains unmatched: '* call    * => one()'
    FAILED tests/test_integration.py::test_pdb[postmortem-pdb] - AssertionError: Waited 60.00secs but ['-> '] did not appear in output in the given order !
    FAILED tests/test_integration.py::test_pdb[postmortem-ipdb] - AssertionError: Waited 60.00secs but ['-> '] did not appear in output in the given order !
    FAILED tests/test_integration.py::test_pdb[settrace-pdb] - AssertionError: Waited 60.00secs but ['-> '] did not appear in output in the given order !
    FAILED tests/test_integration.py::test_pdb[settrace-ipdb] - AssertionError: Waited 60.00secs but ['-> '] did not appear in output in the given order !
    FAILED tests/test_integration.py::test_pdb[debugger-pdb] - AssertionError: Waited 60.00secs but ['-> '] did not appear in output in the given order !
    FAILED tests/test_integration.py::test_pdb[debugger-ipdb] - AssertionError: Waited 60.00secs but ['-> '] did not appear in output in the given order !
    FAILED tests/test_remote.py::test_manhole - AssertionError: Waited 60.00secs but ['Oneshot activation is done by signal'] did not appear in output in the given order !
    FAILED tests/test_remote.py::test_manhole_clean_exit - AssertionError: Waited 60.00secs but ['Oneshot activation is done by signal'] did not appear in output in the give...
    FAILED tests/test_remote.py::test_gdb - AssertionError: Waited 60.00secs but ['return    <= stuff: None', 'line         time.sleep(1)', 'call      => stuff()', 'Output s...
    FAILED tests/test_remote.py::test_gdb_clean_exit - AssertionError: Waited 60.00secs but ['return    <= stuff: None', 'line         time.sleep(1)', 'call      => stuff()'...
    ================================================================ 20 failed, 120 passed in 611.88s (0:10:11) ================================================================
    
    opened by kloczek 6
  • Reduce gdb deadlocks

    Reduce gdb deadlocks

    When using python-hunter's remote feature, a warning is printed that the process may deadlock. (See here.)

    I strongly suspect this can be fixed by setting the gdb flag scheduler-locking off. IDEs like VSCode reliably inject code into Python processes to support debugging existing processes. VSCode's implementation explicitly mentions the importance of setting scheduler-locking off to prevent deadlocks

    I unfortunately don't have the time to open a PR for python-hunter at the moment, but I do plan to maintain a fork of pyrasite with this and other fixes. I will update here if I find additional bugs that can cause deadlocks.

    opened by aantn 7
  • event.stdlib returns false-positive

    event.stdlib returns false-positive

    Unfortunately event.stdlib is True in my case, although the code is not from stdlib.

    Here is a simple way to reproduce it:

    python3 -m venv hunter-env
    
    cd hunter-env
    
    . bin/activate
    
    pip install python-hunter
    
    vi t.py
    

    file t.py:

    import hunter
    
    
    def foo():
        i=0
        i+=1
        print(f'i: {i}')
    
    def print_stdlib(event):
        print(f'{event.source.strip()} {event.stdlib}')
    
    with hunter.trace(print_stdlib):
        foo()
    

    main.py

    import t
    

    Call main.py

    python main.py
    

    output:

    def trace(*predicates, **options): False
    foo() True
    def foo(): True
    i=0 True
    i+=1 True
    print(f'i: {i}') True
    i: 1
    print(f'i: {i}') True
    

    ===> hunter thinks "foo()" is in stdlib, but it is not.


    I guess it is because of:

                elif self.filename.startswith(SYS_PREFIX_PATHS):
                    self._stdlib = True
    

    in _event.pyx

    Maybe it would help to exclude the virtualenv from SYS_PREFIX_PATHS.

    opened by guettli 3
Releases(v3.5.0)
  • v3.5.0(Sep 11, 2022)

  • v3.4.3(Sep 11, 2022)

    • Removed most of the Python 2 support code.
    • Fix some refactoring regression in setup.py and make the 3.4.x series installable only on Python 3.6 and later.
    • Yank 3.4.0, 3.4.1, 3.4.2 releases to avoid install problems on Python 2.7.
    Source code(tar.gz)
    Source code(zip)
  • v3.4.2(Sep 11, 2022)

  • v3.4.1(Sep 11, 2022)

  • v3.4.0(Sep 11, 2022)

    • Switched CI to GitHub Actions, this has a couple consequences:

      • Support for Python 2.7 is dropped. You can still install it there but it's not tested anymore and Python 2 specific handling will be removed at some point.
      • Linux wheels are now provided in musllinux and manylinux2014 variants.
    • Extension building is now completely skipped on PyPy.

    • A pure but tagged as platform specific wheel is now provided for PyPy (to have fast installs there as well).

    Source code(tar.gz)
    Source code(zip)
  • v3.3.8(Sep 11, 2022)

  • v3.3.7(Sep 11, 2022)

  • v3.3.6(Sep 11, 2022)

    • Fixed regression from 3.3.4: stdlib filter was broken.
    • Improved the pth file (PYTHONHUNTER environment variable activation) to use a clean eval environment. No bogus variables like line (from the site.py machinery) will be available anymore.
    • Fixed a bug in VarsSnooper that would make it fail in rare situation where a double return event is emitted.
    Source code(tar.gz)
    Source code(zip)
  • v3.3.5(Sep 11, 2022)

    • Added support for Python 3.10.
    • Added support for time objects and the fold option in safe_repr.
    • 3.3.4 was skipped cause I messed up the CI.
    Source code(tar.gz)
    Source code(zip)
  • v3.3.3(May 8, 2021)

    • Fixed tracer still being active for other threads after it was stopped.

      Python unfortunately only allows removing the trace function for the current thread - now hunter.tracer.Tracer will uninstall itself if it's marked as stopped.

      This fixes bogus errors that appear when using ipdb with the hunter.actions.Debugger action while thread support is enabled (the default).

    Source code(tar.gz)
    Source code(zip)
  • v3.3.2(May 8, 2021)

    • Changed CI to build Python 3.9 wheels. Python 3.5 no longer tested and wheels no longer built to keep things simple.
    • Documentation improvements.
    Source code(tar.gz)
    Source code(zip)
  • v3.3.1(May 8, 2021)

  • v3.3.0(May 8, 2021)

    • Fixed handling so that hunter.event.Event.module is always the "?" string instead of None. Previously it was None when tracing particularly broken code and broke various predicates.
    • Similarly hunter.event.Event.filename is now "?" if there's no filename available.
    • Building on the previous changes the actions have simpler code for displaying missing module/filenames.
    • Changed hunter.actions.CallPrinter so that trace events for builtin functions are displayed differently. These events appear when using profile mode (eg: trace(profile=True)).
    • Fixed failure that could occur if hunter.event.Event.module is an unicode string. Now it's always a regular string. Only applies to Python 2.
    • Fixed argument display when tracing functions with tuple arguments. Closes #88. Only applies to Python 2.
    • Improved error reporting when internal failures occur. Now some details about the triggering event are logged.
    Source code(tar.gz)
    Source code(zip)
  • v3.2.2(May 8, 2021)

    • Fixed oversight over what value is in hunter.event.Event.builtin. Now it's always a boolean, and can be used consistently in filters (eg: builtin=True,function='getattr').
    Source code(tar.gz)
    Source code(zip)
  • v3.2.1(May 8, 2021)

    • Added support for regex, date and datetime in safe_repr.
    • Fixed call argument display when positional and keyword arguments are used in hunter.actions.CallPrinter.
    Source code(tar.gz)
    Source code(zip)
  • v3.2.0(May 8, 2021)

    • Implemented the hunter.actions.StackPrinter action.
    • Implemented the hunter.predicates.Backlog predicate. Contributed by Dan Ailenei in #81.
    • Improved contributing section in docs a bit. Contributed by Tom Schraitle in #85.
    • Improved filtering performance by avoiding a lot of unnecessary PyObject_GetAttr calls in the Cython implementation of hunter.predicates.Backlog.
    • Implemented the hunter.actions.ErrorSnooper action.
    • Added support for profiling mode (eg: trace(profile=True)). This mode will use setprofile instead of settrace.
    • Added ARM64 wheels and CI.
    • Added hunter.event.Event.instruction and hunter.event.Event.builtin (usable in profile mode).
    • Added more cookbook entries.
    Source code(tar.gz)
    Source code(zip)
  • v3.1.3(May 8, 2021)

  • v3.1.2(May 8, 2021)

  • v3.1.1(May 8, 2021)

  • v3.1.0(May 8, 2021)

    • Added hunter.actions.ErrorSnooper - an action that detects silenced exceptions.
    • Added hunter.load_config and fixed issues with configuration being loaded too late from the PYTHONHUNTERCONFIG environment variable.
    • Changed hunter.From helper to automatically move depth and calls filters to the predicate (so they filter after hunter.predicates.From activates).
    • Changed hunter.predicates.From to pass a copy of event to the predicate. The copy will have the depth and calls attributes adjusted to the point where hunter.predicates.From activated.
    • Fixed a bunch of inconsistencies and bugs when using & and | operators with predicates.
    • Fixed a bunch of broken fields on detached events from hunter.event.Event.detach (hunter.event.Event.function_object and hunter.event.Event.arg).
    • Improved docstrings in various and added a configuration doc section.
    • Improved testing (more coverage).
    Source code(tar.gz)
    Source code(zip)
  • v3.0.5(May 8, 2021)

    • Really fixed safe_repr so it doesn't cause side-effects (now isinstance/issubclass are avoided - they can cause side-effects in code that abuses descriptors in special attributes/methods).
    Source code(tar.gz)
    Source code(zip)
  • v3.0.4(May 8, 2021)

    • Really fixed stream setup in actions (using force_colors without any stream was broken). See: hunter.actions.ColorStreamAction.
    • Fixed __repr__ for the hunter.predicates.From predicate to include watermark.
    • Added binary wheels for Python 3.8.
    Source code(tar.gz)
    Source code(zip)
  • v3.0.3(May 8, 2021)

  • v3.0.2(May 8, 2021)

    • Fixed setting stream from PYTHONHUNTERCONFIG environment variable. See: hunter.actions.ColorStreamAction.
    • Fixed a couple minor documentation issues.
    Source code(tar.gz)
    Source code(zip)
  • v3.0.1(May 8, 2021)

  • v3.0.0(May 8, 2021)

    • The package now uses setuptools-scm for development builds (available at https://test.pypi.org/project/hunter/). As a consequence installing the sdist will download setuptools-scm.

    • Recompiled cython modules with latest Cython. Hunter can be installed without any Cython, as before.

    • Refactored some of the cython modules to have more typing information and not use deprecated property syntax.

    • Replaced unsafe_repr option with repr_func. Now you can use your custom repr function in the builtin actions. BACKWARDS INCOMPATIBLE

    • Fixed buggy filename handling when using Hunter in ipython/jupyter. Source code should be properly displayed now.

    • Removed globals option from VarsPrinter action. Globals are now always looked up. BACKWARDS INCOMPATIBLE

    • Added support for locals in VarsPrinter action. Now you can do VarsPrinter('len(foobar)').

    • Always pass module_globals dict to linecache methods. Source code from PEP-302 loaders is now printed properly. Contributed by Mikhail Borisov in #65.

    • Various code cleanup, style and docstring fixing.

    • Added hunter.From helper to allow passing in filters directly as keyword arguments.

    • Added hunter.event.Event.detach for storing events without leaks or side-effects (due to prolonged references to Frame objects, local or global variables).

    • Refactored the internals of actions for easier subclassing.

      Added the filename_prefix, output, pid_prefix, thread_prefix, try_repr and try_source methods to the hunter.actions.ColorStreamAction baseclass.

    • Added hunter.actions.VarsSnooper - a PySnooper-inspired variant of hunter.actions.VarsPrinter. It will record and show variable changes, with the risk of leaking or using too much memory of course :)

    • Fixed tracers to log error and automatically stop if there's an internal failure. Previously error may have been silently dropped in some situations.

    Source code(tar.gz)
    Source code(zip)
  • v2.2.1(May 8, 2021)

  • v2.2.0(May 8, 2021)

    • Added hunter.predicates.From predicate for tracing from a specific point. It stop after returning back to the same call depth with a configurable offset.
    • Fixed PYTHONHUNTERCONFIG not working in some situations (config values were resolved at the wrong time).
    • Made tests in CI test the wheel that will eventually be published to PyPI (tox-wheel).
    • Made event.stdlib more reliable: pkg_resources is considered part of stdlib and few more paths will be considered as stdlib.
    • Dumbed down the get_peercred check that is done when attaching with hunter-trace CLI (via hunter.remote.install()). It will be slightly insecure but will work on OSX.
    • Added OSX in the Travis test grid.
    Source code(tar.gz)
    Source code(zip)
  • v2.1.0(May 8, 2021)

    • Made threading_support on by default but output automatic (also, now 1 or 0 allowed).
    • Added pid_alignment and force_pid action options to show a pid prefix.
    • Fixed some bugs around __eq__ in various classes.
    • Dropped Python 3.3 support.
    • Dropped dependency on fields.
    • Actions now repr using a simplified implementation that tries to avoid calling __repr__ on user classes in order to avoid creating side-effects while tracing.
    • Added support for the PYTHONHUNTERCONFIG environment variable (stores defaults and doesn't activate hunter).
    Source code(tar.gz)
    Source code(zip)
  • v2.0.2(May 8, 2021)

    • Fixed indentation in hunter.actions.CallPrinter action (shouldn't deindent on exception).
    • Fixed option filtering in Cython Query implementation (filtering on tracer was allowed by mistake).
    • Various fixes to docstrings and docs.
    Source code(tar.gz)
    Source code(zip)
A web-based visualization and debugging platform for NuPIC

Cerebro 2 A web-based visualization and debugging platform for NuPIC. Usage Set up cerebro2.server to export your model state. Then, run: cd static py

Numenta 24 Oct 13, 2021
一个小脚本,用于trace so中native函数的调用。

trace_natives 一个IDA小脚本,获取SO代码段中所有函数的偏移地址,再使用frida-trace 批量trace so函数的调用。 使用方法 1.将traceNatives.py丢进IDA plugins目录中 2.IDA中,Edit-Plugins-traceNatives IDA输

296 Dec 28, 2022
A powerful set of Python debugging tools, based on PySnooper

snoop snoop is a powerful set of Python debugging tools. It's primarily meant to be a more featureful and refined version of PySnooper. It also includ

Alex Hall 874 Jan 08, 2023
Hypothesis debugging with vscode

Hypothesis debugging with vscode

Oliver Mannion 0 Feb 09, 2022
Sentry is cross-platform application monitoring, with a focus on error reporting.

Users and logs provide clues. Sentry provides answers. What's Sentry? Sentry is a service that helps you monitor and fix crashes in realtime. The serv

Sentry 32.9k Dec 31, 2022
An x86 old-debug-like program.

An x86 old-debug-like program.

Pablo Niklas 1 Jan 10, 2022
Cyberbrain: Python debugging, redefined.

Cyberbrain1(电子脑) aims to free programmers from debugging.

laike9m 2.3k Jan 07, 2023
An improbable web debugger through WebSockets

wdb - Web Debugger Description wdb is a full featured web debugger based on a client-server architecture. The wdb server which is responsible of manag

Kozea 1.6k Dec 09, 2022
NoPdb: Non-interactive Python Debugger

NoPdb: Non-interactive Python Debugger Installation: pip install nopdb Docs: https://nopdb.readthedocs.io/ NoPdb is a programmatic (non-interactive) d

Ondřej Cífka 67 Oct 15, 2022
GEF (GDB Enhanced Features) - a modern experience for GDB with advanced debugging features for exploit developers & reverse engineers ☢

GEF (GDB Enhanced Features) - a modern experience for GDB with advanced debugging features for exploit developers & reverse engineers ☢

hugsy 5.2k Jan 01, 2023
Voltron is an extensible debugger UI toolkit written in Python.

Voltron is an extensible debugger UI toolkit written in Python. It aims to improve the user experience of various debuggers (LLDB, GDB, VDB an

snare 5.9k Dec 30, 2022
A simple rubber duck debugger

Rubber Duck Debugger I found myself many times asking a question on StackOverflow or to one of my colleagues just for finding the solution simply by d

1 Nov 10, 2021
Full featured multi arch/os debugger built on top of PyQt5 and frida

Full featured multi arch/os debugger built on top of PyQt5 and frida

iGio90 1.1k Dec 26, 2022
A configurable set of panels that display various debug information about the current request/response.

Django Debug Toolbar The Django Debug Toolbar is a configurable set of panels that display various debug information about the current request/respons

Jazzband 7.3k Dec 31, 2022
A drop-in replacement for Django's runserver.

About A drop in replacement for Django's built-in runserver command. Features include: An extendable interface for handling things such as real-time l

David Cramer 1.3k Dec 15, 2022
Sweeter debugging and benchmarking Python programs.

Do you ever use print() or log() to debug your code? If so, ycecream, or y for short, will make printing debug information a lot sweeter. And on top o

42 Dec 12, 2022
Inject code into running Python processes

pyrasite Tools for injecting arbitrary code into running Python processes. homepage: http://pyrasite.com documentation: http://pyrasite.rtfd.org downl

Luke Macken 2.7k Jan 08, 2023
GDB plugin for streaming defmt messages over RTT from e.g. JLinkGDBServer

Defmt RTT plugin from GDB This small plugin runs defmt-print on the RTT stream produced by JLinkGDBServer, so that you can see the defmt logs in the G

Gaute Hope 1 Dec 30, 2021
(OLD REPO) Line-by-line profiling for Python - Current repo ->

line_profiler and kernprof line_profiler is a module for doing line-by-line profiling of functions. kernprof is a convenient script for running either

Robert Kern 3.6k Jan 06, 2023
Middleware that Prints the number of DB queries to the runserver console.

Django Querycount Inspired by this post by David Szotten, this project gives you a middleware that prints DB query counts in Django's runserver consol

Brad Montgomery 332 Dec 23, 2022