web-dev-qa-db-ja.com

基本的なパッケージセットアップ用に__main __。py、__ init__.py、および__setup__.pyを構成する方法

バックグラウンド:

私は次のようなディレクトリ構造を持っています:

Package/
    setup.py
    src/
        __init__.py
        __main__.py 
        code.py

さまざまな方法でコードを実行できるようにしたいと考えています。

  1. pip install Packagepythonfrom Package import *

  2. python -m Package__main__.pyの処理を行う必要があります

  3. python __main__.py__main__.pyの機能を実行する必要がありますが、今回は、pip installingではなくソースをダウンロードしたと仮定します。

これで最初の2つが機能するようになりましたが、設定が面倒です:

setup.py:

setup(
    name='Package',
    packages=['Package'],
    package_dir={'Package': 'src'},
    ...
    entry_points={ 'console_scripts': ['Package = src.__main__:main' ] }

__ init__.py:

from Package.code import .......

__ main__.py:

from . import .......

私にとってより理にかなっているのは、両方の場合に書くことです

from code import ........

しかし、それはインポートエラーを与えます。

質問:

私が持っている方法は本当に唯一の方法ですか?

そして最も重要なことは、3番目のユースケースをどのようにサポートするかということです。今、python __main__.pyがスローします

File "__main__.py", line 10, in <module>
    from . import code
ImportError: cannot import name 'class defined in code.py'

ノート:

読みました

35
Alex Lenail

必要なものはほぼすべて揃っています(もう少し)。私は次のセットアップで行きます:

code.py

foo = 1

__ init__.py:

from .code import foo

パッケージ全体をインポートするときに__init__.pyが使用されるため、ここで相対インポートを実行します。 Python 3(および.を実行した場合はPython 2)に必要であるため、from __future__ import absolute_import-- syntaxを使用してインポートを明示的に相対としてマークすることに注意してください。

__ main__.py:

from Package import foo

print('foo = ', foo)

これはパッケージのメインスクリプトであるため、絶対importステートメントを使用します。そうすることで、パッケージがインストールされている(または少なくともパスに置かれている)と仮定します。それがパッケージの扱い方です!これは3番目のユースケースと競合すると思うかもしれませんが、実際にはパッケージを扱うときにpip installに理由notはありません。そして、それは本当に大したことではありません(特に virtualenv を使用する場合)!

ソースファイルをいじり、__main__.pyファイルを実行して簡単に変更を確認する場合は、-e(「編集可能」)スイッチを使用してパッケージをインストールするだけです。pip install -e .(ディレクトリPackage )。ただし、現在のディレクトリ構造では、-eスイッチがEgg-linksetup.pyファイルを含むディレクトリに配置するため、これは機能しません。このディレクトリにはPackageという名前のパッケージは含まれていませんが、代わりにsrcという名前があります(私は それに関する質問 を持っています)。

代わりに、パッケージ自体(例ではPackage)に基づいてパッケージのソースのルートディレクトリに名前を付ける規則に従っている場合、-eを使用したインストールは問題ありません:Pythonは、対応するディレクトリで必要なパッケージPackageを検索します

$ tree Package/
Package/
├── setup.py
└── Package   <-- Renamed "src" to "Package" because that's the package's name.
    ├── code.py
    ├── __init__.py
    └── __main__.py

これにより、package_dir={'Package': 'src'}setup.pyの追加の定義を省略できます。

setup.pyに関する注意:指定した3つのユースケースでは、エントリポイントを定義する必要はありません。つまり、entry_points={ 'console_scripts': ['Package = src.__main__:main' ] }行をスキップできます。 __main__.pyモジュールを出荷することにより、python -m Packageはこのモジュールのコードを容易に実行します。追加のif節を追加することもできます。

def main():
    print('foo = ', foo)

if __== '__main__':
    main()

一方、エントリポイントを使用すると、CLIから__main__.mainのコードを直接実行できます。 $ Packageを実行すると、対応するコードが実行されます。

要約

一番下の行は、パッケージを扱うときに常にpip installを使用するということです。そして、特にsetup.pyファイルをすでに作成している場合はどうでしょうか?パッケージへの変更を「リアルタイム」で適用する場合は、-eスイッチを使用してインストールできます(これには、srcフォルダーの名前変更が必要になる場合があります。上記を参照)。したがって、3番目の使用例は、「ソースとpip install (-e) Package(virtualenv内)をダウンロードし、その後python __main__.pyを実行できます」と読みます。


編集

__main__.pyなしでpip installを実行する

Pipを介してパッケージをインストールしたくないが、__main__.pyスクリプトを実行できる場合は、上記のセットアップを使用します。次に、from Package import ...ステートメントがまだ成功していることを確認する必要があります。これは、インポートパスを拡張することで実現できます(これには、srcディレクトリの名前をパッケージ名に変更する必要があります!)。

PYTHONPATHを変更

Linux bashの場合、次のようにPythonpathを設定できます。

export PYTHONPATH=$PYTHONPATH:/path/to/Package

または、__main__.pyと同じディレクトリにいる場合:

export PYTHONPATH=$PYTHONPATH:`cd ..; pwd`

もちろん、オペレーティングシステムごとに異なる方法があります。

__main__.pyのパスを拡張します

あなた(またはあなたの同僚)は、スクリプトの先頭(from Package import ...ステートメントの前)に次の行を追加できます。

import sys
sys.path.append('/path/to/Package')

sitecustomize.pyのパスを拡張します

次の行を含むPythonインストールのsitecustomize.pyディレクトリに lib/python3.5/site-packages/ という名前のモジュールを配置できます。

import sys
sys.path.append('/path/to/Package')

別のトップレベルのmain.pyスクリプトを作成します

したがって、次のレイアウトになります。

$ tree Package/
Package/
├── main.py   <-- Add this file.
├── setup.py
└── src
    ├── code.py
    ├── __init__.py
    └── __main__.py

main.pyには次が含まれます

import src.__main__

これで__main__.pysrcパッケージの一部として扱われ、相対インポートが機能します。 python src/__main__.pyを実行する代わりに、今すぐpython main.pyを実行します。

25
a_guest

codeという名前のシステムにPythonパッケージがインストールされていないため、from code import .........は失敗します。 codeという名前のシステムにはPython moduleがありますが、importステートメントではcodeモジュールのパッケージを指定しませんで見つけることができます。

__init__.pyにあるsrc/ファイルの目的は、src/ディレクトリをPythonパッケージとして処理する必要があることをPythonに伝えますパッケージ内のモジュールとしてのコンテンツ。 code.pysrc/ファイルと共に__init__.pyにあるため、codeモジュールはsrcパッケージにあります。

codeモジュールがどのパッケージにあるかがわかったので、次のものを使用してそこからものをインポートできます。

from src.code import .........

また、補足として:__init__.pysrc/ディレクトリに存在するだけで機能するため、コードを含める必要さえありません。そのため、__init__.pyファイルを空白のままにしておくことをお勧めします。

2
MatTheWhale

このセットアップは、python setup.py develop

Package_root/
    setup.py
    src/
        Package/
            __init__.py
            __main__.py 
            code.py

それはおそらく(まだ)あなたが期待している詳細な答えではありませんが、3つのユースケースに挑戦する価値があると思います。

setup( ...
    package_dir = {'': 'src'},
    entry_points = {'console_scripts': ['Package = Package.__main__:main'],},
    packages = find_packages(exclude=["Package.Egg_info",]),
...)
0
Gribouillis