Skip to content

Can't include relative module within an IFO package's __init__.py

(Python 3 only)

I'm trying to define an IFO in a separate directory to pygwinc, but run it using pygwinc's __main__.py. My IFO is defined in a package within a directory called mydir. The structure looks like this:

$> tree mydir
mydir/
├── __init__.py
├── __main__.py
└── tmp
    ├── ifo.yaml
    ├── __init__.py
    └── thing.py

__main__.py contains just a simple wrapper around pygwinc's __main__.py:

from gwinc.__main__ import main

if __name__ == "__main__":
    main()

/tmp/__init__.py is the noise budget definition:

from .thing import test
from gwinc.ifo.noises import *


class MyIFO(nb.Budget):
    name = 'My IFO'
    noises = [
        QuantumVacuum,
        Seismic,
        Newtonian,
        SuspensionThermal,
        CoatingBrownian,
        CoatingThermoOptic,
        SubstrateBrownian,
        SubstrateThermoElastic,
        ExcessGas,
    ]

/tmp/thing.py is just a module I want to define some useful functions in:

def test():
    pass

/tmp/ifo.yaml is the YAML parameter file (can just copy aLIGO's for testing):

...

Including relative modules from within an IFO's __init__.py seems to cause an error:

$> cd /path/to/directory/containing/mydir
$> python -m mydir mydir/tmp
loading module path mydir/tmp...
Traceback (most recent call last):
  File "/home/sean/Workspace/anaconda/envs/gwinc/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/home/sean/Workspace/anaconda/envs/gwinc/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/sean/Workspace/Repositories/pt-modelling/mydir/__main__.py", line 11, in <module>
    main()
  File "/home/sean/Workspace/Repositories/pygwinc/gwinc/__main__.py", line 100, in main
    Budget, ifo, freq, plot_style = load_ifo(args.IFO)
  File "/home/sean/Workspace/Repositories/pygwinc/gwinc/ifo/__init__.py", line 66, in load_ifo
    mod, modpath = load_module(modname)
  File "/home/sean/Workspace/Repositories/pygwinc/gwinc/util.py", line 32, in load_module
    spec.loader.exec_module(mod)
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "mydir/tmp/__init__.py", line 1, in <module>
    from .thing import test
ModuleNotFoundError: No module named 'tmp'

My workaround is to put everything in the IFO's __init__.py file, but this isn't very nice and kind of defeats the point of putting the IFO into a package and not just a module on the top level.

I guess this is caused by the way the module mydir/tmp is included by gwinc.util.load_module (via gwinc.ifo.load_ifo). Maybe this way of loading a module does not allow relative imports. Perhaps first adding the module to the $PATH would fix this.

Edited by Sean Leavey