question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Typechecking appears broken due to off-by-one relative package imports

See original GitHub issue

Describe the bug

PRAW includes respectable coverage type annotations where practical (particularly given its dynamic nature), which have the potential to be very helpful to downstream developers seeking to catch many bugs statically without having to hit the live Reddit API, as well as PRAW development itself.

PRAW modules that use relative imports include the following block, presumably to help the type checker find the parent package (example from praw/reddit.py):

if TYPE_CHECKING:  # pragma: no cover
    from .. import praw

…with the number of .. increasing with each level deep the given module is in the package. However, this results in the relative import going outside the package, which is neither valid Python (without PEP 420 namespace packages) nor works with MyPy, as it means it recurses into a directory that is not itself a package. In addition, one file (praw/objector.py) has an extra .. (the only file that did not consistently follow this pattern), either due to a typo or being previously located in a subpackage.

The net result is that running mypy (and presumably other type checkers) on the PRAW package, or on user code importing praw after adding a py.typed file to the PRAW package root per PEP 561, will fail with a critical error and prevent type checking entirely, as the . Furthermore, this not only prevents type-checking what is often the most critical code in a Reddit-bot or client (along with PRAW’s own correctness), but also causes stubgen to fail with a similar error, so users can’t even provide their own stubs.

To Reproduce Steps to reproduce the behavior:

  1. Install PRAW and MyPy
  2. Run stubgen -p praw -> Error occurs
  3. Run mypy $SITE_PACKAGES/praw -> Error occurs
  4. Run touch $SITE_PACKAGES/praw/py.typed to enable type-checking for PRAW and then mypy $YOUR_PACKAGE on a local package that users PRAW -> Error occurs

Expected behavior

Type checking to work without errors. To fix this issue, the relative imports for TYPE_CHECKING only can be simply changed to absolute imports (import praw), which are shorter, simpler and other than avoiding the errors/invalid behavior, have the exact same intended effect. Because all of these blocks are protected by if TYPE_CHECKING, there is zero runtime impact, it just fixes the type checker.

In addition, to allow PRAW users to take advantage of PRAW’s existing type hints to type check their own code, I advise per PEP 561 adding an empty file named py.typed to the root of the package.

I’ve manually hacked it in there, and it provided helpful type hinting with no major issues and minimal false positives . However, to make this work for other devs locally and on our CIs, we have to run a script that implements these same hacks, which is fragile, ugly and has the potential to break the install. Fixing the import statements will alleviate 90% of that (we’ll just have to touch one file), and adding the py.typed will do the rest.

I’m happy to submit a PR to fix this; let me know and I’ll go ahead. I’d also be interested in cleaning up the remaining flagged typing inconsistencies in PRAW and getting it set up to continually check for bad types (e.g. with pre-commit, either locally or CI-only) so there isn’t a regression on this front. I’d also hope to help add typing to prawcore, if that’s desirable, as it currently seems to be missing at least some of it. Thanks!

Code/Logs

Error with mypy $SITE_PACKAGES/praw:

$SITE_PACKAGES/praw/models/base.py:6: error: No parent module -- cannot perform relative import
Found 1 error in 1 file (errors prevented further checking)

Same error with stubgen -p praw:

Critical error during semantic analysis: $SITE_PACKAGES/praw/models/base.py:6: error: No parent module -- cannot perform relative import

System Info

  • OS: Windows 8.1 x64, Ubuntu 20.04 LTS, Raspbian 10
  • Python: 3.7, 3.8, 3.9
  • PRAW Version: 7.2.0, 7.3.0, latest master
  • MyPy Version: 0.902, 0.910 (latest as of when I tested)

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
CAM-Gerlachcommented, Jul 19, 2021

The GitHub actions only check and will fail if the codebase is not to standard.

Yeah, but that’s exactly what running pre-commit via a Github action on CI will do, unless you run it via Pre-Commit.CI instead (which can automatically apply the fixes if configured to do so), while running pre-commit locally (manually or automatically) will actually make changes to the to-be-committed files and give the contributor the chance to review them (unstaged, so its easy for the contributor to see what it modified) before commiting.

I’ll go ahead with that when I have the time, thanks. PR for this issue coming momentarily.

1reaction
LilSpazJoekpcommented, Jul 19, 2021

There is a difference between the pre_push script and GitHub actions. The GitHub actions only check and will fail if the codebase is not to standard. Feel free to open a PR though regarding the hooks and I’ll take a look.

Thanks!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Relative imports from within the same package lead to "no ...
Hi, I have a problem with mypy and handling of imports. Basically, I have a Python package with several modules which import other...
Read more >
Relative imports in Python 3 - Stack Overflow
Relative imports use a module's __name__ attribute to determine that module's position in the package hierarchy. If the module's name does ...
Read more >
attempted relative import with no known parent package - IQ-Inc
How to fix ImportError: attempted relative import with no known parent package. Learn why it happens and Python import best-practices.
Read more >
Documentation - Module Resolution - TypeScript
A relative import is resolved relative to the importing file and cannot resolve to an ambient module declaration. You should use relative imports...
Read more >
Pylint Documentation - Read the Docs
Pylint is a tool that checks for errors in Python code, tries to enforce a coding standard and looks for code smells. It....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found