Repository: ratt-ru/meqtrees-cattery (language: python)

Issue:
Cattery imports Timba by default (standalone mode broken)
```
  File "/home/hugo/venvtmp/lib/python3.8/site-packages/Cattery/Siamese/OMS/InterpolatedBeams.py", line 11, in <module>
    from Cattery import Meow
  File "/home/hugo/venvtmp/lib/python3.8/site-packages/Cattery/Meow/__init__.py", line 50, in <module>
    from .CorruptComponent import CorruptComponent
  File "/home/hugo/venvtmp/lib/python3.8/site-packages/Cattery/Meow/CorruptComponent.py", line 29, in <module>
    from Timba.TDL import *
```


Discussion / hints:
For now just use 1.7.6 in e.g. DDFacet as a workaround (you won't have heterogeneous beam support then)

Fix patch:
diff --git a/.travis/headless.docker b/.travis/headless.docker
new file mode 100644
index 0000000..f968744
--- /dev/null
+++ b/.travis/headless.docker
@@ -0,0 +1,35 @@
+# Test case for testing headless install (without Timba) 
+
+FROM kernsuite/base:7
+
+RUN docker-apt-install python3-all python3-virtualenv python3-pip git
+
+# other fixed Python-only dependencies
+WORKDIR /src
+RUN git clone -b v1.5.0 https://github.com/ska-sa/purr.git
+RUN git clone -b v1.6.0 https://github.com/ska-sa/owlcat.git
+RUN git clone -b v1.4.3 https://github.com/ska-sa/kittens.git
+RUN git clone -b v1.6.0 https://github.com/ska-sa/tigger-lsm.git
+RUN git clone -b v1.7.1 https://github.com/ska-sa/pyxis.git
+
+RUN pip3 install ./purr ./owlcat ./kittens ./tigger-lsm
+RUN pip3 install -e ./pyxis
+
+# headless mode install without Timba
+WORKDIR /code
+ADD . /code/meqtrees-cattery
+RUN pip3 install ./meqtrees-cattery
+
+# check that the headless imports actually work (used by DDF and the likes)
+RUN python3 -c "import Cattery"
+RUN python3 -c "import Cattery.Siamese.OMS.Utils as Utils"
+RUN python3 -c "import Cattery.Siamese as Siamese"
+RUN python3 -c "import Cattery.Siamese.OMS.InterpolatedBeams as InterpolatedBeams"
+
+# basic unit tests
+RUN mkdir /test && \
+    pip3 install git+https://github.com/ratt-ru/eidos.git@a47fa43 nose && \
+    # check eidos install && \
+    python3 -c "import eidos" && \
+    python3 -m nose -v -s /code/meqtrees-cattery/unittests/ && \
+    rm -rf /test
\ No newline at end of file
diff --git a/Cattery/Siamese/OMS/InterpolatedBeams.py b/Cattery/Siamese/OMS/InterpolatedBeams.py
index d3a7466..abce6c8 100644
--- a/Cattery/Siamese/OMS/InterpolatedBeams.py
+++ b/Cattery/Siamese/OMS/InterpolatedBeams.py
@@ -8,9 +8,6 @@
 from scipy.ndimage import interpolation
 from scipy import interpolate
 
-from Cattery import Meow
-from Cattery.Meow import Context
-
 import Kittens.utils
 _verbosity = Kittens.utils.verbosity(name="vb");
 #_verbosity.set_verbose(5)
diff --git a/Jenkinsfile.sh b/Jenkinsfile.sh
index 024975b..847905a 100644
--- a/Jenkinsfile.sh
+++ b/Jenkinsfile.sh
@@ -21,4 +21,5 @@ cd $PROJECTS_DIR/meqtrees-cattery
 IMAGENAME="mtcatterypr"
 
 # build and test
+docker build -f .travis/headless.docker -t "${IMAGENAME}36_headless:$BUILD_NUMBER" --no-cache=true .
 docker build -f .travis/py3.docker -t "${IMAGENAME}36:$BUILD_NUMBER" --no-cache=true .
diff --git a/setup.py b/setup.py
index eb9a302..1c0be9e 100644
--- a/setup.py
+++ b/setup.py
@@ -52,7 +52,7 @@ def fullsplit(path, result=None):
 
 
 setup(name='meqtrees_cattery',
-      version='1.7.8',
+      version='1.7.9',
       python_requires='>=3.0.0',
       description='MeqTrees-based frameworks for simulation and calibration of radio interferometers ',
       author='Oleg Smirnov',


Test patch:
diff --git a/unittests/test_interpolatedbeam.py b/unittests/test_interpolatedbeam.py
new file mode 100644
index 0000000..c71e54a
--- /dev/null
+++ b/unittests/test_interpolatedbeam.py
@@ -0,0 +1,66 @@
+from nose.tools import *
+import numpy as np
+import time
+from subprocess import Popen
+import os
+
+import Cattery.Siamese.OMS.Utils as Utils
+import Cattery.Siamese as Siamese
+import Cattery.Siamese.OMS.InterpolatedBeams as InterpolatedBeams
+
+PREFIX = "/test/test_beam"
+PATTERN = PREFIX + "_$(corr)_$(reim).fits"
+
+def __run(cmdargs, timeout=600):
+    cmd = " ".join(cmdargs)
+    print(f"Running {cmd} with timeout {timeout} seconds")
+    p = Popen(cmdargs, 
+                env=os.environ.copy())
+
+    x = timeout
+    delay = 1.0
+    timeout = int(x / delay)
+    while p.poll() is None and timeout > 0:
+        time.sleep(delay)
+        timeout -= delay
+    #timeout reached, kill process if it is still rolling
+    ret = p.poll()
+    if ret is None:
+        p.kill()
+        ret = 99
+
+    if ret == 99:
+        raise RuntimeError("Test timeout reached. Killed process.")
+    elif ret != 0:
+        raise RuntimeError("{} exited with non-zero return code {}".format(cmdargs[0], ret))
+
+REALIMAG = dict(re="real",im="imag")
+
+def __make_beam_filename (filename_pattern,corr,reim,stationtype):
+    """Makes beam filename for the given correlation and real/imaginary component (one of "re" or "im")"""
+    return Utils.substitute_pattern(filename_pattern,
+                corr=corr.lower(),xy=corr.lower(),CORR=corr.upper(),XY=corr.upper(),
+                reim=reim.lower(),REIM=reim.upper(),ReIm=reim.title(),
+                realimag=REALIMAG[reim].lower(),REALIMAG=REALIMAG[reim].upper(),
+                RealImag=REALIMAG[reim].title(), 
+                stype=stationtype.lower(), STYPE=stationtype.upper())
+
+def testinterpolatedbeam():
+    print("creating beams...")
+    eidosargs = (f"eidos -d 0.5 -r 0.015625 -f 950 1050 20 -P {PREFIX} -o8").split(" ")
+    __run(eidosargs, timeout=900)
+    filenames = __make_beam_filename(PATTERN, "xy", "re", "default"), \
+                __make_beam_filename(PATTERN, "xy", "im", "default")
+    print("loading beam patterns %s %s" % filenames)
+    vb = InterpolatedBeams.LMVoltageBeam(
+        verbose=10000,
+        l_axis="px", 
+        m_axis="py"
+    )
+    vb.read(*filenames)
+    print("successfully loaded beam patterns %s %s" % filenames)
+    # approx small angle approximation
+    vel = vb.interpolate(np.deg2rad(0.05),np.deg2rad(0.05),freq=1000e6,freqaxis=1)
+    assert np.isclose(vel, np.array([-0.00091718+0.00020009j])), \
+        "Last known good value from Eidos beams interpolated value does not " \
+        "match current interpolated value"
\ No newline at end of file