[Risolto] [Python] TimeoutError vs socket.timeout

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2848
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

[Risolto] [Python] TimeoutError vs socket.timeout

Messaggio da rai »

Ho uno script che si connette a un server smtp. Ho cercato di coprire più eccezioni possibile ma non avevo previsto l'errore di timeout, anche perché non facilissimo da riprodurre (forse dipende dalla qualità della connessione...)

questo è un estratto dello script

Codice: Seleziona tutto

import smtplib
. . . 
smtpSERVER = "ilServerSMTP"

try:
    s = smtplib.SMTP_SSL(smtpSERVER)
except smtplib.SMTPConnectError as e:
    print("ERRORE durante la connessione: {}".format(e))
    . . .

questo l'errore che ho potuto riprodurre una sola volta, aspettando un'eternità

Codice: Seleziona tutto

Traceback (most recent call last):
  File "/dati/My_scripts/ProgettoCTU/INIZIO_operazioniCTU.py", line 373, in <module>
    s = smtplib.SMTP_SSL(smtpSERVER)
  File "/usr/lib/python3.5/smtplib.py", line 1021, in __init__
    source_address)
  File "/usr/lib/python3.5/smtplib.py", line 251, in __init__
    (code, msg) = self.connect(host, port)
  File "/usr/lib/python3.5/smtplib.py", line 335, in connect
    self.sock = self._get_socket(host, port, self.timeout)
  File "/usr/lib/python3.5/smtplib.py", line 1029, in _get_socket
    server_hostname=self._host)
  File "/usr/lib/python3.5/ssl.py", line 377, in wrap_socket
    _context=self)
  File "/usr/lib/python3.5/ssl.py", line 752, in __init__
    self.do_handshake()
  File "/usr/lib/python3.5/ssl.py", line 988, in do_handshake
    self._sslobj.do_handshake()
  File "/usr/lib/python3.5/ssl.py", line 633, in do_handshake
    self._sslobj.do_handshake()
TimeoutError[/url]: [Errno 110] Connection timed out
Nel debug ho provato a forzare l'errore aggiungendo il parametro timeout=1

Codice: Seleziona tutto

s = smtplib.SMTP_SSL(smtpSERVER, timeout=1)
purtroppo facendo così l'eccezione sollevata è sempre socket.timeout che in effetti è quella prevista dalla documentazione di smtplib

Due domande:
1) Se è previsto che l'errore sollevi l'eccezione socket.timeout da dove esce quel TimeoutError che ho postato?

2) Se come dice la documentazione di TimeoutError e di socket.timeout entrambi sono sottoclassi di OSError dovrei potere catturare entrambe le eccezioni con

Codice: Seleziona tutto

except OSError as e:
senza bisogno di importare socket. Corretto? e se sì, l'effetto negativo sarebbe una perdita di specificità nell'errore intercettato?

Scusate la verbosità e grazie
Ultima modifica di rai il giovedì 13 luglio 2017, 13:23, modificato 1 volta in totale.
Avatar utente
crap0101
Rampante Reduce
Rampante Reduce
Messaggi: 8242
Iscrizione: martedì 30 ottobre 2007, 6:33
Desktop: LXDE
Distribuzione: Ubuntu 18.04.1 LTS
Sesso: Maschile
Località: TO
Contatti:

Re: [Python] TimeoutError vs socket.timeout

Messaggio da crap0101 »

forse il TimeoutError è un refuso, che versione stai utilizzando?
per il resto direi di sì, però si può comunque vedere a posteriori l'errore specifico se interessa

Codice: Seleziona tutto

>>> def foo(error, args):
...   try: raise error(*args)
...   except OSError as e:
...     err_tp = "Tout" if e.__class__ == TimeoutError else ("socket" if e.__class__ == socket.timeout else "???")
...     print("ERR!", err_tp)
...   except Exception as e: print("ERR! (---)", e)
... 
>>> foo(TimeoutError, (10, 'foo'))
ERR! Tout
>>> foo(socket.timeout, (10, 'foo'))
ERR! socket
>>> foo(ConnectionError, (10, 'foo'))
ERR! ???
>>> foo(BufferError, (10, 'foo'))
ERR! (---) (10, 'foo')

altrimenti si except-ano entrambi da subito, che funziona comunque (fino alla 3.5 almeno)
http://www.gnu.org/ http://boinc.berkeley.edu/ http://www.python-it.org/
- Ricorda le ultime parole di suo padre: «Sta' alla larga dalle chiese, figlio. La sola cosa per cui hanno la chiave è il merdaio. E giurami che non porterai mai un distintivo della legge» - W.S. Burroughs
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2848
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: [Python] TimeoutError vs socket.timeout

Messaggio da rai »

Grazie dell'intervento. Non avevo pensato a usare raise per fare le verifiche

Si tratta di Python 3.5.2 (default, Nov 17 2016, 17:05:23)

In ogni caso, anche se l'errore che ho già postato è lievemente diverso dal socket.timeout sollevato da smtplib che aggiungo qui

Codice: Seleziona tutto

>>> s = smtplib.SMTP_SSL(smtpSERVER,timeout=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.5/smtplib.py", line 1021, in __init__
    source_address)
  File "/usr/lib/python3.5/smtplib.py", line 251, in __init__
    (code, msg) = self.connect(host, port)
  File "/usr/lib/python3.5/smtplib.py", line 335, in connect
    self.sock = self._get_socket(host, port, self.timeout)
  File "/usr/lib/python3.5/smtplib.py", line 1029, in _get_socket
    server_hostname=self._host)
  File "/usr/lib/python3.5/ssl.py", line 377, in wrap_socket
    _context=self)
  File "/usr/lib/python3.5/ssl.py", line 752, in __init__
    self.do_handshake()
  File "/usr/lib/python3.5/ssl.py", line 988, in do_handshake
    self._sslobj.do_handshake()
  File "/usr/lib/python3.5/ssl.py", line 633, in do_handshake
    self._sslobj.do_handshake()
socket.timeout: _ssl.c:629: The handshake operation timed out
>>>
ho scoperto che entrambi gli erori li catturo con except socket.error

Codice: Seleziona tutto

>>> import socket
>>> try:
...     s = smtplib.SMTP_SSL(smtpSERVER)
... except socket.error as e:
...     print(e.__class__)
...     print(e)
... 
<class 'TimeoutError'>
[Errno 110] Connection timed out
>>> 
>>> try:
...     s = smtplib.SMTP_SSL(smtpSERVER, timeout=1)
... except socket.error as e:
...     print(e.__class__)
...     print(e)
... 
<class 'socket.timeout'>
_ssl.c:629: The handshake operation timed out
>>> 
Quindi TimeoutError e socket.timeout sono entrambe sottoclassi di socket.error ?

Dunque io avrei praticamente risolto, salvo la curiosità teorica di capire:
The optional timeout parameter specifies a timeout in seconds for blocking operations like the connection attempt (if not specified, the global default timeout setting will be used). If the timeout expires, socket.timeout is raised.
cosa sia il global default timeout e eventualmente dove lo si modifica
Avatar utente
crap0101
Rampante Reduce
Rampante Reduce
Messaggi: 8242
Iscrizione: martedì 30 ottobre 2007, 6:33
Desktop: LXDE
Distribuzione: Ubuntu 18.04.1 LTS
Sesso: Maschile
Località: TO
Contatti:

Re: [Python] TimeoutError vs socket.timeout

Messaggio da crap0101 »

http://www.gnu.org/ http://boinc.berkeley.edu/ http://www.python-it.org/
- Ricorda le ultime parole di suo padre: «Sta' alla larga dalle chiese, figlio. La sola cosa per cui hanno la chiave è il merdaio. E giurami che non porterai mai un distintivo della legge» - W.S. Burroughs
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2848
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: [Python] TimeoutError vs socket.timeout

Messaggio da rai »

Grazie del link.
Tra l'altro leggendolo meglio c'è scritto espressamente che è consigliato passare un timeout quando si invoca socket.create_connection() che è appunto il metodo che viene invocato da smtplib.connect().
Ergo: da ora in poi quando uso smtplib.connect() imposto un timeout ragionevole (diciamo 30" ) e così tra l'altro so con certezza che tipo di eccezione devo aspettarmi a riguardo.
Alla prossima.
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 17 ospiti