napari / napari-console

A plugin that adds a console to napari
BSD 3-Clause "New" or "Revised" License
3 stars 12 forks source link

Local modules can't be imported in napari-console #31

Open psobolewskiPhD opened 2 years ago

psobolewskiPhD commented 2 years ago

šŸ› Bug

In contrast to the python REPL, ipython, VS Code, Jupyter, etc. the napari-console doesn't allow local modules/functions to be imported. The sys.path in the napari-console does not include "" in sys.path, which is what permits searching of imports from the current dir. See: https://docs.python.org/3/library/sys.html#sys.path

As a result launching napari from a dir does not permit easy importing of local modules. Because of the inconsistency with other python tools and the fact that the console so strongly mimics those tools, I consider this a bug. (After some growing pains with the napari-console now I'm a big fan, especially for easy single-window hacking, as well as for demos/screensharing.)

However, as the discussion here on zulip with @Czaki points out, it could be considered a feature: https://napari.zulipchat.com/#narrow/stream/212875-general/topic/napari.20console.20vs.20ipython.3A.20importing.20local.20modules By blocking local imports, the end user can't mask important "real" modules needed by plugins.

To Reproduce

Steps to reproduce the behavior:

  1. Have a folder, e.g. dev or python_stuffs and a subfolder napari_scripts (or any other such)
  2. Launch napari from terminal in dev or whatever.
  3. Open console and try to import from a script/module in napari_scripts: from napari_scripts.napari_measure import measure_shape

Result:

ModuleNotFoundError: No module named 'napari_scripts'

The broader import from napari_scripts import napari_measure results in the same error, also it doesn't matter if the sub-dir napari_scripts has __init__.py or not.

(FYI if napari is launched directly from the subdirectory with the scripts, they still cannot be imported.)

Edit: to make matters more confusing for the end user, pwd() works correctly and shows the dir. Also, to further blur the lines between ipython and napari-console: they share a history.

Expected behavior

Both of the above imports work in any of the above mentioned python consoles (regardless of __init__.py). As a result, I would expect the import to work in napari-console and my local functions to be available.

Additional Context

The issue with possible local imports, as @Czaki pointed out is that a user with a local file like tensorflow.py will prevent a napari plugin that uses tensorflow from working.

I tested this by making such a file with just a test function that prints a string. In live napari, stardist-napari (the tensorflow test plugin) works just fine. If one uses: import sys; sys.path.insert(0, "") to add "" to the top of sys.path my local imports work, but launching the Stardist plugin an error results, fairly clearly identifying the issue:

ImportError: cannot import name '__version__' from 'tensorflow' (/Users/piotrsobolewski/Dev/python_stuffs/tensorflow.py)

If one uses instead: import sys; sys.path.append('') then again the local imports work, just like in ipython, et al (which have "" in sys.path at the bottom). Importantly, Stardist plugin still works despite the "malicious/ignorant" tensorflow.py

So the key is to put "" after all the other search dirs (e.g. conda env ones). ipython uses a init_path function that does this on start setting sys.path[0]=""

PS: Not sure if this should be here or napari-console repo?

Environment

napari: 0.4.16rc2.dev17+g0c148bb6 Platform: macOS-12.3.1-arm64-arm-64bit System: MacOS 12.3.1 Python: 3.9.12 | packaged by conda-forge | (main, Mar 24 2022, 23:25:14) [Clang 12.0.1 ] Qt: 5.15.2 PyQt5: 5.15.4 NumPy: 1.21.5 SciPy: 1.8.0 Dask: 2022.02.0 VisPy: 0.10.0

OpenGL:

Screens:

Plugins: