Skip to content

Commit be28e9c

Browse files
viccie30pawamoy
andauthored
feat: Support PEP 695 generics
Issue-342: #342 PR-348: #348 Co-authored-by: Timothée Mazzucotelli <[email protected]>
1 parent 27a385b commit be28e9c

36 files changed

+1759
-83
lines changed

docs/guide/users/checking.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ print(module.special_thing)
544544
545545
> Public object points to a different kind of object
546546
547-
Changing the kind (attribute, function, class, module) of a public object can *silently* break your users' code.
547+
Changing the kind (type alias, attribute, function, class, module) of a public object can *silently* break your users' code.
548548
549549
```python title="before"
550550
# your code

docs/guide/users/extending.md

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ If the source code is not available (the modules are built-in or compiled), Grif
102102

103103
Griffe then follows the [Visitor pattern](https://www.wikiwand.com/en/Visitor_pattern) to walk the tree and extract information. For ASTs, Griffe uses its [Visitor agent][griffe.Visitor] and for object trees, it uses its [Inspector agent][griffe.Inspector].
104104

105-
Sometimes during the walk through the tree (depth-first order), both the visitor and inspector agents will trigger events. These events can be hooked on by extensions to alter or enhance Griffe's behavior. Some hooks will be passed just the current node being visited, others will be passed both the node and an instance of an [Object][griffe.Object] subclass, such as a [Module][griffe.Module], a [Class][griffe.Class], a [Function][griffe.Function], or an [Attribute][griffe.Attribute]. Extensions will therefore be able to modify these instances.
105+
Sometimes during the walk through the tree (depth-first order), both the visitor and inspector agents will trigger events. These events can be hooked on by extensions to alter or enhance Griffe's behavior. Some hooks will be passed just the current node being visited, others will be passed both the node and an instance of an [Object][griffe.Object] subclass, such as a [Module][griffe.Module], a [Class][griffe.Class], a [Function][griffe.Function], an [Attribute][griffe.Attribute], or a [Type Alias][griffe.TypeAlias]. Extensions will therefore be able to modify these instances.
106106

107107
The following flow chart shows an example of an AST visit. The tree is simplified: actual trees have a lot more nodes like `if/elif/else` nodes, `try/except/else/finally` nodes, [and many more][ast.AST].
108108

@@ -200,8 +200,8 @@ There are two **load events**:
200200
There are 3 generic **analysis events**:
201201

202202
- [`on_node`][griffe.Extension.on_node]: The "on node" events are triggered when the agent (visitor or inspector) starts handling a node in the tree (AST or object tree).
203-
- [`on_instance`][griffe.Extension.on_instance]: The "on instance" events are triggered when the agent just created an instance of [Module][griffe.Module], [Class][griffe.Class], [Function][griffe.Function], or [Attribute][griffe.Attribute], and added it as a member of its parent. The "on instance" event is **not** triggered when an [Alias][griffe.Alias] is created.
204-
- [`on_members`][griffe.Extension.on_members]: The "on members" events are triggered when the agent just finished handling all the members of an object. Functions and attributes do not have members, so there are no "on members" events for these two kinds.
203+
- [`on_instance`][griffe.Extension.on_instance]: The "on instance" events are triggered when the agent just created an instance of [Module][griffe.Module], [Class][griffe.Class], [Function][griffe.Function], [Attribute][griffe.Attribute], or [Type Alias][griffe.TypeAlias], and added it as a member of its parent. The "on instance" event is **not** triggered when an [Alias][griffe.Alias] is created.
204+
- [`on_members`][griffe.Extension.on_members]: The "on members" events are triggered when the agent just finished handling all the members of an object. Functions, attributes and type aliases do not have members, so there are no "on members" events for these kinds.
205205

206206
There are also specific **analysis events** for each object kind:
207207

@@ -215,6 +215,8 @@ There are also specific **analysis events** for each object kind:
215215
- [`on_function_instance`][griffe.Extension.on_function_instance]
216216
- [`on_attribute_node`][griffe.Extension.on_attribute_node]
217217
- [`on_attribute_instance`][griffe.Extension.on_attribute_instance]
218+
- [`on_type_alias_node`][griffe.Extension.on_type_alias_node]
219+
- [`on_type_alias_instance`][griffe.Extension.on_type_alias_instance]
218220

219221
And a special event for aliases:
220222

@@ -315,7 +317,7 @@ class MyExtension(Extension):
315317

316318
The preferred method is to check the type of the received node rather than the agent.
317319

318-
Since hooks also receive instantiated modules, classes, functions and attributes, most of the time you will not need to use the `node` argument other than for checking its type and deciding what to do based on the result. And since we always add `**kwargs` to the hooks' signatures, you can drop any parameter you don't use from the signature:
320+
Since hooks also receive instantiated modules, classes, functions, attributes and type aliases, most of the time you will not need to use the `node` argument other than for checking its type and deciding what to do based on the result. And since we always add `**kwargs` to the hooks' signatures, you can drop any parameter you don't use from the signature:
319321

320322
```python
321323
import griffe
@@ -391,7 +393,7 @@ class MyExtension(griffe.Extension):
391393

392394
### Extra data
393395

394-
All Griffe objects (modules, classes, functions, attributes) can store additional (meta)data in their `extra` attribute. This attribute is a dictionary of dictionaries. The first layer is used as namespacing: each extension writes into its own namespace, or integrates with other projects by reading/writing in their namespaces, according to what they support and document.
396+
All Griffe objects (modules, classes, functions, attributes, type aliases) can store additional (meta)data in their `extra` attribute. This attribute is a dictionary of dictionaries. The first layer is used as namespacing: each extension writes into its own namespace, or integrates with other projects by reading/writing in their namespaces, according to what they support and document.
395397

396398
```python
397399
import griffe
@@ -563,10 +565,10 @@ See [how to use extensions](#using-extensions) to learn more about how to load a
563565
> - [`Continue`][ast.Continue]
564566
> - [`Del`][ast.Del]
565567
> - [`Delete`][ast.Delete]
568+
> - [`Dict`][ast.Dict]
566569
>
567570
> </td><td>
568571
>
569-
> - [`Dict`][ast.Dict]
570572
> - [`DictComp`][ast.DictComp]
571573
> - [`Div`][ast.Div]
572574
> - `Ellipsis`[^1]
@@ -595,11 +597,11 @@ See [how to use extensions](#using-extensions) to learn more about how to load a
595597
> - [`IsNot`][ast.IsNot]
596598
> - [`JoinedStr`][ast.JoinedStr]
597599
> - [`keyword`][ast.keyword]
600+
> - [`Lambda`][ast.Lambda]
601+
> - [`List`][ast.List]
598602
>
599603
> </td><td>
600604
>
601-
> - [`Lambda`][ast.Lambda]
602-
> - [`List`][ast.List]
603605
> - [`ListComp`][ast.ListComp]
604606
> - [`Load`][ast.Load]
605607
> - [`LShift`][ast.LShift]
@@ -627,11 +629,12 @@ See [how to use extensions](#using-extensions) to learn more about how to load a
627629
> - [`NotEq`][ast.NotEq]
628630
> - [`NotIn`][ast.NotIn]
629631
> - `Num`[^1]
632+
> - [`Or`][ast.Or]
633+
> - [`ParamSpec`][ast.ParamSpec]
634+
> - [`Pass`][ast.Pass]
630635
>
631636
> </td><td>
632637
>
633-
> - [`Or`][ast.Or]
634-
> - [`Pass`][ast.Pass]
635638
> - `pattern`[^3]
636639
> - [`Pow`][ast.Pow]
637640
> - `Print`[^4]
@@ -650,6 +653,9 @@ See [how to use extensions](#using-extensions) to learn more about how to load a
650653
> - `TryExcept`[^5]
651654
> - `TryFinally`[^6]
652655
> - [`Tuple`][ast.Tuple]
656+
> - [`TypeAlias`][ast.TypeAlias]
657+
> - [`TypeVar`][ast.TypeVar]
658+
> - [`TypeVarTuple`][ast.TypeVarTuple]
653659
> - [`UAdd`][ast.UAdd]
654660
> - [`UnaryOp`][ast.UnaryOp]
655661
> - [`USub`][ast.USub]

docs/guide/users/how-to/support-decorators.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class MyDecorator(griffe.Extension):
2828
"""An extension to suport my decorator."""
2929
```
3030

31-
Now we can declare the [`on_instance`][griffe.Extension.on_instance] hook, which receives any kind of Griffe object ([`Module`][griffe.Module], [`Class`][griffe.Class], [`Function`][griffe.Function], [`Attribute`][griffe.Attribute]), or we could use a kind-specific hook such as [`on_module_instance`][griffe.Extension.on_module_instance], [`on_class_instance`][griffe.Extension.on_class_instance], [`on_function_instance`][griffe.Extension.on_function_instance] and [`on_attribute_instance`][griffe.Extension.on_attribute_instance]. For example, if you know your decorator is only ever used on class declarations, it would make sense to use `on_class_instance`.
31+
Now we can declare the [`on_instance`][griffe.Extension.on_instance] hook, which receives any kind of Griffe object ([`Module`][griffe.Module], [`Class`][griffe.Class], [`Function`][griffe.Function], [`Attribute`][griffe.Attribute], [`TypeAlias`][griffe.TypeAlias]), or we could use a kind-specific hook such as [`on_module_instance`][griffe.Extension.on_module_instance], [`on_class_instance`][griffe.Extension.on_class_instance], [`on_function_instance`][griffe.Extension.on_function_instance], [`on_attribute_instance`][griffe.Extension.on_attribute_instance] and [`on_type_alias_instance`][griffe.Extension.on_type_alias_instance]. For example, if you know your decorator is only ever used on class declarations, it would make sense to use `on_class_instance`.
3232

3333
For the example, lets use the `on_function_instance` hook, which receives `Function` instances.
3434

docs/guide/users/navigating.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Griffe loads API data into data models. These models provide various attributes
66
- [`Class`][griffe.Class], representing Python classes;
77
- [`Function`][griffe.Function], representing Python functions and class methods;
88
- [`Attribute`][griffe.Attribute], representing object attributes that weren't identified as modules, classes or functions;
9+
- [`Type Alias`][griffe.TypeAlias], representing Python type aliases;
910
- [`Alias`][griffe.Alias], representing indirections such as imported objects or class members inherited from parent classes.
1011

1112
When [loading an object](loading.md), Griffe will give you back an instance of one of these models. A few examples:
@@ -84,7 +85,7 @@ To access an object's members, there are a few options:
8485

8586
In particular, Griffe extensions should always use `get_member` instead of the subscript syntax `[]`. The `get_member` method only looks into regular members, while the subscript syntax looks into inherited members too (for classes), which cannot be correctly computed until a package is fully loaded (which is generally not the case when an extension is running).
8687

87-
- In addition to this, models provide the [`attributes`][griffe.Object.attributes], [`functions`][griffe.Object.functions], [`classes`][griffe.Object.classes] or [`modules`][griffe.Object.modules] attributes, which return only members of the corresponding kind. These attributes are computed dynamically each time (they are Python properties).
88+
- In addition to this, models provide the [`attributes`][griffe.Object.attributes], [`functions`][griffe.Object.functions], [`classes`][griffe.Object.classes], [`type_aliases`][griffe.Object.type_aliases] or [`modules`][griffe.Object.modules] attributes, which return only members of the corresponding kind. These attributes are computed dynamically each time (they are Python properties).
8889

8990
The same way members are accessed, they can also be set:
9091

@@ -121,7 +122,7 @@ If a base class cannot be resolved during computation of inherited members, Grif
121122

122123
If you want to access all members at once (both declared and inherited), use the [`all_members`][griffe.Object.all_members] attribute. If you want to access only declared members, use the [`members`][griffe.Object] attribute.
123124

124-
Accessing the [`attributes`][griffe.Object.attributes], [`functions`][griffe.Object.functions], [`classes`][griffe.Object.classes] or [`modules`][griffe.Object.modules] attributes will trigger inheritance computation, so make sure to only access them once everything is loaded by Griffe. Don't try to access inherited members in extensions, while visiting or inspecting modules.
125+
Accessing the [`attributes`][griffe.Object.attributes], [`functions`][griffe.Object.functions], [`classes`][griffe.Object.classes], [`type_aliases`][griffe.Object.type_aliases] or [`modules`][griffe.Object.modules] attributes will trigger inheritance computation, so make sure to only access them once everything is loaded by Griffe. Don't try to access inherited members in extensions, while visiting or inspecting modules.
125126

126127
#### Limitations
127128

@@ -218,7 +219,7 @@ Aliases chains are never partially resolved: either they are resolved down to th
218219

219220
## Object kind
220221

221-
The kind of an object (module, class, function, attribute or alias) can be obtained in several ways.
222+
The kind of an object (module, class, function, attribute, type alias or alias) can be obtained in several ways.
222223

223224
- With the [`kind`][griffe.Object.kind] attribute and the [`Kind`][griffe.Kind] enumeration: `obj.kind is Kind.MODULE`.
224225

@@ -230,7 +231,7 @@ The kind of an object (module, class, function, attribute or alias) can be obtai
230231

231232
When given a set of kinds, the method returns true if the object is of one of the given kinds.
232233

233-
- With the [`is_module`][griffe.Object.is_module], [`is_class`][griffe.Object.is_class], [`is_function`][griffe.Object.is_function], [`is_attribute`][griffe.Object.is_attribute], and [`is_alias`][griffe.Object.is_alias] attributes.
234+
- With the [`is_module`][griffe.Object.is_module], [`is_class`][griffe.Object.is_class], [`is_function`][griffe.Object.is_function], [`is_attribute`][griffe.Object.is_attribute], [`is_type_alias`][griffe.Object.is_type_alias], and [`is_alias`][griffe.Object.is_alias] attributes.
234235

235236
Additionally, it is possible to check if an object is a sub-kind of module, with the following attributes:
236237

@@ -351,7 +352,7 @@ After a package is loaded, it is still possible to change the style used for spe
351352

352353
Do note, however, that the `parsed` attribute is cached, and won't be reset when overriding the `parser` or `parser_options` values.
353354

354-
Docstrings have a [`parent`][griffe.Docstring.parent] field too, that is a reference to their respective module, class, function or attribute.
355+
Docstrings have a [`parent`][griffe.Docstring.parent] field too, that is a reference to their respective module, class, function, attribute or type alias.
355356

356357
## Model-specific fields
357358

@@ -370,13 +371,15 @@ Models have most fields in common, but also have specific fields.
370371
- [`overloads`][griffe.Class.overloads]: A dictionary to store overloads for class-level methods.
371372
- [`decorators`][griffe.Class.decorators]: The [decorators][griffe.Decorator] applied to the class.
372373
- [`parameters`][griffe.Class.parameters]: The [parameters][griffe.Parameters] of the class' `__init__` method, if any.
374+
- [`type_parameters`][griffe.Class.type_parameters]: The [type parameters][griffe.TypeParameters] of the class.
373375

374376
### Functions
375377

376378
- [`decorators`][griffe.Function.decorators]: The [decorators][griffe.Decorator] applied to the function.
377379
- [`overloads`][griffe.Function.overloads]: The overloaded signatures of the function.
378380
- [`parameters`][griffe.Function.parameters]: The [parameters][griffe.Parameters] of the function.
379381
- [`returns`][griffe.Function.returns]: The type annotation of the returned value, in the form of an [expression][griffe.Expr]. The `annotation` field can also be used, for compatibility with attributes.
382+
- [`type_parameters`][griffe.Function.type_parameters]: The [type parameters][griffe.TypeParameters] of the function.
380383

381384
### Attributes
382385

@@ -385,6 +388,10 @@ Models have most fields in common, but also have specific fields.
385388
- [`deleter`][griffe.Attribute.deleter]: The property deleter.
386389
- [`setter`][griffe.Attribute.setter]: The property setter.
387390

391+
### Type aliases
392+
- [`value`][griffe.TypeAlias.value]: The value of the type alias, in the form of an [expression][griffe.Expr].
393+
- [`type_parameters`][griffe.TypeAlias.type_parameters]: The [type parameters][griffe.TypeParameters] of the type alias.
394+
388395
### Alias
389396

390397
- [`alias_lineno`][griffe.Alias.alias_lineno]: The alias line number (where the object is imported).

docs/guide/users/recommendations/docstrings.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ Here are explanations on what docstrings are, and a few recommendations on how t
44

55
## Definition
66

7-
A docstring is a line or block of text describing objects such as modules, classes, functions and attributes. They are written below the object signature or assignment, or appear as first expression in a module:
7+
A docstring is a line or block of text describing objects such as modules, classes, functions, attributes and type aliases. They are written below the object signature or assignment, or appear as first expression in a module:
88

99
```python title="module.py"
1010
"""This is the module docstring."""
1111

12+
type X = dict[str, int]
13+
"""This is a type alias docstring."""
14+
1215
a = 0
1316
"""This is an attribute docstring."""
1417

@@ -51,7 +54,7 @@ Whatever markup you choose, try to stay consistent within your code base.
5154

5255
## Styles
5356

54-
Docstrings can be written for modules, classes, functions, and attributes. But there are other aspects of a Python API that need to be documented, such as function parameters, returned values, and raised exceptions, to name a few. We could document everything in natural language, but that would make it hard for downstream tools such as documentation generators to extract information in a structured way, to allow dedicated rendering such as tables for parameters.
57+
Docstrings can be written for modules, classes, functions, attributes, and type aliases. But there are other aspects of a Python API that need to be documented, such as function parameters, returned values, and raised exceptions, to name a few. We could document everything in natural language, but that would make it hard for downstream tools such as documentation generators to extract information in a structured way, to allow dedicated rendering such as tables for parameters.
5558

5659
To compensate for the lack of structure in natural languages, docstring "styles" emerged. A docstring style is a micro-format for docstrings, allowing to structure the information by following a specific format. With the most popular Google and Numpydoc styles, information in docstrings is decomposed into **sections** of different kinds, for example "parameter" sections or "return" sections. Some kinds of section then support documenting multiple items, or support a single block of markup. For example, we can document multiple parameters in "parameter" sections, but a "note" section is only composed of a text block.
5760

@@ -136,7 +139,7 @@ When documenting objects acting as namespaces (modules, classes, enumerations),
136139

137140
## Modules
138141

139-
Module docstrings should briefly explain what the module contains, and for what purposes these objects can be used. If the documentation generator you chose does not support generating member summaries automatically, you might want to add docstrings sections for attributes, functions, classes and submodules.
142+
Module docstrings should briefly explain what the module contains, and for what purposes these objects can be used. If the documentation generator you chose does not support generating member summaries automatically, you might want to add docstrings sections for attributes, functions, classes, type aliases and submodules.
140143

141144
```python title="package/__init__.py"
142145
"""A generic package to demonstrate docstrings.
@@ -305,6 +308,19 @@ class GhostTown:
305308
"""The town's size."""
306309
```
307310

311+
## Type aliases
312+
313+
Type alias docstrings are written below their assignment. As usual, they should have a short summary, and an optional, longer body.
314+
315+
```python
316+
type Callback = typing.Callable[[int, str], typing.Any]
317+
"""Callback type for Frobnicators.
318+
319+
The first argument is the number of rounds to run, the second argument
320+
is the name of the widget being frobnicated.
321+
"""
322+
```
323+
308324
## Exceptions, warnings
309325

310326
Callables that raise exceptions or emit warnings can document each of these exceptions and warnings. Documenting them informs your users that they could or should catch the raised exceptions, or that they could filter or configure warnings differently. The description next to each exception or warning should explain how or when they are raised or emitted.

0 commit comments

Comments
 (0)