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])
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])
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"}, ), )
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" }))
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)
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))
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")
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)
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"))
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)
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))
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)
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"))
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)
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)
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)
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)
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])
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])
def testSelect(self): self.assertEqual( solve.solve(q.Query("x['y']"), { "x": { "y": 5 } }).value, 5)
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)
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, {})
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
def testMap(self): self.assertEqual( solve.solve(q.Query("foo.bar"), { "foo": { "bar": "baz" } }).value, "baz")
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))
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))
def collect(self): try: result = solve.solve(self.query, self) return repeated.getvalues(result.value) except errors.EfilterError: if self.silent: return None raise
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"))
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)
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
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)
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
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 []
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))
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)
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)
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))
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)
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))
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, )
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
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)
def testStrictOrderedSet(self): self.assertFalse(solve.solve(q.Query("pid > 2"), mocks.Process(1, None, None)).value)
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
def testEquivalence(self): self.assertTrue(solve.solve(q.Query("pid == 1"), mocks.Process(1, None, None)).value)
def testQuotient(self): self.assertEqual( solve.solve( q.Query("10.0 / 4"), mocks.Process(1, None, None)).value, 2.5)
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)
def testBind(self): query = q.Query("bind('x': 5, 'y': 10)") self.assertEqual(solve.solve(query, {}).value, {"x": 5, "y": 10})
def testPartialOrderedSet(self): self.assertTrue( solve.solve(q.Query("pid >= 2"), mocks.Process(2, None, None)).value)
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"))
def testStrictOrderedSet(self): self.assertEqual( solve.solve(q.Query("pid > 2"), mocks.Process(1, None, None)).value, [False])
def testRegexFilter(self): self.assertTrue( solve.solve(q.Query("name =~ 'ini.*'"), mocks.Process(1, "initd", None)).value)
def testVar(self): self.assertEqual( solve.solve(q.Query("foo"), {"foo": "bar"}).value, "bar")
def testRegexFilter(self): self.assertTrue( solve.solve( q.Query("name =~ 'ini.*'"), mocks.Process(1, "initd", None)).value)
def testBind(self): query = q.Query("bind('x': 5, 'y': 10)") self.assertEqual( solve.solve(query, {}).value, {"x": 5, "y": 10})
def filter(self, query, **query_args): query = q.Query(query, params=query_args) return repeated.getvalues(solve.solve(query, self).value)
def testPartialOrderedSet(self): self.assertTrue(solve.solve(q.Query("pid >= 2"), mocks.Process(2, None, None)).value)