【发布时间】:2017-01-24 12:29:21
【问题描述】:
TL;DR
这是一个示例存储库,其设置如第一张图(下图)所述:https://github.com/Poddster/package_problems
如果您可以让它在项目组织方面看起来像第二张图并且仍然可以运行以下命令,那么您已经回答了这个问题:
$ git clone https://github.com/Poddster/package_problems.git
$ cd package_problems
<do your magic here>
$ nosetests
$ ./my_tool/my_tool.py
$ ./my_tool/t.py
$ ./my_tool/d.py
(or for the above commands, $ cd ./my_tool/ && ./my_tool.py is also acceptable)
或者:给我一个不同的项目结构,允许我将相关文件(“包”)组合在一起,单独运行所有文件,将文件导入同一包中的其他文件,并将包/文件导入到其他包的文件。
现状
我有一堆 python 文件。它们中的大多数在可从命令行调用时很有用,即它们都使用 argparse 和 if __name__ == "__main__" 来做有用的事情。
目前我有这个目录结构,一切正常:
.
├── config.txt
├── docs/
│ ├── ...
├── my_tool.py
├── a.py
├── b.py
├── c.py
├── d.py
├── e.py
├── README.md
├── tests
│ ├── __init__.py
│ ├── a.py
│ ├── b.py
│ ├── c.py
│ ├── d.py
│ └── e.py
└── resources
├── ...
一些脚本import 来自其他脚本的东西来完成它们的工作。但是没有脚本仅仅是一个库,它们都是可调用的。例如我可以调用./my_tool.py、./a.by、./b.py、./c.py 等,它们会为用户做有用的事情。
“my_tool.py”是利用所有其他脚本的主脚本。
我想要发生的事情
但是我想改变项目的组织方式。该项目本身代表了一个可供用户使用的整个程序,并将按原样分发,但我知道它的一部分将在以后的不同项目中有用,所以我想尝试将当前文件封装到一个包中。在不久的将来,我还将在同一个项目中添加其他包。
为了促进这一点,我决定将项目重新组织为以下内容:
.
├── config.txt
├── docs/
│ ├── ...
├── my_tool
│ ├── __init__.py
│ ├── my_tool.py
│ ├── a.py
│ ├── b.py
│ ├── c.py
│ ├── d.py
│ ├── e.py
│ └── tests
│ ├── __init__.py
│ ├── a.py
│ ├── b.py
│ ├── c.py
│ ├── d.py
│ └── e.py
├── package2
│ ├── __init__.py
│ ├── my_second_package.py
| ├── ...
├── README.md
└── resources
├── ...
但是,我想不出满足以下条件的项目组织:
- 所有脚本都可以在命令行中调用(
my_tool\a.py或cd my_tool && a.py) - 测试实际运行:)
- package2 中的文件可以做
import my_tool
主要问题在于包和测试使用的导入语句。
目前,包括测试在内的所有包都只需执行import <module> 即可正确解析。但是,当在它周围晃动东西时,它就不起作用了。
请注意,支持 py2.7 是一项要求,因此所有文件的顶部都有 from __future__ import absolute_import, ...。
我的尝试,以及灾难性的结果
1
如果我如上所示移动文件,但将所有导入语句保留为当前状态:
-
$ ./my_tool/*.py工作正常,它们都运行正常 -
$ nosetests从顶层目录运行不起作用。测试无法导入包脚本。 - pycharm 在编辑这些文件时以红色突出显示导入语句 :(
2
如果我将测试脚本更改为:
from my_tool import x
-
$ ./my_tool/*.py仍然可以正常运行 -
$ nosetests从顶层目录运行不起作用。然后测试可以导入正确的脚本,但是当测试脚本导入它们时,脚本本身的导入会失败。 - pycharm 在主脚本中仍以红色突出显示导入语句 :(
3
如果我保持相同的结构并将 everything 更改为 from my_tool import 那么:
-
$ ./my_tool/*.py导致ImportErrors -
$ nosetests一切正常。 - pycharm 不会抱怨任何事情
例如1 个:
Traceback (most recent call last):
File "./my_tool/a.py", line 34, in <module>
from my_tool import b
ImportError: cannot import name b
4
我也尝试过from . import x,但最终还是使用ValueError: Attempted relative import in non-package 直接运行脚本。
查看其他一些 SO 答案:
我不能只使用python -m pkg.tests.core_test作为
a) 我没有 main.py。我想我可以拥有一个?
b) 我希望能够运行所有脚本,而不仅仅是主脚本?
我试过了:
if __name__ == '__main__' and __package__ is None:
from os import sys, path
sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
但这没有帮助。
我也试过了:
__package__ = "my_tool"
from . import b
但收到了:
SystemError: Parent module 'loading_tool' not loaded, cannot perform relative import
在from . import b 之前添加import my_tool 会以ImportError: cannot import name b 结束
修复?
什么是正确的魔法咒语和目录布局来完成所有这些工作?
【问题讨论】:
-
如果你在包内阅读,你应该使用 .{module_name} 让解释器(和用户)知道它是本地的。如果要在资源中导入 my_tool,请添加 from .my_tool import {submodule_name}
-
my_second_package.py这个名称是否具有误导性,因为my_second_package是一个模块?也许my_second_package.py应该命名为another_mod.py。然后您可以创建另一个目录和文件,例如:package2/my_third_package/__init__.py,这实际上是package2包中的第三个包。
标签: python python-2.7 import pycharm packages