As stated in the documentation for __hash__() method in Python 3, if class overrides __eq__() but doesn't define __hash__(), this will implicitely be set to None. This is the case of HttpQueryError exception class. This causes issues for logging, particularly traceback module which raises TypeError: unhashable type: 'HttpQueryError'.
Consider this minimal example:
import logging
from graphql_server import HttpQueryError
logger = logging.getLogger(__name__)
try:
raise HttpQueryError(400, 'Error')
except HttpQueryError as e:
logger.exception(e)
This results in:
--- Logging error ---
Traceback (most recent call last):
File "/usr/lib/python3.5/logging/__init__.py", line 980, in emit
msg = self.format(record)
File "/usr/lib/python3.5/logging/__init__.py", line 830, in format
return fmt.format(record)
File "/usr/lib/python3.5/logging/__init__.py", line 575, in format
record.exc_text = self.formatException(record.exc_info)
File "/usr/lib/python3.5/logging/__init__.py", line 525, in formatException
traceback.print_exception(ei[0], ei[1], tb, None, sio)
File "/usr/lib/python3.5/traceback.py", line 100, in print_exception
type(value), value, tb, limit=limit).format(chain=chain):
File "/usr/lib/python3.5/traceback.py", line 439, in __init__
_seen.add(exc_value)
TypeError: unhashable type: 'HttpQueryError'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test_minimal.py", line 9, in <module>
logger.exception(e)
File "/usr/lib/python3.5/logging/__init__.py", line 1314, in exception
self.error(msg, *args, exc_info=exc_info, **kwargs)
File "/usr/lib/python3.5/logging/__init__.py", line 1308, in error
self._log(ERROR, msg, args, **kwargs)
File "/usr/lib/python3.5/logging/__init__.py", line 1415, in _log
self.handle(record)
File "/usr/lib/python3.5/logging/__init__.py", line 1425, in handle
self.callHandlers(record)
File "/usr/lib/python3.5/logging/__init__.py", line 1495, in callHandlers
lastResort.handle(record)
File "/usr/lib/python3.5/logging/__init__.py", line 855, in handle
self.emit(record)
File "/usr/lib/python3.5/logging/__init__.py", line 986, in emit
self.handleError(record)
File "/usr/lib/python3.5/logging/__init__.py", line 908, in handleError
traceback.print_exception(t, v, tb, None, sys.stderr)
This PR adds __hash__() method for HttpQueryError class implemented as a call to hash() built-in function supplying tuple of components used in __eq__() (as suggested in the documentation).
Note: This issue should be solved in Python 3.6 and Python 3.7 (see Issue 28603) which fixes formatting of tracebacks for unhashable exceptions.
As stated in the documentation for
__hash__()
method in Python 3, if class overrides__eq__()
but doesn't define__hash__()
, this will implicitely be set toNone
. This is the case ofHttpQueryError
exception class. This causes issues for logging, particularlytraceback
module which raisesTypeError: unhashable type: 'HttpQueryError'
.Consider this minimal example:
This results in:
This PR adds
__hash__()
method forHttpQueryError
class implemented as a call tohash()
built-in function supplying tuple of components used in__eq__()
(as suggested in the documentation).Note: This issue should be solved in Python 3.6 and Python 3.7 (see Issue 28603) which fixes formatting of tracebacks for unhashable exceptions.