From fa6432608ddda7a4a688af8baa3e8a69fc224599 Mon Sep 17 00:00:00 2001
From: Michiel Cottaar <MichielCottaar@protonmail.com>
Date: Thu, 15 Aug 2019 13:09:36 +0100
Subject: [PATCH] ENH: look for sub-trees in parent tree directory

---
 fsl/utils/filetree/filetree.py        |  4 +++-
 fsl/utils/filetree/parse.py           | 20 ++++++++++++++++++++
 tests/test_filetree/local_parent.tree |  1 +
 tests/test_filetree/test_read.py      | 12 ++++++++++++
 4 files changed, 36 insertions(+), 1 deletion(-)
 create mode 100644 tests/test_filetree/local_parent.tree

diff --git a/fsl/utils/filetree/filetree.py b/fsl/utils/filetree/filetree.py
index cf21f34b9..09350d161 100644
--- a/fsl/utils/filetree/filetree.py
+++ b/fsl/utils/filetree/filetree.py
@@ -360,6 +360,7 @@ class FileTree(object):
             filename = parse.search_tree(tree_name)
         tree_name = op.splitext(op.basename(filename))[0]
         filename = Path(filename)
+        dirname = str(filename.parent)
 
         templates = {}
         nspaces_level = []
@@ -392,7 +393,8 @@ class FileTree(object):
                     else:
                         sub_dir = current_filename.parents[0]
 
-                    _, sub_tree, short_name = parse.read_subtree_line(line, sub_dir)
+                    with parse.extra_tree_dirs([dirname]):
+                        _, sub_tree, short_name = parse.read_subtree_line(line, sub_dir)
                     if short_name in sub_trees:
                         raise ValueError("Name of sub_tree {short_name} used multiple times in {tree_name}.tree".format(**locals()))
 
diff --git a/fsl/utils/filetree/parse.py b/fsl/utils/filetree/parse.py
index b2d6c883a..409a358bf 100644
--- a/fsl/utils/filetree/parse.py
+++ b/fsl/utils/filetree/parse.py
@@ -1,6 +1,7 @@
 import glob
 import os.path as op
 from . import filetree
+from contextlib import contextmanager
 from pathlib import PurePath
 from typing import Tuple, List
 import re
@@ -9,6 +10,25 @@ import re
 tree_directories = ['.', op.join(op.split(__file__)[0], 'trees')]
 
 
+@contextmanager
+def extra_tree_dirs(extra_dirs):
+    """Temporarily insert ``extra_dirs`` to the beginning of :attr:`tree_directories`.
+
+    :arg extra_dirs: Sequence of additional tree file directories to search.
+    """
+
+    global tree_directories
+
+    old_tree_directories = list(tree_directories)
+
+    tree_directories = list(extra_dirs) + list(tree_directories)
+
+    try:
+        yield
+    finally:
+        tree_directories = old_tree_directories
+
+
 def search_tree(name: str) -> str:
     """
     Searches for the file defining the specific tree
diff --git a/tests/test_filetree/local_parent.tree b/tests/test_filetree/local_parent.tree
new file mode 100644
index 000000000..cac89ead4
--- /dev/null
+++ b/tests/test_filetree/local_parent.tree
@@ -0,0 +1 @@
+->format (format)
\ No newline at end of file
diff --git a/tests/test_filetree/test_read.py b/tests/test_filetree/test_read.py
index 00bd31010..4895ce1d9 100644
--- a/tests/test_filetree/test_read.py
+++ b/tests/test_filetree/test_read.py
@@ -4,6 +4,7 @@ from pathlib import PurePath
 import os.path as op
 import pytest
 from glob import glob
+import os
 
 
 def same_path(p1, p2):
@@ -161,3 +162,14 @@ def test_extract_vars_but():
     assert {'p1': 'opt_file', 'p2': 'test'} == tree.update(p1='opt_file').extract_variables('fn', fn)
     assert {'p1': 'opt', 'p2': 'file_test'} == tree.update(p1='opt').extract_variables('fn', fn)
     assert {'p1': 'opt_{p3}', 'p2': 'test', 'p3': 'file'} == tree.update(p1='opt_{p3}').extract_variables('fn', fn)
+
+
+def test_read_local_sub_children():
+    """
+    Look for trees defined in the same folder as the test directory
+    """
+    directory = op.split(__file__)[0]
+    if op.abspath(op.curdir) == op.abspath(directory):
+        # ensure current directory is not the test directory, which would cause the test to be too easy
+        os.chdir('..')
+    filetree.FileTree.read(op.join(directory, 'local_parent.tree'))
-- 
GitLab