Thanks everyone for your input, it gave me a lot to think about!
I’d like to summarize the options that have been mentioned in this thread so far.
Let me just preface that, assuming I’ll be able to use importlib to find submodules,
the import question is only about the case from foo import bar<tab>. All other forms
can be done purely statically without importing.
That is, in these cases import is not needed:
import foo<tab>
import foo.bar<tab>
from foo<tab>
from foo.bar<tab>
This case currently imports the module foo:
from foo import bar<tab>
This is because in addition to modules, we’re also looking for any
identifiers exported by foo starting with bar.
Here are the options that were mentioned:
-
Allow imports
- pros: works for both Python and C modules and finds both modules and module attributes
- cons:
- security implications
- some packages might take long to import which hurts UX
-
Allow imports but ask for a confirmation (e.g. first
<tab>shows a message, second<tab>imports)- cons: might not be enough to mitigate the security risk
-
Don’t allow imports
- pros:
- no risk from importing modules
- faster than importing
- cons:
- only module names can be completed, not attributes,
e.g.,from pathlib import Pa<tab>would not work
- only module names can be completed, not attributes,
- pros:
-
Don’t allow imports but use static analysis (i.e.
ast.parse) to find attributes.- pros: a good middle ground between usability and security
- cons:
- extension modules not supported (for attribute completions)
- may be less accurate