-
-
Notifications
You must be signed in to change notification settings - Fork 58
Description
Is your feature request related to a problem? Please describe.
More and more, we allow referencing things that aren't symbols (in the sense that you cannot / do not manipulate these things directly within the language / with the language constructs), such as parameters and type parameters. Currently, we allow referencing those with the following syntax:
- parameters:
path.to.symbol(parameter_name)
- type parameters:
path.to.symbol[type_parameter_name]
While these characters play well with the language constructs (parentheses for parameters, like function calls, and square brackets for type parameters, like how they're bound to functions/classes), they do not always play well with Markdown (parentheses are OK-ish, square brackets are just not supported within links), and our way of parsing them in identifiers is a bit messy (they were an after-thought).
Describe the solution you'd like
I would like to design a better system for referencing parameters, type parameters, and many more types of symbol components, with a clear, obvious syntax, and (less obvious) shortcuts for brevity. This system would be properly integrated in Griffe, with good, tested parsing of identifiers, and the whole API would be aware of it.
Symbol components I'd like the system to handle:
- parameters
- type parameters
- returned values
- exceptions raised
- yielded values
- received values
- warnings emitted
The following ones could be interesting, though do not even have matching docstring sections yet:
- logs emitted
- messages written to stdout, stderr, and more file descriptors
- inputs read from stdin, and more file descriptors
- other I/O stuff? file read/writes? network read/writes? side-effects in general?
The syntax I imagine to reference each one of these symbol component types is:
Component type | Clear syntax | Shortcut |
---|---|---|
Parameters | SYMBOL{param:ID} |
SYMBOL <- ID , and SYMBOL(ID) for backward-compatibility |
Type parameters | SYMBOL{type_param:ID} |
SYMBOL @ ID , and SYMBOL[ID] for backward-compatibility |
Returned values | SYMBOL{return:ID} |
SYMBOL -> ID |
Exceptions raised | SYMBOL{exception:ID} |
SYMBOL ! ID |
Yielded values | SYMBOL{yield:ID} |
SYMBOL ~> ID |
Received values | SYMBOL{receive:ID} |
SYMBOL <~ ID |
Warnings emitted | SYMBOL{warning:ID} |
SYMBOL ? ID |
Logs emitted | SYMBOL{log:ID} |
SYMBOL % ID |
Standard output | SYMBOL{output:ID} |
SYMBOL >1 ID |
Standard error | SYMBOL{error:ID} |
SYMBOL >2 ID |
Standard input | SYMBOL{input:ID} |
SYMBOL <0 ID |
Generic file (descriptor) write | SYMBOL{write:ID} , etc. |
SYMBOL > ID , etc. |
Generic file (descriptor) read | SYMBOL{read:ID} , etc. |
SYMBOL < ID , etc. |
Other I/O stuff | SYMBOL{io:ID} |
SYMBOL + ID |
In the shorcut syntax, spaces around the "operator" would be irrelevant. SYMBOL
is the path to a symbol like module.Class.function
and ID
is an identifier for a particular instance of this component type, for example RuntimeError
for an instance of raised exception component.
Maybe standard output/error/input, generic file read/writes and I/O stuff in general could be merged in just read
and write
types, identifiers being file descriptors (0
, 1
, 2
, etc.), file paths (/abs/path
, rel/path
, etc.), environment variables (SOME_THING
, etc.), network interfaces, sockets or whatever (no ID idea yet), URLs (https://example.com/api/things
, /api/things
, etc.), or anything else, really. The point is just to document the inputs/reads and outputs/writes in a structured way.
Describe alternatives you've considered
/
Additional context
This will be needed to finish https://github.com/mkdocstrings/python/pull/221/files#r2296663095, as this PR brings the ability to reference type parameters, but the current supported syntax in Griffe (square brackets) cannot actually be used within Markdown links: [title][path.to.object[type_param_name]]
is incorrect syntax and won't be parsed as expected.
As to "why do we want to reference emitted logs, emitted warnings, raised exceptions, etc?", we want this because users of an API might want to disable warnings, disable logs, catch exceptions, redirect outputs, block network requests, or whatever, so each of these instances should be able to be referenced for better docs, better discoverability and better exploitation.