validator: Remove unused type_structure system.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2020-06-22 13:59:45 -07:00 committed by Tim Abbott
parent 07fa63e0c8
commit d6655689f5
2 changed files with 1 additions and 85 deletions

View File

@ -17,9 +17,6 @@ exclude_lines =
if TYPE_CHECKING: if TYPE_CHECKING:
# Don't require coverage for abstract methods; they're never called. # Don't require coverage for abstract methods; they're never called.
@abstractmethod @abstractmethod
# Don't require coverage for the USING_TYPE_STRUCTURE code paths
# These are only run in a special testing mode, so will fail normal coverage.
if USING_TYPE_STRUCTURE
# PEP 484 overloading syntax # PEP 484 overloading syntax
^\s*\.\.\. ^\s*\.\.\.

View File

@ -29,23 +29,9 @@ for any particular type of object.
''' '''
import re import re
from datetime import datetime from datetime import datetime
from typing import ( from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Tuple, Union, cast, overload
Any,
Callable,
Dict,
Iterable,
List,
Optional,
Set,
Tuple,
TypeVar,
Union,
cast,
overload,
)
import ujson import ujson
from django.conf import settings
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.validators import URLValidator, validate_email from django.core.validators import URLValidator, validate_email
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
@ -53,30 +39,12 @@ from django.utils.translation import ugettext as _
from zerver.lib.request import JsonableError, ResultT from zerver.lib.request import JsonableError, ResultT
from zerver.lib.types import ProfileFieldData, Validator from zerver.lib.types import ProfileFieldData, Validator
FuncT = TypeVar("FuncT", bound=Callable[..., object])
TypeStructure = TypeVar("TypeStructure")
USING_TYPE_STRUCTURE = settings.LOG_API_EVENT_TYPES
# The type_structure system is designed to support using the validators in
# test_events.py to create documentation for our event formats.
#
# Ultimately, it should be possible to do this with mypy rather than a
# parallel system.
def set_type_structure(type_structure: TypeStructure) -> Callable[[FuncT], FuncT]:
def _set_type_structure(func: FuncT) -> FuncT:
if USING_TYPE_STRUCTURE:
func.type_structure = type_structure # type: ignore[attr-defined] # monkey-patching
return func
return _set_type_structure
@set_type_structure("str")
def check_string(var_name: str, val: object) -> str: def check_string(var_name: str, val: object) -> str:
if not isinstance(val, str): if not isinstance(val, str):
raise ValidationError(_('{var_name} is not a string').format(var_name=var_name)) raise ValidationError(_('{var_name} is not a string').format(var_name=var_name))
return val return val
@set_type_structure("str")
def check_required_string(var_name: str, val: object) -> str: def check_required_string(var_name: str, val: object) -> str:
s = check_string(var_name, val) s = check_string(var_name, val)
if not s.strip(): if not s.strip():
@ -84,7 +52,6 @@ def check_required_string(var_name: str, val: object) -> str:
return s return s
def check_string_in(possible_values: Union[Set[str], List[str]]) -> Validator[str]: def check_string_in(possible_values: Union[Set[str], List[str]]) -> Validator[str]:
@set_type_structure("str")
def validator(var_name: str, val: object) -> str: def validator(var_name: str, val: object) -> str:
s = check_string(var_name, val) s = check_string(var_name, val)
if s not in possible_values: if s not in possible_values:
@ -93,12 +60,10 @@ def check_string_in(possible_values: Union[Set[str], List[str]]) -> Validator[st
return validator return validator
@set_type_structure("str")
def check_short_string(var_name: str, val: object) -> str: def check_short_string(var_name: str, val: object) -> str:
return check_capped_string(50)(var_name, val) return check_capped_string(50)(var_name, val)
def check_capped_string(max_length: int) -> Validator[str]: def check_capped_string(max_length: int) -> Validator[str]:
@set_type_structure("str")
def validator(var_name: str, val: object) -> str: def validator(var_name: str, val: object) -> str:
s = check_string(var_name, val) s = check_string(var_name, val)
if len(s) > max_length: if len(s) > max_length:
@ -110,7 +75,6 @@ def check_capped_string(max_length: int) -> Validator[str]:
return validator return validator
def check_string_fixed_length(length: int) -> Validator[str]: def check_string_fixed_length(length: int) -> Validator[str]:
@set_type_structure("str")
def validator(var_name: str, val: object) -> str: def validator(var_name: str, val: object) -> str:
s = check_string(var_name, val) s = check_string(var_name, val)
if len(s) != length: if len(s) != length:
@ -121,11 +85,9 @@ def check_string_fixed_length(length: int) -> Validator[str]:
return validator return validator
@set_type_structure("str")
def check_long_string(var_name: str, val: object) -> str: def check_long_string(var_name: str, val: object) -> str:
return check_capped_string(500)(var_name, val) return check_capped_string(500)(var_name, val)
@set_type_structure("date")
def check_date(var_name: str, val: object) -> str: def check_date(var_name: str, val: object) -> str:
if not isinstance(val, str): if not isinstance(val, str):
raise ValidationError(_('{var_name} is not a string').format(var_name=var_name)) raise ValidationError(_('{var_name} is not a string').format(var_name=var_name))
@ -135,14 +97,12 @@ def check_date(var_name: str, val: object) -> str:
raise ValidationError(_('{var_name} is not a date').format(var_name=var_name)) raise ValidationError(_('{var_name} is not a date').format(var_name=var_name))
return val return val
@set_type_structure("int")
def check_int(var_name: str, val: object) -> int: def check_int(var_name: str, val: object) -> int:
if not isinstance(val, int): if not isinstance(val, int):
raise ValidationError(_('{var_name} is not an integer').format(var_name=var_name)) raise ValidationError(_('{var_name} is not an integer').format(var_name=var_name))
return val return val
def check_int_in(possible_values: List[int]) -> Validator[int]: def check_int_in(possible_values: List[int]) -> Validator[int]:
@set_type_structure("int")
def validator(var_name: str, val: object) -> int: def validator(var_name: str, val: object) -> int:
n = check_int(var_name, val) n = check_int(var_name, val)
if n not in possible_values: if n not in possible_values:
@ -151,19 +111,16 @@ def check_int_in(possible_values: List[int]) -> Validator[int]:
return validator return validator
@set_type_structure("float")
def check_float(var_name: str, val: object) -> float: def check_float(var_name: str, val: object) -> float:
if not isinstance(val, float): if not isinstance(val, float):
raise ValidationError(_('{var_name} is not a float').format(var_name=var_name)) raise ValidationError(_('{var_name} is not a float').format(var_name=var_name))
return val return val
@set_type_structure("bool")
def check_bool(var_name: str, val: object) -> bool: def check_bool(var_name: str, val: object) -> bool:
if not isinstance(val, bool): if not isinstance(val, bool):
raise ValidationError(_('{var_name} is not a boolean').format(var_name=var_name)) raise ValidationError(_('{var_name} is not a boolean').format(var_name=var_name))
return val return val
@set_type_structure("str")
def check_color(var_name: str, val: object) -> str: def check_color(var_name: str, val: object) -> str:
s = check_string(var_name, val) s = check_string(var_name, val)
valid_color_pattern = re.compile(r'^#([a-fA-F0-9]{3,6})$') valid_color_pattern = re.compile(r'^#([a-fA-F0-9]{3,6})$')
@ -173,12 +130,6 @@ def check_color(var_name: str, val: object) -> str:
return s return s
def check_none_or(sub_validator: Validator[ResultT]) -> Validator[Optional[ResultT]]: def check_none_or(sub_validator: Validator[ResultT]) -> Validator[Optional[ResultT]]:
if USING_TYPE_STRUCTURE:
type_structure = 'none_or_' + sub_validator.type_structure # type: ignore[attr-defined] # monkey-patching
else:
type_structure = None
@set_type_structure(type_structure)
def f(var_name: str, val: object) -> Optional[ResultT]: def f(var_name: str, val: object) -> Optional[ResultT]:
if val is None: if val is None:
return val return val
@ -194,15 +145,6 @@ def check_list(sub_validator: None, length: Optional[int]=None) -> Validator[Lis
def check_list(sub_validator: Validator[ResultT], length: Optional[int]=None) -> Validator[List[ResultT]]: def check_list(sub_validator: Validator[ResultT], length: Optional[int]=None) -> Validator[List[ResultT]]:
... ...
def check_list(sub_validator: Optional[Validator[ResultT]]=None, length: Optional[int]=None) -> Validator[List[ResultT]]: def check_list(sub_validator: Optional[Validator[ResultT]]=None, length: Optional[int]=None) -> Validator[List[ResultT]]:
if USING_TYPE_STRUCTURE:
if sub_validator:
type_structure = [sub_validator.type_structure] # type: ignore[attr-defined] # monkey-patching
else:
type_structure = 'list' # type: ignore[assignment] # monkey-patching
else:
type_structure = None # type: ignore[assignment] # monkey-patching
@set_type_structure(type_structure)
def f(var_name: str, val: object) -> List[ResultT]: def f(var_name: str, val: object) -> List[ResultT]:
if not isinstance(val, list): if not isinstance(val, list):
raise ValidationError(_('{var_name} is not a list').format(var_name=var_name)) raise ValidationError(_('{var_name} is not a list').format(var_name=var_name))
@ -240,9 +182,6 @@ def check_dict(required_keys: Iterable[Tuple[str, Validator[ResultT]]]=[],
*, *,
value_validator: Optional[Validator[ResultT]]=None, value_validator: Optional[Validator[ResultT]]=None,
_allow_only_listed_keys: bool=False) -> Validator[Dict[str, ResultT]]: _allow_only_listed_keys: bool=False) -> Validator[Dict[str, ResultT]]:
type_structure: Dict[str, Any] = {}
@set_type_structure(type_structure)
def f(var_name: str, val: object) -> Dict[str, ResultT]: def f(var_name: str, val: object) -> Dict[str, ResultT]:
if not isinstance(val, dict): if not isinstance(val, dict):
raise ValidationError(_('{var_name} is not a dict').format(var_name=var_name)) raise ValidationError(_('{var_name} is not a dict').format(var_name=var_name))
@ -257,23 +196,17 @@ def check_dict(required_keys: Iterable[Tuple[str, Validator[ResultT]]]=[],
)) ))
vname = f'{var_name}["{k}"]' vname = f'{var_name}["{k}"]'
sub_validator(vname, val[k]) sub_validator(vname, val[k])
if USING_TYPE_STRUCTURE:
type_structure[k] = sub_validator.type_structure # type: ignore[attr-defined] # monkey-patching
for k, sub_validator in optional_keys: for k, sub_validator in optional_keys:
if k in val: if k in val:
vname = f'{var_name}["{k}"]' vname = f'{var_name}["{k}"]'
sub_validator(vname, val[k]) sub_validator(vname, val[k])
if USING_TYPE_STRUCTURE:
type_structure[k] = sub_validator.type_structure # type: ignore[attr-defined] # monkey-patching
if value_validator: if value_validator:
for key in val: for key in val:
vname = f'{var_name} contains a value that' vname = f'{var_name} contains a value that'
valid_value = value_validator(vname, val[key]) valid_value = value_validator(vname, val[key])
assert val[key] is valid_value # To justify the unchecked cast below assert val[key] is valid_value # To justify the unchecked cast below
if USING_TYPE_STRUCTURE:
type_structure['any'] = value_validator.type_structure # type: ignore[attr-defined] # monkey-patching
if _allow_only_listed_keys: if _allow_only_listed_keys:
required_keys_set = {x[0] for x in required_keys} required_keys_set = {x[0] for x in required_keys}
@ -302,12 +235,6 @@ def check_union(allowed_type_funcs: Iterable[Validator[ResultT]]) -> Validator[R
types for this variable. types for this variable.
""" """
if USING_TYPE_STRUCTURE:
type_structure = f'any("{[x.type_structure for x in allowed_type_funcs]}")' # type: ignore[attr-defined] # monkey-patching
else:
type_structure = None # type: ignore[assignment] # monkey-patching
@set_type_structure(type_structure)
def enumerated_type_check(var_name: str, val: object) -> ResultT: def enumerated_type_check(var_name: str, val: object) -> ResultT:
for func in allowed_type_funcs: for func in allowed_type_funcs:
try: try:
@ -318,7 +245,6 @@ def check_union(allowed_type_funcs: Iterable[Validator[ResultT]]) -> Validator[R
return enumerated_type_check return enumerated_type_check
def equals(expected_val: ResultT) -> Validator[ResultT]: def equals(expected_val: ResultT) -> Validator[ResultT]:
@set_type_structure(f'equals("{str(expected_val)}")')
def f(var_name: str, val: object) -> ResultT: def f(var_name: str, val: object) -> ResultT:
if val != expected_val: if val != expected_val:
raise ValidationError(_('{variable} != {expected_value} ({value} is wrong)').format( raise ValidationError(_('{variable} != {expected_value} ({value} is wrong)').format(
@ -327,14 +253,12 @@ def equals(expected_val: ResultT) -> Validator[ResultT]:
return cast(ResultT, val) return cast(ResultT, val)
return f return f
@set_type_structure('str')
def validate_login_email(email: str) -> None: def validate_login_email(email: str) -> None:
try: try:
validate_email(email) validate_email(email)
except ValidationError as err: except ValidationError as err:
raise JsonableError(str(err.message)) raise JsonableError(str(err.message))
@set_type_structure('str')
def check_url(var_name: str, val: object) -> str: def check_url(var_name: str, val: object) -> str:
# First, ensure val is a string # First, ensure val is a string
s = check_string(var_name, val) s = check_string(var_name, val)
@ -346,7 +270,6 @@ def check_url(var_name: str, val: object) -> str:
except ValidationError: except ValidationError:
raise ValidationError(_('{var_name} is not a URL').format(var_name=var_name)) raise ValidationError(_('{var_name} is not a URL').format(var_name=var_name))
@set_type_structure('str')
def check_external_account_url_pattern(var_name: str, val: object) -> str: def check_external_account_url_pattern(var_name: str, val: object) -> str:
s = check_string(var_name, val) s = check_string(var_name, val)
@ -433,7 +356,6 @@ def check_widget_content(widget_content: object) -> Dict[str, Any]:
# Converter functions for use with has_request_variables # Converter functions for use with has_request_variables
@set_type_structure('int')
def to_non_negative_int(s: str, max_int_size: int=2**32-1) -> int: def to_non_negative_int(s: str, max_int_size: int=2**32-1) -> int:
x = int(s) x = int(s)
if x < 0: if x < 0:
@ -443,7 +365,6 @@ def to_non_negative_int(s: str, max_int_size: int=2**32-1) -> int:
return x return x
def to_positive_or_allowed_int(allowed_integer: int) -> Callable[[str], int]: def to_positive_or_allowed_int(allowed_integer: int) -> Callable[[str], int]:
@set_type_structure('int')
def convertor(s: str) -> int: def convertor(s: str) -> int:
x = int(s) x = int(s)
if x == allowed_integer: if x == allowed_integer:
@ -453,7 +374,6 @@ def to_positive_or_allowed_int(allowed_integer: int) -> Callable[[str], int]:
return to_non_negative_int(s) return to_non_negative_int(s)
return convertor return convertor
@set_type_structure('any(List[int], str)]')
def check_string_or_int_list(var_name: str, val: object) -> Union[str, List[int]]: def check_string_or_int_list(var_name: str, val: object) -> Union[str, List[int]]:
if isinstance(val, str): if isinstance(val, str):
return val return val
@ -463,7 +383,6 @@ def check_string_or_int_list(var_name: str, val: object) -> Union[str, List[int]
return check_list(check_int)(var_name, val) return check_list(check_int)(var_name, val)
@set_type_structure('any(int, str)')
def check_string_or_int(var_name: str, val: object) -> Union[str, int]: def check_string_or_int(var_name: str, val: object) -> Union[str, int]:
if isinstance(val, str) or isinstance(val, int): if isinstance(val, str) or isinstance(val, int):
return val return val