JsonableError: Move into a normally-typed file.

The file `zerver/lib/request.py` doesn't have type annotations
of its own; if they did, they would duplicate the annotations that
exist in its stub file `zerver/lib/request.pyi`.  The latter exists
so that we can provide types for the highly dynamic `REQ` and
`has_request_variables`, which are beyond the type-checker's ken
to type-check, but we should minimize the scope of code that gets
that kind of treatment and `JsonableError` is not at all the sort of
code that needs it.

So move the definition of `JsonableError` into a file that does
get type-checked.

In doing so, the type-checker points out one issue already:
`__str__` should return a `str`, but we had it returning a `Text`,
which on Python 2 is not the same thing.  Indeed, because the
message we pass to the `JsonableError` constructor is generally
translated, it may well be a Unicode string stuffed full of
non-ASCII characters.  This is potentially a bit of a landmine.
But (a) it can only possibly matter in Python 2 which we intend to
be off before long, and (b) AFAIK it hasn't been biting us in
practice, so we've probably reasonably well worked around it where
it could matter.  Leave it as is.
This commit is contained in:
Greg Price 2017-07-19 15:51:54 -07:00 committed by Tim Abbott
parent a5597e91a1
commit 098b6fc53b
3 changed files with 21 additions and 16 deletions

View File

@ -1,7 +1,25 @@
from __future__ import absolute_import
from typing import Text
from django.core.exceptions import PermissionDenied
class JsonableError(Exception):
msg = None # type: Text
status_code = None # type: int
def __init__(self, msg, status_code=400):
# type: (Text) -> None
self.msg = msg
self.status_code = status_code
def __str__(self):
# type: () -> str
return self.to_json_error_msg() # type: ignore # remove once py3-only
def to_json_error_msg(self):
# type: () -> Text
return self.msg
class RateLimited(PermissionDenied):
def __init__(self, msg=""):
# type: (str) -> None

View File

@ -8,16 +8,7 @@ from six.moves import zip
from django.utils.translation import ugettext as _
class JsonableError(Exception):
def __init__(self, msg, status_code=400):
self.msg = msg
self.status_code = status_code
def __str__(self):
return self.to_json_error_msg()
def to_json_error_msg(self):
return self.msg
from zerver.lib.exceptions import JsonableError
class RequestVariableMissingError(JsonableError):
def __init__(self, var_name, status_code=400):

View File

@ -2,13 +2,9 @@
from typing import Any, Callable, Text, TypeVar
from django.http import HttpResponse
ViewFuncT = TypeVar('ViewFuncT', bound=Callable[..., HttpResponse])
from zerver.lib.exceptions import JsonableError as JsonableError
class JsonableError(Exception):
msg = ... # type: Text
status_code = ... # type: int
def __init__(self, msg: Text) -> None: ...
def to_json_error_msg(self) -> Text: ...
ViewFuncT = TypeVar('ViewFuncT', bound=Callable[..., HttpResponse])
class RequestVariableMissingError(JsonableError): ...
class RequestVariableConversionError(JsonableError): ...