Show More
@@ -154,6 +154,17 b' def is_importable(module, attr, only_modules):' | |||||
154 | else: |
|
154 | else: | |
155 | return not(attr[:2] == '__' and attr[-2:] == '__') |
|
155 | return not(attr[:2] == '__' and attr[-2:] == '__') | |
156 |
|
156 | |||
|
157 | def is_possible_submodule(module, attr): | |||
|
158 | try: | |||
|
159 | obj = getattr(module, attr) | |||
|
160 | except AttributeError: | |||
|
161 | # Is possilby an unimported submodule | |||
|
162 | return True | |||
|
163 | except TypeError: | |||
|
164 | # https://github.com/ipython/ipython/issues/9678 | |||
|
165 | return False | |||
|
166 | return inspect.ismodule(obj) | |||
|
167 | ||||
157 |
|
168 | |||
158 | def try_import(mod: str, only_modules=False) -> List[str]: |
|
169 | def try_import(mod: str, only_modules=False) -> List[str]: | |
159 | """ |
|
170 | """ | |
@@ -172,7 +183,12 b' def try_import(mod: str, only_modules=False) -> List[str]:' | |||||
172 | completions.extend( [attr for attr in dir(m) if |
|
183 | completions.extend( [attr for attr in dir(m) if | |
173 | is_importable(m, attr, only_modules)]) |
|
184 | is_importable(m, attr, only_modules)]) | |
174 |
|
185 | |||
175 |
|
|
186 | m_all = getattr(m, "__all__", []) | |
|
187 | if only_modules: | |||
|
188 | completions.extend(attr for attr in m_all if is_possible_submodule(m, attr)) | |||
|
189 | else: | |||
|
190 | completions.extend(m_all) | |||
|
191 | ||||
176 | if m_is_init: |
|
192 | if m_is_init: | |
177 | completions.extend(module_list(os.path.dirname(m.__file__))) |
|
193 | completions.extend(module_list(os.path.dirname(m.__file__))) | |
178 | completions_set = {c for c in completions if isinstance(c, str)} |
|
194 | completions_set = {c for c in completions if isinstance(c, str)} |
@@ -157,6 +157,11 b' def test_bad_module_all():' | |||||
157 | nt.assert_in('puppies', results) |
|
157 | nt.assert_in('puppies', results) | |
158 | for r in results: |
|
158 | for r in results: | |
159 | nt.assert_is_instance(r, str) |
|
159 | nt.assert_is_instance(r, str) | |
|
160 | ||||
|
161 | # bad_all doesn't contain submodules, but this completion | |||
|
162 | # should finish without raising an exception: | |||
|
163 | results = module_completion("import bad_all.") | |||
|
164 | nt.assert_equal(results, []) | |||
160 | finally: |
|
165 | finally: | |
161 | sys.path.remove(testsdir) |
|
166 | sys.path.remove(testsdir) | |
162 |
|
167 | |||
@@ -176,3 +181,14 b' def test_module_without_init():' | |||||
176 | assert s == [] |
|
181 | assert s == [] | |
177 | finally: |
|
182 | finally: | |
178 | sys.path.remove(tmpdir) |
|
183 | sys.path.remove(tmpdir) | |
|
184 | ||||
|
185 | ||||
|
186 | def test_valid_exported_submodules(): | |||
|
187 | """ | |||
|
188 | Test checking exported (__all__) objects are submodules | |||
|
189 | """ | |||
|
190 | results = module_completion("import os.pa") | |||
|
191 | # ensure we get a valid submodule: | |||
|
192 | nt.assert_in("os.path", results) | |||
|
193 | # ensure we don't get objects that aren't submodules: | |||
|
194 | nt.assert_not_in("os.pathconf", results) |
General Comments 0
You need to be logged in to leave comments.
Login now