Skip to content

Commit

Permalink
Add support to use the pipe (|) syntax for typing.Union. (#285)
Browse files Browse the repository at this point in the history
Fixes #280.
  • Loading branch information
icemac authored Feb 15, 2024
1 parent ca76bcb commit 4ed7ad3
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

- Add preliminary support for Python 3.13 as of 3.13a3.

- Add support to use the pipe (``|``) syntax for ``typing.Union``.
(`#280 <https://github.com/zopefoundation/zope.interface/issues/280>`_)


6.1 (2023-10-05)
================

Expand Down
9 changes: 9 additions & 0 deletions src/zope/interface/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from types import MethodType
from types import FunctionType
import weakref
from typing import Union

from zope.interface._compat import _use_c_impl
from zope.interface.exceptions import Invalid
Expand Down Expand Up @@ -941,6 +942,14 @@ def _call_conform(self, conform):
def __reduce__(self):
return self.__name__

def __or__(self, other):
"""Allow type hinting syntax: Interface | None."""
return Union[self, other]

def __ror__(self, other):
"""Allow type hinting syntax: None | Interface."""
return Union[other, self]

Interface = InterfaceClass("Interface", __module__='zope.interface')
# Interface is the only member of its own SRO.
Interface._calculate_sro = lambda: (Interface,)
Expand Down
34 changes: 34 additions & 0 deletions src/zope/interface/tests/test_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -2636,3 +2636,37 @@ def __enter__(self):
def __exit__(self, exc_type, exc_val, exc_tb):
for key, value in self.to_restore.items():
setattr(self.module, key, value)

class TestTypeAnnotations(unittest.TestCase):
"""Test using Interfaces in type annotations."""

def test___or__(self):
from zope.interface import Interface
from typing import Optional, Union
class I1(Interface):
pass
class I2(Interface):
pass

class B:
a: I1|None
b: I1|I2

self.assertEqual(
B.__annotations__, {'a': Optional[I1], 'b': Union[I1, I2]})

def test___ror__(self):
from zope.interface import Interface
from typing import Optional, Union
class I1(Interface):
pass

class A:
pass

class B:
a: None|I1
b: A|I1

self.assertEqual(
B.__annotations__, {'a': Optional[I1], 'b': Union[A, I1]})

0 comments on commit 4ed7ad3

Please sign in to comment.