You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
automodule does not work with TYPE_CHECKING guarded code #13137
I want to document TypeAlias variables which are typically guarded by if TYPE_CHECKING or they might be defined in a stub file. The issue is that these members are not automatically added and indexed by automodule with members. If I move the section to outside the TYPE_CHECKING if-guard, then the member is being documented.
How to Reproduce
fromtypingimportTYPE_CHECKINGifTYPE_CHECKING:
fromtypingimportTypeAliasComplexType: TypeAlias=int|str"""This has some documentation"""defsome_func(input: ComplexType) ->None:
"""Some function that uses the type alias"""
This is to be expected: autodoc introspects the module by importing them. This is done in a regular python run, in which case typing.TYPE_CHECKING is False. Therefore, your TypeAlias definition is not executed and thus does not exist. Consequently autodoc cannot see it.
I've not tested it, but you could try to adding
import typing
typing.TYPE_CHECKING = True
to your Sphinx conf.py. That should make your alias visible, but be aware that it cancels the effect of the TYPE_CHECKING variable and the guards it has put in place not only for your code but also for all the downstream dependencies you import.
I've tested it out a bit and it breaks on sphinx eources even, so it seems a more sophisticated solution is needed. Is it possible to interogate typing for what members it sees in __dict__, etc. and try to union the results?
typing is just a module. It doesn’t see anything. autodoc uses ordinary runtime introspection. It has no means to get information from a block that’s excluded from running through an effective if False statement. The only way to get that info would be statically parsing the AST.
You could try to unhide your specific location only by something like
if TYPE_CHECKING or “sphinx.ext.autodoc” in sys.modules:
…
(Note: This is an idea, not tested because I don’t have a system to test at hand right now)
The or approach indeed worked. I guess one approach would be to patch in a context TYPE_CHECKING. Maybe this still fails when there are circular dependencies though 🤔.
I was thinking of typing.reveal_type or typing.get_type_hints, but I've tried those and that didn't help. I've also tried PEP695, but that does not have any support atm it seems. Static parsing would be nice and there are sphinx-autoapi and sphinx-autodoc2 that do the static documentation building, but these would not support well more complex objects like attrs that can dynamically alter the docstring. It would be great if these methods could be combined, having 2 passes complementing each other's documentations
That branch lacks the typing.TYPE_CHECKING change in conf.py, but it should be straight forward to add for a reproduction. The test item is in ``fmf_jinja.utils`
@AA-Turner I've seen the changelog entry for SPHINX_AUTODOC_RELOAD_MODULES. However, from that I've not been able to understand when it should be used and what it does exactly. There's no mentioning of it in the regular docs.
I also feel this is a bit inflexible because it's a global variable. Does it only affect the inspected module or may it propagate to modules that are imported in there as well? Even if it only affects the imports for autodoc, it affects all the documented modules. Extending the if TYPE_CHECKING: guard to if TYPE_CHECKING or [sphinx autodoc]: seems like the more flexible approach. how exactly or [sphinx autodoc] is spelled out can be discussed or “sphinx.ext.autodoc” in sys.modules was a quick guess.
Extending the if TYPE_CHECKING: guard to if TYPE_CHECKING or [sphinx autodoc]: seems like the more flexible approach.
This doesn't make any sense, you are not supposed to do invasive changes to the py source for autodoc to work. (Many previous contributors have addressed this -there are workarounds available that get the job done, with some digging in the knowledge base they can be found- and none of them saw the need to change the TYPE_CHECKING clause itself.)
TypeAlias itself isn't currently supported as far as I can tell (wait a minute! I checked one of my projects and I got it working since at least Sphinx 7.2, I published a description of the workaround that several others built on, it's somewhere in an open issue here in the Sphinx repo) what's more there are about 10 outstanding type alias bugs not counting the specific relation between TYPE_CHECKING and how the imports are done, see #9813 - that's to say that currently the prevalent workaround is to use strings instead of the bare type when using the alias.
If there's nothing weird in the typing check branch then there's no reason to use the check at all. The snippet in the opening comment is a case in point. Why isn't it just:
fromtypingimportTypeAliasComplexType: TypeAlias=int|str"""This has some documentation"""defsome_func(input: ComplexType) ->None:
"""Some function that uses the type alias"""
That would work fine with type checking, autodoc and regular execution.
I'd agree that if your code is complex enough to need a TYPE_CHECKING at all then it's complex enough that you need to be explicit about which branch you want autodoc to use by explicitly specify in your code. That's not an unreasonable imposition on the code author.
One issue is with __future__.annotations and guaranteeing the code is compatible with lower python versions, with the type-annotation only running on later python versions. The | operator is not acceptable with python<3.10 which is the case for RHEL9 and some other LTS distros that are currently being supported.
I'd agree that if your code is complex enough to need a TYPE_CHECKING at all then it's complex enough that you need to be explicit about which branch you want autodoc to use by explicitly specify in your code.
I strongly disagree!
Using TYPE_CHECKING is the standard mechanism to prevent cyclic imports.
Additionally linters like ruff will complain about unused imports and even automatically move typing imports into a TYPE_CHECKING block.
Typing imports under TYPE_CHECKING is the status quo in python and should supported accordingly.
Reacted by Leo Fang, Zac Hatfield-Dodds and Janosh Riebesell
Activity
timhoffm commentedon Nov 16, 2024
This is to be expected:
autodocintrospects the module by importing them. This is done in a regular python run, in which casetyping.TYPE_CHECKINGis False. Therefore, your TypeAlias definition is not executed and thus does not exist. Consequentlyautodoccannot see it.I've not tested it, but you could try to adding
to your Sphinx
conf.py. That should make your alias visible, but be aware that it cancels the effect of theTYPE_CHECKINGvariable and the guards it has put in place not only for your code but also for all the downstream dependencies you import.LecrisUT commentedon Nov 16, 2024
I've tested it out a bit and it breaks on sphinx eources even, so it seems a more sophisticated solution is needed. Is it possible to interogate
typingfor what members it sees in__dict__, etc. and try to union the results?timhoffm commentedon Nov 17, 2024
typingis just a module. It doesn’t see anything.autodocuses ordinary runtime introspection. It has no means to get information from a block that’s excluded from running through an effectiveif Falsestatement. The only way to get that info would be statically parsing the AST.You could try to unhide your specific location only by something like
(Note: This is an idea, not tested because I don’t have a system to test at hand right now)
LecrisUT commentedon Nov 17, 2024
The
orapproach indeed worked. I guess one approach would be to patch in a contextTYPE_CHECKING. Maybe this still fails when there are circular dependencies though 🤔.I was thinking of
typing.reveal_typeortyping.get_type_hints, but I've tried those and that didn't help. I've also tried PEP695, but that does not have any support atm it seems. Static parsing would be nice and there aresphinx-autoapiandsphinx-autodoc2that do the static documentation building, but these would not support well more complex objects likeattrsthat can dynamically alter thedocstring. It would be great if these methods could be combined, having 2 passes complementing each other's documentationsAA-Turner commentedon Nov 17, 2024
@LecrisUT does setting
SPHINX_AUTODOC_RELOAD_MODULES=1work? It's a new environment variable in Sphinx 7.2.A
LecrisUT commentedon Nov 17, 2024
@AA-Turner I supose you mean in reference to setting
typing.TYPE_CHECKING=True. That didn't seem to work:Installing
typing-extensionsdid not help, it simply delayed the error a bit further.AA-Turner commentedon Nov 17, 2024
I imagine this is as you use
typing_extensionsin TYPE_CHECKING blocks. What was the second error?A
LecrisUT commentedon Nov 17, 2024
Second attempt is trickier:
AA-Turner commentedon Nov 17, 2024
Can you provide a full reproducer? It shouldn't be reloading internal modules (such as
sphinx.builders.epub3), I think.A
LecrisUT commentedon Nov 17, 2024
The project I'm working on is at: https://github.com/LecrisUT/fmf-jinja/tree/fix/use-upstream-fmf
That branch lacks the
typing.TYPE_CHECKINGchange inconf.py, but it should be straight forward to add for a reproduction. The test item is in ``fmf_jinja.utils`timhoffm commentedon Nov 17, 2024
@AA-Turner I've seen the changelog entry for
SPHINX_AUTODOC_RELOAD_MODULES. However, from that I've not been able to understand when it should be used and what it does exactly. There's no mentioning of it in the regular docs.I also feel this is a bit inflexible because it's a global variable. Does it only affect the inspected module or may it propagate to modules that are imported in there as well? Even if it only affects the imports for autodoc, it affects all the documented modules. Extending the
if TYPE_CHECKING:guard toif TYPE_CHECKING or [sphinx autodoc]:seems like the more flexible approach. how exactlyor [sphinx autodoc]is spelled out can be discussedor “sphinx.ext.autodoc” in sys.moduleswas a quick guess.LecrisUT commentedon Nov 17, 2024
Preferably there would be a different approach. This method:
ruffwhich have a rule that checkif TYPE_CHECKINGguardelectric-coder commentedon Nov 18, 2024
@timhoffm
This doesn't make any sense, you are not supposed to do invasive changes to the py source for autodoc to work. (Many previous contributors have addressed this -there are workarounds available that get the job done, with some digging in the knowledge base they can be found- and none of them saw the need to change the
TYPE_CHECKINGclause itself.)TypeAliasitself isn't currently supported as far as I can tell (wait a minute! I checked one of my projects and I got it working since at least Sphinx 7.2, I published a description of the workaround that several others built on, it's somewhere in an open issue here in the Sphinx repo) what's more there are about 10 outstanding type alias bugs not counting the specific relation betweenTYPE_CHECKINGand how the imports are done, see #9813 - that's to say that currently the prevalent workaround is to use strings instead of the bare type when using the alias.By all accounts this bug report is a duplicate.
arthur-tacca commentedon Nov 23, 2024
If there's nothing weird in the typing check branch then there's no reason to use the check at all. The snippet in the opening comment is a case in point. Why isn't it just:
That would work fine with type checking, autodoc and regular execution.
I'd agree that if your code is complex enough to need a
TYPE_CHECKINGat all then it's complex enough that you need to be explicit about which branch you want autodoc to use by explicitly specify in your code. That's not an unreasonable imposition on the code author.(Just an interested autodoc user.)
LecrisUT commentedon Nov 23, 2024
One issue is with
__future__.annotationsand guaranteeing the code is compatible with lower python versions, with the type-annotation only running on later python versions. The|operator is not acceptable withpython<3.10which is the case for RHEL9 and some other LTS distros that are currently being supported.spacemanspiff2007 commentedon Nov 25, 2024
I strongly disagree!
Using
TYPE_CHECKINGis the standard mechanism to prevent cyclic imports.Additionally linters like
ruffwill complain about unused imports and even automatically move typing imports into aTYPE_CHECKINGblock.Typing imports under
TYPE_CHECKINGis the status quo in python and should supported accordingly.LecrisUT commentedon Dec 18, 2024
Randomly browsing the PEPs, PEP649 seems related to
TYPE_CHECKING. Not sure if this would offer some useful mechanism here