【问题标题】:Launch Python debugger while simultaneously executing module as script启动 Python 调试器,同时将模块作为脚本执行
【发布时间】:2013-08-12 13:07:34
【问题描述】:

在开发 Python 包时,使用-m 选项将包内的模块作为脚本运行以进行快速测试非常方便。例如,对于 somepackage 内部有模块 somemodule.py,调用

python -m somepackage.somemodule

somepackage 所在的目录运行somemodule.py,就好像子模块是__main__。如果包使用如here 所述的显式相对导入,则使用此调用语法尤其重要。

同样,使用-m选项调试脚本也很方便,如

python -m pdb somescript.py

有没有办法同时做这两个?也就是说,我可以像调用脚本一样调用模块并同时启动到调试器中吗?我意识到我可以进入代码本身并在我想要中断的地方插入import pdb; pdb.set_trace(),但我试图避免这种情况。

【问题讨论】:

    标签: python pdb


    【解决方案1】:

    effortsunderway 可以在Python 本身中解决这个问题。看起来像 Python 3.7,你可以这样做:

    python -m pdb -m somepackage.somemodule
    

    我已经为较旧的 Python 版本(2.7+)提供了a backport

    pip install backports.pdb
    python -m backports.pdb -m somepackage.somemodule
    

    【讨论】:

    • python -m pdb -m path.to.module 在 python 3.9.5 中非常适合我
    【解决方案2】:

    经过一段时间的试验,结果证明这种方法确实有效:

    python -c "import runpy; import pdb; pdb.runcall(runpy.run_module, 'somepackage.somemodule', run_name='__main__')"
    

    出于某种原因,使用pdb.runcall 而非pdb.run 很重要。

    【讨论】:

    • pdb.run 需要一个字符串,而不是可调用的。 python -c "import runpy; import pdb; pdb.run(\"runpy.run_module( 'somepackage.somemodule', run_name='__main__')\")" 也可以,但是比较麻烦
    【解决方案3】:

    基于@jed 的回答,我构建了这个模块:

    import pdb
    import runpy
    import sys
    
    
    def main():
        module = sys.argv[1]
        sys.argv[1:] = sys.argv[2:]
        pdb.runcall(runpy.run_module, module, run_name='__main__')
    
    
    __name__ == '__main__' and main()
    

    将该模块作为 mpdb.py 放在 Python 路径中的任何位置(当前目录有效),然后您可以调用:

    python -m mpdb somepackage.somemodule even with args
    

    【讨论】:

      【解决方案4】:

      这是另一个也适用于命令行参数的选项。

      将脚本的逻辑包装在main 函数中通常是个好主意。然后你可以让main 接受一个可选的参数列表来覆盖sys.argv。这是一个名为argdemo.py的示例:

      def main(cmd_line_args=None):
          import argparse
      
          parser = argparse.ArgumentParser()
          parser.add_argument("number", help="a number", type=int)
      
          # allow cmd_line_args to override sys.argv
          if cmd_line_args is None:
              args = parser.parse_args()
          else:
              args = parser.parse_args(cmd_line_args)
      
          print("The number is {}".format(args.number))
      
      if __name__ == '__main__':
          main()
      

      这个模块可以照常运行:

      $ python -m argdemo 2
      > The number is 2
      

      或者可以直接调用main(),使用pdb运行:

      $ python -c "import pdb; import argdemo; pdb.runcall(argdemo.main, ['2'])"
      (Pdb) continue
      > The number is 2
      

      (注意cmd_line_args 必须是字符串列表,就像argv 一样)。

      作为额外的奖励,当您的模块具有可导入的 main 函数时,您可以以相同的方式为其编写单元测试 =)

      【讨论】:

        【解决方案5】:

        这对我有用(使用 -m 选项将 python 模块作为脚本调试)

        我创建了一个草稿

        import runpy
        
        if __name__ == '__main__':
            runpy.run_module('somepackage.somemodule', run_name="__main__", alter_sys=True)
        

        想法来自:Intellij/Pycharm can't debug Python modules

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多