Example #1
0
    def testProduct(self):
        # Multiplying a constant to a list, adds it to each element.
        query = q.Query(
            "SELECT ages * 10 as x FROM (bind('ages': [10, 20, 30]))")

        value = list(solve.solve(query, {}).value)
        x = structured.resolve(value[0], "x")
        self.assertEqual(x, [100, 200, 300])

        # Multiplying a constant to a list, multiply each element.
        query = q.Query(
            "10 * (SELECT age FROM (bind('age': 10), bind('age': 20)))")

        value = list(solve.solve(query, {}).value)
        self.assertEqual(value, [100, 200])

        # Multiplying two subselects multiplies each element.
        query = q.Query(
            """(SELECT age FROM (bind('age': 10), bind('age': 20))) *
               (SELECT age FROM (bind('age': 20), bind('age': 30)))
            """)

        value = list(solve.solve(query, {}).value)
        self.assertEqual(value, [200, 600])

        self.assertEqual(
            solve.solve(q.Query("5 * 5 * 5"),
                        mocks.Process(1, None, None)).value, [125])
Example #2
0
    def testSum(self):
        # Adding a constant to a list, adds it to each element.
        query = q.Query(
            "SELECT ages + 10 as sum FROM (bind('ages': [10, 20, 30]))")

        value = list(solve.solve(query, {}).value)
        sum = structured.resolve(value[0], "sum")
        self.assertEqual(sum, [20, 30, 40])

        # Adding a list to a list, pads the short list with zeros.
        query = q.Query(
            "SELECT ages + [10, 20] as sum FROM (bind('ages': [10, 20, 30]))")

        value = list(solve.solve(query, {}).value)
        sum = structured.resolve(value[0], "sum")
        self.assertEqual(sum, [20, 40, 30])

        # Repeated integers add item by item to the
        query = q.Query(
            "[5, 1, 2] + 10 + SELECT age FROM"
            " (bind('age': 10, 'name': 'Tom'), bind('age': 8, 'name': 'Jerry'))"
            " WHERE name == 'Jerry'")
        self.assertEqual(solve.solve(query, {}).value, [23, 11, 12])

        self.assertEqual(
            solve.solve(q.Query("5 + 15 + 25"),
                        mocks.Process(1, None, None)).value, [45])
Example #3
0
    def testSort(self):
        self.assertEqual(
            solve.solve(
                q.Query("select * from Process order by pid"),
                {"Process": repeated.meld(mocks.Process(2, None, None), mocks.Process(1, None, None))},
            ).value,
            repeated.meld(mocks.Process(1, None, None), mocks.Process(2, None, None)),
        )

        # How about nested repeated fields? This should sort the process
        # children and return those.
        self.assertEqual(
            solve.solve(
                q.Query("select * from Process.children order by pid"),
                {"Process": {"children": repeated.meld(mocks.Process(2, None, None), mocks.Process(1, None, None))}},
            ).value,
            repeated.meld(mocks.Process(1, None, None), mocks.Process(2, None, None)),
        )

        # Sorting BY a repeated expression should be the same as sorting by
        # a tuple.
        self.assertEqual(
            solve.solve(
                q.Query("select name, surname from people order by " "[lower(surname), lower(name)]"),
                {
                    "people": [
                        {"name": "John", "surname": "Smith"},
                        {"name": "John", "surname": "Brown"},
                        {"name": "John", "surname": "Lennon"},
                        {"name": "Alice", "surname": "Brown"},
                    ]
                },
            ).value,
            repeated.meld(
                {"name": "Alice", "surname": "Brown"},
                {"name": "John", "surname": "Brown"},
                {"name": "John", "surname": "Lennon"},
                {"name": "John", "surname": "Smith"},
            ),
        )

        self.assertEqual(
            solve.solve(
                q.Query("select name, surname from people order by " "(lower(surname), lower(name))"),
                {
                    "people": [
                        {"name": "John", "surname": "Smith"},
                        {"name": "John", "surname": "Brown"},
                        {"name": "John", "surname": "Lennon"},
                        {"name": "Alice", "surname": "Brown"},
                    ]
                },
            ).value,
            repeated.meld(
                {"name": "Alice", "surname": "Brown"},
                {"name": "John", "surname": "Brown"},
                {"name": "John", "surname": "Lennon"},
                {"name": "John", "surname": "Smith"},
            ),
        )
Example #4
0
    def testSubselects(self):
        # This should fail because we're selecting two values.
        query = q.Query(
            "5 + SELECT age, name FROM"
            " (bind('age': 10, 'name': 'Tom'), bind('age': 8, 'name': 'Jerry'))"
            " WHERE name == 'Jerry'")
        with self.assertRaises(errors.EfilterTypeError):
            solve.solve(query, {})

        # Returning multiple results from SELECT should work with set
        # operations.
        query = q.Query("let users = ("
                        " bind('age': 10, 'name': 'Tom'),"
                        " bind('age': 8, 'name': 'Jerry')"
                        "),"
                        "names = (SELECT name FROM users) "
                        " SELECT * FROM users WHERE name IN names")

        self.assertValuesEqual(
            solve.solve(query, {}).value,
            repeated.meld({
                "age": 10,
                "name": "Tom"
            }, {
                "age": 8,
                "name": "Jerry"
            }))
Example #5
0
    def testLet(self):
        self.assertEqual(
            solve.solve(
                ast.Let(
                    ast.Bind(
                        ast.Pair(
                            ast.Literal("x"),
                            ast.Literal(5))),
                    ast.Sum(
                        ast.Var("x"),
                        ast.Var("x"))),
                {}).value,
            10)

        # Previous binding should be made available to subsequent bindings.
        self.assertEqual(
            solve.solve(
                ast.Let(
                    ast.Bind(
                        ast.Pair(
                            ast.Literal("x"),
                            ast.Literal(5)),
                        ast.Pair(
                            ast.Literal("y"),
                            ast.Sum(
                                ast.Var("x"),
                                ast.Literal(5)))),
                    ast.Var("y")),
                {}).value,
            10)
Example #6
0
    def testApply(self):
        self.assertEqual(
            solve.solve(q.Query("multiply(x: 5, y: 5)"),
                        dict(multiply=mocks.MockFunction())).value, 25)

        with self.assertRaises(errors.EfilterError):
            solve.solve(q.Query("multiply(x: 5, 'y': 5)"),
                        dict(multiply=lambda x, y: x * y))
Example #7
0
    def testIfElse(self):
        query = q.Query(("if", True, "foo", "bar"))
        self.assertEqual(
            solve.solve(query, {}).value,
            "foo")

        query = q.Query(("if", False, "foo", False, "baz", "bar"))
        self.assertEqual(
            solve.solve(query, {}).value,
            "bar")
Example #8
0
    def testResolve(self):
        self.assertEqual(
            solve.solve(q.Query("x.y"),
                        {"x": {"y": 5}}).value,
            5)

        self.assertEqual(
            solve.solve(q.Query("x.y.z"),
                        {"x": {"y": {"z": 5}}}).value,
            5)
Example #9
0
    def testTuple(self):
        query = q.Query("[1, 2, 3]")
        self.assertEqual(
            solve.solve(query, {}).value,
            (1, 2, 3))

        query = q.Query("[x + 5, 1 == 1, y['foo']]")
        self.assertEqual(
            solve.solve(query, {"x": 2, "y": {"foo": "bar"}}).value,
            (7, True, "bar"))
Example #10
0
    def testResolve(self):
        self.assertEqual(solve.solve(q.Query("x.y"), {"x": {"y": 5}}).value, 5)

        self.assertEqual(
            solve.solve(q.Query("x.y.z"), {
                "x": {
                    "y": {
                        "z": 5
                    }
                }
            }).value, 5)
Example #11
0
    def testApply(self):
        self.assertEqual(
            solve.solve(
                q.Query("multiply(x: 5, y: 5)"),
                dict(multiply=mocks.MockFunction())).value,
            25)

        with self.assertRaises(errors.EfilterError):
            solve.solve(
                q.Query("multiply(x: 5, 'y': 5)"),
                dict(multiply=lambda x, y: x * y))
Example #12
0
    def testDestructuring(self):
        result = solve.solve(q.Query("Process.pid == 1"), {"Process": {"pid": 1}})
        self.assertEqual(True, result.value)

        # Using a let-any form should succeed even if there is only one linked
        # object.
        result = solve.solve(
            q.Query("any Process.parent where (Process.pid == 1 or " "Process.command == 'foo')"),
            {"Process": {"parent": {"Process": {"pid": 1}}}},
        )
        self.assertEqual(True, result.value)
Example #13
0
    def testTuple(self):
        query = q.Query("[1, 2, 3]")
        self.assertEqual(solve.solve(query, {}).value, (1, 2, 3))

        query = q.Query("[x + 5, 1 == 1, y['foo']]")
        self.assertEqual(
            solve.solve(query, {
                "x": 2,
                "y": {
                    "foo": "bar"
                }
            }).value, ([7], True, "bar"))
Example #14
0
    def testAny(self):
        self.assertTrue(
            solve.solve(
                q.Query("any Process.parent where (pid == 1)"),
                {"Process": {"parent": repeated.meld(
                    mocks.Process(1, None, None),
                    mocks.Process(2, None, None))}}).value)

        # Test that unary ANY works as expected.
        query = q.Query(ast.Any(ast.Var("x")))
        self.assertFalse(solve.solve(query, {"x": None}).value)
        self.assertTrue(solve.solve(query, {"x": 1}).value)
        self.assertTrue(solve.solve(query, {"x": repeated.meld(1, 2, 3)}).value)
Example #15
0
    def testEquivalence(self):
        self.assertTrue(
            solve.solve(q.Query("pid == 1"), mocks.Process(1, None,
                                                           None)).value)

        # repeated elements are expanded in the usual way.
        self.assertTrue(
            solve.solve(q.Query("[1] == 1"), mocks.Process(1, None,
                                                           None)).value)

        # Same as [1,2] == [1, None]
        self.assertFalse(
            solve.solve(q.Query("[1, 2] == [1]"), mocks.Process(1, None,
                                                                None)).value)
Example #16
0
    def testIsInstance(self):
        with self.assertRaises(
                errors.EfilterTypeError,
                error_f=lambda e: "Cannot find type named 'FooBar'" in str(e)):
            solve.solve(q.Query("proc isa FooBar"), mocks.MockRootType())

        self.assertTrue(solve.solve(q.Query("proc isa Process"),
                                    mocks.MockRootType()).value)

        # Builtin types should work, too.
        self.assertTrue(solve.solve(q.Query("5 isa int"), {}).value)

        # Always never forget to test for negatives.
        self.assertFalse(solve.solve(q.Query("5 isa str"), {}).value)
Example #17
0
    def testIsInstance(self):
        with self.assertRaises(
                errors.EfilterTypeError,
                error_f=lambda e: "Cannot find type named 'FooBar'" in str(e)):
            solve.solve(q.Query("proc isa FooBar"), mocks.MockRootType())

        self.assertTrue(
            solve.solve(q.Query("proc isa Process"),
                        mocks.MockRootType()).value)

        # Builtin types should work, too.
        self.assertTrue(solve.solve(q.Query("5 isa int"), {}).value)

        # Always never forget to test for negatives.
        self.assertFalse(solve.solve(q.Query("5 isa str"), {}).value)
Example #18
0
    def testLet(self):
        self.assertEqual(
            solve.solve(
                ast.Let(ast.Bind(ast.Pair(ast.Literal("x"), ast.Literal(5))),
                        ast.Sum(ast.Var("x"), ast.Var("x"))), {}).value, [10])

        # Previous binding should be made available to subsequent bindings.
        self.assertEqual(
            solve.solve(
                ast.Let(
                    ast.Bind(
                        ast.Pair(ast.Literal("x"), ast.Literal(5)),
                        ast.Pair(ast.Literal("y"),
                                 ast.Sum(ast.Var("x"), ast.Literal(5)))),
                    ast.Var("y")), {}).value, [10])
Example #19
0
    def testDifference(self):
        # Adding a constant to a list, adds it to each element.
        query = q.Query(
            "SELECT ages - 10 as diff FROM (bind('ages': [10, 20, 30]))")

        value = list(solve.solve(query, {}).value)
        diff = structured.resolve(value[0], "diff")
        self.assertEqual(diff, [0, 10, 20])

        # Subtracting numbers from non numbers just gives None.
        query = q.Query('SELECT ages - 10 as diff FROM '
                        '(bind("ages": ["foo", "bar", "baz"]))')

        value = list(solve.solve(query, {}).value)
        diff = structured.resolve(value[0], "diff")
        self.assertEqual(diff, [None, None, None])
Example #20
0
 def testSelect(self):
     self.assertEqual(
         solve.solve(q.Query("x['y']"), {
             "x": {
                 "y": 5
             }
         }).value, 5)
Example #21
0
 def testEach(self):
     self.assertFalse(
         solve.solve(
             q.Query("each(Process.parent, (pid == 1))"),
             {"Process": {"parent": repeated.meld(
                 mocks.Process(1, None, None),
                 mocks.Process(2, None, None))}}).value)
Example #22
0
    def testRepeat(self):
        query = q.Query("(1, 2, 3, 4)")
        self.assertEqual(solve.solve(query, {}).value, repeated.meld(1, 2, 3, 4))

        # Repeated values flatten automatically.
        query = q.Query("(1, (2, 3), 4)")
        self.assertEqual(solve.solve(query, {}).value, repeated.meld(1, 2, 3, 4))

        # Expressions work.
        query = q.Query("(1, (2 + 2), 3, 4)")
        self.assertEqual(solve.solve(query, {}).value, repeated.meld(1, 4, 3, 4))

        # Repeated values are mono-types.
        with self.assertRaises(errors.EfilterTypeError):
            query = q.Query("(1, 'foo', 3, 4)")
            solve.solve(query, {})
Example #23
0
def search(query, data, replacements=None):

    """Yield objects from 'data' that match the 'query'."""
    query = q.Query(query, params=replacements)
    for entry in data:
        if solve.solve(query, entry).value:
            yield entry
Example #24
0
 def testMap(self):
     self.assertEqual(
         solve.solve(q.Query("foo.bar"), {
             "foo": {
                 "bar": "baz"
             }
         }).value, "baz")
Example #25
0
 def testFilter(self):
     self.assertValuesEqual(
         solve.solve(
             q.Query("select * from Process where (pid == 1)"),
             {"Process": repeated.meld(
                 mocks.Process(2, None, None),
                 mocks.Process(1, None, None))}).value,
         mocks.Process(1, None, None))
Example #26
0
 def testFilter(self):
     self.assertValuesEqual(
         solve.solve(
             q.Query("select * from Process where (pid == 1)"), {
                 "Process":
                 repeated.meld(mocks.Process(2, None, None),
                               mocks.Process(1, None, None))
             }).value, mocks.Process(1, None, None))
Example #27
0
    def collect(self):
        try:
            result = solve.solve(self.query, self)
            return repeated.getvalues(result.value)
        except errors.EfilterError:
            if self.silent:
                return None

            raise
Example #28
0
    def testMatchTrace(self):
        """Make sure that matching branch is recorded where applicable."""
        result = solve.solve(
            q.Query("pid == 1 or pid == 2 or pid == 3"),
            mocks.Process(2, None, None))

        self.assertEqual(
            q.Query(result.branch),
            q.Query("pid == 2"))
Example #29
0
    def collect(self):
        try:
            result = solve.solve(self.query, self)
            return repeated.getvalues(result.value)
        except errors.EfilterError:
            if self.silent:
                return None

            raise
Example #30
0
 def testEach(self):
     self.assertFalse(
         solve.solve(
             q.Query("each(Process.parent, (pid == 1))"), {
                 "Process": {
                     "parent":
                     repeated.meld(mocks.Process(1, None, None),
                                   mocks.Process(2, None, None))
                 }
             }).value)
Example #31
0
    def collect(self):
        """Return the search results without displaying them."""
        try:
            result = solve.solve(self.query, self)
            return repeated.getvalues(result.value)
        except errors.EfilterError:
            if self.silent:
                return None

            raise
Example #32
0
    def collect(self):
        """Return the search results without displaying them."""
        try:
            result = solve.solve(self.query, self)
            return repeated.getvalues(result.value)
        except errors.EfilterError:
            if self.silent:
                return None

            raise
Example #33
0
    def testAny(self):
        self.assertTrue(
            solve.solve(
                q.Query("any Process.parent where (pid == 1)"), {
                    "Process": {
                        "parent":
                        repeated.meld(mocks.Process(1, None, None),
                                      mocks.Process(2, None, None))
                    }
                }).value)

        # Test that unary ANY works as expected.
        query = q.Query(ast.Any(ast.Var("x")))
        self.assertFalse(solve.solve(query, {"x": None}).value)
        self.assertTrue(solve.solve(query, {"x": 1}).value)
        self.assertTrue(
            solve.solve(query, {
                "x": repeated.meld(1, 2, 3)
            }).value)
Example #34
0
    def solve(self):
        """Return the search results exactly as EFILTER returns them.

        Returns:
            Depends on the query.

        Raises:
            EfilterError if anything goes wrong.
        """
        return solve.solve(self.query, self).value
Example #35
0
    def solve(self):
        """Return the search results exactly as EFILTER returns them.

        Returns:
            Depends on the query.

        Raises:
            EfilterError if anything goes wrong.
        """
        return solve.solve(self.query, self).value or []
Example #36
0
 def testReverse(self):
     query = q.Query(
         ast.Apply(
             ast.Var("reverse"),
             ast.Repeat(
                 ast.Literal(1),
                 ast.Literal(2),
                 ast.Literal(3))))
     self.assertEqual(
         solve.solve(query, {}).value,
         repeated.meld(3, 2, 1))
Example #37
0
    def testDestructuring(self):
        result = solve.solve(q.Query("Process.pid == 1"),
                             {"Process": {
                                 "pid": 1
                             }})
        self.assertTrue(result.value)

        # Using a let-any form should succeed even if there is only one linked
        # object.
        result = solve.solve(
            q.Query("any Process.parent where (Process.pid == 1 or "
                    "Process.command == 'foo')"),
            {"Process": {
                "parent": {
                    "Process": {
                        "pid": 1
                    }
                }
            }})
        self.assertTrue(result.value)
Example #38
0
    def testSubselects(self):
        query = q.Query(
            "5 + SELECT age FROM"
            " (bind('age': 10, 'name': 'Tom'), bind('age': 8, 'name': 'Jerry'))"
            " WHERE name == 'Jerry'")
        self.assertEqual(solve.solve(query, {}).value, 13)

        # This should fail because we're selecting two values.
        query = q.Query(
            "5 + SELECT age, name FROM"
            " (bind('age': 10, 'name': 'Tom'), bind('age': 8, 'name': 'Jerry'))"
            " WHERE name == 'Jerry'")
        with self.assertRaises(errors.EfilterTypeError):
            solve.solve(query, {})

        # Returning multiple results from SELECT should work with set
        # operations.
        query = q.Query("let users = ("
                        " bind('age': 10, 'name': 'Tom'),"
                        " bind('age': 8, 'name': 'Jerry')"
                        "),"
                        "names = SELECT name FROM users"
                        " SELECT * FROM users WHERE name IN names")

        self.assertValuesEqual(
            solve.solve(query, {}).value,
            repeated.meld({
                "age": 10,
                "name": "Tom"
            }, {
                "age": 8,
                "name": "Jerry"
            }))

        # However, equivalence should blow up:
        query = q.Query("let users = ("
                        " bind('age': 10, 'name': 'Tom'),"
                        " bind('age': 8, 'name': 'Jerry')"
                        "),"
                        "names = SELECT name FROM users"
                        " SELECT * FROM users WHERE name == names")

        with self.assertRaises(errors.EfilterTypeError):
            # Need to force the results to be realized (solve is lazy), hence
            # the list.
            list(solve.solve(query, {}).value)

        # It also shouldn't work if the subselect returns multiple columns.
        # However, equivalence should blow up:
        query = q.Query("let users = ("
                        " bind('age': 10, 'name': 'Tom'),"
                        " bind('age': 8, 'name': 'Jerry')"
                        "),"
                        "names = SELECT * FROM users"
                        " SELECT * FROM users WHERE name IN names")

        with self.assertRaises(errors.EfilterTypeError):
            # Need to force the results to be realized (solve is lazy), hence
            # the list.
            list(solve.solve(query, {}).value)
Example #39
0
    def testRepeat(self):
        query = q.Query("(1, 2, 3, 4)")
        self.assertEqual(
            solve.solve(query, {}).value, repeated.meld(1, 2, 3, 4))

        # Repeated values flatten automatically.
        query = q.Query("(1, (2, 3), 4)")
        self.assertEqual(
            solve.solve(query, {}).value, repeated.meld(1, 2, 3, 4))

        # Expressions work.
        query = q.Query("(1, (2 + 2), 3, 4)")
        self.assertEqual(
            solve.solve(query, {}).value, repeated.meld(1, 4, 3, 4))

        # Repeated values are mono-types.
        with self.assertRaises(errors.EfilterTypeError):
            query = q.Query("(1, 'foo', 3, 4)")
            solve.solve(query, {})

        # None should be skipped.
        query = q.Query(
            ast.Repeat(ast.Literal(None), ast.Literal(2), ast.Literal(None),
                       ast.Literal(4)))
        self.assertEqual(solve.solve(query, {}).value, repeated.meld(2, 4))
Example #40
0
    def testSubselects(self):
        query = q.Query(
            "5 + SELECT age FROM"
            " (bind('age': 10, 'name': 'Tom'), bind('age': 8, 'name': 'Jerry'))"
            " WHERE name == 'Jerry'")
        self.assertEqual(
            solve.solve(query, {}).value,
            13)

        # This should fail because we're selecting two values.
        query = q.Query(
            "5 + SELECT age, name FROM"
            " (bind('age': 10, 'name': 'Tom'), bind('age': 8, 'name': 'Jerry'))"
            " WHERE name == 'Jerry'")
        with self.assertRaises(errors.EfilterTypeError):
            solve.solve(query, {})

        # Returning multiple results from SELECT should work with set
        # operations.
        query = q.Query(
            "let users = ("
            " bind('age': 10, 'name': 'Tom'),"
            " bind('age': 8, 'name': 'Jerry')"
            "),"
            "names = SELECT name FROM users"
            " SELECT * FROM users WHERE name IN names")

        self.assertValuesEqual(
            solve.solve(query, {}).value,
            repeated.meld({"age": 10, "name": "Tom"},
                          {"age": 8, "name": "Jerry"}))

        # However, equivalence should blow up:
        query = q.Query(
            "let users = ("
            " bind('age': 10, 'name': 'Tom'),"
            " bind('age': 8, 'name': 'Jerry')"
            "),"
            "names = SELECT name FROM users"
            " SELECT * FROM users WHERE name == names")

        with self.assertRaises(errors.EfilterTypeError):
            # Need to force the results to be realized (solve is lazy), hence
            # the list.
            list(solve.solve(query, {}).value)

        # It also shouldn't work if the subselect returns multiple columns.
         # However, equivalence should blow up:
        query = q.Query(
            "let users = ("
            " bind('age': 10, 'name': 'Tom'),"
            " bind('age': 8, 'name': 'Jerry')"
            "),"
            "names = SELECT * FROM users"
            " SELECT * FROM users WHERE name IN names")

        with self.assertRaises(errors.EfilterTypeError):
            # Need to force the results to be realized (solve is lazy), hence
            # the list.
            list(solve.solve(query, {}).value)
Example #41
0
    def testRepeat(self):
        query = q.Query("(1, 2, 3, 4)")
        self.assertEqual(
            solve.solve(query, {}).value, repeated.meld(1, 2, 3, 4))

        # Repeated values do not flatten automatically.
        query = q.Query("(1, (2, 3), 4)")
        self.assertEqual(
            solve.solve(query, {}).value, repeated.meld(1, [2, 3], 4))

        # Expressions work.
        query = q.Query("(1, (2 + 2), 3, 4)")
        self.assertEqual(
            solve.solve(query, {}).value,
            # Operators always return a list.
            repeated.meld(1, [4], 3, 4))

        # None should be skipped.
        query = q.Query(
            ast.Repeat(ast.Literal(None), ast.Literal(2), ast.Literal(None),
                       ast.Literal(4)))
        self.assertEqual(solve.solve(query, {}).value, repeated.meld(2, 4))
Example #42
0
 def testEach(self):
     self.assertEqual(
         solve.solve(
             q.Query("each(Process.parent, (pid == 1))"),
             {
                 "Process": {
                     "parent": superposition.superposition(
                         mocks.Process(1, None, None), mocks.Process(2, None, None)
                     )
                 }
             },
         ).value,
         False,
     )
Example #43
0
def apply(query, replacements=None, vars=None, allow_io=False):
    """Run 'query' on 'vars' and return the result(s).

    Arguments:
        query: A query object or string with the query.
        replacements: Built-time parameters to the query, either as dict or
            as an array (for positional interpolation).
        vars: The variables to be supplied to the query solver.
        allow_io: If True then functions from stdlib.io will be included and
            allowed to read from the filesystem. Use with caution!
            (default: False)

            WARNING: If the query returns a lazily-evaluated result that depends
            on reading from a file (for example, filtering a CSV file) then the
            file descriptor will remain open until the returned result is
            deallocated. The caller is responsible for releasing the result when
            it's no longer needed.

    Returns:
        The result of evaluating the query. The type of the output will depend
        on the query, and can be predicted using 'infer' (provided reflection
        callbacks are implemented). In the common case of a SELECT query the
        return value will be an iterable of filtered data (actually an object
        implementing IRepeated, as well as __iter__.)

    Raises:
        efilter.errors.EfilterError if there are issues with the query.

    Examples:
        apply("5 + 5") # -> 10

        apply("SELECT * FROM people WHERE age > 10",
              people=({"age": 10, "name": "Bob"},
                      {"age": 20, "name": "Alice"},
                      {"age": 30, "name": "Eve"})) # -> LazyRepetition(...)

        # This will replace the question mark (?) with the string "Bob" in a
        # safe manner, preventing SQL injection.
        apply("SELECT * FROM people WHERE name = ?", replacements=["Bob"], ...)
    """
    if vars is None:
        vars = {}

    query = q.Query(query, params=replacements)
    if allow_io:
        vars = scope.ScopeStack(std_io.FUNCTIONS, vars)

    results = solve.solve(query, vars).value

    return results
Example #44
0
    def testMembership(self):
        self.assertTrue(solve.solve(q.Query("pid in [1, 2]"),
                                    mocks.Process(1, None, None)).value)

        # Repeated should work, too.
        self.assertTrue(solve.solve(q.Query("pid in (1, 2)"),
                                    mocks.Process(1, None, None)).value)

        # Strings can be in strings.
        self.assertTrue(solve.solve(q.Query("'foo' in 'foobar'"), {}).value)

        # True negative.
        self.assertFalse(solve.solve(q.Query("'foo' in 'bar'"), {}).value)

        # This should also work for strings.
        self.assertTrue(solve.solve(q.Query("'foo' in 'foobar'"), {}).value)
        self.assertFalse(solve.solve(q.Query("'fzz' in 'foobar'"), {}).value)

        # Single characters.
        self.assertTrue(solve.solve(q.Query("'f' in 'foo'"), {}).value)
Example #45
0
 def testStrictOrderedSet(self):
     self.assertFalse(solve.solve(q.Query("pid > 2"),
                                  mocks.Process(1, None, None)).value)
Example #46
0
def search(query, data, replacements=None):
    """Yield objects from 'data' that match the 'query'."""
    query = q.Query(query, params=replacements)
    for entry in data:
        if solve.solve(query, entry).value:
            yield entry
Example #47
0
def apply(query,
          replacements=None,
          vars=None,
          allow_io=False,
          libs=("stdcore", "stdmath")):
    """Run 'query' on 'vars' and return the result(s).

    Arguments:
        query: A query object or string with the query.
        replacements: Built-time parameters to the query, either as dict or
            as an array (for positional interpolation).
        vars: The variables to be supplied to the query solver.
        allow_io: (Default: False) Include 'stdio' and allow IO functions.
        libs: Iterable of library modules to include, given as strings.
            Default: ('stdcore', 'stdmath')
            For full list of bundled libraries, see efilter.stdlib.

            Note: 'stdcore' must always be included.

            WARNING: Including 'stdio' must be done in conjunction with
                'allow_io'. This is to make enabling IO explicit. 'allow_io'
                implies that 'stdio' should be included and so adding it to
                libs is actually not required.

    Notes on IO: If allow_io is set to True then 'stdio' will be included and
    the EFILTER query will be allowed to read files from disk. Use this with
    caution.

        If the query returns a lazily-evaluated result that depends on reading
        from a file (for example, filtering a CSV file) then the file
        descriptor will remain open until the returned result is deallocated.
        The caller is responsible for releasing the result when it's no longer
        needed.

    Returns:
        The result of evaluating the query. The type of the output will depend
        on the query, and can be predicted using 'infer' (provided reflection
        callbacks are implemented). In the common case of a SELECT query the
        return value will be an iterable of filtered data (actually an object
        implementing IRepeated, as well as __iter__.)

    A word on cardinality of the return value:
        Types in EFILTER always refer to a scalar. If apply returns more than
        one value, the type returned by 'infer' will refer to the type of
        the value inside the returned container.

        If you're unsure whether your query returns one or more values (rows),
        use the 'getvalues' function.

    Raises:
        efilter.errors.EfilterError if there are issues with the query.

    Examples:
        apply("5 + 5") # -> 10

        apply("SELECT * FROM people WHERE age > 10",
              vars={"people":({"age": 10, "name": "Bob"},
                              {"age": 20, "name": "Alice"},
                              {"age": 30, "name": "Eve"}))

        # This will replace the question mark (?) with the string "Bob" in a
        # safe manner, preventing SQL injection.
        apply("SELECT * FROM people WHERE name = ?", replacements=["Bob"], ...)
    """
    if vars is None:
        vars = {}

    if allow_io:
        libs = list(libs)
        libs.append("stdio")

    query = q.Query(query, params=replacements)

    stdcore_included = False
    for lib in libs:
        if lib == "stdcore":
            stdcore_included = True
            # 'solve' always includes this automatically - we don't have a say
            # in the matter.
            continue

        if lib == "stdio" and not allow_io:
            raise ValueError("Attempting to include 'stdio' but IO not "
                             "enabled. Pass allow_io=True.")

        module = std_core.LibraryModule.ALL_MODULES.get(lib)
        if not lib:
            raise ValueError("There is no standard library module %r." % lib)
        vars = scope.ScopeStack(module, vars)

    if not stdcore_included:
        raise ValueError("EFILTER cannot work without standard lib 'stdcore'.")

    results = solve.solve(query, vars).value

    return results
Example #48
0
 def testEquivalence(self):
     self.assertTrue(solve.solve(q.Query("pid == 1"),
                                 mocks.Process(1, None, None)).value)
Example #49
0
 def testQuotient(self):
     self.assertEqual(
         solve.solve(
             q.Query("10.0 / 4"),
             mocks.Process(1, None, None)).value,
         2.5)
Example #50
0
    def testMembership(self):
        # Support tuples (lists):
        self.assertTrue(
            solve.solve(q.Query("x in [1, 2, 3, 4]"), {"x": 2}).value)
        self.assertFalse(solve.solve(q.Query("5 in [1, 2, 3, 4]"), {}).value)

        # Support tuples of strings:
        self.assertTrue(
            solve.solve(q.Query("'foo' in ['bar', 'foo']"), {}).value)
        self.assertTrue(
            solve.solve(q.Query("'baz' not in ['bar', 'foo']"), {}).value)

        # Repeated values:
        self.assertTrue(
            solve.solve(q.Query("'foo' in ('bar', 'foo')"), {}).value)

        # Strings can be in strings:
        self.assertTrue(solve.solve(q.Query("'foo' in 'foobar'"), {}).value)
        self.assertTrue(solve.solve(q.Query("'foo' in ('foobar')"), {}).value)
        self.assertTrue(solve.solve(q.Query("'baz' not in 'foobar'"), {}).value)

        # This should behave as expected - a singleton string is distinct from a
        # string if in a list, but not in a repeated value.
        self.assertTrue(
            solve.solve(q.Query("'foo' not in ['foobar']"), {}).value)

        # All this should be true for vars as well as literals:
        self.assertTrue(
            solve.solve(q.Query("'foo' not in [x]"), {"x": "foobar"}).value)
        self.assertTrue(
            solve.solve(q.Query("'foo' in x"), {"x": "foobar"}).value)
        self.assertTrue(
            solve.solve(q.Query("'foo' in (x)"), {"x": "foobar"}).value)

        # Make sure this is all working for unicode strings as well.
        self.assertTrue(
            solve.solve(q.Query("'foo' in (x)"), {"x": u"foobar"}).value)
        self.assertTrue(
            solve.solve(
                q.Query(ast.Membership(ast.Literal(u"foo"),
                                       ast.Literal(u"foobar"))), {}).value)

        # Repeated values behave correctly.
        self.assertTrue(
            solve.solve(q.Query("'foo' in x"),
                        {"x": repeated.meld("foo", "bar")}).value)
        self.assertTrue(
            solve.solve(q.Query("'foo' not in x"),
                        {"x": repeated.meld("foobar", "bar")}).value)

        # This is where it gets tricky: a repeated value of a single value is
        # equal to the single value - this is how EFILTER is supposed to work.
        # In this case it may be unexpected, but them's the breaks.
        self.assertTrue(
            solve.solve(q.Query("'foo' not in ('foobar', 'bar')"), {}).value)
        self.assertTrue(solve.solve(q.Query("'foo' in ('foobar')"), {}).value)

        # Single characters should behave correctly.
        self.assertTrue(solve.solve(q.Query("'f' in 'foo'"), {}).value)
Example #51
0
    def testBind(self):
        query = q.Query("bind('x': 5, 'y': 10)")

        self.assertEqual(solve.solve(query, {}).value, {"x": 5, "y": 10})
Example #52
0
 def testPartialOrderedSet(self):
     self.assertTrue(
         solve.solve(q.Query("pid >= 2"), mocks.Process(2, None,
                                                        None)).value)
Example #53
0
    def testMatchTrace(self):
        """Make sure that matching branch is recorded where applicable."""
        result = solve.solve(q.Query("pid == 1 or pid == 2 or pid == 3"),
                             mocks.Process(2, None, None))

        self.assertEqual(q.Query(result.branch), q.Query("pid == 2"))
Example #54
0
 def testStrictOrderedSet(self):
     self.assertEqual(
         solve.solve(q.Query("pid > 2"),
                     mocks.Process(1, None, None)).value, [False])
Example #55
0
 def testRegexFilter(self):
     self.assertTrue(
         solve.solve(q.Query("name =~ 'ini.*'"),
                     mocks.Process(1, "initd", None)).value)
Example #56
0
 def testVar(self):
     self.assertEqual(
         solve.solve(q.Query("foo"), {"foo": "bar"}).value,
         "bar")
Example #57
0
 def testRegexFilter(self):
     self.assertTrue(
         solve.solve(
             q.Query("name =~ 'ini.*'"),
             mocks.Process(1, "initd", None)).value)
Example #58
0
    def testBind(self):
        query = q.Query("bind('x': 5, 'y': 10)")

        self.assertEqual(
            solve.solve(query, {}).value,
            {"x": 5, "y": 10})
Example #59
0
 def filter(self, query, **query_args):
     query = q.Query(query, params=query_args)
     return repeated.getvalues(solve.solve(query, self).value)
Example #60
0
 def testPartialOrderedSet(self):
     self.assertTrue(solve.solve(q.Query("pid >= 2"),
                                 mocks.Process(2, None, None)).value)