diff options
author | Marc Mueller <30130371+cdce8p@users.noreply.github.com> | 2021-03-01 12:49:45 +0100 |
---|---|---|
committer | Pierre Sassoulas <pierre.sassoulas@gmail.com> | 2021-03-05 19:08:42 +0100 |
commit | 56b8e229d9150d57e090a1e4bd046b2fe8541d97 (patch) | |
tree | 822bcba13ce360023b18dbb234b37088ae77a850 | |
parent | b8c9472706de23e79d540a4df717cf2966483891 (diff) | |
download | pylint-git-56b8e229d9150d57e090a1e4bd046b2fe8541d97.tar.gz |
Refactor modify sys_path for execution as python module
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | pylint/__init__.py | 23 | ||||
-rw-r--r-- | pylint/__main__.py | 11 | ||||
-rw-r--r-- | tests/test_self.py | 69 |
4 files changed, 98 insertions, 10 deletions
@@ -25,6 +25,11 @@ Release date: TBA Close #3263 +* Fix issue when executing with ``python -m pylint`` + + Closes #4161 + + What's New in Pylint 2.7.2? =========================== Release date: 2021-02-28 diff --git a/pylint/__init__.py b/pylint/__init__.py index 1fd6ffd16..20bb554d2 100644 --- a/pylint/__init__.py +++ b/pylint/__init__.py @@ -8,6 +8,7 @@ # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html # For details: https://github.com/PyCQA/pylint/blob/master/COPYING +import os import sys from pylint.__pkginfo__ import version as __version__ @@ -44,4 +45,26 @@ def run_symilar(): SimilarRun(sys.argv[1:]) +def modify_sys_path() -> None: + """Modify sys path for execution as Python module. + + Strip out the current working directory from sys.path. + Having the working directory in `sys.path` means that `pylint` might + inadvertently import user code from modules having the same name as + stdlib or pylint's own modules. + CPython issue: https://bugs.python.org/issue33053 + + - Remove the first entry. This will always be either "" or the working directory + - Remove the working directory from the second and third entries. This can + occur if PYTHONPATH includes a ":" at the beginning or the end. + https://github.com/PyCQA/pylint/issues/3636 + - Don't remove the working directory from the rest. It will be included + if pylint is installed in an editable configuration (as the last item). + https://github.com/PyCQA/pylint/issues/4161 + """ + sys.path = [ + p for i, p in enumerate(sys.path) if i > 0 and not (i < 3 and p == os.getcwd()) + ] + + __all__ = ["__version__"] diff --git a/pylint/__main__.py b/pylint/__main__.py index 89bd19924..4d7653718 100644 --- a/pylint/__main__.py +++ b/pylint/__main__.py @@ -3,16 +3,7 @@ # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html # For details: https://github.com/PyCQA/pylint/blob/master/COPYING -import os -import sys - import pylint -# Strip out the current working directory from sys.path. -# Having the working directory in `sys.path` means that `pylint` might -# inadvertently import user code from modules having the same name as -# stdlib or pylint's own modules. -# CPython issue: https://bugs.python.org/issue33053 -sys.path = [p for p in sys.path if p not in ("", os.getcwd())] - +pylint.modify_sys_path() pylint.run_pylint() diff --git a/tests/test_self.py b/tests/test_self.py index 5b55f6cca..42ef732ec 100644 --- a/tests/test_self.py +++ b/tests/test_self.py @@ -42,12 +42,16 @@ import subprocess import sys import textwrap import warnings +from copy import copy from io import StringIO from os.path import abspath, dirname, join +from typing import Generator from unittest import mock +from unittest.mock import patch import pytest +from pylint import modify_sys_path from pylint.constants import MAIN_CHECKER_NAME, MSG_TYPES_STATUS from pylint.lint import Run from pylint.reporters import JSONReporter @@ -700,6 +704,71 @@ class TestRunTC: ) @staticmethod + def test_modify_sys_path() -> None: + @contextlib.contextmanager + def test_sys_path() -> Generator[None, None, None]: + original_path = sys.path + try: + yield + finally: + sys.path = original_path + + with test_sys_path(), patch("os.getcwd") as mock_getcwd: + cwd = "/tmp/pytest-of-root/pytest-0/test_do_not_import_files_from_0" + mock_getcwd.return_value = cwd + + paths = [ + cwd, + cwd, + "/usr/local/lib/python39.zip", + "/usr/local/lib/python3.9", + "/usr/local/lib/python3.9/lib-dynload", + "/usr/local/lib/python3.9/site-packages", + ] + sys.path = copy(paths) + modify_sys_path() + assert sys.path == paths[2:] + + paths = [ + cwd, + "/custom_pythonpath", + cwd, + "/usr/local/lib/python39.zip", + "/usr/local/lib/python3.9", + "/usr/local/lib/python3.9/lib-dynload", + "/usr/local/lib/python3.9/site-packages", + ] + sys.path = copy(paths) + modify_sys_path() + assert sys.path == [paths[1]] + paths[3:] + + paths = [ + "", + cwd, + "/custom_pythonpath", + "/usr/local/lib/python39.zip", + "/usr/local/lib/python3.9", + "/usr/local/lib/python3.9/lib-dynload", + "/usr/local/lib/python3.9/site-packages", + ] + sys.path = copy(paths) + modify_sys_path() + assert sys.path == paths[2:] + + paths = [ + "", + cwd, + "/usr/local/lib/python39.zip", + "/usr/local/lib/python3.9", + "/usr/local/lib/python3.9/lib-dynload", + "/usr/local/lib/python3.9/site-packages", + cwd, + ] + sys.path = copy(paths) + modify_sys_path() + assert sys.path == paths[2:] + + @staticmethod def test_do_not_import_files_from_local_directory(tmpdir): p_astroid = tmpdir / "astroid.py" p_astroid.write("'Docstring'\nimport completely_unknown\n") |