def show_result(self, result: object) -> None: """ Show __repr__ for an `eval` result. """ out_prompt = to_formatted_text(self.get_output_prompt()) # If the repr is valid Python code, use the Pygments lexer. result_repr = repr(result) try: compile(result_repr, "", "eval") except SyntaxError: formatted_result_repr = to_formatted_text(result_repr) else: formatted_result_repr = to_formatted_text( PygmentsTokens(list(_lex_python_result(result_repr)))) # If __pt_repr__ is present, take this. This can return # prompt_toolkit formatted text. if hasattr(result, "__pt_repr__"): try: formatted_result_repr = to_formatted_text( getattr(result, "__pt_repr__")()) if isinstance(formatted_result_repr, list): formatted_result_repr = FormattedText( formatted_result_repr) except: pass # Align every line to the prompt. line_sep = "\n" + " " * fragment_list_width(out_prompt) indented_repr: StyleAndTextTuples = [] lines = list(split_lines(formatted_result_repr)) for i, fragment in enumerate(lines): indented_repr.extend(fragment) # Add indentation separator between lines, not after the last line. if i != len(lines) - 1: indented_repr.append(("", line_sep)) # Write output tokens. if self.enable_syntax_highlighting: formatted_output = merge_formatted_text( [out_prompt, indented_repr]) else: formatted_output = FormattedText(out_prompt + [( "", fragment_list_to_text(formatted_result_repr))]) print_formatted_text( formatted_output, style=self._current_style, style_transformation=self.style_transformation, include_default_pygments_style=False, output=self.app.output, ) self.app.output.flush()
def test_del_store_import(): for test in ( 'a!.b', 'a.b.c!.d', ): del_ = f'del {test}' store = f'{test} = 1' for test in del_, store: print(test) ie.compile(test, mode='exec')
def test_invalid_argument_syntax(): for invalid in ( 'def foo(x!): pass', 'def foo(*x!): pass', 'def foo(**y!): pass', 'def foo(*, z!): pass', # note space around equals sign: # class Y(Z!=1) is valid if Z.__ne__ returns a class 'class Y(Z! = 1): pass', ): with py.test.raises(SyntaxError): print(invalid) ie.compile(invalid, mode='exec')
def test_invalid_del_store_import(): for test in ( 'a!', 'a.b!', ): del_ = f'del {test}' store = f'{test} = 1' for test in del_, store: print(test) # we use Exception instead of SyntaxError because this error may be caught # by builtins.compile (raises ValueError) or ie.parse (raises SyntaxError) with py.test.raises(Exception): ie.compile(test, mode='exec')
def better_exec(script, globals_=None, locals_=None): parsed = import_expression.parse(script) base_function = "async def __evaluate_code(): pass" parsed_function = import_expression.parse(base_function) for node in parsed.body: ast.increment_lineno(node) def check_for_yield(payload): if isinstance(payload, (list, tuple)): for node_ in payload: if check_for_yield(node_): return True if isinstance(payload, (ast.Yield, ast.YieldFrom)): return True if hasattr(payload, 'body'): for node_ in payload.body: if check_for_yield(node_): return True if hasattr(payload, 'value'): if check_for_yield(payload.value): return True return False if not check_for_yield(parsed.body): insert_returns(parsed.body) parsed_function.body[0].body = parsed.body import_expression.exec( import_expression.compile(parsed_function, filename="<evaluator>", mode='exec'), globals_, locals_ )
def compile_with_flags(code: str, mode: str): " Compile code with the right compiler flags. " return compile( code, "<stdin>", mode, flags=self.get_compiler_flags(), dont_inherit=True, )
def _load_start_paths(self) -> None: " Start the Read-Eval-Print Loop. " if self._startup_paths: for path in self._startup_paths: if os.path.exists(path): with open(path, "rb") as f: code = compile(f.read(), path, "exec") exec(code, self.get_globals(), self.get_locals()) else: output = self.app.output output.write( "WARNING | File not found: {}\n\n".format(path))
def main(): args = parser.parse_args() if sum((args.list_of_stdin, args.lines_of_stdin)) > 1: err('Pythonpy accepts at most one of [-x, -l] flags') sys.exit(1) if args.pre_cmd: import_expression.exec(args.pre_cmd) if not args.expression and args.post_cmd: import_expression.exec(args.post_cmd) sys.exit(0) stdin = map(str.rstrip, sys.stdin) # ignore trailing newline if args.input_delimiter: split = re.compile(args.input_delimiter).split stdin = (split(l.rstrip()) for l in stdin) if args.output_delimiter: def fprint(x, join=args.output_delimiter.join): if x is not None: print(join(x)) else: def fprint(x): if x is not None: print(x) code = import_expression.compile(args.expression, '<pythonpy expression>', 'eval') if args.list_of_stdin: l = list(stdin) it = [import_expression.eval(code, dict(l=l))] elif args.lines_of_stdin: it = (import_expression.eval(code, dict(x=line)) for line in stdin) else: it = [import_expression.eval(code)] for x in it: try: it = [x] if isinstance(x, str) else iter(x) except TypeError: # not iterable fprint(x) else: for x in it: fprint(x) if args.post_cmd: import_expression.exec(args.post_cmd)
def validate(self, document): """ Check input for Python syntax errors. """ text = document.text # If the input is single line, remove leading whitespace. # (This doesn't have to be a syntax error.) if len(text.splitlines()) == 1: text = text.strip() # When the input starts with Ctrl-Z, always accept. This means EOF in a # Python REPL. if text.startswith("\x1a"): return try: if self.get_compiler_flags: flags = self.get_compiler_flags() else: flags = 0 flags |= PyCF_ALLOW_TOP_LEVEL_AWAIT compile(text, "<input>", "exec", flags=flags, dont_inherit=True) except SyntaxError as e: # Note, the 'or 1' for offset is required because Python 2.7 # gives `None` as offset in case of '4=4' as input. (Looks like # fixed in Python 3.) index = document.translate_row_col_to_index( e.lineno - 1, (e.offset or 1) - 1) raise ValidationError(index, f"Syntax Error: {e}") except TypeError as e: # e.g. "compile() expected string without null bytes" raise ValidationError(0, str(e)) except ValueError as e: # In Python 2, compiling "\x9" (an invalid escape sequence) raises # ValueError instead of SyntaxError. raise ValidationError(0, "Syntax Error: %s" % e)
def main(): args = parser.parse_args() if sum((args.list_of_stdin, args.lines_of_stdin)) > 1: err('Pythonpy accepts at most one of [-x, -l] flags') sys.exit(1) if args.pre_cmd: import_expression.exec(args.pre_cmd) if not args.expression and args.post_cmd: import_expression.exec(args.post_cmd) sys.exit(0) stdin = without_trailing(map(str.rstrip, sys.stdin), trailing='') # ignore trailing newline code = import_expression.compile(args.expression, '<pythonpy expression>', 'eval') if args.list_of_stdin: l = list(stdin) it = [import_expression.eval(code, dict(l=l))] elif args.lines_of_stdin: it = (import_expression.eval(code, dict(x=line)) for line in stdin) else: it = [import_expression.eval(code)] for x in it: if x is None: continue try: it = [x] if isinstance(x, str) else iter(x) except TypeError: # not iterable print(x) else: for x in it: print(x) if args.post_cmd: import_expression.exec(args.post_cmd)
def run_config(repl: PythonInput, config_file: str = "~/.ptpython/config.py") -> None: """ Execute REPL config file. :param repl: `PythonInput` instance. :param config_file: Path of the configuration file. """ # Expand tildes. config_file = os.path.expanduser(config_file) def enter_to_continue() -> None: input("\nPress ENTER to continue...") # Check whether this file exists. if not os.path.exists(config_file): print("Impossible to read %r" % config_file) enter_to_continue() return # Run the config file in an empty namespace. try: namespace: Dict[str, Any] = {} with open(config_file, "rb") as f: code = compile(f.read(), config_file, "exec") exec(code, namespace, namespace) # Now we should have a 'configure' method in this namespace. We call this # method with the repl as an argument. if "configure" in namespace: namespace["configure"](repl) except Exception: traceback.print_exc() enter_to_continue()
async def eval(self, ctx, *, code_string): if not self._env: self._env.update({"discord": discord, "commands": commands, '_': None, import_expression.constants.IMPORTER: importlib.import_module}) self._env['ctx'] = ctx try: expr = import_expression.compile(code_string) ret = eval(expr, self._env) except SyntaxError: pass except Exception as exc: await ctx.message.add_reaction(self.bot.tick_no) return await ctx.send_as_paginator(format_exc(exc), codeblock=True) else: if inspect.isawaitable(ret): fut = asyncio.ensure_future(ret, loop=self.bot.loop) self._evals.append(fut) try: with Timer(ctx.message): ret = await asyncio.wait_for(fut, timeout=self._timeout) except Exception as exc: await ctx.message.add_reaction(self.bot.tick_no) return await ctx.send_as_paginator(format_exc(exc), codeblock=True) finally: self._evals.remove(fut) await ctx.message.add_reaction(self.bot.tick_yes) if ret is None: return self._env['_'] = ret if isinstance(ret, discord.Embed): return await ctx.send(embed=ret) if not isinstance(ret, str): ret = repr(ret) return await ctx.send_as_paginator(ret, codeblock=self._send_in_codeblocks) code = f"""async def __func__(): try: {textwrap.indent(code_string, ' ')} finally: globals().update(locals())""" try: import_expression.exec(code, self._env) except Exception as exc: await ctx.message.add_reaction(self.bot.tick_no) return await ctx.send_as_paginator(format_exc(exc), codeblock=True) func = self._env.pop('__func__') fut = asyncio.ensure_future(func(), loop=self.bot.loop) self._evals.append(fut) try: with Timer(ctx.message): await asyncio.wait_for(fut, timeout=self._timeout) except asyncio.CancelledError: await ctx.message.add_reaction('\U0001f6d1') return except asyncio.TimeoutError: await ctx.message.add_reaction('\u23f0') return except Exception as exc: await ctx.message.add_reaction(self.bot.tick_no) return await ctx.send_as_paginator(format_exc(exc), codeblock=True) else: ret = fut.result() finally: self._evals.remove(fut) await ctx.message.add_reaction(self.bot.tick_yes) if ret is None: return self._env['_'] = ret if isinstance(ret, discord.Embed): return await ctx.send(embed=ret) if not isinstance(ret, str): ret = repr(ret) return await ctx.send_as_paginator(ret, codeblock=self._send_in_codeblocks)
def test_invalid_attribute_syntax(): for invalid in invalid_attribute_cases: print(invalid) # in case it does not raise and we want to see what failed with py.test.raises(SyntaxError): ie.compile(invalid)
def test_valid_string_literals(): for invalid in invalid_attribute_cases: valid = f'"{invalid}"' print(valid) ie.compile(valid)
def test_kwargs(): # See https://github.com/bmintz/import-expression-parser/issues/1 ie.compile('f(**a)', mode='eval') import collections assert ie.eval('dict(x=collections!)')['x'] is collections
async def eval(self, ctx, *, code_string): """ evaluates some code. Do not run this unless you know what you are doing! """ """ The code used in this command is licensed under AGPLv3 clause. Modification or distribution without permission is not granted unless it works with the License. XuaTheGrate - the owner of this code - has granted explicit permission for me to use this code within amalna. The original source code can be located here: https://github.com/iDevision/MostDefinitelyGrant2/blob/master/cogs/dev.py A copy of the AGPLv3 License can be located here: https://github.com/iDevision/MostDefinitelyGrant2/blob/master/LICENSE.md """ if not self._env: self._env.update({ "discord": discord, "twitchio": twitchio, "bot": self.bot, "twitch_streamer": self.core.twitch_streamer, "twitch_bot": self.core.twitch_bot, "db": self.core.db, "commands": commands, '_': None, import_expression.constants.IMPORTER: importlib.import_module}) self._env['ctx'] = ctx try: expr = import_expression.compile(code_string) ret = eval(expr, self._env) except SyntaxError: pass except Exception as exc: await ctx.message.add_reaction(self.bot.tick_no) return await ctx.paginate("".join(traceback.format_exception(type(exc), exc, exc.__traceback__)), codeblocks=True) else: if inspect.isawaitable(ret): fut = asyncio.ensure_future(ret, loop=self.bot.loop) self._evals.append(fut) try: with Timer(ctx.message): ret = await asyncio.wait_for(fut, timeout=self._timeout) except Exception as exc: await ctx.message.add_reaction(self.bot.tick_no) return await ctx.paginate("".join(traceback.format_exception(type(exc), exc, exc.__traceback__)), codeblocks=True) finally: self._evals.remove(fut) await ctx.message.add_reaction(self.bot.tick_yes) if ret is None: return self._env['_'] = ret if isinstance(ret, discord.Embed): return await ctx.send(embed=ret) if not isinstance(ret, str): ret = repr(ret) return await ctx.paginate(ret, codeblock=self._send_in_codeblocks) code = f"""async def __func__(): try: {textwrap.indent(code_string, ' ')} finally: globals().update(locals())""" try: import_expression.exec(code, self._env) except Exception as exc: await ctx.message.add_reaction(self.bot.tick_no) return await ctx.paginate("".join(traceback.format_exception(type(exc), exc, exc.__traceback__)), codeblocks=True) func = self._env.pop('__func__') fut = asyncio.ensure_future(func(), loop=self.bot.loop) self._evals.append(fut) try: with Timer(ctx.message): await asyncio.wait_for(fut, timeout=self._timeout) except asyncio.CancelledError: await ctx.message.add_reaction('\U0001f6d1') return except asyncio.TimeoutError: await ctx.message.add_reaction('\u23f0') return except Exception as exc: await ctx.message.add_reaction(self.bot.tick_no) return await ctx.paginate("".join(traceback.format_exception(type(exc), exc, exc.__traceback__)), codeblocks=True) else: ret = fut.result() finally: self._evals.remove(fut) await ctx.message.add_reaction(self.bot.tick_yes) if ret is None: return self._env['_'] = ret if isinstance(ret, discord.Embed): return await ctx.send(embed=ret) if not isinstance(ret, str): ret = repr(ret) return await ctx.paginate(ret, codeblocks=self._send_in_codeblocks)