sys.pathハックにうんざりしていませんか?
sys.path.append
利用可能な-hacks はたくさんありますが、手元にある問題を解決する別の方法を見つけました。
概要
- コードを1つのフォルダーにラップします(例
packaged_stuff
)
- setuptools.setup()
setup.py
を使用する場合は、作成スクリプトを使用します。
- パッケージを編集可能な状態でピップインストール
pip install -e <myproject_folder>
- 使用してインポート
from packaged_stuff.modulename import function_name
セットアップ
開始点は、と呼ばれるフォルダにラップされた、提供されたファイル構造ですmyproject
。
.
└── myproject
├── api
│ ├── api_key.py
│ ├── api.py
│ └── __init__.py
├── examples
│ ├── example_one.py
│ ├── example_two.py
│ └── __init__.py
├── LICENCE.md
├── README.md
└── tests
├── __init__.py
└── test_one.py
.
ルートフォルダーを呼び出しますC:\tmp\test_imports\
。この例では、フォルダーにあります。
api.py
テストケースとして、次の./api/api.pyを使用します
def function_from_api():
return 'I am the return value from api.api!'
test_one.py
from api.api import function_from_api
def test_function():
print(function_from_api())
if __name__ == '__main__':
test_function()
test_oneを実行してみます。
PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
Traceback (most recent call last):
File ".\myproject\tests\test_one.py", line 1, in <module>
from api.api import function_from_api
ModuleNotFoundError: No module named 'api'
また、相対インポートを試みても機能しません。
使用from ..api.api import function_from_api
すると、
PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
Traceback (most recent call last):
File ".\tests\test_one.py", line 1, in <module>
from ..api.api import function_from_api
ValueError: attempted relative import beyond top-level package
手順
- ルートレベルのディレクトリにsetup.pyファイルを作成する
の内容は次のsetup.py
ようになります*
from setuptools import setup, find_packages
setup(name='myproject', version='1.0', packages=find_packages())
- 仮想環境を使用する
仮想環境に慣れている場合は、仮想環境をアクティブにして、次の手順にスキップしてください。仮想環境の使用は絶対に必須というわけではありませんが、長期的に見ると本当に役立ちます(複数のプロジェクトが進行中の場合)。最も基本的な手順は次のとおりです(ルートフォルダーで実行)
- 仮想環境を作成する
- 仮想環境をアクティブ化
source ./venv/bin/activate
(Linux、macOS)または./venv/Scripts/activate
(Win)
これについて詳しく知るには、「Python virtual env tutorial」などをGoogleから出してください。作成、アクティブ化、非アクティブ化以外のコマンドはおそらく必要ありません。
仮想環境を作成してアクティブ化すると、コンソールに仮想環境の名前が括弧内に表示されます。
PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>
フォルダーツリーは次のようになります**
.
├── myproject
│ ├── api
│ │ ├── api_key.py
│ │ ├── api.py
│ │ └── __init__.py
│ ├── examples
│ │ ├── example_one.py
│ │ ├── example_two.py
│ │ └── __init__.py
│ ├── LICENCE.md
│ ├── README.md
│ └── tests
│ ├── __init__.py
│ └── test_one.py
├── setup.py
└── venv
├── Include
├── Lib
├── pyvenv.cfg
└── Scripts [87 entries exceeds filelimit, not opening dir]
- プロジェクトを編集可能な状態でpipインストールする
を使用して最上位パッケージmyproject
をインストールしますpip
。トリックは-e
、インストールを行うときにフラグを使用することです。これにより、編集可能な状態でインストールされ、.pyファイルに対して行われたすべての編集は、インストールされたパッケージに自動的に含まれます。
ルートディレクトリで、次を実行します。
pip install -e .
(ドットに注意してください。「現在のディレクトリ」を表します)
を使用してインストールされていることも確認できます pip freeze
(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///C:/tmp/test_imports
Installing collected packages: myproject
Running setup.py develop for myproject
Successfully installed myproject
(venv) PS C:\tmp\test_imports> pip freeze
myproject==1.0
myproject.
インポートに追加
myproject.
他の方法では機能しないインポートにのみ追加する必要があることに注意してください。setup.py
&なしで機能したインポートはpip install
引き続き正常に機能します。以下の例を参照してください。
ソリューションをテストする
次に、api.py
上でtest_one.py
定義した定義と下で定義した定義を使用してソリューションをテストします。
test_one.py
from myproject.api.api import function_from_api
def test_function():
print(function_from_api())
if __name__ == '__main__':
test_function()
テストを実行する
(venv) PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
I am the return value from api.api!
*詳細なsetup.pyの例については、setuptoolsのドキュメントをご覧ください。
**実際には、仮想環境をハードディスクのどこにでも置くことができます。
sys.path
ハックをスキップして、これまでに投稿された(7年後の)唯一の実際のソリューションを読むことをお勧めします。