def test_optional_pep604(self): # New PEP 604 union syntax in Python 3.10+ self.assertTrue(typing_utils.is_optional_type(str | None)) self.assertTrue(typing_utils.is_optional_type(None | str)) self.assertEqual(typing_utils.get_optional_type(str | None), str) self.assertEqual(typing_utils.get_optional_type(None | str), str) self.assertFalse(typing_utils.is_optional_type(int | str))
def get_type_info(tp: type) -> TypeInfo: """ Reduce iterable and optional types to their 'base' types. """ is_final = typing_utils.is_final_type(tp) if is_final: tp = typing_utils.get_final_type(tp) if tp is typing.Any: # This used to be supported, but Python 3.10 raises in get_type_hints() if it encounters a plain Final hint. raise TypeError( 'Plain typing.Final is not valid as a type argument.') is_nullable = typing_utils.is_optional_type(tp) if is_nullable: tp = typing_utils.get_optional_type(tp) is_mapping = typing_utils.is_mapping_type(tp) is_many = typing_utils.is_iterable_type(tp) if is_mapping: tp = typing_utils.get_mapping_value_type(tp) elif is_many: # This must be elif (instead of if), as otherwise we'd reduce mappings twice as they're also iterable tp = typing_utils.get_iterable_element_type(tp) if typing_utils.is_type_variable(tp): tp = typing_utils.get_variable_type_substitute(tp) if tp is typing.Any: tp = None return TypeInfo(is_many, is_mapping, is_final, is_nullable, tp)
def get_type_info( tp: type, default_value_type: typing.Optional[type] = None) -> TypeInfo: """ Reduce iterable and optional types to their 'base' types. """ is_final = typing_utils.is_final_type(tp) if is_final: tp = typing_utils.get_final_type(tp) if tp is typing.Any and default_value_type is not None: tp = default_value_type is_optional = typing_utils.is_optional_type(tp) if is_optional: tp = typing_utils.get_optional_type(tp) is_mapping = typing_utils.is_mapping_type(tp) is_many = typing_utils.is_iterable_type(tp) if is_mapping: tp = typing_utils.get_mapping_value_type(tp) elif is_many: # This must be elif (instead of if), as otherwise we'd reduce mappings twice as they're also iterable tp = typing_utils.get_iterable_element_type(tp) if typing_utils.is_type_variable(tp): tp = typing_utils.get_variable_type_substitute(tp) if tp is typing.Any: tp = None return TypeInfo(is_many, is_mapping, is_final, is_optional, tp)
def test_optional(self): self.assertTrue(typing_utils.is_optional_type(typing.Optional[str])) self.assertTrue(typing_utils.is_optional_type(typing.Union[str, None])) self.assertTrue( typing_utils.is_optional_type(typing.Union[str, typing.Optional[str]])) self.assertTrue( typing_utils.is_optional_type(typing.Union[str, typing.Union[str, None]])) self.assertFalse(typing_utils.is_optional_type(str)) self.assertFalse(typing_utils.is_optional_type(int)) self.assertFalse(typing_utils.is_optional_type(TypingTest)) self.assertEqual(typing_utils.get_optional_type(typing.Optional[str]), str) self.assertEqual( typing_utils.get_optional_type(typing.Union[str, None]), str) self.assertEqual( typing_utils.get_optional_type(typing.Union[None, str]), str) self.assertEqual( typing_utils.get_optional_type(typing.Union[str, typing.Optional[str]]), str) self.assertEqual( typing_utils.get_optional_type(typing.Union[str, typing.Union[str, None]]), str) with self.assertRaises(ValueError): typing_utils.get_optional_type(str)
def get_type_info(tp: type) -> TypeInfo: """ Reduce iterable and optional types to their 'base' types. """ is_optional = typing_utils.is_optional_type(tp) if is_optional: tp = typing_utils.get_optional_type(tp) is_mapping = typing_utils.is_mapping_type(tp) is_many = typing_utils.is_iterable_type(tp) if is_mapping: tp = typing_utils.get_mapping_value_type(tp) elif is_many: # This must be elif (instead of if), as otherwise we'd reduce mappings twice tp = typing_utils.get_iterable_element_type(tp) return TypeInfo(is_many, is_mapping, is_optional, tp)