-
Notifications
You must be signed in to change notification settings - Fork 246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Request: an AssertingTypeGuard type for TypeGuard-like semantics #930
Comments
I like this idea, and have been mulling something similar myself. The name floating around my head was def assert_is_nonempty_list_of_str(x: object) -> FailsUnless[list[str]]:
if not isinstance(x, list):
raise ExpectedListError(x)
if not x:
raise EmptyContainerError(x)
if not all(isinstance(y, str) for y in x):
raise ContainedInvalidTypeError(x, str)
return x |
pyanalyze provides a version of this, though there's no Python-level syntax for it yet. They're called "no_return_unless constraints". I have found it useful in two main contexts:
|
That sounds incredibly unsafe, eg: def foo(the_list: list[str]):
the_list[0].upper() # SUS ALERT
l1 = []
l2 = l1
l2.append(1)
l1.append("AMONGUS")
foo(l1) # is l1 a list[str] or a list[str | int] |
That seems consistent with
This seems OT to me. I'm focused more on cases like # some web application with a DB
def check_exists(db_object: Optional[DBModelBase]) -> NoReturnGuard[DBModelBase]:
if db_object is None:
raise HTTPNotFound(db_object)
maybe_user = get_user(user_id)
check_exists(maybe_user)
reveal_type(maybe_user) # DBUser |
mypy doesn't yet understand that `assertIsNotNone` validates the non-None nature of the variable. Related issues: - python/mypy#5088 - python/mypy#4063 - python/typing#930
Something like the following gets nearly what you want (I'm currently using it in a project), but I admit it'd be a bit neater to have a real assert-like custom guard, which would also work with non-assignable variables and types which happen not to be classes. class ParentClass:
a: int
class ChildClass(ParentClass):
b: str
T = typing.TypeVar('T', bound=ParentClass)
def assert_type(instance: ParentClass, expected_type: type[T]) -> T:
if not isinstance(instance, expected_type):
raise ValueError()
return instance
variable: ParentClass = ParentClass()
variable = assert_type(variable, ChildClass)
print(variable.a)
print(variable.b)
print(variable.c)
variable = assert_type(variable, ParentClass)
print(variable.a)
print(variable.b)
print(variable.c) Mypy 1.1.1 returns:
|
There is a frequent pattern of TypeGuard-like functions which
assert
or otherwise raise an exception if a type constraint is not met.For example, microsoft/pyright#2007 points to a case in which
unittest
providesassertIsNotNone
, but a type-checker cannot infer that type narrowing has occurred. Arguably, the popular typeguard library is based around an implementation of "asserting" type guards. (One which deduces what assertions should be made from the annotations.)TypeGuards allow for semantics like
An AssertingTypeGuard would allow for
This becomes especially valuable if we consider that you might not want to do this all with
assert
. I may, as an author, prefer my own custom exceptions, e.g.(Apologies if this repo is the wrong place to submit this request/idea. I'm happy to go through another process if necessary.)
The text was updated successfully, but these errors were encountered: