pyd*_*ner 3 python conventions pylint python-import git-submodules
背景
我有一个Python应用程序,它依赖于另一个作为git子模块提供的包,产生类似于以下内容的目录结构:
foo/
bar/
bar/
__init__.py
eggs.py
test/
setup.py
foo/
__init__.py
ham.py
main.py
Run Code Online (Sandbox Code Playgroud)
从顶层目录执行该访问foo包就足够简单了。但是该程序包嵌套在另一个目录中,不能直接导入。main.pyfoo/barbar
通过sys.path在以下内容的开头进行修改,可以轻松解决此问题main.py:
import sys
# Or sys.path.append()
sys.path.insert(0, './bar')
from bar.eggs import Eggs
from foo.ham import Ham
Run Code Online (Sandbox Code Playgroud)
(注意:此代码示例假定main.py将始终从中调用foo/;如果情况并非如此,则'.bar'可以将其替换,os.path.join(os.path.dirname(__file__), 'bar')尽管这样做显然比较麻烦。)
问题
不幸的是,pylint不喜欢这种解决方案。当代码工作时,lint认为sys.path修改是结束于“模块顶部”的代码块,并给出了不希望的wrong-import-position警告:
C: 6, 0: Import "from bar.eggs import Eggs" should be placed at the top of the module (wrong-import-position)
C: 7, 0: Import "from foo.ham import Ham" should be placed at the top of the module (wrong-import-position)
Run Code Online (Sandbox Code Playgroud)
类似问题
该发问者的问题是pylint无法完全正确地解析导入。这个问题的唯一答案暗示着增加了pylint的内部路径。这无济于事,避免对交错sys.path修改的抱怨。
配置pylint
禁用wrong-import-position检查器.pylintrc是最简单的解决方案,但是会丢弃有效的警告。
A better solution is to tell pylint to ignore the wrong-import-position for these imports, inline. The false-positive imports can be nested in an enable-disable block without losing any coverage elsewhere:
import sys
sys.path.insert(0, './bar')
#pylint: disable=wrong-import-position
from bar.eggs import Eggs
from foo.ham import Ham
#pylint: enable=wrong-import-position
Ham()
# Still caught
import something_else
Run Code Online (Sandbox Code Playgroud)
However, this does have the slight downside of funkiness if wrong-import-order is ever disabled in .pylintrc.
Avoid modifying sys.path
Sometimes unwanted linting warnings stem from going about a problem incorrectly to start with. I've come up with a number of ways to avoid modifying sys.path in the first place, though they are not applicable to my own situation.
Perhaps the most straightforward method is to modify PYTHONPATH to include the submodule directory. This, however, must then either be specified each time the application is invoked, or modified on a system/user level, potentially harming other processes. The variable could be set in a wrapping shell or batch script, but this requires either further environmental assumptions or limits changes to the invocation of Python.
A more modern and less trouble-fraught analog is to install the application in a virtual environment and simply add the submodule path to the virtual environment.
Reaching further afield, if the submodule includes a setuptools setup.py, it may simply be installed, avoiding path customization altogether. This may be accomplished by maintaining a publication to repositories such as pypi (a non-starter for proprietary packages) or by utilizing/abusing pip install -e to install either the submodule package directly or from its repository. Once again, virtual environments make this solution simpler by avoiding potential cross-application conflicts and permissions issues.
If the target OS set can be limited to those with strong symlink support (in practice this excludes all Windows through at least 10), the submodules may be linked into to bypass the wrapping directory and put the target package directly in the working directory:
foo/
bar/ --> bar_src/bar
bar_src/
bar/
__init__.py
eggs.py
test/
setup.py
foo/
__init__.py
ham.py
main.py
Run Code Online (Sandbox Code Playgroud)
这样做的缺点是限制了应用程序的潜在用户,并使foo目录混乱不堪,但在某些情况下可能是可接受的解决方案。
| 归档时间: |
|
| 查看次数: |
4805 次 |
| 最近记录: |