跳转到主要内容

Hunter是一款灵活的代码跟踪工具包。

项目描述

Hunter是一款灵活的代码跟踪工具包,不是用于测量覆盖率,而是用于调试、记录、检查等。它有一个简单的Python API、一个方便的终端API和一个可以附加到进程的CLI工具。

  • 免费软件:BSD 2-Clause许可协议

安装

pip install hunter

文档

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

入门

基本使用涉及将各种过滤器传递给“trace”选项。例如:

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

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

这将导致

>>> 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'

在终端中看起来像这样:

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

另一个有用的场景是忽略所有标准模块,并强制使用颜色,即使输出被重定向到文件,也会使颜色保持不变。

import hunter
hunter.trace(stdlib=False, action=hunter.CallPrinter(force_colors=True))

操作

可以使用“操作”来控制输出格式。有一个名为“CodePrinter”的替代操作,它不处理嵌套(在Hunter 2.0之前,这是默认操作)。

如果过滤器匹配,则将运行操作。示例

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

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

这将导致

>>> 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'
  • 或者在终端中

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

另一个有用的操作是 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')

这将导致

>>> 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'

在终端中看起来像这样:

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

您可以给它一个树状配置,您可以为树的一部分(如变量转储或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()

具有类似于 foo.py 的配置

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()

我们得到

>>> 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)

在终端中看起来像这样:

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

跟踪进程

类似于 strace 的方式,Hunter 可以跟踪其他进程,例如

hunter-trace --gdb -p 123

如果您想确保安全(没有杂乱的 GDB),则在您的代码中添加以下内容

from hunter import remote
remote.install()

然后您可以这样做

hunter-trace -p 123

请参阅有关远程功能的文档

注意: Windows 不受支持。

环境变量激活

为了您的方便,提供了环境变量激活。只需像这样运行您的应用程序

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

在 Windows 上,您会这样做

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

激活使用一个聪明的 .pth 文件,该文件检查该环境变量的存在,并在您的应用程序运行之前执行类似以下操作

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

请注意,即使环境变量为空,Hunter 也会激活,例如:PYTHONHUNTER=""

环境变量配置

有时您总是使用相同的选项(如 stdlib=Falseforce_colors=True)。为了节省打字时间,您可以在环境中设置以下内容

PYTHONHUNTERCONFIG="stdlib=False,force_colors=True"

这相当于 PYTHONHUNTER="stdlib=False,action=CallPrinter(force_colors=True)"

注意

  • 仅设置 PYTHONHUNTERCONFIG 不会激活 hunter。

  • 支持所有内置操作的选项。

  • 虽然支持谓词,但这可能存在问题。以下是不会跟踪任何内容的设置示例

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

    相当于

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

    相当于

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

过滤 DSL

Hunter 支持灵活的查询 DSL,请参阅 介绍

开发

要运行所有测试,请执行

tox

设计说明

Hunter 并非万能。作为此库的设计目标,一些事情被故意设计得简洁且冗长(以避免复杂性、混淆和不一致性)。这有几个后果

  • 运算符,但没有否定运算符。相反,您应该否定查询对象,例如:~Q(module='re')

  • 没有专门的运算符或过滤器 - 所有过滤器的行为完全相同。例如

    • 没有针对包的过滤器。您应该使用运算符通过模块进行过滤。

    • 没有针对参数、返回值或变量的过滤器。您应该编写自己的过滤函数并处理窥探对象的难题。

  • 分层最少。有一些 辅助函数 进行一些参数处理和转换,以节省您的打字时间,但这就是全部。

  • 库不试图隐藏 Python 中跟踪的机制 - 如果您使用 sys.settrace,则与 Python 发送到跟踪函数的内容一一对应。

  • 没有存储。您应该将输出重定向到文件。

您应该将其视为帮助您理解和调试大型应用程序的工具,或是一个减轻您 settrace 繁琐部分的框架,而不是帮助您学习 Python 的工具。

常见问题解答

为什么不使用 Smiley?

Smiley 有一些明显的重叠,但也有一些根本性的区别

  • 复杂性。Smiley 简直是过度设计

    • 它使用 IPC 和 SQL 数据库。

    • 它有一个 Web 服务器。有许多依赖项。

    • 它使用线程。引入了副作用和微妙的错误。

    • 它记录一切。尝试转储任何变量。经常失败并停止工作。

    为什么你需要这么多东西来在终端中调试一些东西呢?简单来说,这确实是个好主意,但在你深陷自己的代码调试时,设计选择却对你不利。根据我的经验,Smiley非常容易出错且不可靠。当然,你的体验可能会有所不同。

  • 跟踪长时间运行的代码。这将导致Smiley记录大量数据,使其无法使用。

    由于Smiley记录了所有内容,你可能会认为它更适合短程序。但遗憾的是,如果你的程序运行得很快,记录执行过程就没有意义了。你可以直接再次运行它。

    似乎只有一种情况下使用Smiley是合理的:远程跟踪I/O密集型应用程序。这些应用程序不会执行大量代码,只是等待网络,因此Smiley的存储不会过载,跟踪开销也可能可以接受。

  • 用例。在我看来,Smiley的真正目的不是调试代码,而更像是一个“非交互式监控”工具。

相比之下,Hunter非常简单

  • 依赖项很少。

  • 开销低(跟踪/过滤代码有一个可选的Cython扩展)。

  • 无存储。这简化了许多事情。

    唯一的成本是可能需要多次运行代码才能正确设置过滤/操作。这意味着Hunter并不适合“事后”调试。如果你无法再次重现问题,Hunter就不会有多大帮助。

为什么不使用pytrace?

Pytrace是另一个跟踪工具。它似乎与Smiley非常相似——它使用sqlite数据库来存储事件、线程和IPC,因此可以合理地预期会遇到相同类型的问题。

为什么不使用PySnooper或snoop?

snoopPySnooper的改进版本。两者更适合跟踪小程序或函数,因为输出更详细,不太适合跟踪大型应用程序,而Hunter提供了更灵活的设置、过滤能力、速度和简洁性。

为什么不使用覆盖率?

对于调试而言,coverage是一个伟大的工具,但它只适用于“通过查看代码是否(未)运行来调试”。检查分支覆盖率是好的,但它只能带你到这里。

从另一个角度来看,你可能想知道是否可以使用Hunter来测量类似覆盖率的东西。你可以做到,但为了这个目的,Hunter非常“粗糙”——它没有内置的存储。你可以自己实现存储,但如果你不需要“预过滤”你记录的内容,这不会给你带来任何优势,因为你不需要自己制作跟踪器。

换句话说,过滤事件是Hunter的主要卖点——它速度快(Cython实现),查询API足够灵活。

使用Hunter的项目

关于Hunter值得注意的使用情况(如果你构建了一个依赖于hunter的工具,请提交PR)

更多使用该工具的项目请参阅https://github.com/ionelmc/python-hunter/network/dependents

变更日志

3.7.0 (2024-05-02)

  • 删除对Python 3.7的支持。

  • 升级linters和重构各种字符串格式化以及其他清理工作。

  • 升级Cython到最新版本(3.0.10)。

  • Linux wheels现在应该回来了。

  • 将文档主题切换到furo。

3.6.1 (2023-04-26)

  • 添加了对Decimal对象的safe repr支持。

3.6.0 (2023-04-25)

  • 为Python 3.11添加了C扩展支持。这可能会导致所有Python运行时最多10%的性能下降(取决于具体用例)。不幸的是,现在一些兼容层被用于获取帧详情。这是为了能够与Python 3.11兼容并提高未来的兼容性。

  • 为ZoneInfo对象添加了安全的repr支持。

  • C扩展文件现在使用Cython 3.0b2预先构建。

  • 用ruff替换了flake8/isort的pre-commit钩子。

  • 禁用了可编辑的wheel(PEP-0662),因为它们不包括hunter.pth文件。可能会有一种方法来做这件事,但我还没有想出一个方法来在不非常脆弱的解决方案中定制setuptools的内部来修改< cite>editable_wheel命令。

3.5.1 (2022-09-27)

  • 修复了在Ctrl-C时中断的破坏性。

3.5.0 (2022-09-11)

  • 装饰器中添加了对生成器和协程的支持。

  • 不再支持Python 3.6。

3.4.3 (2021-12-15)

  • 删除了大部分Python 2支持代码。

  • 修复了setup.py中的某些重构回归,并使3.4.x系列只能在Python 3.6及以后的版本上安装。

  • 撤回了3.4.0、3.4.1、3.4.2版本,以避免在Python 2.7上安装时出现问题。

3.4.2 (2021-12-15)

  • 修复了CI以正确生成win32 wheel。

3.4.1 (2021-12-14)

  • 添加了对构建pp37.pp38标签的wheel的支持(基本上是一个仅适用于这两个PyPy版本的通用wheel)。

3.4.0 (2021-12-14)

  • 将CI切换到GitHub Actions,这有几个后果

    • 不再支持Python 2.7。您仍然可以安装它,但不再进行测试,并且Python 2特定的处理将在某个时候被删除。

    • Linux wheel现在提供在musllinuxmanylinux2014变体中。

  • 在PyPy上完全跳过了扩展构建。

  • 为PyPy提供了一个纯标签为平台特定wheel(为了在这些平台上快速安装)。

3.3.8 (2021-06-23)

  • 修复了CI问题,该问题会发布两次相同类型的wheel。

3.3.7 (2021-06-23)

  • 修复了在Windows(至少)上检测stdlib时的一个bug。

3.3.6 (2021-06-23)

  • 修复了3.3.4中的回归:stdlib过滤器已损坏。

  • 改进了.pth文件(PYTHONHUNTER环境变量激活)以使用干净的eval环境。不再提供诸如line(来自site.py机制)之类的虚假变量。

  • 修复了VarsSnooper中的一个bug,该bug会在发出双return事件的罕见情况下使其失败。

3.3.5 (2021-06-11)

  • 添加了对Python 3.10的支持。

  • safe_repr中添加了对时间对象和fold选项的支持。

  • 跳过了3.3.4版本,因为我搞砸了CI。

3.3.3 (2021-05-04)

  • 修复了在停止后tracer仍然对其他线程活跃的问题。

    不幸的是,Python只允许移除当前线程的跟踪函数 - 现在hunter.tracer.Tracer如果被标记为已停止,将自行卸载。

    这修复了在使用ipdbhunter.actions.Debugger操作同时启用线程支持(默认)时出现的虚假错误。

3.3.2 (2021-03-25)

  • 将CI更改为构建Python 3.9 wheel。Python 3.5不再进行测试,并且不再构建wheel,以保持简单。

  • 改进了文档。

3.3.1 (2020-10-24)

  • 修复了CI/test问题,这些问题阻止了所有21个wheel的发布。

3.3.0 (2020-10-23)

  • 修复了处理,以便hunter.event.Event.module始终是"?"字符串,而不是None。以前,在跟踪特别糟糕的代码时它是None,这破坏了各种断言。

  • 同样地,如果不可用文件名,hunter.event.Event.filename 现在为 "?"

  • 基于之前的变化,动作代码现在用于显示缺失的模块/文件名更为简洁。

  • 修改了 hunter.actions.CallPrinter,使得内置函数的跟踪事件显示不同。这些事件在使用配置模式(例如:trace(profile=True))时出现。

  • 修复了如果 hunter.event.Event.module 是 Unicode 字符串时可能出现的失败。现在它始终是常规字符串。仅适用于 Python 2。

  • 修复了在跟踪具有元组参数的函数时参数显示的问题。关闭了 #88仅适用于 Python 2。

  • 当发生内部错误时,改进了错误报告。现在记录了触发事件的某些详细信息。

3.2.2 (2020-09-04)

  • 修复了 hunter.event.Event.builtin 中的值问题。现在它始终是布尔值,并且可以在过滤器中一致使用(例如:builtin=True,function='getattr')。

3.2.1 (2020-08-18)

  • safe_repr 中添加了对正则表达式、日期和日期时间的支持。

  • 修复了在 hunter.actions.CallPrinter 中使用位置和关键字参数时调用参数显示的问题。

3.2.0 (2020-08-16)

  • 实现了 hunter.actions.StackPrinter 动作。

  • 实现了 hunter.predicates.Backlog 断言。由 Dan Ailenei 贡献,在 #81

  • 在文档中略微改进了贡献部分。由 Tom Schraitle 贡献,在 #85

  • 通过避免在 hunter.predicates.Backlog 的 Cython 实现中进行大量的不必要的 PyObject_GetAttr 调用来提高过滤性能。

  • 实现了 hunter.actions.ErrorSnooper 动作。

  • 添加了对配置模式(例如:trace(profile=True))的支持。此模式将使用 setprofile 而不是 settrace

  • 添加了 ARM64 轮和 CI。

  • 添加了 hunter.event.Event.instructionhunter.event.Event.builtin(在配置模式下可用)。

  • 添加了更多的食谱条目。

3.1.3 (2020-02-02)

  • 再次改进了 stdlib 检查,以更好地处理某些路径。

3.1.2 (2019-01-19)

  • 真正修复了 <frozen importlib.something stdlib 检查。

3.1.1 (2019-01-19)

  • 将所有 <frozen importlib.something 文件标记为 stdlib 的一部分。

3.1.0 (2019-01-19)

  • 添加了 hunter.actions.ErrorSnooper - 一种检测静默异常的动作。

  • 添加了 hunter.load_config 并修复了从 PYTHONHUNTERCONFIG 环境变量加载配置过晚的问题。

  • 修改了 hunter.From 辅助函数,使其自动将 depthcalls 过滤器移动到断言(这样它们在 hunter.predicates.From 激活后进行过滤)。

  • 修改了 hunter.predicates.From,使其向断言传递事件的副本。该副本将调整 depthcalls 属性,以适应 hunter.predicates.From 激活的点。

  • 修复了在使用断言时使用 &| 运算符时的一堆不一致性和错误。

  • 修复了 detached events <hunter.event.Event.detach>hunter.event.Event.function_objecthunter.event.Event.arg)上的许多损坏字段。

  • 改进了各种文档字符串,并添加了一个配置文档部分。

  • 改进了测试(更多覆盖率)。

3.0.5 (2019-12-06)

  • 真正修复了 safe_repr 以避免副作用(现在避免了 isinstance/issubclass,它们可能导致代码在特殊属性/方法中使用描述符时产生副作用)。

3.0.4 (2019-10-26)

  • 真正修复了操作中的 stream 设置(在没有任何 stream 的情况下使用 force_colors 是错误的)。参见:hunter.actions.ColorStreamAction

  • 修复了 hunter.predicates.From 断言的 __repr__,使其包括 watermark

  • 为 Python 3.8 添加了二进制轮。

3.0.3 (2019-10-13)

  • 在 pypy 上修复了 safe_repr,使其在方法对象上更安全。参见:hunter.actions.ColorStreamAction

3.0.2 (2019-10-10)

  • 修复了从 PYTHONHUNTERCONFIG 环境变量设置 stream 的问题。参见:hunter.actions.ColorStreamAction

  • 修复了一些文档的小问题。

3.0.1 (2019-06-17)

  • 修复了颜色缺失源消息的问题(颜色泄露到下一行)。

3.0.0 (2019-06-17)

  • 该软件包现在使用 setuptools-scm 进行开发构建(可在 https://test.pypi.org/project/hunter/ 获取)。因此,安装 sdist 将会下载 setuptools-scm。

  • 使用最新的 Cython 重新编译了 cython 模块。Hunter 可以像以前一样安装而无需 Cython。

  • 重构了一些 cython 模块,以包含更多类型信息并避免使用已弃用的属性语法。

  • unsafe_repr 选项替换为 repr_func。现在您可以在内置操作中使用自己的自定义 repr 函数。向后不兼容

  • 修复了在 ipython/jupyter 中使用 Hunter 时的错误文件名处理。现在应该可以正确显示源代码。

  • VarsPrinter 操作中移除了 globals 选项。现在始终会查找全局变量。向后不兼容

  • VarsPrinter 操作中添加了对 locals 的支持。现在您可以这样做 VarsPrinter('len(foobar)')

  • 始终传递模块全局字典给 linecache 方法。现在从 PEP-302 载入器中提取的源代码可以正确打印。由 Mikhail Borisov 在 #65 贡献。

  • 进行了各种代码清理、样式和文档字符串修复。

  • 添加了 hunter.From 辅助函数,允许直接作为关键字参数传递过滤器。

  • 添加了 hunter.event.Event.detach,以存储事件而不会泄漏或产生副作用(由于对 Frame 对象、局部或全局变量的长期引用)。

  • 重构了操作内部,以简化子类化。

    hunter.actions.ColorStreamAction 基类添加了 hunter.actions.ColorStreamAction.filename_prefixhunter.actions.ColorStreamAction.outputhunter.actions.ColorStreamAction.pid_prefixhunter.actions.ColorStreamAction.thread_prefixhunter.actions.ColorStreamAction.try_reprhunter.actions.ColorStreamAction.try_source 方法。

  • 添加了 hunter.actions.VarsSnooper - 这是 PySnooper 启发的 hunter.actions.VarsPrinter 变体。它将记录并显示变量更改,当然,有泄漏或使用过多内存的风险:)

  • 修复了 tracers,以记录错误并在内部失败时自动停止。以前在某些情况下可能错误地静默地丢弃了错误。

2.2.1 (2019-01-19)

  • 修复了更改日志中的链接。

  • 修复了 Travis 配置中的一些问题。

2.2.0 (2019-01-19)

  • 添加了 hunter.predicates.From 断言,用于从特定点进行跟踪。它在返回到相同的调用深度并具有可配置偏移量后停止。

  • 修复了在某些情况下 PYTHONHUNTERCONFIG 不工作的问题(配置值在错误的时间被解析)。

  • 在CI测试中对即将发布到PyPI的轮进行了测试(tox-wheel)。

  • 增强了event.stdlib的可靠性:将pkg_resources视为标准库的一部分,并将更多路径视为标准库。

  • 降低了使用hunter-trace CLI(通过hunter.remote.install())附加时进行的get_peercred检查的难度。这会稍微降低安全性,但可以在OSX上工作。

  • 在Travis测试网格中添加了OSX。

2.1.0 (2018-11-17)

  • 默认启用threading_support,但输出自动(此外,现在允许使用10)。

  • 添加了显示pid前缀的pid_alignmentforce_pid操作选项。

  • 修复了各种类中关于__eq__的一些错误。

  • 停止支持Python 3.3。

  • 删除了对fields的依赖。

  • 操作现在使用简化的实现来表示,该实现试图避免在跟踪时调用用户类的__repr__,以避免创建副作用。

  • 添加了对PYTHONHUNTERCONFIG环境变量的支持(存储默认值并不激活hunter)。

2.0.2 (2017-11-24)

  • 修复了hunter.actions.CallPrinter操作中的缩进问题(在异常时不应该缩进)。

  • 修复了Cython查询实现中的选项过滤(错误地允许对tracer进行过滤)。

  • 修复了文档字符串和文档的多个问题。

2.0.1 (2017-09-09)

  • 现在使用Py_AddPendingCall代替获取GIL(当使用GDB时)。

2.0.0 (2017-09-02)

  • 添加了hunter.event.Event.counthunter.event.Event.calls属性。

  • 添加了lt/lte/gt/gte查找。

  • startswithsw)、endswithew)、containshas)和regexrx)添加了便利别名。

  • 添加了一个便利的hunter.wrap装饰器,用于在函数周围开始跟踪。

  • 通过hunter-trace二进制文件添加了对远程跟踪的支持(使用两个后端:manhole和GDB)。注意:**Windows不支持**。

  • 将默认操作更改为hunter.actions.CallPrinter。如果您想使用旧输出,则需要使用action=CodePrinter

1.4.1 (2016-09-24)

  • 修复了对Cython模块获取源的支持(在Windows和Python3.5+上已损坏)。

1.4.0 (2016-09-24)

  • 添加了对跟踪Cython模块的支持(#30)。Cython模块需要包含# cython: linetrace=True或等效语句才能正常工作。

1.3.0 (2016-04-14)

  • 添加了hunter.event.Event.thread

  • 添加了hunter.event.Event.threadidhunter.event.Event.threadname(可用于通过hunter.Q进行过滤)。

  • hunter.event.Event.threading_support参数添加到hunter.trace。它使新线程被跟踪,并将操作输出更改为包括线程名称。

  • hunter.actions.Debugger操作中添加了对使用pdb++的支持。

  • 通过新的hunter.actions.Manhole操作添加了对使用manhole的支持。

  • hunter.event.Event.handler作为一个公共但只读属性。

1.2.2 (2016-01-28)

  • 修复了损坏的导入。需要fields>=4.0

  • 简化了Cython代码中的字符串检查。

1.2.1 (2016-01-27)

  • 修复 hunter.actions.CallPrinter 中的 “KeyError: ‘normal’” 错误。从 COLOR 字典创建 NO_COLORS 字典。一些键缺失。

1.2.0 (2016-01-24)

  • 修复了返回非常长字符串的对象的打印输出(在 __repr__() 中)。已截断为 512 字节。可以通过 repr_limit 选项在 actions 中配置。

  • 改进了 hunter.actions.VarsPrinter 的初始化验证。

  • 添加了 hunter.actions.CallPrinter 动作。

1.1.0 (2016-01-21)

  • 为 Cython 跟踪器实现了析构函数(__dealloc__)。

  • 改进了 Cython 跟踪器中恢复先前跟踪器的功能(直接使用 PyEval_SetTrace)。

  • hunter.Query 中移除了 tracer 作为允许的过滤参数。

  • 为传递到 hunter.Q 的位置参数和动作添加了基本验证(必须可调用)。关闭 #23

  • 修复了 stdlib 检查(可靠性不高)。关闭 #24

1.0.2 (2016-01-05)

  • 修复了 setup.py 中的缺失导入。

1.0.1 (2015-12-24)

  • 修复了与 MSVC 编译器的编译问题(似乎它不喜欢 fast_When_call 上的内联选项)。

1.0.0 (2015-12-24)

  • 在 Cython 中实现了快速跟踪器和查询对象。**可能不向后兼容**

    要强制使用旧的纯 Python 实现,请将 PUREPYTHONHUNTER 环境变量设置为非空值。

  • 添加了过滤运算符:containsstartswithendswithin。示例

    • Q(module_startswith='foo' 将匹配来自 foofoo.barfoobar 的事件。

    • Q(module_startswith=['foo', 'bar'] 将匹配来自 foofoo.barfoobarbarbar.foobaroo 的事件。

    • Q(module_endswith='bar' 将匹配来自 foo.barfoobar 的事件。

    • Q(module_contains='ip' 将匹配来自 lipsum 的事件。

    • Q(module_in=['foo', 'bar'] 将匹配来自 foobar 的事件。

    • Q(module_regex=r"(re|sre.*)\b") 将匹配来自 rere.foobarsrefoobar 的事件,但不匹配来自 repr 的事件。

  • 移除了 merge 选项。现在,当多次调用 hunter.trace(...) 时,只有最后一个有效。**可能不向后兼容**

  • 移除了 previous_tracer 的处理。现在,当调用 hunter.trace(...) 时,将禁用先前的跟踪器(sys.gettrace() 中的任何内容),并在调用 hunter.stop() 时恢复。**可能不向后兼容**

  • 修复了 CodePrinter 以在无法获取任何源时显示模块名称。

0.6.0 (2015-10-10)

  • 在跟踪器上添加了 clear_env_var 选项(在子进程中禁用跟踪)。

  • hunter.actions.VarsPrinterhunter.actions.CodePrinter 上添加了 force_colors 选项。

  • 允许将 stream 设置为文件名(在 hunter.actions.VarsPrinterhunter.actions.CodePrinter 上有选项)。

  • 将文件名对齐增加到 40 列。

  • 如果不合并,则self不再作为之前的追踪器保留。解决了#16

  • 修复了VarsPrinter的处理方式:正确打印eval错误,并在发生AttributeError时不要尝试显示任何内容。解决了#18

  • 添加了一个stdlib布尔标志(用于过滤目的)。解决了#15

  • 修复了文件名或模块为“None”的损坏帧(这样它们仍然可以被视为字符串)。

  • 修复了install_lib命令的输出文件,以便pip可以卸载.pth文件。这仅在用pip安装时有效(遗憾的是,setup.py install/developpip install -e仍然会在pip卸载hunter时留下.pth垃圾)。

0.5.1 (2015-04-15)

  • 修复了,使其实际上是全局变量的dict(它只是局部变量)。

0.5.0 (2015-04-06)

  • 修复了的“单参数解包”。

  • 实现了谓词压缩。例如:Or(Or(a, b), c)被转换为Or(a, b, c)

  • 重命名为

  • 添加了一个,它不进行任何花哨的源代码标记。

  • 修复了tokenizer失败情况下的返回值。

  • 在PYTHONHUNTER环境变量有效负载中提供了打印函数。

  • 添加了__repr__。

0.4.0 (2015-03-29)

  • 为Jython禁用了颜色。由Claudiu Popa在#12中贡献。

  • 为Windows测试套件修复了问题。由Claudiu Popa在#11中贡献。

  • 在文档中添加了介绍部分。

  • 实现了一个更漂亮的回退,用于在没有可用源的情况下处理该帧。

  • 实现了将动作类用作谓词的情况下的修复。

0.3.1 (2015-03-29)

  • 忘记合并一些提交……

0.3.0 (2015-03-29)

  • 添加了对内部repr失败的处理。

  • 修复了显示非ascii字符代码的问题。

  • 实现了对调用帧的更好显示,以便当函数有装饰器时显示函数定义(而不仅仅是第一个装饰器)。参见:#8

0.2.1 (2015-03-28)

  • 为异常事件添加了缺少的颜色条目。

  • 添加了属性。它返回正在运行的源代码的行。

0.2.0 (2015-03-27)

  • 添加了颜色支持(以及colorama作为依赖项)。

  • 添加了对表达式的支持。

  • 破坏性更改

    • 重命名为。现在只是的便利包装。

    • 将PYTHON_HUNTER环境变量重命名为PYTHONHUNTER。

    • 更改为接受位置参数。

    • 将输出更改为显示2个路径组件(仍然不可配置)。

    • 更改为接受名称的位置参数。

  • 改进了环境变量激活的错误报告(PYTHONHUNTER)。

  • 修复了使用setup.py install(“egg安装”)和setup.py develop/pip install -e(“egg链接”)安装环境变量激活器(.pth文件)。

0.1.0 (2015-03-22)

  • 在PyPI上的第一次发布。

项目详细信息


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。

源代码分发

hunter-3.7.0.tar.gz (672.6 kB 查看哈希值)

上传时间 源代码

构建分发

hunter-3.7.0-pp310.pp38.pp39-none-any.whl (52.7 kB 查看哈希值)

上传时间 PyPy

hunter-3.7.0-cp312-cp312-win_amd64.whl (279.4 kB 查看哈希值)

上传时间 CPython 3.12 Windows x86-64

hunter-3.7.0-cp312-cp312-win32.whl (241.1 kB 查看哈希值)

上传时间 CPython 3.12 Windows x86

hunter-3.7.0-cp312-cp312-musllinux_1_1_x86_64.whl (1.8 MB 查看哈希值)

上传时间 CPython 3.12 musllinux: musl 1.1+ x86-64

hunter-3.7.0-cp312-cp312-musllinux_1_1_aarch64.whl (1.8 MB 查看哈希值)

上传时间 CPython 3.12 musllinux: musl 1.1+ ARM64

hunter-3.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.8 MB 查看哈希值)

上传于 CPython 3.12 manylinux: glibc 2.17+ x86-64

hunter-3.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.8 MB 查看哈希值)

上传于 CPython 3.12 manylinux: glibc 2.17+ ARM64

hunter-3.7.0-cp312-cp312-macosx_11_0_arm64.whl (296.7 kB 查看哈希值)

上传于 CPython 3.12 macOS 11.0+ ARM64

hunter-3.7.0-cp311-cp311-win_amd64.whl (282.4 kB 查看哈希值)

上传于 CPython 3.11 Windows x86-64

hunter-3.7.0-cp311-cp311-win32.whl (242.3 kB 查看哈希值)

上传于 CPython 3.11 Windows x86

hunter-3.7.0-cp311-cp311-musllinux_1_1_x86_64.whl (1.8 MB 查看哈希值)

上传于 CPython 3.11 musllinux: musl 1.1+ x86-64

hunter-3.7.0-cp311-cp311-musllinux_1_1_aarch64.whl (1.7 MB 查看哈希值)

上传于 CPython 3.11 musllinux: musl 1.1+ ARM64

hunter-3.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.7 MB 查看哈希值)

上传于 CPython 3.11 manylinux: glibc 2.17+ x86-64

hunter-3.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.7 MB 查看哈希值)

上传于 CPython 3.11 manylinux: glibc 2.17+ ARM64

hunter-3.7.0-cp311-cp311-macosx_11_0_arm64.whl (295.3 kB 查看哈希值)

上传于 CPython 3.11 macOS 11.0+ ARM64

hunter-3.7.0-cp310-cp310-win_amd64.whl (282.1 kB 查看哈希值)

上传于 CPython 3.10 Windows x86-64

hunter-3.7.0-cp310-cp310-win32.whl (242.7 kB 查看哈希值)

上传于 CPython 3.10 Windows x86

hunter-3.7.0-cp310-cp310-musllinux_1_1_x86_64.whl (1.6 MB 查看哈希值)

上传于 CPython 3.10 musllinux: musl 1.1+ x86-64

hunter-3.7.0-cp310-cp310-musllinux_1_1_aarch64.whl (1.6 MB 查看哈希值)

上传于 CPython 3.10 musllinux: musl 1.1+ ARM64

hunter-3.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.6 MB 查看哈希值)

上传于 CPython 3.10 manylinux: glibc 2.17+ x86-64

hunter-3.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.6 MB 查看哈希值)

上传于 CPython 3.10 manylinux: glibc 2.17+ ARM64

hunter-3.7.0-cp310-cp310-macosx_11_0_arm64.whl (295.3 kB 查看哈希值)

上传于 CPython 3.10 macOS 11.0+ ARM64

hunter-3.7.0-cp39-cp39-win_amd64.whl (283.0 kB 查看哈希值)

上传于 CPython 3.9 Windows x86-64

hunter-3.7.0-cp39-cp39-win32.whl (244.0 kB 查看哈希值)

上传于 CPython 3.9 Windows x86

hunter-3.7.0-cp39-cp39-musllinux_1_1_x86_64.whl (1.6 MB 查看哈希值)

上传于 CPython 3.9 musllinux: musl 1.1+ x86-64

hunter-3.7.0-cp39-cp39-musllinux_1_1_aarch64.whl (1.6 MB 查看哈希值)

上传于 CPython 3.9 musllinux: musl 1.1+ ARM64

hunter-3.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.6 MB 查看哈希值)

上传于 CPython 3.9 manylinux: glibc 2.17+ x86-64

hunter-3.7.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.6 MB 查看哈希)

上传时间 CPython 3.9 manylinux: glibc 2.17+ ARM64

hunter-3.7.0-cp39-cp39-macosx_11_0_arm64.whl (296.7 kB 查看哈希)

上传时间 CPython 3.9 macOS 11.0+ ARM64

hunter-3.7.0-cp38-cp38-win_amd64.whl (283.6 kB 查看哈希)

上传时间 CPython 3.8 Windows x86-64

hunter-3.7.0-cp38-cp38-win32.whl (243.6 kB 查看哈希)

上传时间 CPython 3.8 Windows x86

hunter-3.7.0-cp38-cp38-musllinux_1_1_x86_64.whl (1.8 MB 查看哈希)

上传时间 CPython 3.8 musllinux: musl 1.1+ x86-64

hunter-3.7.0-cp38-cp38-musllinux_1_1_aarch64.whl (1.7 MB 查看哈希)

上传时间 CPython 3.8 musllinux: musl 1.1+ ARM64

hunter-3.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.7 MB 查看哈希)

上传时间 CPython 3.8 manylinux: glibc 2.17+ x86-64

hunter-3.7.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.7 MB 查看哈希)

上传时间 CPython 3.8 manylinux: glibc 2.17+ ARM64

hunter-3.7.0-cp38-cp38-macosx_11_0_arm64.whl (296.7 kB 查看哈希)

上传时间 CPython 3.8 macOS 11.0+ ARM64

支持者

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面