icatproject/python-icat

Spurious AttributeError on cleanup after connecting to an invalid url

Closed this issue · 0 comments

RKrahl commented

Consider the following Python script:

#! /usr/bin/python3

import icat
import icat.config

config = icat.config.Config(ids=False, preset=dict(url='https://icat.invalid'))
client, conf = config.getconfig()

It tries to connect an ICAT service at an invalid URL. Not very surprisingly, it will throw an urllib.error.URLError (please ignore the first stack trace reporting a spurious socket.gaierror, that is Python's stupid Exception Chaining and Embedded Tracebacks):

$ ./invicat.py           
Traceback (most recent call last):
  File "/opt/python/lib/python3.12/urllib/request.py", line 1344, in do_open
    h.request(req.get_method(), req.selector, req.data, headers,
  File "/opt/python/lib/python3.12/http/client.py", line 1319, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/opt/python/lib/python3.12/http/client.py", line 1365, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/opt/python/lib/python3.12/http/client.py", line 1314, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/opt/python/lib/python3.12/http/client.py", line 1074, in _send_output
    self.send(msg)
  File "/opt/python/lib/python3.12/http/client.py", line 1018, in send
    self.connect()
  File "/opt/python/lib/python3.12/http/client.py", line 1453, in connect
    super().connect()
  File "/opt/python/lib/python3.12/http/client.py", line 984, in connect
    self.sock = self._create_connection(
                ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/python/lib/python3.12/socket.py", line 828, in create_connection
    for res in getaddrinfo(host, port, 0, SOCK_STREAM):
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/python/lib/python3.12/socket.py", line 963, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
socket.gaierror: [Errno -2] Name or service not known

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/abuild/./invicat.py", line 6, in <module>
    config = icat.config.Config(ids=False, preset=dict(url='https://icat.invalid'))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/abuild/test/python-icat-1.1.1.dev2+g054960b/build/lib/icat/config.py", line 702, in __init__
    self.client_kwargs, self.client = self._setup_client()
                                      ^^^^^^^^^^^^^^^^^^^^
  File "/home/abuild/test/python-icat-1.1.1.dev2+g054960b/build/lib/icat/config.py", line 863, in _setup_client
    return client_kwargs, Client(config.url, **client_kwargs)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/abuild/test/python-icat-1.1.1.dev2+g054960b/build/lib/icat/client.py", line 148, in __init__
    super().__init__(self.url, **kwargs)
  File "/opt/python/lib/python3.12/site-packages/suds/client.py", line 122, in __init__
    self.wsdl = reader.open(url)
                ^^^^^^^^^^^^^^^^
  File "/opt/python/lib/python3.12/site-packages/suds/reader.py", line 109, in open
    wsdl = self.fn(url, self.options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/python/lib/python3.12/site-packages/suds/wsdl.py", line 164, in __init__
    d = reader.open(url)
        ^^^^^^^^^^^^^^^^
  File "/opt/python/lib/python3.12/site-packages/suds/reader.py", line 153, in open
    xml = self.__fetch(url)
          ^^^^^^^^^^^^^^^^^
  File "/opt/python/lib/python3.12/site-packages/suds/reader.py", line 194, in __fetch
    fp = self.options.transport.open(request)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/python/lib/python3.12/site-packages/suds/transport/http.py", line 69, in open
    return self.u2open(u2request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/python/lib/python3.12/site-packages/suds/transport/http.py", line 140, in u2open
    return url.open(u2request, timeout=tm)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/python/lib/python3.12/urllib/request.py", line 515, in open
    response = self._open(req, data)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/python/lib/python3.12/urllib/request.py", line 532, in _open
    result = self._call_chain(self.handle_open, protocol, protocol +
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/python/lib/python3.12/urllib/request.py", line 492, in _call_chain
    result = func(*args)
             ^^^^^^^^^^^
  File "/opt/python/lib/python3.12/urllib/request.py", line 1392, in https_open
    return self.do_open(http.client.HTTPSConnection, req,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/python/lib/python3.12/urllib/request.py", line 1347, in do_open
    raise URLError(err)
urllib.error.URLError: <urlopen error [Errno -2] Name or service not known>
Exception ignored in: <function Client.__del__ at 0x7f7d369bca40>
Traceback (most recent call last):
  File "/home/abuild/test/python-icat-1.1.1.dev2+g054960b/build/lib/icat/client.py", line 167, in __del__
    self.cleanup()
  File "/home/abuild/test/python-icat-1.1.1.dev2+g054960b/build/lib/icat/client.py", line 176, in cleanup
    if self.autoLogout:
       ^^^^^^^^^^^^^^^
AttributeError: 'Client' object has no attribute 'autoLogout'

But note the last trace, reporting a weird AttributeError: 'Client' object has no attribute 'autoLogout'. That happens after the fact during program cleanup. It is due to the fact the Client() constructor has been interrupted, which leaves a half initialized object behind that can't even properly discarded. That should not happen.