从含有serial_for_url的脚本中提取可执行文件

1 投票
2 回答
1744 浏览
提问于 2025-04-18 12:50

我写了一个Python脚本,用来和一个数字泵进行串行通信。现在我想把它做成一个可执行文件。不过,虽然在用Python运行时一切都很好,而用py2exe生成的.exe文件也没问题,但当我运行这个可执行文件时,出现了以下错误:

File: pump_model.pyc in line 96 in connect_new
File: serial\__init__.pyc in line 71 in serial_for_url
ValueError: invalid URL protocol 'loop' not known

我代码中相关的部分是这样的: # 新的串行连接 def connect_new(self, port_name): """配置新的串行连接的函数。"""

    try:
        self.ser = serial.Serial(port = port_name,\
                baudrate = 9600,\
                parity = 'N',\
                stopbits = 1,\
                bytesize = 8,\
                timeout = self.timeout_time)
    except serial.SerialException:
        self.ser = serial.serial_for_url('loop://',\
              timeout = self.timeout_time) # This line BLOWS!
    except:
        print sys.exc_info()[0]

    finally:
        self.initialize_pump()

我需要说明的是,这个应用是在OSX上写的,并且在Windows上用Canopy Python Distribution进行了测试。

2 个回答

3

我遇到的问题和“socket://”一样,而不是“loop://”。

不过我没能让大家推荐的解决办法奏效,但下面的方法似乎成功了:

1) 明确导入有问题的 urlhandler.* 模块。

import serial

# explicit import for py2exe - to fix "socket://" url issue
import serial.urlhandler.protocol_socket 

# explicit import for py2exe - to fix "loop://" url issue (OP's particular prob)
import serial.urlhandler.protocol_loop

# use serial_for_url in normal manner
self._serial = serial.serial_for_url('socket://192.168.1.99:12000')

2) 为 py2exe 生成一个设置脚本(可以参考 https://pypi.python.org/pypi/py2exe/)—— 我是在一个虚拟环境中安装了 py2exe:

path\to\env\Scripts\python.exe -m py2exe myscript.py -W mysetup.py

3) 编辑 mysetup.py 文件,加入选项。

zipfile="library.zip" # default generated value is None

(也可以查看 http://www.py2exe.org/index.cgi/ListOfOptions

4) 构建它:

path\to\env\Scripts\python.exe mysetup.py py2exe

5) 运行它。

dist\myscript.exe
0

找到了!

看起来由于某种原因,'loop://'这个参数在生成.exe文件后无法被识别。

我通过研究pyserial/init.py这个脚本发现,当你发出命令serial.serial_for_url(‘loop://')时,实际上是在调用: sys.modules['serial.urlhandler.protocol_loop’].Serial(“loop://“)

所以你需要先导入serial.urlhandler.protocol_loop,然后用这个命令替代那个出问题的命令。

这样你现在可以输入:

__import__('serial.urlhandler.protocol_loop')
sys.modules[‘serial.urlhandler.protocol_loop’].Serial("loop://")

经过这个小小的变通后,一切正常了。

撰写回答