|  | 
| 8 | 8 | import subprocess | 
| 9 | 9 | import sys | 
| 10 | 10 | import tempfile | 
|  | 11 | +from pkgutil import ModuleInfo | 
| 11 | 12 | from unittest import TestCase, skipUnless, skipIf | 
| 12 | 13 | from unittest.mock import patch | 
| 13 | 14 | from test.support import force_not_colorized, make_clean_env, Py_DEBUG | 
| @@ -959,6 +960,46 @@ def test_import_completions(self): | 
| 959 | 960 |                 output = reader.readline() | 
| 960 | 961 |                 self.assertEqual(output, expected) | 
| 961 | 962 | 
 | 
|  | 963 | +    @patch("pkgutil.iter_modules", lambda: [ModuleInfo(None, "public", True), | 
|  | 964 | +                                            ModuleInfo(None, "_private", True)]) | 
|  | 965 | +    @patch("sys.builtin_module_names", ()) | 
|  | 966 | +    def test_private_completions(self): | 
|  | 967 | +        cases = ( | 
|  | 968 | +            # Return public methods by default | 
|  | 969 | +            ("import \t\n", "import public"), | 
|  | 970 | +            ("from \t\n", "from public"), | 
|  | 971 | +            # Return private methods if explicitly specified | 
|  | 972 | +            ("import _\t\n", "import _private"), | 
|  | 973 | +            ("from _\t\n", "from _private"), | 
|  | 974 | +        ) | 
|  | 975 | +        for code, expected in cases: | 
|  | 976 | +            with self.subTest(code=code): | 
|  | 977 | +                events = code_to_events(code) | 
|  | 978 | +                reader = self.prepare_reader(events, namespace={}) | 
|  | 979 | +                output = reader.readline() | 
|  | 980 | +                self.assertEqual(output, expected) | 
|  | 981 | + | 
|  | 982 | +    @patch( | 
|  | 983 | +        "_pyrepl._module_completer.ModuleCompleter.iter_submodules", | 
|  | 984 | +        lambda *_: [ | 
|  | 985 | +            ModuleInfo(None, "public", True), | 
|  | 986 | +            ModuleInfo(None, "_private", True), | 
|  | 987 | +        ], | 
|  | 988 | +    ) | 
|  | 989 | +    def test_sub_module_private_completions(self): | 
|  | 990 | +        cases = ( | 
|  | 991 | +            # Return public methods by default | 
|  | 992 | +            ("from foo import \t\n", "from foo import public"), | 
|  | 993 | +            # Return private methods if explicitly specified | 
|  | 994 | +            ("from foo import _\t\n", "from foo import _private"), | 
|  | 995 | +        ) | 
|  | 996 | +        for code, expected in cases: | 
|  | 997 | +            with self.subTest(code=code): | 
|  | 998 | +                events = code_to_events(code) | 
|  | 999 | +                reader = self.prepare_reader(events, namespace={}) | 
|  | 1000 | +                output = reader.readline() | 
|  | 1001 | +                self.assertEqual(output, expected) | 
|  | 1002 | + | 
| 962 | 1003 |     def test_builtin_completion_top_level(self): | 
| 963 | 1004 |         import importlib | 
| 964 | 1005 |         # Make iter_modules() search only the standard library. | 
| @@ -991,8 +1032,8 @@ def test_relative_import_completions(self): | 
| 991 | 1032 |                 output = reader.readline() | 
| 992 | 1033 |                 self.assertEqual(output, expected) | 
| 993 | 1034 | 
 | 
| 994 |  | -    @patch("pkgutil.iter_modules", lambda: [(None, 'valid_name', None), | 
| 995 |  | -                                            (None, 'invalid-name', None)]) | 
|  | 1035 | +    @patch("pkgutil.iter_modules", lambda: [ModuleInfo(None, "valid_name", True), | 
|  | 1036 | +                                            ModuleInfo(None, "invalid-name", True)]) | 
| 996 | 1037 |     def test_invalid_identifiers(self): | 
| 997 | 1038 |         # Make sure modules which are not valid identifiers | 
| 998 | 1039 |         # are not suggested as those cannot be imported via 'import'. | 
|  | 
0 commit comments