From 462beb442db7f093c3002348667422dd106e5017 Mon Sep 17 00:00:00 2001 From: Vincent Michel Date: Mon, 16 Mar 2020 16:52:29 +0100 Subject: [PATCH 1/6] Rename aioconsole.code to aioconsole.console --- aioconsole/__init__.py | 2 +- aioconsole/command.py | 4 ++-- aioconsole/{code.py => console.py} | 0 aioconsole/events.py | 5 ++--- aioconsole/server.py | 6 +++--- 5 files changed, 8 insertions(+), 9 deletions(-) rename aioconsole/{code.py => console.py} (100%) diff --git a/aioconsole/__init__.py b/aioconsole/__init__.py index 4c9010a..67d1f1b 100644 --- a/aioconsole/__init__.py +++ b/aioconsole/__init__.py @@ -4,7 +4,7 @@ """ from .execute import aexec -from .code import AsynchronousConsole, interact +from .console import AsynchronousConsole, interact from .stream import ainput, aprint, get_standard_streams from .events import InteractiveEventLoop, InteractiveEventLoopPolicy from .events import set_interactive_policy, run_console diff --git a/aioconsole/command.py b/aioconsole/command.py index c4a7402..f986792 100644 --- a/aioconsole/command.py +++ b/aioconsole/command.py @@ -6,10 +6,10 @@ import argparse import shlex -from . import code +from . import console -class AsynchronousCli(code.AsynchronousConsole): +class AsynchronousCli(console.AsynchronousConsole): def __init__(self, commands, streams=None, *, prog=None, prompt_control=None, loop=None): diff --git a/aioconsole/code.py b/aioconsole/console.py similarity index 100% rename from aioconsole/code.py rename to aioconsole/console.py diff --git a/aioconsole/events.py b/aioconsole/events.py index fb1342e..3a94d26 100644 --- a/aioconsole/events.py +++ b/aioconsole/events.py @@ -3,15 +3,14 @@ import asyncio import functools -from . import code -from . import compat from . import server +from . import console class InteractiveEventLoop(asyncio.SelectorEventLoop): """Event loop running a python console.""" - console_class = code.AsynchronousConsole + console_class = console.AsynchronousConsole def __init__(self, *, selector=None, locals=None, banner=None, serve=None, prompt_control=None): diff --git a/aioconsole/server.py b/aioconsole/server.py index 4b57322..a058658 100644 --- a/aioconsole/server.py +++ b/aioconsole/server.py @@ -4,7 +4,7 @@ import socket from functools import partial -from . import code +from . import console @asyncio.coroutine @@ -17,7 +17,7 @@ def handle_connect(reader, writer, factory, banner=None): @asyncio.coroutine -def start_interactive_server(factory=code.AsynchronousConsole, +def start_interactive_server(factory=console.AsynchronousConsole, host=None, port=None, path=None, banner=None, *, loop=None): if (port is None) == (path is None): @@ -39,7 +39,7 @@ def start_console_server(host=None, port=None, path=None, locals=None, filename="", banner=None, prompt_control=None, *, loop=None): factory = partial( - code.AsynchronousConsole, + console.AsynchronousConsole, locals=locals, filename=filename, prompt_control=prompt_control) server = yield from start_interactive_server( factory, From 81126c4b13add55cf9307f00cb2b34a6a5b51209 Mon Sep 17 00:00:00 2001 From: Vincent Michel Date: Mon, 16 Mar 2020 16:53:14 +0100 Subject: [PATCH 2/6] Fix all flake8 warnings --- aioconsole/apython.py | 8 ++++---- aioconsole/command.py | 3 +-- aioconsole/console.py | 2 +- aioconsole/rlwrap.py | 2 +- aioconsole/stream.py | 10 +++++++++- example/cli.py | 1 + example/echo.py | 1 + tests/test_apython.py | 3 +++ tests/test_interact.py | 5 +++-- tests/test_stream.py | 4 ++-- 10 files changed, 26 insertions(+), 13 deletions(-) diff --git a/aioconsole/apython.py b/aioconsole/apython.py index 522fab7..5d2c0b0 100644 --- a/aioconsole/apython.py +++ b/aioconsole/apython.py @@ -35,14 +35,14 @@ def exec_pythonstartup(locals_dict): try: locals_dict['__file__'] = filename exec(startupcode, globals(), locals_dict) - except Exception as e: # pragma: no cover - tb = traceback.format_exc() - print(tb) + except Exception: # pragma: no cover + traceback.print_exc() finally: locals_dict.pop('__file__', None) else: - print('Could not open PYTHONSTARTUP - No such file: {}'.format(filename)) + message = 'Could not open PYTHONSTARTUP - No such file: {}' + print(message.format(filename)) def parse_args(args=None): diff --git a/aioconsole/command.py b/aioconsole/command.py index f986792..50976ee 100644 --- a/aioconsole/command.py +++ b/aioconsole/command.py @@ -1,7 +1,6 @@ """Provide an asynchronous equivalent to the python console.""" import sys -import random import asyncio import argparse import shlex @@ -97,7 +96,7 @@ def runsource(self, source, filename=None): raise # Prompt the traceback or result - except: + except BaseException: self.showtraceback() else: if result is not None: diff --git a/aioconsole/console.py b/aioconsole/console.py index 38748d7..46c9d98 100644 --- a/aioconsole/console.py +++ b/aioconsole/console.py @@ -107,7 +107,7 @@ def runcode(self, code): yield from execute.aexec(code, self.locals, self) except SystemExit: raise - except: + except BaseException: self.showtraceback() yield from self.flush() diff --git a/aioconsole/rlwrap.py b/aioconsole/rlwrap.py index 5e59666..e4ee73f 100644 --- a/aioconsole/rlwrap.py +++ b/aioconsole/rlwrap.py @@ -113,7 +113,7 @@ def write(arg): def input(prompt='', use_stderr=False): # Use readline if possible try: - import readline + import readline # noqa except ImportError: return builtins.input(prompt) # Use stdout diff --git a/aioconsole/stream.py b/aioconsole/stream.py index b823e64..f8402c8 100644 --- a/aioconsole/stream.py +++ b/aioconsole/stream.py @@ -199,7 +199,15 @@ def ainput(prompt='', *, streams=None, use_stderr=False, loop=None): @asyncio.coroutine -def aprint(*values, sep=None, end='\n', flush=False, streams=None, use_stderr=False, loop=None): +def aprint( + *values, + sep=None, + end='\n', + flush=False, + streams=None, + use_stderr=False, + loop=None +): """Asynchronous equivalent to *print*.""" # Get standard streams if streams is None: diff --git a/example/cli.py b/example/cli.py index c650539..801c82b 100644 --- a/example/cli.py +++ b/example/cli.py @@ -68,5 +68,6 @@ def main(args=None): asyncio.ensure_future(make_cli().interact()) return echo.run(host, port) + if __name__ == '__main__': main() diff --git a/example/echo.py b/example/echo.py index 73bf153..5428441 100644 --- a/example/echo.py +++ b/example/echo.py @@ -34,6 +34,7 @@ def main(args): host, port = server.split(':') return run(host, int(port)) + if __name__ == '__main__': import sys main(sys.argv) diff --git a/tests/test_apython.py b/tests/test_apython.py index 4a4ed4d..b07b957 100644 --- a/tests/test_apython.py +++ b/tests/test_apython.py @@ -28,11 +28,13 @@ def hehe(): ''' + @pytest.fixture def tempfd(): with tempfile.NamedTemporaryFile() as tf: yield tf + @contextmanager def mock_module(name): try: @@ -191,6 +193,7 @@ def test_apython_non_existing_module(capfd): assert out == '' assert "No module named idontexist" in err + def test_apython_pythonstartup(capfd, use_readline, monkeypatch, tempfd): monkeypatch.setenv('PYTHONSTARTUP', tempfd.name) diff --git a/tests/test_interact.py b/tests/test_interact.py index c155d1b..3d110ce 100644 --- a/tests/test_interact.py +++ b/tests/test_interact.py @@ -36,8 +36,9 @@ def stdcontrol(event_loop, monkeypatch): @asyncio.coroutine def assert_stream(stream, expected, loose=False): s = None if loose else "\n" - for line in expected.splitlines(): - assert line.strip(s) == (yield from stream.readline()).decode().strip(s) + for expected_line in expected.splitlines(): + line = yield from stream.readline() + assert expected_line.strip(s) == line.decode().strip(s) @pytest.fixture(params=['unix', 'not-unix']) diff --git a/tests/test_stream.py b/tests/test_stream.py index 7504f41..add211b 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -76,7 +76,7 @@ def test_create_standard_stream_with_non_pipe(): data = yield from reader.read(2) assert data == b'c\n' - assert reader.at_eof() == False + assert reader.at_eof() is False if compat.PY35: assert (yield from reader.__aiter__()) == reader @@ -87,7 +87,7 @@ def test_create_standard_stream_with_non_pipe(): assert (yield from reader.read()) == b'd\n' assert (yield from reader.read()) == b'' - assert reader.at_eof() == True + assert reader.at_eof() is True @pytest.mark.asyncio From d2ab409d04f278a5d90844aecd710b7e93d480ec Mon Sep 17 00:00:00 2001 From: Vincent Michel Date: Mon, 16 Mar 2020 17:07:29 +0100 Subject: [PATCH 3/6] Fix python 3.8 compatibility in the tests --- tests/test_apython.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_apython.py b/tests/test_apython.py index b07b957..092e569 100644 --- a/tests/test_apython.py +++ b/tests/test_apython.py @@ -183,7 +183,8 @@ def test_apython_non_existing_file(capfd): apython.run_apython(['idontexist.py']) out, err = capfd.readouterr() assert out == '' - assert "No such file or directory: 'idontexist.py'" in err + assert "No such file or directory" in err + assert "idontexist.py" in err def test_apython_non_existing_module(capfd): From f7414fb886751173d86eaeb7a45c254257bade33 Mon Sep 17 00:00:00 2001 From: Vincent Michel Date: Mon, 16 Mar 2020 17:08:10 +0100 Subject: [PATCH 4/6] Add python 3.9-dev to travis --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 050b8be..9e1b7c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,8 @@ python: - pypy3.5 - 3.6 - 3.7 -- 3.8-dev +- 3.8 +- 3.9-dev matrix: include: From 718bd71942fc106322922c23c7bba29a3b2cfaef Mon Sep 17 00:00:00 2001 From: Vincent Michel Date: Mon, 16 Mar 2020 18:24:51 +0100 Subject: [PATCH 5/6] Fix cx_Freeze issue (help function not availble, issue #59) --- aioconsole/console.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/aioconsole/console.py b/aioconsole/console.py index 46c9d98..8071004 100644 --- a/aioconsole/console.py +++ b/aioconsole/console.py @@ -20,6 +20,11 @@ Try: {0} asyncio.sleep(1, result=3) ---""".format('await' if compat.PY35 else 'yield from') +# cx_Freeze does not include the help function +try: + help_function = help +except NameError: + help_function = None current_task = ( asyncio.current_task if compat.PY37 else asyncio.Task.current_task) @@ -64,7 +69,7 @@ def print(self, *args, **kwargs): kwargs.setdefault('file', self) print(*args, **kwargs) - @functools.wraps(help) + @functools.wraps(help_function) def help(self, obj): self.print(pydoc.render_doc(obj)) From f33a7e0791ee8a84247dc8f4a19d903176ab5a23 Mon Sep 17 00:00:00 2001 From: Vincent Michel Date: Mon, 16 Mar 2020 18:26:04 +0100 Subject: [PATCH 6/6] Fix compatibility with StreamReaderProtocol.connection_lost --- aioconsole/stream.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/aioconsole/stream.py b/aioconsole/stream.py index f8402c8..c3f4b63 100644 --- a/aioconsole/stream.py +++ b/aioconsole/stream.py @@ -36,22 +36,21 @@ def protect_standard_streams(stream): class StandardStreamReaderProtocol(asyncio.StreamReaderProtocol): + def connection_made(self, transport): + # The connection is already made if self._stream_reader._transport is not None: return + # Make the connection super().connection_made(transport) def connection_lost(self, exc): - if self._stream_reader is not None: - if exc is None: - self._stream_reader.feed_eof() - else: - self._stream_reader.set_exception(exc) - if not self._closed.done(): - if exc is None: - self._closed.set_result(None) - else: - self._closed.set_exception(exc) + # Copy the inner state + state = self.__dict__.copy() + # Call the parent + super().connection_lost(exc) + # Restore the inner state + self.__dict__.update(state) class StandardStreamReader(asyncio.StreamReader):