Example #1
0
    def test_filter(self):
        query1 = Query(['col1'])
        query2 = query1.filter(lambda x: x == 'a')
        self.assertIsNot(query1, query2, 'should return new object')

        source = Selector([('col1', 'col2'), ('a', '2'), ('b', '2')])
        result = query2.execute(source)
        self.assertEqual(result.fetch(), ['a'])

        # No filter arg should default to bool()
        source = Selector([('col1', ), (1, ), (2, ), (0, ), (3, )])
        query = Query(set(['col1'])).filter()  # <- No arg!
        result = query.execute(source)
        self.assertEqual(result.fetch(), set([1, 2, 3]))
Example #2
0
    def test_execute_query(self):
        data = [['A', 'B'], ['x', 101], ['y', 202], ['z', 303]]
        source = Selector(data)

        # Test where-clause function.
        def isodd(x):
            return x % 2 == 1

        result = source('A', B=isodd).fetch()
        self.assertEqual(result, ['x', 'z'])

        # Test replacing function.
        def iseven(x):
            return x % 2 == 0

        result = source('A', B=iseven).fetch()
        self.assertEqual(result, ['y'])

        # Test callable-but-unhashable.
        class IsEven(object):
            __hash__ = None

            def __call__(self, x):
                return x % 2 == 0

        unhashable_iseven = IsEven()
        result = source('A', B=unhashable_iseven).fetch()
        self.assertEqual(result, ['y'])
Example #3
0
    def test__copy__(self):
        # Select-arg only.
        query = Query(['B'])
        copied = query.__copy__()
        self.assertIs(copied.source, query.source)
        self.assertEqual(copied.args, query.args)
        self.assertEqual(copied.kwds, query.kwds)
        self.assertEqual(copied._query_steps, query._query_steps)
        self.assertIsNot(copied.kwds, query.kwds)
        self.assertIsNot(copied._query_steps, query._query_steps)

        # Select and keyword.
        query = Query(['B'], C='x')
        copied = query.__copy__()
        self.assertIs(copied.source, query.source)
        self.assertEqual(copied.args, query.args)
        self.assertEqual(copied.kwds, query.kwds)
        self.assertEqual(copied._query_steps, query._query_steps)

        # Source, columns, and keyword.
        source = Selector([('A', 'B'), (1, 2), (1, 2)])
        query = Query(source, ['B'])
        copied = query.__copy__()
        self.assertIs(copied.source, query.source)
        self.assertEqual(copied.args, query.args)
        self.assertEqual(copied.kwds, query.kwds)
        self.assertEqual(copied._query_steps, query._query_steps)

        # Select and additional query methods.
        query = Query(['B']).map(lambda x: str(x).upper())
        copied = query.__copy__()
        self.assertIs(copied.source, query.source)
        self.assertEqual(copied.args, query.args)
        self.assertEqual(copied.kwds, query.kwds)
        self.assertEqual(copied._query_steps, query._query_steps)
Example #4
0
    def test_map(self):
        query1 = Query(['col2'])
        query2 = query1.map(int)
        self.assertIsNot(query1, query2, 'should return new object')

        source = Selector([('col1', 'col2'), ('a', '2'), ('b', '2')])
        result = query2.execute(source)
        self.assertEqual(result.fetch(), [2, 2])
Example #5
0
    def test_reduce(self):
        query1 = Query(['col1'])
        query2 = query1.reduce(lambda x, y: x + y)
        self.assertIsNot(query1, query2, 'should return new object')

        source = Selector([('col1', 'col2'), ('a', '2'), ('b', '2')])
        result = query2.execute(source)
        self.assertEqual(result, 'ab')
Example #6
0
 def test_fetch_datasource(self):
     select = Selector([('A', 'B'), ('1', '2'), ('1', '2')])
     query = Query(select, ['B'])
     query._query_steps = [
         ('map', (int, ), {}),
         ('map', (lambda x: x * 2, ), {}),
         ('sum', (), {}),
     ]
     result = query.fetch()
     self.assertEqual(result, 8)
Example #7
0
    def test_init_with_selector(self):
        source = Selector([('A', 'B'), (1, 2), (1, 2)])
        query = Query(source, ['A'], B=2)
        self.assertEqual(query.source, source)
        self.assertEqual(query.args, (['A'], ))
        self.assertEqual(query.kwds, {'B': 2})
        self.assertEqual(query._query_steps, [])

        with self.assertRaises(TypeError):
            query = Query(None, ['foo'], bar='baz')
Example #8
0
    def test_init_with_invalid_args(self):
        # Missing args.
        with self.assertRaises(TypeError, msg='should require select args'):
            Query()

        # Bad "select" field.
        source = Selector([('A', 'B'), (1, 2), (1, 2)])
        with self.assertRaises(
                LookupError,
                msg=
                'should fail immediately when fieldname conflicts with provided source'
        ):
            query = Query(source, ['X'], B=2)

        # Bad "where" field.
        source = Selector([('A', 'B'), (1, 2), (1, 2)])
        with self.assertRaises(
                LookupError,
                msg=
                'should fail immediately when fieldname conflicts with provided "where" field'
        ):
            query = Query(source, ['A'], Y=2)
Example #9
0
    def test_repr(self):
        data = [['A', 'B'], ['x', 100], ['y', 200]]

        # Empty selector.
        select = Selector()
        regex = ('^<datatest.Selector object at [^\n>]+>\n'
                 'Empty - contains no data\.$')
        self.assertRegex(repr(select), regex)

        # Data-only (no args)
        source = Selector(data)
        regex = ("^<datatest.Selector object at [^\n>]+>\n"
                 "Data from 1 source:\n"
                 " {0}$".format(re.escape(repr(data))))
        self.assertRegex(repr(source), regex)

        # Data with args and kwds.
        iterable = iter(data)
        source = Selector(iterable, 'foo',
                          bar='baz')  # Args don't change repr.
        regex = ('<datatest.Selector object at [^\n>]+>\n'
                 'Data from 1 source:\n'
                 ' <[a-z_]+ object at [^\n>]+>')
        self.assertRegex(repr(source), regex)

        # Extended after instantiation.
        data1 = [['A', 'B'], ['x', 100]]
        data2 = [['A', 'B'], ['y', 200]]
        data3 = [['A', 'B'], ['z', 300]]
        source = Selector(data1)
        source.load_data(data2)
        source.load_data(data3)

        actual_repr = repr(source)
        self.assertTrue(actual_repr.startswith('<datatest.Selector object at'))
        self.assertTrue(
            actual_repr.endswith(">\n"
                                 "Data from 3 sources:\n"
                                 " [['A', 'B'], ['x', 100]]\n"
                                 " [['A', 'B'], ['y', 200]]\n"
                                 " [['A', 'B'], ['z', 300]]"))
Example #10
0
    def test_execute_datasource(self):
        select = Selector([('A', 'B'), ('1', '2'), ('1', '2')])
        query = Query(select, ['B'])
        query._query_steps = [
            ('map', (int, ), {}),
            ('map', (lambda x: x * 2, ), {}),
            ('sum', (), {}),
        ]
        result = query.execute()
        self.assertEqual(result, 8)

        query = Query(['A'])
        regex = "expected 'Selector', got 'list'"
        with self.assertRaisesRegex(TypeError, regex):
            query.execute(['hello',
                           'world'])  # <- Expects None or Query, not list!
Example #11
0
    def test_repr(self):
        # Check "no selector" signature.
        query = Query(['label1'])
        regex = r"Query\(\[u?'label1'\]\)"
        self.assertRegex(repr(query), regex)

        # Check "no selector" with keyword string.
        query = Query(['label1'], label2='x')
        regex = r"Query\(\[u?'label1'\], label2='x'\)"
        self.assertRegex(repr(query), regex)

        # Check "no selector" with keyword list.
        query = Query(['label1'], label2=['x', 'y'])
        regex = r"Query\(\[u?'label1'\], label2=\[u?'x', u?'y'\]\)"
        self.assertRegex(repr(query), regex)

        # Check "selector-provided" signature.
        select = Selector([('A', 'B'), ('x', 1), ('y', 2), ('z', 3)])
        query = Query(select, ['B'])
        short_repr = super(Selector, select).__repr__()
        expected = "Query({0}, {1!r})".format(short_repr, ['B'])
        #print(repr(query))
        self.assertEqual(repr(query), expected)

        # Check "from_object" signature.
        query = Query.from_object([1, 2, 3])
        expected = "Query.from_object([1, 2, 3])"
        self.assertEqual(repr(query), expected)

        # Check query steps.
        query = Query(['label1']).distinct().count()
        regex = r"Query\(\[u?'label1'\]\).distinct\(\).count\(\)"
        self.assertRegex(repr(query), regex)

        # Check query steps with function argument.
        def upper(x):
            return str(x.upper())

        query = Query(['label1']).map(upper)
        regex = r"Query\(\[u?'label1'\]\).map\(upper\)"
        self.assertRegex(repr(query), regex)

        # Check query steps with lambda argument.
        lower = lambda x: str(x).lower()
        query = Query(['label1']).map(lower)
        regex = r"Query\(\[u?'label1'\]\).map\(<lambda>\)"
        self.assertRegex(repr(query), regex)
Example #12
0
    def test_load_data(self):
        select = Selector()  # <- Empty selector.
        self.assertEqual(select.fieldnames, [])

        readerlike1 = [['col1', 'col2'], ['a', 1], ['b', 2]]
        select.load_data(readerlike1)
        self.assertEqual(select.fieldnames, ['col1', 'col2'])

        readerlike2 = [['col1', 'col3'], ['c', 'x'], ['d', 'y']]
        select.load_data(readerlike2)
        self.assertEqual(select.fieldnames, ['col1', 'col2', 'col3'])
Example #13
0
 def test_query_objects(self):
     source = Selector([('A', 'B'), ('1', '2'), ('1', '2')])
     query_obj1 = source(['B'])
     query_obj2 = source(['B'])
     self.assertValid(query_obj1, query_obj2)
Example #14
0
 def setUp(self):
     data = [['label1', 'label2', 'value'], ['a', 'x', '17'],
             ['a', 'x', '13'], ['a', 'y', '20'], ['a', 'z', '15'],
             ['b', 'z', '5'], ['b', 'y', '40'], ['b', 'x', '25']]
     self.source = Selector(data)
Example #15
0
 def test_empty_selector(self):
     select = Selector()
Example #16
0
    def test_fieldnames(self):
        expected = ['label1', 'label2', 'value']
        self.assertEqual(self.source.fieldnames, expected)

        select = Selector()  # <- Empty selector.
        self.assertEqual(select.fieldnames, [], msg='should be empty list')
Example #17
0
    def test_repr(self):
        data = [['A', 'B'], ['x', 100], ['y', 200]]

        # Empty selector.
        select = Selector()
        self.assertEqual(repr(select), '<Selector (no data loaded)>')

        # Data-only (no args)
        select = Selector(data)
        expected = "<Selector [['A', 'B'], ['x', 100], ['y', 200]]>"
        self.assertEqual(repr(select), expected)

        # Data with args (args don't affect repr)
        iterable = iter(data)
        select = Selector(iterable, 'foo', bar='baz')
        regex = '<Selector <[a-z_]+ object at [^\n>]+>>'
        self.assertRegex(repr(select), regex)

        # Extended after instantiation.
        select = Selector()
        select.load_data([['A', 'B'], ['z', 300]])
        select.load_data([['A', 'B'], ['y', 200]])
        select.load_data([['A', 'B'], ['x', 100]])

        expected = ("<Selector (3 sources):\n"
                    "    [['A', 'B'], ['x', 100]]\n"
                    "    [['A', 'B'], ['y', 200]]\n"
                    "    [['A', 'B'], ['z', 300]]>")
        self.assertEqual(repr(select), expected)

        # Test long repr truncation.
        select = Selector([
            ['xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'],
            ['yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'],
        ])

        self.assertEqual(len(repr(select)), 72)

        expected = "<Selector [['xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'], ['yyyyyyyyyyy...yyyyy']]>"
        self.assertEqual(repr(select), expected)
Example #18
0
 def test_Query(self):
     source = Selector([('A', 'B'), ('x', 1), ('y', 2)])
     query = source({'A': 'B'}).apply(lambda x: next(x))
     normalized = DictItems(query)
     self.assertEqual(list(normalized), [('x', 1), ('y', 2)])
Example #19
0
class TestSelector(unittest.TestCase):
    def setUp(self):
        data = [['label1', 'label2', 'value'], ['a', 'x', '17'],
                ['a', 'x', '13'], ['a', 'y', '20'], ['a', 'z', '15'],
                ['b', 'z', '5'], ['b', 'y', '40'], ['b', 'x', '25']]
        self.source = Selector(data)

    def test_empty_selector(self):
        select = Selector()

    def test_fieldnames(self):
        expected = ['label1', 'label2', 'value']
        self.assertEqual(self.source.fieldnames, expected)

        select = Selector()  # <- Empty selector.
        self.assertEqual(select.fieldnames, [], msg='should be empty list')

    def test_load_data(self):
        select = Selector()  # <- Empty selector.
        self.assertEqual(select.fieldnames, [])

        readerlike1 = [['col1', 'col2'], ['a', 1], ['b', 2]]
        select.load_data(readerlike1)
        self.assertEqual(select.fieldnames, ['col1', 'col2'])

        readerlike2 = [['col1', 'col3'], ['c', 'x'], ['d', 'y']]
        select.load_data(readerlike2)
        self.assertEqual(select.fieldnames, ['col1', 'col2', 'col3'])

    def test_repr(self):
        data = [['A', 'B'], ['x', 100], ['y', 200]]

        # Empty selector.
        select = Selector()
        self.assertEqual(repr(select), '<Selector (no data loaded)>')

        # Data-only (no args)
        select = Selector(data)
        expected = "<Selector [['A', 'B'], ['x', 100], ['y', 200]]>"
        self.assertEqual(repr(select), expected)

        # Data with args (args don't affect repr)
        iterable = iter(data)
        select = Selector(iterable, 'foo', bar='baz')
        regex = '<Selector <[a-z_]+ object at [^\n>]+>>'
        self.assertRegex(repr(select), regex)

        # Extended after instantiation.
        select = Selector()
        select.load_data([['A', 'B'], ['z', 300]])
        select.load_data([['A', 'B'], ['y', 200]])
        select.load_data([['A', 'B'], ['x', 100]])

        expected = ("<Selector (3 sources):\n"
                    "    [['A', 'B'], ['x', 100]]\n"
                    "    [['A', 'B'], ['y', 200]]\n"
                    "    [['A', 'B'], ['z', 300]]>")
        self.assertEqual(repr(select), expected)

        # Test long repr truncation.
        select = Selector([
            ['xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'],
            ['yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'],
        ])

        self.assertEqual(len(repr(select)), 72)

        expected = "<Selector [['xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'], ['yyyyyyyyyyy...yyyyy']]>"
        self.assertEqual(repr(select), expected)

    def test_build_where_clause(self):
        _build_where_clause = Selector._build_where_clause

        result = _build_where_clause({'A': 'x'})
        expected = ('A=?', ['x'])
        self.assertEqual(result, expected)

        result = _build_where_clause({'A': ['x', 'y']})
        expected = ('A IN (?, ?)', ['x', 'y'])
        self.assertEqual(result, expected)

        userfunc = lambda x: len(x) == 1
        result = _build_where_clause({'A': userfunc})
        expected = ('FUNC{0}(A)'.format(id(userfunc)), [])
        self.assertEqual(result, expected)

    def test_execute_query(self):
        data = [['A', 'B'], ['x', 101], ['y', 202], ['z', 303]]
        source = Selector(data)

        # Test where-clause function.
        def isodd(x):
            return x % 2 == 1

        result = source('A', B=isodd).fetch()
        self.assertEqual(result, ['x', 'z'])

        # Test replacing function.
        def iseven(x):
            return x % 2 == 0

        result = source('A', B=iseven).fetch()
        self.assertEqual(result, ['y'])

        # Test callable-but-unhashable.
        class IsEven(object):
            __hash__ = None

            def __call__(self, x):
                return x % 2 == 0

        unhashable_iseven = IsEven()
        result = source('A', B=unhashable_iseven).fetch()
        self.assertEqual(result, ['y'])

    def test_iter(self):
        """Test __iter__."""
        result = [row for row in self.source]
        expected = [
            {
                'label1': 'a',
                'label2': 'x',
                'value': '17'
            },
            {
                'label1': 'a',
                'label2': 'x',
                'value': '13'
            },
            {
                'label1': 'a',
                'label2': 'y',
                'value': '20'
            },
            {
                'label1': 'a',
                'label2': 'z',
                'value': '15'
            },
            {
                'label1': 'b',
                'label2': 'z',
                'value': '5'
            },
            {
                'label1': 'b',
                'label2': 'y',
                'value': '40'
            },
            {
                'label1': 'b',
                'label2': 'x',
                'value': '25'
            },
        ]
        self.assertEqual(expected, result)

    def test_select_list_of_strings(self):
        result = self.source._select(['label1'])
        expected = ['a', 'a', 'a', 'a', 'b', 'b', 'b']
        self.assertEqual(result.fetch(), expected)

    def test_select_tuple_of_strings(self):
        result = self.source._select(('label1', ))
        expected = ('a', 'a', 'a', 'a', 'b', 'b', 'b')
        self.assertEqual(result.fetch(), expected)

    def test_select_set_of_strings(self):
        result = self.source._select(set(['label1']))
        expected = set(['a', 'b'])
        self.assertEqual(result.fetch(), expected)

    def test_select_field_not_found(self):
        with self.assertRaises(LookupError):
            result = self.source._select(['bad_field_name'])

    def test_select_list_of_lists(self):
        result = self.source._select([['label1']])
        expected = [['a'], ['a'], ['a'], ['a'], ['b'], ['b'], ['b']]
        self.assertEqual(result.fetch(), expected)

        result = self.source._select([['label1', 'label2']])
        expected = [['a', 'x'], ['a', 'x'], ['a', 'y'], ['a', 'z'], ['b', 'z'],
                    ['b', 'y'], ['b', 'x']]
        self.assertEqual(result.fetch(), expected)

    def test_select_list_of_tuples(self):
        result = self.source._select([('label1', )])
        expected = [('a', ), ('a', ), ('a', ), ('a', ), ('b', ), ('b', ),
                    ('b', )]
        self.assertEqual(result.fetch(), expected)

    def test_select_list_of_namedtuples(self):
        namedtup = collections.namedtuple('namedtup', ['label1', 'label2'])
        result = self.source._select([namedtup('label1', 'label2')])
        expected = [
            namedtup(label1='a', label2='x'),
            namedtup(label1='a', label2='x'),
            namedtup(label1='a', label2='y'),
            namedtup(label1='a', label2='z'),
            namedtup(label1='b', label2='z'),
            namedtup(label1='b', label2='y'),
            namedtup(label1='b', label2='x')
        ]
        self.assertEqual(result.fetch(), expected)

    def test_select_set_of_frozensets(self):
        result = self.source._select(set([frozenset(['label1'])]))
        expected = set([
            frozenset(['a']),
            frozenset(['a']),
            frozenset(['a']),
            frozenset(['a']),
            frozenset(['b']),
            frozenset(['b']),
            frozenset(['b'])
        ])
        self.assertEqual(result.fetch(), expected)

    def test_select_dict(self):
        result = self.source._select({'label1': ['value']})
        expected = {
            'a': ['17', '13', '20', '15'],
            'b': ['5', '40', '25'],
        }
        self.assertEqual(result.fetch(), expected)

    def test_select_dict2(self):
        result = self.source._select({('label1', 'label2'): ['value']})
        expected = {
            ('a', 'x'): ['17', '13'],
            ('a', 'y'): ['20'],
            ('a', 'z'): ['15'],
            ('b', 'x'): ['25'],
            ('b', 'y'): ['40'],
            ('b', 'z'): ['5'],
        }
        self.assertEqual(result.fetch(), expected)

    def test_select_dict3(self):
        result = self.source._select({('label1', 'label2'): [['value']]})
        expected = {
            ('a', 'x'): [['17'], ['13']],
            ('a', 'y'): [['20']],
            ('a', 'z'): [['15']],
            ('b', 'x'): [['25']],
            ('b', 'y'): [['40']],
            ('b', 'z'): [['5']],
        }
        self.assertEqual(result.fetch(), expected)

    def test_select_dict_with_namedtuple_keys(self):
        namedtup = collections.namedtuple('namedtup', ['x', 'y'])
        result = self.source._select({namedtup('label1', 'label2'): ['value']})
        expected = {
            namedtup(x='a', y='x'): ['17', '13'],
            namedtup(x='a', y='y'): ['20'],
            namedtup(x='a', y='z'): ['15'],
            namedtup(x='b', y='x'): ['25'],
            namedtup(x='b', y='y'): ['40'],
            namedtup(x='b', y='z'): ['5'],
        }
        self.assertEqual(result.fetch(), expected)

    def test_select_dict_with_values_container2(self):
        result = self.source._select({'label1': [('label2', 'label2')]})
        expected = {
            'a': [('x', 'x'), ('x', 'x'), ('y', 'y'), ('z', 'z')],
            'b': [('z', 'z'), ('y', 'y'), ('x', 'x')]
        }
        self.assertEqual(result.fetch(), expected)

        result = self.source._select({'label1': [set(['label2', 'label2'])]})
        expected = {
            'a': [set(['x']), set(['x']),
                  set(['y']), set(['z'])],
            'b': [set(['z']), set(['y']), set(['x'])],
        }
        self.assertEqual(result.fetch(), expected)

    def test_select_alternate_mapping_type(self):
        class CustomDict(dict):
            pass

        result = self.source._select(CustomDict({'label1': ['value']}))
        result = result.fetch()
        expected = {
            'a': ['17', '13', '20', '15'],
            'b': ['5', '40', '25'],
        }
        self.assertIsInstance(result, CustomDict)
        self.assertEqual(result, expected)

    def test_select_distinct(self):
        result = self.source._select_distinct(['label1'])
        expected = ['a', 'b']
        self.assertEqual(list(result), expected)

        result = self.source._select_distinct({'label1': ['label2']})
        result = result.fetch()
        expected = {'a': ['x', 'y', 'z'], 'b': ['z', 'y', 'x']}

        self.assertIsInstance(result, dict)

        # Sort values for SQLite versions earlier than 3.7.12
        if (3, 7, 12) > sqlite3.sqlite_version_info:
            sortvalues = lambda x: dict((k, sorted(v)) for k, v in x.items())
            result = sortvalues(result)
            expected = sortvalues(expected)
        self.assertEqual(result, expected)

    def test_select_aggregate(self):
        # Not grouped, single result.
        result = self.source._select_aggregate('COUNT', ['label2'])
        self.assertEqual(result, 7)

        # Not grouped, single result as set.
        result = self.source._select_aggregate('COUNT', set(['label2']))
        self.assertEqual(result, 3)

        # Not grouped, multiple results.
        result = self.source._select_aggregate('SUM', [['value', 'value']])
        self.assertEqual(result, [135, 135])

        # Simple group by (grouped by keys).
        result = self.source._select_aggregate('SUM', {'label1': ['value']})
        self.assertIsInstance(result, Result)

        expected = {
            'a': 65,
            'b': 70,
        }
        self.assertEqual(result.fetch(), expected)

        # Composite value.
        result = self.source._select_aggregate(
            'SUM', {'label1': [('value', 'value')]})
        expected = {
            'a': (65, 65),
            'b': (70, 70),
        }
        self.assertEqual(dict(result), expected)

        # Composite key and composite value.
        result = self.source._select_aggregate(
            'SUM', {('label1', 'label1'): [['value', 'value']]})
        expected = {
            ('a', 'a'): [65, 65],
            ('b', 'b'): [70, 70],
        }
        self.assertEqual(dict(result), expected)

    def test_call(self):
        query = self.source(['label1'])
        expected = ['a', 'a', 'a', 'a', 'b', 'b', 'b']
        self.assertIsInstance(query, Query)
        self.assertEqual(query.fetch(), expected)

        query = self.source([('label1', 'label2')])
        expected = [('a', 'x'), ('a', 'x'), ('a', 'y'), ('a', 'z'), ('b', 'z'),
                    ('b', 'y'), ('b', 'x')]
        self.assertIsInstance(query, Query)
        self.assertEqual(query.fetch(), expected)

        query = self.source([set(['label1', 'label2'])])
        expected = [
            set(['a', 'x']),
            set(['a', 'x']),
            set(['a', 'y']),
            set(['a', 'z']),
            set(['b', 'z']),
            set(['b', 'y']),
            set(['b', 'x'])
        ]
        self.assertIsInstance(query, Query)
        self.assertEqual(query.fetch(), expected)

        query = self.source({'label1': ['label2']})
        expected = {'a': ['x', 'x', 'y', 'z'], 'b': ['z', 'y', 'x']}
        self.assertIsInstance(query, Query)
        self.assertEqual(query.fetch(), expected)