为什么 pydevd 断点在回调中不起作用?

问题描述 投票:0回答:1

我已经在 VS Code 和 PyCharm 中尝试过此操作,并且两者的行为方式相同。我有一个使用

pyads
的 python 应用程序,但我不确定
pyads
有什么特别有趣的地方。问题是,在任一 IDE 中,如果我在将作为
pyads
回调/通知执行的行上放置断点,代码会执行但不会中断。

对于

pyads
,我为特定 PLC 标签设置了通知。这会将回调函数与该标记关联起来,因此如果标记的值发生更改,我的回调就会执行。
pyads
只是
TcAdsDll.dll
的包装,看起来
pyads
使用
ctypes
来完成很多繁重的工作。当我在回调中放置断点并在 VS Code 或 PyCharm(两者都使用 pydevd)中运行代码时,代码会执行,但断点不会被命中。

此外,当我在应用程序中的不同位置打印进程 ID、线程 ID 和堆栈跟踪时,我可以看到进程 ID 相同,但在

pyads
回调中线程 ID 不同。堆栈跟踪特别有趣。在
pyads
回调之外,调用链如下所示:

runpy.py -> __main__.py -> cli.py -> pydevd_runpy.py -> my actual code

在回调内部,调用链看起来像这样

pyads\pyads_ex.py -> my callback

我对 pydevd 不太了解,但我知道所有

runpy.py -> __main__.py -> cli.py -> pydevd_runpy.py
的事情都是由 VS Code 完成的,用于设置调试器。我希望(尽管很容易出错)pydevd 也需要成为回调中调用链的一部分才能使我的断点起作用。

有谁对此有更多的见解,或者有什么我完全误解的吗?关于如何在这样的回调中设置断点有什么想法吗?谢谢!

编辑 07/06/2023 08:19 AM:

我的 VS Code 启动配置非常基本:

{
    "name": "run-my-thing",
    "type": "python",
    "request": "launch",
    "program": "${workspaceFolder}/run-my-thing.py",
    "console": "integratedTerminal",
    "justMyCode": true
}
python visual-studio-code dll pycharm twincat-ads
1个回答
0
投票

你说得对:

pyads
ctypes
模块包装你的回调,它从C DLL中调用,我猜Python调试器不会拾取它。

我设法用两种不同的方法打破了回调:

  1. With
    breakpoint()
    :通过将其添加为回调中的代码,会弹出带有
    pdb
    的控制台,可以在其中进行控制台调试。然而,这似乎不能与 PyCharm 一起使用。
  2. 通过设置
    pydevd.settrace()
    :使用 PyCharm 调试器可以实现
要扩展 2,请在每个回调线程内显式设置跟踪,断点将正常工作。

一个完整的例子:

from pyads import Connection import pyads from time import sleep import threading import multiprocessing import traceback import sys try: import pydevd except ModuleNotFoundError: pydevd = None def print_info(): print("Trace:", threading.gettrace()) print("Thread ID:", threading.get_ident()) print("PID:", multiprocessing.current_process().pid) print("Callstack:") traceback.print_stack(file=sys.stdout) print() def main(): plc = Connection( ams_net_id="169.254.83.50.1.1", ams_net_port=851, ip_address="192.168.56.10", ) print_info() @plc.notification(pyads.PLCTYPE_UDINT) def my_callback(handle, name, timestamp, value): if pydevd: pydevd.settrace() print("New value:", value) print_info() with plc: symbol = plc.get_symbol("MAIN.counter") symbol.add_device_notification(my_callback) sleep(10) return if __name__ == "__main__": main()
    
© www.soinside.com 2019 - 2024. All rights reserved.