溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Pyinstaller打包eel和pygame需要注意什么坑

發(fā)布時間:2022-02-11 09:05:41 來源:億速云 閱讀:137 作者:iii 欄目:開發(fā)技術

本文小編為大家詳細介紹“Pyinstaller打包eel和pygame需要注意什么坑”,內容詳細,步驟清晰,細節(jié)處理妥當,希望這篇“Pyinstaller打包eel和pygame需要注意什么坑”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。

1、打開cmd / Visual Studio等等可以裝包的工具下載pyinstaller

如果是python環(huán)境,那么:pip install pyinstaller;如果是conda環(huán)境,那么:conda install pyinstaller

2、找到你的python_main程序

假設項目根目錄為F:\xx\xx\xx,該目錄的文件管理如下:

	- Web(包括HTML、CSS、JS)
	- 游戲資源文件夾 (包括圖片巴拉巴拉的)
	- Class1.py (Class1中導入Class3)
	- Class2.py
	- Class3.py
	- Python_Main.py (Python_Main中導入Class1,Class2和eel)

3、查看eel庫

eel庫一般在site-pakages里

Pyinstaller打包eel和pygame需要注意什么坑

打開__main__.py文件

#eel的__main__.py文件
from __future__ import print_function
import sys
import pkg_resources as pkg
import PyInstaller.__main__ as pyi
import os
args = sys.argv[1:]
main_script = args.pop(0)
web_folder = args.pop(0)
print("Building executable with main script '%s' and web folder '%s'...\n" %
      (main_script, web_folder))
eel_js_file = pkg.resource_filename('eel', 'eel.js')
js_file_arg = '%s%seel' % (eel_js_file, os.pathsep)
web_folder_arg = '%s%s%s' % (web_folder, os.pathsep, web_folder)
needed_args = ['--hidden-import', 'bottle_websocket',
               '--add-data', js_file_arg, '--add-data', web_folder_arg]
full_args = [main_script] + needed_args + args
print('Running:\npyinstaller', ' '.join(full_args), '\n')
pyi.run(full_args)

注意到print(“Building executable with main script ‘%s’ and web folder ‘%s’…\n” %

(main_script, web_folder))和print(‘Running:\npyinstaller’, ’ '.join(full_args), ‘\n’)可以知道eel的打包原理還是利用pyinstaller

4、打開cmd開始將含有eel的python_main打包起來

python -m eel F:\xx\xx\xx\Python_Main.py F:\xx\xx\xx\Web

這里暫時不加-w -f -i參數(shù)。(因為無論如何必然會出錯) 報錯,提示找不到eel.js文件。呼呼,我就奇怪了,eel.js文件不就在那兒擺著嗎。打開eel的__init__.py文件查看

from __future__ import print_function   # Python 2 compatibility stuff
from builtins import range
from io import open
import gevent as gvt
import json as jsn
import bottle as btl
import bottle.ext.websocket as wbs
import re as rgx
import os
import eel.browsers as brw
import random as rnd
import sys
import pkg_resources as pkg
import socket
_eel_js_file = pkg.resource_filename('eel', 'eel.js')
_eel_js = open(_eel_js_file, encoding='utf-8').read()
	
_websockets = []
_call_return_values = {}
_call_return_callbacks = {}
_call_number = 0
_exposed_functions = {}
_js_functions = []
_mock_queue = []
_mock_queue_done = set()
# All start() options must provide a default value and explanation here
_start_args = {
    'mode':             'chrome',                   # What browser is used
    'host':             'localhost',                # Hostname use for Bottle server
    'port':             8000,                       # Port used for Bottle server (use 0 for auto)
    'block':            True,                       # Whether start() blocks calling thread
    'jinja_templates':  None,                       # Folder for jinja2 templates
    'cmdline_args':     ['--disable-http-cache'],   # Extra cmdline flags to pass to browser start
    'size':             None,                       # (width, height) of main window
    'position':         None,                       # (left, top) of main window
    'geometry':         {},                         # Dictionary of size/position for all windows
    'close_callback':   None,                       # Callback for when all windows have closed
    'app_mode':  True,                              # (Chrome specific option)
    'all_interfaces': False,                        # Allow bottle server to listen for connections on all interfaces
    'disable_cache': True,                          # Sets the no-store response header when serving assets
    'app': btl.default_app(),                       # Allows passing in a custom Bottle instance, e.g. with middleware
}
# == Temporary (suppressable) error message to inform users of breaking API change for v1.0.0 ===
_start_args['suppress_error'] = False
api_error_message = '''
----------------------------------------------------------------------------------
  'options' argument deprecated in v1.0.0, see https://github.com/ChrisKnott/Eel
  To suppress this error, add 'suppress_error=True' to start() call.
  This option will be removed in future versions
----------------------------------------------------------------------------------
'''
# ===============================================================================================
# Public functions
def expose(name_or_function=None):
    # Deal with '@eel.expose()' - treat as '@eel.expose'
    if name_or_function is None:
        return expose
    if type(name_or_function) == str:   # Called as '@eel.expose("my_name")'
        name = name_or_function
        def decorator(function):
            _expose(name, function)
            return function
        return decorator
    else:
        function = name_or_function
        _expose(function.__name__, function)
        return function
def init(path, allowed_extensions=['.js', '.html', '.txt', '.htm',
                                   '.xhtml', '.vue']):
    global root_path, _js_functions
    root_path = _get_real_path(path)
    js_functions = set()
    for root, _, files in os.walk(root_path):
        for name in files:
            if not any(name.endswith(ext) for ext in allowed_extensions):
                continue
            try:
                with open(os.path.join(root, name), encoding='utf-8') as file:
                    contents = file.read()
                    expose_calls = set()
                    finder = rgx.findall(r'eel\.expose\(([^\)]+)\)', contents)
                    for expose_call in finder:
                        # If name specified in 2nd argument, strip quotes and store as function name
                        if ',' in expose_call:
                            expose_call = rgx.sub(r'["\']', '', expose_call.split(',')[1])
                        expose_call = expose_call.strip()
                        # Verify that function name is valid
                        msg = "eel.expose() call contains '(' or '='"
                        assert rgx.findall(r'[\(=]', expose_call) == [], msg
                        expose_calls.add(expose_call)
                    js_functions.update(expose_calls)
            except UnicodeDecodeError:
                pass    # Malformed file probably
    _js_functions = list(js_functions)
    for js_function in _js_functions:
        _mock_js_function(js_function)
def start(*start_urls, **kwargs):
    _start_args.update(kwargs)
    if 'options' in kwargs:
        if _start_args['suppress_error']:
            _start_args.update(kwargs['options'])
        else:
            raise RuntimeError(api_error_message)
    if _start_args['port'] == 0:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind(('localhost', 0))
        _start_args['port'] = sock.getsockname()[1]
        sock.close()
    if _start_args['jinja_templates'] != None:
        from jinja2 import Environment, FileSystemLoader, select_autoescape
        templates_path = os.path.join(root_path, _start_args['jinja_templates'])
        _start_args['jinja_env'] = Environment(loader=FileSystemLoader(templates_path),
                                 autoescape=select_autoescape(['html', 'xml']))
    # Launch the browser to the starting URLs
    show(*start_urls)
    def run_lambda():
        if _start_args['all_interfaces'] == True:
            HOST = '0.0.0.0'
        else:
            HOST = _start_args['host']
        app = _start_args['app']  # type: btl.Bottle
        for route_path, route_params in BOTTLE_ROUTES.items():
            route_func, route_kwargs = route_params
            app.route(path=route_path, callback=route_func, **route_kwargs)
        return btl.run(
            host=HOST,
            port=_start_args['port'],
            server=wbs.GeventWebSocketServer,
            quiet=True,
            app=app)
    # Start the webserver
    if _start_args['block']:
        run_lambda()
    else:
        spawn(run_lambda)
def show(*start_urls):
    brw.open(start_urls, _start_args)
def sleep(seconds):
    gvt.sleep(seconds)
def spawn(function, *args, **kwargs):
    gvt.spawn(function, *args, **kwargs)
# Bottle Routes
def _eel():
    start_geometry = {'default': {'size': _start_args['size'],
                                  'position': _start_args['position']},
                      'pages':   _start_args['geometry']}
    page = _eel_js.replace('/** _py_functions **/',
                           '_py_functions: %s,' % list(_exposed_functions.keys()))
    page = page.replace('/** _start_geometry **/',
                        '_start_geometry: %s,' % _safe_json(start_geometry))
    btl.response.content_type = 'application/javascript'
    _set_response_headers(btl.response)
    return page
def _static(path):
    response = None
    if 'jinja_env' in _start_args and 'jinja_templates' in _start_args:
        template_prefix = _start_args['jinja_templates'] + '/'
        if path.startswith(template_prefix):
            n = len(template_prefix)
            template = _start_args['jinja_env'].get_template(path[n:])
            response = btl.HTTPResponse(template.render())
    if response is None:
        response = btl.static_file(path, root=root_path)
    _set_response_headers(response)
    return response
def _websocket(ws):
    global _websockets
    for js_function in _js_functions:
        _import_js_function(js_function)
    page = btl.request.query.page
    if page not in _mock_queue_done:
        for call in _mock_queue:
            _repeated_send(ws, _safe_json(call))
        _mock_queue_done.add(page)
    _websockets += [(page, ws)]
    while True:
        msg = ws.receive()
        if msg is not None:
            message = jsn.loads(msg)
            spawn(_process_message, message, ws)
        else:
            _websockets.remove((page, ws))
            break
    _websocket_close(page)
BOTTLE_ROUTES = {
    "/eel.js": (_eel, dict()),
    "/<path:path>": (_static, dict()),
    "/eel": (_websocket, dict(apply=[wbs.websocket]))
}
# Private functions
def _safe_json(obj):
    return jsn.dumps(obj, default=lambda o: None)
def _repeated_send(ws, msg):
    for attempt in range(100):
        try:
            ws.send(msg)
            break
        except Exception:
            sleep(0.001)
def _process_message(message, ws):
    if 'call' in message:
        return_val = _exposed_functions[message['name']](*message['args'])
        _repeated_send(ws, _safe_json({ 'return': message['call'],
                                        'value': return_val  }))
    elif 'return' in message:
        call_id = message['return']
        if call_id in _call_return_callbacks:
            callback = _call_return_callbacks.pop(call_id)
            callback(message['value'])
        else:
            _call_return_values[call_id] = message['value']
    else:
        print('Invalid message received: ', message)
def _get_real_path(path):
    if getattr(sys, 'frozen', False):
        return os.path.join(sys._MEIPASS, path)
    else:
        return os.path.abspath(path)
def _mock_js_function(f):
    exec('%s = lambda *args: _mock_call("%s", args)' % (f, f), globals())
def _import_js_function(f):
    exec('%s = lambda *args: _js_call("%s", args)' % (f, f), globals())
def _call_object(name, args):
    global _call_number
    _call_number += 1
    call_id = _call_number + rnd.random()
    return {'call': call_id, 'name': name, 'args': args}
def _mock_call(name, args):
    call_object = _call_object(name, args)
    global _mock_queue
    _mock_queue += [call_object]
    return _call_return(call_object)
def _js_call(name, args):
    call_object = _call_object(name, args)
    for _, ws in _websockets:
        _repeated_send(ws, _safe_json(call_object))
    return _call_return(call_object)
def _call_return(call):
    call_id = call['call']
    def return_func(callback=None):
        if callback is not None:
            _call_return_callbacks[call_id] = callback
        else:
            for w in range(10000):
                if call_id in _call_return_values:
                    return _call_return_values.pop(call_id)
                sleep(0.001)
    return return_func
def _expose(name, function):
    msg = 'Already exposed function with name "%s"' % name
    assert name not in _exposed_functions, msg
    _exposed_functions[name] = function
def _websocket_close(page):
    close_callback = _start_args.get('close_callback')
    if close_callback is not None:
        sockets = [p for _, p in _websockets]
        close_callback(page, sockets)
    else:
        # Default behaviour - wait 1s, then quit if all sockets are closed
        sleep(1.0)
        if len(_websockets) == 0:
            sys.exit()
def _set_response_headers(response):
    if _start_args['disable_cache']:
        # https://stackoverflow.com/a/24748094/280852
        response.set_header('Cache-Control', 'no-store')

注意到了嗎?代碼中有這樣兩句:

_eel_js_file = pkg.resource_filename('eel', 'eel.js')
_eel_js = open(_eel_js_file, encoding='utf-8').read()

一不做,二不休,把eel.js的內容復制下來,然后,奧里給。將代碼做如下修改(即貼即用)

from __future__ import print_function   # Python 2 compatibility stuff
from builtins import range
from io import open
import gevent as gvt
import json as jsn
import bottle as btl
import bottle.ext.websocket as wbs
import re as rgx
import os
import eel.browsers as brw
import random as rnd
import sys
import pkg_resources as pkg
import socket
eelJS = '''
eel = {
    _host: window.location.origin,
    set_host: function (hostname) {
        eel._host = hostname
    },
    expose: function(f, name) {
        if(name === undefined){
            name = f.toString();
            let i = 'function '.length, j = name.indexOf('(');
            name = name.substring(i, j).trim();
        }
        eel._exposed_functions[name] = f;
    },
    guid: function() {
        return eel._guid;
    },
    // These get dynamically added by library when file is served
    /** _py_functions **/
    /** _start_geometry **/
    _guid: ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
            (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
        ),
    _exposed_functions: {},
    _mock_queue: [],
    _mock_py_functions: function() {
        for(let i = 0; i < eel._py_functions.length; i++) {
            let name = eel._py_functions[i];
            eel[name] = function() {
                let call_object = eel._call_object(name, arguments);
                eel._mock_queue.push(call_object);
                return eel._call_return(call_object);
            }
        }
    },
    _import_py_function: function(name) {
        let func_name = name;
        eel[name] = function() {
            let call_object = eel._call_object(func_name, arguments);
            eel._websocket.send(eel._toJSON(call_object));
            return eel._call_return(call_object);
        }
    },
    _call_number: 0,
    _call_return_callbacks: {},
    _call_object: function(name, args) {
        let arg_array = [];
        for(let i = 0; i < args.length; i++){
            arg_array.push(args[i]);
        }
        let call_id = (eel._call_number += 1) + Math.random();
        return {'call': call_id, 'name': name, 'args': arg_array};
    },
    _sleep: function(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    },
    _toJSON: function(obj) {
        return JSON.stringify(obj, (k, v) => v === undefined ? null : v);
    },
    _call_return: function(call) {
        return function(callback = null) {
            if(callback != null) {
                eel._call_return_callbacks[call.call] = callback;
            } else {
                return new Promise(function(resolve) {
                    eel._call_return_callbacks[call.call] = resolve;
                });
            }
        }
    },
    _position_window: function(page) {
        let size = eel._start_geometry【'default'】.size;
        let position = eel._start_geometry['default'].position;
        if(page in eel._start_geometry.pages) {
            size = eel._start_geometry.pages【page】.size;
            position = eel._start_geometry.pages【page】.position;
        }
        if(size != null){
            window.resizeTo(size[0], size[1]);
        }
        if(position != null){
            window.moveTo(position[0], position[1]);
        }
    },
    _init: function() {
        eel._mock_py_functions();
        document.addEventListener("DOMContentLoaded", function(event) {
            let page = window.location.pathname.substring(1);
            eel._position_window(page);
            let websocket_addr = (eel._host + '/eel').replace('http', 'ws');
            websocket_addr += ('?page=' + page);
            eel._websocket = new WebSocket(websocket_addr);
            eel._websocket.onopen = function() {
                for(let i = 0; i < eel._py_functions.length; i++){
                    let py_function = eel._py_functions[i];
                    eel._import_py_function(py_function);
                }
                while(eel._mock_queue.length > 0) {
                    let call = eel._mock_queue.shift();
                    eel._websocket.send(eel._toJSON(call));
                }
            };
            eel._websocket.onmessage = function (e) {
                let message = JSON.parse(e.data);
                if(message.hasOwnProperty('call') ) {
                    // Python making a function call into us
                    if(message.name in eel._exposed_functions) {
                        let return_val = eel._exposed_functions[message.name](...message.args);
                        eel._websocket.send(eel._toJSON({'return': message.call, 'value': return_val}));
                    }
                } else if(message.hasOwnProperty('return')) {
                    // Python returning a value to us
                    if(message['return'] in eel._call_return_callbacks) {
                        eel._call_return_callbacks[message['return']](message.value);
                    }
                } else {
                    throw 'Invalid message ' + message;
                }
            };
        });
    }
}
eel._init();
if(typeof require !== 'undefined'){
    // Avoid name collisions when using Electron, so jQuery etc work normally
    window.nodeRequire = require;
    delete window.require;
    delete window.exports;
    delete window.module;
}
'''
try:
	_eel_js_file = pkg.resource_filename('eel', 'eel.js')
	_eel_js = open(_eel_js_file, encoding='utf-8').read()
except:
	_eel_js = eelJS
_websockets = []
_call_return_values = {}
_call_return_callbacks = {}
_call_number = 0
_exposed_functions = {}
_js_functions = []
_mock_queue = []
_mock_queue_done = set()
# All start() options must provide a default value and explanation here
_start_args = {
    'mode':             'chrome',                   # What browser is used
    'host':             'localhost',                # Hostname use for Bottle server
    'port':             8000,                       # Port used for Bottle server (use 0 for auto)
    'block':            True,                       # Whether start() blocks calling thread
    'jinja_templates':  None,                       # Folder for jinja2 templates
    'cmdline_args':     ['--disable-http-cache'],   # Extra cmdline flags to pass to browser start
    'size':             None,                       # (width, height) of main window
    'position':         None,                       # (left, top) of main window
    'geometry':         {},                         # Dictionary of size/position for all windows
    'close_callback':   None,                       # Callback for when all windows have closed
    'app_mode':  True,                              # (Chrome specific option)
    'all_interfaces': False,                        # Allow bottle server to listen for connections on all interfaces
    'disable_cache': True,                          # Sets the no-store response header when serving assets
    'app': btl.default_app(),                       # Allows passing in a custom Bottle instance, e.g. with middleware
}
# == Temporary (suppressable) error message to inform users of breaking API change for v1.0.0 ===
_start_args['suppress_error'] = False
api_error_message = '''
----------------------------------------------------------------------------------
  'options' argument deprecated in v1.0.0, see https://github.com/ChrisKnott/Eel
  To suppress this error, add 'suppress_error=True' to start() call.
  This option will be removed in future versions
----------------------------------------------------------------------------------
'''
# ===============================================================================================
# Public functions
def expose(name_or_function=None):
    # Deal with '@eel.expose()' - treat as '@eel.expose'
    if name_or_function is None:
        return expose
    if type(name_or_function) == str:   # Called as '@eel.expose("my_name")'
        name = name_or_function
        def decorator(function):
            _expose(name, function)
            return function
        return decorator
    else:
        function = name_or_function
        _expose(function.__name__, function)
        return function
def init(path, allowed_extensions=['.js', '.html', '.txt', '.htm',
                                   '.xhtml', '.vue']):
    global root_path, _js_functions
    root_path = _get_real_path(path)
    js_functions = set()
    for root, _, files in os.walk(root_path):
        for name in files:
            if not any(name.endswith(ext) for ext in allowed_extensions):
                continue
            try:
                with open(os.path.join(root, name), encoding='utf-8') as file:
                    contents = file.read()
                    expose_calls = set()
                    finder = rgx.findall(r'eel\.expose\(([^\)]+)\)', contents)
                    for expose_call in finder:
                        # If name specified in 2nd argument, strip quotes and store as function name
                        if ',' in expose_call:
                            expose_call = rgx.sub(r'["\']', '', expose_call.split(',')[1])
                        expose_call = expose_call.strip()
                        # Verify that function name is valid
                        msg = "eel.expose() call contains '(' or '='"
                        assert rgx.findall(r'[\(=]', expose_call) == [], msg
                        expose_calls.add(expose_call)
                    js_functions.update(expose_calls)
            except UnicodeDecodeError:
                pass    # Malformed file probably
    _js_functions = list(js_functions)
    for js_function in _js_functions:
        _mock_js_function(js_function)
def start(*start_urls, **kwargs):
    _start_args.update(kwargs)
    if 'options' in kwargs:
        if _start_args['suppress_error']:
            _start_args.update(kwargs['options'])
        else:
            raise RuntimeError(api_error_message)
    if _start_args['port'] == 0:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind(('localhost', 0))
        _start_args['port'] = sock.getsockname()[1]
        sock.close()
    if _start_args['jinja_templates'] != None:
        from jinja2 import Environment, FileSystemLoader, select_autoescape
        templates_path = os.path.join(root_path, _start_args['jinja_templates'])
        _start_args['jinja_env'] = Environment(loader=FileSystemLoader(templates_path),
                                 autoescape=select_autoescape(['html', 'xml']))
    # Launch the browser to the starting URLs
    show(*start_urls)
    def run_lambda():
        if _start_args['all_interfaces'] == True:
            HOST = '0.0.0.0'
        else:
            HOST = _start_args['host']
        app = _start_args['app']  # type: btl.Bottle
        for route_path, route_params in BOTTLE_ROUTES.items():
            route_func, route_kwargs = route_params
            app.route(path=route_path, callback=route_func, **route_kwargs)
        return btl.run(
            host=HOST,
            port=_start_args['port'],
            server=wbs.GeventWebSocketServer,
            quiet=True,
            app=app)
    # Start the webserver
    if _start_args['block']:
        run_lambda()
    else:
        spawn(run_lambda)
def show(*start_urls):
    brw.open(start_urls, _start_args)
def sleep(seconds):
    gvt.sleep(seconds)
def spawn(function, *args, **kwargs):
    gvt.spawn(function, *args, **kwargs)
# Bottle Routes
def _eel():
    start_geometry = {'default': {'size': _start_args['size'],
                                  'position': _start_args['position']},
                      'pages':   _start_args['geometry']}
    page = _eel_js.replace('/** _py_functions **/',
                           '_py_functions: %s,' % list(_exposed_functions.keys()))
    page = page.replace('/** _start_geometry **/',
                        '_start_geometry: %s,' % _safe_json(start_geometry))
    btl.response.content_type = 'application/javascript'
    _set_response_headers(btl.response)
    return page
def _static(path):
    response = None
    if 'jinja_env' in _start_args and 'jinja_templates' in _start_args:
        template_prefix = _start_args['jinja_templates'] + '/'
        if path.startswith(template_prefix):
            n = len(template_prefix)
            template = _start_args['jinja_env'].get_template(path[n:])
            response = btl.HTTPResponse(template.render())
    if response is None:
        response = btl.static_file(path, root=root_path)
    _set_response_headers(response)
    return response
def _websocket(ws):
    global _websockets
    for js_function in _js_functions:
        _import_js_function(js_function)
    page = btl.request.query.page
    if page not in _mock_queue_done:
        for call in _mock_queue:
            _repeated_send(ws, _safe_json(call))
        _mock_queue_done.add(page)
    _websockets += [(page, ws)]
    while True:
        msg = ws.receive()
        if msg is not None:
            message = jsn.loads(msg)
            spawn(_process_message, message, ws)
        else:
            _websockets.remove((page, ws))
            break
    _websocket_close(page)
BOTTLE_ROUTES = {
    "/eel.js": (_eel, dict()),
    "/<path:path>": (_static, dict()),
    "/eel": (_websocket, dict(apply=[wbs.websocket]))
}
# Private functions
def _safe_json(obj):
    return jsn.dumps(obj, default=lambda o: None)
def _repeated_send(ws, msg):
    for attempt in range(100):
        try:
            ws.send(msg)
            break
        except Exception:
            sleep(0.001)
def _process_message(message, ws):
    if 'call' in message:
        return_val = _exposed_functions[message['name']](*message['args'])
        _repeated_send(ws, _safe_json({ 'return': message['call'],
                                        'value': return_val  }))
    elif 'return' in message:
        call_id = message['return']
        if call_id in _call_return_callbacks:
            callback = _call_return_callbacks.pop(call_id)
            callback(message['value'])
        else:
            _call_return_values[call_id] = message['value']
    else:
        print('Invalid message received: ', message)
def _get_real_path(path):
    if getattr(sys, 'frozen', False):
        return os.path.join(sys._MEIPASS, path)
    else:
        return os.path.abspath(path)
def _mock_js_function(f):
    exec('%s = lambda *args: _mock_call("%s", args)' % (f, f), globals())
def _import_js_function(f):
    exec('%s = lambda *args: _js_call("%s", args)' % (f, f), globals())
def _call_object(name, args):
    global _call_number
    _call_number += 1
    call_id = _call_number + rnd.random()
    return {'call': call_id, 'name': name, 'args': args}
def _mock_call(name, args):
    call_object = _call_object(name, args)
    global _mock_queue
    _mock_queue += [call_object]
    return _call_return(call_object)
def _js_call(name, args):
    call_object = _call_object(name, args)
    for _, ws in _websockets:
        _repeated_send(ws, _safe_json(call_object))
    return _call_return(call_object)
def _call_return(call):
    call_id = call['call']
    def return_func(callback=None):
        if callback is not None:
            _call_return_callbacks[call_id] = callback
        else:
            for w in range(10000):
                if call_id in _call_return_values:
                    return _call_return_values.pop(call_id)
                sleep(0.001)
    return return_func
def _expose(name, function):
    msg = 'Already exposed function with name "%s"' % name
    assert name not in _exposed_functions, msg
    _exposed_functions[name] = function
def _websocket_close(page):
    close_callback = _start_args.get('close_callback')
    if close_callback is not None:
        sockets = [p for _, p in _websockets]
        close_callback(page, sockets)
    else:
        # Default behaviour - wait 1s, then quit if all sockets are closed
        sleep(1.0)
        if len(_websockets) == 0:
            sys.exit()
def _set_response_headers(response):
    if _start_args['disable_cache']:
        # https://stackoverflow.com/a/24748094/280852
        response.set_header('Cache-Control', 'no-store')

ok,下面在運行一次cmd,執(zhí)行之前的代碼,不報錯了。但是,這次又遇到了新的問題。

'utf-8' codec can't decode byte 0xce

woc。這編碼怎么又出了問題。百度一下,找到了解決方案。在cmd中先輸入

chcp 65001

然后再執(zhí)行

python -m eel F:\xx\xx\xx\Python_Main.py F:\xx\xx\xx\Web

這下總算是成功打包了。

5、找到我們的Python_Main.exe文件

打包后的文件一般在cmd的啟動路徑下能夠找到。如,我的Python_Main.exe文件就應該在C:\Users\Deadpool里

Pyinstaller打包eel和pygame需要注意什么坑

發(fā)現(xiàn)在Deadpool文件里多出了三個文件,分別是Python_Main.spec, distbuild。打開dist后,發(fā)現(xiàn)有一個Python_Main文件夾,打開,便能找到Python_Main.exe,點擊,彈出小黑框。接著,恭喜你,主界面顯示404 Not Found。What?Woc。又是什么問題,難道我需要把Web文件夾移到這個Python_Main文件夾里?經驗證答案是“是”。事實上,我們需要把所有文件都移到這個Python_Main里面,也就是前面的Web以及游戲資源文件夾。OK,問題解決。感動啊 (? _ ?)~~~~當我滿懷激情的點擊了開始游戲,小黑框里又一個錯誤出現(xiàn)了:

pygame.error: Couldn't open xxx\xxx.png

百度一下,原來需要用pyinstaller打包時,pygame的load圖片必須用絕對路徑。ok,那就只有修改代碼,重新打包。問題解決。接下來,就是如何處理掉小黑框了。現(xiàn)在,先讓我們看看Python_Main.spec文件:

# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['F:\\xx\\xx\\Python_Main.py'],
             pathex=['C:\\Users\\Deadpool'],
             binaries=[],
             datas=[('F:\\AnocondaApp\\lib\\site-packages\\eel\\eel.js', 'eel'), ('F:\\xx\\xx\\Web', 'F:\\xx\\xx\\Web')],
             hiddenimports=['bottle_websocket'],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='Python_Main',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=True, icon='')
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               upx_exclude=[],
               name='Python_Main')

簡單分析后,把console = True改為console = False,咦,這里還有一個icon,應該不會是游戲圖標吧,試著改改,于是我讓icon = F:\xx\xx\Web\favicon.ico。改完后,保存。

如何運行spec文件呢?無所不能的網友給出了答案。

chcp 65001
pyinstaller Python_Main.spec

讀到這里,這篇“Pyinstaller打包eel和pygame需要注意什么坑”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI