pythonのmoduleとpackage周り
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 以外になった module は package に属している。
エントリポイントは __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}}}= Nonemod.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}}}.pyunknown: 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}}}= Nonemod3/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 ができない。
💩仕様。