diff --git a/doc/contributing.rst b/doc/contributing.rst
index ef710683b31c8094be90fe39a44d85d2e3e20be4..f4cda099f9d046843a482363bfa77758bd8ff6ce 100644
--- a/doc/contributing.rst
+++ b/doc/contributing.rst
@@ -144,6 +144,7 @@ for a list of error codes):
 - E302: expected 2 blank lines, found 0
 - E303: too many blank lines (3)
 - E701: multiple statements on one line (colon)
+- W504: line break after binary operator
 
 
 The ``pylint`` tool can be *very* opinionated about how you write your code,
@@ -162,7 +163,7 @@ refactoring and convention messages, and a few select warnings (type ``pylint
 To check code with ``flake8`` and ``pylint``, I use the following commands::
 
 
-  flake8 --ignore=E127,E201,E203,E221,E222,E241,E271,E272,E301,E302,E303,E701 fsl
+  flake8 --ignore=E127,E201,E203,E221,E222,E241,E271,E272,E301,E302,E303,E701,W504 fsl
   pylint --extension-pkg-whitelist=numpy,wx \
          --generated-members=np.int8,np.uint8,np.int16,np.uint16,np.int32,np.uint32,np.int64,np.uint64,np.float32,np.float64,np.float128,wx.PyDeadObjectError \
          --disable=R,C,W0511,W0703,W1202 fsl
diff --git a/fsl/utils/filetree/query.py b/fsl/utils/filetree/query.py
index 49433fa546384f4ce4f03b95bf786ce0f6d64a95..ac66091cd60c9fe273b0d939cfd20c3338bbeb7c 100644
--- a/fsl/utils/filetree/query.py
+++ b/fsl/utils/filetree/query.py
@@ -6,7 +6,7 @@
 # Author: Michiel Cottaar <michiel.cottaar@.ndcn.ox.ac.uk>
 #
 """This module contains the :class:`FileTreeQuery` class, which can be used to
-search for files in a directory described by a `.FileTree`. A
+search for files in a directory described by a :class:`.FileTree`. A
 ``FileTreeQuery`` object returns :class:`Match` objects which each represent a
 file that is described by the ``FileTree``, and which is present in the
 directory.
@@ -22,8 +22,9 @@ defined in this module:
 """
 
 
-import logging
-import collections
+import              logging
+import              collections
+import functools as ft
 
 import os.path as op
 from typing import Dict, List, Tuple
@@ -121,6 +122,12 @@ class FileTreeQuery(object):
 
             tvarlens = [len(allvars[v]) for v in tvars]
 
+            # "Scalar" match objects - templates
+            # which have no variables, and for
+            # which zero or one file is present
+            if len(tvarlens) == 0:
+                tvarlens = 1
+
             # An ND array for this short
             # name. Each element is a
             # Match object, or nan.
@@ -142,10 +149,13 @@ class FileTreeQuery(object):
             tvaridxs = varidxs[     match.full_name]
             tarr     = matcharrays[ match.full_name]
             idx      = []
-            for var in tvars:
 
-                val = match.variables[var]
-                idx.append(tvaridxs[var][val])
+            if len(match.variables) == 0:
+                idx = [0]
+            else:
+                for var in tvars:
+                    val = match.variables[var]
+                    idx.append(tvaridxs[var][val])
 
             tarr[tuple(idx)] = match
 
@@ -253,6 +263,7 @@ class FileTreeQuery(object):
         else:       return [m for m in result.flat if isinstance(m, Match)]
 
 
+@ft.total_ordering
 class Match(object):
     """A ``Match`` object represents a file with a name matching a template in
     a ``FileTree``.  The :func:`scan` function and :meth:`FileTree.query`
@@ -338,10 +349,6 @@ class Match(object):
         return isinstance(other, Match) and self.filename < other.filename
 
 
-    def __le__(self, other):
-        return isinstance(other, Match) and self.filename <= other.filename
-
-
     def __repr__(self):
         """Returns a string representation of this ``Match``. """
         return 'Match({}: {})'.format(self.full_name, self.filename)
@@ -397,9 +404,13 @@ def allVariables(
                  containing the variables which are relevant to each template.
     """
     allvars      = collections.defaultdict(set)
-    alltemplates = collections.defaultdict(set)
+    alltemplates = {}
 
     for m in matches:
+
+        if m.full_name not in alltemplates:
+            alltemplates[m.full_name] = set()
+
         for var, val in m.variables.items():
             allvars[     var]        .add(val)
             alltemplates[m.full_name].add(var)
@@ -411,7 +422,7 @@ def allVariables(
 
     allvars      = {var : list(sorted(vals, key=key))
                     for var, vals in allvars.items()}
-    alltemplates = {sn  : list(sorted(vars))
-                    for sn, vars in alltemplates.items()}
+    alltemplates = {tn  : list(sorted(vars))
+                    for tn, vars in alltemplates.items()}
 
     return allvars, alltemplates
diff --git a/setup.cfg b/setup.cfg
index 0c604f57e04cd74faf4721accfb0353964f80ebf..3f611406bec88d7cf6c581943a063647ee3b009e 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -22,4 +22,4 @@ testpaths = tests
 addopts   = -v --niters=50 --cov=fsl -m "not longtest"
 
 [flake8]
-ignore = E127,E201,E203,E221,E222,E241,E271,E272,E301,E302,E303,E701
\ No newline at end of file
+ignore = E127,E201,E203,E221,E222,E241,E271,E272,E301,E302,E303,E701,W504
\ No newline at end of file
diff --git a/tests/test_filetree/test_query.py b/tests/test_filetree/test_query.py
index 274604312e5fdbe536abc3d24bb8ec8f4a662606..3d4bef6db3f229b88f0a7dfef21b38d41a1cb166 100644
--- a/tests/test_filetree/test_query.py
+++ b/tests/test_filetree/test_query.py
@@ -25,6 +25,7 @@ subj-{participant}
     T1w.nii.gz (T1w)
     T2w.nii.gz (T2w)
     {hemi}.{surf}.gii (surface)
+scalar_file.txt (scalar)
 """.strip()
 
 _subjs = ['01', '02', '03']
@@ -36,7 +37,7 @@ _surfs = ['midthickness', 'pial', 'white']
 @contextlib.contextmanager
 def _test_data():
 
-    files = []
+    files = ['scalar_file.txt']
 
     for subj, ses in it.product(_subjs, _sess):
         sesdir = op.join('subj-{}'.format(subj), 'ses-{}'.format(ses))
@@ -60,6 +61,12 @@ def _expected_matches(template, tree, **kwargs):
     surfs   = kwargs.get('surf',        _surfs)
     hemis   = kwargs.get('hemi',        _hemis)
 
+    if template == 'scalar':
+        matches.append(ftquery.Match('scalar_file.txt',
+                                     template,
+                                     tree,
+                                     {}))
+
     for subj, ses in it.product(subjs, sess):
 
         sesdir = op.join('subj-{}'.format(subj), 'ses-{}'.format(ses))
@@ -100,7 +107,10 @@ def _run_and_check_query(query, template, asarray=False, **vars):
     else:
         snvars = query.variables(template)
 
-        assert len(snvars) == len(gotmatches.shape)
+        if len(snvars) == 0:
+            assert gotmatches.shape == (1,)
+        else:
+            assert len(snvars) == len(gotmatches.shape)
 
         for i, var in enumerate(sorted(snvars.keys())):
             if var not in vars or vars[var] == '*':
@@ -124,30 +134,32 @@ def test_query_properties():
         tree  = filetree.FileTree.read('_test_tree.tree', '.')
         query = filetree.FileTreeQuery(tree)
 
+        assert sorted(query.axes('scalar'))  == []
         assert sorted(query.axes('T1w'))     == ['participant', 'session']
         assert sorted(query.axes('T2w'))     == ['participant', 'session']
         assert sorted(query.axes('surface')) == ['hemi',
                                                  'participant',
                                                  'session',
                                                  'surf']
-        assert sorted(query.templates)       == ['T1w', 'T2w', 'surface']
-
-        assert query.variables('T1w')     == {'participant' : ['01', '02', '03'],
-                                              'session'     : ['1', '2']}
-        assert query.variables('T2w')     == {'participant' : ['01', '02', '03'],
-                                              'session'     : ['1', '2']}
-        assert query.variables('surface') == {'participant' : ['01', '02', '03'],
-                                              'session'     : ['1', '2'],
-                                              'surf'        : ['midthickness',
-                                                               'pial',
-                                                               'white'],
-                                              'hemi'        : ['L', 'R']}
-        assert query.variables()          == {'participant' : ['01', '02', '03'],
-                                              'session'     : ['1', '2'],
-                                              'surf'        : ['midthickness',
-                                                               'pial',
-                                                               'white'],
-                                              'hemi'        : ['L', 'R']}
+        assert sorted(query.templates)       == ['T1w', 'T2w', 'scalar', 'surface']
+
+        assert query.variables('scalar')     == {}
+        assert query.variables('T1w')        == {'participant' : ['01', '02', '03'],
+                                                 'session'     : ['1', '2']}
+        assert query.variables('T2w')        == {'participant' : ['01', '02', '03'],
+                                                 'session'     : ['1', '2']}
+        assert query.variables('surface')    == {'participant' : ['01', '02', '03'],
+                                                 'session'     : ['1', '2'],
+                                                 'surf'        : ['midthickness',
+                                                                  'pial',
+                                                                  'white'],
+                                                 'hemi'        : ['L', 'R']}
+        assert query.variables()             == {'participant' : ['01', '02', '03'],
+                                                 'session'     : ['1', '2'],
+                                                 'surf'        : ['midthickness',
+                                                                  'pial',
+                                                                  'white'],
+                                                 'hemi'        : ['L', 'R']}
 
 
 def test_query():
@@ -155,6 +167,7 @@ def test_query():
         tree  = filetree.FileTree.read('_test_tree.tree', '.')
         query = filetree.FileTreeQuery(tree)
 
+    _run_and_check_query(query, 'scalar')
     _run_and_check_query(query, 'T1w')
     _run_and_check_query(query, 'T1w', participant='01')
     _run_and_check_query(query, 'T1w', session='2')
@@ -269,6 +282,7 @@ def test_query_asarray():
         tree  = filetree.FileTree.read('_test_tree.tree', '.')
         query = filetree.FileTreeQuery(tree)
 
+        _run_and_check_query(query, 'scalar', asarray=True)
         _run_and_check_query(query, 'T1w', asarray=True)
         _run_and_check_query(query, 'T1w', asarray=True, participant='01')
         _run_and_check_query(query, 'T1w', asarray=True, session='2')
@@ -388,7 +402,10 @@ def test_scan():
         tree    = filetree.FileTree.read('_test_tree.tree', '.')
         gotmatches = ftquery.scan(tree)
 
-    expmatches = []
+    expmatches = [ftquery.Match('scalar_file.txt',
+                                'scalar',
+                                tree,
+                                {})]
 
     for subj, ses in it.product(_subjs, _sess):
 
@@ -416,6 +433,8 @@ def test_scan():
     assert len(gotmatches) == len(expmatches)
 
     for got, exp in zip(sorted(gotmatches), sorted(expmatches)):
+        assert got            == exp
+        assert str(got)       == str(exp)
         assert got.filename   == exp.filename
         assert got.template   == exp.template
         assert got.variables  == exp.variables
@@ -433,6 +452,7 @@ def test_allVariables():
             'surf'        : _surfs,
             'hemi'        : _hemis}
         expsnames = {
+            'scalar'  : [],
             'T1w'     : ['participant', 'session'],
             'T2w'     : ['participant', 'session'],
             'surface' : ['hemi', 'participant', 'session', 'surf']}