tenacity icon indicating copy to clipboard operation
tenacity copied to clipboard

Explicitly export convenience symbols from tenacity/__init__.py

Open tomasgareau opened this issue 3 years ago • 4 comments

Hello! This PR tweaks all of the convenience exports in tenacity/__init__.py to use the import ... as ... form. This lets type-checkers discover those symbols under the tenacity module, e.g.:

Before

import tenacity

tenacity.wait_random_exponential()  # Pyright: "wait_random_exponential" is not a known member of module

After

import tenacity

tenacity.wait_random_exponential()  # Pyright: (class) wait_random_exponential

Pyright (and I think mypy) will consider imported symbols as private by default unless they:

  • use the import X as X or from A import X as X form, (a redundant alias) or,
  • include the name of the symbol in an __all__ symbol

The from A import X as X form was easier for me to do with a macro but happy to change it to the __all__ form if you'd prefer. Just thought I'd kick off this PR as a place to discuss that.

tomasgareau avatar Mar 23 '22 17:03 tomasgareau

⚠️ No release notes detected. Please make sure to use reno to add a changelog entry.

mergify[bot] avatar Mar 23 '22 17:03 mergify[bot]

Personally I think defining __all__ makes it clearer that the intent is to define a public API.

I'm not familiar with the import conventions you mentioned or their origins, but to me they wouldn't make the intent obvious, and the 'redundant alias' seems like a subtle code smell that's liable to be "cleaned up" by some well-meaning individual in the future.

asqui avatar Mar 23 '22 23:03 asqui

I think the import convention of "import ... as ..." comes (loosely) from PEP-484's section on stub files:

Modules and variables imported into the stub are not considered exported from the stub unless the import uses the import ... as ... form or the equivalent from ... import ... as ... form. (UPDATE: To clarify, the intention here is that only names imported using the form X as X will be exported, i.e. the name before and after as must be the same.)

I say loosely because the typing in here is in-line, not in a stub file. However, it seems as though type-checkers (or at least Pyright) use the same convention for in-line typing too (which makes sense -- more consistent that way). I've found that Pyright's automatic stub generator will use the from X import A as A form to export symbols.

That said, I agree with you that the __all__ form is more explicit -- just force pushed dd86b81 to switch to using __all__.

tomasgareau avatar Mar 24 '22 04:03 tomasgareau

If this could be updated to pass CI, think it would fix #230.

bhrutledge avatar Jul 19 '22 10:07 bhrutledge