Пример #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])
Пример #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])
Пример #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"},
            ),
        )
Пример #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"
            }))
Пример #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)
Пример #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))
Пример #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")
Пример #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)
Пример #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"))
Пример #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)
Пример #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))
Пример #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)
Пример #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"))
Пример #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)
Пример #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)
Пример #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)
Пример #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)
Пример #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])
Пример #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])
Пример #20
0
 def testSelect(self):
     self.assertEqual(
         solve.solve(q.Query("x['y']"), {
             "x": {
                 "y": 5
             }
         }).value, 5)
Пример #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)
Пример #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, {})
Пример #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
Пример #24
0
 def testMap(self):
     self.assertEqual(
         solve.solve(q.Query("foo.bar"), {
             "foo": {
                 "bar": "baz"
             }
         }).value, "baz")
Пример #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))
Пример #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))
Пример #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
Пример #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"))
Пример #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
Пример #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)
Пример #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
Пример #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
Пример #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)
Пример #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
Пример #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 []
Пример #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))
Пример #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)
Пример #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)
Пример #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))
Пример #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)
Пример #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))
Пример #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,
     )
Пример #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
Пример #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)
Пример #45
0
 def testStrictOrderedSet(self):
     self.assertFalse(solve.solve(q.Query("pid > 2"),
                                  mocks.Process(1, None, None)).value)
Пример #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
Пример #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
Пример #48
0
 def testEquivalence(self):
     self.assertTrue(solve.solve(q.Query("pid == 1"),
                                 mocks.Process(1, None, None)).value)
Пример #49
0
 def testQuotient(self):
     self.assertEqual(
         solve.solve(
             q.Query("10.0 / 4"),
             mocks.Process(1, None, None)).value,
         2.5)
Пример #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)
Пример #51
0
    def testBind(self):
        query = q.Query("bind('x': 5, 'y': 10)")

        self.assertEqual(solve.solve(query, {}).value, {"x": 5, "y": 10})
Пример #52
0
 def testPartialOrderedSet(self):
     self.assertTrue(
         solve.solve(q.Query("pid >= 2"), mocks.Process(2, None,
                                                        None)).value)
Пример #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"))
Пример #54
0
 def testStrictOrderedSet(self):
     self.assertEqual(
         solve.solve(q.Query("pid > 2"),
                     mocks.Process(1, None, None)).value, [False])
Пример #55
0
 def testRegexFilter(self):
     self.assertTrue(
         solve.solve(q.Query("name =~ 'ini.*'"),
                     mocks.Process(1, "initd", None)).value)
Пример #56
0
 def testVar(self):
     self.assertEqual(
         solve.solve(q.Query("foo"), {"foo": "bar"}).value,
         "bar")
Пример #57
0
 def testRegexFilter(self):
     self.assertTrue(
         solve.solve(
             q.Query("name =~ 'ini.*'"),
             mocks.Process(1, "initd", None)).value)
Пример #58
0
    def testBind(self):
        query = q.Query("bind('x': 5, 'y': 10)")

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