-
-
Notifications
You must be signed in to change notification settings - Fork 34.5k
gh-141388: Improve docs/tests for non-function callables as annotate functions #142327
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
Changes from 12 commits
91036ac
414251b
fd6125d
c008676
1ab0139
e177621
fe84920
d42d8ad
45cb956
eef70c4
44f2a45
095cfb5
d9bf2e8
943181c
a1daa6e
028e0f9
9cefbaa
8ec86ee
a70a647
1737973
cbc8466
3bfd2e0
5440128
46ef8b1
50828b7
8f4df8d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -510,6 +510,72 @@ annotations from the class and puts them in a separate attribute: | |
| return typ | ||
|
|
||
|
|
||
|
|
||
| Creating a custom callable annotate function | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
|
||
| Custom :term:`annotate functions <annotate function>` may be literal functions like those | ||
| automatically generated for functions, classes, and modules. Or, they may wish to utilise | ||
| the encapsulation provided by classes, in which case any :term:`callable` can be used as | ||
| an :term:`annotate function`. | ||
|
|
||
| However, :term:`methods <method>`, class instances that implement | ||
| :meth:`object.__call__`, and most other callables, do not provide the same attributes as | ||
| true functions, which are needed for the :attr:`~Format.VALUE_WITH_FAKE_GLOBALS` | ||
| machinery to work. :func:`call_annotate_function` and other :mod:`annotationlib` | ||
| functions will attempt to infer those attributes where possible, but some of them must | ||
| always be present for :attr:`~Format.VALUE_WITH_FAKE_GLOBALS` to work. | ||
|
|
||
| Below is an example of a callable class that provides the necessary attributes to be | ||
| used with all formats, and takes advantage of class encapsulation: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| class Annotate: | ||
|
dr-carlos marked this conversation as resolved.
Outdated
dr-carlos marked this conversation as resolved.
Outdated
|
||
| called_formats = [] | ||
|
|
||
| def __call__(self, format=None, *, _self=None): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this the signature we want to force?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, we're not really forcing it, but you're right that it is a somewhat awkward suggestion. I'll have a think about alternatives. We could also move the logic in
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Honestly, at this point, I prefer that we force users to use functions and not arbitrary callable. This additional cost doesn't seem right, it complicates the docs, and makes the code more complex as well. |
||
| # When called with fake globals, `_self` will be the | ||
| # actual self value, and `self` will be the format. | ||
| if _self is not None: | ||
| self, format = _self, self | ||
|
|
||
| self.called_formats.append(format) | ||
| if format <= 2: # VALUE or VALUE_WITH_FAKE_GLOBALS | ||
| return {"x": MyType} | ||
| raise NotImplementedError | ||
|
|
||
| @property | ||
| def __defaults__(self): | ||
| return (None,) | ||
|
|
||
| @property | ||
| def __kwdefaults__(self): | ||
| return {"_self": self} | ||
|
|
||
| @property | ||
| def __code__(self): | ||
| return self.__call__.__code__ | ||
|
dr-carlos marked this conversation as resolved.
Outdated
|
||
|
|
||
| This can then be called with: | ||
|
|
||
| .. code-block:: python | ||
|
dr-carlos marked this conversation as resolved.
Outdated
|
||
|
|
||
| >>> from annotationlib import call_annotate_function, Format | ||
| >>> call_annotate_function(Annotate(), format=Format.STRING) | ||
| {'x': 'MyType'} | ||
|
|
||
| Or used as the annotate function for an object: | ||
|
|
||
| .. code-block:: python | ||
|
dr-carlos marked this conversation as resolved.
Outdated
|
||
|
|
||
| >>> from annotationlib import get_annotations, Format | ||
| >>> class C: | ||
| ... pass | ||
| >>> C.__annotate__ = Annotate() | ||
| >>> get_annotations(Annotate(), format=Format.STRING) | ||
| {'x': 'MyType'} | ||
|
|
||
|
dr-carlos marked this conversation as resolved.
|
||
| Limitations of the ``STRING`` format | ||
| ------------------------------------ | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Improve support, error messages, and documentation for non-function callables as | ||
| :term:`annotate functions <annotate function>`. |
Uh oh!
There was an error while loading. Please reload this page.