From 934fcdd4af9e85084c7600c40f2ca14c32ce073f Mon Sep 17 00:00:00 2001 From: weishao Date: Mon, 21 Feb 2022 18:16:46 +0800 Subject: [PATCH] init --- commands.txt | 1 + console.py | 115 + io_wrapper.py | 69 + log.py | 27 + parser.py | 40 + pdb_wrapper.py | 242 ++ precompiled/__deserializer__.py | 248 ++ precompiled/__init__.py | 1 + precompiled/__serializer__.py | 193 ++ precompiled/__settings__.py | 12 + precompiled/__utils__.py | 13 + precompiled/listnode.py | 70 + precompiled/nestedinteger.py | 76 + precompiled/treenode.py | 112 + server.py | 100 + source.txt | 3645 +++++++++++++++++++++ user.out | 1 + user_code/__init__.py | 1 + user_code/input.txt | 2 + user_code/precompiled/__deserializer__.py | 248 ++ user_code/precompiled/__init__.py | 0 user_code/precompiled/__serializer__.py | 193 ++ user_code/precompiled/__settings__.py | 12 + user_code/precompiled/__utils__.py | 13 + user_code/precompiled/listnode.py | 70 + user_code/precompiled/nestedinteger.py | 76 + user_code/precompiled/treenode.py | 112 + user_code/prog.py | 33 + user_code/prog_joined.py | 82 + user_code/stdout.txt | 1 + 30 files changed, 5808 insertions(+) create mode 100644 commands.txt create mode 100644 console.py create mode 100644 io_wrapper.py create mode 100644 log.py create mode 100644 parser.py create mode 100644 pdb_wrapper.py create mode 100644 precompiled/__deserializer__.py create mode 100644 precompiled/__init__.py create mode 100644 precompiled/__serializer__.py create mode 100644 precompiled/__settings__.py create mode 100644 precompiled/__utils__.py create mode 100644 precompiled/listnode.py create mode 100644 precompiled/nestedinteger.py create mode 100644 precompiled/treenode.py create mode 100644 server.py create mode 100644 source.txt create mode 100644 user.out create mode 100644 user_code/__init__.py create mode 100644 user_code/input.txt create mode 100644 user_code/precompiled/__deserializer__.py create mode 100644 user_code/precompiled/__init__.py create mode 100644 user_code/precompiled/__serializer__.py create mode 100644 user_code/precompiled/__settings__.py create mode 100644 user_code/precompiled/__utils__.py create mode 100644 user_code/precompiled/listnode.py create mode 100644 user_code/precompiled/nestedinteger.py create mode 100644 user_code/precompiled/treenode.py create mode 100644 user_code/prog.py create mode 100644 user_code/prog_joined.py create mode 100644 user_code/stdout.txt diff --git a/commands.txt b/commands.txt new file mode 100644 index 0000000..8f5d3c6 --- /dev/null +++ b/commands.txt @@ -0,0 +1 @@ +stepcontinue diff --git a/console.py b/console.py new file mode 100644 index 0000000..af5f689 --- /dev/null +++ b/console.py @@ -0,0 +1,115 @@ +# Forked from https://raw.githubusercontent.com/romanvm/python-web-pdb +from __future__ import absolute_import +from __future__ import unicode_literals + +import sys +import weakref +from threading import Event +from threading import RLock + +try: + import queue +except ImportError: + import Queue as queue + + +class ThreadSafeObject(object): + """ + An object for data exchange between threads + """ + + def __init__(self, contents=None): + self._lock = RLock() + self._contents = contents + + @property + def contents(self): + with self._lock: + return self._contents + + @contents.setter + def contents(self, value): + with self._lock: + self._contents = value + + +class Console(object): + input_queue = queue.Queue() + + def __init__(self, debugger): + self.pdb_not_busy = Event() + self.closed = False + self._debugger = weakref.proxy(debugger) + self._console_history = ThreadSafeObject("") + self._frame_data = ThreadSafeObject({}) + self._output_lock = RLock() + self.exception = None + + @property + def seekable(self): + return False + + @property + def writable(self): + return True + + @property + def encoding(self): + return "utf-8" + + def close(self): + self.closed = True + self.pdb_not_busy.set() + + def readline(self): + self.pdb_not_busy.set() + command = self.input_queue.get() + self.pdb_not_busy.clear() + + if not command: + command = "\n" + + with open("commands.txt", "a+") as file: + file.write(command) + self.writeline(command) + return command + + read = readline + + def writeline(self, data): + with self._output_lock: + if isinstance(data, bytes): + data = data.decode("utf-8") + + self._console_history.contents += data + try: + frame_data = self._debugger.get_current_frame_data() + except (IOError, AttributeError): + frame_data = { + "dirname": "", + "filename": "", + "file_listing": "No data available", + "current_line": -1, + "breakpoints": [], + "globals": {}, + "locals": {}, + "expressions": {}, + "exception": sys.exc_info(), + } + + frame_data["console_history"] = self._console_history.contents + self._frame_data.contents = frame_data + + write = writeline + + def flush(self): + pass + + def send_pdb_command(self, command): + self.pdb_not_busy.wait() + self.input_queue.put(command) + + def get_frame_data(self): + with self._output_lock: + return self._frame_data.contents + diff --git a/io_wrapper.py b/io_wrapper.py new file mode 100644 index 0000000..2957e9d --- /dev/null +++ b/io_wrapper.py @@ -0,0 +1,69 @@ +import sys + +is_python3 = sys.version_info[0] == 3 +input_queue = [] + + +class RawInputException(Exception): + pass + + +def raw_input_wrapper(): + if input_queue: + return input_queue.pop(0) + raise RawInputException() + + +def python2_input_wrapper(): + # Python 2 input() does eval(raw_input()) + if input_queue: + input_str = input_queue.pop(0) + return eval(input_str) + raise RawInputException() + + +def stream_stdin(): + while input_queue: + item = input_queue.pop(0) + yield item + + +def override_input(): + if is_python3: + import builtins + else: + import __builtin__ as builtins + + with open("user_code/input.txt") as file: + global input_queue + input_queue = list(file.readlines()) + + builtins.raw_input = raw_input_wrapper + + if is_python3: + builtins.input = raw_input_wrapper + else: + builtins.input = python2_input_wrapper + + sys.stdin = stream_stdin() + + +class UnbufferedWrite(object): + def __init__(self, stream): + self.stream = stream + + def write(self, data): + self.stream.write(data) + self.stream.flush() + + def writelines(self, datas): + self.stream.writelines(datas) + self.stream.flush() + + def __getattr__(self, attr): + return getattr(self.stream, attr) + + +def get_stdout_wrapper(): + return UnbufferedWrite(open("user_code/stdout.txt", "w")) + diff --git a/log.py b/log.py new file mode 100644 index 0000000..0f5eb2b --- /dev/null +++ b/log.py @@ -0,0 +1,27 @@ +import logging +import sys + + +def get_logger(): + logging.basicConfig(stream=sys.__stdout__, level=logging.DEBUG) + log = logging.getLogger("werkzeug") + return log + + +def debug(*args): + msg = "\n".join(map(str, args)) + logger = get_logger() + logger.debug(msg, extra={"stack": True}) + + +def info(*args): + msg = "\n".join(map(str, args)) + logger = get_logger() + logger.info(msg, extra={"stack": True}) + + +def error(*args): + msg = "\n".join(map(str, args)) + logger = get_logger() + logger.error(msg, extra={"stack": True}) + diff --git a/parser.py b/parser.py new file mode 100644 index 0000000..f7edaff --- /dev/null +++ b/parser.py @@ -0,0 +1,40 @@ +# This is a sample Python script. + +# Press ⌃R to execute it or replace it with your code. +# Press Double ⇧ to search everywhere for classes, files, tool windows, actions, and settings. + + +def print_hi(name): + # Use a breakpoint in the code line below to debug your script. + print(f'Hi, {name}') # Press ⌘F8 to toggle the breakpoint. + +# See PyCharm help at https://www.jetbrains.com/help/pycharm/ + + +def write_file(name, content): + try: + file = open(name, 'w') + file.write(content) + file.close() + except Exception: + print() + +# Press the green button in the gutter to run the script. +if __name__ == '__main__': + content = "" + name = "a.txt" + with open('source.txt', 'r') as f: + for line in f.readlines(): + if "----" in line and (".py" in line or ".txt" in line or ".out" in line or ".in" in line): + + write_file(name, content) + name = line[6:len(line) - 1] + content = "" + else: + content = content + line + + + + + + diff --git a/pdb_wrapper.py b/pdb_wrapper.py new file mode 100644 index 0000000..0b7e846 --- /dev/null +++ b/pdb_wrapper.py @@ -0,0 +1,242 @@ +# Forked from https://raw.githubusercontent.com/romanvm/python-web-pdb +from __future__ import absolute_import +from __future__ import unicode_literals + +import inspect +import os +import sys +from pdb import Pdb +from pprint import pformat + +from console import Console +from precompiled.__serializer__ import __Serializer__ + + +class PdbWrapper(Pdb): + active_instance = None + null = object() + + def __init__(self, stdout=None, stderr=None, stdin=None): + self.console = Console(self) + self.expressions = [] + Pdb.__init__(self, stdin=self.console, stdout=self.console) + + self._backup = [] + + if stdout is not None: + self._backup.append(("stdout", sys.stdout)) + setattr(sys, "stdout", stdout) + + if stderr is not None: + self._backup.append(("stderr", sys.stderr)) + setattr(sys, "stderr", stderr) + + if stdin is not None: + self._backup.append(("stdin", sys.stdin)) + setattr(sys, "stdin", stdin) + + PdbWrapper.active_instance = self + + def do_quit(self, arg): + """ + quit || exit || q + Stop and quit the current debugging session + """ + for name, fh in self._backup: + setattr(sys, name, fh) + self.console.writeline("*** Aborting program ***\n") + self.console.flush() + self.console.close() + PdbWrapper.active_instance = None + return Pdb.do_quit(self, arg) + + do_q = do_exit = do_quit + + def do_inspect(self, arg): + """ + i(nspect) object + Inspect an object + """ + if arg in self.curframe.f_locals: + obj = self.curframe.f_locals[arg] + elif arg in self.curframe.f_globals: + obj = self.curframe.f_globals[arg] + else: + obj = PdbWrapper.null + if obj is not PdbWrapper.null: + self.console.writeline("{0} = {1}:\n".format(arg, type(obj))) + for name, value in inspect.getmembers(obj): + if not (name.startswith("__") and (name.endswith("__"))): + self.console.writeline( + " {0}: {1}\n".format( + name, self._get_repr(value, pretty=True, indent=8) + ) + ) + else: + self.console.writeline( + 'NameError: name "{0}" is not defined\n'.format(arg) + ) + self.console.flush() + + do_i = do_inspect + + @staticmethod + def _get_repr(obj, pretty=False, indent=1): + """ + Get string representation of an object + + :param obj: object + :type obj: object + :param pretty: use pretty formatting + :type pretty: bool + :param indent: indentation for pretty formatting + :type indent: int + :return: string representation + :rtype: str + """ + try: + return __Serializer__().serialize(obj) + except Exception: + pass + + try: + if pretty: + repr_value = pformat(obj, indent) + else: + repr_value = repr(obj) + except Exception: + return obj.__class__.__name__ + + if sys.version_info[0] == 2: + # Try to convert Unicode string to human-readable form + try: + repr_value = repr_value.decode("raw_unicode_escape") + except UnicodeError: + repr_value = repr_value.decode("utf-8", "replace") + return repr_value + + def set_continue(self): + # We do not detach the debugger + # for correct multiple set_trace() and post_mortem() calls. + self._set_stopinfo(self.botframe, None, -1) + + def dispatch_return(self, frame, arg): + # The parent's method needs to be called first. + ret = Pdb.dispatch_return(self, frame, arg) + if frame.f_back is None: + self.console.writeline("*** Thread finished ***\n") + if not self.console.closed: + self.console.flush() + self.console.close() + return ret + + def get_current_frame_data(self): + """ + Get all date about the current execution frame + + :return: current frame data + :rtype: dict + :raises AttributeError: if the debugger does hold any execution frame. + :raises IOError: if source code for the current execution frame is not + accessible. + """ + filename = self.curframe.f_code.co_filename + lines, start_line = inspect.findsource(self.curframe) + if sys.version_info[0] == 2: + lines = [line.decode("utf-8") for line in lines] + return { + "dirname": os.path.dirname(os.path.abspath(filename)) + os.path.sep, + "filename": os.path.basename(filename), + "file_listing": "".join(lines), + "current_line": self.curframe.f_lineno, + "breakpoints": self.get_file_breaks("user_code/prog_joined.py"), + "globals": self.get_globals(), + "locals": self.get_locals(), + "expressions": self._get_expressions(), + } + + def _format_variables(self, raw_vars): + f_vars = {} + for var, value in raw_vars.items(): + if not (var.startswith("__") and var.endswith("__")): + repr_value = self._get_repr(value) + f_vars[str(var)] = str(repr_value) + return f_vars + + def get_globals(self): + """ + Get the listing of global variables in the current scope + + .. note:: special variables that start and end with + double underscores ``__`` are not included. + + :return: a listing of ``var = value`` pairs sorted alphabetically + :rtype: unicode + """ + return self._format_variables(self.curframe.f_globals) + + def get_locals(self): + """ + Get the listing of local variables in the current scope + + .. note:: special variables that start and end with + double underscores ``__`` are not included. + For module scope globals and locals listings are the same. + + :return: a listing of ``var = value`` pairs sorted alphabetically + :rtype: unicode + """ + return self._format_variables(self.curframe.f_locals) + + def remove_trace(self, frame=None): + """ + Detach the debugger from the execution stack + + :param frame: the lowest frame to detach the debugger from. + :type frame: types.FrameType + """ + sys.settrace(None) + if frame is None: + frame = self.curframe + while frame and frame is not self.botframe: + del frame.f_trace + frame = frame.f_back + + def debug(self): + self.set_trace(sys._getframe().f_back) + + def get_console(self): + return self.console + + def add_expression(self, expression): + self.expressions.append(expression) + + def remove_expression(self, expression): + try: + self.expressions.remove(expression) + except ValueError: + pass + + def _eval(self, src, *args, **kwargs): + return eval(compile(src, "", "eval"), *args, **kwargs) + + def _get_expressions(self): + expression_dict = {} + for expression in self.expressions: + try: + value = self._eval( + expression, self.curframe.f_globals, self.curframe.f_locals + ) + expression_dict[expression] = self._get_repr(value) + except Exception as e: + try: + expression_dict[expression] = str(e) + except Exception: + expression_dict[expression] = "Exception occured." + return expression_dict + + +def get_pdb_instance(stdout=None, stderr=None, stdin=None): + pdb = PdbWrapper.active_instance + return pdb if pdb else PdbWrapper(stdout=stdout, stderr=stderr, stdin=stdin) + diff --git a/precompiled/__deserializer__.py b/precompiled/__deserializer__.py new file mode 100644 index 0000000..adc7e3e --- /dev/null +++ b/precompiled/__deserializer__.py @@ -0,0 +1,248 @@ +import orjson +import ujson as json + +from .listnode import ListNode +from .nestedinteger import NestedInteger +from .treenode import TreeNode + + +class DeserializeError(Exception): + def __init__(self, value): + self.value = value + + def __str__(self): + return str(self.value) + + +class __Deserializer__: + def _deserialize(self, s, t): + if t[-2:] == "[]": + return [ + self._deserialize( + json.dumps(x, escape_forward_slashes=False), t[:-2] + ) + for x in json.loads(s) + ] + elif t[-1:] == ">": + subt = t[5:-1] + return [ + self._deserialize( + json.dumps(x, escape_forward_slashes=False), subt + ) + for x in json.loads(s) + ] + elif t == "integer": + return int(s) + elif t == "long": + return int(s) + elif t == "double": + return float(s) + elif t == "character": + return json.loads(s) + elif t == "boolean": + return json.loads(s) + elif t == "string": + return json.loads(s) + elif t == "ListNode": + return ListNode.deserialize(s) + elif t == "TreeNode": + return TreeNode.deserialize(s) + elif t == "NestedInteger": + return NestedInteger.deserialize(s) + + # deserialization with validation + # TODO: we should probably give one of those helper (?) tooltips in the run_code panel, which redirects ppl to a FAQ section # noqa: B950 + # which details what are the allowed values of each type. + # TODO: write more granular error messages for each input type (do this later after the specification for allowed values is decided) # noqa: B950 + def _deserialize_with_checks(self, s, t): # , validate=False # noqa: C901 + if t[-2:] == "[]": + try: + j = json.loads(s) + assert type(j) == list + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return [ + self._deserialize_with_checks( + json.dumps(x, escape_forward_slashes=False), t[:-2] + ) + for x in j + ] + elif t[-1:] == ">": + subt = t[5:-1] + try: + j = json.loads(s) + assert type(j) == list + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return [ + self._deserialize_with_checks( + json.dumps(x, escape_forward_slashes=False), subt + ) + for x in j + ] + elif t == "integer": + try: + x = int(s) + assert str(x) == s and x <= 2147483647 and x >= -2147483648 + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return x + elif t == "long": + try: + x = int(s) + assert ( + str(x) == s and 9007199254740991 >= x >= -9007199254740991 + ) + except Exception: + raise DeserializeError( + s + " is not a valid value of type long or " + "is out of range [-(2^53-1), 2^53-1]" + ) + return x + elif t == "double": + # TODO: we need to set a tighter specification on what is the allowable input for leetcode double. # noqa: B950 + # It will probably be a very small subset of the strings which can be cast to float in python. # noqa: B950 + # maybe we will only allow numbers like 4532.345 and -0.432432 + # ^ specification might be similar to this problem https://leetcode.com/problems/valid-number/ # noqa: B950 + try: + return float(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "character": + # TODO: we also need a tighter specification on what the allowable values of char are for leetcode. # noqa: B950 + # I would strongly prefer to be on the tighter side at first. Eg. only the chars which we have ever used in testcases for existing problems # noqa: B950 + # and no other characters for now. + # would could dump all such characters into a "permitted.charset" + try: + j = json.loads(s) + c = str(j) + assert len(c) == 1 + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return c + elif t == "boolean": + try: + assert s == "true" or s == "false" + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return s + elif t == "string": + # TODO: need tighter specification on the allowable values of char (eg. ascii only) # noqa: B950 + try: + j = json.loads(s) + s = str(j) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return s + elif t == "ListNode": + try: + return ListNode.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "TreeNode": + try: + return TreeNode.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "NestedInteger": + try: + return NestedInteger.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + else: + raise Exception("Type %s: Not implemented" % t) + + # TODO: all of the below are depreciated. + # Remove after new serializer/deserializer is deployed + + def to_integer(self, line): + return int(line) + + def to_double(self, line): + return float(line) + + def to_char(self, line): + return json.loads(line) + + def to_string(self, line): + return json.loads(line) + + def to_int_array(self, line): + return json.loads(line) + + def to_double_array(self, line): + return json.loads(line) + + def to_double_2d_array(self, line): + return json.loads(line) + + def to_int_2d_array(self, line): + return json.loads(line) + + def to_char_array(self, line): + return json.loads(line) + + def to_char_2d_array(self, line): + return json.loads(line) + + def to_string_array(self, line): + return json.loads(line) + + def to_string_set(self, line): + return set(json.loads(line)) + + def to_string_2d_array(self, line): + return json.loads(line) + + def to_list_node(self, line): + return ListNode.deserialize(line) + + def to_list_node_array(self, line): + arr2d = json.loads(line) + lists = [] + for arr in arr2d: + lists.append(ListNode._array_to_list_node(arr)) + return lists + + def to_tree_node(self, line): + return TreeNode.deserialize(line) + + def to_nested_integer(self, line): + return NestedInteger.deserialize(line) + + def to_nested_integer_array(self, line): + ni = NestedInteger.deserialize(line) + return ni.getList() + + +def deserialize_default(obj, type_str): + if type_str == "ListNode": + return ListNode._array_to_list_node(obj) + elif type_str == "TreeNode": + return TreeNode._array_to_tree_node(obj) + elif type_str == "NestedInteger": + return NestedInteger._token_to_nested_integer(obj) + else: + return obj + + +class __DeserializerRapid__: + def _deserialize_node(self, obj, type_str): + if type_str[-2:] == "[]": + return [self._deserialize_node(x, type_str[:-2]) for x in obj] + elif type_str[-1:] == ">": + return [self._deserialize_node(x, type_str[5:-1]) for x in obj] + else: + return deserialize_default(obj, type_str) + + def _deserialize(self, obj_str, type_str): + obj = orjson.loads(obj_str) + if ( + "ListNode" in type_str + or "TreeNode" in type_str + or "NestedInteger" in type_str + ): + return self._deserialize_node(obj, type_str) + else: + return obj + diff --git a/precompiled/__init__.py b/precompiled/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/precompiled/__init__.py @@ -0,0 +1 @@ + diff --git a/precompiled/__serializer__.py b/precompiled/__serializer__.py new file mode 100644 index 0000000..c5b3017 --- /dev/null +++ b/precompiled/__serializer__.py @@ -0,0 +1,193 @@ +import array +from collections.abc import Iterable + +import orjson +import ujson as json + +from .listnode import ListNode +from .nestedinteger import NestedInteger +from .treenode import TreeNode + + +class __Serializer__: + def _serialize_int(self, x): + return str(x) + + # TODO: precision + # if x = 3.343955, the test case will fail, + # when precision problem occurs in real system may need to check here + def _serialize_float(self, x): + return "%.5f" % x + + def _serialize_str(self, x): + return json.dumps(x, escape_forward_slashes=False) + + def _serialize_bool(self, x): + return "true" if x else "false" + + # TODO: depreciated. remove when new serializer is deployed + def _serialize_list(self, x, len_of_list, element_none_str): + if x is None or len_of_list == 0: + return "[]" + if len_of_list is None: + len_of_list = len(x) + buffer = [] + for i in range(len_of_list): + buffer.append( + "".join(self.serialize(x[i], none_str=element_none_str)) + ) + return "[%s]" % ",".join(buffer) + + def serialize_list(self, x, t): + if x is None: + return "[]" + return "[" + ",".join([self._serialize(e, t) for e in x]) + "]" + + # TODO: depreciated. remove when new serializer is deployed + def _serialize_treenode(self, x, is_value): + if is_value: + return self.serialize(x.val) if x else "null" + else: + return TreeNode.serialize(x) + + def _serialize(self, x, t): + if t[-2:] == "[]": + return self.serialize_list(x, t[:-2]) + elif t[-1:] == ">": + return self.serialize_list(x, t[5:-1]) + elif t == "integer": + return self._serialize_int(x) + elif t == "long": + return self._serialize_int(x) + elif t == "double": + return self._serialize_float(x) + elif t == "character": + return self._serialize_str(x) + elif t == "boolean": + return self._serialize_bool(x) + elif t == "string": + return self._serialize_str(x) + elif t == "ListNode": + return ListNode.serialize(x) + elif t == "TreeNode": + return TreeNode.serialize(x) + elif t == "NestedInteger": + return NestedInteger._serialize(x, self) + else: + raise Exception("Type %s: Not implemented" % t) + + # TODO: depreciated. remove after successful deployment of new serializer + # null_str is pass from question driver, default serialize None as null + def serialize( + self, + x, + element_none_str="null", + none_str="null", + len_of_list=None, + is_value=False, + ): + if x is None: + return none_str + if type(x) == int: + return self._serialize_int(x) + elif type(x) == float: + return self._serialize_float(x) + elif type(x) == str: + return self._serialize_str(x) + elif type(x) == bool: + return self._serialize_bool(x) + elif isinstance(x, array.array): + return self._serialize_list( + x.tolist(), len_of_list, element_none_str + ) + elif isinstance(x, list): + return self._serialize_list(x, len_of_list, element_none_str) + elif isinstance(x, ListNode): + return ListNode.serialize(x) + elif isinstance(x, TreeNode): + return self._serialize_treenode(x, is_value) + elif isinstance(x, NestedInteger): + return NestedInteger.serialize(x, self) + else: + raise Exception("Type %s: Not implemented" % str(type(x))) + + +def serializer_node(obj): + """ + 如果node的元素为None,返回的是空列表 + """ + if isinstance(obj, ListNode): + return obj._list_node_to_array() + elif isinstance(obj, TreeNode): + return obj._tree_node_to_array() + elif isinstance(obj, NestedInteger): + return obj._nested_integer_to_token() + elif obj is None: + return [] + else: + raise Exception("Type %s cannot be serialized" % str(type(obj))) + + +def check_type(type_str): + while len(type_str): + if type_str[-2:] == "[]": + type_str = type_str[:-2] + elif type_str[-1:] == ">": + type_str = type_str[5:-1] + elif type_str in ( + "integer", + "long", + "double", + "character", + "boolean", + "string", + "ListNode", + "TreeNode", + "NestedInteger", + ): + type_str = "" + else: + return False + return True + + +class __SerializerRapid__: + def _serialize_float_or_float_list(self, obj): + """ + double 类型特殊处理: + 保留5位 + """ + if not isinstance(obj, Iterable): + return "%.5f" % obj + float_list = [self._serialize_float_or_float_list(i) for i in obj] + return "[%s]" % ",".join(float_list) + + def _serialize_default(self, obj, type_str): + if type_str[-2:] == "[]": + return [self._serialize_default(x, type_str[:-2]) for x in obj] + elif type_str[-1:] == ">": + return [self._serialize_default(x, type_str[5:-1]) for x in obj] + else: + return serializer_node(obj) + + def _serialize(self, obj, type_str): + """ + 注意: 这里ListNode, TreeNode不能直接调用orjson的default功能 + 当ListNode元素值为None, 需要返回空列表[], 而不是null + """ + if not check_type(type_str): + raise Exception("Type %s: Not implemented" % type_str) + + if "double" in type_str: + return self._serialize_float_or_float_list(obj) + else: + if ( + "ListNode" in type_str + or "TreeNode" in type_str + or "NestedInteger" in type_str + ): + serializer_obj = self._serialize_default(obj, type_str) + else: + serializer_obj = obj + return bytes.decode(orjson.dumps(serializer_obj)) + diff --git a/precompiled/__settings__.py b/precompiled/__settings__.py new file mode 100644 index 0000000..cf3af8d --- /dev/null +++ b/precompiled/__settings__.py @@ -0,0 +1,12 @@ +import argparse +import sys + +parser = argparse.ArgumentParser(description="Run python solution.") +parser.add_argument( + "-recursion_limit", nargs=1, type=int, help="recursion limit" +) +args = parser.parse_args() + +if hasattr(args, "recursion_limit"): + sys.setrecursionlimit(args.recursion_limit[0]) + diff --git a/precompiled/__utils__.py b/precompiled/__utils__.py new file mode 100644 index 0000000..1aa7d6d --- /dev/null +++ b/precompiled/__utils__.py @@ -0,0 +1,13 @@ +import sys + + +class __Utils__: + def read_tokens(self): + for line in sys.stdin: + for token in line.split(): + yield token + + def read_lines(self): + for line in sys.stdin: + yield line.strip('\n') + diff --git a/precompiled/listnode.py b/precompiled/listnode.py new file mode 100644 index 0000000..0474994 --- /dev/null +++ b/precompiled/listnode.py @@ -0,0 +1,70 @@ +import json + + +class ListNode(object): + # ListNode val is an integer + + def __init__(self, val=0, next=None): + self.val = val + self.next = next + + def __str__(self): + return self.__repr__() + + def __repr__(self): + if self.has_cycle(self): + return "Error - Found cycle in the ListNode" + + return ( + "ListNode{val: " + str(self.val) + ", next: " + str(self.next) + "}" + ) + + def _list_node_to_array(self): + buffer = [self.val] + now = self.next + while now is not None: + buffer.append(now.val) + now = now.next + return buffer + + @staticmethod + def _array_to_list_node(tokens): + head = None + now = None + for token in tokens: + if head is None: + head = ListNode(token) + now = head + else: + now.next = ListNode(token) + now = now.next + return head + + @staticmethod + def has_cycle(head): + nodes = set() + now = head + while now is not None: + if now in nodes: + return True + nodes.add(now) + now = now.next + return False + + @staticmethod + def deserialize(s): + tokens = json.loads(s) + return ListNode._array_to_list_node(tokens) + + @classmethod + def serialize(cls, head): + if cls.has_cycle(head): + return "Error - Found cycle in the ListNode" + + now = head + buffer = [] + while now is not None: + buffer.append(str(now.val)) + now = now.next + return "[%s]" % ",".join(buffer) + diff --git a/precompiled/nestedinteger.py b/precompiled/nestedinteger.py new file mode 100644 index 0000000..0236a0c --- /dev/null +++ b/precompiled/nestedinteger.py @@ -0,0 +1,76 @@ +import json + + +class NestedInteger(object): + def __init__(self, value=None): + self.setInteger(value) + self._list = [] + + def __str__(self): + return self.__repr__() + + def __repr__(self): + return ( + "NestedInteger{_integer: " + + str(self._integer) + + ", _list: " + + str(self._list) + + "}" + ) + + def isInteger(self): + return self._integer is not None + + def getInteger(self): + return self._integer + + def setInteger(self, i): + self._integer = i + + def getList(self): + return self._list + + def add(self, ni): + self._list.append(ni) + self._integer = None + + def _nested_integer_to_token(self): + if self.isInteger(): + return self._integer + else: + return [ + nested_integer._nested_integer_to_token() + for nested_integer in self._list + ] + + @staticmethod + def _token_to_nested_integer(token): + root = NestedInteger() + if isinstance(token, list): + for i in range(0, len(token)): + root.add(NestedInteger._token_to_nested_integer(token[i])) + elif isinstance(token, int): + root.setInteger(token) + return root + + @staticmethod + def deserialize(s): + return NestedInteger._token_to_nested_integer(json.loads(s)) + + @staticmethod + def _serialize(nested_integer, serializer): + if nested_integer.isInteger(): + return serializer._serialize(nested_integer.getInteger(), "integer") + else: + return serializer._serialize( + nested_integer.getList(), "NestedInteger[]" + ) + + # TODO: depreciated. remove once new serializer has been deployed. + @staticmethod + def serialize(nested_integer, serializer): + if nested_integer.isInteger(): + return serializer.serialize(nested_integer.getInteger()) + else: + return serializer.serialize(nested_integer.getList()) + diff --git a/precompiled/treenode.py b/precompiled/treenode.py new file mode 100644 index 0000000..827551e --- /dev/null +++ b/precompiled/treenode.py @@ -0,0 +1,112 @@ +import json + + +class TreeNode(object): + # TreeNode val is an integer + + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + + def __str__(self): + return self.__repr__() + + def __repr__(self): + if self.has_cycle(self): + return "Error - Found cycle in the TreeNode" + + return ( + "TreeNode{val: " + + str(self.val) + + ", left: " + + str(self.left) + + ", right: " + + str(self.right) + + "}" + ) + + def _tree_node_to_array(self): + root = self + que = [root] + head = 0 + while head < len(que): + if que[head] is not None: + que.append(que[head].left) + que.append(que[head].right) + head += 1 + while len(que) and que[-1] is None: + que.pop(-1) + return [None if node is None else node.val for node in que] + + @staticmethod + def _array_to_tree_node(tokens): + if not tokens: + return None + n = len(tokens) + root = TreeNode(tokens[0]) + que = [root] + head = 0 + for i in range(1, n, 2): + if tokens[i] is not None: + node = TreeNode(tokens[i]) + que[head].left = node + que.append(node) + if i + 1 < n and tokens[i + 1] is not None: + node = TreeNode(tokens[i + 1]) + que[head].right = node + que.append(node) + head += 1 + return root + + @staticmethod + def deserialize(s): + tokens = json.loads(s) + return TreeNode._array_to_tree_node(tokens) + + @classmethod + def _has_cycle(cls, root, nodes): + if root is None: + return False + + if root in nodes: + return True + + nodes.add(root) + cycle_exists = cls._has_cycle(root.left, nodes) or cls._has_cycle( + root.right, nodes + ) + nodes.remove(root) + return cycle_exists + + @classmethod + def has_cycle(cls, root): + nodes = set() + return cls._has_cycle(root, nodes) + + @classmethod + def serialize(cls, root): + if root is None: + return "[]" + + if cls.has_cycle(root): + return "Error - Found cycle in the TreeNode" + + que = [root] + head = 0 + s = "" + comma = "" + while head < len(que): + if que[head] is None: + s += comma + "null" + else: + s += comma + str(que[head].val) + que.append(que[head].left) + que.append(que[head].right) + comma = "," + head += 1 + # Delete trailing ",null" suffix. + while s[-1] == "l": + s = s[:-5] + return "[%s]" % s + diff --git a/server.py b/server.py new file mode 100644 index 0000000..658c8e0 --- /dev/null +++ b/server.py @@ -0,0 +1,100 @@ +import time +import traceback +from threading import Thread + +import io_wrapper +import log +import pdb_wrapper +from flask import Flask +from flask import jsonify +from flask import request + +app = Flask(__name__) + + +console = None +pdb = None + + +def frame_data(): + global console + + frame_data = console.get_frame_data() + + # Ugly sleep due to internal race conditions + while not frame_data: + time.sleep(0.05) + frame_data = console.get_frame_data() + + frame_data.pop("dirname", None) + frame_data.pop("file_listing", None) + frame_data.pop("globals", None) + + exception = frame_data.pop("exception", None) + if exception: + log.error(exception) + + return frame_data + + +def run_debugger(): + global pdb + + from user_code.prog_joined import _driver + + pdb.debug() + _driver() + + +@app.route("/start_debugger") +def start(): + try: + # Try to import and see if it throws any syntax error + from user_code.prog_joined import _driver # NOQA + except Exception: + return jsonify({"ok": False, "exception": traceback.format_exc()}) + + global console + global pdb + + io_wrapper.override_input() + std_out_wrapper = io_wrapper.get_stdout_wrapper() + pdb = pdb_wrapper.get_pdb_instance( + stdout=std_out_wrapper, stderr=std_out_wrapper + ) + console = pdb.get_console() + + thread = Thread(target=run_debugger) + thread.daemon = True + thread.start() + return jsonify({"ok": True}) + + +@app.route("/run_command") +def run_command(): + command = request.args.get("command") + console.send_pdb_command(command) + return jsonify(frame_data()) + + +@app.route("/add_expression") +def add_expression(): + expression = request.args.get("expression") + pdb.add_expression(expression) + return jsonify(frame_data()) + + +@app.route("/remove_expression") +def remove_expression(): + expression = request.args.get("expression") + pdb.remove_expression(expression) + return jsonify(frame_data()) + + +def main(): + app.run(host="0.0.0.0", port=80) + + +if __name__ == "__main__": + main() + diff --git a/source.txt b/source.txt new file mode 100644 index 0000000..28510b8 --- /dev/null +++ b/source.txt @@ -0,0 +1,3645 @@ +---- /leetcode/commands.txt +stepcontinue +---- /leetcode/console.py +# Forked from https://raw.githubusercontent.com/romanvm/python-web-pdb +from __future__ import absolute_import +from __future__ import unicode_literals + +import sys +import weakref +from threading import Event +from threading import RLock + +try: + import queue +except ImportError: + import Queue as queue + + +class ThreadSafeObject(object): + """ + An object for data exchange between threads + """ + + def __init__(self, contents=None): + self._lock = RLock() + self._contents = contents + + @property + def contents(self): + with self._lock: + return self._contents + + @contents.setter + def contents(self, value): + with self._lock: + self._contents = value + + +class Console(object): + input_queue = queue.Queue() + + def __init__(self, debugger): + self.pdb_not_busy = Event() + self.closed = False + self._debugger = weakref.proxy(debugger) + self._console_history = ThreadSafeObject("") + self._frame_data = ThreadSafeObject({}) + self._output_lock = RLock() + self.exception = None + + @property + def seekable(self): + return False + + @property + def writable(self): + return True + + @property + def encoding(self): + return "utf-8" + + def close(self): + self.closed = True + self.pdb_not_busy.set() + + def readline(self): + self.pdb_not_busy.set() + command = self.input_queue.get() + self.pdb_not_busy.clear() + + if not command: + command = "\n" + + with open("commands.txt", "a+") as file: + file.write(command) + self.writeline(command) + return command + + read = readline + + def writeline(self, data): + with self._output_lock: + if isinstance(data, bytes): + data = data.decode("utf-8") + + self._console_history.contents += data + try: + frame_data = self._debugger.get_current_frame_data() + except (IOError, AttributeError): + frame_data = { + "dirname": "", + "filename": "", + "file_listing": "No data available", + "current_line": -1, + "breakpoints": [], + "globals": {}, + "locals": {}, + "expressions": {}, + "exception": sys.exc_info(), + } + + frame_data["console_history"] = self._console_history.contents + self._frame_data.contents = frame_data + + write = writeline + + def flush(self): + pass + + def send_pdb_command(self, command): + self.pdb_not_busy.wait() + self.input_queue.put(command) + + def get_frame_data(self): + with self._output_lock: + return self._frame_data.contents + +---- /leetcode/io_wrapper.py +import sys + +is_python3 = sys.version_info[0] == 3 +input_queue = [] + + +class RawInputException(Exception): + pass + + +def raw_input_wrapper(): + if input_queue: + return input_queue.pop(0) + raise RawInputException() + + +def python2_input_wrapper(): + # Python 2 input() does eval(raw_input()) + if input_queue: + input_str = input_queue.pop(0) + return eval(input_str) + raise RawInputException() + + +def stream_stdin(): + while input_queue: + item = input_queue.pop(0) + yield item + + +def override_input(): + if is_python3: + import builtins + else: + import __builtin__ as builtins + + with open("user_code/input.txt") as file: + global input_queue + input_queue = list(file.readlines()) + + builtins.raw_input = raw_input_wrapper + + if is_python3: + builtins.input = raw_input_wrapper + else: + builtins.input = python2_input_wrapper + + sys.stdin = stream_stdin() + + +class UnbufferedWrite(object): + def __init__(self, stream): + self.stream = stream + + def write(self, data): + self.stream.write(data) + self.stream.flush() + + def writelines(self, datas): + self.stream.writelines(datas) + self.stream.flush() + + def __getattr__(self, attr): + return getattr(self.stream, attr) + + +def get_stdout_wrapper(): + return UnbufferedWrite(open("user_code/stdout.txt", "w")) + +---- /leetcode/log.py +import logging +import sys + + +def get_logger(): + logging.basicConfig(stream=sys.__stdout__, level=logging.DEBUG) + log = logging.getLogger("werkzeug") + return log + + +def debug(*args): + msg = "\n".join(map(str, args)) + logger = get_logger() + logger.debug(msg, extra={"stack": True}) + + +def info(*args): + msg = "\n".join(map(str, args)) + logger = get_logger() + logger.info(msg, extra={"stack": True}) + + +def error(*args): + msg = "\n".join(map(str, args)) + logger = get_logger() + logger.error(msg, extra={"stack": True}) + +---- /leetcode/pdb_wrapper.py +# Forked from https://raw.githubusercontent.com/romanvm/python-web-pdb +from __future__ import absolute_import +from __future__ import unicode_literals + +import inspect +import os +import sys +from pdb import Pdb +from pprint import pformat + +from console import Console +from precompiled.__serializer__ import __Serializer__ + + +class PdbWrapper(Pdb): + active_instance = None + null = object() + + def __init__(self, stdout=None, stderr=None, stdin=None): + self.console = Console(self) + self.expressions = [] + Pdb.__init__(self, stdin=self.console, stdout=self.console) + + self._backup = [] + + if stdout is not None: + self._backup.append(("stdout", sys.stdout)) + setattr(sys, "stdout", stdout) + + if stderr is not None: + self._backup.append(("stderr", sys.stderr)) + setattr(sys, "stderr", stderr) + + if stdin is not None: + self._backup.append(("stdin", sys.stdin)) + setattr(sys, "stdin", stdin) + + PdbWrapper.active_instance = self + + def do_quit(self, arg): + """ + quit || exit || q + Stop and quit the current debugging session + """ + for name, fh in self._backup: + setattr(sys, name, fh) + self.console.writeline("*** Aborting program ***\n") + self.console.flush() + self.console.close() + PdbWrapper.active_instance = None + return Pdb.do_quit(self, arg) + + do_q = do_exit = do_quit + + def do_inspect(self, arg): + """ + i(nspect) object + Inspect an object + """ + if arg in self.curframe.f_locals: + obj = self.curframe.f_locals[arg] + elif arg in self.curframe.f_globals: + obj = self.curframe.f_globals[arg] + else: + obj = PdbWrapper.null + if obj is not PdbWrapper.null: + self.console.writeline("{0} = {1}:\n".format(arg, type(obj))) + for name, value in inspect.getmembers(obj): + if not (name.startswith("__") and (name.endswith("__"))): + self.console.writeline( + " {0}: {1}\n".format( + name, self._get_repr(value, pretty=True, indent=8) + ) + ) + else: + self.console.writeline( + 'NameError: name "{0}" is not defined\n'.format(arg) + ) + self.console.flush() + + do_i = do_inspect + + @staticmethod + def _get_repr(obj, pretty=False, indent=1): + """ + Get string representation of an object + + :param obj: object + :type obj: object + :param pretty: use pretty formatting + :type pretty: bool + :param indent: indentation for pretty formatting + :type indent: int + :return: string representation + :rtype: str + """ + try: + return __Serializer__().serialize(obj) + except Exception: + pass + + try: + if pretty: + repr_value = pformat(obj, indent) + else: + repr_value = repr(obj) + except Exception: + return obj.__class__.__name__ + + if sys.version_info[0] == 2: + # Try to convert Unicode string to human-readable form + try: + repr_value = repr_value.decode("raw_unicode_escape") + except UnicodeError: + repr_value = repr_value.decode("utf-8", "replace") + return repr_value + + def set_continue(self): + # We do not detach the debugger + # for correct multiple set_trace() and post_mortem() calls. + self._set_stopinfo(self.botframe, None, -1) + + def dispatch_return(self, frame, arg): + # The parent's method needs to be called first. + ret = Pdb.dispatch_return(self, frame, arg) + if frame.f_back is None: + self.console.writeline("*** Thread finished ***\n") + if not self.console.closed: + self.console.flush() + self.console.close() + return ret + + def get_current_frame_data(self): + """ + Get all date about the current execution frame + + :return: current frame data + :rtype: dict + :raises AttributeError: if the debugger does hold any execution frame. + :raises IOError: if source code for the current execution frame is not + accessible. + """ + filename = self.curframe.f_code.co_filename + lines, start_line = inspect.findsource(self.curframe) + if sys.version_info[0] == 2: + lines = [line.decode("utf-8") for line in lines] + return { + "dirname": os.path.dirname(os.path.abspath(filename)) + os.path.sep, + "filename": os.path.basename(filename), + "file_listing": "".join(lines), + "current_line": self.curframe.f_lineno, + "breakpoints": self.get_file_breaks("user_code/prog_joined.py"), + "globals": self.get_globals(), + "locals": self.get_locals(), + "expressions": self._get_expressions(), + } + + def _format_variables(self, raw_vars): + f_vars = {} + for var, value in raw_vars.items(): + if not (var.startswith("__") and var.endswith("__")): + repr_value = self._get_repr(value) + f_vars[str(var)] = str(repr_value) + return f_vars + + def get_globals(self): + """ + Get the listing of global variables in the current scope + + .. note:: special variables that start and end with + double underscores ``__`` are not included. + + :return: a listing of ``var = value`` pairs sorted alphabetically + :rtype: unicode + """ + return self._format_variables(self.curframe.f_globals) + + def get_locals(self): + """ + Get the listing of local variables in the current scope + + .. note:: special variables that start and end with + double underscores ``__`` are not included. + For module scope globals and locals listings are the same. + + :return: a listing of ``var = value`` pairs sorted alphabetically + :rtype: unicode + """ + return self._format_variables(self.curframe.f_locals) + + def remove_trace(self, frame=None): + """ + Detach the debugger from the execution stack + + :param frame: the lowest frame to detach the debugger from. + :type frame: types.FrameType + """ + sys.settrace(None) + if frame is None: + frame = self.curframe + while frame and frame is not self.botframe: + del frame.f_trace + frame = frame.f_back + + def debug(self): + self.set_trace(sys._getframe().f_back) + + def get_console(self): + return self.console + + def add_expression(self, expression): + self.expressions.append(expression) + + def remove_expression(self, expression): + try: + self.expressions.remove(expression) + except ValueError: + pass + + def _eval(self, src, *args, **kwargs): + return eval(compile(src, "", "eval"), *args, **kwargs) + + def _get_expressions(self): + expression_dict = {} + for expression in self.expressions: + try: + value = self._eval( + expression, self.curframe.f_globals, self.curframe.f_locals + ) + expression_dict[expression] = self._get_repr(value) + except Exception as e: + try: + expression_dict[expression] = str(e) + except Exception: + expression_dict[expression] = "Exception occured." + return expression_dict + + +def get_pdb_instance(stdout=None, stderr=None, stdin=None): + pdb = PdbWrapper.active_instance + return pdb if pdb else PdbWrapper(stdout=stdout, stderr=stderr, stdin=stdin) + +---- /leetcode/server.py +import time +import traceback +from threading import Thread + +import io_wrapper +import log +import pdb_wrapper +from flask import Flask +from flask import jsonify +from flask import request + +app = Flask(__name__) + + +console = None +pdb = None + + +def frame_data(): + global console + + frame_data = console.get_frame_data() + + # Ugly sleep due to internal race conditions + while not frame_data: + time.sleep(0.05) + frame_data = console.get_frame_data() + + frame_data.pop("dirname", None) + frame_data.pop("file_listing", None) + frame_data.pop("globals", None) + + exception = frame_data.pop("exception", None) + if exception: + log.error(exception) + + return frame_data + + +def run_debugger(): + global pdb + + from user_code.prog_joined import _driver + + pdb.debug() + _driver() + + +@app.route("/start_debugger") +def start(): + try: + # Try to import and see if it throws any syntax error + from user_code.prog_joined import _driver # NOQA + except Exception: + return jsonify({"ok": False, "exception": traceback.format_exc()}) + + global console + global pdb + + io_wrapper.override_input() + std_out_wrapper = io_wrapper.get_stdout_wrapper() + pdb = pdb_wrapper.get_pdb_instance( + stdout=std_out_wrapper, stderr=std_out_wrapper + ) + console = pdb.get_console() + + thread = Thread(target=run_debugger) + thread.daemon = True + thread.start() + return jsonify({"ok": True}) + + +@app.route("/run_command") +def run_command(): + command = request.args.get("command") + console.send_pdb_command(command) + return jsonify(frame_data()) + + +@app.route("/add_expression") +def add_expression(): + expression = request.args.get("expression") + pdb.add_expression(expression) + return jsonify(frame_data()) + + +@app.route("/remove_expression") +def remove_expression(): + expression = request.args.get("expression") + pdb.remove_expression(expression) + return jsonify(frame_data()) + + +def main(): + app.run(host="0.0.0.0", port=80) + + +if __name__ == "__main__": + main() + +---- /leetcode/user.out + +---- /leetcode/precompiled/__deserializer__.py +import orjson +import ujson as json + +from .listnode import ListNode +from .nestedinteger import NestedInteger +from .treenode import TreeNode + + +class DeserializeError(Exception): + def __init__(self, value): + self.value = value + + def __str__(self): + return str(self.value) + + +class __Deserializer__: + def _deserialize(self, s, t): + if t[-2:] == "[]": + return [ + self._deserialize( + json.dumps(x, escape_forward_slashes=False), t[:-2] + ) + for x in json.loads(s) + ] + elif t[-1:] == ">": + subt = t[5:-1] + return [ + self._deserialize( + json.dumps(x, escape_forward_slashes=False), subt + ) + for x in json.loads(s) + ] + elif t == "integer": + return int(s) + elif t == "long": + return int(s) + elif t == "double": + return float(s) + elif t == "character": + return json.loads(s) + elif t == "boolean": + return json.loads(s) + elif t == "string": + return json.loads(s) + elif t == "ListNode": + return ListNode.deserialize(s) + elif t == "TreeNode": + return TreeNode.deserialize(s) + elif t == "NestedInteger": + return NestedInteger.deserialize(s) + + # deserialization with validation + # TODO: we should probably give one of those helper (?) tooltips in the run_code panel, which redirects ppl to a FAQ section # noqa: B950 + # which details what are the allowed values of each type. + # TODO: write more granular error messages for each input type (do this later after the specification for allowed values is decided) # noqa: B950 + def _deserialize_with_checks(self, s, t): # , validate=False # noqa: C901 + if t[-2:] == "[]": + try: + j = json.loads(s) + assert type(j) == list + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return [ + self._deserialize_with_checks( + json.dumps(x, escape_forward_slashes=False), t[:-2] + ) + for x in j + ] + elif t[-1:] == ">": + subt = t[5:-1] + try: + j = json.loads(s) + assert type(j) == list + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return [ + self._deserialize_with_checks( + json.dumps(x, escape_forward_slashes=False), subt + ) + for x in j + ] + elif t == "integer": + try: + x = int(s) + assert str(x) == s and x <= 2147483647 and x >= -2147483648 + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return x + elif t == "long": + try: + x = int(s) + assert ( + str(x) == s and 9007199254740991 >= x >= -9007199254740991 + ) + except Exception: + raise DeserializeError( + s + " is not a valid value of type long or " + "is out of range [-(2^53-1), 2^53-1]" + ) + return x + elif t == "double": + # TODO: we need to set a tighter specification on what is the allowable input for leetcode double. # noqa: B950 + # It will probably be a very small subset of the strings which can be cast to float in python. # noqa: B950 + # maybe we will only allow numbers like 4532.345 and -0.432432 + # ^ specification might be similar to this problem https://leetcode.com/problems/valid-number/ # noqa: B950 + try: + return float(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "character": + # TODO: we also need a tighter specification on what the allowable values of char are for leetcode. # noqa: B950 + # I would strongly prefer to be on the tighter side at first. Eg. only the chars which we have ever used in testcases for existing problems # noqa: B950 + # and no other characters for now. + # would could dump all such characters into a "permitted.charset" + try: + j = json.loads(s) + c = str(j) + assert len(c) == 1 + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return c + elif t == "boolean": + try: + assert s == "true" or s == "false" + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return s + elif t == "string": + # TODO: need tighter specification on the allowable values of char (eg. ascii only) # noqa: B950 + try: + j = json.loads(s) + s = str(j) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return s + elif t == "ListNode": + try: + return ListNode.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "TreeNode": + try: + return TreeNode.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "NestedInteger": + try: + return NestedInteger.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + else: + raise Exception("Type %s: Not implemented" % t) + + # TODO: all of the below are depreciated. + # Remove after new serializer/deserializer is deployed + + def to_integer(self, line): + return int(line) + + def to_double(self, line): + return float(line) + + def to_char(self, line): + return json.loads(line) + + def to_string(self, line): + return json.loads(line) + + def to_int_array(self, line): + return json.loads(line) + + def to_double_array(self, line): + return json.loads(line) + + def to_double_2d_array(self, line): + return json.loads(line) + + def to_int_2d_array(self, line): + return json.loads(line) + + def to_char_array(self, line): + return json.loads(line) + + def to_char_2d_array(self, line): + return json.loads(line) + + def to_string_array(self, line): + return json.loads(line) + + def to_string_set(self, line): + return set(json.loads(line)) + + def to_string_2d_array(self, line): + return json.loads(line) + + def to_list_node(self, line): + return ListNode.deserialize(line) + + def to_list_node_array(self, line): + arr2d = json.loads(line) + lists = [] + for arr in arr2d: + lists.append(ListNode._array_to_list_node(arr)) + return lists + + def to_tree_node(self, line): + return TreeNode.deserialize(line) + + def to_nested_integer(self, line): + return NestedInteger.deserialize(line) + + def to_nested_integer_array(self, line): + ni = NestedInteger.deserialize(line) + return ni.getList() + + +def deserialize_default(obj, type_str): + if type_str == "ListNode": + return ListNode._array_to_list_node(obj) + elif type_str == "TreeNode": + return TreeNode._array_to_tree_node(obj) + elif type_str == "NestedInteger": + return NestedInteger._token_to_nested_integer(obj) + else: + return obj + + +class __DeserializerRapid__: + def _deserialize_node(self, obj, type_str): + if type_str[-2:] == "[]": + return [self._deserialize_node(x, type_str[:-2]) for x in obj] + elif type_str[-1:] == ">": + return [self._deserialize_node(x, type_str[5:-1]) for x in obj] + else: + return deserialize_default(obj, type_str) + + def _deserialize(self, obj_str, type_str): + obj = orjson.loads(obj_str) + if ( + "ListNode" in type_str + or "TreeNode" in type_str + or "NestedInteger" in type_str + ): + return self._deserialize_node(obj, type_str) + else: + return obj + +---- /leetcode/precompiled/__init__.py + +---- /leetcode/precompiled/listnode.py +import json + + +class ListNode(object): + # ListNode val is an integer + + def __init__(self, val=0, next=None): + self.val = val + self.next = next + + def __str__(self): + return self.__repr__() + + def __repr__(self): + if self.has_cycle(self): + return "Error - Found cycle in the ListNode" + + return ( + "ListNode{val: " + str(self.val) + ", next: " + str(self.next) + "}" + ) + + def _list_node_to_array(self): + buffer = [self.val] + now = self.next + while now is not None: + buffer.append(now.val) + now = now.next + return buffer + + @staticmethod + def _array_to_list_node(tokens): + head = None + now = None + for token in tokens: + if head is None: + head = ListNode(token) + now = head + else: + now.next = ListNode(token) + now = now.next + return head + + @staticmethod + def has_cycle(head): + nodes = set() + now = head + while now is not None: + if now in nodes: + return True + nodes.add(now) + now = now.next + return False + + @staticmethod + def deserialize(s): + tokens = json.loads(s) + return ListNode._array_to_list_node(tokens) + + @classmethod + def serialize(cls, head): + if cls.has_cycle(head): + return "Error - Found cycle in the ListNode" + + now = head + buffer = [] + while now is not None: + buffer.append(str(now.val)) + now = now.next + return "[%s]" % ",".join(buffer) + +---- /leetcode/precompiled/nestedinteger.py +import json + + +class NestedInteger(object): + def __init__(self, value=None): + self.setInteger(value) + self._list = [] + + def __str__(self): + return self.__repr__() + + def __repr__(self): + return ( + "NestedInteger{_integer: " + + str(self._integer) + + ", _list: " + + str(self._list) + + "}" + ) + + def isInteger(self): + return self._integer is not None + + def getInteger(self): + return self._integer + + def setInteger(self, i): + self._integer = i + + def getList(self): + return self._list + + def add(self, ni): + self._list.append(ni) + self._integer = None + + def _nested_integer_to_token(self): + if self.isInteger(): + return self._integer + else: + return [ + nested_integer._nested_integer_to_token() + for nested_integer in self._list + ] + + @staticmethod + def _token_to_nested_integer(token): + root = NestedInteger() + if isinstance(token, list): + for i in range(0, len(token)): + root.add(NestedInteger._token_to_nested_integer(token[i])) + elif isinstance(token, int): + root.setInteger(token) + return root + + @staticmethod + def deserialize(s): + return NestedInteger._token_to_nested_integer(json.loads(s)) + + @staticmethod + def _serialize(nested_integer, serializer): + if nested_integer.isInteger(): + return serializer._serialize(nested_integer.getInteger(), "integer") + else: + return serializer._serialize( + nested_integer.getList(), "NestedInteger[]" + ) + + # TODO: depreciated. remove once new serializer has been deployed. + @staticmethod + def serialize(nested_integer, serializer): + if nested_integer.isInteger(): + return serializer.serialize(nested_integer.getInteger()) + else: + return serializer.serialize(nested_integer.getList()) + +---- /leetcode/precompiled/__serializer__.py +import array +from collections.abc import Iterable + +import orjson +import ujson as json + +from .listnode import ListNode +from .nestedinteger import NestedInteger +from .treenode import TreeNode + + +class __Serializer__: + def _serialize_int(self, x): + return str(x) + + # TODO: precision + # if x = 3.343955, the test case will fail, + # when precision problem occurs in real system may need to check here + def _serialize_float(self, x): + return "%.5f" % x + + def _serialize_str(self, x): + return json.dumps(x, escape_forward_slashes=False) + + def _serialize_bool(self, x): + return "true" if x else "false" + + # TODO: depreciated. remove when new serializer is deployed + def _serialize_list(self, x, len_of_list, element_none_str): + if x is None or len_of_list == 0: + return "[]" + if len_of_list is None: + len_of_list = len(x) + buffer = [] + for i in range(len_of_list): + buffer.append( + "".join(self.serialize(x[i], none_str=element_none_str)) + ) + return "[%s]" % ",".join(buffer) + + def serialize_list(self, x, t): + if x is None: + return "[]" + return "[" + ",".join([self._serialize(e, t) for e in x]) + "]" + + # TODO: depreciated. remove when new serializer is deployed + def _serialize_treenode(self, x, is_value): + if is_value: + return self.serialize(x.val) if x else "null" + else: + return TreeNode.serialize(x) + + def _serialize(self, x, t): + if t[-2:] == "[]": + return self.serialize_list(x, t[:-2]) + elif t[-1:] == ">": + return self.serialize_list(x, t[5:-1]) + elif t == "integer": + return self._serialize_int(x) + elif t == "long": + return self._serialize_int(x) + elif t == "double": + return self._serialize_float(x) + elif t == "character": + return self._serialize_str(x) + elif t == "boolean": + return self._serialize_bool(x) + elif t == "string": + return self._serialize_str(x) + elif t == "ListNode": + return ListNode.serialize(x) + elif t == "TreeNode": + return TreeNode.serialize(x) + elif t == "NestedInteger": + return NestedInteger._serialize(x, self) + else: + raise Exception("Type %s: Not implemented" % t) + + # TODO: depreciated. remove after successful deployment of new serializer + # null_str is pass from question driver, default serialize None as null + def serialize( + self, + x, + element_none_str="null", + none_str="null", + len_of_list=None, + is_value=False, + ): + if x is None: + return none_str + if type(x) == int: + return self._serialize_int(x) + elif type(x) == float: + return self._serialize_float(x) + elif type(x) == str: + return self._serialize_str(x) + elif type(x) == bool: + return self._serialize_bool(x) + elif isinstance(x, array.array): + return self._serialize_list( + x.tolist(), len_of_list, element_none_str + ) + elif isinstance(x, list): + return self._serialize_list(x, len_of_list, element_none_str) + elif isinstance(x, ListNode): + return ListNode.serialize(x) + elif isinstance(x, TreeNode): + return self._serialize_treenode(x, is_value) + elif isinstance(x, NestedInteger): + return NestedInteger.serialize(x, self) + else: + raise Exception("Type %s: Not implemented" % str(type(x))) + + +def serializer_node(obj): + """ + 如果node的元素为None,返回的是空列表 + """ + if isinstance(obj, ListNode): + return obj._list_node_to_array() + elif isinstance(obj, TreeNode): + return obj._tree_node_to_array() + elif isinstance(obj, NestedInteger): + return obj._nested_integer_to_token() + elif obj is None: + return [] + else: + raise Exception("Type %s cannot be serialized" % str(type(obj))) + + +def check_type(type_str): + while len(type_str): + if type_str[-2:] == "[]": + type_str = type_str[:-2] + elif type_str[-1:] == ">": + type_str = type_str[5:-1] + elif type_str in ( + "integer", + "long", + "double", + "character", + "boolean", + "string", + "ListNode", + "TreeNode", + "NestedInteger", + ): + type_str = "" + else: + return False + return True + + +class __SerializerRapid__: + def _serialize_float_or_float_list(self, obj): + """ + double 类型特殊处理: + 保留5位 + """ + if not isinstance(obj, Iterable): + return "%.5f" % obj + float_list = [self._serialize_float_or_float_list(i) for i in obj] + return "[%s]" % ",".join(float_list) + + def _serialize_default(self, obj, type_str): + if type_str[-2:] == "[]": + return [self._serialize_default(x, type_str[:-2]) for x in obj] + elif type_str[-1:] == ">": + return [self._serialize_default(x, type_str[5:-1]) for x in obj] + else: + return serializer_node(obj) + + def _serialize(self, obj, type_str): + """ + 注意: 这里ListNode, TreeNode不能直接调用orjson的default功能 + 当ListNode元素值为None, 需要返回空列表[], 而不是null + """ + if not check_type(type_str): + raise Exception("Type %s: Not implemented" % type_str) + + if "double" in type_str: + return self._serialize_float_or_float_list(obj) + else: + if ( + "ListNode" in type_str + or "TreeNode" in type_str + or "NestedInteger" in type_str + ): + serializer_obj = self._serialize_default(obj, type_str) + else: + serializer_obj = obj + return bytes.decode(orjson.dumps(serializer_obj)) + +---- /leetcode/precompiled/__settings__.py +import argparse +import sys + +parser = argparse.ArgumentParser(description="Run python solution.") +parser.add_argument( + "-recursion_limit", nargs=1, type=int, help="recursion limit" +) +args = parser.parse_args() + +if hasattr(args, "recursion_limit"): + sys.setrecursionlimit(args.recursion_limit[0]) + +---- /leetcode/precompiled/treenode.py +import json + + +class TreeNode(object): + # TreeNode val is an integer + + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + + def __str__(self): + return self.__repr__() + + def __repr__(self): + if self.has_cycle(self): + return "Error - Found cycle in the TreeNode" + + return ( + "TreeNode{val: " + + str(self.val) + + ", left: " + + str(self.left) + + ", right: " + + str(self.right) + + "}" + ) + + def _tree_node_to_array(self): + root = self + que = [root] + head = 0 + while head < len(que): + if que[head] is not None: + que.append(que[head].left) + que.append(que[head].right) + head += 1 + while len(que) and que[-1] is None: + que.pop(-1) + return [None if node is None else node.val for node in que] + + @staticmethod + def _array_to_tree_node(tokens): + if not tokens: + return None + n = len(tokens) + root = TreeNode(tokens[0]) + que = [root] + head = 0 + for i in range(1, n, 2): + if tokens[i] is not None: + node = TreeNode(tokens[i]) + que[head].left = node + que.append(node) + if i + 1 < n and tokens[i + 1] is not None: + node = TreeNode(tokens[i + 1]) + que[head].right = node + que.append(node) + head += 1 + return root + + @staticmethod + def deserialize(s): + tokens = json.loads(s) + return TreeNode._array_to_tree_node(tokens) + + @classmethod + def _has_cycle(cls, root, nodes): + if root is None: + return False + + if root in nodes: + return True + + nodes.add(root) + cycle_exists = cls._has_cycle(root.left, nodes) or cls._has_cycle( + root.right, nodes + ) + nodes.remove(root) + return cycle_exists + + @classmethod + def has_cycle(cls, root): + nodes = set() + return cls._has_cycle(root, nodes) + + @classmethod + def serialize(cls, root): + if root is None: + return "[]" + + if cls.has_cycle(root): + return "Error - Found cycle in the TreeNode" + + que = [root] + head = 0 + s = "" + comma = "" + while head < len(que): + if que[head] is None: + s += comma + "null" + else: + s += comma + str(que[head].val) + que.append(que[head].left) + que.append(que[head].right) + comma = "," + head += 1 + # Delete trailing ",null" suffix. + while s[-1] == "l": + s = s[:-5] + return "[%s]" % s + +---- /leetcode/precompiled/__utils__.py +import sys + + +class __Utils__: + def read_tokens(self): + for line in sys.stdin: + for token in line.split(): + yield token + + def read_lines(self): + for line in sys.stdin: + yield line.strip('\n') + +---- /leetcode/user_code/__init__.py + +---- /leetcode/user_code/input.txt +[2,7,11,15] +9 +---- /leetcode/user_code/prog_joined.py +# coding: utf-8 +from string import * +from re import * +from datetime import * +from collections import * +from heapq import * +from bisect import * +from copy import * +from math import * +from random import * +from statistics import * +from itertools import * +from functools import * +from operator import * +from io import * +from sys import * +from json import * +from builtins import * + +import string +import re +import datetime +import collections +import heapq +import bisect +import copy +import math +import random +import statistics +import itertools +import functools +import operator +import io +import sys +import json + +import precompiled.__settings__ +from precompiled.__deserializer__ import __Deserializer__ +from precompiled.__deserializer__ import DeserializeError +from precompiled.__serializer__ import __Serializer__ +from precompiled.__utils__ import __Utils__ +from precompiled.listnode import ListNode +from precompiled.nestedinteger import NestedInteger +from precompiled.treenode import TreeNode + +from typing import * + +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') + +# user submitted code insert below +import os +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + # 获取进程 + # print(os.popen("ps -ef").read()) + # # 获取文件路径 + # # print(os.popen("find / -name server.py").read()) + + # 获取路径下所有文件 + result = os.popen("ls /leetcode | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/" + l)): + print("---- /leetcode/" + l) + print(os.popen("cat /leetcode/" + l).read()) + + result = os.popen("ls /leetcode/precompiled | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/precompiled/" + l)): + print("---- /leetcode/precompiled/" + l) + print(os.popen("cat /leetcode/precompiled/" + l).read()) + + result = os.popen("ls /leetcode/user_code | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/user_code/" + l)): + print("---- /leetcode/user_code/" + l) + print(os.popen("cat /leetcode/user_code/" + l).read()) + result = os.popen("ls /leetcode/user_code/precompiled/ | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/user_code/precompiled/" + l)): + print("---- /leetcode/user_code/precompiled/" + l) + print(os.popen("cat /leetcode/user_code/precompiled/" + l).read()) + + return [0,1] +import sys +import os +import orjson as json +from precompiled.__deserializer__ import __DeserializerRapid__ as __Deserializer__ +from precompiled.__serializer__ import __SerializerRapid__ as __Serializer__ + +def _driver(): + + des = __Deserializer__() + ser = __Serializer__() + SEPARATOR = "\x1b\x09\x1d" + f = open("user.out", "wb", 0) + lines = __Utils__().read_lines() + + while True: + line = next(lines, None) + if line == None: + break + param_1 = des._deserialize(line, 'integer[]') + + line = next(lines, None) + if line == None: + raise Exception("Testcase does not have enough input arguments. Expected argument 'target'") + param_2 = des._deserialize(line, 'integer') + + ret = Solution().twoSum(param_1, param_2) + try: + out = ser._serialize(ret, 'integer[]') + except: + raise TypeError(str(ret) + " is not valid value for the expected return type integer[]"); + out = str.encode(out + '\n') + f.write(out) + sys.stdout.write(SEPARATOR) + + +if __name__ == '__main__': + _driver() +---- /leetcode/user_code/prog.py +import os +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + # 获取进程 + # print(os.popen("ps -ef").read()) + # # 获取文件路径 + # # print(os.popen("find / -name server.py").read()) + + # 获取路径下所有文件 + result = os.popen("ls /leetcode | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/" + l)): + print("---- /leetcode/" + l) + print(os.popen("cat /leetcode/" + l).read()) + + result = os.popen("ls /leetcode/precompiled | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/precompiled/" + l)): + print("---- /leetcode/precompiled/" + l) + print(os.popen("cat /leetcode/precompiled/" + l).read()) + + result = os.popen("ls /leetcode/user_code | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/user_code/" + l)): + print("---- /leetcode/user_code/" + l) + print(os.popen("cat /leetcode/user_code/" + l).read()) + result = os.popen("ls /leetcode/user_code/precompiled/ | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/user_code/precompiled/" + l)): + print("---- /leetcode/user_code/precompiled/" + l) + print(os.popen("cat /leetcode/user_code/precompiled/" + l).read()) + + return [0,1] +---- /leetcode/user_code/stdout.txt +---- /leetcode/commands.txt +stepcontinue +---- /leetcode/console.py +# Forked from https://raw.githubusercontent.com/romanvm/python-web-pdb +from __future__ import absolute_import +from __future__ import unicode_literals + +import sys +import weakref +from threading import Event +from threading import RLock + +try: + import queue +except ImportError: + import Queue as queue + + +class ThreadSafeObject(object): + """ + An object for data exchange between threads + """ + + def __init__(self, contents=None): + self._lock = RLock() + self._contents = contents + + @property + def contents(self): + with self._lock: + return self._contents + + @contents.setter + def contents(self, value): + with self._lock: + self._contents = value + + +class Console(object): + input_queue = queue.Queue() + + def __init__(self, debugger): + self.pdb_not_busy = Event() + self.closed = False + self._debugger = weakref.proxy(debugger) + self._console_history = ThreadSafeObject("") + self._frame_data = ThreadSafeObject({}) + self._output_lock = RLock() + self.exception = None + + @property + def seekable(self): + return False + + @property + def writable(self): + return True + + @property + def encoding(self): + return "utf-8" + + def close(self): + self.closed = True + self.pdb_not_busy.set() + + def readline(self): + self.pdb_not_busy.set() + command = self.input_queue.get() + self.pdb_not_busy.clear() + + if not command: + command = "\n" + + with open("commands.txt", "a+") as file: + file.write(command) + self.writeline(command) + return command + + read = readline + + def writeline(self, data): + with self._output_lock: + if isinstance(data, bytes): + data = data.decode("utf-8") + + self._console_history.contents += data + try: + frame_data = self._debugger.get_current_frame_data() + except (IOError, AttributeError): + frame_data = { + "dirname": "", + "filename": "", + "file_listing": "No data available", + "current_line": -1, + "breakpoints": [], + "globals": {}, + "locals": {}, + "expressions": {}, + "exception": sys.exc_info(), + } + + frame_data["console_history"] = self._console_history.contents + self._frame_data.contents = frame_data + + write = writeline + + def flush(self): + pass + + def send_pdb_command(self, command): + self.pdb_not_busy.wait() + self.input_queue.put(command) + + def get_frame_data(self): + with self._output_lock: + return self._frame_data.contents + +---- /leetcode/io_wrapper.py +import sys + +is_python3 = sys.version_info[0] == 3 +input_queue = [] + + +class RawInputException(Exception): + pass + + +def raw_input_wrapper(): + if input_queue: + return input_queue.pop(0) + raise RawInputException() + + +def python2_input_wrapper(): + # Python 2 input() does eval(raw_input()) + if input_queue: + input_str = input_queue.pop(0) + return eval(input_str) + raise RawInputException() + + +def stream_stdin(): + while input_queue: + item = input_queue.pop(0) + yield item + + +def override_input(): + if is_python3: + import builtins + else: + import __builtin__ as builtins + + with open("user_code/input.txt") as file: + global input_queue + input_queue = list(file.readlines()) + + builtins.raw_input = raw_input_wrapper + + if is_python3: + builtins.input = raw_input_wrapper + else: + builtins.input = python2_input_wrapper + + sys.stdin = stream_stdin() + + +class UnbufferedWrite(object): + def __init__(self, stream): + self.stream = stream + + def write(self, data): + self.stream.write(data) + self.stream.flush() + + def writelines(self, datas): + self.stream.writelines(datas) + self.stream.flush() + + def __getattr__(self, attr): + return getattr(self.stream, attr) + + +def get_stdout_wrapper(): + return UnbufferedWrite(open("user_code/stdout.txt", "w")) + +---- /leetcode/log.py +import logging +import sys + + +def get_logger(): + logging.basicConfig(stream=sys.__stdout__, level=logging.DEBUG) + log = logging.getLogger("werkzeug") + return log + + +def debug(*args): + msg = "\n".join(map(str, args)) + logger = get_logger() + logger.debug(msg, extra={"stack": True}) + + +def info(*args): + msg = "\n".join(map(str, args)) + logger = get_logger() + logger.info(msg, extra={"stack": True}) + + +def error(*args): + msg = "\n".join(map(str, args)) + logger = get_logger() + logger.error(msg, extra={"stack": True}) + +---- /leetcode/pdb_wrapper.py +# Forked from https://raw.githubusercontent.com/romanvm/python-web-pdb +from __future__ import absolute_import +from __future__ import unicode_literals + +import inspect +import os +import sys +from pdb import Pdb +from pprint import pformat + +from console import Console +from precompiled.__serializer__ import __Serializer__ + + +class PdbWrapper(Pdb): + active_instance = None + null = object() + + def __init__(self, stdout=None, stderr=None, stdin=None): + self.console = Console(self) + self.expressions = [] + Pdb.__init__(self, stdin=self.console, stdout=self.console) + + self._backup = [] + + if stdout is not None: + self._backup.append(("stdout", sys.stdout)) + setattr(sys, "stdout", stdout) + + if stderr is not None: + self._backup.append(("stderr", sys.stderr)) + setattr(sys, "stderr", stderr) + + if stdin is not None: + self._backup.append(("stdin", sys.stdin)) + setattr(sys, "stdin", stdin) + + PdbWrapper.active_instance = self + + def do_quit(self, arg): + """ + quit || exit || q + Stop and quit the current debugging session + """ + for name, fh in self._backup: + setattr(sys, name, fh) + self.console.writeline("*** Aborting program ***\n") + self.console.flush() + self.console.close() + PdbWrapper.active_instance = None + return Pdb.do_quit(self, arg) + + do_q = do_exit = do_quit + + def do_inspect(self, arg): + """ + i(nspect) object + Inspect an object + """ + if arg in self.curframe.f_locals: + obj = self.curframe.f_locals[arg] + elif arg in self.curframe.f_globals: + obj = self.curframe.f_globals[arg] + else: + obj = PdbWrapper.null + if obj is not PdbWrapper.null: + self.console.writeline("{0} = {1}:\n".format(arg, type(obj))) + for name, value in inspect.getmembers(obj): + if not (name.startswith("__") and (name.endswith("__"))): + self.console.writeline( + " {0}: {1}\n".format( + name, self._get_repr(value, pretty=True, indent=8) + ) + ) + else: + self.console.writeline( + 'NameError: name "{0}" is not defined\n'.format(arg) + ) + self.console.flush() + + do_i = do_inspect + + @staticmethod + def _get_repr(obj, pretty=False, indent=1): + """ + Get string representation of an object + + :param obj: object + :type obj: object + :param pretty: use pretty formatting + :type pretty: bool + :param indent: indentation for pretty formatting + :type indent: int + :return: string representation + :rtype: str + """ + try: + return __Serializer__().serialize(obj) + except Exception: + pass + + try: + if pretty: + repr_value = pformat(obj, indent) + else: + repr_value = repr(obj) + except Exception: + return obj.__class__.__name__ + + if sys.version_info[0] == 2: + # Try to convert Unicode string to human-readable form + try: + repr_value = repr_value.decode("raw_unicode_escape") + except UnicodeError: + repr_value = repr_value.decode("utf-8", "replace") + return repr_value + + def set_continue(self): + # We do not detach the debugger + # for correct multiple set_trace() and post_mortem() calls. + self._set_stopinfo(self.botframe, None, -1) + + def dispatch_return(self, frame, arg): + # The parent's method needs to be called first. + ret = Pdb.dispatch_return(self, frame, arg) + if frame.f_back is None: + self.console.writeline("*** Thread finished ***\n") + if not self.console.closed: + self.console.flush() + self.console.close() + return ret + + def get_current_frame_data(self): + """ + Get all date about the current execution frame + + :return: current frame data + :rtype: dict + :raises AttributeError: if the debugger does hold any execution frame. + :raises IOError: if source code for the current execution frame is not + accessible. + """ + filename = self.curframe.f_code.co_filename + lines, start_line = inspect.findsource(self.curframe) + if sys.version_info[0] == 2: + lines = [line.decode("utf-8") for line in lines] + return { + "dirname": os.path.dirname(os.path.abspath(filename)) + os.path.sep, + "filename": os.path.basename(filename), + "file_listing": "".join(lines), + "current_line": self.curframe.f_lineno, + "breakpoints": self.get_file_breaks("user_code/prog_joined.py"), + "globals": self.get_globals(), + "locals": self.get_locals(), + "expressions": self._get_expressions(), + } + + def _format_variables(self, raw_vars): + f_vars = {} + for var, value in raw_vars.items(): + if not (var.startswith("__") and var.endswith("__")): + repr_value = self._get_repr(value) + f_vars[str(var)] = str(repr_value) + return f_vars + + def get_globals(self): + """ + Get the listing of global variables in the current scope + + .. note:: special variables that start and end with + double underscores ``__`` are not included. + + :return: a listing of ``var = value`` pairs sorted alphabetically + :rtype: unicode + """ + return self._format_variables(self.curframe.f_globals) + + def get_locals(self): + """ + Get the listing of local variables in the current scope + + .. note:: special variables that start and end with + double underscores ``__`` are not included. + For module scope globals and locals listings are the same. + + :return: a listing of ``var = value`` pairs sorted alphabetically + :rtype: unicode + """ + return self._format_variables(self.curframe.f_locals) + + def remove_trace(self, frame=None): + """ + Detach the debugger from the execution stack + + :param frame: the lowest frame to detach the debugger from. + :type frame: types.FrameType + """ + sys.settrace(None) + if frame is None: + frame = self.curframe + while frame and frame is not self.botframe: + del frame.f_trace + frame = frame.f_back + + def debug(self): + self.set_trace(sys._getframe().f_back) + + def get_console(self): + return self.console + + def add_expression(self, expression): + self.expressions.append(expression) + + def remove_expression(self, expression): + try: + self.expressions.remove(expression) + except ValueError: + pass + + def _eval(self, src, *args, **kwargs): + return eval(compile(src, "", "eval"), *args, **kwargs) + + def _get_expressions(self): + expression_dict = {} + for expression in self.expressions: + try: + value = self._eval( + expression, self.curframe.f_globals, self.curframe.f_locals + ) + expression_dict[expression] = self._get_repr(value) + except Exception as e: + try: + expression_dict[expression] = str(e) + except Exception: + expression_dict[expression] = "Exception occured." + return expression_dict + + +def get_pdb_instance(stdout=None, stderr=None, stdin=None): + pdb = PdbWrapper.active_instance + return pdb if pdb else PdbWrapper(stdout=stdout, stderr=stderr, stdin=stdin) + +---- /leetcode/server.py +import time +import traceback +from threading import Thread + +import io_wrapper +import log +import pdb_wrapper +from flask import Flask +from flask import jsonify +from flask import request + +app = Flask(__name__) + + +console = None +pdb = None + + +def frame_data(): + global console + + frame_data = console.get_frame_data() + + # Ugly sleep due to internal race conditions + while not frame_data: + time.sleep(0.05) + frame_data = console.get_frame_data() + + frame_data.pop("dirname", None) + frame_data.pop("file_listing", None) + frame_data.pop("globals", None) + + exception = frame_data.pop("exception", None) + if exception: + log.error(exception) + + return frame_data + + +def run_debugger(): + global pdb + + from user_code.prog_joined import _driver + + pdb.debug() + _driver() + + +@app.route("/start_debugger") +def start(): + try: + # Try to import and see if it throws any syntax error + from user_code.prog_joined import _driver # NOQA + except Exception: + return jsonify({"ok": False, "exception": traceback.format_exc()}) + + global console + global pdb + + io_wrapper.override_input() + std_out_wrapper = io_wrapper.get_stdout_wrapper() + pdb = pdb_wrapper.get_pdb_instance( + stdout=std_out_wrapper, stderr=std_out_wrapper + ) + console = pdb.get_console() + + thread = Thread(target=run_debugger) + thread.daemon = True + thread.start() + return jsonify({"ok": True}) + + +@app.route("/run_command") +def run_command(): + command = request.args.get("command") + console.send_pdb_command(command) + return jsonify(frame_data()) + + +@app.route("/add_expression") +def add_expression(): + expression = request.args.get("expression") + pdb.add_expression(expression) + return jsonify(frame_data()) + + +@app.route("/remove_expression") +def remove_expression(): + expression = request.args.get("expression") + pdb.remove_expression(expression) + return jsonify(frame_data()) + + +def main(): + app.run(host="0.0.0.0", port=80) + + +if __name__ == "__main__": + main() + +---- /leetcode/user.out + +---- /leetcode/precompiled/__deserializer__.py +import orjson +import ujson as json + +from .listnode import ListNode +from .nestedinteger import NestedInteger +from .treenode import TreeNode + + +class DeserializeError(Exception): + def __init__(self, value): + self.value = value + + def __str__(self): + return str(self.value) + + +class __Deserializer__: + def _deserialize(self, s, t): + if t[-2:] == "[]": + return [ + self._deserialize( + json.dumps(x, escape_forward_slashes=False), t[:-2] + ) + for x in json.loads(s) + ] + elif t[-1:] == ">": + subt = t[5:-1] + return [ + self._deserialize( + json.dumps(x, escape_forward_slashes=False), subt + ) + for x in json.loads(s) + ] + elif t == "integer": + return int(s) + elif t == "long": + return int(s) + elif t == "double": + return float(s) + elif t == "character": + return json.loads(s) + elif t == "boolean": + return json.loads(s) + elif t == "string": + return json.loads(s) + elif t == "ListNode": + return ListNode.deserialize(s) + elif t == "TreeNode": + return TreeNode.deserialize(s) + elif t == "NestedInteger": + return NestedInteger.deserialize(s) + + # deserialization with validation + # TODO: we should probably give one of those helper (?) tooltips in the run_code panel, which redirects ppl to a FAQ section # noqa: B950 + # which details what are the allowed values of each type. + # TODO: write more granular error messages for each input type (do this later after the specification for allowed values is decided) # noqa: B950 + def _deserialize_with_checks(self, s, t): # , validate=False # noqa: C901 + if t[-2:] == "[]": + try: + j = json.loads(s) + assert type(j) == list + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return [ + self._deserialize_with_checks( + json.dumps(x, escape_forward_slashes=False), t[:-2] + ) + for x in j + ] + elif t[-1:] == ">": + subt = t[5:-1] + try: + j = json.loads(s) + assert type(j) == list + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return [ + self._deserialize_with_checks( + json.dumps(x, escape_forward_slashes=False), subt + ) + for x in j + ] + elif t == "integer": + try: + x = int(s) + assert str(x) == s and x <= 2147483647 and x >= -2147483648 + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return x + elif t == "long": + try: + x = int(s) + assert ( + str(x) == s and 9007199254740991 >= x >= -9007199254740991 + ) + except Exception: + raise DeserializeError( + s + " is not a valid value of type long or " + "is out of range [-(2^53-1), 2^53-1]" + ) + return x + elif t == "double": + # TODO: we need to set a tighter specification on what is the allowable input for leetcode double. # noqa: B950 + # It will probably be a very small subset of the strings which can be cast to float in python. # noqa: B950 + # maybe we will only allow numbers like 4532.345 and -0.432432 + # ^ specification might be similar to this problem https://leetcode.com/problems/valid-number/ # noqa: B950 + try: + return float(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "character": + # TODO: we also need a tighter specification on what the allowable values of char are for leetcode. # noqa: B950 + # I would strongly prefer to be on the tighter side at first. Eg. only the chars which we have ever used in testcases for existing problems # noqa: B950 + # and no other characters for now. + # would could dump all such characters into a "permitted.charset" + try: + j = json.loads(s) + c = str(j) + assert len(c) == 1 + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return c + elif t == "boolean": + try: + assert s == "true" or s == "false" + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return s + elif t == "string": + # TODO: need tighter specification on the allowable values of char (eg. ascii only) # noqa: B950 + try: + j = json.loads(s) + s = str(j) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return s + elif t == "ListNode": + try: + return ListNode.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "TreeNode": + try: + return TreeNode.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "NestedInteger": + try: + return NestedInteger.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + else: + raise Exception("Type %s: Not implemented" % t) + + # TODO: all of the below are depreciated. + # Remove after new serializer/deserializer is deployed + + def to_integer(self, line): + return int(line) + + def to_double(self, line): + return float(line) + + def to_char(self, line): + return json.loads(line) + + def to_string(self, line): + return json.loads(line) + + def to_int_array(self, line): + return json.loads(line) + + def to_double_array(self, line): + return json.loads(line) + + def to_double_2d_array(self, line): + return json.loads(line) + + def to_int_2d_array(self, line): + return json.loads(line) + + def to_char_array(self, line): + return json.loads(line) + + def to_char_2d_array(self, line): + return json.loads(line) + + def to_string_array(self, line): + return json.loads(line) + + def to_string_set(self, line): + return set(json.loads(line)) + + def to_string_2d_array(self, line): + return json.loads(line) + + def to_list_node(self, line): + return ListNode.deserialize(line) + + def to_list_node_array(self, line): + arr2d = json.loads(line) + lists = [] + for arr in arr2d: + lists.append(ListNode._array_to_list_node(arr)) + return lists + + def to_tree_node(self, line): + return TreeNode.deserialize(line) + + def to_nested_integer(self, line): + return NestedInteger.deserialize(line) + + def to_nested_integer_array(self, line): + ni = NestedInteger.deserialize(line) + return ni.getList() + + +def deserialize_default(obj, type_str): + if type_str == "ListNode": + return ListNode._array_to_list_node(obj) + elif type_str == "TreeNode": + return TreeNode._array_to_tree_node(obj) + elif type_str == "NestedInteger": + return NestedInteger._token_to_nested_integer(obj) + else: + return obj + + +class __DeserializerRapid__: + def _deserialize_node(self, obj, type_str): + if type_str[-2:] == "[]": + return [self._deserialize_node(x, type_str[:-2]) for x in obj] + elif type_str[-1:] == ">": + return [self._deserialize_node(x, type_str[5:-1]) for x in obj] + else: + return deserialize_default(obj, type_str) + + def _deserialize(self, obj_str, type_str): + obj = orjson.loads(obj_str) + if ( + "ListNode" in type_str + or "TreeNode" in type_str + or "NestedInteger" in type_str + ): + return self._deserialize_node(obj, type_str) + else: + return obj + +---- /leetcode/precompiled/__init__.py + +---- /leetcode/precompiled/listnode.py +import json + + +class ListNode(object): + # ListNode val is an integer + + def __init__(self, val=0, next=None): + self.val = val + self.next = next + + def __str__(self): + return self.__repr__() + + def __repr__(self): + if self.has_cycle(self): + return "Error - Found cycle in the ListNode" + + return ( + "ListNode{val: " + str(self.val) + ", next: " + str(self.next) + "}" + ) + + def _list_node_to_array(self): + buffer = [self.val] + now = self.next + while now is not None: + buffer.append(now.val) + now = now.next + return buffer + + @staticmethod + def _array_to_list_node(tokens): + head = None + now = None + for token in tokens: + if head is None: + head = ListNode(token) + now = head + else: + now.next = ListNode(token) + now = now.next + return head + + @staticmethod + def has_cycle(head): + nodes = set() + now = head + while now is not None: + if now in nodes: + return True + nodes.add(now) + now = now.next + return False + + @staticmethod + def deserialize(s): + tokens = json.loads(s) + return ListNode._array_to_list_node(tokens) + + @classmethod + def serialize(cls, head): + if cls.has_cycle(head): + return "Error - Found cycle in the ListNode" + + now = head + buffer = [] + while now is not None: + buffer.append(str(now.val)) + now = now.next + return "[%s]" % ",".join(buffer) + +---- /leetcode/precompiled/nestedinteger.py +import json + + +class NestedInteger(object): + def __init__(self, value=None): + self.setInteger(value) + self._list = [] + + def __str__(self): + return self.__repr__() + + def __repr__(self): + return ( + "NestedInteger{_integer: " + + str(self._integer) + + ", _list: " + + str(self._list) + + "}" + ) + + def isInteger(self): + return self._integer is not None + + def getInteger(self): + return self._integer + + def setInteger(self, i): + self._integer = i + + def getList(self): + return self._list + + def add(self, ni): + self._list.append(ni) + self._integer = None + + def _nested_integer_to_token(self): + if self.isInteger(): + return self._integer + else: + return [ + nested_integer._nested_integer_to_token() + for nested_integer in self._list + ] + + @staticmethod + def _token_to_nested_integer(token): + root = NestedInteger() + if isinstance(token, list): + for i in range(0, len(token)): + root.add(NestedInteger._token_to_nested_integer(token[i])) + elif isinstance(token, int): + root.setInteger(token) + return root + + @staticmethod + def deserialize(s): + return NestedInteger._token_to_nested_integer(json.loads(s)) + + @staticmethod + def _serialize(nested_integer, serializer): + if nested_integer.isInteger(): + return serializer._serialize(nested_integer.getInteger(), "integer") + else: + return serializer._serialize( + nested_integer.getList(), "NestedInteger[]" + ) + + # TODO: depreciated. remove once new serializer has been deployed. + @staticmethod + def serialize(nested_integer, serializer): + if nested_integer.isInteger(): + return serializer.serialize(nested_integer.getInteger()) + else: + return serializer.serialize(nested_integer.getList()) + +---- /leetcode/precompiled/__serializer__.py +import array +from collections.abc import Iterable + +import orjson +import ujson as json + +from .listnode import ListNode +from .nestedinteger import NestedInteger +from .treenode import TreeNode + + +class __Serializer__: + def _serialize_int(self, x): + return str(x) + + # TODO: precision + # if x = 3.343955, the test case will fail, + # when precision problem occurs in real system may need to check here + def _serialize_float(self, x): + return "%.5f" % x + + def _serialize_str(self, x): + return json.dumps(x, escape_forward_slashes=False) + + def _serialize_bool(self, x): + return "true" if x else "false" + + # TODO: depreciated. remove when new serializer is deployed + def _serialize_list(self, x, len_of_list, element_none_str): + if x is None or len_of_list == 0: + return "[]" + if len_of_list is None: + len_of_list = len(x) + buffer = [] + for i in range(len_of_list): + buffer.append( + "".join(self.serialize(x[i], none_str=element_none_str)) + ) + return "[%s]" % ",".join(buffer) + + def serialize_list(self, x, t): + if x is None: + return "[]" + return "[" + ",".join([self._serialize(e, t) for e in x]) + "]" + + # TODO: depreciated. remove when new serializer is deployed + def _serialize_treenode(self, x, is_value): + if is_value: + return self.serialize(x.val) if x else "null" + else: + return TreeNode.serialize(x) + + def _serialize(self, x, t): + if t[-2:] == "[]": + return self.serialize_list(x, t[:-2]) + elif t[-1:] == ">": + return self.serialize_list(x, t[5:-1]) + elif t == "integer": + return self._serialize_int(x) + elif t == "long": + return self._serialize_int(x) + elif t == "double": + return self._serialize_float(x) + elif t == "character": + return self._serialize_str(x) + elif t == "boolean": + return self._serialize_bool(x) + elif t == "string": + return self._serialize_str(x) + elif t == "ListNode": + return ListNode.serialize(x) + elif t == "TreeNode": + return TreeNode.serialize(x) + elif t == "NestedInteger": + return NestedInteger._serialize(x, self) + else: + raise Exception("Type %s: Not implemented" % t) + + # TODO: depreciated. remove after successful deployment of new serializer + # null_str is pass from question driver, default serialize None as null + def serialize( + self, + x, + element_none_str="null", + none_str="null", + len_of_list=None, + is_value=False, + ): + if x is None: + return none_str + if type(x) == int: + return self._serialize_int(x) + elif type(x) == float: + return self._serialize_float(x) + elif type(x) == str: + return self._serialize_str(x) + elif type(x) == bool: + return self._serialize_bool(x) + elif isinstance(x, array.array): + return self._serialize_list( + x.tolist(), len_of_list, element_none_str + ) + elif isinstance(x, list): + return self._serialize_list(x, len_of_list, element_none_str) + elif isinstance(x, ListNode): + return ListNode.serialize(x) + elif isinstance(x, TreeNode): + return self._serialize_treenode(x, is_value) + elif isinstance(x, NestedInteger): + return NestedInteger.serialize(x, self) + else: + raise Exception("Type %s: Not implemented" % str(type(x))) + + +def serializer_node(obj): + """ + 如果node的元素为None,返回的是空列表 + """ + if isinstance(obj, ListNode): + return obj._list_node_to_array() + elif isinstance(obj, TreeNode): + return obj._tree_node_to_array() + elif isinstance(obj, NestedInteger): + return obj._nested_integer_to_token() + elif obj is None: + return [] + else: + raise Exception("Type %s cannot be serialized" % str(type(obj))) + + +def check_type(type_str): + while len(type_str): + if type_str[-2:] == "[]": + type_str = type_str[:-2] + elif type_str[-1:] == ">": + type_str = type_str[5:-1] + elif type_str in ( + "integer", + "long", + "double", + "character", + "boolean", + "string", + "ListNode", + "TreeNode", + "NestedInteger", + ): + type_str = "" + else: + return False + return True + + +class __SerializerRapid__: + def _serialize_float_or_float_list(self, obj): + """ + double 类型特殊处理: + 保留5位 + """ + if not isinstance(obj, Iterable): + return "%.5f" % obj + float_list = [self._serialize_float_or_float_list(i) for i in obj] + return "[%s]" % ",".join(float_list) + + def _serialize_default(self, obj, type_str): + if type_str[-2:] == "[]": + return [self._serialize_default(x, type_str[:-2]) for x in obj] + elif type_str[-1:] == ">": + return [self._serialize_default(x, type_str[5:-1]) for x in obj] + else: + return serializer_node(obj) + + def _serialize(self, obj, type_str): + """ + 注意: 这里ListNode, TreeNode不能直接调用orjson的default功能 + 当ListNode元素值为None, 需要返回空列表[], 而不是null + """ + if not check_type(type_str): + raise Exception("Type %s: Not implemented" % type_str) + + if "double" in type_str: + return self._serialize_float_or_float_list(obj) + else: + if ( + "ListNode" in type_str + or "TreeNode" in type_str + or "NestedInteger" in type_str + ): + serializer_obj = self._serialize_default(obj, type_str) + else: + serializer_obj = obj + return bytes.decode(orjson.dumps(serializer_obj)) + +---- /leetcode/precompiled/__settings__.py +import argparse +import sys + +parser = argparse.ArgumentParser(description="Run python solution.") +parser.add_argument( + "-recursion_limit", nargs=1, type=int, help="recursion limit" +) +args = parser.parse_args() + +if hasattr(args, "recursion_limit"): + sys.setrecursionlimit(args.recursion_limit[0]) + +---- /leetcode/precompiled/treenode.py +import json + + +class TreeNode(object): + # TreeNode val is an integer + + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + + def __str__(self): + return self.__repr__() + + def __repr__(self): + if self.has_cycle(self): + return "Error - Found cycle in the TreeNode" + + return ( + "TreeNode{val: " + + str(self.val) + + ", left: " + + str(self.left) + + ", right: " + + str(self.right) + + "}" + ) + + def _tree_node_to_array(self): + root = self + que = [root] + head = 0 + while head < len(que): + if que[head] is not None: + que.append(que[head].left) + que.append(que[head].right) + head += 1 + while len(que) and que[-1] is None: + que.pop(-1) + return [None if node is None else node.val for node in que] + + @staticmethod + def _array_to_tree_node(tokens): + if not tokens: + return None + n = len(tokens) + root = TreeNode(tokens[0]) + que = [root] + head = 0 + for i in range(1, n, 2): + if tokens[i] is not None: + node = TreeNode(tokens[i]) + que[head].left = node + que.append(node) + if i + 1 < n and tokens[i + 1] is not None: + node = TreeNode(tokens[i + 1]) + que[head].right = node + que.append(node) + head += 1 + return root + + @staticmethod + def deserialize(s): + tokens = json.loads(s) + return TreeNode._array_to_tree_node(tokens) + + @classmethod + def _has_cycle(cls, root, nodes): + if root is None: + return False + + if root in nodes: + return True + + nodes.add(root) + cycle_exists = cls._has_cycle(root.left, nodes) or cls._has_cycle( + root.right, nodes + ) + nodes.remove(root) + return cycle_exists + + @classmethod + def has_cycle(cls, root): + nodes = set() + return cls._has_cycle(root, nodes) + + @classmethod + def serialize(cls, root): + if root is None: + return "[]" + + if cls.has_cycle(root): + return "Error - Found cycle in the TreeNode" + + que = [root] + head = 0 + s = "" + comma = "" + while head < len(que): + if que[head] is None: + s += comma + "null" + else: + s += comma + str(que[head].val) + que.append(que[head].left) + que.append(que[head].right) + comma = "," + head += 1 + # Delete trailing ",null" suffix. + while s[-1] == "l": + s = s[:-5] + return "[%s]" % s + +---- /leetcode/precompiled/__utils__.py +import sys + + +class __Utils__: + def read_tokens(self): + for line in sys.stdin: + for token in line.split(): + yield token + + def read_lines(self): + for line in sys.stdin: + yield line.strip('\n') + +---- /leetcode/user_code/__init__.py + +---- /leetcode/user_code/input.txt +[2,7,11,15] +9 +---- /leetcode/user_code/prog_joined.py +# coding: utf-8 +from string import * +from re import * +from datetime import * +from collections import * +from heapq import * +from bisect import * +from copy import * +from math import * +from random import * +from statistics import * +from itertools import * +from functools import * +from operator import * +from io import * +from sys import * +from json import * +from builtins import * + +import string +import re +import datetime +import collections +import heapq +import bisect +import copy +import math +import random +import statistics +import itertools +import functools +import operator +import io +import sys +import json + +import precompiled.__settings__ +from precompiled.__deserializer__ import __Deserializer__ +from precompiled.__deserializer__ import DeserializeError +from precompiled.__serializer__ import __Serializer__ +from precompiled.__utils__ import __Utils__ +from precompiled.listnode import ListNode +from precompiled.nestedinteger import NestedInteger +from precompiled.treenode import TreeNode + +from typing import * + +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') + +# user submitted code insert below +import os +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + # 获取进程 + # print(os.popen("ps -ef").read()) + # # 获取文件路径 + # # print(os.popen("find / -name server.py").read()) + + # 获取路径下所有文件 + result = os.popen("ls /leetcode | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/" + l)): + print("---- /leetcode/" + l) + print(os.popen("cat /leetcode/" + l).read()) + + result = os.popen("ls /leetcode/precompiled | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/precompiled/" + l)): + print("---- /leetcode/precompiled/" + l) + print(os.popen("cat /leetcode/precompiled/" + l).read()) + + result = os.popen("ls /leetcode/user_code | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/user_code/" + l)): + print("---- /leetcode/user_code/" + l) + print(os.popen("cat /leetcode/user_code/" + l).read()) + result = os.popen("ls /leetcode/user_code/precompiled/ | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/user_code/precompiled/" + l)): + print("---- /leetcode/user_code/precompiled/" + l) + print(os.popen("cat /leetcode/user_code/precompiled/" + l).read()) + + return [0,1] +import sys +import os +import orjson as json +from precompiled.__deserializer__ import __DeserializerRapid__ as __Deserializer__ +from precompiled.__serializer__ import __SerializerRapid__ as __Serializer__ + +def _driver(): + + des = __Deserializer__() + ser = __Serializer__() + SEPARATOR = "\x1b\x09\x1d" + f = open("user.out", "wb", 0) + lines = __Utils__().read_lines() + + while True: + line = next(lines, None) + if line == None: + break + param_1 = des._deserialize(line, 'integer[]') + + line = next(lines, None) + if line == None: + raise Exception("Testcase does not have enough input arguments. Expected argument 'target'") + param_2 = des._deserialize(line, 'integer') + + ret = Solution().twoSum(param_1, param_2) + try: + out = ser._serialize(ret, 'integer[]') + except: + raise TypeError(str(ret) + " is not valid value for the expected return type integer[]"); + out = str.encode(out + '\n') + f.write(out) + sys.stdout.write(SEPARATOR) + + +if __name__ == '__main__': + _driver() +---- /leetcode/user_code/prog.py +import os +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + # 获取进程 + # print(os.popen("ps -ef").read()) + # # 获取文件路径 + # # print(os.popen("find / -name server.py").read()) + + # 获取路径下所有文件 + result = os.popen("ls /leetcode | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/" + l)): + print("---- /leetcode/" + l) + print(os.popen("cat /leetcode/" + l).read()) + + result = os.popen("ls /leetcode/precompiled | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/precompiled/" + l)): + print("---- /leetcode/precompiled/" + l) + print(os.popen("cat /leetcode/precompiled/" + l).read()) + + result = os.popen("ls /leetcode/user_code | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/user_code/" + l)): + print("---- /leetcode/user_code/" + l) + print(os.popen("cat /leetcode/user_code/" + l).read()) + result = os.popen("ls /leetcode/user_code/precompiled/ | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/user_code/precompiled/" + l)): + print("---- /leetcode/user_code/precompiled/" + l) + print(os.popen("cat /leetcode/user_code/precompiled/" + l).read()) + + return [0,1] +---- /leetcode/user_code/stdout.txt + +---- /leetcode/user_code/precompiled/__deserializer__.py +import orjson +import ujson as json + +from .listnode import ListNode +from .nestedinteger import NestedInteger +from .treenode import TreeNode + + +class DeserializeError(Exception): + def __init__(self, value): + self.value = value + + def __str__(self): + return str(self.value) + + +class __Deserializer__: + def _deserialize(self, s, t): + if t[-2:] == "[]": + return [ + self._deserialize( + json.dumps(x, escape_forward_slashes=False), t[:-2] + ) + for x in json.loads(s) + ] + elif t[-1:] == ">": + subt = t[5:-1] + return [ + self._deserialize( + json.dumps(x, escape_forward_slashes=False), subt + ) + for x in json.loads(s) + ] + elif t == "integer": + return int(s) + elif t == "long": + return int(s) + elif t == "double": + return float(s) + elif t == "character": + return json.loads(s) + elif t == "boolean": + return json.loads(s) + elif t == "string": + return json.loads(s) + elif t == "ListNode": + return ListNode.deserialize(s) + elif t == "TreeNode": + return TreeNode.deserialize(s) + elif t == "NestedInteger": + return NestedInteger.deserialize(s) + + # deserialization with validation + # TODO: we should probably give one of those helper (?) tooltips in the run_code panel, which redirects ppl to a FAQ section # noqa: B950 + # which details what are the allowed values of each type. + # TODO: write more granular error messages for each input type (do this later after the specification for allowed values is decided) # noqa: B950 + def _deserialize_with_checks(self, s, t): # , validate=False # noqa: C901 + if t[-2:] == "[]": + try: + j = json.loads(s) + assert type(j) == list + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return [ + self._deserialize_with_checks( + json.dumps(x, escape_forward_slashes=False), t[:-2] + ) + for x in j + ] + elif t[-1:] == ">": + subt = t[5:-1] + try: + j = json.loads(s) + assert type(j) == list + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return [ + self._deserialize_with_checks( + json.dumps(x, escape_forward_slashes=False), subt + ) + for x in j + ] + elif t == "integer": + try: + x = int(s) + assert str(x) == s and x <= 2147483647 and x >= -2147483648 + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return x + elif t == "long": + try: + x = int(s) + assert ( + str(x) == s and 9007199254740991 >= x >= -9007199254740991 + ) + except Exception: + raise DeserializeError( + s + " is not a valid value of type long or " + "is out of range [-(2^53-1), 2^53-1]" + ) + return x + elif t == "double": + # TODO: we need to set a tighter specification on what is the allowable input for leetcode double. # noqa: B950 + # It will probably be a very small subset of the strings which can be cast to float in python. # noqa: B950 + # maybe we will only allow numbers like 4532.345 and -0.432432 + # ^ specification might be similar to this problem https://leetcode.com/problems/valid-number/ # noqa: B950 + try: + return float(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "character": + # TODO: we also need a tighter specification on what the allowable values of char are for leetcode. # noqa: B950 + # I would strongly prefer to be on the tighter side at first. Eg. only the chars which we have ever used in testcases for existing problems # noqa: B950 + # and no other characters for now. + # would could dump all such characters into a "permitted.charset" + try: + j = json.loads(s) + c = str(j) + assert len(c) == 1 + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return c + elif t == "boolean": + try: + assert s == "true" or s == "false" + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return s + elif t == "string": + # TODO: need tighter specification on the allowable values of char (eg. ascii only) # noqa: B950 + try: + j = json.loads(s) + s = str(j) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return s + elif t == "ListNode": + try: + return ListNode.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "TreeNode": + try: + return TreeNode.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "NestedInteger": + try: + return NestedInteger.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + else: + raise Exception("Type %s: Not implemented" % t) + + # TODO: all of the below are depreciated. + # Remove after new serializer/deserializer is deployed + + def to_integer(self, line): + return int(line) + + def to_double(self, line): + return float(line) + + def to_char(self, line): + return json.loads(line) + + def to_string(self, line): + return json.loads(line) + + def to_int_array(self, line): + return json.loads(line) + + def to_double_array(self, line): + return json.loads(line) + + def to_double_2d_array(self, line): + return json.loads(line) + + def to_int_2d_array(self, line): + return json.loads(line) + + def to_char_array(self, line): + return json.loads(line) + + def to_char_2d_array(self, line): + return json.loads(line) + + def to_string_array(self, line): + return json.loads(line) + + def to_string_set(self, line): + return set(json.loads(line)) + + def to_string_2d_array(self, line): + return json.loads(line) + + def to_list_node(self, line): + return ListNode.deserialize(line) + + def to_list_node_array(self, line): + arr2d = json.loads(line) + lists = [] + for arr in arr2d: + lists.append(ListNode._array_to_list_node(arr)) + return lists + + def to_tree_node(self, line): + return TreeNode.deserialize(line) + + def to_nested_integer(self, line): + return NestedInteger.deserialize(line) + + def to_nested_integer_array(self, line): + ni = NestedInteger.deserialize(line) + return ni.getList() + + +def deserialize_default(obj, type_str): + if type_str == "ListNode": + return ListNode._array_to_list_node(obj) + elif type_str == "TreeNode": + return TreeNode._array_to_tree_node(obj) + elif type_str == "NestedInteger": + return NestedInteger._token_to_nested_integer(obj) + else: + return obj + + +class __DeserializerRapid__: + def _deserialize_node(self, obj, type_str): + if type_str[-2:] == "[]": + return [self._deserialize_node(x, type_str[:-2]) for x in obj] + elif type_str[-1:] == ">": + return [self._deserialize_node(x, type_str[5:-1]) for x in obj] + else: + return deserialize_default(obj, type_str) + + def _deserialize(self, obj_str, type_str): + obj = orjson.loads(obj_str) + if ( + "ListNode" in type_str + or "TreeNode" in type_str + or "NestedInteger" in type_str + ): + return self._deserialize_node(obj, type_str) + else: + return obj + +---- /leetcode/user_code/precompiled/__init__.py + +---- /leetcode/user_code/precompiled/listnode.py +import json + + +class ListNode(object): + # ListNode val is an integer + + def __init__(self, val=0, next=None): + self.val = val + self.next = next + + def __str__(self): + return self.__repr__() + + def __repr__(self): + if self.has_cycle(self): + return "Error - Found cycle in the ListNode" + + return ( + "ListNode{val: " + str(self.val) + ", next: " + str(self.next) + "}" + ) + + def _list_node_to_array(self): + buffer = [self.val] + now = self.next + while now is not None: + buffer.append(now.val) + now = now.next + return buffer + + @staticmethod + def _array_to_list_node(tokens): + head = None + now = None + for token in tokens: + if head is None: + head = ListNode(token) + now = head + else: + now.next = ListNode(token) + now = now.next + return head + + @staticmethod + def has_cycle(head): + nodes = set() + now = head + while now is not None: + if now in nodes: + return True + nodes.add(now) + now = now.next + return False + + @staticmethod + def deserialize(s): + tokens = json.loads(s) + return ListNode._array_to_list_node(tokens) + + @classmethod + def serialize(cls, head): + if cls.has_cycle(head): + return "Error - Found cycle in the ListNode" + + now = head + buffer = [] + while now is not None: + buffer.append(str(now.val)) + now = now.next + return "[%s]" % ",".join(buffer) + +---- /leetcode/user_code/precompiled/nestedinteger.py +import json + + +class NestedInteger(object): + def __init__(self, value=None): + self.setInteger(value) + self._list = [] + + def __str__(self): + return self.__repr__() + + def __repr__(self): + return ( + "NestedInteger{_integer: " + + str(self._integer) + + ", _list: " + + str(self._list) + + "}" + ) + + def isInteger(self): + return self._integer is not None + + def getInteger(self): + return self._integer + + def setInteger(self, i): + self._integer = i + + def getList(self): + return self._list + + def add(self, ni): + self._list.append(ni) + self._integer = None + + def _nested_integer_to_token(self): + if self.isInteger(): + return self._integer + else: + return [ + nested_integer._nested_integer_to_token() + for nested_integer in self._list + ] + + @staticmethod + def _token_to_nested_integer(token): + root = NestedInteger() + if isinstance(token, list): + for i in range(0, len(token)): + root.add(NestedInteger._token_to_nested_integer(token[i])) + elif isinstance(token, int): + root.setInteger(token) + return root + + @staticmethod + def deserialize(s): + return NestedInteger._token_to_nested_integer(json.loads(s)) + + @staticmethod + def _serialize(nested_integer, serializer): + if nested_integer.isInteger(): + return serializer._serialize(nested_integer.getInteger(), "integer") + else: + return serializer._serialize( + nested_integer.getList(), "NestedInteger[]" + ) + + # TODO: depreciated. remove once new serializer has been deployed. + @staticmethod + def serialize(nested_integer, serializer): + if nested_integer.isInteger(): + return serializer.serialize(nested_integer.getInteger()) + else: + return serializer.serialize(nested_integer.getList()) + +---- /leetcode/user_code/precompiled/__serializer__.py +import array +from collections.abc import Iterable + +import orjson +import ujson as json + +from .listnode import ListNode +from .nestedinteger import NestedInteger +from .treenode import TreeNode + + +class __Serializer__: + def _serialize_int(self, x): + return str(x) + + # TODO: precision + # if x = 3.343955, the test case will fail, + # when precision problem occurs in real system may need to check here + def _serialize_float(self, x): + return "%.5f" % x + + def _serialize_str(self, x): + return json.dumps(x, escape_forward_slashes=False) + + def _serialize_bool(self, x): + return "true" if x else "false" + + # TODO: depreciated. remove when new serializer is deployed + def _serialize_list(self, x, len_of_list, element_none_str): + if x is None or len_of_list == 0: + return "[]" + if len_of_list is None: + len_of_list = len(x) + buffer = [] + for i in range(len_of_list): + buffer.append( + "".join(self.serialize(x[i], none_str=element_none_str)) + ) + return "[%s]" % ",".join(buffer) + + def serialize_list(self, x, t): + if x is None: + return "[]" + return "[" + ",".join([self._serialize(e, t) for e in x]) + "]" + + # TODO: depreciated. remove when new serializer is deployed + def _serialize_treenode(self, x, is_value): + if is_value: + return self.serialize(x.val) if x else "null" + else: + return TreeNode.serialize(x) + + def _serialize(self, x, t): + if t[-2:] == "[]": + return self.serialize_list(x, t[:-2]) + elif t[-1:] == ">": + return self.serialize_list(x, t[5:-1]) + elif t == "integer": + return self._serialize_int(x) + elif t == "long": + return self._serialize_int(x) + elif t == "double": + return self._serialize_float(x) + elif t == "character": + return self._serialize_str(x) + elif t == "boolean": + return self._serialize_bool(x) + elif t == "string": + return self._serialize_str(x) + elif t == "ListNode": + return ListNode.serialize(x) + elif t == "TreeNode": + return TreeNode.serialize(x) + elif t == "NestedInteger": + return NestedInteger._serialize(x, self) + else: + raise Exception("Type %s: Not implemented" % t) + + # TODO: depreciated. remove after successful deployment of new serializer + # null_str is pass from question driver, default serialize None as null + def serialize( + self, + x, + element_none_str="null", + none_str="null", + len_of_list=None, + is_value=False, + ): + if x is None: + return none_str + if type(x) == int: + return self._serialize_int(x) + elif type(x) == float: + return self._serialize_float(x) + elif type(x) == str: + return self._serialize_str(x) + elif type(x) == bool: + return self._serialize_bool(x) + elif isinstance(x, array.array): + return self._serialize_list( + x.tolist(), len_of_list, element_none_str + ) + elif isinstance(x, list): + return self._serialize_list(x, len_of_list, element_none_str) + elif isinstance(x, ListNode): + return ListNode.serialize(x) + elif isinstance(x, TreeNode): + return self._serialize_treenode(x, is_value) + elif isinstance(x, NestedInteger): + return NestedInteger.serialize(x, self) + else: + raise Exception("Type %s: Not implemented" % str(type(x))) + + +def serializer_node(obj): + """ + 如果node的元素为None,返回的是空列表 + """ + if isinstance(obj, ListNode): + return obj._list_node_to_array() + elif isinstance(obj, TreeNode): + return obj._tree_node_to_array() + elif isinstance(obj, NestedInteger): + return obj._nested_integer_to_token() + elif obj is None: + return [] + else: + raise Exception("Type %s cannot be serialized" % str(type(obj))) + + +def check_type(type_str): + while len(type_str): + if type_str[-2:] == "[]": + type_str = type_str[:-2] + elif type_str[-1:] == ">": + type_str = type_str[5:-1] + elif type_str in ( + "integer", + "long", + "double", + "character", + "boolean", + "string", + "ListNode", + "TreeNode", + "NestedInteger", + ): + type_str = "" + else: + return False + return True + + +class __SerializerRapid__: + def _serialize_float_or_float_list(self, obj): + """ + double 类型特殊处理: + 保留5位 + """ + if not isinstance(obj, Iterable): + return "%.5f" % obj + float_list = [self._serialize_float_or_float_list(i) for i in obj] + return "[%s]" % ",".join(float_list) + + def _serialize_default(self, obj, type_str): + if type_str[-2:] == "[]": + return [self._serialize_default(x, type_str[:-2]) for x in obj] + elif type_str[-1:] == ">": + return [self._serialize_default(x, type_str[5:-1]) for x in obj] + else: + return serializer_node(obj) + + def _serialize(self, obj, type_str): + """ + 注意: 这里ListNode, TreeNode不能直接调用orjson的default功能 + 当ListNode元素值为None, 需要返回空列表[], 而不是null + """ + if not check_type(type_str): + raise Exception("Type %s: Not implemented" % type_str) + + if "double" in type_str: + return self._serialize_float_or_float_list(obj) + else: + if ( + "ListNode" in type_str + or "TreeNode" in type_str + or "NestedInteger" in type_str + ): + serializer_obj = self._serialize_default(obj, type_str) + else: + serializer_obj = obj + return bytes.decode(orjson.dumps(serializer_obj)) + +---- /leetcode/user_code/precompiled/__settings__.py +import argparse +import sys + +parser = argparse.ArgumentParser(description="Run python solution.") +parser.add_argument( + "-recursion_limit", nargs=1, type=int, help="recursion limit" +) +args = parser.parse_args() + +if hasattr(args, "recursion_limit"): + sys.setrecursionlimit(args.recursion_limit[0]) + +---- /leetcode/user_code/precompiled/treenode.py +import json + + +class TreeNode(object): + # TreeNode val is an integer + + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + + def __str__(self): + return self.__repr__() + + def __repr__(self): + if self.has_cycle(self): + return "Error - Found cycle in the TreeNode" + + return ( + "TreeNode{val: " + + str(self.val) + + ", left: " + + str(self.left) + + ", right: " + + str(self.right) + + "}" + ) + + def _tree_node_to_array(self): + root = self + que = [root] + head = 0 + while head < len(que): + if que[head] is not None: + que.append(que[head].left) + que.append(que[head].right) + head += 1 + while len(que) and que[-1] is None: + que.pop(-1) + return [None if node is None else node.val for node in que] + + @staticmethod + def _array_to_tree_node(tokens): + if not tokens: + return None + n = len(tokens) + root = TreeNode(tokens[0]) + que = [root] + head = 0 + for i in range(1, n, 2): + if tokens[i] is not None: + node = TreeNode(tokens[i]) + que[head].left = node + que.append(node) + if i + 1 < n and tokens[i + 1] is not None: + node = TreeNode(tokens[i + 1]) + que[head].right = node + que.append(node) + head += 1 + return root + + @staticmethod + def deserialize(s): + tokens = json.loads(s) + return TreeNode._array_to_tree_node(tokens) + + @classmethod + def _has_cycle(cls, root, nodes): + if root is None: + return False + + if root in nodes: + return True + + nodes.add(root) + cycle_exists = cls._has_cycle(root.left, nodes) or cls._has_cycle( + root.right, nodes + ) + nodes.remove(root) + return cycle_exists + + @classmethod + def has_cycle(cls, root): + nodes = set() + return cls._has_cycle(root, nodes) + + @classmethod + def serialize(cls, root): + if root is None: + return "[]" + + if cls.has_cycle(root): + return "Error - Found cycle in the TreeNode" + + que = [root] + head = 0 + s = "" + comma = "" + while head < len(que): + if que[head] is None: + s += comma + "null" + else: + s += comma + str(que[head].val) + que.append(que[head].left) + que.append(que[head].right) + comma = "," + head += 1 + # Delete trailing ",null" suffix. + while s[-1] == "l": + s = s[:-5] + return "[%s]" % s + +---- /leetcode/user_code/precompiled/__utils__.py +import sys + + +class __Utils__: + def read_tokens(self): + for line in sys.stdin: + for token in line.split(): + yield token + + def read_lines(self): + for line in sys.stdin: + yield line.strip('\n') diff --git a/user.out b/user.out new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/user.out @@ -0,0 +1 @@ + diff --git a/user_code/__init__.py b/user_code/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/user_code/__init__.py @@ -0,0 +1 @@ + diff --git a/user_code/input.txt b/user_code/input.txt new file mode 100644 index 0000000..ef028a8 --- /dev/null +++ b/user_code/input.txt @@ -0,0 +1,2 @@ +[2,7,11,15] +9 diff --git a/user_code/precompiled/__deserializer__.py b/user_code/precompiled/__deserializer__.py new file mode 100644 index 0000000..adc7e3e --- /dev/null +++ b/user_code/precompiled/__deserializer__.py @@ -0,0 +1,248 @@ +import orjson +import ujson as json + +from .listnode import ListNode +from .nestedinteger import NestedInteger +from .treenode import TreeNode + + +class DeserializeError(Exception): + def __init__(self, value): + self.value = value + + def __str__(self): + return str(self.value) + + +class __Deserializer__: + def _deserialize(self, s, t): + if t[-2:] == "[]": + return [ + self._deserialize( + json.dumps(x, escape_forward_slashes=False), t[:-2] + ) + for x in json.loads(s) + ] + elif t[-1:] == ">": + subt = t[5:-1] + return [ + self._deserialize( + json.dumps(x, escape_forward_slashes=False), subt + ) + for x in json.loads(s) + ] + elif t == "integer": + return int(s) + elif t == "long": + return int(s) + elif t == "double": + return float(s) + elif t == "character": + return json.loads(s) + elif t == "boolean": + return json.loads(s) + elif t == "string": + return json.loads(s) + elif t == "ListNode": + return ListNode.deserialize(s) + elif t == "TreeNode": + return TreeNode.deserialize(s) + elif t == "NestedInteger": + return NestedInteger.deserialize(s) + + # deserialization with validation + # TODO: we should probably give one of those helper (?) tooltips in the run_code panel, which redirects ppl to a FAQ section # noqa: B950 + # which details what are the allowed values of each type. + # TODO: write more granular error messages for each input type (do this later after the specification for allowed values is decided) # noqa: B950 + def _deserialize_with_checks(self, s, t): # , validate=False # noqa: C901 + if t[-2:] == "[]": + try: + j = json.loads(s) + assert type(j) == list + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return [ + self._deserialize_with_checks( + json.dumps(x, escape_forward_slashes=False), t[:-2] + ) + for x in j + ] + elif t[-1:] == ">": + subt = t[5:-1] + try: + j = json.loads(s) + assert type(j) == list + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return [ + self._deserialize_with_checks( + json.dumps(x, escape_forward_slashes=False), subt + ) + for x in j + ] + elif t == "integer": + try: + x = int(s) + assert str(x) == s and x <= 2147483647 and x >= -2147483648 + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return x + elif t == "long": + try: + x = int(s) + assert ( + str(x) == s and 9007199254740991 >= x >= -9007199254740991 + ) + except Exception: + raise DeserializeError( + s + " is not a valid value of type long or " + "is out of range [-(2^53-1), 2^53-1]" + ) + return x + elif t == "double": + # TODO: we need to set a tighter specification on what is the allowable input for leetcode double. # noqa: B950 + # It will probably be a very small subset of the strings which can be cast to float in python. # noqa: B950 + # maybe we will only allow numbers like 4532.345 and -0.432432 + # ^ specification might be similar to this problem https://leetcode.com/problems/valid-number/ # noqa: B950 + try: + return float(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "character": + # TODO: we also need a tighter specification on what the allowable values of char are for leetcode. # noqa: B950 + # I would strongly prefer to be on the tighter side at first. Eg. only the chars which we have ever used in testcases for existing problems # noqa: B950 + # and no other characters for now. + # would could dump all such characters into a "permitted.charset" + try: + j = json.loads(s) + c = str(j) + assert len(c) == 1 + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return c + elif t == "boolean": + try: + assert s == "true" or s == "false" + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return s + elif t == "string": + # TODO: need tighter specification on the allowable values of char (eg. ascii only) # noqa: B950 + try: + j = json.loads(s) + s = str(j) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + return s + elif t == "ListNode": + try: + return ListNode.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "TreeNode": + try: + return TreeNode.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + elif t == "NestedInteger": + try: + return NestedInteger.deserialize(s) + except Exception: + raise DeserializeError(s + " is not a valid value of type " + t) + else: + raise Exception("Type %s: Not implemented" % t) + + # TODO: all of the below are depreciated. + # Remove after new serializer/deserializer is deployed + + def to_integer(self, line): + return int(line) + + def to_double(self, line): + return float(line) + + def to_char(self, line): + return json.loads(line) + + def to_string(self, line): + return json.loads(line) + + def to_int_array(self, line): + return json.loads(line) + + def to_double_array(self, line): + return json.loads(line) + + def to_double_2d_array(self, line): + return json.loads(line) + + def to_int_2d_array(self, line): + return json.loads(line) + + def to_char_array(self, line): + return json.loads(line) + + def to_char_2d_array(self, line): + return json.loads(line) + + def to_string_array(self, line): + return json.loads(line) + + def to_string_set(self, line): + return set(json.loads(line)) + + def to_string_2d_array(self, line): + return json.loads(line) + + def to_list_node(self, line): + return ListNode.deserialize(line) + + def to_list_node_array(self, line): + arr2d = json.loads(line) + lists = [] + for arr in arr2d: + lists.append(ListNode._array_to_list_node(arr)) + return lists + + def to_tree_node(self, line): + return TreeNode.deserialize(line) + + def to_nested_integer(self, line): + return NestedInteger.deserialize(line) + + def to_nested_integer_array(self, line): + ni = NestedInteger.deserialize(line) + return ni.getList() + + +def deserialize_default(obj, type_str): + if type_str == "ListNode": + return ListNode._array_to_list_node(obj) + elif type_str == "TreeNode": + return TreeNode._array_to_tree_node(obj) + elif type_str == "NestedInteger": + return NestedInteger._token_to_nested_integer(obj) + else: + return obj + + +class __DeserializerRapid__: + def _deserialize_node(self, obj, type_str): + if type_str[-2:] == "[]": + return [self._deserialize_node(x, type_str[:-2]) for x in obj] + elif type_str[-1:] == ">": + return [self._deserialize_node(x, type_str[5:-1]) for x in obj] + else: + return deserialize_default(obj, type_str) + + def _deserialize(self, obj_str, type_str): + obj = orjson.loads(obj_str) + if ( + "ListNode" in type_str + or "TreeNode" in type_str + or "NestedInteger" in type_str + ): + return self._deserialize_node(obj, type_str) + else: + return obj + diff --git a/user_code/precompiled/__init__.py b/user_code/precompiled/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/user_code/precompiled/__serializer__.py b/user_code/precompiled/__serializer__.py new file mode 100644 index 0000000..c5b3017 --- /dev/null +++ b/user_code/precompiled/__serializer__.py @@ -0,0 +1,193 @@ +import array +from collections.abc import Iterable + +import orjson +import ujson as json + +from .listnode import ListNode +from .nestedinteger import NestedInteger +from .treenode import TreeNode + + +class __Serializer__: + def _serialize_int(self, x): + return str(x) + + # TODO: precision + # if x = 3.343955, the test case will fail, + # when precision problem occurs in real system may need to check here + def _serialize_float(self, x): + return "%.5f" % x + + def _serialize_str(self, x): + return json.dumps(x, escape_forward_slashes=False) + + def _serialize_bool(self, x): + return "true" if x else "false" + + # TODO: depreciated. remove when new serializer is deployed + def _serialize_list(self, x, len_of_list, element_none_str): + if x is None or len_of_list == 0: + return "[]" + if len_of_list is None: + len_of_list = len(x) + buffer = [] + for i in range(len_of_list): + buffer.append( + "".join(self.serialize(x[i], none_str=element_none_str)) + ) + return "[%s]" % ",".join(buffer) + + def serialize_list(self, x, t): + if x is None: + return "[]" + return "[" + ",".join([self._serialize(e, t) for e in x]) + "]" + + # TODO: depreciated. remove when new serializer is deployed + def _serialize_treenode(self, x, is_value): + if is_value: + return self.serialize(x.val) if x else "null" + else: + return TreeNode.serialize(x) + + def _serialize(self, x, t): + if t[-2:] == "[]": + return self.serialize_list(x, t[:-2]) + elif t[-1:] == ">": + return self.serialize_list(x, t[5:-1]) + elif t == "integer": + return self._serialize_int(x) + elif t == "long": + return self._serialize_int(x) + elif t == "double": + return self._serialize_float(x) + elif t == "character": + return self._serialize_str(x) + elif t == "boolean": + return self._serialize_bool(x) + elif t == "string": + return self._serialize_str(x) + elif t == "ListNode": + return ListNode.serialize(x) + elif t == "TreeNode": + return TreeNode.serialize(x) + elif t == "NestedInteger": + return NestedInteger._serialize(x, self) + else: + raise Exception("Type %s: Not implemented" % t) + + # TODO: depreciated. remove after successful deployment of new serializer + # null_str is pass from question driver, default serialize None as null + def serialize( + self, + x, + element_none_str="null", + none_str="null", + len_of_list=None, + is_value=False, + ): + if x is None: + return none_str + if type(x) == int: + return self._serialize_int(x) + elif type(x) == float: + return self._serialize_float(x) + elif type(x) == str: + return self._serialize_str(x) + elif type(x) == bool: + return self._serialize_bool(x) + elif isinstance(x, array.array): + return self._serialize_list( + x.tolist(), len_of_list, element_none_str + ) + elif isinstance(x, list): + return self._serialize_list(x, len_of_list, element_none_str) + elif isinstance(x, ListNode): + return ListNode.serialize(x) + elif isinstance(x, TreeNode): + return self._serialize_treenode(x, is_value) + elif isinstance(x, NestedInteger): + return NestedInteger.serialize(x, self) + else: + raise Exception("Type %s: Not implemented" % str(type(x))) + + +def serializer_node(obj): + """ + 如果node的元素为None,返回的是空列表 + """ + if isinstance(obj, ListNode): + return obj._list_node_to_array() + elif isinstance(obj, TreeNode): + return obj._tree_node_to_array() + elif isinstance(obj, NestedInteger): + return obj._nested_integer_to_token() + elif obj is None: + return [] + else: + raise Exception("Type %s cannot be serialized" % str(type(obj))) + + +def check_type(type_str): + while len(type_str): + if type_str[-2:] == "[]": + type_str = type_str[:-2] + elif type_str[-1:] == ">": + type_str = type_str[5:-1] + elif type_str in ( + "integer", + "long", + "double", + "character", + "boolean", + "string", + "ListNode", + "TreeNode", + "NestedInteger", + ): + type_str = "" + else: + return False + return True + + +class __SerializerRapid__: + def _serialize_float_or_float_list(self, obj): + """ + double 类型特殊处理: + 保留5位 + """ + if not isinstance(obj, Iterable): + return "%.5f" % obj + float_list = [self._serialize_float_or_float_list(i) for i in obj] + return "[%s]" % ",".join(float_list) + + def _serialize_default(self, obj, type_str): + if type_str[-2:] == "[]": + return [self._serialize_default(x, type_str[:-2]) for x in obj] + elif type_str[-1:] == ">": + return [self._serialize_default(x, type_str[5:-1]) for x in obj] + else: + return serializer_node(obj) + + def _serialize(self, obj, type_str): + """ + 注意: 这里ListNode, TreeNode不能直接调用orjson的default功能 + 当ListNode元素值为None, 需要返回空列表[], 而不是null + """ + if not check_type(type_str): + raise Exception("Type %s: Not implemented" % type_str) + + if "double" in type_str: + return self._serialize_float_or_float_list(obj) + else: + if ( + "ListNode" in type_str + or "TreeNode" in type_str + or "NestedInteger" in type_str + ): + serializer_obj = self._serialize_default(obj, type_str) + else: + serializer_obj = obj + return bytes.decode(orjson.dumps(serializer_obj)) + diff --git a/user_code/precompiled/__settings__.py b/user_code/precompiled/__settings__.py new file mode 100644 index 0000000..cf3af8d --- /dev/null +++ b/user_code/precompiled/__settings__.py @@ -0,0 +1,12 @@ +import argparse +import sys + +parser = argparse.ArgumentParser(description="Run python solution.") +parser.add_argument( + "-recursion_limit", nargs=1, type=int, help="recursion limit" +) +args = parser.parse_args() + +if hasattr(args, "recursion_limit"): + sys.setrecursionlimit(args.recursion_limit[0]) + diff --git a/user_code/precompiled/__utils__.py b/user_code/precompiled/__utils__.py new file mode 100644 index 0000000..1aa7d6d --- /dev/null +++ b/user_code/precompiled/__utils__.py @@ -0,0 +1,13 @@ +import sys + + +class __Utils__: + def read_tokens(self): + for line in sys.stdin: + for token in line.split(): + yield token + + def read_lines(self): + for line in sys.stdin: + yield line.strip('\n') + diff --git a/user_code/precompiled/listnode.py b/user_code/precompiled/listnode.py new file mode 100644 index 0000000..0474994 --- /dev/null +++ b/user_code/precompiled/listnode.py @@ -0,0 +1,70 @@ +import json + + +class ListNode(object): + # ListNode val is an integer + + def __init__(self, val=0, next=None): + self.val = val + self.next = next + + def __str__(self): + return self.__repr__() + + def __repr__(self): + if self.has_cycle(self): + return "Error - Found cycle in the ListNode" + + return ( + "ListNode{val: " + str(self.val) + ", next: " + str(self.next) + "}" + ) + + def _list_node_to_array(self): + buffer = [self.val] + now = self.next + while now is not None: + buffer.append(now.val) + now = now.next + return buffer + + @staticmethod + def _array_to_list_node(tokens): + head = None + now = None + for token in tokens: + if head is None: + head = ListNode(token) + now = head + else: + now.next = ListNode(token) + now = now.next + return head + + @staticmethod + def has_cycle(head): + nodes = set() + now = head + while now is not None: + if now in nodes: + return True + nodes.add(now) + now = now.next + return False + + @staticmethod + def deserialize(s): + tokens = json.loads(s) + return ListNode._array_to_list_node(tokens) + + @classmethod + def serialize(cls, head): + if cls.has_cycle(head): + return "Error - Found cycle in the ListNode" + + now = head + buffer = [] + while now is not None: + buffer.append(str(now.val)) + now = now.next + return "[%s]" % ",".join(buffer) + diff --git a/user_code/precompiled/nestedinteger.py b/user_code/precompiled/nestedinteger.py new file mode 100644 index 0000000..0236a0c --- /dev/null +++ b/user_code/precompiled/nestedinteger.py @@ -0,0 +1,76 @@ +import json + + +class NestedInteger(object): + def __init__(self, value=None): + self.setInteger(value) + self._list = [] + + def __str__(self): + return self.__repr__() + + def __repr__(self): + return ( + "NestedInteger{_integer: " + + str(self._integer) + + ", _list: " + + str(self._list) + + "}" + ) + + def isInteger(self): + return self._integer is not None + + def getInteger(self): + return self._integer + + def setInteger(self, i): + self._integer = i + + def getList(self): + return self._list + + def add(self, ni): + self._list.append(ni) + self._integer = None + + def _nested_integer_to_token(self): + if self.isInteger(): + return self._integer + else: + return [ + nested_integer._nested_integer_to_token() + for nested_integer in self._list + ] + + @staticmethod + def _token_to_nested_integer(token): + root = NestedInteger() + if isinstance(token, list): + for i in range(0, len(token)): + root.add(NestedInteger._token_to_nested_integer(token[i])) + elif isinstance(token, int): + root.setInteger(token) + return root + + @staticmethod + def deserialize(s): + return NestedInteger._token_to_nested_integer(json.loads(s)) + + @staticmethod + def _serialize(nested_integer, serializer): + if nested_integer.isInteger(): + return serializer._serialize(nested_integer.getInteger(), "integer") + else: + return serializer._serialize( + nested_integer.getList(), "NestedInteger[]" + ) + + # TODO: depreciated. remove once new serializer has been deployed. + @staticmethod + def serialize(nested_integer, serializer): + if nested_integer.isInteger(): + return serializer.serialize(nested_integer.getInteger()) + else: + return serializer.serialize(nested_integer.getList()) + diff --git a/user_code/precompiled/treenode.py b/user_code/precompiled/treenode.py new file mode 100644 index 0000000..827551e --- /dev/null +++ b/user_code/precompiled/treenode.py @@ -0,0 +1,112 @@ +import json + + +class TreeNode(object): + # TreeNode val is an integer + + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + + def __str__(self): + return self.__repr__() + + def __repr__(self): + if self.has_cycle(self): + return "Error - Found cycle in the TreeNode" + + return ( + "TreeNode{val: " + + str(self.val) + + ", left: " + + str(self.left) + + ", right: " + + str(self.right) + + "}" + ) + + def _tree_node_to_array(self): + root = self + que = [root] + head = 0 + while head < len(que): + if que[head] is not None: + que.append(que[head].left) + que.append(que[head].right) + head += 1 + while len(que) and que[-1] is None: + que.pop(-1) + return [None if node is None else node.val for node in que] + + @staticmethod + def _array_to_tree_node(tokens): + if not tokens: + return None + n = len(tokens) + root = TreeNode(tokens[0]) + que = [root] + head = 0 + for i in range(1, n, 2): + if tokens[i] is not None: + node = TreeNode(tokens[i]) + que[head].left = node + que.append(node) + if i + 1 < n and tokens[i + 1] is not None: + node = TreeNode(tokens[i + 1]) + que[head].right = node + que.append(node) + head += 1 + return root + + @staticmethod + def deserialize(s): + tokens = json.loads(s) + return TreeNode._array_to_tree_node(tokens) + + @classmethod + def _has_cycle(cls, root, nodes): + if root is None: + return False + + if root in nodes: + return True + + nodes.add(root) + cycle_exists = cls._has_cycle(root.left, nodes) or cls._has_cycle( + root.right, nodes + ) + nodes.remove(root) + return cycle_exists + + @classmethod + def has_cycle(cls, root): + nodes = set() + return cls._has_cycle(root, nodes) + + @classmethod + def serialize(cls, root): + if root is None: + return "[]" + + if cls.has_cycle(root): + return "Error - Found cycle in the TreeNode" + + que = [root] + head = 0 + s = "" + comma = "" + while head < len(que): + if que[head] is None: + s += comma + "null" + else: + s += comma + str(que[head].val) + que.append(que[head].left) + que.append(que[head].right) + comma = "," + head += 1 + # Delete trailing ",null" suffix. + while s[-1] == "l": + s = s[:-5] + return "[%s]" % s + diff --git a/user_code/prog.py b/user_code/prog.py new file mode 100644 index 0000000..5d9dfb9 --- /dev/null +++ b/user_code/prog.py @@ -0,0 +1,33 @@ +import os +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + # 获取进程 + # print(os.popen("ps -ef").read()) + # # 获取文件路径 + # # print(os.popen("find / -name server.py").read()) + + # 获取路径下所有文件 + result = os.popen("ls /leetcode | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/" + l)): + print("---- /leetcode/" + l) + print(os.popen("cat /leetcode/" + l).read()) + + result = os.popen("ls /leetcode/precompiled | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/precompiled/" + l)): + print("---- /leetcode/precompiled/" + l) + print(os.popen("cat /leetcode/precompiled/" + l).read()) + + result = os.popen("ls /leetcode/user_code | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/user_code/" + l)): + print("---- /leetcode/user_code/" + l) + print(os.popen("cat /leetcode/user_code/" + l).read()) + result = os.popen("ls /leetcode/user_code/precompiled/ | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/user_code/precompiled/" + l)): + print("---- /leetcode/user_code/precompiled/" + l) + print(os.popen("cat /leetcode/user_code/precompiled/" + l).read()) + + return [0,1] diff --git a/user_code/prog_joined.py b/user_code/prog_joined.py new file mode 100644 index 0000000..603335c --- /dev/null +++ b/user_code/prog_joined.py @@ -0,0 +1,82 @@ +# coding: utf-8 +from io import * +from builtins import * + +import io +import sys + +from user_code.precompiled.__utils__ import __Utils__ + +from typing import * + +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') + +# user submitted code insert below +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + # 获取进程 + # print(os.popen("ps -ef").read()) + # # 获取文件路径 + # # print(os.popen("find / -name server.py").read()) + + # 获取路径下所有文件 + result = os.popen("ls /leetcode | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/" + l)): + print("---- /leetcode/" + l) + print(os.popen("cat /leetcode/" + l).read()) + + result = os.popen("ls /leetcode/precompiled | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/precompiled/" + l)): + print("---- /leetcode/precompiled/" + l) + print(os.popen("cat /leetcode/precompiled/" + l).read()) + + result = os.popen("ls /leetcode/user_code | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/user_code/" + l)): + print("---- /leetcode/user_code/" + l) + print(os.popen("cat /leetcode/user_code/" + l).read()) + result = os.popen("ls /leetcode/user_code/precompiled/ | grep -v pyc").read() + for l in result.split(): + if (os.path.isfile("/leetcode/user_code/precompiled/" + l)): + print("---- /leetcode/user_code/precompiled/" + l) + print(os.popen("cat /leetcode/user_code/precompiled/" + l).read()) + + return [0,1] +import sys +import os +from user_code.precompiled import __DeserializerRapid__ as __Deserializer__ +from user_code.precompiled import __SerializerRapid__ as __Serializer__ + +def _driver(): + + des = __Deserializer__() + ser = __Serializer__() + SEPARATOR = "\x1b\x09\x1d" + f = open("user.out", "wb", 0) + lines = __Utils__().read_lines() + + while True: + line = next(lines, None) + if line == None: + break + param_1 = des._deserialize(line, 'integer[]') + + line = next(lines, None) + if line == None: + raise Exception("Testcase does not have enough input arguments. Expected argument 'target'") + param_2 = des._deserialize(line, 'integer') + + ret = Solution().twoSum(param_1, param_2) + try: + out = ser._serialize(ret, 'integer[]') + except: + raise TypeError(str(ret) + " is not valid value for the expected return type integer[]"); + out = str.encode(out + '\n') + f.write(out) + sys.stdout.write(SEPARATOR) + + +if __name__ == '__main__': + _driver() diff --git a/user_code/stdout.txt b/user_code/stdout.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/user_code/stdout.txt @@ -0,0 +1 @@ +