On Wed, 2025-11-19 at 09:49 -0800, Clark Boylan wrote:
On Wed, Nov 19, 2025, at 8:59 AM, Stephen Finucane wrote:
o/
I've been slowly adding type hints to oslo and SDK projects of late as time has allowed. One thing that I've noticed is that strict adherence to hacking's H301 (Do not import more than one module per line) and H303 (Do not use wildcard * import) rules results in both stupidly long groups of imports and overly verbose and difficult to read signatures [1]. I've therefore proposed a change to these rules that exempt some typing-related libraries - collections.abc, types, and typing - from these rules. This is proposed at [2]. As noted there, exceptions already exist for the sqlalchemy and projects' i18n modules for the same reason so this should be nothing new. I am instead bringing this up so projects currently using e.g. 'import typing as ty' imports can pivot to something sooner once this is merged.
Isn't the concern with H303 that using wildcard imports makes you susceptible to unexpected name collisions either due to updates in your imports or changes to your local code? The example in [2] actually points at an extremely common case of this: `_`. A single underscore is commonly used as a throwaway result in code like:
result, _ = some_fun()
Which if you expect `_()` to perform gettext actions could suddenly become problematic. Type checking probably does alleviate some of this as it may be able to detect where `_` is no longer a function. Similarly if you're using some name as a type in a definition and that name has been shadowed the type checker will likely complain.
Sorry, Clark: I meant to call out the 'Do not import objects, only modules (*)' rule (which doesn't actually have a hacking (the tool) rule associated with since it would presumably be very difficult/impossible to enforce). I agree with the '[H303] Do not use wildcard * import (*)' rule and wildcard imports are actually discourage from a typing perspective.
Is it possible to relax the rules only when there is an expectation that we'll catch the rules through another process like type checking?
It is also worth noting that the current rules allow us to take advantage of lazy import behaviors when Python adds support for them without making major changes. This is particularly relevant to type checking as I believe one of the benefits of lazy imports is the mitigation of cost for type checking imports and code at runtime. So we may want to be careful making changes here even if we are type checking.
Yes, for expensive imports you can work around this by placing imports behind the 'TYPE_CHECKING' guard, e.g.: if TYPE_CHECKING: from collections.abc import Sequence But you'd have to either using '__future__.annotations' or wrap these in strings to prevent them being evaluated at runtime. I don't believe the cost of imports of objects from three proposed stdlib libraries is high enough to justify the cognitive load/tooling costs of dealing with deferred evaluation, but we should definitely evaluate whether that's the case for other libraries and modules. I've experimented with doing this for things like libvirt in Nova, for example. Stephen
Cheers, Stephen
[1] If you've already started writing a reply about how type hints *themselves* make function signatures more verbose and difficult to read, (a) is your name Sean Mooney and (b) stop right there, go enable an LSP in your editor, then come back to me in a month once you've seen the quality of life improvement hints provide. Then we'll talk 😄