From 69912e474dc2d50ebecf6148557b7afd67c1d865 Mon Sep 17 00:00:00 2001 From: EcmaXp Date: Sat, 3 Nov 2018 12:35:26 +0900 Subject: [PATCH] Update OpenPython OS: #24 --- .../resources/assets/openpython/opos/.prop | 1 + .../assets/openpython/opos/boot/01_basic.py | 16 - .../assets/openpython/opos/boot/03_value.py | 3 + .../assets/openpython/opos/boot/04_builtin.py | 20 ++ .../opos/boot/{03_screen.py => 05_screen.py} | 0 .../resources/assets/openpython/opos/init.py | 7 +- .../assets/openpython/opos/lib/computer.py | 2 - .../assets/openpython/opos/lib/event.py | 69 ---- .../opos/lib/{ => internal}/errno.py | 0 .../opos/lib/{ => internal}/heapq.py | 0 .../openpython/opos/lib/{ => internal}/imp.py | 0 .../opos/lib/{ => internal}/json.py | 0 .../opos/lib/{ => internal}/msgpack.py | 0 .../opos/lib/{ => internal}/random.py | 0 .../openpython/opos/lib/{ => internal}/re.py | 0 .../opos/lib/{ => internal}/time.py | 0 .../openpython/opos/lib/micropython/typing.py | 0 .../openpython/opos/lib/openos/colors.py | 44 +++ .../opos/lib/{ => openos}/component.py | 34 +- .../openpython/opos/lib/openos/computer.py | 21 ++ .../openpython/opos/lib/openos/devfs.py | 1 + .../openpython/opos/lib/openos/event.py | 259 +++++++++++++ .../openpython/opos/lib/openos/internet.py | 32 ++ .../openpython/opos/lib/openos/keyboard.py | 236 ++++++++++++ .../assets/openpython/opos/lib/openos/note.py | 24 ++ .../assets/openpython/opos/lib/openos/pipe.py | 4 + .../opos/lib/{ => openos}/process.py | 16 + .../assets/openpython/opos/lib/openos/rc.py | 4 + .../openpython/opos/lib/openos/robot.py | 340 ++++++++++++++++++ .../opos/lib/openos/serialization.py | 15 + .../openpython/opos/lib/openos/shell.py | 8 + .../openpython/opos/lib/openos/sides.py | 29 ++ .../assets/openpython/opos/lib/openos/term.py | 2 + .../assets/openpython/opos/lib/openos/text.py | 2 + .../assets/openpython/opos/lib/openos/tty.py | 61 ++++ .../assets/openpython/opos/lib/openos/uuid.py | 2 + .../openpython/opos/lib/openos/vt100.py | 2 + .../assets/openpython/opos/lib/shell.py | 3 - .../openpython/opos/lib/urllib/parse.py | 3 +- 39 files changed, 1162 insertions(+), 98 deletions(-) create mode 100644 src/main/resources/assets/openpython/opos/.prop create mode 100644 src/main/resources/assets/openpython/opos/boot/03_value.py rename src/main/resources/assets/openpython/opos/boot/{03_screen.py => 05_screen.py} (100%) delete mode 100644 src/main/resources/assets/openpython/opos/lib/computer.py delete mode 100644 src/main/resources/assets/openpython/opos/lib/event.py rename src/main/resources/assets/openpython/opos/lib/{ => internal}/errno.py (100%) rename src/main/resources/assets/openpython/opos/lib/{ => internal}/heapq.py (100%) rename src/main/resources/assets/openpython/opos/lib/{ => internal}/imp.py (100%) rename src/main/resources/assets/openpython/opos/lib/{ => internal}/json.py (100%) rename src/main/resources/assets/openpython/opos/lib/{ => internal}/msgpack.py (100%) rename src/main/resources/assets/openpython/opos/lib/{ => internal}/random.py (100%) rename src/main/resources/assets/openpython/opos/lib/{ => internal}/re.py (100%) rename src/main/resources/assets/openpython/opos/lib/{ => internal}/time.py (100%) delete mode 100644 src/main/resources/assets/openpython/opos/lib/micropython/typing.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/colors.py rename src/main/resources/assets/openpython/opos/lib/{ => openos}/component.py (78%) create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/computer.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/devfs.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/event.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/internet.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/keyboard.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/note.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/pipe.py rename src/main/resources/assets/openpython/opos/lib/{ => openos}/process.py (52%) create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/rc.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/robot.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/serialization.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/shell.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/sides.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/term.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/text.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/tty.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/uuid.py create mode 100644 src/main/resources/assets/openpython/opos/lib/openos/vt100.py delete mode 100644 src/main/resources/assets/openpython/opos/lib/shell.py diff --git a/src/main/resources/assets/openpython/opos/.prop b/src/main/resources/assets/openpython/opos/.prop new file mode 100644 index 00000000..9ba21168 --- /dev/null +++ b/src/main/resources/assets/openpython/opos/.prop @@ -0,0 +1 @@ +{label="OpenPython OS", reboot=true, setlabel=true, setboot=true} \ No newline at end of file diff --git a/src/main/resources/assets/openpython/opos/boot/01_basic.py b/src/main/resources/assets/openpython/opos/boot/01_basic.py index d0f3ad5c..bb431423 100644 --- a/src/main/resources/assets/openpython/opos/boot/01_basic.py +++ b/src/main/resources/assets/openpython/opos/boot/01_basic.py @@ -1,23 +1,7 @@ import machine import event -import value -buf = [] - - -@machine.hook_stdin -def input_handler(): - while not buf: - event.wait(10) - - return int(buf.pop(0)) - - -@event.register("key_down") -def handle_key_down(_0, _1, char, *_): - buf.append(char) event.setup() -value.setup() diff --git a/src/main/resources/assets/openpython/opos/boot/03_value.py b/src/main/resources/assets/openpython/opos/boot/03_value.py new file mode 100644 index 00000000..90383030 --- /dev/null +++ b/src/main/resources/assets/openpython/opos/boot/03_value.py @@ -0,0 +1,3 @@ +import value + +value.setup() diff --git a/src/main/resources/assets/openpython/opos/boot/04_builtin.py b/src/main/resources/assets/openpython/opos/boot/04_builtin.py index 9338b105..11b7600f 100644 --- a/src/main/resources/assets/openpython/opos/boot/04_builtin.py +++ b/src/main/resources/assets/openpython/opos/boot/04_builtin.py @@ -1,6 +1,26 @@ import builtins + +import event +import machine import sys +last_input = [] +buf = [] + + +def check_key_down(name, *_): + return name == "key_down" + + +@machine.hook_stdin +def input_handler(): + while True: + signal = event.pull_filtered(1, check_key_down) + if signal is not None: + _name, _address, char, code, _user = signal + if char: + return int(char) + # noinspection PyShadowingBuiltins def input(prompt=None): diff --git a/src/main/resources/assets/openpython/opos/boot/03_screen.py b/src/main/resources/assets/openpython/opos/boot/05_screen.py similarity index 100% rename from src/main/resources/assets/openpython/opos/boot/03_screen.py rename to src/main/resources/assets/openpython/opos/boot/05_screen.py diff --git a/src/main/resources/assets/openpython/opos/init.py b/src/main/resources/assets/openpython/opos/init.py index 1d2f2f64..81f3c424 100644 --- a/src/main/resources/assets/openpython/opos/init.py +++ b/src/main/resources/assets/openpython/opos/init.py @@ -51,6 +51,9 @@ def print_handler(string): def init(): uos.mount(FileSystem(__path__), '/') sys.path.append('/lib') + sys.path.append('/lib/internal') + sys.path.append('/lib/openos') + sys.path.append('/usr/lib') sys.path.append('/lib/micropython') for filename in sorted(uos.listdir("/boot")): @@ -58,8 +61,8 @@ def init(): # noinspection PyUnresolvedReferences execfile("/boot/" + filename, context) - from shell import spawn - spawn("/bin/python.py") + # from shell import spawn + # spawn("/bin/python.py") if __name__ == "__main__": diff --git a/src/main/resources/assets/openpython/opos/lib/computer.py b/src/main/resources/assets/openpython/opos/lib/computer.py deleted file mode 100644 index 6f434121..00000000 --- a/src/main/resources/assets/openpython/opos/lib/computer.py +++ /dev/null @@ -1,2 +0,0 @@ -# noinspection PyUnresolvedReferences -from ucomputer import * diff --git a/src/main/resources/assets/openpython/opos/lib/event.py b/src/main/resources/assets/openpython/opos/lib/event.py deleted file mode 100644 index 7bc41b30..00000000 --- a/src/main/resources/assets/openpython/opos/lib/event.py +++ /dev/null @@ -1,69 +0,0 @@ -import machine - -from computer import pop_signal - -__all__ = ["register", "unregister", "setup"] - -event = {} -lastInterrupt = None - -registered = {} - - -def signal_handler(ticks): - signal = pop_signal(ticks) - if not signal: - return - - name, args = signal - handlers = registered.get(name) - if not handlers: - return - - for handler in handlers: - try: - handler(name, *args) - except BaseException as e: - machine.debug("signal_handler exc => %s: %s" % (type(e).__name__, e)) - - -def listen(name, callback): - handlers = registered.setdefault(name, []) - if callback in handlers: - return False - - handlers.append(callback) - return True - - -def ignore(name, callback): - handlers = registered.get(name) # type: list - if not handlers: - return False - - if callback not in handlers: - return False - - handlers.remove(callback) - return True - - -def register(name): - def wrapper(callback): - listen(name, callback) - return callback - - return wrapper - - -def unregister(name, func): - handlers = registered.setdefault(name, []) - handlers.remove(func) - - -def setup(): - machine.hook_signal(signal_handler) - - -def wait(ticks): - signal_handler(ticks) diff --git a/src/main/resources/assets/openpython/opos/lib/errno.py b/src/main/resources/assets/openpython/opos/lib/internal/errno.py similarity index 100% rename from src/main/resources/assets/openpython/opos/lib/errno.py rename to src/main/resources/assets/openpython/opos/lib/internal/errno.py diff --git a/src/main/resources/assets/openpython/opos/lib/heapq.py b/src/main/resources/assets/openpython/opos/lib/internal/heapq.py similarity index 100% rename from src/main/resources/assets/openpython/opos/lib/heapq.py rename to src/main/resources/assets/openpython/opos/lib/internal/heapq.py diff --git a/src/main/resources/assets/openpython/opos/lib/imp.py b/src/main/resources/assets/openpython/opos/lib/internal/imp.py similarity index 100% rename from src/main/resources/assets/openpython/opos/lib/imp.py rename to src/main/resources/assets/openpython/opos/lib/internal/imp.py diff --git a/src/main/resources/assets/openpython/opos/lib/json.py b/src/main/resources/assets/openpython/opos/lib/internal/json.py similarity index 100% rename from src/main/resources/assets/openpython/opos/lib/json.py rename to src/main/resources/assets/openpython/opos/lib/internal/json.py diff --git a/src/main/resources/assets/openpython/opos/lib/msgpack.py b/src/main/resources/assets/openpython/opos/lib/internal/msgpack.py similarity index 100% rename from src/main/resources/assets/openpython/opos/lib/msgpack.py rename to src/main/resources/assets/openpython/opos/lib/internal/msgpack.py diff --git a/src/main/resources/assets/openpython/opos/lib/random.py b/src/main/resources/assets/openpython/opos/lib/internal/random.py similarity index 100% rename from src/main/resources/assets/openpython/opos/lib/random.py rename to src/main/resources/assets/openpython/opos/lib/internal/random.py diff --git a/src/main/resources/assets/openpython/opos/lib/re.py b/src/main/resources/assets/openpython/opos/lib/internal/re.py similarity index 100% rename from src/main/resources/assets/openpython/opos/lib/re.py rename to src/main/resources/assets/openpython/opos/lib/internal/re.py diff --git a/src/main/resources/assets/openpython/opos/lib/time.py b/src/main/resources/assets/openpython/opos/lib/internal/time.py similarity index 100% rename from src/main/resources/assets/openpython/opos/lib/time.py rename to src/main/resources/assets/openpython/opos/lib/internal/time.py diff --git a/src/main/resources/assets/openpython/opos/lib/micropython/typing.py b/src/main/resources/assets/openpython/opos/lib/micropython/typing.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/main/resources/assets/openpython/opos/lib/openos/colors.py b/src/main/resources/assets/openpython/opos/lib/openos/colors.py new file mode 100644 index 00000000..79791b09 --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/colors.py @@ -0,0 +1,44 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/colors.lua + +from micropython import const + +__all__ = ["WHITE", "ORANGE", "MAGENTA", "LIGHTBLUE", + "YELLOW", "LIME", "PINK", "GRAY", + "SILVER", "CYAN", "PURPLE", "BLUE", + "BROWN", "GREEN", "RED", "BLACK"] + +WHITE = const(0) +ORANGE = const(1) +MAGENTA = const(2) +LIGHTBLUE = const(3) +YELLOW = const(4) +LIME = const(5) +PINK = const(6) +GRAY = const(7) +SILVER = const(8) +CYAN = const(9) +PURPLE = const(10) +BLUE = const(11) +BROWN = const(12) +GREEN = const(13) +RED = const(14) +BLACK = const(15) + +# alias +white = WHITE +orange = ORANGE +magenta = MAGENTA +lightblue = LIGHTBLUE +yellow = YELLOW +lime = LIME +pink = PINK +gray = GRAY +silver = SILVER +cyan = CYAN +purple = PURPLE +blue = BLUE +brown = BROWN +green = GREEN +red = RED +black = BLACK diff --git a/src/main/resources/assets/openpython/opos/lib/component.py b/src/main/resources/assets/openpython/opos/lib/openos/component.py similarity index 78% rename from src/main/resources/assets/openpython/opos/lib/component.py rename to src/main/resources/assets/openpython/opos/lib/openos/component.py index 623d14ed..b193f4c6 100644 --- a/src/main/resources/assets/openpython/opos/lib/component.py +++ b/src/main/resources/assets/openpython/opos/lib/openos/component.py @@ -1,10 +1,11 @@ -from ucomponent import invoke, get_methods, get_doc, get_list, get_type, get_slot +from ucomponent import invoke, invokes, get_methods, get_doc, get_list, get_type, get_slot import event +import sys _list = list -__all__ = ['Component', 'is_available', 'get_primary', 'get_primary_checked', 'set_primary'] +__all__ = ['Component', 'is_available', 'get_primary', 'get_primary_checked', 'set_primary', 'guard'] primaries = {} @@ -19,6 +20,15 @@ def __init__(self, component, name): def __call__(self, *args): return invoke(self.component.address, self.name, *args) + def call(self, *args): + return self(*args) # alias + + def _call(self, *args): + return invokes(self.component.address, self.name, *args) + + def _guard_call(self, count, *args): + return guard(self._call(*args), count) + @property def __doc__(self): return doc(self.component.address, self.name) @@ -128,14 +138,21 @@ def set_primary(component_type: str, address: str): primaries[component_type] = proxy(address) -@event.register("component_added") +def guard(result, count: int): + if isinstance(result, tuple): + return result + (None,) * (count - len(result)) + else: + return (result,) + (None,) * (count - 1) + + +@event.on("component_added") def on_component_added(_, address, component_type): prev = primaries.get(component_type) if prev is None: primaries[component_type] = proxy(address) -@event.register("component_removed") +@event.on("component_removed") def on_component_removed(_, address, component_type): prev = primaries.get(component_type) if prev is not None and prev.address == address: @@ -150,3 +167,12 @@ def setup(): for address, component_type in get_list().items(): if not is_available(component_type): set_primary(component_type, address) + + +def import_component(component_type: str, module_name: str) -> Component: + component = get_primary(component_type) + if component is None: + del sys.modules[module_name] + raise ImportError("component {!r} is missing; import {!r} failed".format(component_type, module_name)) + + return component diff --git a/src/main/resources/assets/openpython/opos/lib/openos/computer.py b/src/main/resources/assets/openpython/opos/lib/openos/computer.py new file mode 100644 index 00000000..50a29e2d --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/computer.py @@ -0,0 +1,21 @@ +# noinspection PyUnresolvedReferences +from ucomputer import * +import ucomputer +import utime + + +def address(): + return ucomputer.get_computer_address() + + +def uptime(): + return utime.time_up() + + +def pull_signal(seconds): + signal = ucomputer.pop_signal(int(seconds * 20)) + if signal is None: + return None + + name, args = signal + return (name,) + args diff --git a/src/main/resources/assets/openpython/opos/lib/openos/devfs.py b/src/main/resources/assets/openpython/opos/lib/openos/devfs.py new file mode 100644 index 00000000..30e73a04 --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/devfs.py @@ -0,0 +1 @@ +raise NotImplementedError diff --git a/src/main/resources/assets/openpython/opos/lib/openos/event.py b/src/main/resources/assets/openpython/opos/lib/openos/event.py new file mode 100644 index 00000000..aad8bf2f --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/event.py @@ -0,0 +1,259 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/event.lua +# - src/main/resources/assets/opencomputers/loot/openos/lib/core/full_event.lua + +import sys + +import computer +import machine +import process + +from computer import pop_signal + +__all__ = ["Handlers", "on", "listen", "pull", "pull_filtered", "pull_multiple", "cancel", "ignore"] + +INF = sys.maxsize +ALWAYS = None +TIMER = False +EMPTY = () + +last_interrupt = -1 + +keyboard = None + + +class Handler: + def __init__(self, key, callback, interval: float = None, times=None): + self.key = key + self.callback = callback + self.times = times + self.interval = interval # timer + self.timeout = INF if interval is None else computer.uptime() + interval # timer + + +class Handlers: + def __init__(self): + self.callback_by_event = {} + self.registered = {} + + def register(self, handler: Handler): + self.registered[id(handler)] = handler + + seq = self.callback_by_event.setdefault(handler.key, []) + seq.append(handler) + + return id(handler) + + def unregister(self, handler: Handler): + handler = self.registered.pop(id(handler), None) + if handler is not None: + key = handler.key + seq = self.callback_by_event[key] # type: list + seq.remove(handler) + if not seq: + del self.callback_by_event[key] + + return handler is None + + def iter_all_handlers(self): + return self.registered.values() + + def get_handlers(self, name): + return self.callback_by_event.get(name) or EMPTY + + def unregister_by_id(self, timer_id): + handler = self.registered.get(timer_id) + return self.unregister(handler) + + +handlers = Handlers() + + +def register(key, callback, interval=INF, times=INF, opt_handlers: Handlers = None): + opt_handlers = opt_handlers if opt_handlers is not None else handlers + handler = Handler(key, callback, interval, times) + return opt_handlers.register(handler) + + +def create_plain_filter(name, *args): + def func(sname, *sargs): + if name != sname: + return False + + for arg, sarg in zip(args, sargs): + if arg is not None and arg != sarg: + return False + + return True + + return func + + +def create_multiple_filter(*args): + def func(name, *_): + for arg in args: + if arg == name: + return True + + return False + + return func + + +def signal_handler(ticks): + global last_interrupt + current_time = computer.uptime() + interrupting = ( + current_time - last_interrupt > 1 and + keyboard.is_control_down() and + keyboard.is_key_down(keyboard.KEYS.c) + ) if keyboard else False + + if interrupting: + last_interrupt = current_time + if keyboard and keyboard.is_alt_down(): + process.current_process().signal("INTERRUPTED") + + push("interrupted", current_time) + + removes = set() + signal = pop_signal(ticks) + + def process_handler(etype, signal): + for handler in handlers.get_handlers(etype): # type: Handler + is_timer = handler.timeout is not None + if is_timer and current_time < handler.timeout: + continue + + if handler.times is not None: + handler.times -= 1 + if handler.times <= 0: + removes.add(handler) + elif handler.interval is not None: + handler.timeout = current_time + handler.interval + + try: + name, args = signal + result = handler.callback(name, *args) + except BaseException as e: + on_error(e) + else: + if result is False: + removes.add(handler) + + process_handler(TIMER, None) + for handler in removes: + handlers.unregister(handler) + + if signal is None: + return + + removes = set() + name, args = signal + process_handler(ALWAYS, signal) + process_handler(name, signal) + + for handler in removes: + handlers.unregister(handler) + + return (name,) + args + + +def on(name): + def wrapper(callback): + listen(name, callback) + return callback + + return wrapper + + +def listen(name, callback): + for handler in handlers.registered.values(): + if handler.key == name and handler.callback == callback: + return False + + return register(name, callback) + + +def ignore(name, callback): + removes = set() + for handler in handlers.iter_all_handlers(): + if handler.key == name and handler.callback == callback: + removes.add(handler) + break # ..? + + for handler in removes: + handlers.unregister(handler) + + return len(removes) > 0 + + +def timer(interval: float, callback, times: int): + return register(TIMER, callback, interval, times) + + +def cancel(timer_id): + return handlers.unregister_by_id(timer_id) + + +def push(name, *args): + computer.push_signal(name, *args) + + +def pull(first, *args): + if isinstance(first, str): + return pull_filtered(create_plain_filter(first, *args)) + else: + return pull_filtered(first, create_plain_filter(*args)) + + +def pull_filtered(first, second=None): + seconds = INF + func = None + + if callable(first) and second is None: + func = first + elif callable(second): + seconds = first + func = second + + deadline = computer.uptime() + seconds + while computer.uptime() < deadline: + closest = deadline + for handler in handlers.iter_all_handlers(): + closest = min(closest, handler.timeout) + + signal = computer.pull_signal(closest - computer.uptime()) + if signal is None: + continue + + if func(*signal): + return signal + + +def pull_multiple(first, *args): + if isinstance(first, int): + return pull_filtered(first, create_multiple_filter(*args)) + else: + return pull_filtered(create_multiple_filter(first, *args)) + + +def on_error(e): + machine.debug("signal_handler exc => %s: %s" % (type(e).__name__, e)) + + +def setup(): + global keyboard + def pull_signal(seconds): + ticks = sys.maxsize if seconds == INF else int(seconds * 20) + return signal_handler(ticks) + + # noinspection PyUnresolvedReferences + import keyboard + + computer.pull_signal = pull_signal + machine.hook_signal(signal_handler) + + +def wait(ticks): + signal_handler(ticks) diff --git a/src/main/resources/assets/openpython/opos/lib/openos/internet.py b/src/main/resources/assets/openpython/opos/lib/openos/internet.py new file mode 100644 index 00000000..54a4d464 --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/internet.py @@ -0,0 +1,32 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# src/main/resources/assets/opencomputers/loot/openos/lib/internet.lua + +import component + +robot = component.import_component("robot", __name__) + + +def request(url: str, data=None, headers: dict = None): + internet = component.get_primary("internet") + + post = None + if data is None: + pass + elif isinstance(data, (str, bytes)): + post = data + elif isinstance(data, dict): + post = "&".join("{}={}".format(key, value) for key, value in data.items()) + else: + raise TypeError + + return internet.request(url, post, headers) + + +def socket(address, port): + internet = component.get_primary("internet") + return internet.socket(address, port) + + +def open(address, port): + internet = component.get_primary("internet") + return internet.open(address, port) diff --git a/src/main/resources/assets/openpython/opos/lib/openos/keyboard.py b/src/main/resources/assets/openpython/opos/lib/openos/keyboard.py new file mode 100644 index 00000000..00e0d715 --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/keyboard.py @@ -0,0 +1,236 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/keyboard.lua +# - src/main/resources/assets/opencomputers/loot/openos/lib/core/full_keyboard.lua + +import component +from micropython import const + +keyboards_pressed_chars = {} +keyboards_pressed_codes = {} + +__all__ = ["get_keyboard_address", "get_pressed_codes", "get_pressed_chars", + "is_alt_down", "is_control", "is_control_down", "is_key_down", "is_shift_down"] + +_LMENU = const(0x38) +_RMENU = const(0xB8) +_LCONTROL = const(0x1D) +_RCONTROL = const(0x9D) +_LSHIFT = const(0x2A) +_RSHIFT = const(0x36) + + +class KEYS: + N1 = 0x02 + N2 = 0x03 + N3 = 0x04 + N4 = 0x05 + N5 = 0x06 + N6 = 0x07 + N7 = 0x08 + N8 = 0x09 + N9 = 0x0A + N0 = 0x0B + A = 0x1E + B = 0x30 + C = 0x2E + D = 0x20 + E = 0x12 + F = 0x21 + G = 0x22 + H = 0x23 + I = 0x17 + J = 0x24 + K = 0x25 + L = 0x26 + M = 0x32 + N = 0x31 + O = 0x18 + P = 0x19 + Q = 0x10 + R = 0x13 + S = 0x1F + T = 0x14 + U = 0x16 + V = 0x2F + W = 0x11 + X = 0x2D + Y = 0x15 + Z = 0x2C + + APOSTROPHE = 0x28 + AT = 0x91 + BACK = 0x0E # BACKSPACE + BACKSLASH = 0x2B + CAPITAL = 0x3A # CAPSLOCK + COLON = 0x92 + COMMA = 0x33 + ENTER = 0x1C + EQUALS = 0x0D + GRAVE = 0x29 # ACCENT GRAVE + LBRACKET = 0x1A + LCONTROL = 0x1D + LMENU = 0x38 # LEFT ALT + LSHIFT = 0x2A + MINUS = 0x0C + NUMLOCK = 0x45 + PAUSE = 0xC5 + PERIOD = 0x34 + RBRACKET = 0x1B + RCONTROL = 0x9D + RMENU = 0xB8 # RIGHT ALT + RSHIFT = 0x36 + SCROLL = 0x46 # SCROLL LOCK + SEMICOLON = 0x27 + SLASH = 0x35 # / ON MAIN KEYBOARD + SPACE = 0x39 + STOP = 0x95 + TAB = 0x0F + UNDERLINE = 0x93 + + # KEYPAD (AND NUMPAD WITH NUMLOCK OFF) + UP = 0xC8 + DOWN = 0xD0 + LEFT = 0xCB + RIGHT = 0xCD + HOME = 0xC7 + END = 0xCF + PAGEUP = 0xC9 + PAGEDOWN = 0xD1 + INSERT = 0xD2 + DELETE = 0xD3 + + # FUNCTION KEYS + F1 = 0x3B + F2 = 0x3C + F3 = 0x3D + F4 = 0x3E + F5 = 0x3F + F6 = 0x40 + F7 = 0x41 + F8 = 0x42 + F9 = 0x43 + F10 = 0x44 + F11 = 0x57 + F12 = 0x58 + F13 = 0x64 + F14 = 0x65 + F15 = 0x66 + F16 = 0x67 + F17 = 0x68 + F18 = 0x69 + F19 = 0x71 + + # JAPANESE KEYBOARDS + KANA = 0x70 + KANJI = 0x94 + CONVERT = 0x79 + NOCONVERT = 0x7B + YEN = 0x7D + CIRCUMFLEX = 0x90 + AX = 0x96 + + # NUMPAD + NUMPAD0 = 0x52 + NUMPAD1 = 0x4F + NUMPAD2 = 0x50 + NUMPAD3 = 0x51 + NUMPAD4 = 0x4B + NUMPAD5 = 0x4C + NUMPAD6 = 0x4D + NUMPAD7 = 0x47 + NUMPAD8 = 0x48 + NUMPAD9 = 0x49 + NUMPADMUL = 0x37 + NUMPADDIV = 0xB5 + NUMPADSUB = 0x4A + NUMPADADD = 0x4E + NUMPADDECIMAL = 0x53 + NUMPADCOMMA = 0xB3 + NUMPADENTER = 0x9C + NUMPADEQUALS = 0x8D + + def __init__(self): + index = {} + for name in dir(self): + value = getattr(self, name) + if isinstance(value, int): + if name.startswith("N") and len(name) == 2: + index[name[1:]] = value + index[name] = value + index[value] = name + elif len(name) == 1: + index[name.upper()] = value + index[name.lower()] = value + index[value] = name + else: + index[name] = value + index[value] = name + + self._index = index + + def __getitem__(self, item): + return self._index[item] + + +KEYS = KEYS() + +assert _LMENU == KEYS.LMENU +assert _RMENU == KEYS.RMENU +assert _LCONTROL == KEYS.LCONTROL +assert _RCONTROL == KEYS.RCONTROL +assert _LSHIFT == KEYS.LSHIFT +assert _RSHIFT == KEYS.RSHIFT + + +def get_keyboard_address(address=None): + if address is not None: + return address + + keyboard = component.get_primary("keyboard") + if keyboard is not None: + return keyboard.address + + return None + + +def get_pressed_codes(address=None): + address = get_keyboard_address(address) + return keyboards_pressed_codes.get(address) if address else None + + +def get_pressed_chars(address=None): + address = get_keyboard_address(address) + return keyboards_pressed_chars.get(address) if address else None + + +def is_alt_down(address=None) -> bool: + pressed_codes = get_pressed_codes(address) + return (pressed_codes.get(_LMENU) or pressed_codes.get(_RMENU)) \ + if pressed_codes is not None else False + + +def is_control(char: int) -> bool: + return ((char < 0x20) or (0x7F <= char <= 0x9F)) if isinstance(char, int) else False + + +def is_control_down(address=None) -> bool: + pressed_codes = get_pressed_codes(address) + return pressed_codes.get(_LCONTROL) or pressed_codes.get(_RCONTROL) \ + if pressed_codes is not None else False + + +def is_key_down(char_or_code, address=None) -> bool: + if isinstance(char_or_code, str): + pressed_chars = get_pressed_chars(address) + return bool(pressed_chars.get(char_or_code)) \ + if pressed_chars is not None else False + else: + pressed_codes = get_pressed_codes(address) + return bool(pressed_codes.get(char_or_code)) \ + if pressed_codes is not None else False + + +def is_shift_down(address=None): + pressed_codes = get_pressed_codes(address) + return pressed_codes.get(_LSHIFT) or pressed_codes.get(_RSHIFT) \ + if pressed_codes is not None else False diff --git a/src/main/resources/assets/openpython/opos/lib/openos/note.py b/src/main/resources/assets/openpython/opos/lib/openos/note.py new file mode 100644 index 00000000..4d3c64c3 --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/note.py @@ -0,0 +1,24 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/note.lua + +note = {} +notes = {} # The table that maps note names to their respective MIDI codes +reverseNotes = {} # The reversed table "notes" + +tempNotes = ["c", "c#", "d", "d#", "e", "f", "f#", "g", "g#", "a", "a#", "b"] +sNotes = ["a0", "a#0", "b0"] +bNotes = ["bb0"] + +for i in range(1, 6 + 1): + for v in tempNotes: + sNotes.append(v + str(i)) + if len(v) == 1 and v != "c" and v != "f": + bNotes.append(v + "b" + str(i)) + +for v in range(21, 95 + 1): + k = sNotes[v - 20 - 1] + notes[k] = str(v) + reverseNotes[v] = k + +# TODO: ? +raise NotImplementedError diff --git a/src/main/resources/assets/openpython/opos/lib/openos/pipe.py b/src/main/resources/assets/openpython/opos/lib/openos/pipe.py new file mode 100644 index 00000000..da847436 --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/pipe.py @@ -0,0 +1,4 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/pipe.lua + +raise NotImplementedError diff --git a/src/main/resources/assets/openpython/opos/lib/process.py b/src/main/resources/assets/openpython/opos/lib/openos/process.py similarity index 52% rename from src/main/resources/assets/openpython/opos/lib/process.py rename to src/main/resources/assets/openpython/opos/lib/openos/process.py index 1c8e43b1..42e8860e 100644 --- a/src/main/resources/assets/openpython/opos/lib/process.py +++ b/src/main/resources/assets/openpython/opos/lib/openos/process.py @@ -1,3 +1,6 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/process.lua + try: import usys as sys except ImportError: @@ -12,13 +15,26 @@ def __init__(self, context): self.context = context +_current_proccess = Process({}) + + def spawn(path): + global _current_proccess context = {'__name__': '__main__', '__path__': path} + proc = Process({}) + parent_proc, _current_proccess = _current_proccess, proc + try: # noinspection PyUnresolvedReferences execfile(path, context) except SystemExit as e: return e.code + finally: + _current_proccess = parent_proc return 0 + + +def current_process(): + return _current_proccess diff --git a/src/main/resources/assets/openpython/opos/lib/openos/rc.py b/src/main/resources/assets/openpython/opos/lib/openos/rc.py new file mode 100644 index 00000000..79658ca1 --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/rc.py @@ -0,0 +1,4 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/rc.lua + +loaded = {} diff --git a/src/main/resources/assets/openpython/opos/lib/openos/robot.py b/src/main/resources/assets/openpython/opos/lib/openos/robot.py new file mode 100644 index 00000000..e51cac56 --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/robot.py @@ -0,0 +1,340 @@ +from micropython import const + +import component +import random +from sides import * + +robot = component.import_component("robot", __name__) + +__all__ = [ + # General + "name", "get_light_color", "set_light_color", + + # World + "detect", + + # Inventory + "slot", "compare", "drop", "place", "suck", + + # Tool + "durability", "swing", "use", + + # Movement + "move", "forward", "back", "up", "down", "turn", + + # Tank + "tank", "compare_fluid", "drain", "fill", +] + +# check sides.py +DOWN = const(0) +UP = const(1) +BACK = const(2) +FRONT = const(3) + + +class SidedMethod: + def __init__(self, func): + self.func = func + + def __doc__(self): + return self.func.__doc__ + + # __str__, __repr__ later + + def __call__(self, *args): + return self.front(*args) + + def front(self, *args): + return self.func(FRONT, *args) + + def up(self, *args): + return self.func(UP, *args) + + def down(self, *args): + return self.func(DOWN, *args) + + +class SidedContextMethod: + def __init__(self, func, context_func): + self.func = func + self.context_func = context_func + + def __doc__(self): + return self.func.__doc__ + + # __str__, __repr__ later + + def __call__(self, *args): + return self.front(*args) + + def front(self, *args): + with self.context_func(): + return self.func(FRONT, *args) + + def up(self, *args): + with self.context_func(): + return self.func(UP, *args) + + def down(self, *args): + with self.context_func(): + return self.func(DOWN, *args) + + + + +class RobotResult: + def __init__(self, result): + self.result = result + + @property + def success(self): + return self.result[0] + + @property + def reason(self): + return self.result[1] if len(self.result) >= 2 else None + + def unwarp(self): + if not self: + raise Exception(self.reason) + + return True + + def __bool__(self): + return bool(self.success) + + @classmethod + def proxy(cls, method): + # noinspection PyProtectedMember + func = method._call + + return lambda *args: cls(func(*args)) + + def __repr__(self): + if self: + return "" + else: + if self.reason is None: + return "" + else: + return "".format(self.reason) + + +def all_slots(): + pass + + +# General +def name(): + return robot.name() + + +def get_light_color() -> int: + return robot.getLightColor() + + +def set_light_color(color: int): + return robot.setLightColor(color) + + +# World +detect = SidedMethod(robot.detect) + + +# Inventory +class SlotContext: + def __init__(self, slot): + self.slot = slot + self.selected = None + + def __enter__(self): + self.selected = robot.select() + robot.select(self.slot) + + def __exit__(self, exc_type, exc_val, exc_tb): + robot.select(self.slot) + + +class Slot: + @classmethod + def selected(cls): + return robot.select() + + @classmethod + def size(cls): + return robot.inventorySize() + + def __init__(self, slot): + self.slot = slot + + def __int__(self): + return self.slot + + def select(self): + success = robot.select(self.slot) == self.slot + if success: + _SELECTED_SLOT = self.slot + + return success + + @property + def count(self): + return robot.count(self.slot) + + @property + def space(self): + return robot.space(self.slot) + + def context(self): + return SlotContext(self.slot) + + def compare_to(self, another_slot): + with self.context(): + return robot.compareTo(another_slot) + + def transfer(self, new_slot, count: int): + with self.context(): + return robot.transferTo(new_slot, count) + + @property + def compare(self): + return SidedContextMethod(robot.compare, self.context) + + @property + def drop(self): + return SidedContextMethod(robot.drop, self.context) + + @property + def place(self): + return SidedContextMethod(robot.place, self.context) + + @property + def suck(self): + return SidedContextMethod(robot.suck, self.context) + + +slot = Slot + +# Inventory + World +compare = SidedMethod(robot.compare) +drop = SidedMethod(robot.drop) +place = SidedMethod(RobotResult.proxy(robot.place)) +suck = SidedMethod(robot.suck) + +# Tool +durability = robot.durability +swing = SidedMethod(RobotResult.proxy(robot.swing)) +use = SidedMethod(RobotResult.proxy(robot.use)) + + +# Movement + + +class Move: + def __init__(self): + self._move = RobotResult.proxy(robot.move) + + def forward(self): + return self._move(FRONT) + + def back(self): + return self._move(BACK) + + def up(self): + return self._move(UP) + + def down(self): + return self._move(DOWN) + + +move = Move() +forward = move.forward +back = move.back +up = move.up +down = move.down + + +class Turn: + def __init__(self): + self._turn = RobotResult.proxy(robot.turn) + + def left(self): + return self._turn(False) + + def right(self): + return self._turn(True) + + def around(self): + turn = random.random() > 0.5 + return self._turn(turn) and self._turn(turn) + + +turn = Turn() + + +# Tank +class TankContext: + def __init__(self, tank): + self.tank = tank + self.selected = None + + def __enter__(self): + self.selected = robot.selectTank() + robot.selectTank(self.tank) + + def __exit__(self, exc_type, exc_val, exc_tb): + robot.selectTank(self.tank) + + +class Tank: + @classmethod + def selected(cls): + return robot.selectTank() + + def __init__(self, slot): + self.tank = slot + + def __int__(self): + return self.tank + + def select(self): + return robot.selectTank(self.tank) == self.tank + + @property + def level(self): + return robot.tankLevel(self.tank) + + @property + def space(self): + return robot.tankSpace(self.tank) + + def context(self): + return TankContext(self.tank) + + def compare_to(self, another_tank): + with self.context(): + return robot.compareFluidTo(another_tank) + + def transfer(self, new_tank, count: int): + with self.context(): + return robot.transferFluidTo(new_tank, count) + + @property + def compare(self): + return SidedContextMethod(robot.compareFluid, self.context) + + @property + def drain(self): + return SidedContextMethod(robot.drain, self.context) + + @property + def fill(self): + return SidedContextMethod(robot.fill, self.context) + + +tank = Tank + +compare_fluid = SidedMethod(robot.compareFluid) +drain = SidedMethod(robot.drain) +fill = SidedMethod(robot.fill) diff --git a/src/main/resources/assets/openpython/opos/lib/openos/serialization.py b/src/main/resources/assets/openpython/opos/lib/openos/serialization.py new file mode 100644 index 00000000..36c200ff --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/serialization.py @@ -0,0 +1,15 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/serialization.lua + +__all__ = ["serialize", "unserialize"] + + +def serialize(value, pretty=False): + raise NotImplementedError + + +def unserialize(value): + raise NotImplementedError + + +raise NotImplementedError diff --git a/src/main/resources/assets/openpython/opos/lib/openos/shell.py b/src/main/resources/assets/openpython/opos/lib/openos/shell.py new file mode 100644 index 00000000..b0b4b7ec --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/shell.py @@ -0,0 +1,8 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/shell.lua +# - src/main/resources/assets/opencomputers/loot/openos/lib/core/full_shell.lua + + +from process import spawn + +__all__ = ["spawn"] diff --git a/src/main/resources/assets/openpython/opos/lib/openos/sides.py b/src/main/resources/assets/openpython/opos/lib/openos/sides.py new file mode 100644 index 00000000..52637b6d --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/sides.py @@ -0,0 +1,29 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/sides.lua + +from micropython import const + +__all__ = ["BOTTOM", "TOP", "BACK", "FRONT", "RIGHT", "LEFT"] + +BOTTOM = const(0) +TOP = const(1) +BACK = const(2) +FRONT = const(3) +RIGHT = const(4) +LEFT = const(5) + +# alias +NEGY = DOWN = BOTTOM +POSY = UP = TOP +NEGZ = NORTH = BACK +POSZ = SOUTH = FORWARD = FRONT +NEGX = WEST = RIGHT +POSX = EAST = LEFT + +# alias for lowercase +negy = down = bottom = BOTTOM +posy = up = top = TOP +negz = north = back = BACK +posz = south = forward = front = FRONT +negx = west = right = RIGHT +posx = east = left = LEFT diff --git a/src/main/resources/assets/openpython/opos/lib/openos/term.py b/src/main/resources/assets/openpython/opos/lib/openos/term.py new file mode 100644 index 00000000..5826e715 --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/term.py @@ -0,0 +1,2 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/term.lua diff --git a/src/main/resources/assets/openpython/opos/lib/openos/text.py b/src/main/resources/assets/openpython/opos/lib/openos/text.py new file mode 100644 index 00000000..d9e33f05 --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/text.py @@ -0,0 +1,2 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/text.lua diff --git a/src/main/resources/assets/openpython/opos/lib/openos/tty.py b/src/main/resources/assets/openpython/opos/lib/openos/tty.py new file mode 100644 index 00000000..cc7fe9ba --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/tty.py @@ -0,0 +1,61 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/tty.lua + +import event + +__all__ = "window" + +screen_cache = {} +gpu_intercept = {} + + +class Window: + def __init__(self): + self.fullscreen = True + self.blink = True + self.dx = 0 + self.dy = 0 + self.x = 0 + self.y = 1 + self.width = None + self.height = None + self.output_buffer = "" + self.stream = None + self.gpu = None + + @property + def screen(self): + return self.gpu.getScreen() if self.gpu else None + + def get_viewport(self): + screen = self.screen + if self.fullscreen and screen and not screen_cache[screen]: + screen_cache[screen] = True + self.height, self.height = self.gpu.getViewPort() + + return self.width, self.height, self.dx, self.dy, self.x, self.y + + def clear(self): + self.stream.scroll(None) + self.set_cursor(1, 1) + + def is_available(self): + return bool(self.gpu and self.screen) + + def bind(self, gpu): + + +class WindowStream: + def read(self): + pass + + def write(self, value): + pass + + +window = Window() + + +@event.on("screen_resized") +def screen_reset(_name, gpu, addr): + pass diff --git a/src/main/resources/assets/openpython/opos/lib/openos/uuid.py b/src/main/resources/assets/openpython/opos/lib/openos/uuid.py new file mode 100644 index 00000000..282a4c93 --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/uuid.py @@ -0,0 +1,2 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/uuid.lua diff --git a/src/main/resources/assets/openpython/opos/lib/openos/vt100.py b/src/main/resources/assets/openpython/opos/lib/openos/vt100.py new file mode 100644 index 00000000..6c8dec04 --- /dev/null +++ b/src/main/resources/assets/openpython/opos/lib/openos/vt100.py @@ -0,0 +1,2 @@ +# https://github.com/MightyPirates/OpenComputers/blob/master-MC1.12/ +# - src/main/resources/assets/opencomputers/loot/openos/lib/vt100.lua diff --git a/src/main/resources/assets/openpython/opos/lib/shell.py b/src/main/resources/assets/openpython/opos/lib/shell.py deleted file mode 100644 index 1825b89a..00000000 --- a/src/main/resources/assets/openpython/opos/lib/shell.py +++ /dev/null @@ -1,3 +0,0 @@ -from process import spawn - -__all__ = ["spawn"] diff --git a/src/main/resources/assets/openpython/opos/lib/urllib/parse.py b/src/main/resources/assets/openpython/opos/lib/urllib/parse.py index 8e65d2bf..17734bb4 100644 --- a/src/main/resources/assets/openpython/opos/lib/urllib/parse.py +++ b/src/main/resources/assets/openpython/opos/lib/urllib/parse.py @@ -28,7 +28,6 @@ """ import re -import sys import collections __all__ = ["urlparse", "urlunparse", "urljoin", "urldefrag", @@ -890,7 +889,7 @@ def splitpasswd(user): global _passwdprog if _passwdprog is None: import re - _passwdprog = re.compile('^([^:]*):(.*)$',re.S) + _passwdprog = re.compile('^([^:]*):(.*)$', re.S) match = _passwdprog.match(user) if match: return match.group(1, 2)