1

First off, I know there are a number of questions related to this one already asked here (This and This seem most similar). I've read through a number of them, but am finding myself still very confused about the appropriate way to accomplish this.

I have a project that I'm working on that is structured in this way:

--LabAnalysisModules
  |-- __init__.py
  |-- EphysTools
      |-- __init__.py
      |-- synaptics.py
      |-- utilities.py
  |-- PrairieAnalysis
      |-- pv_import.py
      |-- pxml_parse.py

--PVAnalysis
  |-- __init__.py
  |-- MainWindow.py
  |-- DataViewer.py
  |-- AnalysisWindows
      |-- __init__.py
      |-- AnalysisWidget.py

AnalysisWidget inherits from the DataViewer class in DataViewer. In trying to import DataViewer I have run into two points of confusion.

  1. What is the most appropriate way to actually import DataViewer. I am currently resorting to including sys.path.append(os.path.abspath("../../PVAnalysis")) in AnalysisWidget, since a relative import gives me SystemError: Parent module '' not loaded, cannot perform relative import

  2. Within DataViewer I have this try...except block (on some of my machines LabAnalysisModules has been permanently added to the python path, and on others it hasn't)

    try:
        import PrairieAnalysis.pv_import as pvi
        import EphysTools.utilities as util
    except ImportError:
        import os
        sys.path.append(os.path.abspath('../LabAnalysisModules'))
        import PrairieAnalysis.pv_import as pvi
        import EphysTools.utilities as util
    

Running DataViewer itself works fine, but I run into another import error import DataViewer from AnalysisWidget:

ImportError: No module named 'PrairieAnalysis'

Adding print(sys.path) to the above except block, this is what is added to sys.path when DataViewer is imported:

E:\\Users\\Dan\\SkyDrive\\Documents\\Python\\PVAnalysis\\LabAnalysisModules'

Which is obviously not correct.

I can fix this import error by including sys.path.append('../../LabAnalysisModules') in AnalysisWidget, but this seems like a very kludgy fix

Edit 1

As I say in the comments, ultimately AnalysisWidget will be imported by MainWindow. Again, really not clear on how relative imports work. Getting:

    from .. import DataViewer
ValueError: attempted relative import beyond top-level package

At the end of the day, the two things I'm trying to do are:

  1. Be able to simply run AnalysisWidget.py (I know that in general you aren't supposed to run scripts from within a module, but when it comes to creating a GUI I find myself doing this all the time)

  2. Be able to import AnalysisWidget into MainWindow.

If I clean up how I'm doing imports for the LabAnalysisModules as well that would be good.

Community
  • 1
  • 1
dan_g
  • 2,712
  • 5
  • 25
  • 44
  • How are you invoking `AnalysisWidget`? Directly, or with the `-m` switch to Python? – Kevin Jan 29 '15 at 14:54
  • The SystemError reported above is from just trying to import AnalysisWidget within the python shell. I have tried using the -m switch, but I don't seem to be doing something properly as I just get Error while finding spec for...etc – dan_g Jan 29 '15 at 15:12
  • Ultimate, though, AnalysisWidget will be imported by MainWindow. – dan_g Jan 29 '15 at 15:26
  • `from .. import DataViewer`: this only works if the parent directory is also a package (`PVAnalysis` should then contain `__init__.py`), because the two dots `..` just mean to go up one directory/module level. –  Jan 29 '15 at 15:49
  • PVAnalysis does contain `__init__.py`, unless I'm misunderstanding – dan_g Jan 29 '15 at 15:56
  • Is `PVAnalysis` supposed to be a package? Or just a directory in the general sense of terms? –  Jan 29 '15 at 16:04
  • It is acting just as a directory, which presumably makes the `__init__.py` superfluous? Nothing outside of PVAnalysis will ever have to import anything within PVAnalysis. – dan_g Jan 29 '15 at 16:09

1 Answers1

1

In order for package imports to work properly in Python 3, your working directory must be the parent of LabAnalysisModules and PVAnalysis (or said directory must appear on sys.path, but making it the working directory is the easiest way to do that). Furthermore, if any of your modules are runnable, they must be invoked with syntax like this:

python -m 'PVAnalysis.AnalysisWindows.AnalysisWidget'

Please consult PEP 328 for more information.

Kevin
  • 28,963
  • 9
  • 62
  • 81
  • Reading through PEP 328 I still don't understand why, from within AnalysisWidget.py, `from ..DataViewer import DataViewer` doesn't work. This is with calling `import AnalysisWindows.AnalysisWidget` from within MainWindow.py. To me that looks identical to the `from ..moduleA import foo` example in the PEP – dan_g Jan 29 '15 at 20:25
  • That's because you're crossing top-level package boundaries. If you want to import something from a separate top-level package, you need to use an absolute import. – Kevin Jan 29 '15 at 20:37
  • I'm sorry, I still don't understand what you mean. How is the file / package structure I presented above different than the one in the PEP such that what I am doing is invalid (thanks for bearing with me on this) – dan_g Jan 29 '15 at 20:42
  • Oh, I misinterpreted you. That *should* work, if `PVAnalysis` is contained in one of the directories listed in `sys.path`. Since the working directory is always on that list, you just need to make sure the working directory is the **parent** of `PVAnalysis`, and **not** `PVAnalysis` itself. – Kevin Jan 29 '15 at 20:45
  • And if PVAnalysis is the working directory? Ultimately this is going to be an application where there is a PVAnalysis.py file that sets everything up and puts it all together. The folder is really PVAnalysis just a container for me to keep everything organized. – dan_g Jan 29 '15 at 20:54
  • You can't do that. To import a top-level package, it must be *contained in* one of the directories on `sys.path`. It should not actually *be* one of those directories. Either create a new parent directory which contains `PVAnalysis` or drop the relative imports and treat `AnalysisWindows` as your top-level package. – Kevin Jan 29 '15 at 21:23
  • Ok, I'll reorganize things to make it work properly. Do you have any suggestions with regards to the issue I'm running in to with importing packages contained within LabAnalysisModules. In essence, what is the appropriate way to import packages that are currently contained within a folder that is in the system path? What I'm currently doing in DataViewever, for example, with appending to sys.path is causing issues when DataViewer is imported by another module, presumably because of the different paths to LabAnalysisModules – dan_g Jan 29 '15 at 21:33
  • `LabAnalysisModules` is a top-level package. You can only do relative imports of its modules from within `LabAnalysisModules`. The rest of the time, you should use absolute imports (e.g. `import LabAnalysisModules.EphysTools.synaptics`). – Kevin Jan 29 '15 at 21:36
  • Right, I understand that. What I'm trying to say LabAnalysisModules (or its container) do not normally exist in `sys.path`. Normally as part of my import statements I append the container for LabAnalysisModules (or well, normally I append LabAnalysisModules, since its really just acting as a container for the subpackages). But doing that is causing a problem since, when DataViewer is imported by AnalysisWidget `sys.path.append(os.path.abspath('../LabAnalysisModules'))` - which is in DataViewer - results in an incorrect path (see in OP). Is there any good way to do this? – dan_g Jan 29 '15 at 21:49
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/69867/discussion-between-kevin-and-user3014097). – Kevin Jan 30 '15 at 02:15