ImportError: attempted relative import with no known parent package

相対Importの制限

わいのやりたいことは実現不可能なのだな。 packageの内部でちょっとしたテストをするコードを、

if __name__ == '__main__':
    sample()

という風に書いて実行しようとしていたのだが、 同階層のファイルを、

from . import my_module
ImportError: attempted relative import with no known parent package

で阻まれてしまう。 エントリポイントが、

__package__ == None
__name__ == '__main__'

となるので、ImportError となるのである。 こんちくしょう。

無理やり誤魔化すなら・・・

もう一つ外のソースから import したかのように偽装する。

python -c 'import my_package; my_package.sample()'

💩過ぎる。 ライブラリにユーティリティが付属している場合にめちゃくちゃ作りづらい。 前からPythonのもっとも💩なところだと思っていた。 ライブラリの開発時に部分的に実行する時に邪魔でしかない。

package

複数のモジュールを束ねたもの。 import したときに __package__None 以外になった modulepackage に属している。

エントリポイントは __package__ = None

以下のファイル構成で実験してみた。

main.py # import mod
mod.py # import mod2
mod2.py # import mod3
mod3
    + __init__.py # from . import mod4
    + mod4.py

# それぞれ以下を記述
print(f'"{__name__}" in "{__package__}"')

python main.py として実行

__package__ が、

  • main.py

    unknown: strong => {"type":"strong","children":[{"type":"text","value":"packag","position":{"start":{"line":76,"column":13,"offset":1149},"end":{"line":76,"column":19,"offset":1155}}}],"position":{"start":{"line":76,"column":11,"offset":1147},"end":{"line":76,"column":21,"offset":1157}}}
    = None

  • mod.py

    unknown: strong => {"type":"strong","children":[{"type":"text","value":"packag","position":{"start":{"line":77,"column":12,"offset":1176},"end":{"line":77,"column":18,"offset":1182}}}],"position":{"start":{"line":77,"column":10,"offset":1174},"end":{"line":77,"column":20,"offset":1184}}}
    = ""

  • mod2.py

    unknown: strong => {"type":"strong","children":[{"type":"text","value":"packag","position":{"start":{"line":78,"column":13,"offset":1202},"end":{"line":78,"column":19,"offset":1208}}}],"position":{"start":{"line":78,"column":11,"offset":1200},"end":{"line":78,"column":21,"offset":1210}}}
    = ""

  • mod3/

    unknown: strong => {"type":"strong","children":[{"type":"text","value":"init","position":{"start":{"line":79,"column":10,"offset":1225},"end":{"line":79,"column":14,"offset":1229}}}],"position":{"start":{"line":79,"column":8,"offset":1223},"end":{"line":79,"column":16,"offset":1231}}}
    .py
    unknown: strong => {"type":"strong","children":[{"type":"text","value":"packag","position":{"start":{"line":79,"column":22,"offset":1237},"end":{"line":79,"column":28,"offset":1243}}}],"position":{"start":{"line":79,"column":20,"offset":1235},"end":{"line":79,"column":30,"offset":1245}}}
    = "mod3"

  • mod3/mod4.py

    unknown: strong => {"type":"strong","children":[{"type":"text","value":"packag","position":{"start":{"line":80,"column":18,"offset":1272},"end":{"line":80,"column":24,"offset":1278}}}],"position":{"start":{"line":80,"column":16,"offset":1270},"end":{"line":80,"column":26,"offset":1280}}}
    = "mod3"

  • mod3/

    unknown: strong => {"type":"strong","children":[{"type":"text","value":"init","position":{"start":{"line":84,"column":10,"offset":1303},"end":{"line":84,"column":14,"offset":1307}}}],"position":{"start":{"line":84,"column":8,"offset":1301},"end":{"line":84,"column":16,"offset":1309}}}
    .py.
    unknown: strong => {"type":"strong","children":[{"type":"text","value":"packag","position":{"start":{"line":84,"column":23,"offset":1316},"end":{"line":84,"column":29,"offset":1322}}}],"position":{"start":{"line":84,"column":21,"offset":1314},"end":{"line":84,"column":31,"offset":1324}}}
    = "mod3"

  • mod3/mod4.py.

    unknown: strong => {"type":"strong","children":[{"type":"text","value":"packag","position":{"start":{"line":85,"column":19,"offset":1352},"end":{"line":85,"column":25,"offset":1358}}}],"position":{"start":{"line":85,"column":17,"offset":1350},"end":{"line":85,"column":27,"offset":1360}}}
    = "mod3"

のみが from . import mod4 等の相対インポートが可能だった。 他は、

ImportError: attempted relative import with no known parent package

が出る。 つまり、__packag__ が None(エントリポイント) もしくは ""(エントリポイントと同じ階層) であると相対インポートができない。

python mod3/__init__.py とすると、

  • mod3/

    unknown: strong => {"type":"strong","children":[{"type":"text","value":"init","position":{"start":{"line":99,"column":10,"offset":1618},"end":{"line":99,"column":14,"offset":1622}}}],"position":{"start":{"line":99,"column":8,"offset":1616},"end":{"line":99,"column":16,"offset":1624}}}
    .py.
    unknown: strong => {"type":"strong","children":[{"type":"text","value":"packag","position":{"start":{"line":99,"column":23,"offset":1631},"end":{"line":99,"column":29,"offset":1637}}}],"position":{"start":{"line":99,"column":21,"offset":1629},"end":{"line":99,"column":31,"offset":1639}}}
    = None

  • mod3/mod4.py.

    unknown: strong => {"type":"strong","children":[{"type":"text","value":"packag","position":{"start":{"line":100,"column":19,"offset":1665},"end":{"line":100,"column":25,"offset":1671}}}],"position":{"start":{"line":100,"column":17,"offset":1663},"end":{"line":100,"column":27,"offset":1673}}}
    = ""

と変化して、相対 import ができない。

💩仕様。