从嵌入式Python安装中打开一个REPL

4
我正在使用一款软件,它自带嵌入式 (embedded) 版本的IronPython。这个IP是为了让用户编写能与程序API互动的.py脚本。 在程序安装目录中没有可用的ipy.exe或python.exe文件,只有各种IronPython DLL文件。标准库完全可用。 没有交互式命令行可用。我真的需要调试我的代码,并使用比纯文本弹出窗口更强大的工具,但是当我尝试使用调试器时,这个程序就挂起了。
import pdb;pdb.set_trace()

如果有一段代码,我可以将其放入这些.py模块中之一,以启动当前python会话的命令行REPL,那就太好了。我尝试过使用code模块从SO获取解决方案,但它不起作用。能做到吗?

1
这个有帮助吗?https://dev59.com/W3M_5IYBdhLWcg3wZSPX 看看第二个答案。 - MattDMo
@MattDMo 我特别说明了我尝试过使用代码模块的解决方案,但它不起作用。REPL窗口没有启动。 - Rick
请详细说明“不工作”的情况。是否有异常?还是运行时没有任何可见控制台输入?它是否接受键盘输入? - Kroshka Kartoshka
2个回答

4

由于某些原因,使用FIFO功能无法正常工作,因此我实施了这种奇怪的方法。 它使用文件在控制器实例(仅从终端运行)和在从任何地方调用的不同代码之间进行通信。 还使用猴子补丁将我们的新set_trace添加到pdb中。

import time
import pdb


IN_FILE = "in.pdb"
OUT_FILE = "out.pdb"


class _Receiver(object):
    def __init__(self, in_file):
        self.in_file = in_file
        with open(in_file, "w") as file:
            file.write("")

    def readline(self):
        x = ""
        while x == "":
            time.sleep(0.1)
            with open(self.in_file, "r") as file:
                x = file.readline()

        with open(self.in_file, "w") as file:
            file.write("")

        return x


class _Sender(object):
    def __init__(self, out_file):
        self.out_file = out_file
        with open(out_file, "w") as file:
            file.write("")

    def write(self, x):
        with open(self.out_file, "a") as file:
            file.write(x)

    def flush(self):
        pass


mypdb = pdb.Pdb(stdin=_Receiver(in_file=IN_FILE),
                stdout=_Sender(out_file=OUT_FILE))

pdb.set_trace = mypdb.set_trace

使用断点在其他代码中:

from youcannameit import pdb

pdb.set_trace()

要连接到pdb,请在cmd中运行主批处理脚本。它的效果还不错,但不如bash版本好,因此我会将其留在那里以防您选择使用它。您不能使用CRT-C类型的q退出。一旦退出,建议打开一个新的cmd,因为在同一个cmd中再次运行会非常有bug。也许有更多批处理知识的人能够修复它。

主批处理脚本:

@echo off

set IN_FILE="in.pdb"
set OUT_FILE="out.pdb"
set LOCK="lock.lock"

echo running > %LOCK%
start /b read.cmd
timeout 1 /NOBREAK >NUL
echo PDB:
goto :write_pdb


:print_file
type %OUT_FILE%
timeout 1 /NOBREAK >NUL
NUL > %OUT_FILE% 2>NUL
goto :read_pdb


:read_pdb
for /f %%i in (%OUT_FILE%) do set size=%%~zi
if %size% gtr 0 goto :print_file
timeout 1 /NOBREAK >NUL
goto :read_pdb


:write_pdb
set /P INPUT=%=%
echo %INPUT% > %IN_FILE%
If /I "%Input%"=="q" goto :end
If /I "%Input%"=="quit" goto :end
If /I "%Input%"=="exit" goto :end
goto :write_pdb


:end
del %LOCK%
echo Exiting..
EXIT /B 0

这是第二个批处理脚本,可以同时打印和输入(将其命名为read.cmd并放在与主脚本相同的文件夹中):

@echo off

set IN_FILE="in.pdb"
set OUT_FILE="out.pdb"
set LOCK="lock.lock"

goto :read_pdb


:print_file
type %OUT_FILE%
timeout 1 /NOBREAK >NUL
NUL > %OUT_FILE% 2>NUL
goto :read_pdb


:read_pdb
if not exist %LOCK% goto :end
for /f %%i in (%OUT_FILE%) do set size=%%~zi
if %size% gtr 0 goto :print_file
timeout 1 /NOBREAK >NUL
goto :read_pdb

:end

如果您坚持使用Bash版本:
#!/bin/bash

IN_FILE="in.pdb"
OUT_FILE="out.pdb"

echo PDB:

# trap ctrl-c and call ctrl_c()
trap ctrl_c INT

function ctrl_c() {
    kill $READER >/dev/null 2>&1
    exit 1
}

read_pdb(){
    while true
    do
        if [ -s $OUT_FILE ]
        then
            cat $OUT_FILE
            sleep 0.05
            > $OUT_FILE
        fi
    done
}

write_pdb(){
    while true
    do
        sleep 0.1
        read user_inp
        echo $user_inp > $IN_FILE

        if [ "$user_inp" == "q" ];
        then
            kill $READER >/dev/null 2>&1
            exit 1
        fi
    done
}

read_pdb &
READER=$!
write_pdb

要在终端连接到断点,只需执行bash脚本。您必须确保路径(IN_FILEOUT_FILELOCK)是您的系统上的实际路径。


这看起来很有前途!但由于它是IronPython,我们只能在Windows上运行,没有Bash可用...不过我喜欢这个概念。 - Rick
我的意思是我会看看将其翻译成批处理脚本有多难。 - Hadus
1
这里有一个批处理版本。虽然不是很好,但我认为足够好用了。 - Hadus
1
我只是没有时间尝试它。其他项目优先级更高。我通常也会让我的赏金完全过期,然后等到最后一刻再颁发,以防还有其他人有额外的有用意见。 - Rick
1
可能会让这个回答复活,但是+1因为第一次看到使用“Monkey Patching”这个术语。 - CaffeineDependent
显示剩余2条评论

0

请尝试这个方法并报告是否有效:

import code
code.InteractiveConsole(locals=globals()).interact()

它运行一个普通的Python控制台:

$ python3 ./temp.py
Python 3.6.9 (default, Jul 17 2020, 12:50:27)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>

正如我在问题中已经解释过的那样,这个解决方案不会起作用。 - Rick
代码运行正常,但没有REPL窗口出现。执行脚本的主程序一直挂起等待脚本退出,但它从未退出。因此,我不得不强制退出程序。 - Rick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接