如何重新编写此python代码以在pyinstaller生成的exe中工作?

时间:2018-12-17 04:24:46

标签: python pyinstaller

PyInstaller 3.4
Python 3.7
赢7-64位

我使用.exe从python代码中制作了PyInstaller,它具有以下逻辑。目标是在Windows的新控制台窗口中启动http服务器。这是为了避免锁定/阻止主应用程序,并且用户在使用完http服务器后,只需关闭新启动的控制台窗口即可。

p = subprocess.call('start "" python  -m http.server --directory {} {} --bind {}'.format(web_server_path, web_server_port, web_bind_ip), shell=True)

这在安装了Python的Windows PC上有效,但在没有Python的PC上自然不可用。

由于目标是将此.exe分发给没有安装python的用户,有人可以推荐正确的方法来在PyInstaller中使用Python来完成上述行为吗?我知道PyInstaller生成的.exe实际上正在运行Python解释器,但是我不知道如何使用我的代码来使用它。

UPDATE
要求用户能够设置directoryportaddress。理想情况下,只需关闭一个窗口就可以很容易地停止它(因此采用原始的命令行方法),但是可以更改。

进一步更新
是否可以加载python3.dll并以某种方式直接使用其功能? ctypes.WinDLL('Path:\to\my.dll')

1 个答案:

答案 0 :(得分:1)

由于示例代码可能会启动Web服务器而不会阻止脚本的进一步执行,因此您希望在单独的线程上运行Web服务器。

from sys import version_info
import http.server
import socketserver
from threading import Thread


class WebServer(Thread):
    @staticmethod
    def get_directory_simple_http_request_handler(directory):
        _current_only = version_info < (3, 7)

        class _DirectorySimpleHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
            _current_only = version_info < (3, 7)

            def __init__(self, *args, **kwargs):
                if not self._current_only:
                    kwargs['directory'] = directory
                super(_DirectorySimpleHTTPRequestHandler, self).__init__(*args, **kwargs)

            @property
            def current_only(self):
                return self._current_only

        return _DirectorySimpleHTTPRequestHandler

    def __init__(self, address='127.0.0.1', port=8000, directory=''):
        self.handler = self.get_directory_simple_http_request_handler(directory)
        self.httpd = socketserver.TCPServer((address, port), self.handler)
        Thread.__init__(self)

    def run(self):
        self.httpd.serve_forever()

    def join(self, *args, **kwargs):
        self.httpd.shutdown()
        super().join(*args, **kwargs)


web_server = None
while True:
    if web_server is None:
        print('Currently not running (type start or exit).')
    else:
        print('Running on:', web_server.httpd.server_address, '(type stop or exit)')
        if web_server.handler.current_only:
            print('Serving current directory, Python <3.7 has no `directory` on SimpleHTTPRequestHandler.')

    command = input('>')

    if command == 'start':
        if web_server is None:
            web_server = WebServer(directory=r'C:\Temp')
            web_server.start()
    if command == 'stop':
        if web_server is not None:
            web_server.join()
            web_server = None
    if command == 'exit':
        exit(0)

请注意,Python 3.7是第一个支持directory参数的版本,早期版本的Python仅会为该进程提供当前目录。

可以使用工厂静态方法来设置SimpleHTTPRequestHandler的单独实例,并使用所需目录对其进行初始化。

如果您实际上希望仅启动控制台窗口,请运行Python(测试)Web服务器(或其他外部服务器,如果Python不可用):

import time
from subprocess import Popen, CREATE_NEW_CONSOLE

proc = Popen(['python', '-m', 'http.server', '8000'],
             cwd=r'C:\temp',
             creationflags=CREATE_NEW_CONSOLE, close_fds=True)

while True:
    print('Running')
    time.sleep(2)

类似地,如果您喜欢安静的环境,但是不需要访问Web服务器对象,那么它也可以工作:

import time
from subprocess import Popen

proc = Popen(['python', '-m', 'http.server', '8000'], close_fds=True, cwd=r'C:\temp')

while True:
    print('Running')
    time.sleep(2)