Skip to content

Commit 5f6f995

Browse files
committed
[ty] Add attribute assignment tests for unions
1 parent 7893cf9 commit 5f6f995

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

crates/ty_python_semantic/resources/mdtest/attributes.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,6 +1685,103 @@ date.year = 2025
16851685
date.tz = "UTC"
16861686
```
16871687

1688+
### Setting attributes on unions
1689+
1690+
Setting attributes on unions where all elements of the union have the attribute is acceptable
1691+
1692+
```py
1693+
from typing import Union
1694+
1695+
class A:
1696+
x: int
1697+
1698+
class B:
1699+
x: int
1700+
1701+
C = Union[A, B]
1702+
1703+
a: C = A()
1704+
a.x = 42
1705+
```
1706+
1707+
Setting attributes on unions where any element of the union does not have the attribute reports
1708+
possibly unbound
1709+
1710+
```py
1711+
from typing import Union, Sequence
1712+
1713+
class A:
1714+
pass
1715+
1716+
class B:
1717+
x: int
1718+
1719+
C = Union[A, B]
1720+
1721+
def _(a: C):
1722+
a.x = 42 # TODO: error: [possibly-unbound-attribute]
1723+
```
1724+
1725+
The same goes for
1726+
1727+
```py
1728+
from dataclasses import dataclass
1729+
from typing import Union, Sequence
1730+
from abc import ABC
1731+
1732+
class Base(ABC):
1733+
x: Sequence[bytes] = ()
1734+
1735+
class Derived(Base):
1736+
pass
1737+
1738+
class Other:
1739+
pass
1740+
1741+
D = Union[Derived, Other]
1742+
1743+
d: D = Other()
1744+
1745+
# TODO: error: [possibly-unbound-attribute]
1746+
# error: [unresolved-attribute]
1747+
d.x = None
1748+
```
1749+
1750+
Setting attributes on a generic where the upper bound is a union, and not all elements of the union
1751+
have the attribute, also reports possibly unbound:
1752+
1753+
```py
1754+
from typing import Union, TypeVar
1755+
1756+
class A:
1757+
pass
1758+
1759+
class B:
1760+
x: int
1761+
1762+
C = TypeVar("C", bound=Union[A, B])
1763+
1764+
def _(a: C):
1765+
a.x = 42 # error: [possibly-unbound-attribute]
1766+
```
1767+
1768+
### Assigning to a data descriptor attribute
1769+
1770+
This is invalid
1771+
1772+
```py
1773+
class A:
1774+
def __init__(self, x: int):
1775+
self.x = x
1776+
1777+
@property
1778+
def y(self) -> int:
1779+
return self.x
1780+
1781+
a = A(42)
1782+
a.y = 1 # error: [invalid-assignment] "Invalid assignment to data descriptor attribute `y` on type `A` with custom `__set__` method"
1783+
```
1784+
16881785
### `argparse.Namespace`
16891786

16901787
A standard library example of a class with a custom `__setattr__` method is `argparse.Namespace`:

0 commit comments

Comments
 (0)