Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-terminado for 
openSUSE:Factory checked in at 2021-10-11 15:31:55
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-terminado (Old)
 and      /work/SRC/openSUSE:Factory/.python-terminado.new.2443 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-terminado"

Mon Oct 11 15:31:55 2021 rev:12 rq:924566 version:0.12.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-terminado/python-terminado.changes        
2021-05-15 01:24:13.099018513 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-terminado.new.2443/python-terminado.changes  
    2021-10-11 15:32:56.946973084 +0200
@@ -1,0 +2,15 @@
+Sun Oct 10 19:56:06 UTC 2021 - Ben Greiner <c...@bnavigator.de>
+
+- update to version 0.12.1
+  * correctly set the TERM variable
+  * Replace deprecated unittest aliases
+  * Clean up tests
+  * Log terminal output
+  * Switch select() to poll() in pty_read()
+  * Fix blocking of pty_read when there isn't pty data ready to
+    read
+  * Support creating terminal given name in kwargs.
+  * avoid persistent handle on IOLoop instance
+  * async/await syntax
+
+-------------------------------------------------------------------

Old:
----
  terminado-0.9.5.tar.gz

New:
----
  terminado-0.12.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-terminado.spec ++++++
--- /var/tmp/diff_new_pack.zvfZU0/_old  2021-10-11 15:32:57.390973796 +0200
+++ /var/tmp/diff_new_pack.zvfZU0/_new  2021-10-11 15:32:57.394973802 +0200
@@ -21,7 +21,7 @@
 # Disable tests until random testing race condition fixed, see: 
https://github.com/jupyter/terminado/issues/21
 %bcond_with     tests
 Name:           python-terminado
-Version:        0.9.5
+Version:        0.12.1
 Release:        0
 Summary:        Terminals served to termjs using Tornado websockets
 License:        BSD-2-Clause

++++++ terminado-0.9.5.tar.gz -> terminado-0.12.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/terminado-0.9.5/PKG-INFO 
new/terminado-0.12.1/PKG-INFO
--- old/terminado-0.9.5/PKG-INFO        2021-05-11 13:40:15.468093400 +0200
+++ new/terminado-0.12.1/PKG-INFO       2021-09-07 16:32:39.483855700 +0200
@@ -1,86 +1,11 @@
 Metadata-Version: 2.1
 Name: terminado
-Version: 0.9.5
+Version: 0.12.1
 Summary: Tornado websocket backend for the Xterm.js Javascript terminal 
emulator library.
 Home-page: https://github.com/jupyter/terminado
 Author: Jupyter Development Team
 Author-email: jupy...@googlegroups.com
 License: UNKNOWN
-Description: This is a `Tornado <http://tornadoweb.org/>`_ websocket backend 
for the
-        `Xterm.js <https://xtermjs.org/>`_ Javascript terminal emulator
-        library.
-        
-        It evolved out of `pyxterm <https://github.com/mitotic/pyxterm>`_, 
which was
-        part of `GraphTerm <https://github.com/mitotic/graphterm>`_ (as 
lineterm.py),
-        v0.57.0 (2014-07-18), and ultimately derived from the public-domain 
`Ajaxterm
-        <http://antony.lesuisse.org/software/ajaxterm/>`_ code, v0.11 
(2008-11-13) (also
-        on Github as part of `QWeb <https://github.com/antonylesuisse/qweb>`_).
-        
-        Modules:
-        
-        * ``terminado.management``: controls launching virtual terminals,
-          connecting them to Tornado's event loop, and closing them down.
-        * ``terminado.websocket``: Provides a websocket handler for 
communicating with
-          a terminal.
-        * ``terminado.uimodule``: Provides a ``Terminal`` Tornado `UI Module
-          
<http://www.tornadoweb.org/en/stable/guide/templates.html#ui-modules>`_.
-        
-        JS:
-        
-        * ``terminado/_static/terminado.js``: A lightweight wrapper to set up a
-          term.js terminal with a websocket.
-        
-        Local Installation:
-        
-            $ pip install -e .[test]
-        
-        
-        Usage example:
-        
-        .. code:: python
-        
-            import os.path
-            import tornado.web
-            import tornado.ioloop
-            # This demo requires tornado_xstatic and XStatic-term.js
-            import tornado_xstatic
-        
-            import terminado
-            STATIC_DIR = os.path.join(os.path.dirname(terminado.__file__), 
"_static")
-        
-            class TerminalPageHandler(tornado.web.RequestHandler):
-                def get(self):
-                    return self.render("termpage.html", static=self.static_url,
-                                       
xstatic=self.application.settings['xstatic_url'],
-                                       ws_url_path="/websocket")
-        
-            if __name__ == '__main__':
-                term_manager = 
terminado.SingleTermManager(shell_command=['bash'])
-                handlers = [
-                            (r"/websocket", terminado.TermSocket,
-                                 {'term_manager': term_manager}),
-                            (r"/", TerminalPageHandler),
-                            (r"/xstatic/(.*)", 
tornado_xstatic.XStaticFileHandler,
-                                 {'allowed_modules': ['termjs']})
-                           ]
-                app = tornado.web.Application(handlers, static_path=STATIC_DIR,
-                                  xstatic_url = 
tornado_xstatic.url_maker('/xstatic/'))
-                # Serve at http://localhost:8765/ N.B. Leaving out 'localhost' 
here will
-                # work, but it will listen on the public network interface as 
well.
-                # Given what terminado does, that would be rather a security 
hole.
-                app.listen(8765, 'localhost')
-                try:
-                    tornado.ioloop.IOLoop.instance().start()
-                finally:
-                    term_manager.shutdown()
-        
-        See the `demos directory 
<https://github.com/takluyver/terminado/tree/master/demos>`_
-        for more examples. This is a simplified version of the ``single.py`` 
demo.
-        
-        Run the unit tests with:
-        
-            $ pytest
-        
 Platform: UNKNOWN
 Classifier: Environment :: Web Environment
 Classifier: License :: OSI Approved :: BSD License
@@ -90,3 +15,81 @@
 Requires-Python: >=3.6
 Description-Content-Type: text/x-rst
 Provides-Extra: test
+License-File: LICENSE
+
+This is a `Tornado <http://tornadoweb.org/>`_ websocket backend for the
+`Xterm.js <https://xtermjs.org/>`_ Javascript terminal emulator
+library.
+
+It evolved out of `pyxterm <https://github.com/mitotic/pyxterm>`_, which was
+part of `GraphTerm <https://github.com/mitotic/graphterm>`_ (as lineterm.py),
+v0.57.0 (2014-07-18), and ultimately derived from the public-domain `Ajaxterm
+<http://antony.lesuisse.org/software/ajaxterm/>`_ code, v0.11 (2008-11-13) 
(also
+on Github as part of `QWeb <https://github.com/antonylesuisse/qweb>`_).
+
+Modules:
+
+* ``terminado.management``: controls launching virtual terminals,
+  connecting them to Tornado's event loop, and closing them down.
+* ``terminado.websocket``: Provides a websocket handler for communicating with
+  a terminal.
+* ``terminado.uimodule``: Provides a ``Terminal`` Tornado `UI Module
+  <http://www.tornadoweb.org/en/stable/guide/templates.html#ui-modules>`_.
+
+JS:
+
+* ``terminado/_static/terminado.js``: A lightweight wrapper to set up a
+  term.js terminal with a websocket.
+
+Local Installation:
+
+    $ pip install -e .[test]
+
+
+Usage example:
+
+.. code:: python
+
+    import os.path
+    import tornado.web
+    import tornado.ioloop
+    # This demo requires tornado_xstatic and XStatic-term.js
+    import tornado_xstatic
+
+    import terminado
+    STATIC_DIR = os.path.join(os.path.dirname(terminado.__file__), "_static")
+
+    class TerminalPageHandler(tornado.web.RequestHandler):
+        def get(self):
+            return self.render("termpage.html", static=self.static_url,
+                               
xstatic=self.application.settings['xstatic_url'],
+                               ws_url_path="/websocket")
+
+    if __name__ == '__main__':
+        term_manager = terminado.SingleTermManager(shell_command=['bash'])
+        handlers = [
+                    (r"/websocket", terminado.TermSocket,
+                         {'term_manager': term_manager}),
+                    (r"/", TerminalPageHandler),
+                    (r"/xstatic/(.*)", tornado_xstatic.XStaticFileHandler,
+                         {'allowed_modules': ['termjs']})
+                   ]
+        app = tornado.web.Application(handlers, static_path=STATIC_DIR,
+                          xstatic_url = tornado_xstatic.url_maker('/xstatic/'))
+        # Serve at http://localhost:8765/ N.B. Leaving out 'localhost' here 
will
+        # work, but it will listen on the public network interface as well.
+        # Given what terminado does, that would be rather a security hole.
+        app.listen(8765, 'localhost')
+        try:
+            tornado.ioloop.IOLoop.instance().start()
+        finally:
+            term_manager.shutdown()
+
+See the `demos directory 
<https://github.com/takluyver/terminado/tree/master/demos>`_
+for more examples. This is a simplified version of the ``single.py`` demo.
+
+Run the unit tests with:
+
+    $ pytest
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/terminado-0.9.5/setup.py 
new/terminado-0.12.1/setup.py
--- old/terminado-0.9.5/setup.py        2021-05-11 13:35:48.000000000 +0200
+++ new/terminado-0.12.1/setup.py       2021-05-18 11:41:39.000000000 +0200
@@ -21,7 +21,7 @@
     long_description_content_type="text/x-rst",
     install_requires = [
         "ptyprocess;os_name!='nt'",
-        "pywinpty (>=0.5,<1);os_name=='nt'",
+        "pywinpty (>=1.1.0);os_name=='nt'",
         "tornado (>=4)",
     ],
     extras_require = dict(test=['pytest']),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/terminado-0.9.5/terminado/__init__.py 
new/terminado-0.12.1/terminado/__init__.py
--- old/terminado-0.9.5/terminado/__init__.py   2021-05-11 13:40:05.000000000 
+0200
+++ new/terminado-0.12.1/terminado/__init__.py  2021-09-07 16:32:30.000000000 
+0200
@@ -12,4 +12,4 @@
 # Prevent a warning about no attached handlers in Python 2
 logging.getLogger(__name__).addHandler(logging.NullHandler())
 
-__version__ = '0.9.5'
+__version__ = '0.12.1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/terminado-0.9.5/terminado/management.py 
new/terminado-0.12.1/terminado/management.py
--- old/terminado-0.9.5/terminado/management.py 2021-03-29 17:41:42.000000000 
+0200
+++ new/terminado-0.12.1/terminado/management.py        2021-09-07 
16:32:20.000000000 +0200
@@ -6,19 +6,15 @@
 
 from __future__ import absolute_import, print_function
 
-import sys
-if sys.version_info[0] < 3:
-    byte_code = ord
-else:
-    def byte_code(x): return x
-    unicode = str
-
+import asyncio
 from collections import deque
 import itertools
 import logging
 import os
 import signal
 import codecs
+import warnings
+import select
 
 try:
     from ptyprocess import PtyProcessUnicode
@@ -28,12 +24,12 @@
     from winpty import PtyProcess as PtyProcessUnicode
     preexec_fn = None
 
-from tornado import gen
 from tornado.ioloop import IOLoop
 
 ENV_PREFIX = "PYXTERM_"         # Environment variable prefix
 
-DEFAULT_TERM_TYPE = "xterm"
+# TERM is set according to xterm.js capabilities
+DEFAULT_TERM_TYPE = "xterm-256color"
 
 
 class PtyWithClients(object):
@@ -60,7 +56,7 @@
         """Set the terminal size to that of the smallest client dimensions.
 
         A terminal not using the full space available is much nicer than a
-        terminal trying to use more than the available space, so we keep it 
+        terminal trying to use more than the available space, so we keep it
         sized to the smallest client.
         """
         minrows = mincols = 10001
@@ -89,8 +85,7 @@
         pgid = os.getpgid(self.ptyproc.pid)
         os.killpg(pgid, sig)
 
-    @gen.coroutine
-    def terminate(self, force=False):
+    async def terminate(self, force=False):
         '''This forces a child process to terminate. It starts nicely with
         SIGHUP and SIGINT. If "force" is True then moves onto SIGKILL. This
         returns True if the child was terminated. This returns False if the
@@ -102,34 +97,34 @@
                        signal.SIGTERM]
 
         loop = IOLoop.current()
-        def sleep(): return gen.sleep(self.ptyproc.delayafterterminate)
+        def sleep(): return asyncio.sleep(self.ptyproc.delayafterterminate)
 
         if not self.ptyproc.isalive():
-            raise gen.Return(True)
+            return True
         try:
             for sig in signals:
                 self.kill(sig)
-                yield sleep()
+                await sleep()
                 if not self.ptyproc.isalive():
-                    raise gen.Return(True)
+                    return True
             if force:
                 self.kill(signal.SIGKILL)
-                yield sleep()
+                await sleep()
                 if not self.ptyproc.isalive():
-                    raise gen.Return(True)
+                    return True
                 else:
-                    raise gen.Return(False)
-            raise gen.Return(False)
+                    return False
+            return False
         except OSError:
             # I think there are kernel timing issues that sometimes cause
             # this to happen. I think isalive() reports True, but the
             # process is dead to the kernel.
             # Make one last attempt to see if the kernel is up to date.
-            yield sleep()
+            await sleep()
             if not self.ptyproc.isalive():
-                raise gen.Return(True)
+                return True
             else:
-                raise gen.Return(False)
+                return False
 
 
 def _update_removing(target, changes):
@@ -142,6 +137,19 @@
             target[k] = v
 
 
+def _poll(fd, timeout: float = 0.1):
+    """Poll using poll() on posix systems and select() elsewhere (e.g., 
Windows)
+    """
+    if os.name == "posix":
+        poller = select.poll()  # noqa: ignore missing method on Windows
+        poller.register(fd, select.POLLIN | select.POLLPRI | select.POLLHUP | 
select.POLLERR)  # read-only
+        return poller.poll(timeout * 1000)  # milliseconds
+    else:
+        # poll() not supported on Windows
+        r, _, _ = select.select([fd], [], [], timeout)
+        return r
+
+
 class TermManagerBase(object):
     """Base class for a terminal manager."""
 
@@ -156,14 +164,17 @@
         self.ptys_by_fd = {}
 
         if ioloop is not None:
-            self.ioloop = ioloop
-        else:
-            import tornado.ioloop
-            self.ioloop = tornado.ioloop.IOLoop.instance()
+            warnings.warn(
+                f"Setting {self.__class__.__name__}.ioloop is deprecated and 
ignored",
+                DeprecationWarning,
+                stacklevel=2,
+            )
 
     def make_term_env(self, height=25, width=80, winheight=0, winwidth=0, 
**kwargs):
         """Build the environment variables for the process in the terminal."""
         env = os.environ.copy()
+        # ignore any previously set TERM
+        # TERM is set according to xterm.js capabilities
         env["TERM"] = self.term_settings.get("type", DEFAULT_TERM_TYPE)
         dimensions = "%dx%d" % (width, height)
         if winwidth and winheight:
@@ -194,7 +205,8 @@
         """Connect a terminal to the tornado event loop to read data from 
it."""
         fd = ptywclients.ptyproc.fd
         self.ptys_by_fd[fd] = ptywclients
-        self.ioloop.add_handler(fd, self.pty_read, self.ioloop.READ)
+        loop = IOLoop.current()
+        loop.add_handler(fd, self.pty_read, loop.READ)
 
     def on_eof(self, ptywclients):
         """Called when the pty has closed.
@@ -203,13 +215,17 @@
         fd = ptywclients.ptyproc.fd
         self.log.info("EOF on FD %d; stopping reading", fd)
         del self.ptys_by_fd[fd]
-        self.ioloop.remove_handler(fd)
+        IOLoop.current().remove_handler(fd)
 
         # This closes the fd, and should result in the process being reaped.
         ptywclients.ptyproc.close()
 
     def pty_read(self, fd, events=None):
         """Called by the event loop when there is pty data ready to read."""
+        # prevent blocking on fd
+        if not _poll(fd, timeout=0.1):  # 100ms
+            self.log.debug(f"Spurious pty_read() on fd {fd}")
+            return
         ptywclients = self.ptys_by_fd[fd]
         try:
             s = ptywclients.ptyproc.read(65536)
@@ -240,18 +256,16 @@
         """
         pass
 
-    @gen.coroutine
-    def shutdown(self):
-        yield self.kill_all()
+    async def shutdown(self):
+        await self.kill_all()
 
-    @gen.coroutine
-    def kill_all(self):
+    async def kill_all(self):
         futures = []
         for term in self.ptys_by_fd.values():
             futures.append(term.terminate(force=True))
         # wait for futures to finish
-        for f in futures:
-            yield f
+        if futures:
+            await asyncio.gather(*futures)
 
 
 class SingleTermManager(TermManagerBase):
@@ -267,9 +281,8 @@
             self.start_reading(self.terminal)
         return self.terminal
 
-    @gen.coroutine
-    def kill_all(self):
-        yield super(SingleTermManager, self).kill_all()
+    async def kill_all(self):
+        await super().kill_all()
         self.terminal = None
 
 
@@ -344,7 +357,10 @@
                 return name
 
     def new_named_terminal(self, **kwargs):
-        name = self._next_available_name()
+        if 'name' in kwargs:
+            name = kwargs['name']
+        else:
+            name = self._next_available_name()
         term = self.new_terminal(**kwargs)
         self.log.info("New terminal with automatic name: %s", name)
         term.term_name = name
@@ -356,10 +372,9 @@
         term = self.terminals[name]
         term.kill(sig)   # This should lead to an EOF
 
-    @gen.coroutine
-    def terminate(self, name, force=False):
+    async def terminate(self, name, force=False):
         term = self.terminals[name]
-        yield term.terminate(force=force)
+        await term.terminate(force=force)
 
     def on_eof(self, ptywclients):
         super(NamedTermManager, self).on_eof(ptywclients)
@@ -367,7 +382,6 @@
         self.log.info("Terminal %s closed", name)
         self.terminals.pop(name, None)
 
-    @gen.coroutine
-    def kill_all(self):
-        yield super(NamedTermManager, self).kill_all()
+    async def kill_all(self):
+        await super().kill_all()
         self.terminals = {}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/terminado-0.9.5/terminado/tests/basic_test.py 
new/terminado-0.12.1/terminado/tests/basic_test.py
--- old/terminado-0.9.5/terminado/tests/basic_test.py   2021-03-19 
18:57:45.000000000 +0100
+++ new/terminado-0.12.1/terminado/tests/basic_test.py  2021-09-07 
11:21:15.000000000 +0200
@@ -19,6 +19,8 @@
 import os
 import re
 import signal
+import pytest
+from sys import platform
 
 # We must set the policy for python >=3.8, see 
https://www.tornadoweb.org/en/stable/#installation
 # Snippet from 
https://github.com/tornadoweb/tornado/issues/2608#issuecomment-619524992
@@ -41,111 +43,116 @@
         self.ws = websocket
         self.pending_read = None
 
-    @tornado.gen.coroutine
-    def read_msg(self):
+    async def read_msg(self):
 
         # Because the Tornado Websocket client has no way to cancel
         # a pending read, we have to keep track of them...
         if self.pending_read is None:
             self.pending_read = self.ws.read_message()
 
-        response = yield self.pending_read
+        response = await self.pending_read
         self.pending_read = None
         if response:
             response = json.loads(response)
-        raise tornado.gen.Return(response)
+        return response
 
-    @tornado.gen.coroutine
-    def read_all_msg(self, timeout=DONE_TIMEOUT):
+    async def read_all_msg(self, timeout=DONE_TIMEOUT):
         """Read messages until read times out"""
         msglist = []
         delta = datetime.timedelta(seconds=timeout)
         while True:
             try:
                 mf = self.read_msg()
-                msg = yield tornado.gen.with_timeout(delta, mf)
+                msg = await tornado.gen.with_timeout(delta, mf)
             except tornado.gen.TimeoutError:
-                raise tornado.gen.Return(msglist)
+                return msglist
 
             msglist.append(msg)
 
-    def write_msg(self, msg):
-        self.ws.write_message(json.dumps(msg))
+    async def write_msg(self, msg):
+        await self.ws.write_message(json.dumps(msg))
 
-    @tornado.gen.coroutine
-    def read_stdout(self, timeout=DONE_TIMEOUT):
+    async def read_stdout(self, timeout=DONE_TIMEOUT):
         """Read standard output until timeout read reached,
            return stdout and any non-stdout msgs received."""
-        msglist = yield self.read_all_msg(timeout)
+        msglist = await self.read_all_msg(timeout)
         stdout = "".join([msg[1] for msg in msglist if msg[0] == 'stdout'])
         othermsg = [msg for msg in msglist if msg[0] != 'stdout']
-        raise tornado.gen.Return((stdout, othermsg))
+        return (stdout, othermsg)
 
-    def write_stdin(self, data):
+    async def write_stdin(self, data):
         """Write to terminal stdin"""
-        self.write_msg(['stdin', data])
+        await self.write_msg(['stdin', data])
 
-    @tornado.gen.coroutine
-    def get_pid(self):
+    async def get_pid(self):
         """Get process ID of terminal shell process"""
-        yield self.read_stdout()                          # Clear out any 
pending
-        self.write_stdin("echo $$\r")
-        (stdout, extra) = yield self.read_stdout()
+        await self.read_stdout()                          # Clear out any 
pending
+        await self.write_stdin("echo $$\r")
+        (stdout, extra) = await self.read_stdout()
         if os.name == 'nt':
-            match = re.search(r'echo \$\$\x1b\[0K\r\n(\d+)', stdout)
+            print(repr(stdout))
+            match = re.search(r'echo \$\$\\x1b\[71X\\x1b\[71C\\r\\n(\d+)', 
repr(stdout))
+            if match is None:
+                match = re.search(r'echo \$\$ \\r\\n(\d+)', repr(stdout))
+            if match is None:
+                match = re.search(
+                    r'echo \$\$ \\r\\n\\x1b\[\?25h\\x1b\[\?25l(\d+)',
+                    repr(stdout))
             pid = int(match.groups()[0])
         else:
+            print('stdout=%r, extra=%r' % (stdout, extra))
             pid = int(stdout.split('\n')[1])
-        raise tornado.gen.Return(pid)
+        return pid
 
     def close(self):
         self.ws.close()
 
 class TermTestCase(tornado.testing.AsyncHTTPTestCase):
 
-    # Factory for TestTermClient, because it has to be a Tornado co-routine.
+    # Factory for TestTermClient, because it has to be async
     # See:  https://github.com/tornadoweb/tornado/issues/1161
-    @tornado.gen.coroutine
-    def get_term_client(self, path):
+    async def get_term_client(self, path):
         port = self.get_http_port()
         url = 'ws://127.0.0.1:%d%s' % (port, path)
         request = tornado.httpclient.HTTPRequest(url,
                     headers={'Origin' : 'http://127.0.0.1:%d' % port})
 
-        ws = yield tornado.websocket.websocket_connect(request)
-        raise tornado.gen.Return(TestTermClient(ws))
+        ws = await tornado.websocket.websocket_connect(request)
+        return TestTermClient(ws)
 
-    @tornado.gen.coroutine
-    def get_term_clients(self, paths):
-        tms = yield [self.get_term_client(path) for path in paths]
-        raise tornado.gen.Return(tms)
+    async def get_term_clients(self, paths):
+        return await asyncio.gather(*(self.get_term_client(path) for path in 
paths))
 
-    @tornado.gen.coroutine
-    def get_pids(self, tm_list):
+    async def get_pids(self, tm_list):
         pids = []
-        for tm in tm_list:                  # Must be sequential, in case 
terms are shared
-            pid = yield tm.get_pid()
+        for tm in tm_list: # Must be sequential, in case terms are shared
+            pid = await tm.get_pid()
             pids.append(pid)
 
-        raise tornado.gen.Return(pids)
+        return pids
 
     def tearDown(self):
-        self.named_tm.kill_all()
-        self.single_tm.kill_all()
-        self.unique_tm.kill_all()
+        run = IOLoop.current().run_sync
+        run(self.named_tm.kill_all)
+        run(self.single_tm.kill_all)
+        run(self.unique_tm.kill_all)
         super().tearDown()
 
     def get_app(self):
-        self.named_tm = NamedTermManager(shell_command=['bash'], 
-                                            max_terminals=MAX_TERMS,
-                                            ioloop=self.io_loop)
-        self.single_tm = SingleTermManager(shell_command=['bash'], 
-                                            ioloop=self.io_loop)
-        self.unique_tm = UniqueTermManager(shell_command=['bash'], 
-                                            max_terminals=MAX_TERMS,
-                                            ioloop=self.io_loop)
+        self.named_tm = NamedTermManager(
+            shell_command=['bash'],
+            max_terminals=MAX_TERMS,
+        )
         
+        self.single_tm = SingleTermManager(shell_command=['bash'])
+        
+        self.unique_tm = UniqueTermManager(
+            shell_command=['bash'],
+            max_terminals=MAX_TERMS,
+        )
+
         named_tm = self.named_tm
+        
         class NewTerminalHandler(tornado.web.RequestHandler):
             """Create a new named terminal, return redirect"""
             def get(self):
@@ -159,29 +166,29 @@
                     (r"/unique",      TermSocket, {'term_manager': 
self.unique_tm})
                 ], debug=True)
 
-    test_urls = ('/named/term1', '/unique', '/single')
+    test_urls = ('/named/term1', '/unique') + (('/single',) if os.name != 'nt' 
else tuple())
 
 class CommonTests(TermTestCase):
     @tornado.testing.gen_test
-    def test_basic(self):
+    async def test_basic(self):
         for url in self.test_urls:
-            tm = yield self.get_term_client(url)
-            response = yield tm.read_msg()                    
+            tm = await self.get_term_client(url)
+            response = await tm.read_msg()
             self.assertEqual(response, ['setup', {}])
 
             # Check for initial shell prompt
-            response = yield tm.read_msg()
+            response = await tm.read_msg()
             self.assertEqual(response[0], 'stdout')
             self.assertGreater(len(response[1]), 0)
-            tm.close()        
+            tm.close()
 
     @tornado.testing.gen_test
-    def test_basic_command(self):
+    async def test_basic_command(self):
         for url in self.test_urls:
-            tm = yield self.get_term_client(url)
-            yield tm.read_all_msg()
-            tm.write_stdin("whoami\n")
-            (stdout, other) = yield tm.read_stdout()
+            tm = await self.get_term_client(url)
+            await tm.read_all_msg()
+            await tm.write_stdin("whoami\n")
+            (stdout, other) = await tm.read_stdout()
             if os.name == 'nt':
                 assert 'whoami' in stdout
             else:
@@ -200,60 +207,62 @@
         self.assertIn(name, self.named_tm.terminals)
 
     @tornado.testing.gen_test
-    def test_namespace(self):
+    async def test_namespace(self):
         names = ["/named/1"]*2 + ["/named/2"]*2
-        tms = yield self.get_term_clients(names)
-        pids = yield self.get_pids(tms)
+        tms = await self.get_term_clients(names)
+        pids = await self.get_pids(tms)
 
         self.assertEqual(pids[0], pids[1])
         self.assertEqual(pids[2], pids[3])
         self.assertNotEqual(pids[0], pids[3])
 
     @tornado.testing.gen_test
-    def test_max_terminals(self):
+    @pytest.mark.skipif('linux' not in platform, reason='It only works on 
Linux')
+    async def test_max_terminals(self):
         urls = ["/named/%d" % i for i in range(MAX_TERMS+1)]
-        tms = yield self.get_term_clients(urls[:MAX_TERMS])
-        pids = yield self.get_pids(tms)
+        tms = await self.get_term_clients(urls[:MAX_TERMS])
+        pids = await self.get_pids(tms)
 
         # MAX_TERMS+1 should fail
-        tm = yield self.get_term_client(urls[MAX_TERMS])
-        msg = yield tm.read_msg()
+        tm = await self.get_term_client(urls[MAX_TERMS])
+        msg = await tm.read_msg()
         self.assertEqual(msg, None)             # Connection closed
 
 class SingleTermTests(TermTestCase):
     @tornado.testing.gen_test
-    def test_single_process(self):
-        tms = yield self.get_term_clients(["/single", "/single"])
-        pids = yield self.get_pids(tms)
+    async def test_single_process(self):
+        tms = await self.get_term_clients(["/single", "/single"])
+        pids = await self.get_pids(tms)
         self.assertEqual(pids[0], pids[1])
 
 class UniqueTermTests(TermTestCase):
     @tornado.testing.gen_test
-    def test_unique_processes(self):
-        tms = yield self.get_term_clients(["/unique", "/unique"])
-        pids = yield self.get_pids(tms)
+    async def test_unique_processes(self):
+        tms = await self.get_term_clients(["/unique", "/unique"])
+        pids = await self.get_pids(tms)
         self.assertNotEqual(pids[0], pids[1])
 
     @tornado.testing.gen_test
-    def test_max_terminals(self):
-        tms = yield self.get_term_clients(['/unique'] * MAX_TERMS)
-        pids = yield self.get_pids(tms)
+    @pytest.mark.skipif('linux' not in platform, reason='It only works on 
Linux')
+    async def test_max_terminals(self):
+        tms = await self.get_term_clients(['/unique'] * MAX_TERMS)
+        pids = await self.get_pids(tms)
         self.assertEqual(len(set(pids)), MAX_TERMS)        # All PIDs unique
 
         # MAX_TERMS+1 should fail
-        tm = yield self.get_term_client("/unique")
-        msg = yield tm.read_msg()
+        tm = await self.get_term_client("/unique")
+        msg = await tm.read_msg()
         self.assertEqual(msg, None)             # Connection closed
 
         # Close one
         tms[0].close()
-        msg = yield tms[0].read_msg()           # Closed
-        self.assertEquals(msg, None)
+        msg = await tms[0].read_msg()           # Closed
+        self.assertEqual(msg, None)
 
         # Should be able to open back up to MAX_TERMS
-        tm = yield self.get_term_client("/unique")
-        msg = yield tm.read_msg()
-        self.assertEquals(msg[0], 'setup')
+        tm = await self.get_term_client("/unique")
+        msg = await tm.read_msg()
+        self.assertEqual(msg[0], 'setup')
 
 if __name__ == '__main__':
     unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/terminado-0.9.5/terminado/websocket.py 
new/terminado-0.12.1/terminado/websocket.py
--- old/terminado-0.9.5/terminado/websocket.py  2021-03-19 18:57:45.000000000 
+0100
+++ new/terminado-0.12.1/terminado/websocket.py 2021-08-12 13:08:56.000000000 
+0200
@@ -7,6 +7,8 @@
 from __future__ import absolute_import, print_function
 
 # Python3-friendly imports
+import os
+
 try:
     from urllib.parse import urlparse
 except ImportError:
@@ -14,6 +16,7 @@
 
 import json
 import logging
+import re
 
 import tornado.web
 import tornado.websocket
@@ -35,6 +38,7 @@
         self.terminal = None
 
         self._logger = logging.getLogger(__name__)
+        self._user_command = ''
 
     def origin_check(self, origin=None):
         """Deprecated: backward-compat for terminado <= 0.5."""
@@ -74,6 +78,12 @@
 
     def send_json_message(self, content):
         json_msg = json.dumps(content)
+        pattern = re.compile(r'^(\w|\d)+')
+        try:
+            if pattern.search(content[1]):
+                self.log_terminal_output(f'STDOUT: {content[1]}')
+        except TypeError as e:
+            self._logger.error(f'not able to serialize: {e}')
         self.write_message(json_msg)
 
     def on_message(self, message):
@@ -88,6 +98,11 @@
 
         if msg_type == "stdin":
             self.terminal.ptyproc.write(command[1])
+            if command[1] == '\r':
+                self.log_terminal_output(f'STDIN: {self._user_command}')
+                self._user_command = ''
+            else:
+                self._user_command += command[1]
         elif msg_type == "set_size":
             self.size = command[1:3]
             self.terminal.resize_to_smallest()
@@ -110,3 +125,12 @@
         self.send_json_message(['disconnect', 1])
         self.close()
         self.terminal = None
+
+    def log_terminal_output(self, log: str = ''):
+        """
+        Logs the terminal input/output if the environment variable 
LOG_TERMINAL_OUTPUT is "true"
+        :param log: log line to write
+        :return:
+        """
+        if str.lower(os.getenv("LOG_TERMINAL_OUTPUT", "false")) == "true":
+            self._logger.debug(log)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/terminado-0.9.5/terminado.egg-info/PKG-INFO 
new/terminado-0.12.1/terminado.egg-info/PKG-INFO
--- old/terminado-0.9.5/terminado.egg-info/PKG-INFO     2021-05-11 
13:40:15.000000000 +0200
+++ new/terminado-0.12.1/terminado.egg-info/PKG-INFO    2021-09-07 
16:32:39.000000000 +0200
@@ -1,86 +1,11 @@
 Metadata-Version: 2.1
 Name: terminado
-Version: 0.9.5
+Version: 0.12.1
 Summary: Tornado websocket backend for the Xterm.js Javascript terminal 
emulator library.
 Home-page: https://github.com/jupyter/terminado
 Author: Jupyter Development Team
 Author-email: jupy...@googlegroups.com
 License: UNKNOWN
-Description: This is a `Tornado <http://tornadoweb.org/>`_ websocket backend 
for the
-        `Xterm.js <https://xtermjs.org/>`_ Javascript terminal emulator
-        library.
-        
-        It evolved out of `pyxterm <https://github.com/mitotic/pyxterm>`_, 
which was
-        part of `GraphTerm <https://github.com/mitotic/graphterm>`_ (as 
lineterm.py),
-        v0.57.0 (2014-07-18), and ultimately derived from the public-domain 
`Ajaxterm
-        <http://antony.lesuisse.org/software/ajaxterm/>`_ code, v0.11 
(2008-11-13) (also
-        on Github as part of `QWeb <https://github.com/antonylesuisse/qweb>`_).
-        
-        Modules:
-        
-        * ``terminado.management``: controls launching virtual terminals,
-          connecting them to Tornado's event loop, and closing them down.
-        * ``terminado.websocket``: Provides a websocket handler for 
communicating with
-          a terminal.
-        * ``terminado.uimodule``: Provides a ``Terminal`` Tornado `UI Module
-          
<http://www.tornadoweb.org/en/stable/guide/templates.html#ui-modules>`_.
-        
-        JS:
-        
-        * ``terminado/_static/terminado.js``: A lightweight wrapper to set up a
-          term.js terminal with a websocket.
-        
-        Local Installation:
-        
-            $ pip install -e .[test]
-        
-        
-        Usage example:
-        
-        .. code:: python
-        
-            import os.path
-            import tornado.web
-            import tornado.ioloop
-            # This demo requires tornado_xstatic and XStatic-term.js
-            import tornado_xstatic
-        
-            import terminado
-            STATIC_DIR = os.path.join(os.path.dirname(terminado.__file__), 
"_static")
-        
-            class TerminalPageHandler(tornado.web.RequestHandler):
-                def get(self):
-                    return self.render("termpage.html", static=self.static_url,
-                                       
xstatic=self.application.settings['xstatic_url'],
-                                       ws_url_path="/websocket")
-        
-            if __name__ == '__main__':
-                term_manager = 
terminado.SingleTermManager(shell_command=['bash'])
-                handlers = [
-                            (r"/websocket", terminado.TermSocket,
-                                 {'term_manager': term_manager}),
-                            (r"/", TerminalPageHandler),
-                            (r"/xstatic/(.*)", 
tornado_xstatic.XStaticFileHandler,
-                                 {'allowed_modules': ['termjs']})
-                           ]
-                app = tornado.web.Application(handlers, static_path=STATIC_DIR,
-                                  xstatic_url = 
tornado_xstatic.url_maker('/xstatic/'))
-                # Serve at http://localhost:8765/ N.B. Leaving out 'localhost' 
here will
-                # work, but it will listen on the public network interface as 
well.
-                # Given what terminado does, that would be rather a security 
hole.
-                app.listen(8765, 'localhost')
-                try:
-                    tornado.ioloop.IOLoop.instance().start()
-                finally:
-                    term_manager.shutdown()
-        
-        See the `demos directory 
<https://github.com/takluyver/terminado/tree/master/demos>`_
-        for more examples. This is a simplified version of the ``single.py`` 
demo.
-        
-        Run the unit tests with:
-        
-            $ pytest
-        
 Platform: UNKNOWN
 Classifier: Environment :: Web Environment
 Classifier: License :: OSI Approved :: BSD License
@@ -90,3 +15,81 @@
 Requires-Python: >=3.6
 Description-Content-Type: text/x-rst
 Provides-Extra: test
+License-File: LICENSE
+
+This is a `Tornado <http://tornadoweb.org/>`_ websocket backend for the
+`Xterm.js <https://xtermjs.org/>`_ Javascript terminal emulator
+library.
+
+It evolved out of `pyxterm <https://github.com/mitotic/pyxterm>`_, which was
+part of `GraphTerm <https://github.com/mitotic/graphterm>`_ (as lineterm.py),
+v0.57.0 (2014-07-18), and ultimately derived from the public-domain `Ajaxterm
+<http://antony.lesuisse.org/software/ajaxterm/>`_ code, v0.11 (2008-11-13) 
(also
+on Github as part of `QWeb <https://github.com/antonylesuisse/qweb>`_).
+
+Modules:
+
+* ``terminado.management``: controls launching virtual terminals,
+  connecting them to Tornado's event loop, and closing them down.
+* ``terminado.websocket``: Provides a websocket handler for communicating with
+  a terminal.
+* ``terminado.uimodule``: Provides a ``Terminal`` Tornado `UI Module
+  <http://www.tornadoweb.org/en/stable/guide/templates.html#ui-modules>`_.
+
+JS:
+
+* ``terminado/_static/terminado.js``: A lightweight wrapper to set up a
+  term.js terminal with a websocket.
+
+Local Installation:
+
+    $ pip install -e .[test]
+
+
+Usage example:
+
+.. code:: python
+
+    import os.path
+    import tornado.web
+    import tornado.ioloop
+    # This demo requires tornado_xstatic and XStatic-term.js
+    import tornado_xstatic
+
+    import terminado
+    STATIC_DIR = os.path.join(os.path.dirname(terminado.__file__), "_static")
+
+    class TerminalPageHandler(tornado.web.RequestHandler):
+        def get(self):
+            return self.render("termpage.html", static=self.static_url,
+                               
xstatic=self.application.settings['xstatic_url'],
+                               ws_url_path="/websocket")
+
+    if __name__ == '__main__':
+        term_manager = terminado.SingleTermManager(shell_command=['bash'])
+        handlers = [
+                    (r"/websocket", terminado.TermSocket,
+                         {'term_manager': term_manager}),
+                    (r"/", TerminalPageHandler),
+                    (r"/xstatic/(.*)", tornado_xstatic.XStaticFileHandler,
+                         {'allowed_modules': ['termjs']})
+                   ]
+        app = tornado.web.Application(handlers, static_path=STATIC_DIR,
+                          xstatic_url = tornado_xstatic.url_maker('/xstatic/'))
+        # Serve at http://localhost:8765/ N.B. Leaving out 'localhost' here 
will
+        # work, but it will listen on the public network interface as well.
+        # Given what terminado does, that would be rather a security hole.
+        app.listen(8765, 'localhost')
+        try:
+            tornado.ioloop.IOLoop.instance().start()
+        finally:
+            term_manager.shutdown()
+
+See the `demos directory 
<https://github.com/takluyver/terminado/tree/master/demos>`_
+for more examples. This is a simplified version of the ``single.py`` demo.
+
+Run the unit tests with:
+
+    $ pytest
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/terminado-0.9.5/terminado.egg-info/requires.txt 
new/terminado-0.12.1/terminado.egg-info/requires.txt
--- old/terminado-0.9.5/terminado.egg-info/requires.txt 2021-05-11 
13:40:15.000000000 +0200
+++ new/terminado-0.12.1/terminado.egg-info/requires.txt        2021-09-07 
16:32:39.000000000 +0200
@@ -4,7 +4,7 @@
 ptyprocess
 
 [:os_name == "nt"]
-pywinpty<1,>=0.5
+pywinpty>=1.1.0
 
 [test]
 pytest

Reply via email to