我试图用我不拥有的Python项目创建一个库。该项目具有以下目录布局:
.
├── MANIFEST.in
├── pyproject.toml
└── src
├── all.py
├── the.py
└── sources.py
在pyproject.toml
中,我有:
[tool.setuptools]
packages = ["mypkg"]
[tool.setuptools.package-dir]
mypkg = "src"
我面临的问题是,当我构建和安装这个包时,我不能使用它,因为作者在各种源文件中导入没有mypkg
前缀的东西。
F.ex。在all.py
中
from the import SomeThing
因为我不拥有这个包,所以我不能修改所有的源代码,但是我仍然希望能够通过添加MANIFEST.in
和pyproject.toml
来构建一个库。
是否可能以某种方式指示setuptools构建一个包,它不会丢弃所有的源,同时仍然允许在没有site-packages
前缀的情况下导入它们?
发布于 2022-10-14 04:04:07
在包中添加自定义导入挂钩是不可能的。钩子采用随包附带的模块的形式,必须在从模块使用之前导入它(例如,在src/all.py
中)
src/mypkgimp.py
import sys
import importlib
class MyPkgLoader(importlib.abc.Loader):
def find_spec(self, name, path=None, target=None):
# update the list with modules that should be treated special
if name in ['sources', 'the']:
return importlib.util.spec_from_loader(name, self)
return None
def create_module(self, spec):
# Uncomment if "normal" imports should have precedence
# try:
# sys.meta_path = [x for x in sys.meta_path[:] if x is not self]
# return importlib.import_module(spec.name)
# except ImportError:
# pass
# finally:
# sys.meta_path = [self] + sys.meta_path
# Otherwise, this will unconditionally shadow normal imports
module = importlib.import_module('.' + spec.name, 'mypkg')
# Final step: inject the module to the "shortened" name
sys.modules[spec.name] = module
return module
def exec_module(self, module):
pass
if not hasattr(sys, 'frozen'):
sys.meta_path = [MyPkgLoader()] + sys.meta_path
是的,上面使用了我之前链接过的thread描述的不同方法,因为importlib
在Python3.10中反对使用这些方法,有关详细信息,请参阅文档。
无论如何,在演示中,在模块中放置一些虚拟类:
src/the.py
class SomeThing: ...
src/sources.py
class Source: ...
现在,修改src/all.py
,使其具有以下内容:
import mypkg.mypkgimp
from the import SomeThing
示例用法:
>>> from sources import Source
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'sources'
>>> from mypkg import all
>>> all.SomeThing
<class 'mypkg.the.SomeThing'>
>>> from sources import Source
>>> Source
<class 'mypkg.sources.Source'>
>>> from sources import Error
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name 'Error' from 'mypkg.sources' (/tmp/mypkg/src/sources.py)
注意导入最初是如何不工作的,但是在导入mypkg.all
之后,sources
导入现在是全局工作的。因此,可能需要注意不要隐藏“真实”导入,并且我已经提供了使用“默认”*导入机制导入的示例。
如果您希望模块名称看起来不同(即没有mypkg.
前缀),这将是一个单独的问题,因为代码通常不检查它们自己的模块名称是否具有功能(而且没关系,这实际上显示了名称空间是如何隐式使用的--更改实际名称更类似于模块重新定位,这是可以做到的,但更复杂一些,这个答案足够长)。
*“默认”,如不包括此自定义导入钩子引入的行为-其他导入钩子可能会做自己的其他诡计。
https://stackoverflow.com/questions/74039092
复制相似问题