@@ -74,7 +74,7 @@ reveal_type(c_instance.declared_and_bound) # revealed: bool
7474
7575#### Variable declared in class body and possibly bound in ` __init__ `
7676
77- The same rule applies even if the variable is * declared * (not bound!) in the class body: it is still
77+ The same rule applies even if the variable is _ declared _ (not bound!) in the class body: it is still
7878a pure instance variable.
7979
8080``` py
@@ -780,7 +780,7 @@ reveal_type(c_instance.variable_with_class_default1) # revealed: str
780780#### Descriptor attributes as class variables
781781
782782Whether they are explicitly qualified as ` ClassVar ` , or just have a class level default, we treat
783- descriptor attributes as class variables. This test mainly makes sure that we do * not * treat them as
783+ descriptor attributes as class variables. This test mainly makes sure that we do _ not _ treat them as
784784instance variables. This would lead to a different outcome, since the ` __get__ ` method would not be
785785called (the descriptor protocol is not invoked for instance variables).
786786
@@ -897,7 +897,7 @@ def _(flag: bool):
897897 reveal_type(C3.attr2) # revealed: Literal["metaclass value", "class value"]
898898```
899899
900- If the * metaclass * attribute is only partially defined, we emit a ` possibly-unbound-attribute `
900+ If the _ metaclass _ attribute is only partially defined, we emit a ` possibly-unbound-attribute `
901901diagnostic:
902902
903903``` py
@@ -1400,7 +1400,7 @@ def _(a_and_b: Intersection[A, B]):
14001400
14011401The union of the set of types that ` Any ` could materialise to is equivalent to ` object ` . It follows
14021402from this that attribute access on ` Any ` resolves to ` Any ` if the attribute does not exist on
1403- ` object ` -- but if the attribute * does * exist on ` object ` , the type of the attribute is
1403+ ` object ` -- but if the attribute _ does _ exist on ` object ` , the type of the attribute is
14041404` <type as it exists on object> & Any ` .
14051405
14061406``` py
@@ -1628,6 +1628,70 @@ date.year = 2025
16281628date.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
1655+
1656+ class A :
1657+ pass
1658+
1659+ class B :
1660+ x: int
1661+
1662+ C = Union[A, B]
1663+
1664+ a: C = A()
1665+
1666+ # instead of unresolved-attribute, this should report possibly-unbound-attribute
1667+ # TODO : error: [possibly-unbound-attribute]
1668+ # error: [unresolved-attribute]
1669+ a.x = 42
1670+
1671+ a: C = B()
1672+
1673+ # TODO : error: [possibly-unbound-attribute]
1674+ a.x = 42
1675+ ```
1676+
1677+ Setting attributes on a generic where the upper bound is a union, and not all elements of the union
1678+ have the attribute, also reports possibly unbound:
1679+
1680+ ``` py
1681+ from typing import Union, TypeVar
1682+
1683+ class A :
1684+ pass
1685+
1686+ class B :
1687+ x: int
1688+
1689+ C = TypeVar(" C" , bound = Union[A, B])
1690+
1691+ def _ (a : C):
1692+ a.x = 42 # error: [possibly-unbound-attribute]
1693+ ```
1694+
16311695### ` argparse.Namespace `
16321696
16331697A standard library example of a class with a custom ` __setattr__ ` method is ` argparse.Namespace ` :
@@ -1732,11 +1796,13 @@ for mod.global_symbol in IntIterable():
17321796` outer/__init__.py ` :
17331797
17341798``` py
1799+
17351800```
17361801
17371802` outer/nested/__init__.py ` :
17381803
17391804``` py
1805+
17401806```
17411807
17421808` outer/nested/inner.py ` :
@@ -2111,7 +2177,7 @@ reveal_type(Foo.__members__) # revealed: @Todo(Attribute access on enum classes
21112177
21122178## References
21132179
2114- Some of the tests in the * Class and instance variables * section draw inspiration from
2180+ Some of the tests in the _ Class and instance variables _ section draw inspiration from
21152181[ pyright's documentation] on this topic.
21162182
21172183[ descriptor protocol tests ] : descriptor_protocol.md
0 commit comments