首页 > 编程问答 >自定义异常 - 捕获不继承自 BaseException 的类

自定义异常 - 捕获不继承自 BaseException 的类

时间:2024-07-29 07:50:39浏览次数:10  
标签:python exception python-requests web3py

我正在尝试编写一些自定义异常处理,但不断遇到“TypeError:不允许捕获不从 BaseException 继承的类”错误的问题。 我有一个名为 NodeError 的异常基类,它继承自 Exception。 从那里,我有几个继承自 NodeError 的自定义异常。

web3 模块使用 requests 模块与节点进行通信。 我的测试不断尝试从节点获取 tx 计数,在执行此操作时,我尝试通过禁用 NIC 来模拟中断。 我尝试在 get_tx_count() 中捕获 requests.exceptions.ConnectionError 并引发我自己的异常。 它似乎根据堆栈跟踪正确地命中了 NodeConnectionError 自定义异常,但随后收到另一个异常,并抱怨捕获不从 BaseException 继承的类。

不知道为什么它认为我没有从 BaseException 继承,但我有感觉它与首先捕获请求异常有关。

堆栈跟踪:

Traceback (most recent call last):
  File "C:\Python39\lib\site-packages\urllib3\connection.py", line 169, in _new_conn
    conn = connection.create_connection(
  File "C:\Python39\lib\site-packages\urllib3\util\connection.py", line 73, in create_connection
    for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):
  File "C:\Python39\lib\socket.py", line 953, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno 11001] getaddrinfo failed

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Python39\lib\site-packages\urllib3\connectionpool.py", line 699, in urlopen
    httplib_response = self._make_request(
  File "C:\Python39\lib\site-packages\urllib3\connectionpool.py", line 382, in _make_request
    self._validate_conn(conn)
  File "C:\Python39\lib\site-packages\urllib3\connectionpool.py", line 1010, in _validate_conn
    conn.connect()
  File "C:\Python39\lib\site-packages\urllib3\connection.py", line 353, in connect
    conn = self._new_conn()
  File "C:\Python39\lib\site-packages\urllib3\connection.py", line 181, in _new_conn
    raise NewConnectionError(
urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPSConnection object at 0x000001413971AB50>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Python39\lib\site-packages\requests\adapters.py", line 439, in send
    resp = conn.urlopen(
  File "C:\Python39\lib\site-packages\urllib3\connectionpool.py", line 755, in urlopen
    retries = retries.increment(
  File "C:\Python39\lib\site-packages\urllib3\util\retry.py", line 574, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='matic-mainnet-full-rpc.bwarelabs.com', port=443): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x000001413971AB50>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed'))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\t\extest.py", line 87, in get_tx_count
    nonce = w3.eth.get_transaction_count(address)
  File "C:\Python39\lib\site-packages\web3\module.py", line 57, in caller
    result = w3.manager.request_blocking(method_str,
  File "C:\Python39\lib\site-packages\web3\manager.py", line 186, in request_blocking
    response = self._make_request(method, params)
  File "C:\Python39\lib\site-packages\web3\manager.py", line 147, in _make_request
    return request_func(method, params)
  File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
    return self.func(*args, **kwargs)
  File "C:\Python39\lib\site-packages\web3\middleware\formatting.py", line 76, in apply_formatters
    response = make_request(method, params)
  File "C:\Python39\lib\site-packages\web3\middleware\gas_price_strategy.py", line 84, in middleware
    return make_request(method, params)
  File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
    return self.func(*args, **kwargs)
  File "C:\Python39\lib\site-packages\web3\middleware\formatting.py", line 74, in apply_formatters
    response = make_request(method, formatted_params)
  File "C:\Python39\lib\site-packages\web3\middleware\attrdict.py", line 33, in middleware
    response = make_request(method, params)
  File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
    return self.func(*args, **kwargs)
  File "C:\Python39\lib\site-packages\web3\middleware\formatting.py", line 74, in apply_formatters
    response = make_request(method, formatted_params)
  File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
    return self.func(*args, **kwargs)
  File "C:\Python39\lib\site-packages\web3\middleware\formatting.py", line 76, in apply_formatters
    response = make_request(method, params)
  File "cytoolz/functoolz.pyx", line 250, in cytoolz.functoolz.curry.__call__
    return self.func(*args, **kwargs)
  File "C:\Python39\lib\site-packages\web3\middleware\formatting.py", line 74, in apply_formatters
    response = make_request(method, formatted_params)
  File "C:\Python39\lib\site-packages\web3\middleware\buffered_gas_estimate.py", line 40, in middleware
    return make_request(method, params)
  File "C:\Python39\lib\site-packages\web3\middleware\exception_retry_request.py", line 105, in middleware
    return make_request(method, params)
  File "C:\Python39\lib\site-packages\web3\providers\rpc.py", line 88, in make_request
    raw_response = make_post_request(
  File "C:\Python39\lib\site-packages\web3\_utils\request.py", line 48, in make_post_request
    response = session.post(endpoint_uri, data=data, *args, **kwargs)  # type: ignore
  File "C:\Python39\lib\site-packages\requests\sessions.py", line 590, in post
    return self.request('POST', url, data=data, json=json, **kwargs)
  File "C:\Python39\lib\site-packages\requests\sessions.py", line 542, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Python39\lib\site-packages\requests\sessions.py", line 655, in send
    r = adapter.send(request, **kwargs)
  File "C:\Python39\lib\site-packages\requests\adapters.py", line 516, in send
    raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='matic-mainnet-full-rpc.bwarelabs.com', port=443): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x000001413971AB50>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed'))

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\t\extest.py", line 114, in main
    print(get_tx_count(w3, address))
  File "C:\t\extest.py", line 90, in get_tx_count
    raise NodeConnectionError(w3) from e
__main__.NodeConnectionError: An error occurred with the node at A web3 connection error occurred talking to https://matic-mainnet-full-rpc.bwarelabs.com:443..

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\t\extest.py", line 140, in <module>
    main()
  File "C:\t\extest.py", line 116, in main
    except NodeNotConnected(w3.provider.endpoint_uri, w3):
TypeError: catching classes that do not inherit from BaseException is not allowed

测试代码:

from web3 import Web3
from time import sleep
from requests.exceptions import ConnectionError, ConnectTimeout, HTTPError
import sys

class NodeError(Exception):
    """Base exception for node errors"""
    def __init__(self, url, msg=None):
        if msg is None:
            msg = f"An error occurred with the node at {url}."
        super().__init__(msg)
        self.url = url

class NodeNotConnected(NodeError):
    """web3 could not connect to a node"""
    def __init__(self, url, w3=None):
        msg = f"A web3 connection could not be made to URL {url}."
        super().__init__(url, msg=msg)
        self.w3 = w3

class NodeConnectionError(NodeError):
    """A web3 error occurred communicating with a node"""
    def __init__(self, w3):
        msg = (
            f"A web3 connection error occurred talking to "
            f"{w3.provider.endpoint_uri}."
        )
        super().__init__(msg)
        self.w3 = w3

class NodeTooManyRequests(NodeError):
    def __init__(self, w3):
        msg = (
            f"Too many requests made to {w3.provider.endpoint_uri}.  Try a "
            f"different node."
        )
        super().__init__(msg)
        self.w3 = w3

class NodeNoAvailableNodes(NodeError):
    def __init__(self):
        msg = f"Unable to connect to any nodes."
        super().__init__(msg)

class NodeInternalError(NodeError):
    def __init__(self):
        msg = "The node had an internal error."
        super().__init__(msg)

def lib_connect_to_node(url):
    """Emulates library connect to node function"""
    try:
        w3 = Web3(
            Web3.HTTPProvider(
                url,
                request_kwargs={"timeout": 5}
            )
        )
        if not w3.isConnected():
            raise NodeNotConnected(url, w3)
    except Exception as e:
        raise NodeNotConnected(url) from e
    else:
        return w3

def connect_to_node(urls, node_retries):
    while node_retries >= 0:
        try:
            w3 = lib_connect_to_node(urls[0])
        except NodeNotConnected(urls[0]) as e:
            if node_retries == 0:
                raise NodeNoAvailableNodes from e
            node_retries -= 1
            urls = get_next_node(urls)
            print('Trying another node')
            sleep(1)
            continue
        else:
            return w3

def get_next_node(urls):
    urls.append(urls.pop(urls.index(urls[0])))
    return urls

def get_tx_count(w3, address):
    try:
        nonce = w3.eth.get_transaction_count(address)
    except (ConnectionError, ConnectTimeout) as e:
        print("A requests.exceptions.ConnectionError occurred.")
        raise NodeConnectionError(w3) from e
    except HTTPError as e:
        if e.code == 429:
            raise NodeTooManyRequests from e
    else:
        return nonce

def main():
    urls = [
        'https://matic-mainnet-full-rpc.bwarelabs.com:443',
        'https://matic-mainnet.chainstacklabs.com:443',
        'https://rpc-mainnet.maticvigil.com:443',
        'https://rpc-mainnet.matic.network:443'
    ]
    node_retries = 3
    address = '0xe18A0D121057B002BaFb90aD5F1AB951594A61E8'
    try:
        w3 = connect_to_node(urls, node_retries)
    except NodeNoAvailableNodes as e:
        print(e)
        sys.exit()

    while True:
        try:
            print(get_tx_count(w3, address))
            sleep(0.05)
        except NodeNotConnected(w3.provider.endpoint_uri, w3):
            urls = get_next_node(urls)
            try:
                w3 = connect_to_node(urls, node_retries)
            except NodeNoAvailableNodes as e:
                print(e)
                sys.exit()
        except NodeConnectionError(w3) as e:
            urls = get_next_node(urls)
            try:
                w3 = connect_to_node(urls, node_retries)
            except NodeNoAvailableNodes as e:
                print(e)
                sys.exit() 
        except NodeTooManyRequests(w3) as e:
            print('Too many requests')
            urls = get_next_node(urls)
            try:
                w3 = connect_to_node(urls, node_retries)
            except NodeNoAvailableNodes as e:
                print(e)
                sys.exit()

if __name__ == '__main__':
    main()

该错误信息告诉你,你试图使用 except NodeNotConnected(w3.provider.endpoint_uri, w3): 语句来捕获一个本身并不是异常的 实例 。在 Python 中,你应该捕获异常的 类型 ,而不是一个用值初始化后的特定实例。

将你的 except 语句从:

except NodeNotConnected(w3.provider.endpoint_uri, w3):

改为:

except NodeNotConnected:

并在 except 块中访问该异常对象及其属性:

except NodeNotConnected as e:
    print(f"NodeNotConnected: {e.url}")  # 打印异常的 url 属性
    urls = get_next_node(urls)
    # ... 其余的错误处理逻辑

NodeConnectionError NodeTooManyRequests 也进行同样的修改。

这些修改后,你的代码应该能正确地捕获和处理异常,而不会出现 TypeError

标签:python,exception,python-requests,web3py
From: 69257825

相关文章

  • 如何用Python制作Android服务?
    我想构建一个简单的Android应用程序,例如PushOver应用程序,它具有TCP服务器并接收其记录的文本消息,然后将其作为推送通知发送。这部分已经完成并且工作正常。但即使GUI应用程序关闭,我也想接收消息。我知道这是可能的,因为PushOver应用程序做到了!我想,我可能需要一......
  • Python Discord Bot 的应用程序命令的区域设置名称(多语言别名)
    如何根据用户的语言设置,使应用程序命令的名称具有不同的名称例如,如果一个用户将其discord的语言设置为英语,则用户可以看到英语的应用程序命令名称。另一方面,如果另一个用户将其不和谐语言设置为法语,则用户可以看到法语中的相同应用程序命令的名称。为此,我尝试使用ap......
  • 如何在Python中添加热键?
    我正在为游戏制作一个机器人,我想在按下热键时调用该函数。我已经尝试了一些解决方案,但效果不佳。这是我的代码:defstart():whileTrue:ifkeyboard.is_pressed('alt+s'):break...defmain():whileTrue:ifkeyboard.is_pr......
  • 在Python中解压文件
    我通读了zipfile文档,但不明白如何解压缩文件,只了解如何压缩文件。如何将zip文件的所有内容解压缩到同一目录中?importzipfilewithzipfile.ZipFile('your_zip_file.zip','r')aszip_ref:zip_ref.extractall('target_directory')将......
  • 如何在Python中从RSA公钥中提取N和E?
    我有一个RSA公钥,看起来像-----BEGINPUBLICKEY-----MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAvm0WYXg6mJc5GOWJ+5jkhtbBOe0gyTlujRER++cvKOxbIdg8So3mV1eASEHxqSnp5lGa8R9Pyxz3iaZpBCBBvDB7Fbbe5koVTmt+K06o96ki1/4NbHGyRVL/x5fFiVuTVfmk+GZNakH5dXDq0fwvJyVmUtGYA......
  • Swagger、Docker、Python-Flask: : https://editor.swagger.io/ 生成服务器 python-fl
    在https://editor.swagger.io/上您可以粘贴一些json/yaml。我正在将此作为JSON进行测试(不要转换为YAML):{"swagger":"2.0","info":{"version":"1.0","title":"OurfirstgeneratedRES......
  • 使用 Matplotlib 的 Python 代码中出现意外的控制流
    Ubuntu22.04上的此Python3.12代码的行为符合预期,除非我按q或ESC键退出。代码如下:importnumpyasnp,matplotlib.pyplotaspltfrompathlibimportPathfromcollectionsimportnamedtuplefromskimage.ioimportimreadfrommatplotlib.widgets......
  • 参考 - Python 类型提示
    这是什么?这是与在Python中使用类型提示主题相关的问题和答案的集合。这个问题本身就是一个社区维基;欢迎大家参与维护。这是为什么?Python类型提示是一个不断增长的话题,因此许多(可能的)新问题已经被提出,其中许多甚至已经有了答案。该集合有助于查找现有内容。范......
  • 我的 Python 程序中解决 UVa 860 的运行时错误 - 熵文本分析器
    我正在尝试为UVa860编写一个解决方案,但是当我通过vJudge发送它时,它一直显示“运行时错误”。fromsysimportstdinimportmathdefmain():end_of_input=Falselambda_words=0dictionary={}text_entropy=0relative_entropy=0whilenotend_of_in......
  • Python进度条
    当我的脚本正在执行某些可能需要时间的任务时,如何使用进度条?例如,一个需要一些时间才能完成并在完成后返回True的函数。如何在函数执行期间显示进度条?请注意,我需要实时显示进度条,所以我不知道该怎么办。我需要thread为此吗?我不知道。现在在执行函数......