Repository: MouseLand/facemap (language: python)

Issue:
update dev w/ main



Discussion / hints:

Fix patch:
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..9af7e6f
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[aliases]
+test=pytest
\ No newline at end of file
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..4d69aa8
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,32 @@
+# For more information about tox, see https://tox.readthedocs.io/en/latest/
+[tox]
+envlist = py{37,38,39}-{linux,macos,windows}
+
+[gh-actions]
+python =
+    3.7: py37
+    3.8: py38
+    3.9: py39
+    
+[gh-actions:env]
+PLATFORM =
+    ubuntu-latest: linux
+    macos-latest: macos
+    windows-latest: windows
+
+[testenv]
+platform = 
+    macos: darwin
+    linux: linux
+    windows: win32
+passenv = 
+    CI
+    GITHUB_ACTIONS
+    DISPLAY XAUTHORITY
+    NUMPY_EXPERIMENTAL_ARRAY_FUNCTION
+    PYVISTA_OFF_SCREEN
+deps = 
+    pytest  # https://docs.pytest.org/en/latest/contents.html
+    pytest-cov  # https://pytest-cov.readthedocs.io/en/latest/
+    pytest-xvfb ; sys_platform == 'linux'
+commands = pytest -v --color=yes --cov=facemap --cov-report=xml
\ No newline at end of file


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index 4f25d5a..8f3a781 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,6 +1,8 @@
 import pytest
-import os, sys
+import os, sys, tempfile, shutil
+from tqdm import tqdm
 from pathlib import Path
+from urllib.request import urlopen
 
 @pytest.fixture()
 def video_names():
@@ -10,6 +12,61 @@ def video_names():
 
 @pytest.fixture()
 def data_dir(video_names):
-    data_dir = os.path.join(os.getcwd(),'Video_samples/sample_movies/')
-    #data_dir2 = os.path.join(os.getcwd(),'Video_samples/sample_movies2/')
-    return data_dir#1, data_dir2
+    #data_dir = os.path.join(os.getcwd(),'Video_samples/sample_movies/')
+    fm_dir = Path.home().joinpath('.facemap')
+    fm_dir.mkdir(exist_ok=True)
+    data_dir = fm_dir.joinpath('data')
+    data_dir.mkdir(exist_ok=True)
+    data_dir_cam1 = data_dir.joinpath('cam1')
+    data_dir_cam1.mkdir(exist_ok=True)
+    data_dir_cam2 = data_dir.joinpath('cam2')
+    data_dir_cam2.mkdir(exist_ok=True)
+
+    for i,video_name in enumerate(video_names):
+        url = 'https://www.facemappy.org/test_data/' + video_name
+        if '1' in video_name:
+            cached_file = str(data_dir_cam1.joinpath(video_name))
+        else:
+            cached_file = str(data_dir_cam2.joinpath(video_name))
+        if not os.path.exists(cached_file):
+            download_url_to_file(url, cached_file)
+    return data_dir
+
+def download_url_to_file(url, dst, progress=True):
+    # Following adapted from https://github.com/MouseLand/cellpose/blob/35c16c94e285a4ec2fa17f148f06bbd414deb5b8/cellpose/utils.py#L45
+    """Download object at the given URL to a local path.
+            Thanks to torch, slightly modified
+    Args:
+        url (string): URL of the object to download
+        dst (string): Full path where object will be saved, e.g. `/tmp/temporary_file`
+        progress (bool, optional): whether or not to display a progress bar to stderr
+            Default: True
+    """
+    file_size = None
+    u = urlopen(url)
+    meta = u.info()
+    if hasattr(meta, 'getheaders'):
+        content_length = meta.getheaders("Content-Length")
+    else:
+        content_length = meta.get_all("Content-Length")
+    if content_length is not None and len(content_length) > 0:
+        file_size = int(content_length[0])
+    # We deliberately save it in a temp file and move it after
+    dst = os.path.expanduser(dst)
+    dst_dir = os.path.dirname(dst)
+    f = tempfile.NamedTemporaryFile(delete=False, dir=dst_dir)
+    try:
+        with tqdm(total=file_size, disable=not progress,
+                  unit='B', unit_scale=True, unit_divisor=1024) as pbar:
+            while True:
+                buffer = u.read(8192)
+                if len(buffer) == 0:
+                    break
+                f.write(buffer)
+                pbar.update(len(buffer))
+        f.close()
+        shutil.move(f.name, dst)
+    finally:
+        f.close()
+        if os.path.exists(f.name):
+            os.remove(f.name)
\ No newline at end of file
diff --git a/tests/test_output.py b/tests/test_output.py
index c4e3441..9245cbc 100644
--- a/tests/test_output.py
+++ b/tests/test_output.py
@@ -6,32 +6,38 @@
 
 r_tol, a_tol = 1e-2, 1e-2
 
-def output_single_video(data_dir, video_names):#test_
+def test_output_single_video(data_dir, video_names):
+    clear_output(data_dir, video_names)
     v1, _ = video_names
-    test_filenames = [[data_dir+video for video in v1]]
-    process.run(test_filenames, movSVD = True, savepath=os.getcwd()+"/tests/")    
+    test_filenames = [[str(data_dir.joinpath('data').joinpath('cam1').joinpath(v1))]] # [[data_dir+video for video in v1]]
+    save_path = str(data_dir.joinpath('data').joinpath('cam1'))
+    process.run(test_filenames, movSVD=True, savepath=save_path)    
 
     output_filename, _ = os.path.splitext(v1[0])
-    test_proc_filename = os.getcwd()+"/tests/"+output_filename+"_proc.npy"
+    test_proc_filename = save_path.joinpath(output_filename+"_proc.npy")
     output = np.load(test_proc_filename,allow_pickle=True).item()
     expected_proc_filename = os.getcwd()+"/tests/expected_output/singlevideo_proc.npy"
     expected_output = np.load(expected_proc_filename,allow_pickle=True).item()
-    
+    clear_output(data_dir, video_names)
+
     assert is_output_correct(output, expected_output)
 
 def test_output_multivideo(data_dir, video_names):
+    clear_output(data_dir, video_names)
     v1, v2 = video_names
-    test1 = os.path.join(data_dir,v1[0])
-    test2 = os.path.join(data_dir,v2[0])
+    test1 = str(data_dir.joinpath('data').joinpath('cam1').joinpath(v1))#os.path.join(data_dir,v1[0])
+    test2 = str(data_dir.joinpath('data').joinpath('cam2').joinpath(v2))#os.path.join(data_dir,v2[0])
     # For videos recorded simultaneously from multiple cams
-    test_filenames = [test1, test2]
-    process.run(test_filenames, movSVD = True, savepath=os.getcwd()+"/tests/")    
+    test_filenames = [[test1, test2]]
+    save_path = str(data_dir.joinpath('data').joinpath('cam2'))
+    process.run(test_filenames, movSVD=True, savepath=save_path)    
 
-    output_filename, _ = os.path.splitext(v1[0])
-    test_proc_filename = os.getcwd()+"/tests/"+output_filename+"_proc.npy"
+    output_filename, _ = os.path.splitext(v2[0])
+    test_proc_filename = save_path.joinpath(output_filename+"_proc.npy")
     output = np.load(test_proc_filename,allow_pickle=True).item()
     expected_proc_filename = os.getcwd()+"/tests/expected_output/multivideo_proc.npy"
     expected_output = np.load(expected_proc_filename,allow_pickle=True).item()
+    clear_output(data_dir, video_names)
 
     assert is_output_correct(output, expected_output)
 
@@ -80,4 +86,19 @@ def check_V(test_output, expected_output):
     return motion_V and movie_V
 
 def check_motion(test_output, expected_output):
-    return (test_output['motion'][0] == expected_output['motion'][0]).all()
\ No newline at end of file
+    return (test_output['motion'][0] == expected_output['motion'][0]).all()
+
+def clear_output(data_dir, video_names):
+    data_dir_cam1 = data_dir.joinpath('cam1')
+    data_dir_cam2 = data_dir.joinpath('cam2')
+    for video_name in video_names:
+        if '1' in video_name:
+            cached_file = str(data_dir_cam1.joinpath(video_name))
+            name, ext = os.path.splitext(cached_file)
+            output = name + '_proc.npy'
+        else:
+            cached_file = str(data_dir_cam2.joinpath(video_name))
+            name, ext = os.path.splitext(cached_file)
+            output = name + '_proc.npy'
+        if os.path.exists(output):
+            os.remove(output)