Skip to content

Commit ea2d263

Browse files
committed
[ty] Add attribute assignment tests for unions
1 parent 3eada01 commit ea2d263

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
@@ -1628,6 +1628,103 @@ date.year = 2025
16281628
date.tz = "UTC"
16291629
```
16301630

1631+
### Setting attributes on unions
1632+
1633+
Setting attributes on unions where all elements of the union have the attribute is acceptable
1634+
1635+
```py
1636+
from typing import Union
1637+
1638+
class A:
1639+
x: int
1640+
1641+
class B:
1642+
x: int
1643+
1644+
C = Union[A, B]
1645+
1646+
a: C = A()
1647+
a.x = 42
1648+
```
1649+
1650+
Setting attributes on unions where any element of the union does not have the attribute reports
1651+
possibly unbound
1652+
1653+
```py
1654+
from typing import Union, Sequence
1655+
1656+
class A:
1657+
pass
1658+
1659+
class B:
1660+
x: int
1661+
1662+
C = Union[A, B]
1663+
1664+
def _(a: C):
1665+
a.x = 42 # TODO: error: [possibly-unbound-attribute]
1666+
```
1667+
1668+
The same goes for
1669+
1670+
```py
1671+
from dataclasses import dataclass
1672+
from typing import Union, Sequence
1673+
from abc import ABC
1674+
1675+
class Base(ABC):
1676+
x: Sequence[bytes] = ()
1677+
1678+
class Derived(Base):
1679+
pass
1680+
1681+
class Other:
1682+
pass
1683+
1684+
D = Union[Derived, Other]
1685+
1686+
d: D = Other()
1687+
1688+
# TODO: error: [possibly-unbound-attribute]
1689+
# error: [unresolved-attribute]
1690+
d.x = None
1691+
```
1692+
1693+
Setting attributes on a generic where the upper bound is a union, and not all elements of the union
1694+
have the attribute, also reports possibly unbound:
1695+
1696+
```py
1697+
from typing import Union, TypeVar
1698+
1699+
class A:
1700+
pass
1701+
1702+
class B:
1703+
x: int
1704+
1705+
C = TypeVar("C", bound=Union[A, B])
1706+
1707+
def _(a: C):
1708+
a.x = 42 # error: [possibly-unbound-attribute]
1709+
```
1710+
1711+
### Assigning to a data descriptor attribute
1712+
1713+
This is invalid
1714+
1715+
```py
1716+
class A:
1717+
def __init__(self, x: int):
1718+
self.x = x
1719+
1720+
@property
1721+
def y(self) -> int:
1722+
return self.x
1723+
1724+
a = A(42)
1725+
a.y = 1 # error: [invalid-assignment] "Invalid assignment to data descriptor attribute `y` on type `A` with custom `__set__` method"
1726+
```
1727+
16311728
### `argparse.Namespace`
16321729

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

0 commit comments

Comments
 (0)