【问题标题】:What is the correct way to import modules for standalone app created using `python -m zipapp`?为使用`python -m zipapp`创建的独立应用程序导入模块的正确方法是什么?
【发布时间】:2020-09-27 21:10:50
【问题描述】:

我有一个要作为独立应用程序分发的模块。模块结构如下:

$ tree -L 2 ./
./
├── mymodule
│   ├── __main__.py
│   ├── fun.py
└── mymodule.pyz

mymodule/__main__.py 包含下一行:

#!/usr/bin/env python

import argparse
import sys
import os.path
from mymodule.fun import Fun

def main():
    sys.stdout.write('main is running')
    Fun().run()

if __name__ == '__main__':
    main()

mymodule/fun.py 包含下一行:

#!/usr/bin/env python

import sys

class Fun:
    """FUN"""

    def __init__(self):
        pass

    def run(self):
        sys.stdout.write("fun")

如果我使用$ python -m mymodule 运行模块,则输出为 main is runningfun

但是如果我使用 $ python -m zipapp -p "/usr/bin/evn python" mymodule 创建一个独立的应用程序并运行它 $ python mymodule.pyz 我得到了错误

Traceback (most recent call last):
  File "/Users/igork/.pyenv/versions/3.6.4/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/Users/igork/.pyenv/versions/3.6.4/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "mymodule.pyz/__main__.py", line 6, in <module>
ModuleNotFoundError: No module named 'mymodule'

import 有什么问题?

更新: sys.path 输出

$ python -m mymodule
['', '/Users/igork/.pyenv/versions/3.6.4/lib/python36.zip', '/Users/igork/.pyenv/versions/3.6.4/lib/python3.6', '/Users/igork/.pyenv/versions/3.6.4/lib/python3.6/lib-dynload', '/Users/igork/.local/lib/python3.6/site-packages', '/Users/igork/.pyenv/versions/3.6.4/lib/python3.6/site-packages']

$ python mymodule.pyz
['mymodule.pyz', '/Users/igork/.pyenv/versions/3.6.4/lib/python36.zip', '/Users/igork/.pyenv/versions/3.6.4/lib/python3.6', '/Users/igork/.pyenv/versions/3.6.4/lib/python3.6/lib-dynload', '/Users/igork/.local/lib/python3.6/site-packages', '/Users/igork/.pyenv/versions/3.6.4/lib/python3.6/site-packages']

【问题讨论】:

  • 我对 zipapp 不熟悉,但是您是否尝试过使用相对导入?即from .fun import Fun
  • @Jasmijn 可能有一些东西。这一切都归结为“你的sys.path 的价值是多少?”。我敢打赌,这两种环境的价值是不同的。我建议你在你的程序中添加一个print(sys.path)(如果你还没有添加import sys),看看我是否真的是对的。如果是这样,那么您可能想要做的只是在不工作的模式下附加到sys.path1 上,而在工作模式下sys.path1 中缺少任何内容。

标签: python python-import zipapp


【解决方案1】:

首先我使用错误的命令运行应用程序,正确的是:

$ python mymodule

要创建单个文件应用程序并运行它,我需要使用:

$ python -m zipapp -p "/usr/bin/evn python" mymodule
$ python mymodule.pyz

要运行单元测试,我需要使用:

$ python -m unittest

但单元测试因错误而失败:

======================================================================                                                          
ERROR: test_fun (unittest.loader._FailedTest)                                                                                   
----------------------------------------------------------------------                                                          
ImportError: Failed to import test module: test_fun                                                                             
Traceback (most recent call last):                                                                                              
  File "/Users/igork/.pyenv/versions/3.6.4/lib/python3.6/unittest/loader.py", line 153, in loadTestsFromName                    
    module = __import__(module_name)                                                                                            
  File "/Users/igork/developer/github/python/testzipapp/tests/test_fun.py", line 2, in <module>                                 
    from mymodule.fun import Fun                                                                                                
  File "/Users/igork/developer/github/python/testzipapp/mymodule/fun.py", line 8, in <module>                                   
    from bar import Bar                                                                                                         
ModuleNotFoundError: No module named 'bar'                                                                                      
                                                                                                                                
                                                                                                                                
----------------------------------------------------------------------                                                          
Ran 1 test in 0.000s                                                                                                            
                                                                                                                                
FAILED (errors=1)                                                                                                               

为了修复错误,我在tests/__init__.py 文件中添加了下一行:

import sys                    
sys.path.append('mymodule')   

总结: 我使用的项目结构是:

testzipapp $ tree -L 2             
.                                             
├── create-pyz.sh                              
├── mymodule                                  
│   ├── __main__.py                            
│   ├── bar.py                                
│   ├── fun.py                                
├── mymodule.pyz                              
└── tests                                     
    ├── __init__.py                           
    ├── test_fun.py                           
   

文件tests/test_fun.py 是:

import unittest                                                 
from mymodule.fun import Fun                                    
                                                                
                                                                
class TestFunImports(unittest.TestCase):                        
    def test_fun_run(self):                                     
        s = Fun()                                               
        s.run()                                                 
        self.assertEqual(2+2,4)                                 
                                                                

文件mymodule/__main__.py 是:

#!/usr/bin/env python                                                      
                                                                           
import sys                                                                                                                            
from fun import Fun                                                        
                                                                           
def main():                                                                
    sys.stdout.write('main is running ')                                   
    Fun().run()                                                            
                                                                           
if __name__ == '__main__':                                                 
    main()                                                                 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-17
    • 1970-01-01
    相关资源
    最近更新 更多