Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,6 @@ If users want to read/write to attributes such as `__qualname__`, they need to c
of the attribute first:

```py
from inspect import getattr_static

def f_okay(c: Callable[[], None]):
if hasattr(c, "__qualname__"):
reveal_type(c.__qualname__) # revealed: object
Expand All @@ -397,14 +395,11 @@ def f_okay(c: Callable[[], None]):
reveal_type(type(c).__qualname__) # revealed: @Todo(Intersection meta-type)

# `hasattr` only guarantees that an attribute is readable.
#
# error: [invalid-assignment] "Object of type `Literal["my_callable"]` is not assignable to attribute `__qualname__` on type `(() -> None) & <Protocol with members '__qualname__'>`"
# TODO: This assignment should ideally be an error, since the synthesized
# protocol member is a read-only property. Currently, the `Callable` element
# of the intersection has `type.__qualname__: str` at the class level,
# which allows the assignment to go through.
c.__qualname__ = "my_callable"

result = getattr_static(c, "__qualname__")
reveal_type(result) # revealed: property
if isinstance(result, property) and result.fset:
c.__qualname__ = "my_callable" # okay
```

## From a class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1492,9 +1492,7 @@ reveal_type(fields(Foo)) # revealed: tuple[Field[Any], ...]
But calling `asdict` on the class object is not allowed:

```py
# TODO: this should be a invalid-argument-type error, but we don't properly check the
# types (and more importantly, the `ClassVar` type qualifier) of protocol members yet.
asdict(Foo)
asdict(Foo) # error: [invalid-argument-type]
```

## `dataclasses.KW_ONLY`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,5 @@ xs = np.array([1, 2, 3])
reveal_type(xs) # revealed: ndarray[tuple[Any, ...], dtype[Any]]

xs = np.array([1.0, 2.0, 3.0], dtype=np.float64)
# TODO: should be `ndarray[tuple[Any, ...], dtype[float64]]`
reveal_type(xs) # revealed: ndarray[tuple[Any, ...], dtype[Unknown]]
reveal_type(xs) # revealed: ndarray[tuple[Any, ...], dtype[float64]]
```
232 changes: 147 additions & 85 deletions crates/ty_python_semantic/resources/mdtest/protocols.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ static_assert(is_disjoint_from(type[UsesMeta1], type[UsesMeta2]))

```py
from ty_extensions import is_disjoint_from, static_assert, TypeOf
from typing import final
from typing import final, Protocol, Literal

class C:
@property
Expand All @@ -567,6 +567,29 @@ static_assert(not is_disjoint_from(Whatever, TypeOf[C.prop]))
static_assert(not is_disjoint_from(TypeOf[C.prop], Whatever))
static_assert(is_disjoint_from(TypeOf[C.prop], D))
static_assert(is_disjoint_from(D, TypeOf[C.prop]))

@final
class E:
@property
def prop(self) -> int:
return 1

class F:
prop: Literal["a"]

class HasIntProp(Protocol):
@property
def prop(self) -> int: ...

class HasReadWriteIntProp(Protocol):
@property
def prop(self) -> int: ...
@prop.setter
def prop(self, value: int) -> None: ...

static_assert(not is_disjoint_from(HasIntProp, E))
static_assert(is_disjoint_from(HasIntProp, F))
static_assert(is_disjoint_from(HasReadWriteIntProp, E))
```

### `TypeGuard` and `TypeIs`
Expand Down
Loading