def proxyMethod(*args, **kwargs): # We are in the script thread here, we must syncronize with the main # thread before calling the attribute condition.acquire() args = list(args) if len(args) >= 2 and lua_type(args[1]) == 'table': # First parameter is a lua table. Handle this as **kwargs call kwargs = dict(args[1]) del args[1] # TODO: Also loop through kwargs and look for lua types for i, arg in enumerate(args): if lua_type(arg) == 'function': t = LuaFunctionWrapper(self, arg) args[i] = t self.references.append(weakref.ref(t)) try: Application().queue(mainThreadCaller, args, kwargs) condition.wait( 20) # Timeout to not let the script hang forever if 'error' in retval: self.p("Error during call: %s", retval['error']) raise AttributeError(retval['error']) elif 'return' in retval: if type(retval['return']) is dict: # Wrap to lua table return self.lua.table_from(retval['return']) return retval['return'] finally: condition.release() raise AttributeError('The call to the function "%s" timed out' % attrName)
def l2p(obj, depth): if depth <= 0: raise ValueError( "Can't convert Lua object to Python: depth limit is reached") if isinstance(obj, dict): return { l2p(key, depth - 1): l2p(value, depth - 1) for key, value in obj.iteritems() } if isinstance(obj, list): return [l2p(el, depth - 1) for el in obj] if isinstance(obj, tuple): return tuple([l2p(el, depth - 1) for el in obj]) if isinstance(obj, set): return {l2p(el, depth - 1) for el in obj} if lupa.lua_type(obj) == 'table': if _is_table_a_list(lua, obj): res = [] prev_key = 0 for key, value in obj.items(): if not isinstance(key, int): raise ValueError( "Can't build a Python list from Lua table: invalid key %r" % key) if key <= prev_key: raise ValueError( "Can't build a Python list from Lua table: bad index %s" % key) filler_size = key - prev_key - 1 if filler_size > sparse_limit: raise ValueError( "Lua table is too sparse. Try not to use nil values." ) res.extend([None] * filler_size) res.append(l2p(value, depth - 1)) prev_key = key return res else: return { l2p(key, depth - 1): l2p(value, depth - 1) for key, value in obj.items() } if strict and lupa.lua_type(obj) is not None: raise ValueError("Lua %s objects are not allowed." % lupa.lua_type(obj)) if binary and isinstance(obj, unicode): obj = obj.encode('utf8') return obj
def wrapLuaToPy(self, arg): if lua_type(arg) == 'function': func = LuaFunctionWrapper(self, arg) self.references.append(weakref.ref(func)) return func elif lua_type(arg) == 'table': table = dict(arg) for key in table: # Recursive wrap table[key] = self.wrapLuaToPy(table[key]) return table return arg
def change_value_by_path_regex(regEx, func, luaTable, rootTable=None, path=''): import lupa if not rootTable: rootTable = luaTable for key in list(luaTable): v = luaTable[key] newPath = '/'.join([path, str(key)]) if regEx.match(newPath): luaTable[key] = func(key, v, rootTable) elif lupa.lua_type(v) == 'table': change_value_by_path_regex(regEx, func, v, rootTable, newPath) elif lupa.lua_type(v) == 'function': change_value_by_path_regex(regEx, func, v(), rootTable, newPath)
def l2p(obj, depth): if depth <= 0: raise ValueError("Can't convert Lua object to Python: depth limit is reached") if isinstance(obj, dict): return { l2p(key, depth-1): l2p(value, depth-1) for key, value in obj.iteritems() } if isinstance(obj, list): return [l2p(el, depth-1) for el in obj] if isinstance(obj, tuple): return tuple([l2p(el, depth-1) for el in obj]) if isinstance(obj, set): return {l2p(el, depth-1) for el in obj} if lupa.lua_type(obj) == 'table': if _is_table_a_list(lua, obj): res = [] prev_key = 0 for key, value in obj.items(): if not isinstance(key, int): raise ValueError("Can't build a Python list from Lua table: invalid key %r" % key) if key <= prev_key: raise ValueError("Can't build a Python list from Lua table: bad index %s" % key) filler_size = key - prev_key - 1 if filler_size > sparse_limit: raise ValueError("Lua table is too sparse. Try not to use nil values.") res.extend([None] * filler_size) res.append(l2p(value, depth-1)) prev_key = key return res else: return { l2p(key, depth-1): l2p(value, depth-1) for key, value in obj.items() } if strict and lupa.lua_type(obj) is not None: raise ValueError( "Lua %s objects are not allowed." % lupa.lua_type(obj) ) if binary and isinstance(obj, unicode): obj = obj.encode('utf8') return obj
def __run(self): while True: state = self.state() self.__threadLock.acquire() task = None try: if len(self.__queue): task = self.__queue.pop(0) elif state in [LuaScript.LOADING, LuaScript.CLOSING]: # Abort any threads that might be running for t in self.runningLuaThreads: t.abort() self.runningLuaThreads = [] for r in self.references: if r() is not None: r().abort() self.references[:] = [] else: self.__threadLock.wait(300) finally: self.__threadLock.release() if state == LuaScript.CLOSING: self.__setState(LuaScript.CLOSED) return if state == LuaScript.LOADING: self.__load() elif task is not None: name, args = task args = list(args) for i, arg in enumerate(args): if type(arg) == dict: args[i] = self.lua.table_from(arg) if type(name) == str or type(name) == unicode: fn = getattr(self.lua.globals(), name) self.runningLuaThread = fn.coroutine(*args) elif lua_type(name) == 'thread': self.runningLuaThread = name elif lua_type(name) == 'function': self.runningLuaThread = name.coroutine(*args) else: continue try: self.__setState(LuaScript.RUNNING) self.runningLuaThread.send(None) except StopIteration: pass except Exception as e: self.p("Could not execute function %s: %s", name, e) self.runningLuaThread = None self.__setState(LuaScript.IDLE)
def dictify_table_recursively(t): """ Turns a table into a dict. """ d = {} for (k, v) in t.items(): typ = lupa.lua_type(v) print(k, v, typ) if lupa.lua_type(v) == "table": d[k] = dictify_table_recursively(v) else: d[k] = str(v) return d
def populate_room(self): for distribution_node in self.node[1].items(): container_id = distribution_node[0] container_node = distribution_node[1] if str(lupa.lua_type( container_node)) != Distribution.LUA_TYPE_TABLE: continue items = None items_procedural = None items_junk = None for container_node_property_key, container_node_property_value in container_node.items( ): if container_node_property_key == Distribution.KEY_ITEMS: items = container_node_property_value elif container_node_property_key == Distribution.KEY_PROCEDURAL: items_procedural = container_node_property_value elif container_node_property_key == Distribution.KEY_JUNK: items_junk = container_node_property_value if items: is_value = True for item_id in items.values(): if is_value: self.add_item(item_id, container_id) is_value = not is_value elif items_procedural: for item_procedural in items_procedural.values(): for distribution_procedural in self.procedural_distributions: if item_procedural.name == distribution_procedural.name: for item in distribution_procedural.items: self.add_item(item, container_id, False)
def lua_table_to_dict(lua_table): result = dict() for i in lua_table: result[i] = lua_table[i] if lupa.lua_type(result[i]) is 'table': result[i] = lua_table_to_dict(result[i]) return result
def __init__(self, prototype, icon_loader): super().__init__(prototype, icon_loader) self.speed = prototype.crafting_speed self.categories = list(prototype.crafting_categories.values()) if prototype.allowed_effects is not None: self.allowed_effects = list(prototype.allowed_effects.values()) else: self.allowed_effects = [] if prototype.module_specification is not None: self.module_slots = prototype.module_specification.module_slots or 0 else: self.module_slots = 0 self.input_fluid_box = 0 self.output_fluid_box = 0 if prototype.fluid_boxes is not None: for box in prototype.fluid_boxes.values(): if lupa.lua_type(box) == 'table': if 'input' == box.production_type: self.input_fluid_box += 1 elif 'output' == box.production_type: self.output_fluid_box += 1 self.ingredient_count = self._get_int( prototype.ingredient_count, self._get_int(prototype.source_inventory_size, -1)) self.fixed_recipe = self._get_str(prototype.fixed_recipe, "") self.base_productivity = self._get_float(prototype.base_productivity, 0)
def exec_lua(code: str): # 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 _ = sandbox.run(code, lua.table_from({})) if isinstance(_, bool): # idk return NO_RESULT called, result = _ if lupa.lua_type(result) == 'table': # dictify result = dictify_table_recursively(result) try: pickle.dumps(result) except: return str(result) return result
def luaTableToDict(table, runtime=None): """ recursively (deep) convert lua table to dictionary params: table: lupa.LuaTable runtime: lupa.LuaRuntime if runtime is specified, the function will attempt to find the metatables. if found, each dict will include the metatable dict under the key "__metatable". """ if lupa.lua_type(table) != "table": return table d = {} if runtime: getmetatable = runtime.eval("getmetatable") for k, v in table.items(): d[k] = luaTableToDict(v) if runtime: mt = getmetatable(table) if mt: d["__metatable"] = luaTableToDict(mt, runtime) return d
def private_call_later(self, callback, delay=None): if delay is None: delay = 0 if not isinstance(delay, (float, int)): raise ScriptError({ "argument": "delay", "message": "splash:call_later delay must be a number", "splash_method": "call_later", }) delay = int(float(delay)*1000) if delay < 0: raise ScriptError({ "argument": "delay", "message": "splash:call_later delay must be >= 0", "splash_method": "call_later", }) if lupa.lua_type(callback) != 'function': raise ScriptError({ "argument": "callback", "message": "splash:call_later callback is not a function", "splash_method": "call_later", }) qtimer = QTimer(self.tab) qtimer.setSingleShot(True) timer = _ExposedTimer(self, qtimer) run_coro = self.get_coroutine_run_func( "splash:call_later", callback, return_error=timer.store_error ) qtimer.timeout.connect(run_coro) qtimer.start(delay) return timer
def mapSaveLuaVector(mirrorFunc, value): import lupa if lupa.lua_type(value) == 'table': if list(value) == [1, 2, 3]: value = mirrorFunc((value[1], value[2], value[3])) elif value.startswith('VECTOR3'): value = eval(value[7:]) value = mirrorFunc(value) return "VECTOR3( {}, {}, {} )".format(*value) return value
def default(self, o): try: if isinstance(o, datetime.datetime): return o.strftime('%Y-%m-%d %H:%M:%S') if isinstance(o, datetime.date): return str(o) if lupa.lua_type(o) == 'table': return dict(o) return super().default(o) except TypeError as e: return str(o)
def luaTableToList(table, runtime=None): if lupa.lua_type(table) != "table": return TypeError("table must be Lua table") l = [] for i, v in ipairs(table): l.append(luaTableToDict(v, runtime)) return l
def getTablesByPathRegex(regEx, luaTable, path=''): import lupa ret = {} for key in list(luaTable): v = luaTable[key] newPath = '/'.join([path, str(key)]) if regEx.match(newPath): ret.update({key: v}) elif lupa.lua_type(v) == 'table': ret.update(getTablesByPathRegex(regEx, v, newPath)) return ret
def convert_field(field, value): if isinstance(value, float): return value elif isinstance(value, str): return value elif isinstance(value, int): return value elif lupa.lua_type(value) == "table": return table_to_dict(value) else: raise Exception(f"No handler for type {type(value)}")
def _check_main(main): if main is None: raise ScriptError({ "type": ScriptError.MAIN_NOT_FOUND_ERROR, "message": "'main' function is not found", }) if lupa.lua_type(main) != 'function': raise ScriptError({ "type": ScriptError.BAD_MAIN_ERROR, "message": "'main' is not a function", })
def writeSaveLua(oStream, luaTable, path='', first=False): import lupa indent = " " * (path.count('/')) # try to make output look more like original keys = orderedSaveLuaKeys(list(luaTable), path) # iterate over lua table keys for k in keys: newPath = '/'.join([path, str(k)]) printPathDecorator(oStream, indent, newPath) if keyIsWrittenAlternativly(newPath): oStream.write("{}['{}'] = ".format(indent, k)) else: oStream.write("{}{} = ".format(indent, k)) v = luaTable[k] if lupa.lua_type(v) == 'table' or type(v) is dict: if list(v) == [1, 2, 3]: oStream.write("{{ {0:.6f}, {1:.6f}, {2:.6f} }}".format( v[1], v[2], v[3])) else: oStream.write("{\n") writeSaveLua(oStream, v, newPath) oStream.write("{}}}".format(indent)) elif type(v) is str: if v[:5] in ['FLOAT', 'BOOLE', 'STRIN', 'VECTO']: oStream.write("{}".format(v)) else: oStream.write("'{}'".format(v)) elif type(v) is int: oStream.write("{}".format(v)) elif lupa.lua_type(v) == 'function': oStream.write("GROUP {\n") writeSaveLua(oStream, v(), newPath) oStream.write("{}}}".format(indent)) elif type(v) is tuple: oStream.write("{{ {:.6f}, {:.6f}, {:.6f} }}".format(*v)) else: raise Exception("Unknown format {} at {} ".format( type(v), newPath)) if not first: oStream.write(",\n")
def lua2py(obj): t = lua_type(obj) if t == 'table': keys = list(obj.keys()) is_sequence = keys == [i + 1 for i in range(len(keys))] if is_sequence: return [lua2py(v) for v in obj.values()] else: return {lua2py(k): lua2py(obj[k]) for k in keys} elif t is None: return obj else: raise ValueError(f'unsupported Lua type {t}')
def init(self, func, *args): # HACK: should not directly reference lupa here import lupa if lupa.lua_type(args) == 'table': args = args.values() print ('Expression: ', func, args) self.func = func self.args = list(args) self.output = Signal() # Workaround for list event bug self.input = self.args[0]
def recursice_dict(lua_dict): d = {} is_list = True for key, value in lua_dict.items(): if not isinstance(key, int): is_list = False if lupa.lua_type(value) == "table": value = recursice_dict(value) d[key] = value if is_list: return list(d.values()) else: return d
def populate_container(self): for distribution_node in self.node[1].items(): container_id = distribution_node[0] container_node = distribution_node[1] if container_id != Distribution.KEY_ITEMS or str( lupa.lua_type( container_node)) != Distribution.LUA_TYPE_TABLE: continue is_value = True for item_id in container_node.values(): if is_value: self.add_item(item_id, container_id) is_value = not is_value
def __sandboxInterpreter(self): for obj in self.lua.globals(): if obj == '_G': # Allow _G here to not start recursion continue if obj not in safeFunctions: del self.lua.globals()[obj] continue if lua_type(self.lua.globals()[obj]) != 'table': continue funcs = safeFunctions[obj] for func in self.lua.globals()[obj]: if func not in funcs: del self.lua.globals()[obj][func] self.lua.globals().list = List self.lua.globals().require = self.__require
def localise_string(self, t): if type(t) == dict or lupa.lua_type(t) == 'table': key = t[1] params = [self.localise_string(t[i+2]) for i in range(len(t)-1)] if key == '': return ''.join(params) if key in self.current_values: template = self.current_values[key] elif key in self.default_values: template = self.default_values[key] else: template = 'Unknown key:"'+key+'"' def plural_replacer(match): index = int(match.group(1)) number = int(params[index-1]) patterns = match.group(2) patterns = patterns.split('|') for pattern in patterns: rules = pattern.split('=')[0] result = '='.join(pattern.split('=')[1:]) for rule in rules.split(','): if rule.startswith('ends in '): tail = rule[len('ends in '):] if str(number).endswith(tail): return result elif rule == 'rest': return result elif rule == str(number): return result return "Unknown plural for number " + str(number) def argument_replacer(match): index = int(match.group(1)) return params[index-1] template = re.sub("__plural_for_parameter_([0-9]+)_\{([^}]*)\}__", plural_replacer, template) template = re.sub("__([0-9]+)__", argument_replacer, template) return template else: return str(t)
def eval_string(path): """ runs the lua file and transforms the lua table to a dict path: path to the lua file for the unit """ # read the contents of a unit file f = open(path, "r") string = f.read() # capture the unit name unit_name = string.partition('\n')[0].replace("local unitName = ", "") """ in the lua code there are references to Spring.I18n this function is unavailable in our environment so we need to change local unitName = Spring.I18N('units.names.armaca') to local unitName = "units.names.armaca" and description = Spring.I18N('units.heap', { name = unitName }), to description = "units.heap.armsomethingsomething", """ if "Spring.I18N('" in string: unit_name = unit_name.replace("Spring.I18N('", "\"").replace("')", "\"", 1) string = string \ .replace("Spring.I18N('", "\"") \ .replace("', { name = unitName }", "." + unit_name.split(".")[-1].replace("\"", "") + "'") \ .replace("')", "\"") string = string.replace("units.names.", "").replace("units.names.", "") try: data = lua.execute(string) if (not lupa.lua_type(data) == "table"): print("found broken thing at " + path) return open_unit_table(data) except lupa._lupa.LuaError as e: print("encountered the following error while parsing " + path) print(e.message) if "attempt to index a nil value" in e.args[0]: return None raise
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)
def xm_sandbox_interactive(lua, instance): instance["__global__"] = lgl = lua.globals() try: while True: try: rv = lgl.setfenv(lgl.loadstring(xm_sandbox_loadline()), instance)() print('= ', end='') stdout.flush() if lua_type(rv) == 'table': lgl.table.dump(rv) else: lgl.print(rv) except (LuaSyntaxError, LuaError) as e: print(e) except KeyboardInterrupt: print("\nEOF or `os.exit()` to exit") except EOFError: pass finally: instance["__global__"] = None
def recurse(x): if isinstance(x, (str, int, float, type(None), type(True))): return x if lupa.lua_type(x) == "table": conv_to_dict = (flags & 1) != 0 # JSON_PRESERVE_KEYS flag if not conv_to_dict: # Also convert to dict if keys are not sequential integers # starting from 1 if not all(isinstance(k, int) for k in x.keys()): conv_to_dict = True else: keys = list(sorted(x.keys())) if not all(keys[i] == i + 1 for i in range(len(keys))): conv_to_dict = True if conv_to_dict: ht = {} for k, v in x.items(): ht[str(k)] = recurse(v) return ht # Convert to list (JSON array) return list(map(recurse, x.values())) return x
def private_call_later(self, callback, delay=None): if delay is None: delay = 0 if not isinstance(delay, (float, int)): raise ScriptError( { "argument": "delay", "message": "splash:call_later delay must be a number", "splash_method": "call_later", } ) delay = int(float(delay) * 1000) if delay < 0: raise ScriptError( {"argument": "delay", "message": "splash:call_later delay must be >= 0", "splash_method": "call_later"} ) if lupa.lua_type(callback) != "function": raise ScriptError( { "argument": "callback", "message": "splash:call_later callback is not a function", "splash_method": "call_later", } ) qtimer = QTimer(self.tab) qtimer.setSingleShot(True) # timer is used outside call_later callbacks, so errors # are reported as main Splash errors. timer = _ExposedTimer(self.lua, self.exceptions, qtimer) self._objects_to_clear.add(timer) run_coro = self.get_coroutine_run_func("splash:call_later", callback, return_error=timer.store_error) qtimer.timeout.connect(run_coro) qtimer.start(delay) return timer
def proxyMethod(*args, **kwargs): # We are in the script thread here, we must syncronize with the main # thread before calling the attribute condition.acquire() args = list(args) if len(args) >= 2 and lua_type(args[1]) == 'table': # First parameter is a lua table. Handle this as **kwargs call kwargs = self.wrapLuaToPy(args[1]) del args[1] for i, __arg in enumerate(args): args[i] = self.wrapLuaToPy(args[i]) try: Application().queue(mainThreadCaller, args, kwargs) condition.wait( 20) # Timeout to not let the script hang forever if 'error' in retval: self.log("Error during call: %s", retval['error']) raise AttributeError(retval['error']) elif 'return' in retval: return self.wrapPyToLua(retval['return']) finally: condition.release() raise AttributeError('The call to the function "%s" timed out' % attrName)
def _check_main(main): if main is None: raise ValueError("'main' function is not found") if lupa.lua_type(main) != 'function': raise ValueError("'main' is not a function")
def _decode(o): return dict( table = lambda c: dict(c), ).get(lupa.lua_type(o), lambda o: o)(o)
def _remove_lua_overlays(self): for dofname, dof in Expression.dofs.iteritems(): for overlay in dof.overlays: if lupa.lua_type(overlay) is not None: # It's a Lua value, remove it! dof.overlays.remove(overlay)