web-dev-qa-db-ja.com

PEP8 – .sys.pathでファイルの先頭にないインポート

問題

PEP8には、インポートをファイルの先頭に置くことに関するルールがあります。

インポートは常にファイルの先頭、モジュールのコメントとドキュメント文字列の直後、モジュールのグローバルと定数の前に置かれます。

ただし、特定のケースでは、次のようなことをしたい場合があります。

import sys
sys.path.insert("..", 0)

import my_module

この場合、pep8コマンドラインユーティリティは私のコードにフラグを立てます:

E402モジュールレベルのインポートがファイルの先頭にありません

sys.pathの変更でPEP8に準拠するための最良の方法は何ですか?

なぜ

The Hitchhiker's Guide to Python で指定されている プロジェクト構造 に従っているため、このコードがあります。

このガイドでは、testsフォルダーとは別のmy_moduleフォルダーがあり、どちらも同じディレクトリにあることを推奨しています。 testsからmy_moduleにアクセスするには、..sys.pathに追加する必要があると思います

53
Luke Taylor

多くの場合、プロジェクトのサブディレクトリfoo/testsにテストのある複数のファイルがありますが、テストしているモジュールはfoo/srcにあります。インポートエラーなしでfoo/testsからテストを実行するには、次のようなファイルfoo/tests/pathmagic.pyを作成します。

"""Path hack to make tests work."""

import os
import sys

bp = os.path.dirname(os.path.realpath('.')).split(os.sep)
modpath = os.sep.join(bp + ['src'])
sys.path.insert(0, modpath)

すべてのテストファイルで、次に使用します

import pathmagic  # noqa

最初のインポートとして。 「noqa」コメントは、pycodestyle/pep8が未使用のインポートについて文句を言うのを防ぎます。

36
Roland Smith

インポートが数個しかない場合、それらのimport行のPEP8を無視できます:

import sys
sys.path.insert("..", 0)
import my_module  # noqa: E402
53
astorga

別の回避策があります。

import sys
... all your other imports...

sys.path.insert("..", 0)
try:
    import my_module
except:
    raise
9
Peuchele

私は同様の質問に苦労しましたが、受け入れられた答えよりも少しいい解決策を見つけたと思います。

実際のsys.path操作を行うpathmagicモジュールを作成しますが、 context manager内で変更を行います

"""Path hack to make tests work."""

import os
import sys

class context:
    def __enter__(self):
        bp = os.path.dirname(os.path.realpath('.')).split(os.sep)
        modpath = os.sep.join(bp + ['src'])
        sys.path.insert(0, modpath)

    def __exit__(self, *args):
        pass

次に、テストファイル(または必要な場所)で、次の操作を行います。

import pathmagic

with pathmagic.context():
    import my_module
    # ...

このように、flake8/pycodestyleから苦情を受け取らず、特別なコメントを必要とせず、構造は理にかなっているようです。

簡潔にするために、実際に__exit__ブロック内のパスを元に戻すことを検討してください。ただし、これは遅延インポート(モジュールコードをコンテキストの外に置く場合)で問題を引き起こす可能性があります。


[〜#〜] edit [〜#〜]:別の質問への 回答でもっと簡単なトリックを見たnoqaコメントを避けるために、インポートの下にassert pathmagicを追加します。

4
itsadok

すでに次のことを試しましたか:

import sys
from importlib import import_module

sys.path.insert("..", 0)

# import module
my_mod = import_module('my_module')

# get method or function from my_mod
my_method = getattr(my_mod , 'my_method')
2
Daniel Lee

Pep8に準拠するには、相対/絶対インポートを実行するためにpythonパスにプロジェクトパスを含める必要があります。

これを行うには、次の回答をご覧ください。 PYTHONPATHにディレクトリを永続的に追加

2
Pierre Barre