Как создать exe с помощью pyinstaller из скрипта python, который использует cvxpy и CBC?

#python #pyinstaller #linear-programming #cvxpy #coin-or-cbc

#python #pyinstaller #линейное программирование #cvxpy #монета или cbc

Вопрос:

Я пытаюсь собрать exe из скрипта python, чтобы решить проблему LP, используя cvxpy и CBC (через cylp) с помощью pyinstaller.
Код выглядит следующим образом:

 import numpy as np
import cvxpy as cp

if __name__ == "__main__":
    A = np.array([[2, 0, 0],
                  [1, 0, 2],
                  [0, 3, 1]])
    b = np.array([4, 8, 6])
    c = np.array([3, 4, 2])

    # Define and solve the problem.
    x = cp.Variable(3)
    prob = cp.Problem(cp.Maximize(c.T @ x),
                      [A @ x <= b, x >= 0])
    prob.solve(solver=cp.CBC)
    print(f"solver: {prob.solver_stats.solver_name}")

    # Print result.
    print("The optimal value is", prob.value)
    print("A solution x is")
    print(x.value)
  

это корректно работает с интерпретатором python

 > python .LP.py
solver: CBC
The optimal value is 16.0
A solution x is
[2. 1. 3.]
  

но exe, созданный pyinstaller, выдает ошибку

 > pyinstaller .LP.spec
> .distLP.exe
Traceback (most recent call last):
  File "LP.py", line 15, in <module>
    prob.solve(solver=cp.CBC)
  File "cvxpyproblemsproblem.py", line 396, in solve
  File "cvxpyproblemsproblem.py", line 745, in _solve
  File "cvxpyproblemsproblem.py", line 500, in get_problem_data
  File "cvxpyproblemsproblem.py", line 651, in _construct_chain
  File "cvxpyproblemsproblem.py", line 576, in _find_candidate_solvers
cvxpy.error.SolverError: The solver CBC is not installed.
[18960] Failed to execute script LP
  

Есть ли способ это исправить?

Я не могу избежать использования CBC, потому что на самом деле я хочу сделать, это создать exe, решающий задачу программирования со смешанным целым числом.

Моя среда:
numpy: 1.19.1
cvxpy: 1.1.4
cylp: 0.91.0
PyInstaller: 4.0
Python: 3.7.9
Платформа: Windows 10 v1909 64bit

Мой файл спецификации (созданный pyinstaller .LP.py -F и мной модифицированный datas ):

 # -*- mode: python ; coding: utf-8 -*-

block_cipher = None


a = Analysis(
    ['LP.py'],
    pathex=['C:\Users\aaa\Desktop\LP'],
    binaries=[],
    datas=[
        ('C:\Users\aaa\AppData\Local\Programs\Python\Python37\Lib\site-packages\cylp\*',
         '.\cylp\')],
    hiddenimports=[],
    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,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='LP',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True)
  

Ответ №1:

Я сталкиваюсь с той же проблемой. Я попробовал обе следующие команды для сборки с тем же результатом:

     pyinstaller name_of_my_package.py
    pyinstaller --hidden-imports=cylp name_of_my_package.py
  

Но я все еще получаю ту же ошибку. Поскольку я создаю свой с несколькими файлами, я могу просто зайти в каталог dist / name_of_my_package / cylp /, и я вижу, что папка модуля cylp существует, но в этом каталоге есть только подпапка cy. Когда я удаляю dist / name_of_my_package / cylp / cy / из сборки и копирую содержимое моей папки cylp непосредственно из моей виртуальной среды python в dist/name_of_my_package / cylp /, мой exe работает. Но вы можете сделать это, только если вы не создаете с флагом —onefile.

Когда я закончу, я увижу следующую структуру папок:

     dist/name_of_my_package/cylp/
    |--cpp/
       |--<a bunch of stuff in here>
    |--cy/
       |--<a bunch of stuff in here>
    |--py
       |--<a bunch of stuff in here>
    |--__init__.py
    |--VERSION
  

Исходная структура папок, созданная pyinstaller, выглядит только так:

     dist/name_of_my_package/cylp/
    |--cy/
       |--<a bunch of stuff in here>
  

Похоже, что pyinstaller знает, как получить пакет cylp, но он не копирует все необходимые фрагменты. Я не уверен, каков реальный ответ здесь, но этот обходной путь работает для меня на данный момент. Надеюсь, кто-нибудь может указать нам правильный ответ.

Ответ №2:

Согласно документации, параметр «—add-data» или «Analysis / datas» в первой строке равен «относительно местоположения файла спецификации».

pyinstaller читает документ, используя файл данных из модуля

Я использовал строку консоли в Windows (двойные кавычки и разделитель точкой с запятой), чтобы добавить весь каталог cpp и файл ВЕРСИИ (больше ничего не нужно).

pyinstaller —add-data «cylp cpp; cylp cpp» —add-data «cylp VERSION; cylp» LP.py

Добавьте -F, если вы хотите сборку «onefile».

Поскольку путь к первой строке является относительным, сначала вам нужно скопировать всю папку cylp package-site из исходного каталога python в каталог LP.py

PS: Это мой первый ответ в Stackoverflow!