如何获取当前的“包"名称?(setup.py) [英] How do I get the current 'package' name? (setup.py)
问题描述
如何获取当前最顶层的包,即 setup.py 中定义的名称?
这是我的树
:
到目前为止,我工作的唯一解决方案是:
导入操作系统导入系统os.path.basename(sys.path[1])
但这显然是一个糟糕的解决方案.其他解决方案,例如在我最上层的 __init__.py
文件中有一个 __name__
并使用 ast.parse
阅读setup.py
的相关部分也显得很麻烦.
我尝试过的其他解决方案——通过在 unittest.TestCase
在我的tests
python [sub]包中继承class
——包括检查sys.modules[__name__]代码>,
inspect.getmodule
&inspect.stack
,以及作为这些问题的答案:
- Python - 获取根项目结构路径
- 获取完整的包模块名称
- 在 Python 中获取对象的完全限定类名
- 如何在 Python 中访问当前执行的模块或类名?
- 获取完整的调用者名称(package.module.function)(Python 秘籍)
- https://docs.python.org/2/library/modulefinder.html
顺便说一句:如果你想知道为什么我想要包名......这样我就可以运行:
import pkg_resourcesversion = pkg_resources.require('the_project_name_for_this_pkg')[0].versiondata_file = path.join(resource_filename('the_project_name_for_this_pkg', '__init__.py'),'_config', 'data_file.txt')
不完全确定更大的目标是什么,但也许您可能有兴趣阅读 importlib.resources
以及 importlib.metadata
.
类似于以下内容:
import importlib.metadata导入 importlib.resourcesversion = importlib.metadata.version('SomeProject')data = importlib.resources.files('top_level_package.sub_package').joinpath('file.txt').read_text()
更一般地说,从代码中 100% 可靠地检测项目的名称 (SomeProject
) 几乎是不可能的(或不值得进行大量的工作).直接对其进行硬编码会更容易.
不过,这里有一些技术和想法,可以从其中一个模块中检索项目名称:
- https://bitbucket.org/pypa/distlib/issues/102/getting-the-distribution-that-a-module
- https://stackoverflow.com/a/22845276/11138259
- https://stackoverflow.com/a/56032725/11138259
更新:
我相信像下面这样的函数应该返回包含当前文件的已安装发行版的名称:
导入路径库导入 importlib_metadatadef get_project_name():对于 importlib_metadata.distributions() 中的 dist:尝试:relative = pathlib.Path(__file__).relative_to(dist.locate_file(''))除了值错误:经过别的:如果在 dist.files 中相对:返回 dist.metadata['Name']返回无
更新(2021 年 2 月):
由于 importlib_metadata
中新添加的 packages_distributions()
函数,看起来这会变得更容易:
- https://importlib-metadata.readthedocs.io/en/stable/using.html#package-distributions
- https://github.com/python/importlib_metadata/pull/287/files
How do I get the current topmost package, i.e., the name defined in setup.py?
Here is my tree
:
.
|-- README.md
|-- the_project_name_for_this_pkg
| |-- __init__.py
| |-- __main__.py
| |-- _config
| | `-- foo.conf
| |-- _data
| | `-- logging.yml
| `-- tests
| |-- __init__.py
| `-- test_foo.py <--- # executing from here
|-- requirements.txt
`-- setup.py
4 directories, 9 files
The only solution I've gotten to work so far is this:
import os
import sys
os.path.basename(sys.path[1])
But this is obviously a bad solution. Other solutions like having a __name__
in my uppermost __init__.py
file and using ast.parse
to read in the relevant section of setup.py
also seems cumbersome.
Other solutions I've tried—by calling them within a unittest.TestCase
inheriting class
in my tests
python [sub]package—include checking sys.modules[__name__]
, inspect.getmodule
& inspect.stack
, as well as the answers to these questions:
- Python - Get path of root project structure
- Get full package module name
- Get fully qualified class name of an object in Python
- How can I access the current executing module or class name in Python?
- Get full caller name (package.module.function) (Python recipe)
- https://docs.python.org/2/library/modulefinder.html
BTW: In case you were wondering why I want the package name… it's so I can run things like:
import pkg_resources
version = pkg_resources.require('the_project_name_for_this_pkg')[0].version
data_file = path.join(resource_filename('the_project_name_for_this_pkg', '__init__.py'),
'_config', 'data_file.txt')
Not entirely sure what the larger goal is, but maybe you could be interested in reading about importlib.resources
as well as importlib.metadata
.
Something like the following:
import importlib.metadata
import importlib.resources
version = importlib.metadata.version('SomeProject')
data = importlib.resources.files('top_level_package.sub_package').joinpath('file.txt').read_text()
And more generally, it is near impossible (or not worth the amount of work) to 100% reliably detect the name of the project (SomeProject
) from within the code. It is easier to just hard-code it.
Nevertheless here are some techniques, and ideas to retrieve the name of the project from one of its modules:
- https://bitbucket.org/pypa/distlib/issues/102/getting-the-distribution-that-a-module
- https://stackoverflow.com/a/22845276/11138259
- https://stackoverflow.com/a/56032725/11138259
Update:
I believe some function like the following should return the name of the installed distribution containing the current file:
import pathlib
import importlib_metadata
def get_project_name():
for dist in importlib_metadata.distributions():
try:
relative = pathlib.Path(__file__).relative_to(dist.locate_file(''))
except ValueError:
pass
else:
if relative in dist.files:
return dist.metadata['Name']
return None
Update (February 2021):
Looks like this could become easier thanks to the newly added packages_distributions()
function in importlib_metadata
:
- https://importlib-metadata.readthedocs.io/en/stable/using.html#package-distributions
- https://github.com/python/importlib_metadata/pull/287/files
这篇关于如何获取当前的“包"名称?(setup.py)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!