def _parse_procedure_arguments(self, type_hints, request_json): arguments = {} version = type_hints.get('_v', 1) name_map = type_hints['_names'] for argument_name, type_ in type_hints.items(): if argument_name.startswith('_'): continue if version >= 2: type_ = type_() behind_name = name_map[argument_name] try: data = request_json[behind_name] except KeyError: raise NirumProcedureArgumentRequiredError( "A argument named '{}' is missing, it is required.".format( behind_name)) try: arguments[argument_name] = deserialize_meta(type_, data) except ValueError: raise NirumProcedureArgumentValueError( "Incorrect type '{0}' for '{1}'. " "expected '{2}'.".format(typing._type_repr(data.__class__), behind_name, typing._type_repr(type_))) return arguments
def _parse_procedure_arguments(self, method_facial_name, request_json): type_hints = self.service.__nirum_service_methods__[method_facial_name] arguments = {} version = type_hints.get('_v', 1) name_map = type_hints['_names'] errors = MethodArgumentError() for argument_name, type_ in type_hints.items(): if argument_name.startswith('_'): continue if version >= 2: type_ = type_() behind_name = name_map[argument_name] try: data = request_json[behind_name] except KeyError: if is_optional_type(type_): arguments[argument_name] = None else: errors.on_error('.' + behind_name, 'Expected to exist.') continue try: arguments[argument_name] = deserialize_meta(type_, data) except ValueError: errors.on_error( '.' + behind_name, 'Expected {0}, but {1} was given.'.format( typing._type_repr(type_), typing._type_repr(type(data)))) errors.raise_if_errored() return arguments
def check_tuple(data: typing.Tuple, hint: typing.Union[type, typing.TypingMeta]) -> bool: """Check argument type & return type of :class:`typing.Tuple`. since it raises check :class:`typing.Tuple` using `isinstance`, so compare in diffrent way :param data: tuple given as a argument :param hint: assumed type of given ``data`` """ if not isinstance(data, tuple): raise TypeError( 'expected {}, not {}'.format( typing._type_repr(hint), 'None' if data is None else '{}: {!r}'.format( typing._type_repr(type(data)), data ) ) ) tuple_param = hint.__tuple_params__ if len(data) != len(tuple_param): raise TypeError('expected tuple size is {}, not {}: ' '{!r}'.format(len(tuple_param), len(data), data)) zipped = itertools.zip_longest(data, tuple_param) for i, (v, t) in enumerate(zipped): _, correct = check_type(v, t) if not correct: raise TypeError( '{0}th item `{1}` in tuple must be {2!r}, not: {3!r}'.format( i, v, t, v ) ) return hint, True
def test_readable_error_when_null_returned_from_null_disallowed_method(caplog): """Even if the method implementation returns None (FYI Python functions return None when it lacks return statement so that service methods are prone to return None by mistake) the error message should be readable and helpful for debugging. """ expected_message = '''The return type of null-disallowed-method() method \ is not optional (i.e., no trailing question mark), but its server-side \ implementation has tried to return nothing (i.e., null, nil, None). \ It is an internal server error and should be fixed by server-side.''' app = WsgiApp(NullDisallowedMethodServiceImpl(None)) client = Client(app, Response) caplog.handler.records = [] # Clear log records response = client.post('/?method=null_disallowed_method', data=json.dumps({}), content_type='application/json') assert caplog.record_tuples and caplog.record_tuples[-1] == ( '{0}.null_disallowed_method'.format( typing._type_repr(NullDisallowedMethodServiceImpl)), logging.ERROR, '''None is an invalid return value for the return type of {0}.\ null_disallowed_method() method.'''.format( typing._type_repr(NullDisallowedMethodServiceImpl)), ) assert response.status_code == 500, response.get_data(as_text=True) actual = json.loads(response.get_data(as_text=True)) assert actual == { '_type': 'error', '_tag': 'internal_server_error', 'message': expected_message, }
def deserialize_union_type(cls, value): if '_type' not in value: raise ValueError('"_type" field is missing.') if '_tag' not in value: raise ValueError('"_tag" field is missing.') if not hasattr(cls, '__nirum_tag__'): if hasattr(cls, '__nirum_tag_classes__'): tag = cls.Tag(value['_tag']) try: cls = cls.__nirum_tag_classes__[tag] except KeyError: raise ValueError( '{0!r} is not deserialzable tag of {1} ({2!r})'.format( value, typing._type_repr(cls), tag ) ) else: # FIXME: This fallback for backward compatibility should be removed # in the future releases. # See also: https://github.com/spoqa/nirum/pull/192 for sub_cls in cls.__subclasses__(): if sub_cls.__nirum_tag__.value == value['_tag']: cls = sub_cls break else: raise ValueError( '{0!r} is not deserialzable tag of {1}'.format( value, typing._type_repr(cls) ) ) if not cls.__nirum_union_behind_name__ == value['_type']: raise ValueError('{0} expect "_type" equal to' ' "{1.__nirum_union_behind_name__}"' ', but found {2}.'.format(typing._type_repr(cls), cls, value['_type'])) if not cls.__nirum_tag__.value == value['_tag']: raise ValueError('{0} expect "_tag" equal to' ' "{1.__nirum_tag__.value}"' ', but found {1}.'.format(typing._type_repr(cls), cls, value['_tag'])) args = {} behind_names = cls.__nirum_tag_names__.behind_names for attribute_name, item in value.items(): if attribute_name in {'_type', '_tag'}: continue if attribute_name in behind_names: name = behind_names[attribute_name] else: name = attribute_name tag_types = cls.__nirum_tag_types__ if callable(tag_types): # old compiler could generate non-callable map tag_types = dict(tag_types()) args[name] = deserialize_meta(tag_types[name], item) return cls(**args)
def test_wsgi_app_error(caplog, fx_test_client): # method not allowed assert_response( fx_test_client.get('/?method=get_music_by_artist_name'), 405, { '_type': 'error', '_tag': 'method_not_allowed', 'message': 'The requested URL / was not allowed HTTP method GET.' }) # method missing assert_response( fx_test_client.post('/'), 400, { '_type': 'error', '_tag': 'bad_request', 'message': u'`method` is missing.', }) # invalid procedure name assert_response( fx_test_client.post('/?method=foo'), 400, { '_type': 'error', '_tag': 'bad_request', 'message': 'No service method `foo` found.' }) # invalid json assert_response( fx_test_client.post('/?method=get_music_by_artist_name', data="!", content_type='application/json'), 400, { '_type': 'error', '_tag': 'bad_request', 'message': "Invalid JSON payload: '!'." }) # incorrect return caplog.handler.records = [] # Clear log records response = fx_test_client.post('/?method=incorrect_return') assert caplog.record_tuples and caplog.record_tuples[-1] == ( typing._type_repr(MusicServiceImpl) + '.incorrect_return', logging.ERROR, '''1 is an invalid return value for the return type ({0}) of {1}.\ incorrect_return() method.'''.format('unicode' if PY2 else 'str', typing._type_repr(MusicServiceImpl)), ) assert_response( response, 500, { '_type': 'error', '_tag': 'internal_server_error', 'message': '''The return type of the incorrect-return() method is \ {0}, but its server-side implementation has tried to return a value of \ an invalid type. It is an internal server error and should be fixed by \ server-side.'''.format('unicode' if PY2 else 'str') })
def __init__(self): for method_name in self.__nirum_service_methods__: try: method = getattr(self, method_name) except AttributeError: raise InvalidNirumServiceMethodNameError( "{0}.{1} inexist.".format( typing._type_repr(self.__class__), method_name)) if not callable(method): raise InvalidNirumServiceMethodTypeError( "{0}.{1} isn't callable".format( typing._type_repr(self.__class__), method_name))
def __init__(self): for method_name in self.__nirum_service_methods__: try: method = getattr(self, method_name) except AttributeError: raise InvalidNirumServiceMethodNameError( '{0}.{1}() method has to be implemented.'.format( typing._type_repr(type(self)), method_name)) if not callable(method): raise InvalidNirumServiceMethodTypeError( '{0}.{1} has to be callable so that is a method'.format( typing._type_repr(type(self)), method_name))
def _link_type_args(self, obj: Any, reverse_index: Dict[int, str], linker: signature_lib.FormatArguments) -> str: """Recurses into typehint object and links known objects to their pages.""" arg_full_name = reverse_index.get(id(obj), None) if arg_full_name is not None: return linker.get_link(arg_full_name) result = [] if getattr(obj, '__args__', None): for arg in obj.__args__: result.append(self._link_type_args(arg, reverse_index, linker)) origin_str = typing._type_repr(obj.__origin__) # pylint: disable=protected-access # pytype: disable=module-attr result = self._custom_join(result, origin_str) return f'{origin_str}[{result}]' else: return typing._type_repr(obj) # pylint: disable=protected-access # pytype: disable=module-attr
def deserialize_record_type(cls, value): if '_type' not in value: raise ValueError('"_type" field is missing.') if not cls.__nirum_record_behind_name__ == value['_type']: raise ValueError( '{0} expect "_type" equal to "{1.__nirum_record_behind_name__}"' ', but found {2}.'.format( typing._type_repr(cls), cls, value['_type'] ) ) args = {} behind_names = cls.__nirum_field_names__.behind_names field_types = cls.__nirum_field_types__ if callable(field_types): field_types = field_types() # old compiler could generate non-callable dictionary for attribute_name, item in value.items(): if attribute_name == '_type': continue if attribute_name in behind_names: name = behind_names[attribute_name] else: name = attribute_name args[name] = deserialize_meta(field_types[name], item) return cls(**args)
def __getitem__(self, params): if not isinstance(params, tuple): params = (params,) if not params: raise TypeError("Cannot have empty parameter list") params = tuple(params) if self.__parameters__ is None: for p in params: if not isinstance(p, (TypeVar, TypeParam)): raise TypeError("Initial parameters must be " "type variables; got %s" % p) if len(set(params)) != len(params): raise TypeError("All type variables in Generic[...] must be distinct.") else: if len(params) != len(self.__parameters__): raise TypeError("Cannot change parameter count from %d to %d" % (len(self.__parameters__), len(params))) for new, old in zip(params, self.__parameters__): if isinstance(old, TypeVar): if not old.__constraints__: # Substituting for an unconstrained TypeVar is OK. continue if issubclass(new, Union[old.__constraints__]): # Specializing a constrained type variable is OK. continue if not issubclass(new, old): raise TypeError("Cannot substitute %s for %s in %s" % (_type_repr(new), _type_repr(old), self)) return self.__class__( self.__name__, self.__bases__, dict(self.__dict__), parameters=params, origin=self, extra=self.__extra__ )
def deserialize_primitive(cls, data): if cls is datetime.datetime: try: d = parse_date(data) except iso8601.ParseError: raise ValueError("'{}' is not a datetime.".format(data)) elif cls is datetime.date: try: d = parse_date(data).date() except iso8601.ParseError: raise ValueError("'{}' is not a date.".format(data)) elif cls in {int, float, uuid.UUID, bool}: d = cls(data) elif cls is numbers.Integral: d = data elif cls is decimal.Decimal: try: d = cls(data) except decimal.InvalidOperation: raise ValueError("'{}' is not a decimal.".format(data)) elif cls is text_type: if not isinstance(data, text_type): raise ValueError("'{}' is not a string.".format(data)) d = cls(data) else: raise TypeError("'{0}' is not a primitive type.".format( typing._type_repr(cls))) return d
def typecheck(self, value) -> None: union_types = get_union_types(self.cls) cls = self.cls if union_types is None else union_types if not isinstance(value, cls): raise ConfigTypeError( '{0} configuration must be {1}, not {2!r}'.format( self.key, typing._type_repr(self.cls), value))
def __get__(self, obj, cls: typing.Optional[type] = None): if obj is None: return self if self.cached: cache_key = ' cache_{!s}'.format(self.key) try: instance = getattr(obj, cache_key) except AttributeError: pass else: return instance default, expression = self.get_raw_value(obj) if default: return expression if not isinstance(expression, collections.abc.Mapping): raise ConfigTypeError( '{0!r} field must be a mapping, not {1}'.format( self.key, typing._type_repr(type(expression)))) elif 'class' not in expression: raise ConfigValueError('{0!r} field lacks "class" field'.format( self.key)) value = self.evaluate(expression) self.typecheck(value) if self.cached: setattr(obj, cache_key, value) return value
def rpc(self, request, service_method, request_json): name_map = self.service.__nirum_method_names__ try: method_facial_name = name_map.behind_names[service_method] except KeyError: raise ServiceMethodError() try: func = getattr(self.service, method_facial_name) except AttributeError: return self.error(400, request, message="Service has no procedure '{}'.".format( service_method)) if not callable(func): return self.error( 400, request, message="Remote procedure '{}' is not callable.".format( service_method)) type_hints = self.service.__nirum_service_methods__[method_facial_name] try: arguments = self._parse_procedure_arguments( type_hints, request_json) except (NirumProcedureArgumentValueError, NirumProcedureArgumentRequiredError) as e: return self.error(400, request, message=str(e)) method_error_types = self.service.__nirum_method_error_types__ if not callable(method_error_types): # generated by older compiler method_error_types = method_error_types.get method_error = method_error_types(method_facial_name, ()) try: result = func(**arguments) except method_error as e: return self._raw_response(400, serialize_meta(e)) return_type = type_hints['_return'] if type_hints.get('_v', 1) >= 2: return_type = return_type() if not self._check_return_type(return_type, result): return self.error(400, request, message="Incorrect return type '{0}' " "for '{1}'. expected '{2}'.".format( typing._type_repr(result.__class__), service_method, typing._type_repr(return_type))) else: return self._raw_response(200, serialize_meta(result))
def _tree_repr(self, tree): cls, origin, metadata = tree if not isinstance(origin, tuple): tp_repr = typing._type_repr(origin) else: tp_repr = origin[0]._tree_repr(origin) metadata_reprs = ", ".join(repr(arg) for arg in metadata) return '%s[%s, %s]' % (cls, tp_repr, metadata_reprs)
def do_request(self, request_url, payload): request_tuple = self.make_request(u'POST', request_url, [ ('Content-type', 'application/json;charset=utf-8'), ('Accepts', 'application/json'), ], payload) if not isinstance(request_tuple, collections.Sequence) and \ len(request_tuple) == 3: raise TypeError( 'make_request() must return a triple of ' '(status_code, content, headers): {}'.format(request_tuple)) http_method, request_url, headers, content = request_tuple if not isinstance(request_url, text_type): raise TypeError( '`request_url` have to be instance of text. not {}'.format( typing._type_repr(type(request_url)))) if not isinstance(headers, collections.Sequence): raise TypeError( '`headers` have to be instance of sequence. not {}'.format( typing._type_repr(type(headers)))) if not isinstance(content, bytes): raise TypeError( '`content` have to be instance of bytes. not {}'.format( typing._type_repr(type(content)))) if not isinstance(http_method, text_type): raise TypeError( '`method` have to be instance of text. not {}'.format( typing._type_repr(type(http_method)))) http_method = http_method.upper() proper_http_method_names = { 'GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'TRACE', 'CONNECT', 'HEAD' } if http_method not in proper_http_method_names: raise ValueError('`method` have to be one of {!r}.: {}'.format( proper_http_method_names, http_method)) request = urllib.request.Request(request_url, data=content) request.get_method = lambda: http_method.upper() for header_name, header_content in headers: request.add_header(header_name, header_content) response = self.opener.open(request, None) response_text = response.read() if 200 <= response.code < 300: return response_text.decode('utf-8') else: raise UnexpectedNirumResponseError(response_text)
def typecheck(self, value) -> None: union_types = get_union_types(self.cls) cls = self.cls if union_types is None else union_types if not isinstance(value, cls): raise ConfigTypeError( '{0} configuration must be {1}, not {2!r}'.format( self.key, typing._type_repr(self.cls), value ) )
def validate_record_type(record): for attr, type_ in record.__nirum_field_types__.items(): data = getattr(record, attr) if not validate_type(data, type_): raise TypeError('expect {0}.{1} to be {2}' ', but found: {3}'.format( typing._type_repr(record.__class__), attr, type_, type(data))) else: return record
def validate_union_type(union): for attr, type_ in union.__nirum_tag_types__.items(): data = getattr(union, attr) if not validate_type(data, type_): raise TypeError('expect {0}.{1} to be {2}' ', but found: {3}'.format( typing._type_repr(union.__class__), attr, type_, type(data))) else: return union
def _dp_init_subclass(sub_cls, *args, **kwargs): # Add function for datapipe instance to reinforce the type sub_cls.reinforce_type = reinforce_type # TODO: # - add global switch for type checking at compile-time # Ignore internal type class if getattr(sub_cls, '__type_class__', False): return # Check if the string type is valid if isinstance(sub_cls.type.param, ForwardRef): base_globals = sys.modules[sub_cls.__module__].__dict__ try: param = _eval_type(sub_cls.type.param, base_globals, locals()) sub_cls.type.param = param except TypeError as e: raise TypeError("{} is not supported by Python typing".format( sub_cls.type.param.__forward_arg__)) from e if '__iter__' in sub_cls.__dict__: iter_fn = sub_cls.__dict__['__iter__'] hints = get_type_hints(iter_fn) if 'return' in hints: return_hint = hints['return'] # Plain Return Hint for Python 3.6 if return_hint == Iterator: return if not (hasattr(return_hint, '__origin__') and (return_hint.__origin__ == Iterator or return_hint.__origin__ == collections.abc.Iterator)): raise TypeError( "Expected 'Iterator' as the return annotation for `__iter__` of {}" ", but found {}".format(sub_cls.__name__, _type_repr(hints['return']))) data_type = return_hint.__args__[0] if not issubtype(data_type, sub_cls.type.param): raise TypeError( "Expected return type of '__iter__' as a subtype of {}, but found {}" " for {}".format(sub_cls.type, _type_repr(data_type), sub_cls.__name__))
def _dp_init_subclass(sub_cls, *args, **kwargs): # TODO: # - add global switch for type checking at compile-time if '__iter__' in sub_cls.__dict__: iter_fn = sub_cls.__dict__['__iter__'] hints = get_type_hints(iter_fn) if 'return' in hints: return_hint = hints['return'] # Plain Return Hint for Python 3.6 if return_hint == Iterator: return if not (hasattr(return_hint, '__origin__') and (return_hint.__origin__ == Iterator or return_hint.__origin__ == collections.abc.Iterator)): raise TypeError("Expected 'Iterator' as the return annotation for `__iter__` of {}" ", but found {}".format(sub_cls.__name__, _type_repr(hints['return']))) data_type = return_hint.__args__[0] if not issubtype(data_type, sub_cls.type.param): raise TypeError("Expected return type of '__iter__' is a subtype of {}, but found {}" " for {}".format(sub_cls.type, _type_repr(data_type), sub_cls.__name__))
def collect_docs(self) -> None: """Collect all information necessary to genertate the function page. Mainly this is details about the function signature. For the type alias signature, the args are extracted and replaced with the full_name if the object is present in `parser_config.reverse_index`. They are also linkified to point to that symbol's page. For example (If generating docs for symbols in TF library): ``` X = Union[int, str, bool, tf.Tensor, np.ndarray] ``` In this case `tf.Tensor` will get linked to that symbol's page. Note: In the signature `tf.Tensor` is an object, so it will show up as `tensorflow.python.framework.ops.Tensor`. That's why we need to query `parser_config.reverse_index` to get the full_name of the object which will be `tf.Tensor`. Hence the signature will be: ``` X = Union[int, str, bool, <a href="URL">tf.Tensor</a>, np.ndarray] ``` """ assert self.signature is None linker = signature_lib.FormatArguments( parser_config=self.parser_config) sig_args = [] if self.py_object.__origin__: for arg_obj in self.py_object.__args__: sig_args.append( self._link_type_args(arg_obj, self.parser_config.reverse_index, linker)) sig_args_str = textwrap.indent(',\n'.join(sig_args), ' ') if self.py_object.__origin__: origin_str = typing._type_repr(self.py_object.__origin__) # pylint: disable=protected-access # pytype: disable=module-attr sig = f'{origin_str}[\n{sig_args_str}\n]' else: sig = repr(self.py_object) # pytype: enable=module-attr # Starting in Python 3.7, the __origin__ attribute of typing constructs # contains the equivalent runtime class rather than the construct itself # (e.g., typing.Callable.__origin__ is collections.abc.Callable). self._signature = sig.replace('typing.', '').replace('collections.abc.', '')
def validate_union_type(union): tag_types = union.__nirum_tag_types__ if not callable(tag_types): # generated by older compiler tag_types = tag_types.items for attr, type_ in tag_types(): data = getattr(union, attr) if not validate_type(data, type_): raise TypeError('expect {0}.{1} to be {2}' ', but found: {3}'.format( typing._type_repr(union.__class__), attr, type_, type(data))) else: return union
def validate_record_type(record): field_types = record.__nirum_field_types__ if callable(field_types): field_types = field_types() # old compiler could generate non-callable dictionary for attr, type_ in field_types.items(): data = getattr(record, attr) if not validate_type(data, type_): raise TypeError('expect {0}.{1} to be {2}' ', but found: {3}'.format( typing._type_repr(record.__class__), attr, type_, type(data))) else: return record
def deserialize_union_type(cls, value): if '_type' not in value: raise ValueError('"_type" field is missing.') if '_tag' not in value: raise ValueError('"_tag" field is missing.') if not hasattr(cls, '__nirum_tag__'): for sub_cls in cls.__subclasses__(): if sub_cls.__nirum_tag__.value == value['_tag']: cls = sub_cls break else: raise ValueError('{0!r} is not deserialzable tag of `{1}`.'.format( value, typing._type_repr(cls))) if not cls.__nirum_union_behind_name__ == value['_type']: raise ValueError('{0} expect "_type" equal to' ' "{1.__nirum_union_behind_name__}"' ', but found {2}.'.format(typing._type_repr(cls), cls, value['_type'])) if not cls.__nirum_tag__.value == value['_tag']: raise ValueError('{0} expect "_tag" equal to' ' "{1.__nirum_tag__.value}"' ', but found {1}.'.format(typing._type_repr(cls), cls, value['_tag'])) args = {} behind_names = cls.__nirum_tag_names__.behind_names for attribute_name, item in value.items(): if attribute_name in {'_type', '_tag'}: continue if attribute_name in behind_names: name = behind_names[attribute_name] else: name = attribute_name tag_types = cls.__nirum_tag_types__ if callable(tag_types): # old compiler could generate non-callable map tag_types = dict(tag_types()) args[name] = deserialize_meta(tag_types[name], item) return cls(**args)
def __get__(self, obj, cls: typing.Optional[type] = None): if obj is None: return self default, expression = self.get_raw_value(obj) if not default: if not isinstance(expression, collections.abc.Mapping): raise ConfigTypeError( '{0!r} field must be a mapping, not {1}'.format( self.key, typing._type_repr(type(expression)))) elif 'class' not in expression: raise ConfigValueError( '{0!r} field lacks "class" field'.format(self.key)) value = self.evaluate(expression) self.typecheck(value) return value
def __getitem__(self, params): if not isinstance(params, tuple): params = (params, ) if not params: raise TypeError("Cannot have empty parameter list") params = tuple(params) if self.__parameters__ is None: for p in params: if not isinstance(p, (TypeVar, TypeParam)): raise TypeError("Initial parameters must be " "type variables; got %s" % p) if len(set(params)) != len(params): raise TypeError( "All type variables in Generic[...] must be distinct.") else: if len(params) != len(self.__parameters__): raise TypeError("Cannot change parameter count from %d to %d" % (len(self.__parameters__), len(params))) for new, old in zip(params, self.__parameters__): if isinstance(old, TypeVar): if not old.__constraints__: # Substituting for an unconstrained TypeVar is OK. continue if issubclass(new, Union[old.__constraints__]): # Specializing a constrained type variable is OK. continue if not issubclass(new, old): raise TypeError("Cannot substitute %s for %s in %s" % (_type_repr(new), _type_repr(old), self)) return self.__class__(self.__name__, self.__bases__, dict(self.__dict__), parameters=params, origin=self, extra=self.__extra__)
def _raw_response(self, status_code, response_json, **kwargs): response_tuple = self.make_response( status_code, headers=[('Content-type', 'application/json')], content=json.dumps(response_json).encode('utf-8')) if not (isinstance(response_tuple, collections.Sequence) and len(response_tuple) == 3): raise TypeError('make_response() must return a triple of ' '(status_code, headers, content), not ' + repr(response_tuple)) status_code, headers, content = response_tuple if not isinstance(status_code, integer_types): raise TypeError( '`status_code` have to be instance of integer. not {}'.format( typing._type_repr(type(status_code)))) if not isinstance(headers, collections.Sequence): raise TypeError( '`headers` have to be instance of sequence. not {}'.format( typing._type_repr(type(headers)))) if not isinstance(content, bytes): raise TypeError( '`content` have to be instance of bytes. not {}'.format( typing._type_repr(type(content)))) return Response(content, status_code, headers, **kwargs)
def reinforce_type(self, expected_type): r""" Reinforce the type for DataPipe instance. And the 'expected_type' is required to be a subtype of the original type hint to restrict the type requirement of DataPipe instance. """ if isinstance(expected_type, tuple): expected_type = Tuple[expected_type] _type_check(expected_type, msg="'expected_type' must be a type") if not issubtype(expected_type, self.type.param): raise TypeError("Expected 'expected_type' as subtype of {}, but found {}" .format(self.type, _type_repr(expected_type))) self.type = _DataPipeType(expected_type) return self
def test_serializer_deserializer(spec_file): with io.open(spec_file, 'r', encoding='utf-8') as f: spec = json.load(f) print() print('Spec:', os.path.relpath(spec_file, test_suite_dir)) print('Description:', spec['description']) print('Type:', spec['type']) candidates = list( pkg_resources.iter_entry_points('nirum.classes', name=spec['type'])) assert 'normal' in spec or 'errors' in spec, ( 'The specification must have either "normal" or "errors" field.') assert candidates, ( 'Failed to resolve a corresponding Python class to the Nirum ' 'type "{0}".'.format(spec['type'])) assert len(candidates) < 2, ( 'Too many classes are mapped to the Nirum type name "{0}":\n' '{1}'.format(spec['type'], '\n'.join(map(str, candidates)))) cls = candidates[0].resolve() print('Class:', _type_repr(cls)) print('Input:', dump_json(spec['input'])) if 'normal' in spec: deserialized = cls.__nirum_deserialize__(spec['input']) print('Deserialized:', pprint.pformat(deserialized)) print('Normal:', dump_json(spec['normal'])) serialized = deserialized.__nirum_serialize__() print('Serialized:', dump_json(serialized)) if 'ignoreOrder' in spec: normalize(spec['ignoreOrder'], spec['normal']) normalize(spec['ignoreOrder'], serialized) assert serialized == spec['normal'] else: print('Expected errors:', dump_json(spec['errors'])) actual_errors = set() deserialized = cls.__nirum_deserialize__( spec['input'], on_error=lambda field, msg: actual_errors.add((field, msg))) print( 'Actual errors:', dump_json([{ 'path': p, 'message': m } for (p, m) in sorted(actual_errors)])) if not actual_errors: print('Deserialized:', pprint.pformat(deserialized)) assert actual_errors == frozenset( (e['path'], e['message']) for e in spec['errors']) print()
def __get__(self, obj, cls: typing.Optional[type] = None): if obj is None: return self default, expression = self.get_raw_value(obj) if not default: if not isinstance(expression, collections.abc.Mapping): raise ConfigTypeError( '{0!r} field must be a mapping, not {1}'.format( self.key, typing._type_repr(type(expression)) ) ) elif 'class' not in expression: raise ConfigValueError( '{0!r} field lacks "class" field'.format(self.key) ) value = self.evaluate(expression) self.typecheck(value) return value
def __repr__(self): r = super(_Final, self).__repr__() if self.__type__ is not None: r += '[{}]'.format(typing._type_repr(self.__type__)) return r
def __repr__(self): return _type_repr(self.param)