graphql-python / graphql-server

This is the core package for using GraphQL in a custom server easily
MIT License
120 stars 72 forks source link

Make HttpQueryError hashable #8

Closed tlinhart closed 6 years ago

tlinhart commented 6 years ago

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.