-
Notifications
You must be signed in to change notification settings - Fork 28
Enable py3.14 and deprecate some alias functionality #225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
nstarman
wants to merge
6
commits into
beartype:master
Choose a base branch
from
nstarman:mnt/py314
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
b5a1472
test: py3.14
nstarman 0b8b5f7
feat: deprecate union aliasing
nstarman 0444c5b
refactor: some simplifications
nstarman 9e9178c
feat: union alias in python 3.14
nstarman e606ed2
feat: de-deprecate (de)activate_union_aliases
nstarman 0d2ed52
Apply suggestions from code review
nstarman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,108 +1,157 @@ | ||
| (union-aliases)= | ||
| # Union Aliases | ||
|
|
||
| To understand what union aliases are and what problem they solve, consider the | ||
| following example. | ||
| Suppose that we would want to implement a special addition function, and we would | ||
| want to implement it for all NumPy scalar types: | ||
|
|
||
| ```python | ||
| import numpy as np | ||
|
|
||
| from typing import Union | ||
| from plum import dispatch | ||
|
|
||
|
|
||
| scalar_types = tuple(np.sctypeDict.values()) # All NumPy scalar types | ||
| Scalar = Union[scalar_types] # Union of all NumPy scalar types | ||
|
|
||
|
|
||
| @dispatch | ||
| def add(x: Scalar, y: Scalar): | ||
| return x + y | ||
| ``` | ||
|
|
||
| This looks all fine, until you look at the documentation. | ||
| In particular, `help(add)` prints | ||
|
|
||
|
|
||
| ``` | ||
| Help on Function in module __main__: | ||
|
|
||
| add(x: Union[numpy.int8, numpy.int16, numpy.int32, numpy.int64, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64, numpy.float16, numpy.float32, numpy.float64, numpy.float128, numpy.complex64, numpy.complex128, numpy.complex256, bool, object, bytes, str, numpy.void], y: Union[numpy.int8, numpy.int16, numpy.int32, numpy.int64, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64, numpy.float16, numpy.float32, numpy.float64, numpy.float128, numpy.complex64, numpy.complex128, numpy.complex256, bool, object, bytes, str, numpy.void]) | ||
| ``` | ||
|
|
||
| While the documentation is accurate, it is not at all helpful to expand the union in | ||
| its many elements, because it obscures the key message: `add(x, y)` is implemented | ||
| for all _scalars_. | ||
| A better option would be to print `add(x: Scalar, y: Scalar)`. | ||
| This is precisely what union aliases do: | ||
| by aliasing a union, you change the way it is displayed. | ||
| Union aliases must be activated explicitly, because the feature | ||
| monkeypatches `Union.__str__` and `Union.__repr__`. | ||
|
|
||
| ```python | ||
| >>> from plum import activate_union_aliases, set_union_alias | ||
|
|
||
| >>> activate_union_aliases() | ||
|
|
||
| >>> set_union_alias(Scalar, alias="Scalar") | ||
| typing.Union[Scalar] | ||
| ``` | ||
|
|
||
| After this, `help(add)` now prints the following: | ||
|
|
||
| % skip: next "Example" | ||
|
|
||
| ```python | ||
| Help on Function in module __main__: | ||
|
|
||
| add(x: Union[Scalar], y: Union[Scalar]) | ||
| ``` | ||
|
|
||
| Hurray! | ||
| Note that the documentation prints `Union[Scalar]` rather than just `Scalar`. | ||
| This is intentional: it is to prevent breaking code that depends on how unions | ||
| print. | ||
| For example, printing just `Scalar` would omit the type parameter(s). | ||
|
|
||
| Let's see with a few more examples how this works: | ||
|
|
||
| ```python | ||
| >>> Scalar | ||
| typing.Union[Scalar] | ||
|
|
||
| >>> Union[tuple(scalar_types)] | ||
| typing.Union[Scalar] | ||
|
|
||
| >>> Union[tuple(scalar_types) + (tuple,)] # Scalar or tuple | ||
| typing.Union[Scalar, tuple] | ||
|
|
||
| >>> Union[tuple(scalar_types) + (tuple, list)] # Scalar or tuple or list | ||
| typing.Union[Scalar, tuple, list] | ||
| ``` | ||
|
|
||
| If we don't include all of `scalar_types`, we won't see `Scalar`, as desired: | ||
|
|
||
| % invisible-code-block: python | ||
| % | ||
| % import sys | ||
|
|
||
| % skip: next "Result depends on NumPy version." | ||
|
|
||
| ```python | ||
| >>> Union[tuple(scalar_types[:-1])] | ||
| typing.Union[numpy.int8, numpy.int16, numpy.int32, numpy.longlong, numpy.int64, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64, numpy.ulonglong, numpy.float16, numpy.float32, numpy.float64, numpy.longdouble, numpy.complex64, numpy.complex128, numpy.clongdouble, numpy.str_, numpy.bytes_, numpy.void, numpy.bool] | ||
| ``` | ||
|
|
||
| You can deactivate union aliases with `deactivate_union_aliases`: | ||
|
|
||
| ```python | ||
| >>> from plum import deactivate_union_aliases | ||
|
|
||
| >>> deactivate_union_aliases() | ||
|
|
||
| % skip: next "Result depends on NumPy version." | ||
| >>> Scalar | ||
| typing.Union[numpy.int8, numpy.int16, numpy.int32, numpy.longlong, numpy.int64, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64, numpy.ulonglong, numpy.float16, numpy.float32, numpy.float64, numpy.longdouble, numpy.complex64, numpy.complex128, numpy.clongdouble, numpy.str_, numpy.bytes_, numpy.void, numpy.bool, numpy.object_] | ||
| ``` | ||
| (union-aliases)= | ||
| # Union Aliases | ||
|
|
||
| To understand what union aliases are and what problem they solve, consider the | ||
| following example. | ||
| Suppose that we would want to implement a special addition function, and we would | ||
| want to implement it for all NumPy scalar types: | ||
|
|
||
| ```python | ||
| import numpy as np | ||
|
|
||
| from typing import Union | ||
| from plum import dispatch | ||
|
|
||
|
|
||
| scalar_types = tuple(np.sctypeDict.values()) # All NumPy scalar types | ||
| Scalar = Union[scalar_types] # Union of all NumPy scalar types | ||
|
|
||
|
|
||
| @dispatch | ||
| def add(x: Scalar, y: Scalar): | ||
| return x + y | ||
| ``` | ||
|
|
||
| This looks all fine, until you look at the documentation. | ||
| In particular, `help(add)` prints | ||
|
|
||
|
|
||
| ``` | ||
| Help on Function in module __main__: | ||
|
|
||
| add(x: Union[numpy.int8, numpy.int16, numpy.int32, numpy.int64, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64, numpy.float16, numpy.float32, numpy.float64, numpy.float128, numpy.complex64, numpy.complex128, numpy.complex256, bool, object, bytes, str, numpy.void], y: Union[numpy.int8, numpy.int16, numpy.int32, numpy.int64, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64, numpy.float16, numpy.float32, numpy.float64, numpy.float128, numpy.complex64, numpy.complex128, numpy.complex256, bool, object, bytes, str, numpy.void]) | ||
| ``` | ||
|
|
||
| While the documentation is accurate, it is not at all helpful to expand the | ||
| union in its many elements, because it obscures the key message: `add(x, y)` is | ||
| implemented for all _scalars_. A better option would be to print `add(x: | ||
| Scalar, y: Scalar)`. This is precisely what union aliases do: by aliasing a | ||
| union, you change the way it is displayed. On Python 3.13 and earlier, union | ||
| aliases work by monkeypatching `typing.Union.__str__` and | ||
| `typing.Union.__repr__`, and therefore must be activated explicitly. On Python | ||
| 3.14 and later, `typing.Union`'s representation can no longer be monkeypatched; | ||
| union aliases instead only affect how Plum formats unions in its own printed | ||
| output. | ||
|
|
||
| % invisible-code-block: python | ||
| % | ||
| % import sys | ||
|
|
||
| % skip: start if(sys.version_info < (3, 14), reason="Union repr changed in Python 3.14+") | ||
|
|
||
| ```python | ||
| >>> from plum import set_union_alias | ||
|
|
||
| >>> set_union_alias(Scalar, alias="Scalar") | ||
| numpy.bool | numpy.float16 | ... | ||
| ``` | ||
|
|
||
| % skip: end | ||
|
|
||
| % skip: start if(sys.version_info >= (3, 14), reason="Representation of unions changed in Python 3.14.") | ||
|
|
||
| ```python | ||
| >>> from plum import activate_union_aliases, set_union_alias | ||
|
|
||
| >>> activate_union_aliases() | ||
|
|
||
| >>> set_union_alias(Scalar, alias="Scalar") | ||
| typing.Union[Scalar] | ||
| ``` | ||
|
|
||
| % skip: end | ||
|
|
||
| After this, `help(add)` now prints the following: | ||
|
|
||
| % skip: next "Example" | ||
|
|
||
| ```python | ||
| Help on Function in module __main__: | ||
|
|
||
| add(x: Union[Scalar], y: Union[Scalar]) | ||
| ``` | ||
|
|
||
| Hurray! | ||
| Note that the documentation prints `Union[Scalar]` rather than just `Scalar`. | ||
| This is intentional: it is to prevent breaking code that depends on how unions | ||
| print. | ||
| For example, printing just `Scalar` would omit the type parameter(s). | ||
|
|
||
| Let's see with a few more examples how this works: | ||
|
|
||
| % invisible-code-block: python | ||
| % | ||
| % import sys | ||
|
|
||
| % skip: start if(sys.version_info < (3, 14), reason="Representation of unions changed in Python 3.14.") | ||
|
|
||
| ```python | ||
| >>> Scalar | ||
| numpy.bool | numpy.float16 | ... | ||
|
|
||
| >>> Union[tuple(scalar_types)] | ||
| numpy.bool | numpy.float16 | ... | ||
|
|
||
| >>> Union[tuple(scalar_types) + (tuple,)] # Scalar or tuple | ||
| numpy.bool | numpy.float16 | ... | tuple | ||
|
|
||
| >>> Union[tuple(scalar_types) + (tuple, list)] # Scalar or tuple or list | ||
| numpy.bool | numpy.float16 | ... | tuple | list | ||
| ``` | ||
|
|
||
| % skip: end | ||
|
|
||
| % skip: start if(sys.version_info >= (3, 14), reason="Representation of unions changed in Python 3.14.") | ||
|
|
||
| ```python | ||
| >>> Scalar | ||
| typing.Union[Scalar] | ||
|
|
||
| >>> Union[tuple(scalar_types)] | ||
| typing.Union[Scalar] | ||
|
|
||
| >>> Union[tuple(scalar_types) + (tuple,)] # Scalar or tuple | ||
| typing.Union[Scalar, tuple] | ||
|
|
||
| >>> Union[tuple(scalar_types) + (tuple, list)] # Scalar or tuple or list | ||
| typing.Union[Scalar, tuple, list] | ||
| ``` | ||
|
|
||
| % skip: end | ||
|
|
||
| If we don't include all of `scalar_types`, we won't see `Scalar`, as desired: | ||
|
|
||
| % invisible-code-block: python | ||
| % | ||
| % import sys | ||
|
|
||
| % skip: next "Result depends on NumPy version." | ||
|
|
||
| ```python | ||
| >>> Union[tuple(scalar_types[:-1])] | ||
| typing.Union[numpy.int8, numpy.int16, numpy.int32, numpy.longlong, numpy.int64, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64, numpy.ulonglong, numpy.float16, numpy.float32, numpy.float64, numpy.longdouble, numpy.complex64, numpy.complex128, numpy.clongdouble, numpy.str_, numpy.bytes_, numpy.void, numpy.bool] | ||
| ``` | ||
|
|
||
| You can deactivate union aliases with `deactivate_union_aliases`: | ||
|
|
||
| ```python | ||
| >>> import warnings | ||
|
|
||
| >>> from plum import deactivate_union_aliases | ||
|
|
||
| >>> deactivate_union_aliases() | ||
|
|
||
| % skip: next "Result depends on NumPy version." | ||
| >>> Scalar | ||
| typing.Union[numpy.int8, numpy.int16, numpy.int32, numpy.longlong, numpy.int64, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64, numpy.ulonglong, numpy.float16, numpy.float32, numpy.float64, numpy.longdouble, numpy.complex64, numpy.complex128, numpy.clongdouble, numpy.str_, numpy.bytes_, numpy.void, numpy.bool, numpy.object_] | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.