解决:pipenv shell报错:AttributeError: 'module' object has no attribute 'run'

利用pipenv shell切换到虚拟环境时,显示报错:AttributeError: 'module' object has no attribute 'run'

可以看到是d:\program\python34\lib\site-packages\pipenv\shells.py文件的第62行报错了,提示模块没有run的属性,于是就跑到该文件的第62行去看

选中run,CTRL+B发现能看到源码,源码如下:

if sys.version_info >= (3, 6):
        # Nearly same args as Popen.__init__ except for timeout, input, and check
        def run(args: _CMD,
                timeout: Optional[float] = ...,
                input: Optional[_TXT] = ...,
                check: bool = ...,
                bufsize: int = ...,
                executable: _PATH = ...,
                stdin: _FILE = ...,
                stdout: _FILE = ...,
                stderr: _FILE = ...,
                preexec_fn: Callable[[], Any] = ...,
                close_fds: bool = ...,
                shell: bool = ...,
                cwd: Optional[_PATH] = ...,
                env: Optional[_ENV] = ...,
                universal_newlines: bool = ...,
                startupinfo: Any = ...,
                creationflags: int = ...,
                restore_signals: bool = ...,
                start_new_session: bool = ...,
                pass_fds: Any = ...,
                *,
                encoding: Optional[str] = ...,
                errors: Optional[str] = ...) -> CompletedProcess: ...
    else:
        # Nearly same args as Popen.__init__ except for timeout, input, and check
        def run(args: _CMD,
                timeout: Optional[float] = ...,
                input: Optional[_TXT] = ...,
                check: bool = ...,
                bufsize: int = ...,
                executable: _PATH = ...,
                stdin: _FILE = ...,
                stdout: _FILE = ...,
                stderr: _FILE = ...,
                preexec_fn: Callable[[], Any] = ...,
                close_fds: bool = ...,
                shell: bool = ...,
                cwd: Optional[_PATH] = ...,
                env: Optional[_ENV] = ...,
                universal_newlines: bool = ...,
                startupinfo: Any = ...,
                creationflags: int = ...,
                restore_signals: bool = ...,
                start_new_session: bool = ...,
                pass_fds: Any = ...) -> CompletedProcess: ...

但是请看第一行 if sys.version_info >= (3, 6):  ,我们姑且猜测一下,这个3.6就是python的版本号,如果版本大于3.6,就用第一个run函数,否则就用第二个run函数,这两个函数有什么不同——第一个run函数多了下面两行

         encoding: Optional[str] = ...,
               errors: Optional[str] = ...)

可是,既然版本大于3.6和小于3.6都会调用已存在的run函数,那为什么会报错?我们来看一下比较完整的代码

不知道有没有留意到当版本大于3.5时,才会去第二个if里判断是否大于3.6,而我当前的版本是3.4.4,因此不满足大于3.5的if判断,而满足大于3.3的if判断,此时下面的方法都是call了(事实上,只要满足版本<3.5,都应该调用的是call方法)

if sys.version_info >= (3, 5):
    class CompletedProcess:
        # morally: _CMD
        args = ...  # type: Any
        returncode = ...  # type: int
        # morally: Optional[_TXT]
        stdout = ...  # type: Any
        stderr = ...  # type: Any
        def __init__(self, args: _CMD,
                     returncode: int,
                     stdout: Optional[_TXT] = ...,
                     stderr: Optional[_TXT] = ...) -> None: ...
        def check_returncode(self) -> None: ...

    if sys.version_info >= (3, 6):
        # Nearly same args as Popen.__init__ except for timeout, input, and check
        def run(args: _CMD,
                timeout: Optional[float] = ...,
                input: Optional[_TXT] = ...,
                check: bool = ...,
                bufsize: int = ...,
                executable: _PATH = ...,
                stdin: _FILE = ...,
                stdout: _FILE = ...,
                stderr: _FILE = ...,
                preexec_fn: Callable[[], Any] = ...,
                close_fds: bool = ...,
                shell: bool = ...,
                cwd: Optional[_PATH] = ...,
                env: Optional[_ENV] = ...,
                universal_newlines: bool = ...,
                startupinfo: Any = ...,
                creationflags: int = ...,
                restore_signals: bool = ...,
                start_new_session: bool = ...,
                pass_fds: Any = ...,
                *,
                encoding: Optional[str] = ...,
                errors: Optional[str] = ...) -> CompletedProcess: ...
    else:
        # Nearly same args as Popen.__init__ except for timeout, input, and check
        def run(args: _CMD,
                timeout: Optional[float] = ...,
                input: Optional[_TXT] = ...,
                check: bool = ...,
                bufsize: int = ...,
                executable: _PATH = ...,
                stdin: _FILE = ...,
                stdout: _FILE = ...,
                stderr: _FILE = ...,
                preexec_fn: Callable[[], Any] = ...,
                close_fds: bool = ...,
                shell: bool = ...,
                cwd: Optional[_PATH] = ...,
                env: Optional[_ENV] = ...,
                universal_newlines: bool = ...,
                startupinfo: Any = ...,
                creationflags: int = ...,
                restore_signals: bool = ...,
                start_new_session: bool = ...,
                pass_fds: Any = ...) -> CompletedProcess: ...

# Same args as Popen.__init__
if sys.version_info >= (3, 3):
    # 3.3 added timeout
    def call(args: _CMD,
             bufsize: int = ...,
             executable: _PATH = ...,
             stdin: _FILE = ...,
             stdout: _FILE = ...,
             stderr: _FILE = ...,
             preexec_fn: Callable[[], Any] = ...,
             close_fds: bool = ...,
             shell: bool = ...,
             cwd: Optional[_PATH] = ...,
             env: Optional[_ENV] = ...,
             universal_newlines: bool = ...,
             startupinfo: Any = ...,
             creationflags: int = ...,
             restore_signals: bool = ...,
             start_new_session: bool = ...,
             pass_fds: Any = ...,
             timeout: float = ...) -> int: ...
else:
    def call(args: _CMD,
             bufsize: int = ...,
             executable: _PATH = ...,
             stdin: _FILE = ...,
             stdout: _FILE = ...,
             stderr: _FILE = ...,
             preexec_fn: Callable[[], Any] = ...,
             close_fds: bool = ...,
             shell: bool = ...,
             cwd: Optional[_PATH] = ...,
             env: Optional[_ENV] = ...,
             universal_newlines: bool = ...,
             startupinfo: Any = ...,
             creationflags: int = ...,
             restore_signals: bool = ...,
             start_new_session: bool = ...,
             pass_fds: Any = ...) -> int: ...

了解这个,就知道如何解决了,只要修改源码把run换成call即可(如果要使用3.5及以上的版本,建议把call再换回run)

再次使用pipenv shell,发现可以切换到虚拟环境了

扫描二维码关注公众号,回复: 3057430 查看本文章

参考文章

https://cuiqingcai.com/5846.html

猜你喜欢

转载自www.cnblogs.com/cnhkzyy/p/9589200.html