Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Usage of module-level symbols declared in stub files should not report private usage #2326

Closed
silriozs opened this issue Feb 3, 2022 · 4 comments
Labels
waiting for user response Requires more information from user

Comments

@silriozs
Copy link

silriozs commented Feb 3, 2022

Environment data

Language Server version: Pylance language server 2022.1.5 (pyright 8d096292)

Expected behaviour

Module-level symbols declared in stub files should not be reported reportPrivateUsage when used.

Actual behaviour

Module-level symbols declared in stub files are reported reportPrivateUsage when used.

Code Snippet

from __future__ import annotations

import hashlib
import pathlib

def hash_file(filename: pathlib.Path, hash_obj: hashlib._Hash) -> hashlib._Hash:  # (1)
    with open(filename, 'rb') as file:
        while data := file.read(2 ** 16):
            hash_obj.update(data)
    return hash_obj
  • line (1) reported "_Hash" is private and used outside of the module in which it is declared

Notes

Some module-level symbols in stub files, e.g., hashlib._Hash and curses._CursesWindow, are essential for writing type annotations. And I think they should be considered public interface.

#1454 (comment) already address the similar problem for private class members.
This enhancement request is specifically for module-level symbols.

@github-actions github-actions bot added the triage label Feb 3, 2022
@erictraut
Copy link
Contributor

I remember now why I didn't include this as part of the earlier change for member variables and methods. The problem is that it's common to use underscore names for private (non-runtime) classes, TypeVars, and type aliases in type stubs. For example, look at builtins.pyi, which defines _SupportsIter, _T1, and _SupportsNextT among others. If you were to try to import these in your code, you would receive a runtime exception because they are not actually present at runtime.

So I think it's best to continue to treat symbols with names that begin with underscores as "private" when they appear in type stubs at the module level. If you have reason to override this in stubs that you use, you can disable the reportPrivateUsage diagnostic check — for your entire project or on a file-by-file basis using a # pyright: reportPrivateUsage=false comment.

@silriozs
Copy link
Author

silriozs commented Feb 3, 2022

I understand why not all symbols that begin with underscores are considered public. But for cases like hashlib._Hash, it seems that not all of such symbols are private, too. I agree that continue to treat such symbols as "private" if there has no better way to distinguish both cases.

If you have reason to override this in stubs that you use, you can disable the reportPrivateUsage diagnostic check — for your entire project or on a file-by-file basis using a # pyright: reportPrivateUsage=false comment.

Is there a way to disable the check on a line-by-line basis or only for certain symbols? Because I do want to keep the reportPrivateUsage check for the rest of file but only disable for certain cases.

@erictraut
Copy link
Contributor

You can assign a local alias for the private usage and then use a # type: ignore for that line.

from hashlib import _Hash as Hash  # type: ignore
import hashlib
Hash = hashlib._Hash # type: ignore

@judej judej added the waiting for user response Requires more information from user label Feb 3, 2022
@github-actions github-actions bot removed the triage label Feb 3, 2022
@silriozs
Copy link
Author

silriozs commented Feb 4, 2022

The method requires some boilerplates to work:

from __future__ import annotations

import hashlib
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from hashlib import _Hash as Hash  # type: ignore

def do_hash(hash_obj: Hash) -> Hash:
    ...

if TYPE_CHECKING: prevent the symbol from been imported at runtime.
from __future__ import annotations or quoting the type annotation is required.

The code is a little bit verbose for suppressing a single warning, but I think it works for my use case.

Thanks for helping!

@silriozs silriozs closed this as completed Feb 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
waiting for user response Requires more information from user
Projects
None yet
Development

No branches or pull requests

3 participants