Estou escrevendo um pacote python com módulos que precisam abrir arquivos de dados em um ./data/
subdiretório. No momento, tenho os caminhos dos arquivos codificados em minhas classes e funções. Gostaria de escrever um código mais robusto que possa acessar o subdiretório, independentemente de onde ele esteja instalado no sistema do usuário.
Eu tentei uma variedade de métodos, mas até agora não tive sorte. Parece que a maioria dos comandos "diretório atual" retornam o diretório do interpretador python do sistema, e não o diretório do módulo.
Parece que deve ser um problema comum e trivial. No entanto, eu não consigo entender. Parte do problema é que meus arquivos de dados não são .py
arquivos, então não posso usar funções de importação e coisas do gênero.
Alguma sugestão?
No momento, meu diretório de pacotes se parece com:
/
__init__.py
module1.py
module2.py
data/
data.txt
Estou tentando acessar data.txt
a partir module*.py
!
Respostas:
Você pode usar
__file__
para obter o caminho para o pacote, assim:fonte
__file__
não funciona com py2exe, pois o valor será o caminho para o arquivo zip.A maneira padrão de fazer isso é com os pacotes setuptools e pkg_resources.
Você pode organizar seu pacote de acordo com a seguinte hierarquia e configurar o arquivo de instalação do pacote para apontar seus recursos de dados, conforme este link:
http://docs.python.org/distutils/setupscript.html#installing-package-data
Você pode então encontrar novamente e usar esses arquivos usando pkg_resources, conforme este link:
http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access
fonte
python-setuptools
apenas disso? Até agora__file__
funciona bem para mim.from pkg_resources import resource_filename open(resource_filename('data', 'data.txt'), 'rb')
importlib.resources
substituipkg_resources
para esse fim (devido a problemas de desempenho).Para fornecer uma solução funcionando hoje. Definitivamente, use esta API para não reinventar todas essas rodas.
É necessário um nome de arquivo verdadeiro do sistema de arquivos. Ovos compactados serão extraídos para um diretório de cache:
Retornar um objeto parecido com um arquivo legível para o recurso especificado; pode ser um arquivo real, um StringIO ou algum objeto semelhante. O fluxo está no "modo binário", no sentido de que quaisquer bytes existentes no recurso serão lidos como estão.
Descoberta de pacotes e acesso a recursos usando pkg_resources
fonte
Muitas vezes, não faz sentido responder que detalha o código que não funciona como está, mas acredito que isso seja uma exceção. Python 3.7 adicionado
importlib.resources
que deve substituirpkg_resources
. Funcionaria para acessar arquivos dentro de pacotes que não possuem barras nos nomes, ou seja,ou seja, você pode acessar o
data2.txt
pacote internofoo
com, por exemplomas falharia com uma exceção para
Isso não pode ser fixo, exceto colocando
__init__.py
emdata
e, em seguida, usá-lo como um pacote:A razão para esse comportamento é "é por design" ; mas o design pode mudar ...
fonte
"This was a deliberate choice, but I think you have a valid use case. @brettcannon what do you think? And if we allow this, should we make sure it gets into Python 3.7?"
Você precisa de um nome para todo o seu módulo; sua árvore de diretórios não fornece esses detalhes; para mim, isso funcionou:
Notavelmente, o setuptools não parece resolver arquivos com base em uma correspondência de nome com os arquivos de dados compactados, então você precisa incluir o
data/
prefixo praticamente, não importa o quê. Você pode usaros.path.join('data', 'data.txt)
se precisar de separadores de diretório alternativos. Geralmente, não encontro problemas de compatibilidade com os separadores de diretório de estilo unix codificados.fonte
Eu acho que procurei uma resposta.
Eu faço um módulo data_path.py, que importo em meus outros módulos contendo:
E então eu abro todos os meus arquivos com
fonte
pkg_resources.resource_string('pkg_name', 'data/file.txt')
__file__
algum lugar. No meu caso, eu uso uma biblioteca que realmente deseja caminhos e não fluxos. É claro que eu poderia gravar os arquivos temporariamente no disco, mas sendo preguiçoso, apenas uso o recurso setuptools.