将 JS 文件移动到 site-packages/notebook/static 的潜在不明智之处

the potential inadvisability of moving JS files to site-packages/notebook/static

我有一个 setup.py 配置可以工作,但感觉非常糟糕。 它适用于一个小部件(通过 ipywidgets.DOMWidget 继承),其 JS 代码是多部分的并且在所有 CDN 中都是错误的——所以我不能简单地 require(['www.some_cdn.com/foo']) 在注入浏览器的 JS 中。 结果 post-安装我得到 setup.py 将所需的文件复制到 site-packages/notebook/static,允许 JS require(['/static/jsfolder/some.entry.point.js']) 工作(下面的代码)。

我想一定有一个标准的方法可以做到这一点,特别是因为这个 hack 只适用于源代码分发而不是 wheel,但我莫名其妙地似乎无法找到“官方”方法。我找不到的文档在哪里?

import os
import importlib.util
from distutils.dir_util import copy_tree, remove_tree
from distutils import log

def post_install():
    """
    Moves the jsfolder folder contents to site-packages/notebook/static
    """
    log.info('copying files over to site-packages/notebook/static')
    init_of_notebook = importlib.util.find_spec('notebook').origin
    copy_tree('jsfolder', os.path.join(os.path.dirname(init_of_notebook), 'static', 'jsfolder'))

# are we in a github or a source package?
if os.path.exists(os.path.join('.git')) and not os.path.exists('PKG-INFO'):
    # we are in a git repo, so the usual fluff for pypi
    with open('README.md') as f:
        readme = f.read(). # etc.
    # any pre-packaging tinkering would probably happen here
    # ...

setup(...,
      include_package_data=True,  # MANIFEST.in has `recursive-include * *.png *.js *.css *.gif *.txt` or `graft jsfolder/**` etc.
      )
post_install()
好奇路人的解释性脚注

这个问题非常技术性,所以为了防止未来的用户偶然发现顺便说的东西,我想我会扩展它——只是不要复制黑客!

在 Jupyter notebook 中,你可以 not 在 URL 中指定的根目录下提供任何东西(幸运的是),除了特殊路由 /static以预期的 MIME 类型提供 site-packages/notebook/static 中的文件,static/contents 中的文件除外,它们是 text/htmlsite-packages是pip安装包一般放的文件夹。

如果有 MANIFEST.in 文件,setup 中的 include_package_data=True 参数将指定的文件复制到存储库根目录中的源分发,而不需要 __init__.py 在每个文件夹中不像更干净但更费力的 package_data 参数。

这里有几个post执行代码预安装和post-install涉及继承from setuptools.command.install import install。截至 2022 年,python setup.py install 已弃用,取而代之的是 pip install .,其中许多无效。

此外,任何 log.info 都比 print 好,因为它会显示为 pip install foo.tar.gz -v

official-ish 解决方案似乎是 https://github.com/jupyter/jupyter-packaging 这用于 https://github.com/jupyter-widgets/widget-cookiecutter

中的示例
from jupyter_packaging import wrap_installers, npm_builder
from types import FunctionType
from typing import Dict
builder:FunctionType = npm_builder()
cmdclass:Dict[str,type] = wrap_installers(pre_develop=builder, pre_dist=builder)
setup(cmdclass=cmdclass, ...))

与我的 hack 不同,他们通过 nodejs 包管理器安装 js。即, npm_builder 是一个工厂,它...

import inspect
print(inspect.getsource(npm_builder))

以下:

def npm_builder(
    path=None, build_dir=None, source_dir=None, build_cmd="build", force=False, npm=None
):
...
npm_cmd = npm
...
def builder():
    ...
    npm_cmd = npm
    ...
    run(npm_cmd + ["install"], cwd=node_package)
            if build_cmd:
                run(npm_cmd + ["run", build_cmd], cwd=node_package)