打包一个 Python 项目及其关联的 IPython 魔术扩展

Packaging a Python project and its associated IPython magic extension

我正在向 Pypi 部署一个 Python 项目,我们称它为 foobar。我想用 shell 命令 一个 IPython 魔术命令来分发它。我使用 Poetry,我的 .toml 配置文件的相关部分是:

  [tool.poetry.scripts]
  foobar = 'foobar.cli:main'
  foobar_magic = 'foobar.magic:load_ipython_extension'

将其上传到 TestPypi 并使用 pip 安装后,shell 命令 (foobar) 按预期工作。但是,在 Jupyter Notebook 中执行 %load_ext foobar_magic 失败并显示:

  ModuleNotFoundError: No module named 'foobar_magic'

根据 documentation:

You can put your extension modules anywhere you want, as long as they can be imported by Python’s standard import mechanism.

在同一个笔记本下,我验证了!foobarimport foobar都有效。我怎样才能让 foobar_magic 也被发现?

另外,虽然我还没到,估计入口点的后缀也是错误的。事实上,我在 : 之后指定的函数将在没有参数的情况下被调用,但是函数 load_ipython_extension() 需要一个 IPython 实例。

所以我感到完全迷失了,找不到任何部署 IPython Notebook 扩展的相关文档。


编辑 1. %load_ext foobar.magic 出乎意料的有效,魔术 %foobar 没有抱怨参数。我不明白为什么,为什么它是 %foobar 而不是声明的 %foobar_magic

编辑 2. foobar_magic = ... 内容被忽略或无用。抑制它对 %load_ext foobar.magic 没有任何影响。我认为后一种调用可能没问题。但是不明白这是怎么回事有点烦人。

我终于找到了解决方法:

  1. 删除我的.toml的第foobar_magic = ...行。
  2. foobar/magic.py的内容移动到foobar/__init__.py(原来是空的),用下面两行守护:

    import sys
    if "ipykernel" in sys.modules:
       # magic stuff
    
  3. 每次导入模块时都会执行这个文件,现在做就够了(笔记本下):

    %load_ext foobar
    

    当且仅当从 IPython.

  4. 导入 foobar 时,守卫确保执行神奇的东西

这没有回答我最初的问题,我仍然不完全理解这些入口点应该如何工作,但我对实际结果很满意。