Пример #1
0
class LuaRunner(object):
    def __init__(self, keyspace):
        self._runtime = LuaRuntime(unpack_returned_tuples=True)
        self._lua_table_type = type(self._runtime.table())
        self._redis_obj = RedisLua(keyspace, self._runtime)

    def run(self, script, keys, argv):
        self._runtime.execute('KEYS = {%s}' % ', '.join(map(json.dumps, keys)))
        self._runtime.execute('ARGV = {%s}' % ', '.join(map(json.dumps, argv)))
        script_function = self._runtime.eval(
            'function(redis) {} end'.format(script))
        result = script_function(self._redis_obj)
        return self._convert_lua_types_to_redis_types(result)

    def _convert_lua_types_to_redis_types(self, result):
        def convert(value):
            """
            str -> str
            true -> 1
            false -> None
            number -> int
            table -> {
                if 'err' key is present, raise an error
                else if 'ok' key is present, return its value
                else convert to a list using the previous rules
            }

            Reference:
            https://github.com/antirez/redis/blob/5b4bec9d336655889641b134791dfdd2adc864cf/src/scripting.c#L273-L340

            """
            if isinstance(value, self._lua_table_type):
                if 'err' in value:
                    raise RedisScriptError(value['err'])
                elif 'ok' in value:
                    return value['ok']
                else:
                    return map(convert, value.values())
            elif isinstance(value, (tuple, list, set)):
                return map(convert, value)
            elif value is True:
                return 1
            elif value is False:
                return None
            elif isinstance(value, float):
                return int(value)
            else:
                # assuming string at this point
                return value

        return convert(result)
Пример #2
0
def test_redislua_with_error_pcall():
    k = Keyspace()
    lua_runtime = LuaRuntime(unpack_returned_tuples=True)
    redis_lua = RedisLua(k, lua_runtime)
    table = redis_lua.pcall('GET')

    assert table['err'] == "wrong number of arguments for 'get' command"
Пример #3
0
def test_redislua_with_command_error_pcall():
    k = Keyspace()
    lua_runtime = LuaRuntime(unpack_returned_tuples=True)
    redis_lua = RedisLua(k, lua_runtime)
    table = redis_lua.pcall('cmd_not_found')

    assert table[
        'err'] == '@user_script: Unknown Redis command called from Lua script'
Пример #4
0
def test_redislua_with_error_call():
    k = Keyspace()
    lua_runtime = LuaRuntime(unpack_returned_tuples=True)
    redis_lua = RedisLua(k, lua_runtime)

    with pytest.raises(RedisScriptError) as exc:
        redis_lua.call('GET')

    assert str(exc.value) == "wrong number of arguments for 'get' command"
Пример #5
0
    def _lua_render_template(luastr: str, kwargs=None):
        """
        Renders a Lua template.
        """

        def getter(obj, attr_name):
            if attr_name.startswith("_"):
                raise AttributeError("Not allowed to access attribute `{}` of `{}`"
                                     .format(attr_name, type(obj).__name__))

            return attr_name

        def setter(obj, attr_name, value):
            raise AttributeError("Python object attribute setting is forbidden")

        # the attribute_handlers are probably enough to prevent access eval otherwise
        lua = LuaRuntime(register_eval=False,
                         unpack_returned_tuples=True,
                         attribute_handlers=(getter, setter))

        # execute the sandbox preamble
        sandbox = lua.execute(sandbox_preamble)

        # call sandbox.run with `glob.sandbox, code`
        # and unpack the variables
        new = {}
        # HECK
        for key, val in kwargs.items():
            new[key] = lua.table_from(val)

        _ = sandbox.run(luastr, lua.table_from(new))
        if isinstance(_, bool):
            # idk
            return NO_RESULT

        called, result = _

        if lupa.lua_type(result) == 'table':
            # dictify
            result = dictify_table_recursively(result)

        return str(result)
Пример #6
0
def test_redislua_with_command_error_call():
    k = Keyspace()
    lua_runtime = LuaRuntime(unpack_returned_tuples=True)
    redis_lua = RedisLua(k, lua_runtime)

    with pytest.raises(RedisScriptError) as exc:
        redis_lua.call('cmd_not_found')

    assert str(
        exc.value
    ) == '@user_script: Unknown Redis command called from Lua script'
Пример #7
0
def test_redislua_return_lua_types_pcall():
    k = Keyspace()
    lua_runtime = LuaRuntime(unpack_returned_tuples=True)
    redis_lua = RedisLua(k, lua_runtime)
    lua_script = """return {'test', true, false, 10, 20.3, {'another string'}, redis.call('ping')}"""
    table = redis_lua.pcall('EVAL', lua_script, 0, [])

    assert table[1] == 'test'
    assert table[2] == 1
    assert table[3] is False
    assert table[4] == 10
    assert table[5] == 20
    assert table[6][1] == 'another string'
    assert table[7] == 'PONG'
Пример #8
0
 def __init__(self, keyspace):
     self._runtime = LuaRuntime(unpack_returned_tuples=True)
     self._lua_table_type = type(self._runtime.table())
     self._redis_obj = RedisLua(keyspace, self._runtime)