Eu tenho um projeto Python com um arquivo de configuração na raiz do projeto. O arquivo de configuração precisa ser acessado em alguns arquivos diferentes em todo o projeto.
Portanto, parece algo como: <ROOT>/configuration.conf
<ROOT>/A/a.py
, <ROOT>/A/B/b.py
(quando b, acesso a.py o arquivo de configuração).
Qual é a maneira melhor / mais fácil de obter o caminho para a raiz do projeto e o arquivo de configuração sem depender de qual arquivo dentro do projeto estou? ou seja, sem usar ../../
? É normal presumir que sabemos o nome da raiz do projeto.
<ROOT>/__init__.py
existe?os.path.expanduser('~/.myproject/myproject.conf')
. Funciona em Unix e Windows.Respostas:
Você pode fazer isso como o Django faz: definir uma variável para a raiz do projeto a partir de um arquivo que está no nível superior do projeto. Por exemplo, se esta é a aparência da estrutura do seu projeto:
Em
definitions.py
você pode definir (isso requerimport os
):Assim, com a raiz do projeto conhecida, você pode criar uma variável que aponta para a localização da configuração (isso pode ser definido em qualquer lugar, mas um lugar lógico seria colocá-lo em um local onde as constantes são definidas - por exemplo
definitions.py
):Em seguida, você pode facilmente acessar a constante (em qualquer um dos outros ficheiros) com a declaração de importação (por exemplo,
utils.py
):from definitions import CONFIG_PATH
.fonte
__init__.py
arquivo ao diretório raiz do projeto também? Isso deveria estar correto? Acabei de começar com python e não tenho certeza sobre as melhores práticas. Obrigado.__init__.py
não será necessário, já que esse arquivo só é necessário ao definir pacotes: Os__init__.py
arquivos são necessários para fazer o Python tratar os diretórios como contendo pacotes; isso é feito para evitar que diretórios com um nome comum, como string, ocultem acidentalmente módulos válidos que ocorrem posteriormente no caminho de pesquisa do módulo. No caso mais simples,__init__.py
pode ser apenas um arquivo vazio, mas também pode executar o código de inicialização do pacote ou definir a__all__
variável, descrita posteriormente. Consulte: docs.python.org/3/tutorial/modules.html#packages__init.py__
pacote raiz. Isso economizaria a criação de outro arquivo, bem como permitiria uma sintaxe mais agradável defrom root_pack import ROOT_DIR, CONFIG_PATH
.__init__.py
vazio, mas isso não é estritamente verdadeiro (afinal, é uma convenção). Veja mais: stackoverflow.com/questions/2361124/using-init-pyos.path.abspath
está chamando uma string'__file__'
,. Lembre-se de que,__file__
na verdade, é um atributo de importação definido para módulos Python. Neste caso,__file__
retornará o nome do caminho a partir do qual o módulo foi carregado. Leia mais aqui (consulte a seção de módulos): docs.python.org/3/reference/datamodel.htmlOutras respostas conselhos para usar um arquivo no nível superior do projeto. Isso não é necessário se você usar
pathlib.Path
eparent
(Python 3.4 e superior). Considere a seguinte estrutura de diretório onde todos os arquivos excetoREADME.md
eutils.py
foram omitidos.Em
utils.py
nós definimos a seguinte função.Em qualquer módulo do projeto, agora podemos obter a raiz do projeto da seguinte maneira.
Benefícios : Qualquer módulo que chama
get_project_root
pode ser movido sem alterar o comportamento do programa. Somente quando o móduloutils.py
é movido, temos que atualizarget_project_root
e importar (ferramentas de refatoração podem ser usadas para automatizar isso).fonte
Todas as soluções anteriores parecem ser excessivamente complicadas para o que eu acho que você precisa, e muitas vezes não funcionaram para mim. O seguinte comando de uma linha faz o que você deseja:
fonte
Para obter o caminho do módulo "raiz", você pode usar:
Mas o mais interessante é que, se você tiver um "objeto" de configuração em seu módulo superior, poderá -lê-lo- desta forma:
fonte
os
não está disponível por padrão. Precisa importaros
. Portanto, adicionar a linhaimport os
tornaria a resposta mais completa.python3 -m topmodule.submodule.script
ele dará em/path/to/topmodule/submodule
vez de/path/to/topmodule
.Uma maneira padrão de conseguir isso seria usar o
pkg_resources
módulo que faz parte dosetuptools
pacote.setuptools
é usado para criar um pacote python instalável.Você pode usar
pkg_resources
para retornar o conteúdo do arquivo desejado como uma string e você pode usarpkg_resources
para obter o caminho real do arquivo desejado em seu sistema.Digamos que você tenha um pacote chamado
stackoverflow
.Agora, digamos que você deseja acessar o arquivo Rush de um módulo
app.run
. Usepkg_resources.resouces_filename
para obter o caminho para o Rush epkg_resources.resource_string
para obter o conteúdo do Rush; assim:A saída:
Isso funciona para todos os pacotes em seu caminho python. Então, se você quiser saber onde
lxml.etree
existe em seu sistema:resultado:
O ponto é que você pode usar este método padrão para acessar arquivos que estão instalados em seu sistema (por exemplo, pip install xxx ou yum -y install python-xxx) e arquivos que estão dentro do módulo no qual você está trabalhando atualmente.
fonte
Experimentar:
fonte
Abaixo do código retorna o caminho até a raiz do seu projeto
fonte
Eu também lutei com esse problema até chegar a essa solução. Esta é a solução mais limpa na minha opinião.
Em seu setup.py adicione "pacotes"
Na tua python_script.py
fonte
python3 setup.py install
ele não apontava mais para a pasta do código-fonte, mas para o ovo dentro~./virtualenv/..../app.egg
. Então, eu tive que incluir o arquivo de configuração na instalação do pacote.Apenas um exemplo: desejo executar runio.py de dentro de helper1.py
Exemplo de árvore de projeto:
Obtenha a raiz do projeto:
Construir caminho para o script:
fonte
Isso funcionou para mim usando um projeto PyCharm padrão com meu ambiente virtual (venv) sob o diretório raiz do projeto.
O código abaixo não é o mais bonito, mas sempre obtém a raiz do projeto. Ele retorna o caminho completo do diretório para venv da
VIRTUAL_ENV
variável de ambiente, por exemplo/Users/NAME/documents/PROJECT/venv
Em seguida, ele divide o caminho por último
/
, fornecendo uma matriz com dois elementos. O primeiro elemento será o caminho do projeto, por exemplo/Users/NAME/documents/PROJECT
fonte
Recentemente, tenho tentado fazer algo semelhante e descobri que essas respostas são inadequadas para meus casos de uso (uma biblioteca distribuída que precisa detectar a raiz do projeto). Principalmente, tenho lutado contra diferentes ambientes e plataformas, e ainda não encontrei algo perfeitamente universal.
Código local para projeto
Eu vi este exemplo mencionado e usado em alguns lugares, Django, etc.
Por mais simples que seja, só funciona quando o arquivo em que o snippet está, na verdade, faz parte do projeto. Não recuperamos o diretório do projeto, mas sim o diretório do snippet
Da mesma forma, a abordagem sys.modules falha quando chamada de fora do ponto de entrada do aplicativo, especificamente, observei que um thread filho não pode determinar isso sem relação com o módulo ' principal '. Coloquei explicitamente a importação dentro de uma função para demonstrar uma importação de um thread filho, movê-la para o nível superior de app.py resolveria isso.
app.py
settings.py
A execução deste programa produz um erro de atributo:
... portanto, uma solução baseada em threading
Independente de localização
Usando a mesma estrutura de aplicativo de antes, mas modificando settings.py
Resolvendo isso: Primeiro, queremos encontrar com precisão o ID do thread principal. No Python3.4 +, a biblioteca de threading tem
threading.main_thread()
, entretanto, todo mundo não usa 3.4+, então pesquisamos todos os threads procurando pelo thread principal, exceto seu ID. Se o tópico principal já foi encerrado, ele não será listado nothreading.enumerate()
. Levantamos umRuntimeError()
neste caso até encontrar uma solução melhor.Em seguida, encontramos o primeiro frame de pilha do thread principal. Usando a função específica cPython
sys._current_frames()
, obtemos um dicionário de cada frame de pilha atual do thread. Em seguida, utilizandoinspect.getouterframes()
, podemos recuperar a pilha inteira para o thread principal e o primeiro quadro. current_main_frame = sys._current_frames () [main_id] base_frame = inspect.getouterframes (current_main_frame) [- 1] Finalmente, as diferenças entre as implementações do Windows e do Linuxinspect.getouterframes()
precisam ser tratadas. Use o nome do arquivo limpoos.path.abspath()
eos.path.dirname()
limpe as coisas.Até agora, testei isso no Python 2.7 e 3.6 no Windows, bem como no Python3.4 no WSL
fonte
Se você estiver trabalhando com o projeto anaconda, você pode consultar o PROJECT_ROOT da variável de ambiente -> os.getenv ('PROJECT_ROOT'). Isso funciona apenas se o script for executado através da execução do projeto anaconda.
Se você não quiser que seu script seja executado pelo anaconda-project, você pode consultar o caminho absoluto do binário executável do interpretador Python que você está usando e extrair a string do caminho até o diretório envs exclusiv. Por exemplo: O interpretador python do meu env conda está localizado em:
Isso funciona apenas com o projeto conda com estrutura de projeto fixa de um projeto anaconda
fonte
Usei o método ../ para buscar o caminho do projeto atual.
Exemplo: Projeto1 - D: \ projetos
src
ConfigurationFiles
Configuration.cfg
Path = "../ src / ConfigurationFiles / Configuration.cfg"
fonte
No momento em que este artigo foi escrito, nenhuma das outras soluções era muito independente. Eles dependem de uma variável de ambiente ou da posição do módulo na estrutura do pacote. A melhor resposta com a solução 'Django' é vítima da última, exigindo uma importação relativa. Também tem a desvantagem de ter que modificar um módulo no nível superior.
Esta deve ser a abordagem correta para encontrar o caminho do diretório do pacote de nível superior:
Ele funciona pegando o primeiro componente na string pontilhada contida
__name__
e usando-o como uma chave nasys.modules
qual retorna o objeto de módulo do pacote de nível superior. Seu__file__
atributo contém o caminho que queremos depois de cortar/__init__.py
usandoos.path.dirname()
.Esta solução é independente. Ele funciona em qualquer lugar em qualquer módulo do pacote, incluindo no
__init__.py
arquivo de nível superior .fonte
Tive que implementar uma solução customizada porque não é tão simples quanto você imagina. Minha solução é baseada na inspeção de rastreamento de pilha (
inspect.stack()
) +sys.path
e está funcionando bem, não importa a localização do módulo python em que a função é chamada nem o interpretador (tentei executá-lo no PyCharm, em um shell de poesia e outros ... ) Esta é a implementação completa com comentários:fonte
Há muitas respostas aqui, mas não consegui encontrar algo simples que abranja todos os casos, então permita-me sugerir minha solução também:
fonte