Доступ к файлу из яйца python

Привет, я работаю с упаковкой Python. У меня есть 3 файла non-code, а именно ['synonyms.csv', 'acronyms.csv', 'words.txt'].

  • Эти файлы существуют в структуре папок Wordproject/WordProject/Repository/DataBank/
  • У меня есть класс RepositoryReader по пути Wordproject/WordProject/Repository/
  • Я написал код, который извлекает текущее местоположение RepositoryReader, а затем ищет subdirectory с именем DataBank и ищет там 3 файла.

Проблема в том, что когда я создаю egg из кода, а затем запускаю его,

Мой код дает мне ошибку:

Не удалось найти файл в папке X:\1. Проекты\Python\Wordproject\venv\lib\site-packages\Wordproject-1.0-py3.6.egg\Wordproject\Repository\DataBank\synonyms.csv

Он не может получить файл или прочитать его по пути, если путь соответствует яйцу. Есть ли способ обойти это? Эти файлы должны быть в папке egg.


person iam.Carrot    schedule 11.04.2018    source источник
comment
Ваша цель — установить эти файлы где-нибудь в доступном месте в pip install время или встроить их в каталог пакета и получить к ним доступ так же, как к подмодулям?   -  person abarnert    schedule 11.04.2018
comment
@abarnert на самом деле я не могу отправить этот код в PyPI, так как это организационная вещь. Но меня больше интересует obfuscation кода, чтобы даже при доступе никто не мог декомпилировать пакет. И поэтому я хочу, чтобы файлы были встроены в сам пакет.   -  person iam.Carrot    schedule 11.04.2018
comment
Ну, вы не получите много запутанности из файла яйца. По сути, это просто zip-файл плюс манифест, сообщающий вам, где находятся все интересные файлы, что может замедлить работу начинающего хакера примерно на 60 секунд…   -  person abarnert    schedule 11.04.2018
comment
@abarnert что-нибудь, что вы могли бы порекомендовать для такого рода требований?   -  person iam.Carrot    schedule 11.04.2018
comment
Зависит от того, почему вы пытаетесь запутать вещи, но обычно лучший ответ таков: не пытайтесь; почти все, что вы придумаете, будет стоить больше, чем оно того стоит, и только даст вам ложное чувство безопасности, которое не позволит вам найти лучшее решение. Есть редкие случаи, когда стоит запутать код Python (и участвовать в потенциально бесконечной гонке вооружений с каким-то противником), но в 99% случаев, когда люди просят об этом, они даже не имеют ни малейшего представления о том, кто может быть злоумышленником. , и, вероятно, его не будет, и то, как они пытаются защитить вещи, все равно не поможет.   -  person abarnert    schedule 11.04.2018


Ответы (3)


Здесь вы можете попытаться сделать две разные вещи:

  • Рассматривайте файлы данных как часть вашего пакета, как модули Python, и обращайтесь к ним во время выполнения, как если бы ваш пакет был обычным деревом каталогов, даже если это не так.
  • Получите файлы данных, установленные в другом месте в pip install время, в место, к которому вы можете получить обычный доступ.

Оба объяснения описаны в разделе о файлах данных в документы PyPA/setuptools. Я думаю, вам нужен первый здесь, который описан в подразделе Доступ к файлам данных во время выполнения:

Как правило, существующие программы манипулируют атрибутом __file__ пакета, чтобы найти расположение файлов данных. Однако эта манипуляция несовместима с обработчиками импорта на основе PEP 302, включая импорт из zip-файлов и Python Eggs. Настоятельно рекомендуется, если вы используете файлы данных, использовать ResourceManager API из pkg_resources для доступа к ним. Модуль pkg_resources распространяется как часть setuptools, поэтому, если вы используете setuptools для распространения своего пакета, нет причин не использовать его API управления ресурсами. См. также Доступ к ресурсам пакетов для быстрого примера преобразования кода, использующего __file__ для использования pkg_resources вместо этого.

Перейдите по этой ссылке, и вы обнаружите что-то похожее на старую документацию PEAK, но это только потому, что это действительно старая документация PEAK. Существует версия, спрятанная внутри setuptools документов, которую вам может быть легче читать. и перемещайтесь, как только вам удастся его найти.

Как говорится, вы можете try использовать get_data (который будет работать внутри egg/zip), а затем вернуться к доступу к файлу (который будет работать при запуске из исходного кода), но вам лучше используя обертки в pkg_resources. В принципе, если ваш код делал это:

path = os.path.join(__file__, 'Wordproject/WordProject/Repository/DataBank/', datathingy)
with open(path) as f:
    for line in f:
        do_stuff(line)

… вы измените его на это:

path = 'Wordproject/WordProject/Repository/DataBank/' + datathingy
f = pkg_resources.resource_stream(__name__, path)
for line in f:
    do_stuff(line.decode())

Обратите внимание, что файлы resource_stream всегда открываются в двоичном режиме. Поэтому, если вы хотите прочитать их как текст, вам нужно обернуть их TextIOWrapper или декодировать каждую строку.

person abarnert    schedule 11.04.2018
comment
TBH Моя первая интуиция заключалась в использовании самого API менеджера ресурсов. Но я не мог заставить его работать. Когда я передал имя файла со структурой папок, это выдало мне ошибку, и поэтому я выбрал вопрос здесь. Было бы очень полезно, если бы вы могли продемонстрировать пример кода для этого, где файл egg WordProject, в то время как у него есть подкаталог Repository, а внутри этого каталога у меня есть другой каталог DataBank, и я читаю файлы оттуда. - person iam.Carrot; 11.04.2018
comment
@ iam.Carrot Я не могу создать образец, соответствующий вашему макету, потому что я не знаю его. Но вы можете предоставить нам минимально воспроизводимый пример, который точно показывает, что вы пробовали, и какую именно ошибку вы получили, и то мы можем помочь отладить это. - person abarnert; 11.04.2018
comment
да, я как бы видел, что один приближается. Я посмотрю, смогу ли я поработать над чем-нибудь для этого - person iam.Carrot; 11.04.2018
comment
У меня есть последний вопрос, я использовал pandas для чтения файла csv в качестве кадра данных, есть ли способ добиться этого с помощью API диспетчера ресурсов? - person iam.Carrot; 11.04.2018
comment
@ iam.Carrot Я не пробовал, но думаю, что Pandas может использовать поток ресурсов так же, как он использует реальный открытый файл. Если нет… Я предполагаю, что файл слишком велик, чтобы прочитать все это в память, а затем сказать Pandas проанализировать его как строку, иначе вы бы просто сделали это, поэтому вам, возможно, придется создать временный файл, скопировать поток в временный файл , затем попросите Pandas открыть это, но это наихудший вариант. - person abarnert; 11.04.2018
comment
@ iam.Carrot - Вы случайно не нашли правильное решение? - person Manish; 03.03.2021
comment
@Manish На самом деле я использовал вышеуказанное решение, где я использовал вышеуказанное решение, используя pkg_resources для получения базового пути к файлу, а затем определил relative path для файла, который я пытался загрузить, и это сработало. Если хотите, могу поделиться образцом. - person iam.Carrot; 05.03.2021

egg файлы просто переименованы в файлы .zip.

Вы можете использовать библиотеку zipfile, чтобы открыть яйцо и извлечь или прочитать файл. тебе нужно.

import zipfile

zip = zipfile.ZipFile('/path/to/file.egg', 'r')

# open file from within the egg
f = zip.open('synonyms.csv', 'r')
txt = f.read()
person Brendan Abel    schedule 11.04.2018
comment
так вы имеете в виду, что я разархивирую файл egg во время выполнения, а затем читаю его? Где распаковать? - person iam.Carrot; 11.04.2018
comment
@ iam.Carrot Обновлен мой ответ, чтобы показать, как читать файлы непосредственно из zip-архива, не нужно извлекать данные на диск. - person Brendan Abel; 11.04.2018
comment
Я использую pandas для чтения csv, есть ли способ в pandas, через который я могу прочитать файл? - person iam.Carrot; 11.04.2018
comment
@iam.Carrot Объект, возвращенный из zip.open, представляет собой файловый объект, который вы должны иметь возможность передать непосредственно в pandas.read_csv. - person Brendan Abel; 11.04.2018
comment
Я бы также предложил использовать контекстный менеджер! with zipfile.ZipFile('/path/to/file.egg/', 'r') as zip: - person Josie Thompson; 13.09.2018

Основываясь на документации, мы можем читать содержимое файла несколькими способами.

Решение 1. Считайте содержимое файла непосредственно в память.

Без извлечения файла локально.

import zipfile, tempfile
tfile = tempfile.NamedTemporaryFile()
with zipfile.ZipFile('/path/to/egg.egg') as myzip:
    with myzip.open('relative/path/to/file.txt') as myfile:
        tfile.write(myfile.read())

# .. do something with temporary file

tfile.close()

Теперь tfile — ваш локальный дескриптор временного файла. Его имя tfile.name, и все файловые операции, такие как open(tfile) и т. д., работают с ним как обычно. tfile.close() необходимо вызвать в конце, чтобы закрыть дескриптор.

Содержимое файла может быть прочитано самим myfile.read(), но мы теряем дескриптор myfile, как только выходим из контекста. Таким образом, содержимое файла копируется во временный файл, если его необходимо передать для других операций.

Решение 2. Локальное извлечение члена egg

zipfile предоставляет API для извлечения определенного члена

import zipfile
x = zipfile.ZipFile('/path/to/egg.egg')
x.extractall(path='temp/dest/folder', members=['path/to/file.txt'])

Решение 3. Извлеките яйцо целиком

Другое решение — извлечь яйцо во временную папку, а затем прочитать файл. Яйцо можно извлечь в командной строке следующим образом

python -m zipfile -e path/to/my.egg ./temp_destination
person ViFI    schedule 14.09.2018