Как получить доступ к переменным в пространстве имен файлов хука PyInstaller из кода времени выполнения? - PullRequest
0 голосов
/ 09 декабря 2018

Я пытаюсь получить выходные данные git describe, оцененные на этапе анализа PyInstaller, и сделать их доступными для переменной времени выполнения Python, чтобы предоставить приложению строку ревизии, полученную из среды сборки и отображаемую во время выполнения.

Для этого я предполагаю, что хуки PyInstaller - лучшее средство, потому что они позволяют выполнять произвольный код Python в файле хуков, пока он строит дерево импорта.Однако я не нашел способа передать значение переменной из фазы анализа PyInstaller в переменную времени выполнения, чтобы оно могло отображаться приложением, работающим как сгенерированный файл .exe.

Пример: файл подключенияhook-rev.py, который импортируется механизмом анализа PyInstaller при обнаружении import rev:

import git

rev = git.Repo().git.describe()
print('got rev = {}'.format(rev))

mymodule.py содержит:

import rev

rev.py содержит:

global AppRev
try:
    # Get the revision from the hook file
    AppRev = rev
except:
    print('rev is not defined')

Запуск PyInstaller как:

pyinstaller --additional-hooks-dir=. mymodule.py

подтверждает, что импорт файла подключения запускается на этапе анализа PyInstaller, а оператор печати показывает, что переменной rev присвоен правильный результат git describeв области файла подключения, пока PyInstaller создает дерево импорта.Но сгенерированный файл .exe выдает:

rev is not defined

Конечно, это верно с учетом примеров кода, потому что rev не находится в локальном или другом доступном пространстве имен.Я не знаю, что такое пространство имен файла ловушек, и, следовательно, переменная rev.

Добавив этот оператор печати

print('module name = {}'.format(__name__))

в файл ловушек hook-rev.pyЯ вижу, что механизм импорта ловушек PyInstaller назначает имя __PyInstaller_hooks_0_rev импортированному подключаемому модулю.Но этот импорт существует только во время сборки, поэтому попытка доступа к переменной rev во время выполнения в run.py, так как __PyInstaller_hooks_0_rev.rev завершается неудачей, так как модуль __PyInstaller_hooks_0_rev неизвестен во время выполнения.

Есть ли другойспособ соединить пространства имен между средой выполнения и обработкой импорта хуков PyInstaller?

1 Ответ

0 голосов
/ 10 декабря 2018

Для справки, вот способ достижения требуемой функциональности.Это не идеальное решение, потому что оно опирается на два дополнительных файла Python (файл ловушек, сгенерированный файл, общий для PyInstaller и время выполнения) для достижения того, что, я надеюсь, возможно только с файлом ловушек.Недостатком также является то, что ревизия приложения, отображаемая в среде разработчика, отражает ревизию, последнюю установленную PyInstaller.Я не буду отмечать это как принятый ответ, пока не станет ясно, что более простой метод невозможен.

Схема:

  1. В приложении используйте import rev, которыйзапускает механизм ловушек PyInstaller для поиска файла hook-rev.py для импорта на этапе анализа
  2. В hook-rev.py создайте строку ревизии и запишите файл Python, например buildrev.py, который содержит назначение ревизиистрока для переменной
  3. В rev.py используйте import buildrev и определите get_rev(), который возвращает buildrev.rev
  4. В файле приложения получите доступ к строке редакции, вызвав rev.get_rev()

Файлы для реализации этой схемы показаны ниже.

mymodule.py (основное приложение):

import rev

print('application revision is', rev.get_rev())

rev.py (определяет get_rev(), который возвращаетстрока редакции):

# import buildrev fails in dev environment if PyInstaller has not been run
try:
    import buildrev
    rev_string = buildrev.rev
except:
    rev_string = 'unknown'

def get_rev():
    return rev_string

hook-rev.py (файл ловушек, импортированный PyInstaller во время фазы анализа, создает buildrev.py):

try:
    # Get the build-time revision string and write it into
    # buildrev.py as a Python variable assignment. Must search
    # parent directories because PyInstaller analyze is run in a lower level.
    rev_string = git.Repo(search_parent_directories=True).git.describe()
    with open('buildrev.py', 'w') as rev_file:
        print('rev = \'{}\''.format(rev_string), file=rev_file)
except: 
    pass

В созданном файле buildrev.py строка ревизии отражает ревизию рабочей копии вВремя сборки дерева импорта PyInstaller.При доступе с помощью обычного интерпретатора Python, как в среде IDE в среде разработки, эта строка редакции по-прежнему отражает версию рабочей области при последнем запуске PyInstaller, которая может быть неточной.buildrev.py не должен отслеживаться VCS.

...