PySFTP / Paramiko异常泄漏到stderr中

问题描述 投票:0回答:1

我正在尝试捕获paramiko异常,但它们仍被写入stderr。

有没有办法停止在那儿写作?

编辑:甚至在paramiko参与之前就发生了:

import pysftp

try:
    pysftp.Connection(host="localhost")
except Exception as e:
    print(e)

结果:

enter image description here

具有正确的SFTP参数的示例:

enter image description here

UPDATE:

$ pipenv graph
...
pysftp==0.2.9
  - paramiko [required: >=1.17, installed: 2.6.0]
...

$ pipenv run python
Python 3.7.3 (default, Jul 19 2019, 11:21:39)
[Clang 11.0.0 (clang-1100.0.28.3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pysftp
>>> try:
...     pysftp.Connection(host="localhost")
... except Exception as e:
...     print(e)
...
No hostkey for host localhost found.
Exception ignored in: <function Connection.__del__ at 0x10f7e8268>
Traceback (most recent call last):
  File "/Users/andrei/Work/try/.venv/lib/python3.7/site-packages/pysftp/__init__.py", line 1013, in __del__
    self.close()
  File "/Users/andrei/Work/try/.venv/lib/python3.7/site-packages/pysftp/__init__.py", line 784, in close
    if self._sftp_live:
AttributeError: 'Connection' object has no attribute '_sftp_live'
>>>
python exception paramiko stderr pysftp
1个回答
3
投票

我想指出PySFTP[PyPI]: PySFTP)已有[3 +年未维护(或已移至其他位置-到目前为止保密:))。

我转载了问题。下面是您的代码的更详细的版本。

code00.py

#!/usr/bin/env python3

import sys
import pysftp
import traceback


def main(argv):
    hostname = argv[0] if argv else "localhost"
    print("Attempting to connect to {0:s} ...".format(hostname))
    try:
        print("----------Before conn----------")
        conn = pysftp.Connection(host=hostname)
        print("----------After conn----------")
    except:
        print("----------Before exc print----------")
        traceback.print_exc()
        print("----------After exc print----------")
    finally:
        print("----------Finally----------")
    print("----------After try / except / finally----------")

if __name__ == "__main__":
    print("Python {0:s} {1:d}bit on {2:s}".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    print("pysftp version: {0:s}\n".format(pysftp.__version__))
    main(sys.argv[1:])
    print("\nDone.")

输出

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q058110732]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" code00.py
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32
pysftp version: 0.2.9

Attempting to connect to localhost ...
----------Before conn----------
e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\pysftp\__init__.py:61: UserWarning: Failed to load HostKeys from C:\Users\cfati\.ssh\known_hosts.  You will need to explicitly load HostKeys (cnopts.hostkeys.load(filename)) or disableHostKey checking (cnopts.hostkeys = None).
  warnings.warn(wmsg, UserWarning)
----------Before exc print----------
Traceback (most recent call last):
  File "code00.py", line 13, in main
    conn = pysftp.Connection(host=hostname)
  File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\pysftp\__init__.py", line 132, in __init__
    self._tconnect['hostkey'] = self._cnopts.get_hostkey(host)
  File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\pysftp\__init__.py", line 71, in get_hostkey
    raise SSHException("No hostkey for host %s found." % host)
paramiko.ssh_exception.SSHException: No hostkey for host localhost found.
----------After exc print----------
Exception ignored in: <function Connection.__del__ at 0x000001CC720C80D0>
Traceback (most recent call last):
  File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\pysftp\__init__.py", line 1013, in __del__
    self.close()
  File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\pysftp\__init__.py", line 784, in close
    if self._sftp_live:
AttributeError: 'Connection' object has no attribute '_sftp_live'
----------Finally----------
----------After try / except / finally----------

Done.

这是PySFTP错误:

  1. Connection对象被构造(__ new __
  2. 初始化器(__ init __)被称为
    1. 在初始化程序中的某个地方发生异常
    2. 不执行异常后的行
  3. 当对象(自动)被垃圾回收时(当对象超出范围时,在[[except块的末尾)),采用其close方法(由析构函数(__ del__]调用) >)),引用了某些属性
      但是由于这些属性初始化发生在
    1. #2.2。
    的行(引发异常)中,所以它们从未被初始化,因此它们的引用引发了[[AttributeError
解决方法很简单:在初始化程序的开头将属性初始化为一些默认值,因此,如果发生上述情况,则对它们的引用不会出现问题。我注意到您已经在BitBucket上提交了问题。

考虑:

我不是

BitBucket

专家

  • 我创建了自己的repo
  • (在上一个中),并将更改推送到:[[[BitBucket]: CristiFati0/pysftp - [Issue #144]: Exceptions leaking into stderr(到目前为止,一次提交)。
  • 输出

  • (在将修补程序手动应用于pip安装的文件之后):

    [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q058110732]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" code00.py Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32 pysftp version: 0.2.9 Attempting to connect to localhost ... ----------Before conn---------- e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\pysftp\__init__.py:61: UserWarning: Failed to load HostKeys from C:\Users\cfati\.ssh\known_hosts. You will need to explicitly load HostKeys (cnopts.hostkeys.load(filename)) or disableHostKey checking (cnopts.hostkeys = None). warnings.warn(wmsg, UserWarning) ----------Before exc print---------- Traceback (most recent call last): File "code00.py", line 13, in main conn = pysftp.Connection(host=hostname) File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\pysftp\__init__.py", line 135, in __init__ self._tconnect['hostkey'] = self._cnopts.get_hostkey(host) File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\pysftp\__init__.py", line 71, in get_hostkey raise SSHException("No hostkey for host %s found." % host) paramiko.ssh_exception.SSHException: No hostkey for host localhost found. ----------After exc print---------- ----------Finally---------- ----------After try / except / finally---------- Done.

    不用说,对于不同的情况,可能会引发其他未处理的异常。
    @ EDIT0

    显然,这不只是眼神。除了上述

    PySFTP

    错误外,还有2件事会污染stderr。1。警告

    就我而言(因为我在Win

    上并且没有安装任何本机SSH工具),它每次都会弹出(除非我在其中创建/复制了一些有效的

    known_hosts

    文件我的家

    dir),但在Nix系统上很可能不会。无论如何,此修复程序(如果需要)很容易,例如,通过设置%PYTHONWARNINGS%

    env

    var,只需抑制UserWarning

    ignore :: UserWarning2。 Paramiko例外我能够通过手动修改transport.py(并提高socket.timeout)来重现此内容。由paramiko.Transport初始化(由初始化程序调用)的

    pysftp.Connection._start_transport执行其工作[[在线程中。如果该线程中引发了某些异常,则无法被调用线程捕获。这是

    Python

    的限制,请选中[Python.Bugs]: threading.Thread should have way to catch an exception thrown within为此,有一个(lame)解决方法(

    gainarie

    ),并且正在重定向stderr。当然,还有其他解决方法,但是它们暗示着修改Paramiko,因此我建议您不要使用它们。下面是将

    stderr

    重定向到stdout的示例(但是您可以选择任何其他文件-包括/ dev / null(或Win上的

    nul

    ))。它是通过代码完成的(但也可以通过解释器命令行完成),因此它仅影响所需的(热)区域code01.py
    #!/usr/bin/env python3 import sys import pysftp import paramiko import traceback import threading _sys_stderr = sys.stderr # For restoring purposes def main(argv): hostname = argv[0] if argv else "localhost" print("Attempting to connect to {0:s} ...".format(hostname)) try: cnopts = pysftp.CnOpts() cnopts.hostkeys = None print("---------- STATS: {0:s} {1:d} ----------".format(__file__, threading.get_ident())) print("---------- Before conn ----------") sys.stderr.write("DUMMY TEXT before sent to stderr\n") sys.stderr = sys.stdout # @TODO - cfati: decomment so that everything from stderr is redirected to stdout conn = pysftp.Connection(host=hostname, port=22001, username="usr", password="pwd", cnopts=cnopts,) print("---------- After conn ----------") except: sys.stderr = _sys_stderr print("---------- Before exc tb ----------") traceback.print_exc(file=sys.stdout) print("---------- After exc tb ----------") finally: sys.stderr = _sys_stderr print("---------- Finally ----------") sys.stderr.write("DUMMY TEXT after sent to stderr\n") print("---------- After try / except / finally ----------") if __name__ == "__main__": print("Python {0:s} {1:d}bit on {2:s}".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform)) print("pysftp version: {0:s}\nparamiko version: {1:s}".format(pysftp.__version__, paramiko.__version__)) main(sys.argv[1:]) print("\nDone.") 输出:

    [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q058110732]> sopr.bat *** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages *** [prompt]> dir /b code00.py code01.py [prompt]> :: Suppress warning [prompt]> set PYTHONWARNINGS=ignore::UserWarning [prompt]> :: Redirect stdout and stderr to different files, so it is obvious which is which [prompt]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" code01.py 1>1.out 2>1.err [prompt]> type 1.err DUMMY TEXT before sent to stderr DUMMY TEXT after sent to stderr [prompt]> type 1.out Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32 pysftp version: 0.2.9 paramiko version: 2.6.0 Attempting to connect to localhost ... ---------- STATS: code01.py 23016 ---------- ---------- Before conn ---------- ---------- STATS: e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\paramiko\transport.py 45616 ---------- Exception: Error reading SSH protocol banner Traceback (most recent call last): File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\paramiko\transport.py", line 2212, in _check_banner raise socket.timeout() socket.timeout During handling of the above exception, another exception occurred: Traceback (most recent call last): File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\paramiko\transport.py", line 2039, in run self._check_banner() File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\paramiko\transport.py", line 2218, in _check_banner "Error reading SSH protocol banner" + str(e) paramiko.ssh_exception.SSHException: Error reading SSH protocol banner ---------- Before exc tb ---------- Traceback (most recent call last): File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\paramiko\transport.py", line 2212, in _check_banner raise socket.timeout() socket.timeout During handling of the above exception, another exception occurred: Traceback (most recent call last): File "code01.py", line 23, in main conn = pysftp.Connection(host=hostname, port=22001, username="usr", password="pwd", cnopts=cnopts,) File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\pysftp\__init__.py", line 144, in __init__ self._transport.connect(**self._tconnect) File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\paramiko\transport.py", line 1291, in connect self.start_client() File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\paramiko\transport.py", line 660, in start_client raise e File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\paramiko\transport.py", line 2039, in run self._check_banner() File "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\lib\site-packages\paramiko\transport.py", line 2218, in _check_banner "Error reading SSH protocol banner" + str(e) paramiko.ssh_exception.SSHException: Error reading SSH protocol banner ---------- After exc tb ---------- ---------- Finally ---------- ---------- After try / except / finally ---------- Done.

    以及它在

    PyCharm

    中的外观(必须将其拉伸到最大以适合整个东西):img0
    © www.soinside.com 2019 - 2024. All rights reserved.