summaryrefslogtreecommitdiffstats
path: root/contrib/python/pexpect
diff options
context:
space:
mode:
authorMikhail Borisov <[email protected]>2022-02-10 16:45:39 +0300
committerDaniil Cherednik <[email protected]>2022-02-10 16:45:39 +0300
commita6a92afe03e02795227d2641b49819b687f088f8 (patch)
treef6984a1d27d5a7ec88a6fdd6e20cd5b7693b6ece /contrib/python/pexpect
parentc6dc8b8bd530985bc4cce0137e9a5de32f1087cb (diff)
Restoring authorship annotation for Mikhail Borisov <[email protected]>. Commit 1 of 2.
Diffstat (limited to 'contrib/python/pexpect')
-rw-r--r--contrib/python/pexpect/LICENSE30
-rw-r--r--contrib/python/pexpect/pexpect/ANSI.py702
-rw-r--r--contrib/python/pexpect/pexpect/FSM.py668
-rw-r--r--contrib/python/pexpect/pexpect/__init__.py168
-rw-r--r--contrib/python/pexpect/pexpect/_async.py114
-rw-r--r--contrib/python/pexpect/pexpect/exceptions.py70
-rw-r--r--contrib/python/pexpect/pexpect/expect.py508
-rw-r--r--contrib/python/pexpect/pexpect/fdpexpect.py212
-rw-r--r--contrib/python/pexpect/pexpect/popen_spawn.py332
-rw-r--r--contrib/python/pexpect/pexpect/pty_spawn.py1446
-rw-r--r--contrib/python/pexpect/pexpect/pxssh.py754
-rw-r--r--contrib/python/pexpect/pexpect/replwrap.py218
-rw-r--r--contrib/python/pexpect/pexpect/run.py312
-rw-r--r--contrib/python/pexpect/pexpect/screen.py858
-rw-r--r--contrib/python/pexpect/pexpect/spawnbase.py940
-rw-r--r--contrib/python/pexpect/pexpect/utils.py216
-rw-r--r--contrib/python/pexpect/ya.make46
17 files changed, 3797 insertions, 3797 deletions
diff --git a/contrib/python/pexpect/LICENSE b/contrib/python/pexpect/LICENSE
index 754db5afcb8..11f4b1686f4 100644
--- a/contrib/python/pexpect/LICENSE
+++ b/contrib/python/pexpect/LICENSE
@@ -1,20 +1,20 @@
ISC LICENSE
-
- This license is approved by the OSI and FSF as GPL-compatible.
- http://opensource.org/licenses/isc-license.txt
-
- Copyright (c) 2013-2014, Pexpect development team
- Copyright (c) 2012, Noah Spurrier <[email protected]>
-
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2013-2014, Pexpect development team
+ Copyright (c) 2012, Noah Spurrier <[email protected]>
+
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
diff --git a/contrib/python/pexpect/pexpect/ANSI.py b/contrib/python/pexpect/pexpect/ANSI.py
index 1cd2e90e7ab..50bd7732f7f 100644
--- a/contrib/python/pexpect/pexpect/ANSI.py
+++ b/contrib/python/pexpect/pexpect/ANSI.py
@@ -1,351 +1,351 @@
-'''This implements an ANSI (VT100) terminal emulator as a subclass of screen.
-
-PEXPECT LICENSE
-
- This license is approved by the OSI and FSF as GPL-compatible.
- http://opensource.org/licenses/isc-license.txt
-
- Copyright (c) 2012, Noah Spurrier <[email protected]>
- PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
- PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
- COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-'''
-
-# references:
-# http://en.wikipedia.org/wiki/ANSI_escape_code
-# http://www.retards.org/terminals/vt102.html
-# http://vt100.net/docs/vt102-ug/contents.html
-# http://vt100.net/docs/vt220-rm/
-# http://www.termsys.demon.co.uk/vtansi.htm
-
-from . import screen
-from . import FSM
-import string
-
-#
-# The 'Do.*' functions are helper functions for the ANSI class.
-#
-def DoEmit (fsm):
-
- screen = fsm.memory[0]
- screen.write_ch(fsm.input_symbol)
-
-def DoStartNumber (fsm):
-
- fsm.memory.append (fsm.input_symbol)
-
-def DoBuildNumber (fsm):
-
- ns = fsm.memory.pop()
- ns = ns + fsm.input_symbol
- fsm.memory.append (ns)
-
-def DoBackOne (fsm):
-
- screen = fsm.memory[0]
- screen.cursor_back ()
-
-def DoBack (fsm):
-
- count = int(fsm.memory.pop())
- screen = fsm.memory[0]
- screen.cursor_back (count)
-
-def DoDownOne (fsm):
-
- screen = fsm.memory[0]
- screen.cursor_down ()
-
-def DoDown (fsm):
-
- count = int(fsm.memory.pop())
- screen = fsm.memory[0]
- screen.cursor_down (count)
-
-def DoForwardOne (fsm):
-
- screen = fsm.memory[0]
- screen.cursor_forward ()
-
-def DoForward (fsm):
-
- count = int(fsm.memory.pop())
- screen = fsm.memory[0]
- screen.cursor_forward (count)
-
-def DoUpReverse (fsm):
-
- screen = fsm.memory[0]
- screen.cursor_up_reverse()
-
-def DoUpOne (fsm):
-
- screen = fsm.memory[0]
- screen.cursor_up ()
-
-def DoUp (fsm):
-
- count = int(fsm.memory.pop())
- screen = fsm.memory[0]
- screen.cursor_up (count)
-
-def DoHome (fsm):
-
- c = int(fsm.memory.pop())
- r = int(fsm.memory.pop())
- screen = fsm.memory[0]
- screen.cursor_home (r,c)
-
-def DoHomeOrigin (fsm):
-
- c = 1
- r = 1
- screen = fsm.memory[0]
- screen.cursor_home (r,c)
-
-def DoEraseDown (fsm):
-
- screen = fsm.memory[0]
- screen.erase_down()
-
-def DoErase (fsm):
-
- arg = int(fsm.memory.pop())
- screen = fsm.memory[0]
- if arg == 0:
- screen.erase_down()
- elif arg == 1:
- screen.erase_up()
- elif arg == 2:
- screen.erase_screen()
-
-def DoEraseEndOfLine (fsm):
-
- screen = fsm.memory[0]
- screen.erase_end_of_line()
-
-def DoEraseLine (fsm):
-
- arg = int(fsm.memory.pop())
- screen = fsm.memory[0]
- if arg == 0:
- screen.erase_end_of_line()
- elif arg == 1:
- screen.erase_start_of_line()
- elif arg == 2:
- screen.erase_line()
-
-def DoEnableScroll (fsm):
-
- screen = fsm.memory[0]
- screen.scroll_screen()
-
-def DoCursorSave (fsm):
-
- screen = fsm.memory[0]
- screen.cursor_save_attrs()
-
-def DoCursorRestore (fsm):
-
- screen = fsm.memory[0]
- screen.cursor_restore_attrs()
-
-def DoScrollRegion (fsm):
-
- screen = fsm.memory[0]
- r2 = int(fsm.memory.pop())
- r1 = int(fsm.memory.pop())
- screen.scroll_screen_rows (r1,r2)
-
-def DoMode (fsm):
-
- screen = fsm.memory[0]
- mode = fsm.memory.pop() # Should be 4
- # screen.setReplaceMode ()
-
-def DoLog (fsm):
-
- screen = fsm.memory[0]
- fsm.memory = [screen]
- fout = open ('log', 'a')
- fout.write (fsm.input_symbol + ',' + fsm.current_state + '\n')
- fout.close()
-
-class term (screen.screen):
-
- '''This class is an abstract, generic terminal.
- This does nothing. This is a placeholder that
- provides a common base class for other terminals
- such as an ANSI terminal. '''
-
- def __init__ (self, r=24, c=80, *args, **kwargs):
-
- screen.screen.__init__(self, r,c,*args,**kwargs)
-
-class ANSI (term):
- '''This class implements an ANSI (VT100) terminal.
- It is a stream filter that recognizes ANSI terminal
- escape sequences and maintains the state of a screen object. '''
-
- def __init__ (self, r=24,c=80,*args,**kwargs):
-
- term.__init__(self,r,c,*args,**kwargs)
-
- #self.screen = screen (24,80)
- self.state = FSM.FSM ('INIT',[self])
- self.state.set_default_transition (DoLog, 'INIT')
- self.state.add_transition_any ('INIT', DoEmit, 'INIT')
- self.state.add_transition ('\x1b', 'INIT', None, 'ESC')
- self.state.add_transition_any ('ESC', DoLog, 'INIT')
- self.state.add_transition ('(', 'ESC', None, 'G0SCS')
- self.state.add_transition (')', 'ESC', None, 'G1SCS')
- self.state.add_transition_list ('AB012', 'G0SCS', None, 'INIT')
- self.state.add_transition_list ('AB012', 'G1SCS', None, 'INIT')
- self.state.add_transition ('7', 'ESC', DoCursorSave, 'INIT')
- self.state.add_transition ('8', 'ESC', DoCursorRestore, 'INIT')
- self.state.add_transition ('M', 'ESC', DoUpReverse, 'INIT')
- self.state.add_transition ('>', 'ESC', DoUpReverse, 'INIT')
- self.state.add_transition ('<', 'ESC', DoUpReverse, 'INIT')
- self.state.add_transition ('=', 'ESC', None, 'INIT') # Selects application keypad.
- self.state.add_transition ('#', 'ESC', None, 'GRAPHICS_POUND')
- self.state.add_transition_any ('GRAPHICS_POUND', None, 'INIT')
- self.state.add_transition ('[', 'ESC', None, 'ELB')
- # ELB means Escape Left Bracket. That is ^[[
- self.state.add_transition ('H', 'ELB', DoHomeOrigin, 'INIT')
- self.state.add_transition ('D', 'ELB', DoBackOne, 'INIT')
- self.state.add_transition ('B', 'ELB', DoDownOne, 'INIT')
- self.state.add_transition ('C', 'ELB', DoForwardOne, 'INIT')
- self.state.add_transition ('A', 'ELB', DoUpOne, 'INIT')
- self.state.add_transition ('J', 'ELB', DoEraseDown, 'INIT')
- self.state.add_transition ('K', 'ELB', DoEraseEndOfLine, 'INIT')
- self.state.add_transition ('r', 'ELB', DoEnableScroll, 'INIT')
- self.state.add_transition ('m', 'ELB', self.do_sgr, 'INIT')
- self.state.add_transition ('?', 'ELB', None, 'MODECRAP')
- self.state.add_transition_list (string.digits, 'ELB', DoStartNumber, 'NUMBER_1')
- self.state.add_transition_list (string.digits, 'NUMBER_1', DoBuildNumber, 'NUMBER_1')
- self.state.add_transition ('D', 'NUMBER_1', DoBack, 'INIT')
- self.state.add_transition ('B', 'NUMBER_1', DoDown, 'INIT')
- self.state.add_transition ('C', 'NUMBER_1', DoForward, 'INIT')
- self.state.add_transition ('A', 'NUMBER_1', DoUp, 'INIT')
- self.state.add_transition ('J', 'NUMBER_1', DoErase, 'INIT')
- self.state.add_transition ('K', 'NUMBER_1', DoEraseLine, 'INIT')
- self.state.add_transition ('l', 'NUMBER_1', DoMode, 'INIT')
- ### It gets worse... the 'm' code can have infinite number of
- ### number;number;number before it. I've never seen more than two,
- ### but the specs say it's allowed. crap!
- self.state.add_transition ('m', 'NUMBER_1', self.do_sgr, 'INIT')
- ### LED control. Same implementation problem as 'm' code.
- self.state.add_transition ('q', 'NUMBER_1', self.do_decsca, 'INIT')
-
- # \E[?47h switch to alternate screen
- # \E[?47l restores to normal screen from alternate screen.
- self.state.add_transition_list (string.digits, 'MODECRAP', DoStartNumber, 'MODECRAP_NUM')
- self.state.add_transition_list (string.digits, 'MODECRAP_NUM', DoBuildNumber, 'MODECRAP_NUM')
- self.state.add_transition ('l', 'MODECRAP_NUM', self.do_modecrap, 'INIT')
- self.state.add_transition ('h', 'MODECRAP_NUM', self.do_modecrap, 'INIT')
-
-#RM Reset Mode Esc [ Ps l none
- self.state.add_transition (';', 'NUMBER_1', None, 'SEMICOLON')
- self.state.add_transition_any ('SEMICOLON', DoLog, 'INIT')
- self.state.add_transition_list (string.digits, 'SEMICOLON', DoStartNumber, 'NUMBER_2')
- self.state.add_transition_list (string.digits, 'NUMBER_2', DoBuildNumber, 'NUMBER_2')
- self.state.add_transition_any ('NUMBER_2', DoLog, 'INIT')
- self.state.add_transition ('H', 'NUMBER_2', DoHome, 'INIT')
- self.state.add_transition ('f', 'NUMBER_2', DoHome, 'INIT')
- self.state.add_transition ('r', 'NUMBER_2', DoScrollRegion, 'INIT')
- ### It gets worse... the 'm' code can have infinite number of
- ### number;number;number before it. I've never seen more than two,
- ### but the specs say it's allowed. crap!
- self.state.add_transition ('m', 'NUMBER_2', self.do_sgr, 'INIT')
- ### LED control. Same problem as 'm' code.
- self.state.add_transition ('q', 'NUMBER_2', self.do_decsca, 'INIT')
- self.state.add_transition (';', 'NUMBER_2', None, 'SEMICOLON_X')
-
- # Create a state for 'q' and 'm' which allows an infinite number of ignored numbers
- self.state.add_transition_any ('SEMICOLON_X', DoLog, 'INIT')
- self.state.add_transition_list (string.digits, 'SEMICOLON_X', DoStartNumber, 'NUMBER_X')
- self.state.add_transition_list (string.digits, 'NUMBER_X', DoBuildNumber, 'NUMBER_X')
- self.state.add_transition_any ('NUMBER_X', DoLog, 'INIT')
- self.state.add_transition ('m', 'NUMBER_X', self.do_sgr, 'INIT')
- self.state.add_transition ('q', 'NUMBER_X', self.do_decsca, 'INIT')
- self.state.add_transition (';', 'NUMBER_X', None, 'SEMICOLON_X')
-
- def process (self, c):
- """Process a single character. Called by :meth:`write`."""
- if isinstance(c, bytes):
- c = self._decode(c)
- self.state.process(c)
-
- def process_list (self, l):
-
- self.write(l)
-
- def write (self, s):
- """Process text, writing it to the virtual screen while handling
- ANSI escape codes.
- """
- if isinstance(s, bytes):
- s = self._decode(s)
- for c in s:
- self.process(c)
-
- def flush (self):
- pass
-
- def write_ch (self, ch):
- '''This puts a character at the current cursor position. The cursor
- position is moved forward with wrap-around, but no scrolling is done if
- the cursor hits the lower-right corner of the screen. '''
-
- if isinstance(ch, bytes):
- ch = self._decode(ch)
-
- #\r and \n both produce a call to cr() and lf(), respectively.
- ch = ch[0]
-
- if ch == u'\r':
- self.cr()
- return
- if ch == u'\n':
- self.crlf()
- return
- if ch == chr(screen.BS):
- self.cursor_back()
- return
- self.put_abs(self.cur_r, self.cur_c, ch)
- old_r = self.cur_r
- old_c = self.cur_c
- self.cursor_forward()
- if old_c == self.cur_c:
- self.cursor_down()
- if old_r != self.cur_r:
- self.cursor_home (self.cur_r, 1)
- else:
- self.scroll_up ()
- self.cursor_home (self.cur_r, 1)
- self.erase_line()
-
- def do_sgr (self, fsm):
- '''Select Graphic Rendition, e.g. color. '''
- screen = fsm.memory[0]
- fsm.memory = [screen]
-
- def do_decsca (self, fsm):
- '''Select character protection attribute. '''
- screen = fsm.memory[0]
- fsm.memory = [screen]
-
- def do_modecrap (self, fsm):
- '''Handler for \x1b[?<number>h and \x1b[?<number>l. If anyone
- wanted to actually use these, they'd need to add more states to the
- FSM rather than just improve or override this method. '''
- screen = fsm.memory[0]
- fsm.memory = [screen]
+'''This implements an ANSI (VT100) terminal emulator as a subclass of screen.
+
+PEXPECT LICENSE
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2012, Noah Spurrier <[email protected]>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+'''
+
+# references:
+# http://en.wikipedia.org/wiki/ANSI_escape_code
+# http://www.retards.org/terminals/vt102.html
+# http://vt100.net/docs/vt102-ug/contents.html
+# http://vt100.net/docs/vt220-rm/
+# http://www.termsys.demon.co.uk/vtansi.htm
+
+from . import screen
+from . import FSM
+import string
+
+#
+# The 'Do.*' functions are helper functions for the ANSI class.
+#
+def DoEmit (fsm):
+
+ screen = fsm.memory[0]
+ screen.write_ch(fsm.input_symbol)
+
+def DoStartNumber (fsm):
+
+ fsm.memory.append (fsm.input_symbol)
+
+def DoBuildNumber (fsm):
+
+ ns = fsm.memory.pop()
+ ns = ns + fsm.input_symbol
+ fsm.memory.append (ns)
+
+def DoBackOne (fsm):
+
+ screen = fsm.memory[0]
+ screen.cursor_back ()
+
+def DoBack (fsm):
+
+ count = int(fsm.memory.pop())
+ screen = fsm.memory[0]
+ screen.cursor_back (count)
+
+def DoDownOne (fsm):
+
+ screen = fsm.memory[0]
+ screen.cursor_down ()
+
+def DoDown (fsm):
+
+ count = int(fsm.memory.pop())
+ screen = fsm.memory[0]
+ screen.cursor_down (count)
+
+def DoForwardOne (fsm):
+
+ screen = fsm.memory[0]
+ screen.cursor_forward ()
+
+def DoForward (fsm):
+
+ count = int(fsm.memory.pop())
+ screen = fsm.memory[0]
+ screen.cursor_forward (count)
+
+def DoUpReverse (fsm):
+
+ screen = fsm.memory[0]
+ screen.cursor_up_reverse()
+
+def DoUpOne (fsm):
+
+ screen = fsm.memory[0]
+ screen.cursor_up ()
+
+def DoUp (fsm):
+
+ count = int(fsm.memory.pop())
+ screen = fsm.memory[0]
+ screen.cursor_up (count)
+
+def DoHome (fsm):
+
+ c = int(fsm.memory.pop())
+ r = int(fsm.memory.pop())
+ screen = fsm.memory[0]
+ screen.cursor_home (r,c)
+
+def DoHomeOrigin (fsm):
+
+ c = 1
+ r = 1
+ screen = fsm.memory[0]
+ screen.cursor_home (r,c)
+
+def DoEraseDown (fsm):
+
+ screen = fsm.memory[0]
+ screen.erase_down()
+
+def DoErase (fsm):
+
+ arg = int(fsm.memory.pop())
+ screen = fsm.memory[0]
+ if arg == 0:
+ screen.erase_down()
+ elif arg == 1:
+ screen.erase_up()
+ elif arg == 2:
+ screen.erase_screen()
+
+def DoEraseEndOfLine (fsm):
+
+ screen = fsm.memory[0]
+ screen.erase_end_of_line()
+
+def DoEraseLine (fsm):
+
+ arg = int(fsm.memory.pop())
+ screen = fsm.memory[0]
+ if arg == 0:
+ screen.erase_end_of_line()
+ elif arg == 1:
+ screen.erase_start_of_line()
+ elif arg == 2:
+ screen.erase_line()
+
+def DoEnableScroll (fsm):
+
+ screen = fsm.memory[0]
+ screen.scroll_screen()
+
+def DoCursorSave (fsm):
+
+ screen = fsm.memory[0]
+ screen.cursor_save_attrs()
+
+def DoCursorRestore (fsm):
+
+ screen = fsm.memory[0]
+ screen.cursor_restore_attrs()
+
+def DoScrollRegion (fsm):
+
+ screen = fsm.memory[0]
+ r2 = int(fsm.memory.pop())
+ r1 = int(fsm.memory.pop())
+ screen.scroll_screen_rows (r1,r2)
+
+def DoMode (fsm):
+
+ screen = fsm.memory[0]
+ mode = fsm.memory.pop() # Should be 4
+ # screen.setReplaceMode ()
+
+def DoLog (fsm):
+
+ screen = fsm.memory[0]
+ fsm.memory = [screen]
+ fout = open ('log', 'a')
+ fout.write (fsm.input_symbol + ',' + fsm.current_state + '\n')
+ fout.close()
+
+class term (screen.screen):
+
+ '''This class is an abstract, generic terminal.
+ This does nothing. This is a placeholder that
+ provides a common base class for other terminals
+ such as an ANSI terminal. '''
+
+ def __init__ (self, r=24, c=80, *args, **kwargs):
+
+ screen.screen.__init__(self, r,c,*args,**kwargs)
+
+class ANSI (term):
+ '''This class implements an ANSI (VT100) terminal.
+ It is a stream filter that recognizes ANSI terminal
+ escape sequences and maintains the state of a screen object. '''
+
+ def __init__ (self, r=24,c=80,*args,**kwargs):
+
+ term.__init__(self,r,c,*args,**kwargs)
+
+ #self.screen = screen (24,80)
+ self.state = FSM.FSM ('INIT',[self])
+ self.state.set_default_transition (DoLog, 'INIT')
+ self.state.add_transition_any ('INIT', DoEmit, 'INIT')
+ self.state.add_transition ('\x1b', 'INIT', None, 'ESC')
+ self.state.add_transition_any ('ESC', DoLog, 'INIT')
+ self.state.add_transition ('(', 'ESC', None, 'G0SCS')
+ self.state.add_transition (')', 'ESC', None, 'G1SCS')
+ self.state.add_transition_list ('AB012', 'G0SCS', None, 'INIT')
+ self.state.add_transition_list ('AB012', 'G1SCS', None, 'INIT')
+ self.state.add_transition ('7', 'ESC', DoCursorSave, 'INIT')
+ self.state.add_transition ('8', 'ESC', DoCursorRestore, 'INIT')
+ self.state.add_transition ('M', 'ESC', DoUpReverse, 'INIT')
+ self.state.add_transition ('>', 'ESC', DoUpReverse, 'INIT')
+ self.state.add_transition ('<', 'ESC', DoUpReverse, 'INIT')
+ self.state.add_transition ('=', 'ESC', None, 'INIT') # Selects application keypad.
+ self.state.add_transition ('#', 'ESC', None, 'GRAPHICS_POUND')
+ self.state.add_transition_any ('GRAPHICS_POUND', None, 'INIT')
+ self.state.add_transition ('[', 'ESC', None, 'ELB')
+ # ELB means Escape Left Bracket. That is ^[[
+ self.state.add_transition ('H', 'ELB', DoHomeOrigin, 'INIT')
+ self.state.add_transition ('D', 'ELB', DoBackOne, 'INIT')
+ self.state.add_transition ('B', 'ELB', DoDownOne, 'INIT')
+ self.state.add_transition ('C', 'ELB', DoForwardOne, 'INIT')
+ self.state.add_transition ('A', 'ELB', DoUpOne, 'INIT')
+ self.state.add_transition ('J', 'ELB', DoEraseDown, 'INIT')
+ self.state.add_transition ('K', 'ELB', DoEraseEndOfLine, 'INIT')
+ self.state.add_transition ('r', 'ELB', DoEnableScroll, 'INIT')
+ self.state.add_transition ('m', 'ELB', self.do_sgr, 'INIT')
+ self.state.add_transition ('?', 'ELB', None, 'MODECRAP')
+ self.state.add_transition_list (string.digits, 'ELB', DoStartNumber, 'NUMBER_1')
+ self.state.add_transition_list (string.digits, 'NUMBER_1', DoBuildNumber, 'NUMBER_1')
+ self.state.add_transition ('D', 'NUMBER_1', DoBack, 'INIT')
+ self.state.add_transition ('B', 'NUMBER_1', DoDown, 'INIT')
+ self.state.add_transition ('C', 'NUMBER_1', DoForward, 'INIT')
+ self.state.add_transition ('A', 'NUMBER_1', DoUp, 'INIT')
+ self.state.add_transition ('J', 'NUMBER_1', DoErase, 'INIT')
+ self.state.add_transition ('K', 'NUMBER_1', DoEraseLine, 'INIT')
+ self.state.add_transition ('l', 'NUMBER_1', DoMode, 'INIT')
+ ### It gets worse... the 'm' code can have infinite number of
+ ### number;number;number before it. I've never seen more than two,
+ ### but the specs say it's allowed. crap!
+ self.state.add_transition ('m', 'NUMBER_1', self.do_sgr, 'INIT')
+ ### LED control. Same implementation problem as 'm' code.
+ self.state.add_transition ('q', 'NUMBER_1', self.do_decsca, 'INIT')
+
+ # \E[?47h switch to alternate screen
+ # \E[?47l restores to normal screen from alternate screen.
+ self.state.add_transition_list (string.digits, 'MODECRAP', DoStartNumber, 'MODECRAP_NUM')
+ self.state.add_transition_list (string.digits, 'MODECRAP_NUM', DoBuildNumber, 'MODECRAP_NUM')
+ self.state.add_transition ('l', 'MODECRAP_NUM', self.do_modecrap, 'INIT')
+ self.state.add_transition ('h', 'MODECRAP_NUM', self.do_modecrap, 'INIT')
+
+#RM Reset Mode Esc [ Ps l none
+ self.state.add_transition (';', 'NUMBER_1', None, 'SEMICOLON')
+ self.state.add_transition_any ('SEMICOLON', DoLog, 'INIT')
+ self.state.add_transition_list (string.digits, 'SEMICOLON', DoStartNumber, 'NUMBER_2')
+ self.state.add_transition_list (string.digits, 'NUMBER_2', DoBuildNumber, 'NUMBER_2')
+ self.state.add_transition_any ('NUMBER_2', DoLog, 'INIT')
+ self.state.add_transition ('H', 'NUMBER_2', DoHome, 'INIT')
+ self.state.add_transition ('f', 'NUMBER_2', DoHome, 'INIT')
+ self.state.add_transition ('r', 'NUMBER_2', DoScrollRegion, 'INIT')
+ ### It gets worse... the 'm' code can have infinite number of
+ ### number;number;number before it. I've never seen more than two,
+ ### but the specs say it's allowed. crap!
+ self.state.add_transition ('m', 'NUMBER_2', self.do_sgr, 'INIT')
+ ### LED control. Same problem as 'm' code.
+ self.state.add_transition ('q', 'NUMBER_2', self.do_decsca, 'INIT')
+ self.state.add_transition (';', 'NUMBER_2', None, 'SEMICOLON_X')
+
+ # Create a state for 'q' and 'm' which allows an infinite number of ignored numbers
+ self.state.add_transition_any ('SEMICOLON_X', DoLog, 'INIT')
+ self.state.add_transition_list (string.digits, 'SEMICOLON_X', DoStartNumber, 'NUMBER_X')
+ self.state.add_transition_list (string.digits, 'NUMBER_X', DoBuildNumber, 'NUMBER_X')
+ self.state.add_transition_any ('NUMBER_X', DoLog, 'INIT')
+ self.state.add_transition ('m', 'NUMBER_X', self.do_sgr, 'INIT')
+ self.state.add_transition ('q', 'NUMBER_X', self.do_decsca, 'INIT')
+ self.state.add_transition (';', 'NUMBER_X', None, 'SEMICOLON_X')
+
+ def process (self, c):
+ """Process a single character. Called by :meth:`write`."""
+ if isinstance(c, bytes):
+ c = self._decode(c)
+ self.state.process(c)
+
+ def process_list (self, l):
+
+ self.write(l)
+
+ def write (self, s):
+ """Process text, writing it to the virtual screen while handling
+ ANSI escape codes.
+ """
+ if isinstance(s, bytes):
+ s = self._decode(s)
+ for c in s:
+ self.process(c)
+
+ def flush (self):
+ pass
+
+ def write_ch (self, ch):
+ '''This puts a character at the current cursor position. The cursor
+ position is moved forward with wrap-around, but no scrolling is done if
+ the cursor hits the lower-right corner of the screen. '''
+
+ if isinstance(ch, bytes):
+ ch = self._decode(ch)
+
+ #\r and \n both produce a call to cr() and lf(), respectively.
+ ch = ch[0]
+
+ if ch == u'\r':
+ self.cr()
+ return
+ if ch == u'\n':
+ self.crlf()
+ return
+ if ch == chr(screen.BS):
+ self.cursor_back()
+ return
+ self.put_abs(self.cur_r, self.cur_c, ch)
+ old_r = self.cur_r
+ old_c = self.cur_c
+ self.cursor_forward()
+ if old_c == self.cur_c:
+ self.cursor_down()
+ if old_r != self.cur_r:
+ self.cursor_home (self.cur_r, 1)
+ else:
+ self.scroll_up ()
+ self.cursor_home (self.cur_r, 1)
+ self.erase_line()
+
+ def do_sgr (self, fsm):
+ '''Select Graphic Rendition, e.g. color. '''
+ screen = fsm.memory[0]
+ fsm.memory = [screen]
+
+ def do_decsca (self, fsm):
+ '''Select character protection attribute. '''
+ screen = fsm.memory[0]
+ fsm.memory = [screen]
+
+ def do_modecrap (self, fsm):
+ '''Handler for \x1b[?<number>h and \x1b[?<number>l. If anyone
+ wanted to actually use these, they'd need to add more states to the
+ FSM rather than just improve or override this method. '''
+ screen = fsm.memory[0]
+ fsm.memory = [screen]
diff --git a/contrib/python/pexpect/pexpect/FSM.py b/contrib/python/pexpect/pexpect/FSM.py
index 46b392ea08a..45fcc1baa96 100644
--- a/contrib/python/pexpect/pexpect/FSM.py
+++ b/contrib/python/pexpect/pexpect/FSM.py
@@ -1,334 +1,334 @@
-#!/usr/bin/env python
-
-'''This module implements a Finite State Machine (FSM). In addition to state
-this FSM also maintains a user defined "memory". So this FSM can be used as a
-Push-down Automata (PDA) since a PDA is a FSM + memory.
-
-The following describes how the FSM works, but you will probably also need to
-see the example function to understand how the FSM is used in practice.
-
-You define an FSM by building tables of transitions. For a given input symbol
-the process() method uses these tables to decide what action to call and what
-the next state will be. The FSM has a table of transitions that associate:
-
- (input_symbol, current_state) --> (action, next_state)
-
-Where "action" is a function you define. The symbols and states can be any
-objects. You use the add_transition() and add_transition_list() methods to add
-to the transition table. The FSM also has a table of transitions that
-associate:
-
- (current_state) --> (action, next_state)
-
-You use the add_transition_any() method to add to this transition table. The
-FSM also has one default transition that is not associated with any specific
-input_symbol or state. You use the set_default_transition() method to set the
-default transition.
-
-When an action function is called it is passed a reference to the FSM. The
-action function may then access attributes of the FSM such as input_symbol,
-current_state, or "memory". The "memory" attribute can be any object that you
-want to pass along to the action functions. It is not used by the FSM itself.
-For parsing you would typically pass a list to be used as a stack.
-
-The processing sequence is as follows. The process() method is given an
-input_symbol to process. The FSM will search the table of transitions that
-associate:
-
- (input_symbol, current_state) --> (action, next_state)
-
-If the pair (input_symbol, current_state) is found then process() will call the
-associated action function and then set the current state to the next_state.
-
-If the FSM cannot find a match for (input_symbol, current_state) it will then
-search the table of transitions that associate:
-
- (current_state) --> (action, next_state)
-
-If the current_state is found then the process() method will call the
-associated action function and then set the current state to the next_state.
-Notice that this table lacks an input_symbol. It lets you define transitions
-for a current_state and ANY input_symbol. Hence, it is called the "any" table.
-Remember, it is always checked after first searching the table for a specific
-(input_symbol, current_state).
-
-For the case where the FSM did not match either of the previous two cases the
-FSM will try to use the default transition. If the default transition is
-defined then the process() method will call the associated action function and
-then set the current state to the next_state. This lets you define a default
-transition as a catch-all case. You can think of it as an exception handler.
-There can be only one default transition.
-
-Finally, if none of the previous cases are defined for an input_symbol and
-current_state then the FSM will raise an exception. This may be desirable, but
-you can always prevent this just by defining a default transition.
-
-Noah Spurrier 20020822
-
-PEXPECT LICENSE
-
- This license is approved by the OSI and FSF as GPL-compatible.
- http://opensource.org/licenses/isc-license.txt
-
- Copyright (c) 2012, Noah Spurrier <[email protected]>
- PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
- PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
- COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-'''
-
-class ExceptionFSM(Exception):
-
- '''This is the FSM Exception class.'''
-
- def __init__(self, value):
- self.value = value
-
- def __str__(self):
- return 'ExceptionFSM: ' + str(self.value)
-
-class FSM:
-
- '''This is a Finite State Machine (FSM).
- '''
-
- def __init__(self, initial_state, memory=None):
-
- '''This creates the FSM. You set the initial state here. The "memory"
- attribute is any object that you want to pass along to the action
- functions. It is not used by the FSM. For parsing you would typically
- pass a list to be used as a stack. '''
-
- # Map (input_symbol, current_state) --> (action, next_state).
- self.state_transitions = {}
- # Map (current_state) --> (action, next_state).
- self.state_transitions_any = {}
- self.default_transition = None
-
- self.input_symbol = None
- self.initial_state = initial_state
- self.current_state = self.initial_state
- self.next_state = None
- self.action = None
- self.memory = memory
-
- def reset (self):
-
- '''This sets the current_state to the initial_state and sets
- input_symbol to None. The initial state was set by the constructor
- __init__(). '''
-
- self.current_state = self.initial_state
- self.input_symbol = None
-
- def add_transition (self, input_symbol, state, action=None, next_state=None):
-
- '''This adds a transition that associates:
-
- (input_symbol, current_state) --> (action, next_state)
-
- The action may be set to None in which case the process() method will
- ignore the action and only set the next_state. The next_state may be
- set to None in which case the current state will be unchanged.
-
- You can also set transitions for a list of symbols by using
- add_transition_list(). '''
-
- if next_state is None:
- next_state = state
- self.state_transitions[(input_symbol, state)] = (action, next_state)
-
- def add_transition_list (self, list_input_symbols, state, action=None, next_state=None):
-
- '''This adds the same transition for a list of input symbols.
- You can pass a list or a string. Note that it is handy to use
- string.digits, string.whitespace, string.letters, etc. to add
- transitions that match character classes.
-
- The action may be set to None in which case the process() method will
- ignore the action and only set the next_state. The next_state may be
- set to None in which case the current state will be unchanged. '''
-
- if next_state is None:
- next_state = state
- for input_symbol in list_input_symbols:
- self.add_transition (input_symbol, state, action, next_state)
-
- def add_transition_any (self, state, action=None, next_state=None):
-
- '''This adds a transition that associates:
-
- (current_state) --> (action, next_state)
-
- That is, any input symbol will match the current state.
- The process() method checks the "any" state associations after it first
- checks for an exact match of (input_symbol, current_state).
-
- The action may be set to None in which case the process() method will
- ignore the action and only set the next_state. The next_state may be
- set to None in which case the current state will be unchanged. '''
-
- if next_state is None:
- next_state = state
- self.state_transitions_any [state] = (action, next_state)
-
- def set_default_transition (self, action, next_state):
-
- '''This sets the default transition. This defines an action and
- next_state if the FSM cannot find the input symbol and the current
- state in the transition list and if the FSM cannot find the
- current_state in the transition_any list. This is useful as a final
- fall-through state for catching errors and undefined states.
-
- The default transition can be removed by setting the attribute
- default_transition to None. '''
-
- self.default_transition = (action, next_state)
-
- def get_transition (self, input_symbol, state):
-
- '''This returns (action, next state) given an input_symbol and state.
- This does not modify the FSM state, so calling this method has no side
- effects. Normally you do not call this method directly. It is called by
- process().
-
- The sequence of steps to check for a defined transition goes from the
- most specific to the least specific.
-
- 1. Check state_transitions[] that match exactly the tuple,
- (input_symbol, state)
-
- 2. Check state_transitions_any[] that match (state)
- In other words, match a specific state and ANY input_symbol.
-
- 3. Check if the default_transition is defined.
- This catches any input_symbol and any state.
- This is a handler for errors, undefined states, or defaults.
-
- 4. No transition was defined. If we get here then raise an exception.
- '''
-
- if (input_symbol, state) in self.state_transitions:
- return self.state_transitions[(input_symbol, state)]
- elif state in self.state_transitions_any:
- return self.state_transitions_any[state]
- elif self.default_transition is not None:
- return self.default_transition
- else:
- raise ExceptionFSM ('Transition is undefined: (%s, %s).' %
- (str(input_symbol), str(state)) )
-
- def process (self, input_symbol):
-
- '''This is the main method that you call to process input. This may
- cause the FSM to change state and call an action. This method calls
- get_transition() to find the action and next_state associated with the
- input_symbol and current_state. If the action is None then the action
- is not called and only the current state is changed. This method
- processes one complete input symbol. You can process a list of symbols
- (or a string) by calling process_list(). '''
-
- self.input_symbol = input_symbol
- (self.action, self.next_state) = self.get_transition (self.input_symbol, self.current_state)
- if self.action is not None:
- self.action (self)
- self.current_state = self.next_state
- self.next_state = None
-
- def process_list (self, input_symbols):
-
- '''This takes a list and sends each element to process(). The list may
- be a string or any iterable object. '''
-
- for s in input_symbols:
- self.process (s)
-
-##############################################################################
-# The following is an example that demonstrates the use of the FSM class to
-# process an RPN expression. Run this module from the command line. You will
-# get a prompt > for input. Enter an RPN Expression. Numbers may be integers.
-# Operators are * / + - Use the = sign to evaluate and print the expression.
-# For example:
-#
-# 167 3 2 2 * * * 1 - =
-#
-# will print:
-#
-# 2003
-##############################################################################
-
-import sys
-import string
-
-PY3 = (sys.version_info[0] >= 3)
-
-#
-# These define the actions.
-# Note that "memory" is a list being used as a stack.
-#
-
-def BeginBuildNumber (fsm):
- fsm.memory.append (fsm.input_symbol)
-
-def BuildNumber (fsm):
- s = fsm.memory.pop ()
- s = s + fsm.input_symbol
- fsm.memory.append (s)
-
-def EndBuildNumber (fsm):
- s = fsm.memory.pop ()
- fsm.memory.append (int(s))
-
-def DoOperator (fsm):
- ar = fsm.memory.pop()
- al = fsm.memory.pop()
- if fsm.input_symbol == '+':
- fsm.memory.append (al + ar)
- elif fsm.input_symbol == '-':
- fsm.memory.append (al - ar)
- elif fsm.input_symbol == '*':
- fsm.memory.append (al * ar)
- elif fsm.input_symbol == '/':
- fsm.memory.append (al / ar)
-
-def DoEqual (fsm):
- print(str(fsm.memory.pop()))
-
-def Error (fsm):
- print('That does not compute.')
- print(str(fsm.input_symbol))
-
-def main():
-
- '''This is where the example starts and the FSM state transitions are
- defined. Note that states are strings (such as 'INIT'). This is not
- necessary, but it makes the example easier to read. '''
-
- f = FSM ('INIT', [])
- f.set_default_transition (Error, 'INIT')
- f.add_transition_any ('INIT', None, 'INIT')
- f.add_transition ('=', 'INIT', DoEqual, 'INIT')
- f.add_transition_list (string.digits, 'INIT', BeginBuildNumber, 'BUILDING_NUMBER')
- f.add_transition_list (string.digits, 'BUILDING_NUMBER', BuildNumber, 'BUILDING_NUMBER')
- f.add_transition_list (string.whitespace, 'BUILDING_NUMBER', EndBuildNumber, 'INIT')
- f.add_transition_list ('+-*/', 'INIT', DoOperator, 'INIT')
-
- print()
- print('Enter an RPN Expression.')
- print('Numbers may be integers. Operators are * / + -')
- print('Use the = sign to evaluate and print the expression.')
- print('For example: ')
- print(' 167 3 2 2 * * * 1 - =')
- inputstr = (input if PY3 else raw_input)('> ') # analysis:ignore
- f.process_list(inputstr)
-
-
-if __name__ == '__main__':
- main()
+#!/usr/bin/env python
+
+'''This module implements a Finite State Machine (FSM). In addition to state
+this FSM also maintains a user defined "memory". So this FSM can be used as a
+Push-down Automata (PDA) since a PDA is a FSM + memory.
+
+The following describes how the FSM works, but you will probably also need to
+see the example function to understand how the FSM is used in practice.
+
+You define an FSM by building tables of transitions. For a given input symbol
+the process() method uses these tables to decide what action to call and what
+the next state will be. The FSM has a table of transitions that associate:
+
+ (input_symbol, current_state) --> (action, next_state)
+
+Where "action" is a function you define. The symbols and states can be any
+objects. You use the add_transition() and add_transition_list() methods to add
+to the transition table. The FSM also has a table of transitions that
+associate:
+
+ (current_state) --> (action, next_state)
+
+You use the add_transition_any() method to add to this transition table. The
+FSM also has one default transition that is not associated with any specific
+input_symbol or state. You use the set_default_transition() method to set the
+default transition.
+
+When an action function is called it is passed a reference to the FSM. The
+action function may then access attributes of the FSM such as input_symbol,
+current_state, or "memory". The "memory" attribute can be any object that you
+want to pass along to the action functions. It is not used by the FSM itself.
+For parsing you would typically pass a list to be used as a stack.
+
+The processing sequence is as follows. The process() method is given an
+input_symbol to process. The FSM will search the table of transitions that
+associate:
+
+ (input_symbol, current_state) --> (action, next_state)
+
+If the pair (input_symbol, current_state) is found then process() will call the
+associated action function and then set the current state to the next_state.
+
+If the FSM cannot find a match for (input_symbol, current_state) it will then
+search the table of transitions that associate:
+
+ (current_state) --> (action, next_state)
+
+If the current_state is found then the process() method will call the
+associated action function and then set the current state to the next_state.
+Notice that this table lacks an input_symbol. It lets you define transitions
+for a current_state and ANY input_symbol. Hence, it is called the "any" table.
+Remember, it is always checked after first searching the table for a specific
+(input_symbol, current_state).
+
+For the case where the FSM did not match either of the previous two cases the
+FSM will try to use the default transition. If the default transition is
+defined then the process() method will call the associated action function and
+then set the current state to the next_state. This lets you define a default
+transition as a catch-all case. You can think of it as an exception handler.
+There can be only one default transition.
+
+Finally, if none of the previous cases are defined for an input_symbol and
+current_state then the FSM will raise an exception. This may be desirable, but
+you can always prevent this just by defining a default transition.
+
+Noah Spurrier 20020822
+
+PEXPECT LICENSE
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2012, Noah Spurrier <[email protected]>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+'''
+
+class ExceptionFSM(Exception):
+
+ '''This is the FSM Exception class.'''
+
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return 'ExceptionFSM: ' + str(self.value)
+
+class FSM:
+
+ '''This is a Finite State Machine (FSM).
+ '''
+
+ def __init__(self, initial_state, memory=None):
+
+ '''This creates the FSM. You set the initial state here. The "memory"
+ attribute is any object that you want to pass along to the action
+ functions. It is not used by the FSM. For parsing you would typically
+ pass a list to be used as a stack. '''
+
+ # Map (input_symbol, current_state) --> (action, next_state).
+ self.state_transitions = {}
+ # Map (current_state) --> (action, next_state).
+ self.state_transitions_any = {}
+ self.default_transition = None
+
+ self.input_symbol = None
+ self.initial_state = initial_state
+ self.current_state = self.initial_state
+ self.next_state = None
+ self.action = None
+ self.memory = memory
+
+ def reset (self):
+
+ '''This sets the current_state to the initial_state and sets
+ input_symbol to None. The initial state was set by the constructor
+ __init__(). '''
+
+ self.current_state = self.initial_state
+ self.input_symbol = None
+
+ def add_transition (self, input_symbol, state, action=None, next_state=None):
+
+ '''This adds a transition that associates:
+
+ (input_symbol, current_state) --> (action, next_state)
+
+ The action may be set to None in which case the process() method will
+ ignore the action and only set the next_state. The next_state may be
+ set to None in which case the current state will be unchanged.
+
+ You can also set transitions for a list of symbols by using
+ add_transition_list(). '''
+
+ if next_state is None:
+ next_state = state
+ self.state_transitions[(input_symbol, state)] = (action, next_state)
+
+ def add_transition_list (self, list_input_symbols, state, action=None, next_state=None):
+
+ '''This adds the same transition for a list of input symbols.
+ You can pass a list or a string. Note that it is handy to use
+ string.digits, string.whitespace, string.letters, etc. to add
+ transitions that match character classes.
+
+ The action may be set to None in which case the process() method will
+ ignore the action and only set the next_state. The next_state may be
+ set to None in which case the current state will be unchanged. '''
+
+ if next_state is None:
+ next_state = state
+ for input_symbol in list_input_symbols:
+ self.add_transition (input_symbol, state, action, next_state)
+
+ def add_transition_any (self, state, action=None, next_state=None):
+
+ '''This adds a transition that associates:
+
+ (current_state) --> (action, next_state)
+
+ That is, any input symbol will match the current state.
+ The process() method checks the "any" state associations after it first
+ checks for an exact match of (input_symbol, current_state).
+
+ The action may be set to None in which case the process() method will
+ ignore the action and only set the next_state. The next_state may be
+ set to None in which case the current state will be unchanged. '''
+
+ if next_state is None:
+ next_state = state
+ self.state_transitions_any [state] = (action, next_state)
+
+ def set_default_transition (self, action, next_state):
+
+ '''This sets the default transition. This defines an action and
+ next_state if the FSM cannot find the input symbol and the current
+ state in the transition list and if the FSM cannot find the
+ current_state in the transition_any list. This is useful as a final
+ fall-through state for catching errors and undefined states.
+
+ The default transition can be removed by setting the attribute
+ default_transition to None. '''
+
+ self.default_transition = (action, next_state)
+
+ def get_transition (self, input_symbol, state):
+
+ '''This returns (action, next state) given an input_symbol and state.
+ This does not modify the FSM state, so calling this method has no side
+ effects. Normally you do not call this method directly. It is called by
+ process().
+
+ The sequence of steps to check for a defined transition goes from the
+ most specific to the least specific.
+
+ 1. Check state_transitions[] that match exactly the tuple,
+ (input_symbol, state)
+
+ 2. Check state_transitions_any[] that match (state)
+ In other words, match a specific state and ANY input_symbol.
+
+ 3. Check if the default_transition is defined.
+ This catches any input_symbol and any state.
+ This is a handler for errors, undefined states, or defaults.
+
+ 4. No transition was defined. If we get here then raise an exception.
+ '''
+
+ if (input_symbol, state) in self.state_transitions:
+ return self.state_transitions[(input_symbol, state)]
+ elif state in self.state_transitions_any:
+ return self.state_transitions_any[state]
+ elif self.default_transition is not None:
+ return self.default_transition
+ else:
+ raise ExceptionFSM ('Transition is undefined: (%s, %s).' %
+ (str(input_symbol), str(state)) )
+
+ def process (self, input_symbol):
+
+ '''This is the main method that you call to process input. This may
+ cause the FSM to change state and call an action. This method calls
+ get_transition() to find the action and next_state associated with the
+ input_symbol and current_state. If the action is None then the action
+ is not called and only the current state is changed. This method
+ processes one complete input symbol. You can process a list of symbols
+ (or a string) by calling process_list(). '''
+
+ self.input_symbol = input_symbol
+ (self.action, self.next_state) = self.get_transition (self.input_symbol, self.current_state)
+ if self.action is not None:
+ self.action (self)
+ self.current_state = self.next_state
+ self.next_state = None
+
+ def process_list (self, input_symbols):
+
+ '''This takes a list and sends each element to process(). The list may
+ be a string or any iterable object. '''
+
+ for s in input_symbols:
+ self.process (s)
+
+##############################################################################
+# The following is an example that demonstrates the use of the FSM class to
+# process an RPN expression. Run this module from the command line. You will
+# get a prompt > for input. Enter an RPN Expression. Numbers may be integers.
+# Operators are * / + - Use the = sign to evaluate and print the expression.
+# For example:
+#
+# 167 3 2 2 * * * 1 - =
+#
+# will print:
+#
+# 2003
+##############################################################################
+
+import sys
+import string
+
+PY3 = (sys.version_info[0] >= 3)
+
+#
+# These define the actions.
+# Note that "memory" is a list being used as a stack.
+#
+
+def BeginBuildNumber (fsm):
+ fsm.memory.append (fsm.input_symbol)
+
+def BuildNumber (fsm):
+ s = fsm.memory.pop ()
+ s = s + fsm.input_symbol
+ fsm.memory.append (s)
+
+def EndBuildNumber (fsm):
+ s = fsm.memory.pop ()
+ fsm.memory.append (int(s))
+
+def DoOperator (fsm):
+ ar = fsm.memory.pop()
+ al = fsm.memory.pop()
+ if fsm.input_symbol == '+':
+ fsm.memory.append (al + ar)
+ elif fsm.input_symbol == '-':
+ fsm.memory.append (al - ar)
+ elif fsm.input_symbol == '*':
+ fsm.memory.append (al * ar)
+ elif fsm.input_symbol == '/':
+ fsm.memory.append (al / ar)
+
+def DoEqual (fsm):
+ print(str(fsm.memory.pop()))
+
+def Error (fsm):
+ print('That does not compute.')
+ print(str(fsm.input_symbol))
+
+def main():
+
+ '''This is where the example starts and the FSM state transitions are
+ defined. Note that states are strings (such as 'INIT'). This is not
+ necessary, but it makes the example easier to read. '''
+
+ f = FSM ('INIT', [])
+ f.set_default_transition (Error, 'INIT')
+ f.add_transition_any ('INIT', None, 'INIT')
+ f.add_transition ('=', 'INIT', DoEqual, 'INIT')
+ f.add_transition_list (string.digits, 'INIT', BeginBuildNumber, 'BUILDING_NUMBER')
+ f.add_transition_list (string.digits, 'BUILDING_NUMBER', BuildNumber, 'BUILDING_NUMBER')
+ f.add_transition_list (string.whitespace, 'BUILDING_NUMBER', EndBuildNumber, 'INIT')
+ f.add_transition_list ('+-*/', 'INIT', DoOperator, 'INIT')
+
+ print()
+ print('Enter an RPN Expression.')
+ print('Numbers may be integers. Operators are * / + -')
+ print('Use the = sign to evaluate and print the expression.')
+ print('For example: ')
+ print(' 167 3 2 2 * * * 1 - =')
+ inputstr = (input if PY3 else raw_input)('> ') # analysis:ignore
+ f.process_list(inputstr)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/python/pexpect/pexpect/__init__.py b/contrib/python/pexpect/pexpect/__init__.py
index 7e30453787c..0e5f215e7c3 100644
--- a/contrib/python/pexpect/pexpect/__init__.py
+++ b/contrib/python/pexpect/pexpect/__init__.py
@@ -1,85 +1,85 @@
-'''Pexpect is a Python module for spawning child applications and controlling
-them automatically. Pexpect can be used for automating interactive applications
-such as ssh, ftp, passwd, telnet, etc. It can be used to a automate setup
-scripts for duplicating software package installations on different servers. It
-can be used for automated software testing. Pexpect is in the spirit of Don
-Libes' Expect, but Pexpect is pure Python. Other Expect-like modules for Python
-require TCL and Expect or require C extensions to be compiled. Pexpect does not
-use C, Expect, or TCL extensions. It should work on any platform that supports
-the standard Python pty module. The Pexpect interface focuses on ease of use so
-that simple tasks are easy.
-
-There are two main interfaces to the Pexpect system; these are the function,
-run() and the class, spawn. The spawn class is more powerful. The run()
-function is simpler than spawn, and is good for quickly calling program. When
-you call the run() function it executes a given program and then returns the
-output. This is a handy replacement for os.system().
-
-For example::
-
- pexpect.run('ls -la')
-
-The spawn class is the more powerful interface to the Pexpect system. You can
-use this to spawn a child program then interact with it by sending input and
-expecting responses (waiting for patterns in the child's output).
-
-For example::
-
- child = pexpect.spawn('scp foo [email protected]:.')
- child.expect('Password:')
- child.sendline(mypassword)
-
-This works even for commands that ask for passwords or other input outside of
-the normal stdio streams. For example, ssh reads input directly from the TTY
-device which bypasses stdin.
-
-Credits: Noah Spurrier, Richard Holden, Marco Molteni, Kimberley Burchett,
-Robert Stone, Hartmut Goebel, Chad Schroeder, Erick Tryzelaar, Dave Kirby, Ids
-vander Molen, George Todd, Noel Taylor, Nicolas D. Cesar, Alexander Gattin,
-Jacques-Etienne Baudoux, Geoffrey Marshall, Francisco Lourenco, Glen Mabey,
-Karthik Gurusamy, Fernando Perez, Corey Minyard, Jon Cohen, Guillaume
-Chazarain, Andrew Ryan, Nick Craig-Wood, Andrew Stone, Jorgen Grahn, John
-Spiegel, Jan Grant, and Shane Kerr. Let me know if I forgot anyone.
-
-Pexpect is free, open source, and all that good stuff.
-http://pexpect.sourceforge.net/
-
-PEXPECT LICENSE
-
- This license is approved by the OSI and FSF as GPL-compatible.
- http://opensource.org/licenses/isc-license.txt
-
- Copyright (c) 2012, Noah Spurrier <[email protected]>
- PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
- PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
- COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-'''
-
-import sys
-PY3 = (sys.version_info[0] >= 3)
-
-from .exceptions import ExceptionPexpect, EOF, TIMEOUT
-from .utils import split_command_line, which, is_executable_file
-from .expect import Expecter, searcher_re, searcher_string
-
-if sys.platform != 'win32':
- # On Unix, these are available at the top level for backwards compatibility
- from .pty_spawn import spawn, spawnu
- from .run import run, runu
-
+'''Pexpect is a Python module for spawning child applications and controlling
+them automatically. Pexpect can be used for automating interactive applications
+such as ssh, ftp, passwd, telnet, etc. It can be used to a automate setup
+scripts for duplicating software package installations on different servers. It
+can be used for automated software testing. Pexpect is in the spirit of Don
+Libes' Expect, but Pexpect is pure Python. Other Expect-like modules for Python
+require TCL and Expect or require C extensions to be compiled. Pexpect does not
+use C, Expect, or TCL extensions. It should work on any platform that supports
+the standard Python pty module. The Pexpect interface focuses on ease of use so
+that simple tasks are easy.
+
+There are two main interfaces to the Pexpect system; these are the function,
+run() and the class, spawn. The spawn class is more powerful. The run()
+function is simpler than spawn, and is good for quickly calling program. When
+you call the run() function it executes a given program and then returns the
+output. This is a handy replacement for os.system().
+
+For example::
+
+ pexpect.run('ls -la')
+
+The spawn class is the more powerful interface to the Pexpect system. You can
+use this to spawn a child program then interact with it by sending input and
+expecting responses (waiting for patterns in the child's output).
+
+For example::
+
+ child = pexpect.spawn('scp foo [email protected]:.')
+ child.expect('Password:')
+ child.sendline(mypassword)
+
+This works even for commands that ask for passwords or other input outside of
+the normal stdio streams. For example, ssh reads input directly from the TTY
+device which bypasses stdin.
+
+Credits: Noah Spurrier, Richard Holden, Marco Molteni, Kimberley Burchett,
+Robert Stone, Hartmut Goebel, Chad Schroeder, Erick Tryzelaar, Dave Kirby, Ids
+vander Molen, George Todd, Noel Taylor, Nicolas D. Cesar, Alexander Gattin,
+Jacques-Etienne Baudoux, Geoffrey Marshall, Francisco Lourenco, Glen Mabey,
+Karthik Gurusamy, Fernando Perez, Corey Minyard, Jon Cohen, Guillaume
+Chazarain, Andrew Ryan, Nick Craig-Wood, Andrew Stone, Jorgen Grahn, John
+Spiegel, Jan Grant, and Shane Kerr. Let me know if I forgot anyone.
+
+Pexpect is free, open source, and all that good stuff.
+http://pexpect.sourceforge.net/
+
+PEXPECT LICENSE
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2012, Noah Spurrier <[email protected]>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+'''
+
+import sys
+PY3 = (sys.version_info[0] >= 3)
+
+from .exceptions import ExceptionPexpect, EOF, TIMEOUT
+from .utils import split_command_line, which, is_executable_file
+from .expect import Expecter, searcher_re, searcher_string
+
+if sys.platform != 'win32':
+ # On Unix, these are available at the top level for backwards compatibility
+ from .pty_spawn import spawn, spawnu
+ from .run import run, runu
+
__version__ = '4.8.0'
-__revision__ = ''
-__all__ = ['ExceptionPexpect', 'EOF', 'TIMEOUT', 'spawn', 'spawnu', 'run', 'runu',
- 'which', 'split_command_line', '__version__', '__revision__']
-
-
-
-# vim: set shiftround expandtab tabstop=4 shiftwidth=4 ft=python autoindent :
+__revision__ = ''
+__all__ = ['ExceptionPexpect', 'EOF', 'TIMEOUT', 'spawn', 'spawnu', 'run', 'runu',
+ 'which', 'split_command_line', '__version__', '__revision__']
+
+
+
+# vim: set shiftround expandtab tabstop=4 shiftwidth=4 ft=python autoindent :
diff --git a/contrib/python/pexpect/pexpect/_async.py b/contrib/python/pexpect/pexpect/_async.py
index dfbfeef5fb9..4260ad6107b 100644
--- a/contrib/python/pexpect/pexpect/_async.py
+++ b/contrib/python/pexpect/pexpect/_async.py
@@ -1,16 +1,16 @@
-import asyncio
-import errno
+import asyncio
+import errno
import signal
-
-from pexpect import EOF
-
-def expect_async(expecter, timeout=None):
- # First process data that was previously read - if it maches, we don't need
- # async stuff.
+
+from pexpect import EOF
+
+def expect_async(expecter, timeout=None):
+ # First process data that was previously read - if it maches, we don't need
+ # async stuff.
idx = expecter.existing_data()
- if idx is not None:
- return idx
+ if idx is not None:
+ return idx
if not expecter.spawn.async_pw_transport:
pw = PatternWaiter()
pw.set_expecter(expecter)
@@ -21,12 +21,12 @@ def expect_async(expecter, timeout=None):
pw, transport = expecter.spawn.async_pw_transport
pw.set_expecter(expecter)
transport.resume_reading()
- try:
- return (yield from asyncio.wait_for(pw.fut, timeout))
- except asyncio.TimeoutError as e:
- transport.pause_reading()
- return expecter.timeout(e)
-
+ try:
+ return (yield from asyncio.wait_for(pw.fut, timeout))
+ except asyncio.TimeoutError as e:
+ transport.pause_reading()
+ return expecter.timeout(e)
+
@asyncio.coroutine
def repl_run_command_async(repl, cmdlines, timeout=-1):
res = []
@@ -45,59 +45,59 @@ def repl_run_command_async(repl, cmdlines, timeout=-1):
raise ValueError("Continuation prompt found - input was incomplete:")
return u''.join(res + [repl.child.before])
-class PatternWaiter(asyncio.Protocol):
+class PatternWaiter(asyncio.Protocol):
transport = None
def set_expecter(self, expecter):
- self.expecter = expecter
- self.fut = asyncio.Future()
+ self.expecter = expecter
+ self.fut = asyncio.Future()
- def found(self, result):
- if not self.fut.done():
- self.fut.set_result(result)
+ def found(self, result):
+ if not self.fut.done():
+ self.fut.set_result(result)
self.transport.pause_reading()
- def error(self, exc):
- if not self.fut.done():
- self.fut.set_exception(exc)
+ def error(self, exc):
+ if not self.fut.done():
+ self.fut.set_exception(exc)
self.transport.pause_reading()
def connection_made(self, transport):
self.transport = transport
- def data_received(self, data):
- spawn = self.expecter.spawn
- s = spawn._decoder.decode(data)
- spawn._log(s, 'read')
-
- if self.fut.done():
+ def data_received(self, data):
+ spawn = self.expecter.spawn
+ s = spawn._decoder.decode(data)
+ spawn._log(s, 'read')
+
+ if self.fut.done():
spawn._before.write(s)
spawn._buffer.write(s)
- return
-
- try:
+ return
+
+ try:
index = self.expecter.new_data(s)
- if index is not None:
- # Found a match
- self.found(index)
- except Exception as e:
- self.expecter.errored()
- self.error(e)
+ if index is not None:
+ # Found a match
+ self.found(index)
+ except Exception as e:
+ self.expecter.errored()
+ self.error(e)
- def eof_received(self):
- # N.B. If this gets called, async will close the pipe (the spawn object)
- # for us
- try:
- self.expecter.spawn.flag_eof = True
- index = self.expecter.eof()
- except EOF as e:
- self.error(e)
- else:
- self.found(index)
+ def eof_received(self):
+ # N.B. If this gets called, async will close the pipe (the spawn object)
+ # for us
+ try:
+ self.expecter.spawn.flag_eof = True
+ index = self.expecter.eof()
+ except EOF as e:
+ self.error(e)
+ else:
+ self.found(index)
- def connection_lost(self, exc):
- if isinstance(exc, OSError) and exc.errno == errno.EIO:
- # We may get here without eof_received being called, e.g on Linux
- self.eof_received()
- elif exc is not None:
- self.error(exc)
+ def connection_lost(self, exc):
+ if isinstance(exc, OSError) and exc.errno == errno.EIO:
+ # We may get here without eof_received being called, e.g on Linux
+ self.eof_received()
+ elif exc is not None:
+ self.error(exc)
diff --git a/contrib/python/pexpect/pexpect/exceptions.py b/contrib/python/pexpect/pexpect/exceptions.py
index cb360f02614..f1c10df2e1f 100644
--- a/contrib/python/pexpect/pexpect/exceptions.py
+++ b/contrib/python/pexpect/pexpect/exceptions.py
@@ -1,35 +1,35 @@
-"""Exception classes used by Pexpect"""
-
-import traceback
-import sys
-
-class ExceptionPexpect(Exception):
- '''Base class for all exceptions raised by this module.
- '''
-
- def __init__(self, value):
- super(ExceptionPexpect, self).__init__(value)
- self.value = value
-
- def __str__(self):
- return str(self.value)
-
- def get_trace(self):
- '''This returns an abbreviated stack trace with lines that only concern
- the caller. In other words, the stack trace inside the Pexpect module
- is not included. '''
-
- tblist = traceback.extract_tb(sys.exc_info()[2])
- tblist = [item for item in tblist if ('pexpect/__init__' not in item[0])
- and ('pexpect/expect' not in item[0])]
- tblist = traceback.format_list(tblist)
- return ''.join(tblist)
-
-
-class EOF(ExceptionPexpect):
- '''Raised when EOF is read from a child.
- This usually means the child has exited.'''
-
-
-class TIMEOUT(ExceptionPexpect):
- '''Raised when a read time exceeds the timeout. '''
+"""Exception classes used by Pexpect"""
+
+import traceback
+import sys
+
+class ExceptionPexpect(Exception):
+ '''Base class for all exceptions raised by this module.
+ '''
+
+ def __init__(self, value):
+ super(ExceptionPexpect, self).__init__(value)
+ self.value = value
+
+ def __str__(self):
+ return str(self.value)
+
+ def get_trace(self):
+ '''This returns an abbreviated stack trace with lines that only concern
+ the caller. In other words, the stack trace inside the Pexpect module
+ is not included. '''
+
+ tblist = traceback.extract_tb(sys.exc_info()[2])
+ tblist = [item for item in tblist if ('pexpect/__init__' not in item[0])
+ and ('pexpect/expect' not in item[0])]
+ tblist = traceback.format_list(tblist)
+ return ''.join(tblist)
+
+
+class EOF(ExceptionPexpect):
+ '''Raised when EOF is read from a child.
+ This usually means the child has exited.'''
+
+
+class TIMEOUT(ExceptionPexpect):
+ '''Raised when a read time exceeds the timeout. '''
diff --git a/contrib/python/pexpect/pexpect/expect.py b/contrib/python/pexpect/pexpect/expect.py
index d3409db9d73..00ad4f07483 100644
--- a/contrib/python/pexpect/pexpect/expect.py
+++ b/contrib/python/pexpect/pexpect/expect.py
@@ -1,27 +1,27 @@
-import time
-
-from .exceptions import EOF, TIMEOUT
-
-class Expecter(object):
- def __init__(self, spawn, searcher, searchwindowsize=-1):
- self.spawn = spawn
- self.searcher = searcher
+import time
+
+from .exceptions import EOF, TIMEOUT
+
+class Expecter(object):
+ def __init__(self, spawn, searcher, searchwindowsize=-1):
+ self.spawn = spawn
+ self.searcher = searcher
# A value of -1 means to use the figure from spawn, which should
# be None or a positive number.
- if searchwindowsize == -1:
- searchwindowsize = spawn.searchwindowsize
- self.searchwindowsize = searchwindowsize
+ if searchwindowsize == -1:
+ searchwindowsize = spawn.searchwindowsize
+ self.searchwindowsize = searchwindowsize
self.lookback = None
if hasattr(searcher, 'longest_string'):
self.lookback = searcher.longest_string
def do_search(self, window, freshlen):
- spawn = self.spawn
- searcher = self.searcher
+ spawn = self.spawn
+ searcher = self.searcher
if freshlen > len(window):
freshlen = len(window)
index = searcher.search(window, freshlen, self.searchwindowsize)
- if index >= 0:
+ if index >= 0:
spawn._buffer = spawn.buffer_type()
spawn._buffer.write(window[searcher.end:])
spawn.before = spawn._before.getvalue()[
@@ -29,10 +29,10 @@ class Expecter(object):
spawn._before = spawn.buffer_type()
spawn._before.write(window[searcher.end:])
spawn.after = window[searcher.start:searcher.end]
- spawn.match = searcher.match
- spawn.match_index = index
- # Found a match
- return index
+ spawn.match = searcher.match
+ spawn.match_index = index
+ # Found a match
+ return index
elif self.searchwindowsize or self.lookback:
maintain = self.searchwindowsize or self.lookback
if spawn._buffer.tell() > maintain:
@@ -97,275 +97,275 @@ class Expecter(object):
window = spawn._buffer.read()
return self.do_search(window, freshlen)
- def eof(self, err=None):
- spawn = self.spawn
-
+ def eof(self, err=None):
+ spawn = self.spawn
+
spawn.before = spawn._before.getvalue()
spawn._buffer = spawn.buffer_type()
spawn._before = spawn.buffer_type()
- spawn.after = EOF
- index = self.searcher.eof_index
- if index >= 0:
- spawn.match = EOF
- spawn.match_index = index
- return index
- else:
- spawn.match = None
- spawn.match_index = None
- msg = str(spawn)
+ spawn.after = EOF
+ index = self.searcher.eof_index
+ if index >= 0:
+ spawn.match = EOF
+ spawn.match_index = index
+ return index
+ else:
+ spawn.match = None
+ spawn.match_index = None
+ msg = str(spawn)
msg += '\nsearcher: %s' % self.searcher
- if err is not None:
- msg = str(err) + '\n' + msg
+ if err is not None:
+ msg = str(err) + '\n' + msg
exc = EOF(msg)
exc.__cause__ = None # in Python 3.x we can use "raise exc from None"
raise exc
- def timeout(self, err=None):
- spawn = self.spawn
-
+ def timeout(self, err=None):
+ spawn = self.spawn
+
spawn.before = spawn._before.getvalue()
- spawn.after = TIMEOUT
- index = self.searcher.timeout_index
- if index >= 0:
- spawn.match = TIMEOUT
- spawn.match_index = index
- return index
- else:
- spawn.match = None
- spawn.match_index = None
- msg = str(spawn)
+ spawn.after = TIMEOUT
+ index = self.searcher.timeout_index
+ if index >= 0:
+ spawn.match = TIMEOUT
+ spawn.match_index = index
+ return index
+ else:
+ spawn.match = None
+ spawn.match_index = None
+ msg = str(spawn)
msg += '\nsearcher: %s' % self.searcher
- if err is not None:
- msg = str(err) + '\n' + msg
-
+ if err is not None:
+ msg = str(err) + '\n' + msg
+
exc = TIMEOUT(msg)
exc.__cause__ = None # in Python 3.x we can use "raise exc from None"
raise exc
- def errored(self):
- spawn = self.spawn
+ def errored(self):
+ spawn = self.spawn
spawn.before = spawn._before.getvalue()
- spawn.after = None
- spawn.match = None
- spawn.match_index = None
-
- def expect_loop(self, timeout=-1):
- """Blocking expect"""
- spawn = self.spawn
+ spawn.after = None
+ spawn.match = None
+ spawn.match_index = None
- if timeout is not None:
- end_time = time.time() + timeout
-
- try:
+ def expect_loop(self, timeout=-1):
+ """Blocking expect"""
+ spawn = self.spawn
+
+ if timeout is not None:
+ end_time = time.time() + timeout
+
+ try:
idx = self.existing_data()
if idx is not None:
return idx
- while True:
- # No match at this point
- if (timeout is not None) and (timeout < 0):
- return self.timeout()
- # Still have time left, so read more data
- incoming = spawn.read_nonblocking(spawn.maxread, timeout)
+ while True:
+ # No match at this point
+ if (timeout is not None) and (timeout < 0):
+ return self.timeout()
+ # Still have time left, so read more data
+ incoming = spawn.read_nonblocking(spawn.maxread, timeout)
if self.spawn.delayafterread is not None:
time.sleep(self.spawn.delayafterread)
idx = self.new_data(incoming)
# Keep reading until exception or return.
if idx is not None:
return idx
- if timeout is not None:
- timeout = end_time - time.time()
- except EOF as e:
- return self.eof(e)
- except TIMEOUT as e:
- return self.timeout(e)
- except:
- self.errored()
- raise
-
-
-class searcher_string(object):
- '''This is a plain string search helper for the spawn.expect_any() method.
- This helper class is for speed. For more powerful regex patterns
- see the helper class, searcher_re.
-
- Attributes:
-
- eof_index - index of EOF, or -1
- timeout_index - index of TIMEOUT, or -1
-
- After a successful match by the search() method the following attributes
- are available:
-
- start - index into the buffer, first byte of match
- end - index into the buffer, first byte after match
- match - the matching string itself
-
- '''
-
- def __init__(self, strings):
- '''This creates an instance of searcher_string. This argument 'strings'
- may be a list; a sequence of strings; or the EOF or TIMEOUT types. '''
-
- self.eof_index = -1
- self.timeout_index = -1
- self._strings = []
+ if timeout is not None:
+ timeout = end_time - time.time()
+ except EOF as e:
+ return self.eof(e)
+ except TIMEOUT as e:
+ return self.timeout(e)
+ except:
+ self.errored()
+ raise
+
+
+class searcher_string(object):
+ '''This is a plain string search helper for the spawn.expect_any() method.
+ This helper class is for speed. For more powerful regex patterns
+ see the helper class, searcher_re.
+
+ Attributes:
+
+ eof_index - index of EOF, or -1
+ timeout_index - index of TIMEOUT, or -1
+
+ After a successful match by the search() method the following attributes
+ are available:
+
+ start - index into the buffer, first byte of match
+ end - index into the buffer, first byte after match
+ match - the matching string itself
+
+ '''
+
+ def __init__(self, strings):
+ '''This creates an instance of searcher_string. This argument 'strings'
+ may be a list; a sequence of strings; or the EOF or TIMEOUT types. '''
+
+ self.eof_index = -1
+ self.timeout_index = -1
+ self._strings = []
self.longest_string = 0
- for n, s in enumerate(strings):
- if s is EOF:
- self.eof_index = n
- continue
- if s is TIMEOUT:
- self.timeout_index = n
- continue
- self._strings.append((n, s))
+ for n, s in enumerate(strings):
+ if s is EOF:
+ self.eof_index = n
+ continue
+ if s is TIMEOUT:
+ self.timeout_index = n
+ continue
+ self._strings.append((n, s))
if len(s) > self.longest_string:
self.longest_string = len(s)
-
- def __str__(self):
- '''This returns a human-readable string that represents the state of
- the object.'''
-
+
+ def __str__(self):
+ '''This returns a human-readable string that represents the state of
+ the object.'''
+
ss = [(ns[0], ' %d: %r' % ns) for ns in self._strings]
- ss.append((-1, 'searcher_string:'))
- if self.eof_index >= 0:
- ss.append((self.eof_index, ' %d: EOF' % self.eof_index))
- if self.timeout_index >= 0:
- ss.append((self.timeout_index,
- ' %d: TIMEOUT' % self.timeout_index))
- ss.sort()
- ss = list(zip(*ss))[1]
- return '\n'.join(ss)
-
- def search(self, buffer, freshlen, searchwindowsize=None):
+ ss.append((-1, 'searcher_string:'))
+ if self.eof_index >= 0:
+ ss.append((self.eof_index, ' %d: EOF' % self.eof_index))
+ if self.timeout_index >= 0:
+ ss.append((self.timeout_index,
+ ' %d: TIMEOUT' % self.timeout_index))
+ ss.sort()
+ ss = list(zip(*ss))[1]
+ return '\n'.join(ss)
+
+ def search(self, buffer, freshlen, searchwindowsize=None):
'''This searches 'buffer' for the first occurrence of one of the search
- strings. 'freshlen' must indicate the number of bytes at the end of
- 'buffer' which have not been searched before. It helps to avoid
- searching the same, possibly big, buffer over and over again.
-
- See class spawn for the 'searchwindowsize' argument.
-
- If there is a match this returns the index of that string, and sets
- 'start', 'end' and 'match'. Otherwise, this returns -1. '''
-
- first_match = None
-
- # 'freshlen' helps a lot here. Further optimizations could
- # possibly include:
- #
- # using something like the Boyer-Moore Fast String Searching
- # Algorithm; pre-compiling the search through a list of
- # strings into something that can scan the input once to
- # search for all N strings; realize that if we search for
- # ['bar', 'baz'] and the input is '...foo' we need not bother
- # rescanning until we've read three more bytes.
- #
- # Sadly, I don't know enough about this interesting topic. /grahn
-
- for index, s in self._strings:
- if searchwindowsize is None:
- # the match, if any, can only be in the fresh data,
- # or at the very end of the old data
- offset = -(freshlen + len(s))
- else:
- # better obey searchwindowsize
- offset = -searchwindowsize
- n = buffer.find(s, offset)
- if n >= 0 and (first_match is None or n < first_match):
- first_match = n
- best_index, best_match = index, s
- if first_match is None:
- return -1
- self.match = best_match
- self.start = first_match
- self.end = self.start + len(self.match)
- return best_index
-
-
-class searcher_re(object):
- '''This is regular expression string search helper for the
- spawn.expect_any() method. This helper class is for powerful
- pattern matching. For speed, see the helper class, searcher_string.
-
- Attributes:
-
- eof_index - index of EOF, or -1
- timeout_index - index of TIMEOUT, or -1
-
- After a successful match by the search() method the following attributes
- are available:
-
- start - index into the buffer, first byte of match
- end - index into the buffer, first byte after match
+ strings. 'freshlen' must indicate the number of bytes at the end of
+ 'buffer' which have not been searched before. It helps to avoid
+ searching the same, possibly big, buffer over and over again.
+
+ See class spawn for the 'searchwindowsize' argument.
+
+ If there is a match this returns the index of that string, and sets
+ 'start', 'end' and 'match'. Otherwise, this returns -1. '''
+
+ first_match = None
+
+ # 'freshlen' helps a lot here. Further optimizations could
+ # possibly include:
+ #
+ # using something like the Boyer-Moore Fast String Searching
+ # Algorithm; pre-compiling the search through a list of
+ # strings into something that can scan the input once to
+ # search for all N strings; realize that if we search for
+ # ['bar', 'baz'] and the input is '...foo' we need not bother
+ # rescanning until we've read three more bytes.
+ #
+ # Sadly, I don't know enough about this interesting topic. /grahn
+
+ for index, s in self._strings:
+ if searchwindowsize is None:
+ # the match, if any, can only be in the fresh data,
+ # or at the very end of the old data
+ offset = -(freshlen + len(s))
+ else:
+ # better obey searchwindowsize
+ offset = -searchwindowsize
+ n = buffer.find(s, offset)
+ if n >= 0 and (first_match is None or n < first_match):
+ first_match = n
+ best_index, best_match = index, s
+ if first_match is None:
+ return -1
+ self.match = best_match
+ self.start = first_match
+ self.end = self.start + len(self.match)
+ return best_index
+
+
+class searcher_re(object):
+ '''This is regular expression string search helper for the
+ spawn.expect_any() method. This helper class is for powerful
+ pattern matching. For speed, see the helper class, searcher_string.
+
+ Attributes:
+
+ eof_index - index of EOF, or -1
+ timeout_index - index of TIMEOUT, or -1
+
+ After a successful match by the search() method the following attributes
+ are available:
+
+ start - index into the buffer, first byte of match
+ end - index into the buffer, first byte after match
match - the re.match object returned by a successful re.search
-
- '''
-
- def __init__(self, patterns):
- '''This creates an instance that searches for 'patterns' Where
- 'patterns' may be a list or other sequence of compiled regular
- expressions, or the EOF or TIMEOUT types.'''
-
- self.eof_index = -1
- self.timeout_index = -1
- self._searches = []
+
+ '''
+
+ def __init__(self, patterns):
+ '''This creates an instance that searches for 'patterns' Where
+ 'patterns' may be a list or other sequence of compiled regular
+ expressions, or the EOF or TIMEOUT types.'''
+
+ self.eof_index = -1
+ self.timeout_index = -1
+ self._searches = []
for n, s in enumerate(patterns):
- if s is EOF:
- self.eof_index = n
- continue
- if s is TIMEOUT:
- self.timeout_index = n
- continue
- self._searches.append((n, s))
-
- def __str__(self):
- '''This returns a human-readable string that represents the state of
- the object.'''
-
- #ss = [(n, ' %d: re.compile("%s")' %
- # (n, repr(s.pattern))) for n, s in self._searches]
- ss = list()
- for n, s in self._searches:
+ if s is EOF:
+ self.eof_index = n
+ continue
+ if s is TIMEOUT:
+ self.timeout_index = n
+ continue
+ self._searches.append((n, s))
+
+ def __str__(self):
+ '''This returns a human-readable string that represents the state of
+ the object.'''
+
+ #ss = [(n, ' %d: re.compile("%s")' %
+ # (n, repr(s.pattern))) for n, s in self._searches]
+ ss = list()
+ for n, s in self._searches:
ss.append((n, ' %d: re.compile(%r)' % (n, s.pattern)))
- ss.append((-1, 'searcher_re:'))
- if self.eof_index >= 0:
- ss.append((self.eof_index, ' %d: EOF' % self.eof_index))
- if self.timeout_index >= 0:
- ss.append((self.timeout_index, ' %d: TIMEOUT' %
- self.timeout_index))
- ss.sort()
- ss = list(zip(*ss))[1]
- return '\n'.join(ss)
-
- def search(self, buffer, freshlen, searchwindowsize=None):
+ ss.append((-1, 'searcher_re:'))
+ if self.eof_index >= 0:
+ ss.append((self.eof_index, ' %d: EOF' % self.eof_index))
+ if self.timeout_index >= 0:
+ ss.append((self.timeout_index, ' %d: TIMEOUT' %
+ self.timeout_index))
+ ss.sort()
+ ss = list(zip(*ss))[1]
+ return '\n'.join(ss)
+
+ def search(self, buffer, freshlen, searchwindowsize=None):
'''This searches 'buffer' for the first occurrence of one of the regular
- expressions. 'freshlen' must indicate the number of bytes at the end of
- 'buffer' which have not been searched before.
-
- See class spawn for the 'searchwindowsize' argument.
-
- If there is a match this returns the index of that string, and sets
- 'start', 'end' and 'match'. Otherwise, returns -1.'''
-
- first_match = None
- # 'freshlen' doesn't help here -- we cannot predict the
- # length of a match, and the re module provides no help.
- if searchwindowsize is None:
- searchstart = 0
- else:
- searchstart = max(0, len(buffer) - searchwindowsize)
- for index, s in self._searches:
- match = s.search(buffer, searchstart)
- if match is None:
- continue
- n = match.start()
- if first_match is None or n < first_match:
- first_match = n
- the_match = match
- best_index = index
- if first_match is None:
- return -1
- self.start = first_match
- self.match = the_match
- self.end = self.match.end()
+ expressions. 'freshlen' must indicate the number of bytes at the end of
+ 'buffer' which have not been searched before.
+
+ See class spawn for the 'searchwindowsize' argument.
+
+ If there is a match this returns the index of that string, and sets
+ 'start', 'end' and 'match'. Otherwise, returns -1.'''
+
+ first_match = None
+ # 'freshlen' doesn't help here -- we cannot predict the
+ # length of a match, and the re module provides no help.
+ if searchwindowsize is None:
+ searchstart = 0
+ else:
+ searchstart = max(0, len(buffer) - searchwindowsize)
+ for index, s in self._searches:
+ match = s.search(buffer, searchstart)
+ if match is None:
+ continue
+ n = match.start()
+ if first_match is None or n < first_match:
+ first_match = n
+ the_match = match
+ best_index = index
+ if first_match is None:
+ return -1
+ self.start = first_match
+ self.match = the_match
+ self.end = self.match.end()
return best_index
diff --git a/contrib/python/pexpect/pexpect/fdpexpect.py b/contrib/python/pexpect/pexpect/fdpexpect.py
index cddd50e1005..a3096537f66 100644
--- a/contrib/python/pexpect/pexpect/fdpexpect.py
+++ b/contrib/python/pexpect/pexpect/fdpexpect.py
@@ -1,119 +1,119 @@
-'''This is like pexpect, but it will work with any file descriptor that you
+'''This is like pexpect, but it will work with any file descriptor that you
pass it. You are responsible for opening and close the file descriptor.
-This allows you to use Pexpect with sockets and named pipes (FIFOs).
-
-PEXPECT LICENSE
-
- This license is approved by the OSI and FSF as GPL-compatible.
- http://opensource.org/licenses/isc-license.txt
-
- Copyright (c) 2012, Noah Spurrier <[email protected]>
- PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
- PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
- COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-'''
-
-from .spawnbase import SpawnBase
+This allows you to use Pexpect with sockets and named pipes (FIFOs).
+
+PEXPECT LICENSE
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2012, Noah Spurrier <[email protected]>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+'''
+
+from .spawnbase import SpawnBase
from .exceptions import ExceptionPexpect, TIMEOUT
from .utils import select_ignore_interrupts, poll_ignore_interrupts
-import os
-
-__all__ = ['fdspawn']
-
-class fdspawn(SpawnBase):
- '''This is like pexpect.spawn but allows you to supply your own open file
- descriptor. For example, you could use it to read through a file looking
- for patterns, or to control a modem or serial device. '''
-
- def __init__ (self, fd, args=None, timeout=30, maxread=2000, searchwindowsize=None,
+import os
+
+__all__ = ['fdspawn']
+
+class fdspawn(SpawnBase):
+ '''This is like pexpect.spawn but allows you to supply your own open file
+ descriptor. For example, you could use it to read through a file looking
+ for patterns, or to control a modem or serial device. '''
+
+ def __init__ (self, fd, args=None, timeout=30, maxread=2000, searchwindowsize=None,
logfile=None, encoding=None, codec_errors='strict', use_poll=False):
- '''This takes a file descriptor (an int) or an object that support the
- fileno() method (returning an int). All Python file-like objects
- support fileno(). '''
-
- if type(fd) != type(0) and hasattr(fd, 'fileno'):
- fd = fd.fileno()
-
- if type(fd) != type(0):
- raise ExceptionPexpect('The fd argument is not an int. If this is a command string then maybe you want to use pexpect.spawn.')
-
- try: # make sure fd is a valid file descriptor
- os.fstat(fd)
- except OSError:
- raise ExceptionPexpect('The fd argument is not a valid file descriptor.')
-
- self.args = None
- self.command = None
- SpawnBase.__init__(self, timeout, maxread, searchwindowsize, logfile,
- encoding=encoding, codec_errors=codec_errors)
- self.child_fd = fd
- self.own_fd = False
- self.closed = False
- self.name = '<file descriptor %d>' % fd
+ '''This takes a file descriptor (an int) or an object that support the
+ fileno() method (returning an int). All Python file-like objects
+ support fileno(). '''
+
+ if type(fd) != type(0) and hasattr(fd, 'fileno'):
+ fd = fd.fileno()
+
+ if type(fd) != type(0):
+ raise ExceptionPexpect('The fd argument is not an int. If this is a command string then maybe you want to use pexpect.spawn.')
+
+ try: # make sure fd is a valid file descriptor
+ os.fstat(fd)
+ except OSError:
+ raise ExceptionPexpect('The fd argument is not a valid file descriptor.')
+
+ self.args = None
+ self.command = None
+ SpawnBase.__init__(self, timeout, maxread, searchwindowsize, logfile,
+ encoding=encoding, codec_errors=codec_errors)
+ self.child_fd = fd
+ self.own_fd = False
+ self.closed = False
+ self.name = '<file descriptor %d>' % fd
self.use_poll = use_poll
+
+ def close (self):
+ """Close the file descriptor.
+
+ Calling this method a second time does nothing, but if the file
+ descriptor was closed elsewhere, :class:`OSError` will be raised.
+ """
+ if self.child_fd == -1:
+ return
+
+ self.flush()
+ os.close(self.child_fd)
+ self.child_fd = -1
+ self.closed = True
+
+ def isalive (self):
+ '''This checks if the file descriptor is still valid. If :func:`os.fstat`
+ does not raise an exception then we assume it is alive. '''
+
+ if self.child_fd == -1:
+ return False
+ try:
+ os.fstat(self.child_fd)
+ return True
+ except:
+ return False
+
+ def terminate (self, force=False): # pragma: no cover
+ '''Deprecated and invalid. Just raises an exception.'''
+ raise ExceptionPexpect('This method is not valid for file descriptors.')
- def close (self):
- """Close the file descriptor.
-
- Calling this method a second time does nothing, but if the file
- descriptor was closed elsewhere, :class:`OSError` will be raised.
- """
- if self.child_fd == -1:
- return
-
- self.flush()
- os.close(self.child_fd)
- self.child_fd = -1
- self.closed = True
-
- def isalive (self):
- '''This checks if the file descriptor is still valid. If :func:`os.fstat`
- does not raise an exception then we assume it is alive. '''
-
- if self.child_fd == -1:
- return False
- try:
- os.fstat(self.child_fd)
- return True
- except:
- return False
-
- def terminate (self, force=False): # pragma: no cover
- '''Deprecated and invalid. Just raises an exception.'''
- raise ExceptionPexpect('This method is not valid for file descriptors.')
-
- # These four methods are left around for backwards compatibility, but not
- # documented as part of fdpexpect. You're encouraged to use os.write
- # directly.
- def send(self, s):
- "Write to fd, return number of bytes written"
- s = self._coerce_send_string(s)
- self._log(s, 'send')
+ # These four methods are left around for backwards compatibility, but not
+ # documented as part of fdpexpect. You're encouraged to use os.write
+ # directly.
+ def send(self, s):
+ "Write to fd, return number of bytes written"
+ s = self._coerce_send_string(s)
+ self._log(s, 'send')
- b = self._encoder.encode(s, final=False)
- return os.write(self.child_fd, b)
+ b = self._encoder.encode(s, final=False)
+ return os.write(self.child_fd, b)
- def sendline(self, s):
- "Write to fd with trailing newline, return number of bytes written"
- s = self._coerce_send_string(s)
- return self.send(s + self.linesep)
+ def sendline(self, s):
+ "Write to fd with trailing newline, return number of bytes written"
+ s = self._coerce_send_string(s)
+ return self.send(s + self.linesep)
- def write(self, s):
- "Write to fd, return None"
- self.send(s)
+ def write(self, s):
+ "Write to fd, return None"
+ self.send(s)
- def writelines(self, sequence):
- "Call self.write() for each item in sequence"
- for s in sequence:
- self.write(s)
+ def writelines(self, sequence):
+ "Call self.write() for each item in sequence"
+ for s in sequence:
+ self.write(s)
def read_nonblocking(self, size=1, timeout=-1):
"""
diff --git a/contrib/python/pexpect/pexpect/popen_spawn.py b/contrib/python/pexpect/pexpect/popen_spawn.py
index 4bb58cfe76c..59cd85738a2 100644
--- a/contrib/python/pexpect/pexpect/popen_spawn.py
+++ b/contrib/python/pexpect/pexpect/popen_spawn.py
@@ -1,30 +1,30 @@
-"""Provides an interface like pexpect.spawn interface using subprocess.Popen
-"""
-import os
-import threading
-import subprocess
-import sys
-import time
-import signal
-import shlex
-
-try:
- from queue import Queue, Empty # Python 3
-except ImportError:
- from Queue import Queue, Empty # Python 2
-
-from .spawnbase import SpawnBase, PY3
-from .exceptions import EOF
+"""Provides an interface like pexpect.spawn interface using subprocess.Popen
+"""
+import os
+import threading
+import subprocess
+import sys
+import time
+import signal
+import shlex
+
+try:
+ from queue import Queue, Empty # Python 3
+except ImportError:
+ from Queue import Queue, Empty # Python 2
+
+from .spawnbase import SpawnBase, PY3
+from .exceptions import EOF
from .utils import string_types
-
-class PopenSpawn(SpawnBase):
- def __init__(self, cmd, timeout=30, maxread=2000, searchwindowsize=None,
+
+class PopenSpawn(SpawnBase):
+ def __init__(self, cmd, timeout=30, maxread=2000, searchwindowsize=None,
logfile=None, cwd=None, env=None, encoding=None,
codec_errors='strict', preexec_fn=None):
- super(PopenSpawn, self).__init__(timeout=timeout, maxread=maxread,
- searchwindowsize=searchwindowsize, logfile=logfile,
- encoding=encoding, codec_errors=codec_errors)
-
+ super(PopenSpawn, self).__init__(timeout=timeout, maxread=maxread,
+ searchwindowsize=searchwindowsize, logfile=logfile,
+ encoding=encoding, codec_errors=codec_errors)
+
# Note that `SpawnBase` initializes `self.crlf` to `\r\n`
# because the default behaviour for a PTY is to convert
# incoming LF to `\r\n` (see the `onlcr` flag and
@@ -37,152 +37,152 @@ class PopenSpawn(SpawnBase):
else:
self.crlf = self.string_type (os.linesep)
- kwargs = dict(bufsize=0, stdin=subprocess.PIPE,
- stderr=subprocess.STDOUT, stdout=subprocess.PIPE,
+ kwargs = dict(bufsize=0, stdin=subprocess.PIPE,
+ stderr=subprocess.STDOUT, stdout=subprocess.PIPE,
cwd=cwd, preexec_fn=preexec_fn, env=env)
-
- if sys.platform == 'win32':
- startupinfo = subprocess.STARTUPINFO()
- startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
- kwargs['startupinfo'] = startupinfo
- kwargs['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP
-
+
+ if sys.platform == 'win32':
+ startupinfo = subprocess.STARTUPINFO()
+ startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+ kwargs['startupinfo'] = startupinfo
+ kwargs['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP
+
if isinstance(cmd, string_types) and sys.platform != 'win32':
cmd = shlex.split(cmd, posix=os.name == 'posix')
-
- self.proc = subprocess.Popen(cmd, **kwargs)
+
+ self.proc = subprocess.Popen(cmd, **kwargs)
self.pid = self.proc.pid
- self.closed = False
- self._buf = self.string_type()
-
- self._read_queue = Queue()
- self._read_thread = threading.Thread(target=self._read_incoming)
- self._read_thread.setDaemon(True)
- self._read_thread.start()
-
- _read_reached_eof = False
-
- def read_nonblocking(self, size, timeout):
- buf = self._buf
- if self._read_reached_eof:
- # We have already finished reading. Use up any buffered data,
- # then raise EOF
- if buf:
- self._buf = buf[size:]
- return buf[:size]
- else:
- self.flag_eof = True
- raise EOF('End Of File (EOF).')
-
- if timeout == -1:
- timeout = self.timeout
- elif timeout is None:
- timeout = 1e6
-
- t0 = time.time()
- while (time.time() - t0) < timeout and size and len(buf) < size:
- try:
- incoming = self._read_queue.get_nowait()
- except Empty:
- break
- else:
- if incoming is None:
- self._read_reached_eof = True
- break
-
- buf += self._decoder.decode(incoming, final=False)
-
- r, self._buf = buf[:size], buf[size:]
-
- self._log(r, 'read')
- return r
-
- def _read_incoming(self):
- """Run in a thread to move output from a pipe to a queue."""
- fileno = self.proc.stdout.fileno()
- while 1:
- buf = b''
- try:
- buf = os.read(fileno, 1024)
- except OSError as e:
- self._log(e, 'read')
-
- if not buf:
- # This indicates we have reached EOF
- self._read_queue.put(None)
- return
-
- self._read_queue.put(buf)
-
- def write(self, s):
- '''This is similar to send() except that there is no return value.
- '''
- self.send(s)
-
- def writelines(self, sequence):
- '''This calls write() for each element in the sequence.
-
- The sequence can be any iterable object producing strings, typically a
- list of strings. This does not add line separators. There is no return
- value.
- '''
- for s in sequence:
- self.send(s)
-
- def send(self, s):
- '''Send data to the subprocess' stdin.
-
- Returns the number of bytes written.
- '''
- s = self._coerce_send_string(s)
- self._log(s, 'send')
-
- b = self._encoder.encode(s, final=False)
- if PY3:
- return self.proc.stdin.write(b)
- else:
- # On Python 2, .write() returns None, so we return the length of
- # bytes written ourselves. This assumes they all got written.
- self.proc.stdin.write(b)
- return len(b)
-
- def sendline(self, s=''):
- '''Wraps send(), sending string ``s`` to child process, with os.linesep
- automatically appended. Returns number of bytes written. '''
-
- n = self.send(s)
- return n + self.send(self.linesep)
-
- def wait(self):
- '''Wait for the subprocess to finish.
-
- Returns the exit code.
- '''
- status = self.proc.wait()
- if status >= 0:
- self.exitstatus = status
- self.signalstatus = None
- else:
- self.exitstatus = None
- self.signalstatus = -status
- self.terminated = True
- return status
-
- def kill(self, sig):
- '''Sends a Unix signal to the subprocess.
+ self.closed = False
+ self._buf = self.string_type()
+
+ self._read_queue = Queue()
+ self._read_thread = threading.Thread(target=self._read_incoming)
+ self._read_thread.setDaemon(True)
+ self._read_thread.start()
+
+ _read_reached_eof = False
+
+ def read_nonblocking(self, size, timeout):
+ buf = self._buf
+ if self._read_reached_eof:
+ # We have already finished reading. Use up any buffered data,
+ # then raise EOF
+ if buf:
+ self._buf = buf[size:]
+ return buf[:size]
+ else:
+ self.flag_eof = True
+ raise EOF('End Of File (EOF).')
+
+ if timeout == -1:
+ timeout = self.timeout
+ elif timeout is None:
+ timeout = 1e6
+
+ t0 = time.time()
+ while (time.time() - t0) < timeout and size and len(buf) < size:
+ try:
+ incoming = self._read_queue.get_nowait()
+ except Empty:
+ break
+ else:
+ if incoming is None:
+ self._read_reached_eof = True
+ break
+
+ buf += self._decoder.decode(incoming, final=False)
+
+ r, self._buf = buf[:size], buf[size:]
+
+ self._log(r, 'read')
+ return r
+
+ def _read_incoming(self):
+ """Run in a thread to move output from a pipe to a queue."""
+ fileno = self.proc.stdout.fileno()
+ while 1:
+ buf = b''
+ try:
+ buf = os.read(fileno, 1024)
+ except OSError as e:
+ self._log(e, 'read')
+
+ if not buf:
+ # This indicates we have reached EOF
+ self._read_queue.put(None)
+ return
+
+ self._read_queue.put(buf)
+
+ def write(self, s):
+ '''This is similar to send() except that there is no return value.
+ '''
+ self.send(s)
+
+ def writelines(self, sequence):
+ '''This calls write() for each element in the sequence.
+
+ The sequence can be any iterable object producing strings, typically a
+ list of strings. This does not add line separators. There is no return
+ value.
+ '''
+ for s in sequence:
+ self.send(s)
+
+ def send(self, s):
+ '''Send data to the subprocess' stdin.
- Use constants from the :mod:`signal` module to specify which signal.
- '''
- if sys.platform == 'win32':
- if sig in [signal.SIGINT, signal.CTRL_C_EVENT]:
- sig = signal.CTRL_C_EVENT
- elif sig in [signal.SIGBREAK, signal.CTRL_BREAK_EVENT]:
- sig = signal.CTRL_BREAK_EVENT
- else:
- sig = signal.SIGTERM
+ Returns the number of bytes written.
+ '''
+ s = self._coerce_send_string(s)
+ self._log(s, 'send')
+
+ b = self._encoder.encode(s, final=False)
+ if PY3:
+ return self.proc.stdin.write(b)
+ else:
+ # On Python 2, .write() returns None, so we return the length of
+ # bytes written ourselves. This assumes they all got written.
+ self.proc.stdin.write(b)
+ return len(b)
+
+ def sendline(self, s=''):
+ '''Wraps send(), sending string ``s`` to child process, with os.linesep
+ automatically appended. Returns number of bytes written. '''
+
+ n = self.send(s)
+ return n + self.send(self.linesep)
+
+ def wait(self):
+ '''Wait for the subprocess to finish.
- os.kill(self.proc.pid, sig)
+ Returns the exit code.
+ '''
+ status = self.proc.wait()
+ if status >= 0:
+ self.exitstatus = status
+ self.signalstatus = None
+ else:
+ self.exitstatus = None
+ self.signalstatus = -status
+ self.terminated = True
+ return status
+
+ def kill(self, sig):
+ '''Sends a Unix signal to the subprocess.
- def sendeof(self):
- '''Closes the stdin pipe from the writing end.'''
- self.proc.stdin.close()
+ Use constants from the :mod:`signal` module to specify which signal.
+ '''
+ if sys.platform == 'win32':
+ if sig in [signal.SIGINT, signal.CTRL_C_EVENT]:
+ sig = signal.CTRL_C_EVENT
+ elif sig in [signal.SIGBREAK, signal.CTRL_BREAK_EVENT]:
+ sig = signal.CTRL_BREAK_EVENT
+ else:
+ sig = signal.SIGTERM
+
+ os.kill(self.proc.pid, sig)
+
+ def sendeof(self):
+ '''Closes the stdin pipe from the writing end.'''
+ self.proc.stdin.close()
diff --git a/contrib/python/pexpect/pexpect/pty_spawn.py b/contrib/python/pexpect/pexpect/pty_spawn.py
index 8e28ca7cd7d..3c055cdda33 100644
--- a/contrib/python/pexpect/pexpect/pty_spawn.py
+++ b/contrib/python/pexpect/pexpect/pty_spawn.py
@@ -1,447 +1,447 @@
-import os
-import sys
-import time
-import pty
-import tty
-import errno
-import signal
-from contextlib import contextmanager
-
-import ptyprocess
-from ptyprocess.ptyprocess import use_native_pty_fork
-
-from .exceptions import ExceptionPexpect, EOF, TIMEOUT
-from .spawnbase import SpawnBase
+import os
+import sys
+import time
+import pty
+import tty
+import errno
+import signal
+from contextlib import contextmanager
+
+import ptyprocess
+from ptyprocess.ptyprocess import use_native_pty_fork
+
+from .exceptions import ExceptionPexpect, EOF, TIMEOUT
+from .spawnbase import SpawnBase
from .utils import (
which, split_command_line, select_ignore_interrupts, poll_ignore_interrupts
)
-
-@contextmanager
-def _wrap_ptyprocess_err():
- """Turn ptyprocess errors into our own ExceptionPexpect errors"""
- try:
- yield
- except ptyprocess.PtyProcessError as e:
- raise ExceptionPexpect(*e.args)
-
-PY3 = (sys.version_info[0] >= 3)
-
-class spawn(SpawnBase):
- '''This is the main class interface for Pexpect. Use this class to start
- and control child applications. '''
-
- # This is purely informational now - changing it has no effect
- use_native_pty_fork = use_native_pty_fork
-
- def __init__(self, command, args=[], timeout=30, maxread=2000,
- searchwindowsize=None, logfile=None, cwd=None, env=None,
- ignore_sighup=False, echo=True, preexec_fn=None,
+
+@contextmanager
+def _wrap_ptyprocess_err():
+ """Turn ptyprocess errors into our own ExceptionPexpect errors"""
+ try:
+ yield
+ except ptyprocess.PtyProcessError as e:
+ raise ExceptionPexpect(*e.args)
+
+PY3 = (sys.version_info[0] >= 3)
+
+class spawn(SpawnBase):
+ '''This is the main class interface for Pexpect. Use this class to start
+ and control child applications. '''
+
+ # This is purely informational now - changing it has no effect
+ use_native_pty_fork = use_native_pty_fork
+
+ def __init__(self, command, args=[], timeout=30, maxread=2000,
+ searchwindowsize=None, logfile=None, cwd=None, env=None,
+ ignore_sighup=False, echo=True, preexec_fn=None,
encoding=None, codec_errors='strict', dimensions=None,
use_poll=False):
- '''This is the constructor. The command parameter may be a string that
- includes a command and any arguments to the command. For example::
-
- child = pexpect.spawn('/usr/bin/ftp')
- child = pexpect.spawn('/usr/bin/ssh [email protected]')
- child = pexpect.spawn('ls -latr /tmp')
-
- You may also construct it with a list of arguments like so::
-
- child = pexpect.spawn('/usr/bin/ftp', [])
- child = pexpect.spawn('/usr/bin/ssh', ['[email protected]'])
- child = pexpect.spawn('ls', ['-latr', '/tmp'])
-
- After this the child application will be created and will be ready to
- talk to. For normal use, see expect() and send() and sendline().
-
- Remember that Pexpect does NOT interpret shell meta characters such as
- redirect, pipe, or wild cards (``>``, ``|``, or ``*``). This is a
- common mistake. If you want to run a command and pipe it through
- another command then you must also start a shell. For example::
-
- child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > logs.txt"')
- child.expect(pexpect.EOF)
-
- The second form of spawn (where you pass a list of arguments) is useful
- in situations where you wish to spawn a command and pass it its own
- argument list. This can make syntax more clear. For example, the
- following is equivalent to the previous example::
-
- shell_cmd = 'ls -l | grep LOG > logs.txt'
- child = pexpect.spawn('/bin/bash', ['-c', shell_cmd])
- child.expect(pexpect.EOF)
-
- The maxread attribute sets the read buffer size. This is maximum number
- of bytes that Pexpect will try to read from a TTY at one time. Setting
- the maxread size to 1 will turn off buffering. Setting the maxread
- value higher may help performance in cases where large amounts of
- output are read back from the child. This feature is useful in
- conjunction with searchwindowsize.
-
- When the keyword argument *searchwindowsize* is None (default), the
- full buffer is searched at each iteration of receiving incoming data.
- The default number of bytes scanned at each iteration is very large
- and may be reduced to collaterally reduce search cost. After
- :meth:`~.expect` returns, the full buffer attribute remains up to
- size *maxread* irrespective of *searchwindowsize* value.
-
- When the keyword argument ``timeout`` is specified as a number,
- (default: *30*), then :class:`TIMEOUT` will be raised after the value
- specified has elapsed, in seconds, for any of the :meth:`~.expect`
- family of method calls. When None, TIMEOUT will not be raised, and
- :meth:`~.expect` may block indefinitely until match.
-
-
- The logfile member turns on or off logging. All input and output will
- be copied to the given file object. Set logfile to None to stop
- logging. This is the default. Set logfile to sys.stdout to echo
- everything to standard output. The logfile is flushed after each write.
-
- Example log input and output to a file::
-
- child = pexpect.spawn('some_command')
- fout = open('mylog.txt','wb')
- child.logfile = fout
-
- Example log to stdout::
-
- # In Python 2:
- child = pexpect.spawn('some_command')
- child.logfile = sys.stdout
-
+ '''This is the constructor. The command parameter may be a string that
+ includes a command and any arguments to the command. For example::
+
+ child = pexpect.spawn('/usr/bin/ftp')
+ child = pexpect.spawn('/usr/bin/ssh [email protected]')
+ child = pexpect.spawn('ls -latr /tmp')
+
+ You may also construct it with a list of arguments like so::
+
+ child = pexpect.spawn('/usr/bin/ftp', [])
+ child = pexpect.spawn('/usr/bin/ssh', ['[email protected]'])
+ child = pexpect.spawn('ls', ['-latr', '/tmp'])
+
+ After this the child application will be created and will be ready to
+ talk to. For normal use, see expect() and send() and sendline().
+
+ Remember that Pexpect does NOT interpret shell meta characters such as
+ redirect, pipe, or wild cards (``>``, ``|``, or ``*``). This is a
+ common mistake. If you want to run a command and pipe it through
+ another command then you must also start a shell. For example::
+
+ child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > logs.txt"')
+ child.expect(pexpect.EOF)
+
+ The second form of spawn (where you pass a list of arguments) is useful
+ in situations where you wish to spawn a command and pass it its own
+ argument list. This can make syntax more clear. For example, the
+ following is equivalent to the previous example::
+
+ shell_cmd = 'ls -l | grep LOG > logs.txt'
+ child = pexpect.spawn('/bin/bash', ['-c', shell_cmd])
+ child.expect(pexpect.EOF)
+
+ The maxread attribute sets the read buffer size. This is maximum number
+ of bytes that Pexpect will try to read from a TTY at one time. Setting
+ the maxread size to 1 will turn off buffering. Setting the maxread
+ value higher may help performance in cases where large amounts of
+ output are read back from the child. This feature is useful in
+ conjunction with searchwindowsize.
+
+ When the keyword argument *searchwindowsize* is None (default), the
+ full buffer is searched at each iteration of receiving incoming data.
+ The default number of bytes scanned at each iteration is very large
+ and may be reduced to collaterally reduce search cost. After
+ :meth:`~.expect` returns, the full buffer attribute remains up to
+ size *maxread* irrespective of *searchwindowsize* value.
+
+ When the keyword argument ``timeout`` is specified as a number,
+ (default: *30*), then :class:`TIMEOUT` will be raised after the value
+ specified has elapsed, in seconds, for any of the :meth:`~.expect`
+ family of method calls. When None, TIMEOUT will not be raised, and
+ :meth:`~.expect` may block indefinitely until match.
+
+
+ The logfile member turns on or off logging. All input and output will
+ be copied to the given file object. Set logfile to None to stop
+ logging. This is the default. Set logfile to sys.stdout to echo
+ everything to standard output. The logfile is flushed after each write.
+
+ Example log input and output to a file::
+
+ child = pexpect.spawn('some_command')
+ fout = open('mylog.txt','wb')
+ child.logfile = fout
+
+ Example log to stdout::
+
+ # In Python 2:
+ child = pexpect.spawn('some_command')
+ child.logfile = sys.stdout
+
# In Python 3, we'll use the ``encoding`` argument to decode data
# from the subprocess and handle it as unicode:
child = pexpect.spawn('some_command', encoding='utf-8')
- child.logfile = sys.stdout
-
- The logfile_read and logfile_send members can be used to separately log
- the input from the child and output sent to the child. Sometimes you
- don't want to see everything you write to the child. You only want to
- log what the child sends back. For example::
-
- child = pexpect.spawn('some_command')
- child.logfile_read = sys.stdout
-
- You will need to pass an encoding to spawn in the above code if you are
- using Python 3.
-
- To separately log output sent to the child use logfile_send::
-
- child.logfile_send = fout
-
- If ``ignore_sighup`` is True, the child process will ignore SIGHUP
- signals. The default is False from Pexpect 4.0, meaning that SIGHUP
- will be handled normally by the child.
-
- The delaybeforesend helps overcome a weird behavior that many users
- were experiencing. The typical problem was that a user would expect() a
- "Password:" prompt and then immediately call sendline() to send the
- password. The user would then see that their password was echoed back
- to them. Passwords don't normally echo. The problem is caused by the
- fact that most applications print out the "Password" prompt and then
- turn off stdin echo, but if you send your password before the
- application turned off echo, then you get your password echoed.
- Normally this wouldn't be a problem when interacting with a human at a
- real keyboard. If you introduce a slight delay just before writing then
- this seems to clear up the problem. This was such a common problem for
- many users that I decided that the default pexpect behavior should be
- to sleep just before writing to the child application. 1/20th of a
- second (50 ms) seems to be enough to clear up the problem. You can set
+ child.logfile = sys.stdout
+
+ The logfile_read and logfile_send members can be used to separately log
+ the input from the child and output sent to the child. Sometimes you
+ don't want to see everything you write to the child. You only want to
+ log what the child sends back. For example::
+
+ child = pexpect.spawn('some_command')
+ child.logfile_read = sys.stdout
+
+ You will need to pass an encoding to spawn in the above code if you are
+ using Python 3.
+
+ To separately log output sent to the child use logfile_send::
+
+ child.logfile_send = fout
+
+ If ``ignore_sighup`` is True, the child process will ignore SIGHUP
+ signals. The default is False from Pexpect 4.0, meaning that SIGHUP
+ will be handled normally by the child.
+
+ The delaybeforesend helps overcome a weird behavior that many users
+ were experiencing. The typical problem was that a user would expect() a
+ "Password:" prompt and then immediately call sendline() to send the
+ password. The user would then see that their password was echoed back
+ to them. Passwords don't normally echo. The problem is caused by the
+ fact that most applications print out the "Password" prompt and then
+ turn off stdin echo, but if you send your password before the
+ application turned off echo, then you get your password echoed.
+ Normally this wouldn't be a problem when interacting with a human at a
+ real keyboard. If you introduce a slight delay just before writing then
+ this seems to clear up the problem. This was such a common problem for
+ many users that I decided that the default pexpect behavior should be
+ to sleep just before writing to the child application. 1/20th of a
+ second (50 ms) seems to be enough to clear up the problem. You can set
delaybeforesend to None to return to the old behavior.
-
- Note that spawn is clever about finding commands on your path.
- It uses the same logic that "which" uses to find executables.
-
- If you wish to get the exit status of the child you must call the
- close() method. The exit or signal status of the child will be stored
- in self.exitstatus or self.signalstatus. If the child exited normally
- then exitstatus will store the exit return code and signalstatus will
- be None. If the child was terminated abnormally with a signal then
+
+ Note that spawn is clever about finding commands on your path.
+ It uses the same logic that "which" uses to find executables.
+
+ If you wish to get the exit status of the child you must call the
+ close() method. The exit or signal status of the child will be stored
+ in self.exitstatus or self.signalstatus. If the child exited normally
+ then exitstatus will store the exit return code and signalstatus will
+ be None. If the child was terminated abnormally with a signal then
signalstatus will store the signal value and exitstatus will be None::
child = pexpect.spawn('some_command')
child.close()
print(child.exitstatus, child.signalstatus)
- If you need more detail you can also read the self.status member which
- stores the status returned by os.waitpid. You can interpret this using
- os.WIFEXITED/os.WEXITSTATUS or os.WIFSIGNALED/os.TERMSIG.
-
- The echo attribute may be set to False to disable echoing of input.
- As a pseudo-terminal, all input echoed by the "keyboard" (send()
- or sendline()) will be repeated to output. For many cases, it is
- not desirable to have echo enabled, and it may be later disabled
- using setecho(False) followed by waitnoecho(). However, for some
- platforms such as Solaris, this is not possible, and should be
- disabled immediately on spawn.
+ If you need more detail you can also read the self.status member which
+ stores the status returned by os.waitpid. You can interpret this using
+ os.WIFEXITED/os.WEXITSTATUS or os.WIFSIGNALED/os.TERMSIG.
+
+ The echo attribute may be set to False to disable echoing of input.
+ As a pseudo-terminal, all input echoed by the "keyboard" (send()
+ or sendline()) will be repeated to output. For many cases, it is
+ not desirable to have echo enabled, and it may be later disabled
+ using setecho(False) followed by waitnoecho(). However, for some
+ platforms such as Solaris, this is not possible, and should be
+ disabled immediately on spawn.
- If preexec_fn is given, it will be called in the child process before
- launching the given command. This is useful to e.g. reset inherited
- signal handlers.
-
- The dimensions attribute specifies the size of the pseudo-terminal as
- seen by the subprocess, and is specified as a two-entry tuple (rows,
- columns). If this is unspecified, the defaults in ptyprocess will apply.
+ If preexec_fn is given, it will be called in the child process before
+ launching the given command. This is useful to e.g. reset inherited
+ signal handlers.
+
+ The dimensions attribute specifies the size of the pseudo-terminal as
+ seen by the subprocess, and is specified as a two-entry tuple (rows,
+ columns). If this is unspecified, the defaults in ptyprocess will apply.
The use_poll attribute enables using select.poll() over select.select()
for socket handling. This is handy if your system could have > 1024 fds
- '''
- super(spawn, self).__init__(timeout=timeout, maxread=maxread, searchwindowsize=searchwindowsize,
- logfile=logfile, encoding=encoding, codec_errors=codec_errors)
- self.STDIN_FILENO = pty.STDIN_FILENO
- self.STDOUT_FILENO = pty.STDOUT_FILENO
- self.STDERR_FILENO = pty.STDERR_FILENO
+ '''
+ super(spawn, self).__init__(timeout=timeout, maxread=maxread, searchwindowsize=searchwindowsize,
+ logfile=logfile, encoding=encoding, codec_errors=codec_errors)
+ self.STDIN_FILENO = pty.STDIN_FILENO
+ self.STDOUT_FILENO = pty.STDOUT_FILENO
+ self.STDERR_FILENO = pty.STDERR_FILENO
self.str_last_chars = 100
- self.cwd = cwd
- self.env = env
- self.echo = echo
- self.ignore_sighup = ignore_sighup
- self.__irix_hack = sys.platform.lower().startswith('irix')
- if command is None:
- self.command = None
- self.args = None
- self.name = '<pexpect factory incomplete>'
- else:
- self._spawn(command, args, preexec_fn, dimensions)
+ self.cwd = cwd
+ self.env = env
+ self.echo = echo
+ self.ignore_sighup = ignore_sighup
+ self.__irix_hack = sys.platform.lower().startswith('irix')
+ if command is None:
+ self.command = None
+ self.args = None
+ self.name = '<pexpect factory incomplete>'
+ else:
+ self._spawn(command, args, preexec_fn, dimensions)
self.use_poll = use_poll
-
- def __str__(self):
- '''This returns a human-readable string that represents the state of
- the object. '''
-
- s = []
- s.append(repr(self))
- s.append('command: ' + str(self.command))
- s.append('args: %r' % (self.args,))
+
+ def __str__(self):
+ '''This returns a human-readable string that represents the state of
+ the object. '''
+
+ s = []
+ s.append(repr(self))
+ s.append('command: ' + str(self.command))
+ s.append('args: %r' % (self.args,))
s.append('buffer (last %s chars): %r' % (self.str_last_chars,self.buffer[-self.str_last_chars:]))
s.append('before (last %s chars): %r' % (self.str_last_chars,self.before[-self.str_last_chars:] if self.before else ''))
- s.append('after: %r' % (self.after,))
- s.append('match: %r' % (self.match,))
- s.append('match_index: ' + str(self.match_index))
- s.append('exitstatus: ' + str(self.exitstatus))
+ s.append('after: %r' % (self.after,))
+ s.append('match: %r' % (self.match,))
+ s.append('match_index: ' + str(self.match_index))
+ s.append('exitstatus: ' + str(self.exitstatus))
if hasattr(self, 'ptyproc'):
s.append('flag_eof: ' + str(self.flag_eof))
- s.append('pid: ' + str(self.pid))
- s.append('child_fd: ' + str(self.child_fd))
- s.append('closed: ' + str(self.closed))
- s.append('timeout: ' + str(self.timeout))
- s.append('delimiter: ' + str(self.delimiter))
- s.append('logfile: ' + str(self.logfile))
- s.append('logfile_read: ' + str(self.logfile_read))
- s.append('logfile_send: ' + str(self.logfile_send))
- s.append('maxread: ' + str(self.maxread))
- s.append('ignorecase: ' + str(self.ignorecase))
- s.append('searchwindowsize: ' + str(self.searchwindowsize))
- s.append('delaybeforesend: ' + str(self.delaybeforesend))
- s.append('delayafterclose: ' + str(self.delayafterclose))
- s.append('delayafterterminate: ' + str(self.delayafterterminate))
- return '\n'.join(s)
-
- def _spawn(self, command, args=[], preexec_fn=None, dimensions=None):
- '''This starts the given command in a child process. This does all the
- fork/exec type of stuff for a pty. This is called by __init__. If args
- is empty then command will be parsed (split on spaces) and args will be
- set to parsed arguments. '''
-
- # The pid and child_fd of this object get set by this method.
- # Note that it is difficult for this method to fail.
- # You cannot detect if the child process cannot start.
- # So the only way you can tell if the child process started
- # or not is to try to read from the file descriptor. If you get
- # EOF immediately then it means that the child is already dead.
- # That may not necessarily be bad because you may have spawned a child
- # that performs some task; creates no stdout output; and then dies.
-
- # If command is an int type then it may represent a file descriptor.
- if isinstance(command, type(0)):
- raise ExceptionPexpect('Command is an int type. ' +
- 'If this is a file descriptor then maybe you want to ' +
- 'use fdpexpect.fdspawn which takes an existing ' +
- 'file descriptor instead of a command string.')
-
- if not isinstance(args, type([])):
- raise TypeError('The argument, args, must be a list.')
-
- if args == []:
- self.args = split_command_line(command)
- self.command = self.args[0]
- else:
- # Make a shallow copy of the args list.
- self.args = args[:]
- self.args.insert(0, command)
- self.command = command
-
+ s.append('pid: ' + str(self.pid))
+ s.append('child_fd: ' + str(self.child_fd))
+ s.append('closed: ' + str(self.closed))
+ s.append('timeout: ' + str(self.timeout))
+ s.append('delimiter: ' + str(self.delimiter))
+ s.append('logfile: ' + str(self.logfile))
+ s.append('logfile_read: ' + str(self.logfile_read))
+ s.append('logfile_send: ' + str(self.logfile_send))
+ s.append('maxread: ' + str(self.maxread))
+ s.append('ignorecase: ' + str(self.ignorecase))
+ s.append('searchwindowsize: ' + str(self.searchwindowsize))
+ s.append('delaybeforesend: ' + str(self.delaybeforesend))
+ s.append('delayafterclose: ' + str(self.delayafterclose))
+ s.append('delayafterterminate: ' + str(self.delayafterterminate))
+ return '\n'.join(s)
+
+ def _spawn(self, command, args=[], preexec_fn=None, dimensions=None):
+ '''This starts the given command in a child process. This does all the
+ fork/exec type of stuff for a pty. This is called by __init__. If args
+ is empty then command will be parsed (split on spaces) and args will be
+ set to parsed arguments. '''
+
+ # The pid and child_fd of this object get set by this method.
+ # Note that it is difficult for this method to fail.
+ # You cannot detect if the child process cannot start.
+ # So the only way you can tell if the child process started
+ # or not is to try to read from the file descriptor. If you get
+ # EOF immediately then it means that the child is already dead.
+ # That may not necessarily be bad because you may have spawned a child
+ # that performs some task; creates no stdout output; and then dies.
+
+ # If command is an int type then it may represent a file descriptor.
+ if isinstance(command, type(0)):
+ raise ExceptionPexpect('Command is an int type. ' +
+ 'If this is a file descriptor then maybe you want to ' +
+ 'use fdpexpect.fdspawn which takes an existing ' +
+ 'file descriptor instead of a command string.')
+
+ if not isinstance(args, type([])):
+ raise TypeError('The argument, args, must be a list.')
+
+ if args == []:
+ self.args = split_command_line(command)
+ self.command = self.args[0]
+ else:
+ # Make a shallow copy of the args list.
+ self.args = args[:]
+ self.args.insert(0, command)
+ self.command = command
+
command_with_path = which(self.command, env=self.env)
- if command_with_path is None:
- raise ExceptionPexpect('The command was not found or was not ' +
- 'executable: %s.' % self.command)
- self.command = command_with_path
- self.args[0] = self.command
-
- self.name = '<' + ' '.join(self.args) + '>'
-
- assert self.pid is None, 'The pid member must be None.'
- assert self.command is not None, 'The command member must not be None.'
-
- kwargs = {'echo': self.echo, 'preexec_fn': preexec_fn}
- if self.ignore_sighup:
- def preexec_wrapper():
- "Set SIGHUP to be ignored, then call the real preexec_fn"
- signal.signal(signal.SIGHUP, signal.SIG_IGN)
- if preexec_fn is not None:
- preexec_fn()
- kwargs['preexec_fn'] = preexec_wrapper
-
- if dimensions is not None:
- kwargs['dimensions'] = dimensions
-
+ if command_with_path is None:
+ raise ExceptionPexpect('The command was not found or was not ' +
+ 'executable: %s.' % self.command)
+ self.command = command_with_path
+ self.args[0] = self.command
+
+ self.name = '<' + ' '.join(self.args) + '>'
+
+ assert self.pid is None, 'The pid member must be None.'
+ assert self.command is not None, 'The command member must not be None.'
+
+ kwargs = {'echo': self.echo, 'preexec_fn': preexec_fn}
+ if self.ignore_sighup:
+ def preexec_wrapper():
+ "Set SIGHUP to be ignored, then call the real preexec_fn"
+ signal.signal(signal.SIGHUP, signal.SIG_IGN)
+ if preexec_fn is not None:
+ preexec_fn()
+ kwargs['preexec_fn'] = preexec_wrapper
+
+ if dimensions is not None:
+ kwargs['dimensions'] = dimensions
+
if self.encoding is not None:
# Encode command line using the specified encoding
self.args = [a if isinstance(a, bytes) else a.encode(self.encoding)
for a in self.args]
-
+
self.ptyproc = self._spawnpty(self.args, env=self.env,
cwd=self.cwd, **kwargs)
- self.pid = self.ptyproc.pid
- self.child_fd = self.ptyproc.fd
-
-
- self.terminated = False
- self.closed = False
-
+ self.pid = self.ptyproc.pid
+ self.child_fd = self.ptyproc.fd
+
+
+ self.terminated = False
+ self.closed = False
+
def _spawnpty(self, args, **kwargs):
'''Spawn a pty and return an instance of PtyProcess.'''
return ptyprocess.PtyProcess.spawn(args, **kwargs)
- def close(self, force=True):
- '''This closes the connection with the child application. Note that
- calling close() more than once is valid. This emulates standard Python
- behavior with files. Set force to True if you want to make sure that
- the child is terminated (SIGKILL is sent if the child ignores SIGHUP
- and SIGINT). '''
-
- self.flush()
+ def close(self, force=True):
+ '''This closes the connection with the child application. Note that
+ calling close() more than once is valid. This emulates standard Python
+ behavior with files. Set force to True if you want to make sure that
+ the child is terminated (SIGKILL is sent if the child ignores SIGHUP
+ and SIGINT). '''
+
+ self.flush()
with _wrap_ptyprocess_err():
# PtyProcessError may be raised if it is not possible to terminate
# the child.
self.ptyproc.close(force=force)
- self.isalive() # Update exit status from ptyproc
- self.child_fd = -1
+ self.isalive() # Update exit status from ptyproc
+ self.child_fd = -1
self.closed = True
-
- def isatty(self):
- '''This returns True if the file descriptor is open and connected to a
- tty(-like) device, else False.
-
- On SVR4-style platforms implementing streams, such as SunOS and HP-UX,
- the child pty may not appear as a terminal device. This means
- methods such as setecho(), setwinsize(), getwinsize() may raise an
- IOError. '''
-
- return os.isatty(self.child_fd)
-
- def waitnoecho(self, timeout=-1):
- '''This waits until the terminal ECHO flag is set False. This returns
- True if the echo mode is off. This returns False if the ECHO flag was
- not set False before the timeout. This can be used to detect when the
- child is waiting for a password. Usually a child application will turn
- off echo mode when it is waiting for the user to enter a password. For
- example, instead of expecting the "password:" prompt you can wait for
- the child to set ECHO off::
-
- p = pexpect.spawn('ssh [email protected]')
- p.waitnoecho()
- p.sendline(mypassword)
-
- If timeout==-1 then this method will use the value in self.timeout.
- If timeout==None then this method to block until ECHO flag is False.
- '''
-
- if timeout == -1:
- timeout = self.timeout
- if timeout is not None:
- end_time = time.time() + timeout
- while True:
- if not self.getecho():
- return True
- if timeout < 0 and timeout is not None:
- return False
- if timeout is not None:
- timeout = end_time - time.time()
- time.sleep(0.1)
-
- def getecho(self):
- '''This returns the terminal echo mode. This returns True if echo is
- on or False if echo is off. Child applications that are expecting you
- to enter a password often set ECHO False. See waitnoecho().
-
- Not supported on platforms where ``isatty()`` returns False. '''
- return self.ptyproc.getecho()
-
- def setecho(self, state):
- '''This sets the terminal echo mode on or off. Note that anything the
- child sent before the echo will be lost, so you should be sure that
- your input buffer is empty before you call setecho(). For example, the
- following will work as expected::
-
- p = pexpect.spawn('cat') # Echo is on by default.
- p.sendline('1234') # We expect see this twice from the child...
- p.expect(['1234']) # ... once from the tty echo...
- p.expect(['1234']) # ... and again from cat itself.
- p.setecho(False) # Turn off tty echo
- p.sendline('abcd') # We will set this only once (echoed by cat).
- p.sendline('wxyz') # We will set this only once (echoed by cat)
- p.expect(['abcd'])
- p.expect(['wxyz'])
-
- The following WILL NOT WORK because the lines sent before the setecho
- will be lost::
-
- p = pexpect.spawn('cat')
- p.sendline('1234')
- p.setecho(False) # Turn off tty echo
- p.sendline('abcd') # We will set this only once (echoed by cat).
- p.sendline('wxyz') # We will set this only once (echoed by cat)
- p.expect(['1234'])
- p.expect(['1234'])
- p.expect(['abcd'])
- p.expect(['wxyz'])
-
-
- Not supported on platforms where ``isatty()`` returns False.
- '''
- return self.ptyproc.setecho(state)
-
- def read_nonblocking(self, size=1, timeout=-1):
- '''This reads at most size characters from the child application. It
- includes a timeout. If the read does not complete within the timeout
- period then a TIMEOUT exception is raised. If the end of file is read
- then an EOF exception will be raised. If a logfile is specified, a
- copy is written to that log.
-
- If timeout is None then the read may block indefinitely.
- If timeout is -1 then the self.timeout value is used. If timeout is 0
- then the child is polled and if there is no data immediately ready
- then this will raise a TIMEOUT exception.
-
- The timeout refers only to the amount of time to read at least one
- character. This is not affected by the 'size' parameter, so if you call
- read_nonblocking(size=100, timeout=30) and only one character is
- available right away then one character will be returned immediately.
- It will not wait for 30 seconds for another 99 characters to come in.
-
+
+ def isatty(self):
+ '''This returns True if the file descriptor is open and connected to a
+ tty(-like) device, else False.
+
+ On SVR4-style platforms implementing streams, such as SunOS and HP-UX,
+ the child pty may not appear as a terminal device. This means
+ methods such as setecho(), setwinsize(), getwinsize() may raise an
+ IOError. '''
+
+ return os.isatty(self.child_fd)
+
+ def waitnoecho(self, timeout=-1):
+ '''This waits until the terminal ECHO flag is set False. This returns
+ True if the echo mode is off. This returns False if the ECHO flag was
+ not set False before the timeout. This can be used to detect when the
+ child is waiting for a password. Usually a child application will turn
+ off echo mode when it is waiting for the user to enter a password. For
+ example, instead of expecting the "password:" prompt you can wait for
+ the child to set ECHO off::
+
+ p = pexpect.spawn('ssh [email protected]')
+ p.waitnoecho()
+ p.sendline(mypassword)
+
+ If timeout==-1 then this method will use the value in self.timeout.
+ If timeout==None then this method to block until ECHO flag is False.
+ '''
+
+ if timeout == -1:
+ timeout = self.timeout
+ if timeout is not None:
+ end_time = time.time() + timeout
+ while True:
+ if not self.getecho():
+ return True
+ if timeout < 0 and timeout is not None:
+ return False
+ if timeout is not None:
+ timeout = end_time - time.time()
+ time.sleep(0.1)
+
+ def getecho(self):
+ '''This returns the terminal echo mode. This returns True if echo is
+ on or False if echo is off. Child applications that are expecting you
+ to enter a password often set ECHO False. See waitnoecho().
+
+ Not supported on platforms where ``isatty()`` returns False. '''
+ return self.ptyproc.getecho()
+
+ def setecho(self, state):
+ '''This sets the terminal echo mode on or off. Note that anything the
+ child sent before the echo will be lost, so you should be sure that
+ your input buffer is empty before you call setecho(). For example, the
+ following will work as expected::
+
+ p = pexpect.spawn('cat') # Echo is on by default.
+ p.sendline('1234') # We expect see this twice from the child...
+ p.expect(['1234']) # ... once from the tty echo...
+ p.expect(['1234']) # ... and again from cat itself.
+ p.setecho(False) # Turn off tty echo
+ p.sendline('abcd') # We will set this only once (echoed by cat).
+ p.sendline('wxyz') # We will set this only once (echoed by cat)
+ p.expect(['abcd'])
+ p.expect(['wxyz'])
+
+ The following WILL NOT WORK because the lines sent before the setecho
+ will be lost::
+
+ p = pexpect.spawn('cat')
+ p.sendline('1234')
+ p.setecho(False) # Turn off tty echo
+ p.sendline('abcd') # We will set this only once (echoed by cat).
+ p.sendline('wxyz') # We will set this only once (echoed by cat)
+ p.expect(['1234'])
+ p.expect(['1234'])
+ p.expect(['abcd'])
+ p.expect(['wxyz'])
+
+
+ Not supported on platforms where ``isatty()`` returns False.
+ '''
+ return self.ptyproc.setecho(state)
+
+ def read_nonblocking(self, size=1, timeout=-1):
+ '''This reads at most size characters from the child application. It
+ includes a timeout. If the read does not complete within the timeout
+ period then a TIMEOUT exception is raised. If the end of file is read
+ then an EOF exception will be raised. If a logfile is specified, a
+ copy is written to that log.
+
+ If timeout is None then the read may block indefinitely.
+ If timeout is -1 then the self.timeout value is used. If timeout is 0
+ then the child is polled and if there is no data immediately ready
+ then this will raise a TIMEOUT exception.
+
+ The timeout refers only to the amount of time to read at least one
+ character. This is not affected by the 'size' parameter, so if you call
+ read_nonblocking(size=100, timeout=30) and only one character is
+ available right away then one character will be returned immediately.
+ It will not wait for 30 seconds for another 99 characters to come in.
+
On the other hand, if there are bytes available to read immediately,
all those bytes will be read (up to the buffer size). So, if the
buffer size is 1 megabyte and there is 1 megabyte of data available
to read, the buffer will be filled, regardless of timeout.
-
+
This is a wrapper around os.read(). It uses select.select() or
select.poll() to implement the timeout. '''
- if self.closed:
- raise ValueError('I/O operation on closed file.')
-
+ if self.closed:
+ raise ValueError('I/O operation on closed file.')
+
if self.use_poll:
def select(timeout):
return poll_ignore_interrupts([self.child_fd], timeout)
@@ -472,10 +472,10 @@ class spawn(SpawnBase):
return incoming
return incoming
- if timeout == -1:
- timeout = self.timeout
-
- if not self.isalive():
+ if timeout == -1:
+ timeout = self.timeout
+
+ if not self.isalive():
# The process is dead, but there may or may not be data
# available to read. Note that some systems such as Solaris
# do not give an EOF when the child dies. In fact, you can
@@ -486,20 +486,20 @@ class spawn(SpawnBase):
return super(spawn, self).read_nonblocking(size)
self.flag_eof = True
raise EOF('End Of File (EOF). Braindead platform.')
- elif self.__irix_hack:
- # Irix takes a long time before it realizes a child was terminated.
+ elif self.__irix_hack:
+ # Irix takes a long time before it realizes a child was terminated.
# Make sure that the timeout is at least 2 seconds.
- # FIXME So does this mean Irix systems are forced to always have
- # FIXME a 2 second delay when calling read_nonblocking? That sucks.
+ # FIXME So does this mean Irix systems are forced to always have
+ # FIXME a 2 second delay when calling read_nonblocking? That sucks.
if timeout is not None and timeout < 2:
timeout = 2
-
+
# Because of the select(0) check above, we know that no data
# is available right now. But if a non-zero timeout is given
# (possibly timeout=None), we call select() with a timeout.
if (timeout != 0) and select(timeout):
- return super(spawn, self).read_nonblocking(size)
-
+ return super(spawn, self).read_nonblocking(size)
+
if not self.isalive():
# Some platforms, such as Irix, will claim that their
# processes are alive; timeout on the select; and
@@ -508,353 +508,353 @@ class spawn(SpawnBase):
raise EOF('End of File (EOF). Very slow platform.')
else:
raise TIMEOUT('Timeout exceeded.')
-
- def write(self, s):
- '''This is similar to send() except that there is no return value.
- '''
-
- self.send(s)
-
- def writelines(self, sequence):
- '''This calls write() for each element in the sequence. The sequence
- can be any iterable object producing strings, typically a list of
- strings. This does not add line separators. There is no return value.
- '''
-
- for s in sequence:
- self.write(s)
-
- def send(self, s):
- '''Sends string ``s`` to the child process, returning the number of
- bytes written. If a logfile is specified, a copy is written to that
- log.
-
- The default terminal input mode is canonical processing unless set
- otherwise by the child process. This allows backspace and other line
- processing to be performed prior to transmitting to the receiving
- program. As this is buffered, there is a limited size of such buffer.
-
- On Linux systems, this is 4096 (defined by N_TTY_BUF_SIZE). All
- other systems honor the POSIX.1 definition PC_MAX_CANON -- 1024
- on OSX, 256 on OpenSolaris, and 1920 on FreeBSD.
-
- This value may be discovered using fpathconf(3)::
-
+
+ def write(self, s):
+ '''This is similar to send() except that there is no return value.
+ '''
+
+ self.send(s)
+
+ def writelines(self, sequence):
+ '''This calls write() for each element in the sequence. The sequence
+ can be any iterable object producing strings, typically a list of
+ strings. This does not add line separators. There is no return value.
+ '''
+
+ for s in sequence:
+ self.write(s)
+
+ def send(self, s):
+ '''Sends string ``s`` to the child process, returning the number of
+ bytes written. If a logfile is specified, a copy is written to that
+ log.
+
+ The default terminal input mode is canonical processing unless set
+ otherwise by the child process. This allows backspace and other line
+ processing to be performed prior to transmitting to the receiving
+ program. As this is buffered, there is a limited size of such buffer.
+
+ On Linux systems, this is 4096 (defined by N_TTY_BUF_SIZE). All
+ other systems honor the POSIX.1 definition PC_MAX_CANON -- 1024
+ on OSX, 256 on OpenSolaris, and 1920 on FreeBSD.
+
+ This value may be discovered using fpathconf(3)::
+
>>> from os import fpathconf
>>> print(fpathconf(0, 'PC_MAX_CANON'))
256
-
- On such a system, only 256 bytes may be received per line. Any
- subsequent bytes received will be discarded. BEL (``'\a'``) is then
- sent to output if IMAXBEL (termios.h) is set by the tty driver.
- This is usually enabled by default. Linux does not honor this as
- an option -- it behaves as though it is always set on.
-
- Canonical input processing may be disabled altogether by executing
- a shell, then stty(1), before executing the final program::
-
+
+ On such a system, only 256 bytes may be received per line. Any
+ subsequent bytes received will be discarded. BEL (``'\a'``) is then
+ sent to output if IMAXBEL (termios.h) is set by the tty driver.
+ This is usually enabled by default. Linux does not honor this as
+ an option -- it behaves as though it is always set on.
+
+ Canonical input processing may be disabled altogether by executing
+ a shell, then stty(1), before executing the final program::
+
>>> bash = pexpect.spawn('/bin/bash', echo=False)
>>> bash.sendline('stty -icanon')
>>> bash.sendline('base64')
>>> bash.sendline('x' * 5000)
- '''
-
+ '''
+
if self.delaybeforesend is not None:
time.sleep(self.delaybeforesend)
-
- s = self._coerce_send_string(s)
- self._log(s, 'send')
-
- b = self._encoder.encode(s, final=False)
- return os.write(self.child_fd, b)
-
- def sendline(self, s=''):
- '''Wraps send(), sending string ``s`` to child process, with
- ``os.linesep`` automatically appended. Returns number of bytes
- written. Only a limited number of bytes may be sent for each
- line in the default terminal mode, see docstring of :meth:`send`.
- '''
+
+ s = self._coerce_send_string(s)
+ self._log(s, 'send')
+
+ b = self._encoder.encode(s, final=False)
+ return os.write(self.child_fd, b)
+
+ def sendline(self, s=''):
+ '''Wraps send(), sending string ``s`` to child process, with
+ ``os.linesep`` automatically appended. Returns number of bytes
+ written. Only a limited number of bytes may be sent for each
+ line in the default terminal mode, see docstring of :meth:`send`.
+ '''
s = self._coerce_send_string(s)
return self.send(s + self.linesep)
-
- def _log_control(self, s):
- """Write control characters to the appropriate log files"""
- if self.encoding is not None:
- s = s.decode(self.encoding, 'replace')
- self._log(s, 'send')
-
- def sendcontrol(self, char):
- '''Helper method that wraps send() with mnemonic access for sending control
- character to the child (such as Ctrl-C or Ctrl-D). For example, to send
- Ctrl-G (ASCII 7, bell, '\a')::
-
- child.sendcontrol('g')
-
- See also, sendintr() and sendeof().
- '''
- n, byte = self.ptyproc.sendcontrol(char)
- self._log_control(byte)
- return n
-
- def sendeof(self):
- '''This sends an EOF to the child. This sends a character which causes
- the pending parent output buffer to be sent to the waiting child
- program without waiting for end-of-line. If it is the first character
- of the line, the read() in the user program returns 0, which signifies
- end-of-file. This means to work as expected a sendeof() has to be
- called at the beginning of a line. This method does not send a newline.
- It is the responsibility of the caller to ensure the eof is sent at the
- beginning of a line. '''
-
- n, byte = self.ptyproc.sendeof()
- self._log_control(byte)
-
- def sendintr(self):
- '''This sends a SIGINT to the child. It does not require
- the SIGINT to be the first character on a line. '''
-
- n, byte = self.ptyproc.sendintr()
- self._log_control(byte)
-
- @property
- def flag_eof(self):
- return self.ptyproc.flag_eof
-
- @flag_eof.setter
- def flag_eof(self, value):
- self.ptyproc.flag_eof = value
-
- def eof(self):
- '''This returns True if the EOF exception was ever raised.
- '''
- return self.flag_eof
-
- 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
- child could not be terminated. '''
-
- if not self.isalive():
- return True
- try:
- self.kill(signal.SIGHUP)
- time.sleep(self.delayafterterminate)
- if not self.isalive():
- return True
- self.kill(signal.SIGCONT)
- time.sleep(self.delayafterterminate)
- if not self.isalive():
- return True
- self.kill(signal.SIGINT)
- time.sleep(self.delayafterterminate)
- if not self.isalive():
- return True
- if force:
- self.kill(signal.SIGKILL)
- time.sleep(self.delayafterterminate)
- if not self.isalive():
- return True
- else:
- 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.
- time.sleep(self.delayafterterminate)
- if not self.isalive():
- return True
- else:
- return False
-
- def wait(self):
- '''This waits until the child exits. This is a blocking call. This will
- not read any data from the child, so this will block forever if the
- child has unread output and has terminated. In other words, the child
- may have printed output then called exit(), but, the child is
- technically still alive until its output is read by the parent.
-
- This method is non-blocking if :meth:`wait` has already been called
- previously or :meth:`isalive` method returns False. It simply returns
- the previously determined exit status.
- '''
-
- ptyproc = self.ptyproc
- with _wrap_ptyprocess_err():
- # exception may occur if "Is some other process attempting
- # "job control with our child pid?"
- exitstatus = ptyproc.wait()
- self.status = ptyproc.status
- self.exitstatus = ptyproc.exitstatus
- self.signalstatus = ptyproc.signalstatus
- self.terminated = True
-
- return exitstatus
-
- def isalive(self):
- '''This tests if the child process is running or not. This is
- non-blocking. If the child was terminated then this will read the
- exitstatus or signalstatus of the child. This returns True if the child
- process appears to be running or False if not. It can take literally
- SECONDS for Solaris to return the right status. '''
-
- ptyproc = self.ptyproc
- with _wrap_ptyprocess_err():
- alive = ptyproc.isalive()
-
- if not alive:
- self.status = ptyproc.status
- self.exitstatus = ptyproc.exitstatus
- self.signalstatus = ptyproc.signalstatus
- self.terminated = True
-
- return alive
-
- def kill(self, sig):
-
- '''This sends the given signal to the child application. In keeping
- with UNIX tradition it has a misleading name. It does not necessarily
- kill the child unless you send the right signal. '''
-
- # Same as os.kill, but the pid is given for you.
- if self.isalive():
- os.kill(self.pid, sig)
-
- def getwinsize(self):
- '''This returns the terminal window size of the child tty. The return
- value is a tuple of (rows, cols). '''
- return self.ptyproc.getwinsize()
-
- def setwinsize(self, rows, cols):
- '''This sets the terminal window size of the child tty. This will cause
- a SIGWINCH signal to be sent to the child. This does not change the
- physical window size. It changes the size reported to TTY-aware
- applications like vi or curses -- applications that respond to the
- SIGWINCH signal. '''
- return self.ptyproc.setwinsize(rows, cols)
-
-
- def interact(self, escape_character=chr(29),
- input_filter=None, output_filter=None):
-
- '''This gives control of the child process to the interactive user (the
- human at the keyboard). Keystrokes are sent to the child process, and
- the stdout and stderr output of the child process is printed. This
- simply echos the child stdout and child stderr to the real stdout and
- it echos the real stdin to the child stdin. When the user types the
- escape_character this method will return None. The escape_character
- will not be transmitted. The default for escape_character is
- entered as ``Ctrl - ]``, the very same as BSD telnet. To prevent
- escaping, escape_character may be set to None.
-
- If a logfile is specified, then the data sent and received from the
- child process in interact mode is duplicated to the given log.
-
- You may pass in optional input and output filter functions. These
+
+ def _log_control(self, s):
+ """Write control characters to the appropriate log files"""
+ if self.encoding is not None:
+ s = s.decode(self.encoding, 'replace')
+ self._log(s, 'send')
+
+ def sendcontrol(self, char):
+ '''Helper method that wraps send() with mnemonic access for sending control
+ character to the child (such as Ctrl-C or Ctrl-D). For example, to send
+ Ctrl-G (ASCII 7, bell, '\a')::
+
+ child.sendcontrol('g')
+
+ See also, sendintr() and sendeof().
+ '''
+ n, byte = self.ptyproc.sendcontrol(char)
+ self._log_control(byte)
+ return n
+
+ def sendeof(self):
+ '''This sends an EOF to the child. This sends a character which causes
+ the pending parent output buffer to be sent to the waiting child
+ program without waiting for end-of-line. If it is the first character
+ of the line, the read() in the user program returns 0, which signifies
+ end-of-file. This means to work as expected a sendeof() has to be
+ called at the beginning of a line. This method does not send a newline.
+ It is the responsibility of the caller to ensure the eof is sent at the
+ beginning of a line. '''
+
+ n, byte = self.ptyproc.sendeof()
+ self._log_control(byte)
+
+ def sendintr(self):
+ '''This sends a SIGINT to the child. It does not require
+ the SIGINT to be the first character on a line. '''
+
+ n, byte = self.ptyproc.sendintr()
+ self._log_control(byte)
+
+ @property
+ def flag_eof(self):
+ return self.ptyproc.flag_eof
+
+ @flag_eof.setter
+ def flag_eof(self, value):
+ self.ptyproc.flag_eof = value
+
+ def eof(self):
+ '''This returns True if the EOF exception was ever raised.
+ '''
+ return self.flag_eof
+
+ 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
+ child could not be terminated. '''
+
+ if not self.isalive():
+ return True
+ try:
+ self.kill(signal.SIGHUP)
+ time.sleep(self.delayafterterminate)
+ if not self.isalive():
+ return True
+ self.kill(signal.SIGCONT)
+ time.sleep(self.delayafterterminate)
+ if not self.isalive():
+ return True
+ self.kill(signal.SIGINT)
+ time.sleep(self.delayafterterminate)
+ if not self.isalive():
+ return True
+ if force:
+ self.kill(signal.SIGKILL)
+ time.sleep(self.delayafterterminate)
+ if not self.isalive():
+ return True
+ else:
+ 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.
+ time.sleep(self.delayafterterminate)
+ if not self.isalive():
+ return True
+ else:
+ return False
+
+ def wait(self):
+ '''This waits until the child exits. This is a blocking call. This will
+ not read any data from the child, so this will block forever if the
+ child has unread output and has terminated. In other words, the child
+ may have printed output then called exit(), but, the child is
+ technically still alive until its output is read by the parent.
+
+ This method is non-blocking if :meth:`wait` has already been called
+ previously or :meth:`isalive` method returns False. It simply returns
+ the previously determined exit status.
+ '''
+
+ ptyproc = self.ptyproc
+ with _wrap_ptyprocess_err():
+ # exception may occur if "Is some other process attempting
+ # "job control with our child pid?"
+ exitstatus = ptyproc.wait()
+ self.status = ptyproc.status
+ self.exitstatus = ptyproc.exitstatus
+ self.signalstatus = ptyproc.signalstatus
+ self.terminated = True
+
+ return exitstatus
+
+ def isalive(self):
+ '''This tests if the child process is running or not. This is
+ non-blocking. If the child was terminated then this will read the
+ exitstatus or signalstatus of the child. This returns True if the child
+ process appears to be running or False if not. It can take literally
+ SECONDS for Solaris to return the right status. '''
+
+ ptyproc = self.ptyproc
+ with _wrap_ptyprocess_err():
+ alive = ptyproc.isalive()
+
+ if not alive:
+ self.status = ptyproc.status
+ self.exitstatus = ptyproc.exitstatus
+ self.signalstatus = ptyproc.signalstatus
+ self.terminated = True
+
+ return alive
+
+ def kill(self, sig):
+
+ '''This sends the given signal to the child application. In keeping
+ with UNIX tradition it has a misleading name. It does not necessarily
+ kill the child unless you send the right signal. '''
+
+ # Same as os.kill, but the pid is given for you.
+ if self.isalive():
+ os.kill(self.pid, sig)
+
+ def getwinsize(self):
+ '''This returns the terminal window size of the child tty. The return
+ value is a tuple of (rows, cols). '''
+ return self.ptyproc.getwinsize()
+
+ def setwinsize(self, rows, cols):
+ '''This sets the terminal window size of the child tty. This will cause
+ a SIGWINCH signal to be sent to the child. This does not change the
+ physical window size. It changes the size reported to TTY-aware
+ applications like vi or curses -- applications that respond to the
+ SIGWINCH signal. '''
+ return self.ptyproc.setwinsize(rows, cols)
+
+
+ def interact(self, escape_character=chr(29),
+ input_filter=None, output_filter=None):
+
+ '''This gives control of the child process to the interactive user (the
+ human at the keyboard). Keystrokes are sent to the child process, and
+ the stdout and stderr output of the child process is printed. This
+ simply echos the child stdout and child stderr to the real stdout and
+ it echos the real stdin to the child stdin. When the user types the
+ escape_character this method will return None. The escape_character
+ will not be transmitted. The default for escape_character is
+ entered as ``Ctrl - ]``, the very same as BSD telnet. To prevent
+ escaping, escape_character may be set to None.
+
+ If a logfile is specified, then the data sent and received from the
+ child process in interact mode is duplicated to the given log.
+
+ You may pass in optional input and output filter functions. These
functions should take bytes array and return bytes array too. Even
with ``encoding='utf-8'`` support, meth:`interact` will always pass
input_filter and output_filter bytes. You may need to wrap your
function to decode and encode back to UTF-8.
-
+
The output_filter will be passed all the output from the child process.
The input_filter will be passed all the keyboard input from the user.
The input_filter is run BEFORE the check for the escape_character.
- Note that if you change the window size of the parent the SIGWINCH
- signal will not be passed through to the child. If you want the child
- window size to change when the parent's window size changes then do
- something like the following example::
-
- import pexpect, struct, fcntl, termios, signal, sys
- def sigwinch_passthrough (sig, data):
- s = struct.pack("HHHH", 0, 0, 0, 0)
- a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(),
- termios.TIOCGWINSZ , s))
+ Note that if you change the window size of the parent the SIGWINCH
+ signal will not be passed through to the child. If you want the child
+ window size to change when the parent's window size changes then do
+ something like the following example::
+
+ import pexpect, struct, fcntl, termios, signal, sys
+ def sigwinch_passthrough (sig, data):
+ s = struct.pack("HHHH", 0, 0, 0, 0)
+ a = struct.unpack('hhhh', fcntl.ioctl(sys.stdout.fileno(),
+ termios.TIOCGWINSZ , s))
if not p.closed:
p.setwinsize(a[0],a[1])
# Note this 'p' is global and used in sigwinch_passthrough.
- p = pexpect.spawn('/bin/bash')
- signal.signal(signal.SIGWINCH, sigwinch_passthrough)
- p.interact()
- '''
-
- # Flush the buffer.
- self.write_to_stdout(self.buffer)
- self.stdout.flush()
+ p = pexpect.spawn('/bin/bash')
+ signal.signal(signal.SIGWINCH, sigwinch_passthrough)
+ p.interact()
+ '''
+
+ # Flush the buffer.
+ self.write_to_stdout(self.buffer)
+ self.stdout.flush()
self._buffer = self.buffer_type()
- mode = tty.tcgetattr(self.STDIN_FILENO)
- tty.setraw(self.STDIN_FILENO)
- if escape_character is not None and PY3:
- escape_character = escape_character.encode('latin-1')
- try:
- self.__interact_copy(escape_character, input_filter, output_filter)
- finally:
- tty.tcsetattr(self.STDIN_FILENO, tty.TCSAFLUSH, mode)
-
- def __interact_writen(self, fd, data):
- '''This is used by the interact() method.
- '''
-
- while data != b'' and self.isalive():
- n = os.write(fd, data)
- data = data[n:]
-
- def __interact_read(self, fd):
- '''This is used by the interact() method.
- '''
-
- return os.read(fd, 1000)
-
+ mode = tty.tcgetattr(self.STDIN_FILENO)
+ tty.setraw(self.STDIN_FILENO)
+ if escape_character is not None and PY3:
+ escape_character = escape_character.encode('latin-1')
+ try:
+ self.__interact_copy(escape_character, input_filter, output_filter)
+ finally:
+ tty.tcsetattr(self.STDIN_FILENO, tty.TCSAFLUSH, mode)
+
+ def __interact_writen(self, fd, data):
+ '''This is used by the interact() method.
+ '''
+
+ while data != b'' and self.isalive():
+ n = os.write(fd, data)
+ data = data[n:]
+
+ def __interact_read(self, fd):
+ '''This is used by the interact() method.
+ '''
+
+ return os.read(fd, 1000)
+
def __interact_copy(
self, escape_character=None, input_filter=None, output_filter=None
):
-
- '''This is used by the interact() method.
- '''
-
- while self.isalive():
+
+ '''This is used by the interact() method.
+ '''
+
+ while self.isalive():
if self.use_poll:
r = poll_ignore_interrupts([self.child_fd, self.STDIN_FILENO])
else:
r, w, e = select_ignore_interrupts(
[self.child_fd, self.STDIN_FILENO], [], []
)
- if self.child_fd in r:
- try:
- data = self.__interact_read(self.child_fd)
- except OSError as err:
- if err.args[0] == errno.EIO:
- # Linux-style EOF
- break
- raise
- if data == b'':
- # BSD-style EOF
- break
- if output_filter:
- data = output_filter(data)
- self._log(data, 'read')
- os.write(self.STDOUT_FILENO, data)
- if self.STDIN_FILENO in r:
- data = self.__interact_read(self.STDIN_FILENO)
- if input_filter:
- data = input_filter(data)
- i = -1
- if escape_character is not None:
- i = data.rfind(escape_character)
- if i != -1:
- data = data[:i]
- if data:
- self._log(data, 'send')
- self.__interact_writen(self.child_fd, data)
- break
- self._log(data, 'send')
- self.__interact_writen(self.child_fd, data)
-
-
-def spawnu(*args, **kwargs):
- """Deprecated: pass encoding to spawn() instead."""
- kwargs.setdefault('encoding', 'utf-8')
- return spawn(*args, **kwargs)
+ if self.child_fd in r:
+ try:
+ data = self.__interact_read(self.child_fd)
+ except OSError as err:
+ if err.args[0] == errno.EIO:
+ # Linux-style EOF
+ break
+ raise
+ if data == b'':
+ # BSD-style EOF
+ break
+ if output_filter:
+ data = output_filter(data)
+ self._log(data, 'read')
+ os.write(self.STDOUT_FILENO, data)
+ if self.STDIN_FILENO in r:
+ data = self.__interact_read(self.STDIN_FILENO)
+ if input_filter:
+ data = input_filter(data)
+ i = -1
+ if escape_character is not None:
+ i = data.rfind(escape_character)
+ if i != -1:
+ data = data[:i]
+ if data:
+ self._log(data, 'send')
+ self.__interact_writen(self.child_fd, data)
+ break
+ self._log(data, 'send')
+ self.__interact_writen(self.child_fd, data)
+
+
+def spawnu(*args, **kwargs):
+ """Deprecated: pass encoding to spawn() instead."""
+ kwargs.setdefault('encoding', 'utf-8')
+ return spawn(*args, **kwargs)
diff --git a/contrib/python/pexpect/pexpect/pxssh.py b/contrib/python/pexpect/pexpect/pxssh.py
index 3d53bd97462..00e10aad071 100644
--- a/contrib/python/pexpect/pexpect/pxssh.py
+++ b/contrib/python/pexpect/pexpect/pxssh.py
@@ -1,38 +1,38 @@
-'''This class extends pexpect.spawn to specialize setting up SSH connections.
-This adds methods for login, logout, and expecting the shell prompt.
-
-PEXPECT LICENSE
-
- This license is approved by the OSI and FSF as GPL-compatible.
- http://opensource.org/licenses/isc-license.txt
-
- Copyright (c) 2012, Noah Spurrier <[email protected]>
- PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
- PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
- COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-'''
-
-from pexpect import ExceptionPexpect, TIMEOUT, EOF, spawn
-import time
-import os
+'''This class extends pexpect.spawn to specialize setting up SSH connections.
+This adds methods for login, logout, and expecting the shell prompt.
+
+PEXPECT LICENSE
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2012, Noah Spurrier <[email protected]>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+'''
+
+from pexpect import ExceptionPexpect, TIMEOUT, EOF, spawn
+import time
+import os
import sys
import re
-
-__all__ = ['ExceptionPxssh', 'pxssh']
-
-# Exception classes used by this module.
-class ExceptionPxssh(ExceptionPexpect):
- '''Raised for pxssh exceptions.
- '''
-
+
+__all__ = ['ExceptionPxssh', 'pxssh']
+
+# Exception classes used by this module.
+class ExceptionPxssh(ExceptionPexpect):
+ '''Raised for pxssh exceptions.
+ '''
+
if sys.version_info > (3, 0):
from shlex import quote
else:
@@ -49,240 +49,240 @@ else:
# the string $'b is then quoted as '$'"'"'b'
return "'" + s.replace("'", "'\"'\"'") + "'"
-class pxssh (spawn):
- '''This class extends pexpect.spawn to specialize setting up SSH
- connections. This adds methods for login, logout, and expecting the shell
- prompt. It does various tricky things to handle many situations in the SSH
- login process. For example, if the session is your first login, then pxssh
- automatically accepts the remote certificate; or if you have public key
- authentication setup then pxssh won't wait for the password prompt.
-
- pxssh uses the shell prompt to synchronize output from the remote host. In
- order to make this more robust it sets the shell prompt to something more
- unique than just $ or #. This should work on most Borne/Bash or Csh style
- shells.
-
- Example that runs a few commands on a remote server and prints the result::
-
+class pxssh (spawn):
+ '''This class extends pexpect.spawn to specialize setting up SSH
+ connections. This adds methods for login, logout, and expecting the shell
+ prompt. It does various tricky things to handle many situations in the SSH
+ login process. For example, if the session is your first login, then pxssh
+ automatically accepts the remote certificate; or if you have public key
+ authentication setup then pxssh won't wait for the password prompt.
+
+ pxssh uses the shell prompt to synchronize output from the remote host. In
+ order to make this more robust it sets the shell prompt to something more
+ unique than just $ or #. This should work on most Borne/Bash or Csh style
+ shells.
+
+ Example that runs a few commands on a remote server and prints the result::
+
from pexpect import pxssh
- import getpass
- try:
- s = pxssh.pxssh()
- hostname = raw_input('hostname: ')
- username = raw_input('username: ')
- password = getpass.getpass('password: ')
- s.login(hostname, username, password)
- s.sendline('uptime') # run a command
- s.prompt() # match the prompt
- print(s.before) # print everything before the prompt.
- s.sendline('ls -l')
- s.prompt()
- print(s.before)
- s.sendline('df')
- s.prompt()
- print(s.before)
- s.logout()
- except pxssh.ExceptionPxssh as e:
- print("pxssh failed on login.")
- print(e)
-
- Example showing how to specify SSH options::
-
+ import getpass
+ try:
+ s = pxssh.pxssh()
+ hostname = raw_input('hostname: ')
+ username = raw_input('username: ')
+ password = getpass.getpass('password: ')
+ s.login(hostname, username, password)
+ s.sendline('uptime') # run a command
+ s.prompt() # match the prompt
+ print(s.before) # print everything before the prompt.
+ s.sendline('ls -l')
+ s.prompt()
+ print(s.before)
+ s.sendline('df')
+ s.prompt()
+ print(s.before)
+ s.logout()
+ except pxssh.ExceptionPxssh as e:
+ print("pxssh failed on login.")
+ print(e)
+
+ Example showing how to specify SSH options::
+
from pexpect import pxssh
- s = pxssh.pxssh(options={
- "StrictHostKeyChecking": "no",
- "UserKnownHostsFile": "/dev/null"})
- ...
-
- Note that if you have ssh-agent running while doing development with pxssh
- then this can lead to a lot of confusion. Many X display managers (xdm,
- gdm, kdm, etc.) will automatically start a GUI agent. You may see a GUI
- dialog box popup asking for a password during development. You should turn
- off any key agents during testing. The 'force_password' attribute will turn
- off public key authentication. This will only work if the remote SSH server
- is configured to allow password logins. Example of using 'force_password'
- attribute::
-
- s = pxssh.pxssh()
- s.force_password = True
- hostname = raw_input('hostname: ')
- username = raw_input('username: ')
- password = getpass.getpass('password: ')
- s.login (hostname, username, password)
+ s = pxssh.pxssh(options={
+ "StrictHostKeyChecking": "no",
+ "UserKnownHostsFile": "/dev/null"})
+ ...
+
+ Note that if you have ssh-agent running while doing development with pxssh
+ then this can lead to a lot of confusion. Many X display managers (xdm,
+ gdm, kdm, etc.) will automatically start a GUI agent. You may see a GUI
+ dialog box popup asking for a password during development. You should turn
+ off any key agents during testing. The 'force_password' attribute will turn
+ off public key authentication. This will only work if the remote SSH server
+ is configured to allow password logins. Example of using 'force_password'
+ attribute::
+
+ s = pxssh.pxssh()
+ s.force_password = True
+ hostname = raw_input('hostname: ')
+ username = raw_input('username: ')
+ password = getpass.getpass('password: ')
+ s.login (hostname, username, password)
`debug_command_string` is only for the test suite to confirm that the string
generated for SSH is correct, using this will not allow you to do
anything other than get a string back from `pxssh.pxssh.login()`.
- '''
-
- def __init__ (self, timeout=30, maxread=2000, searchwindowsize=None,
- logfile=None, cwd=None, env=None, ignore_sighup=True, echo=True,
+ '''
+
+ def __init__ (self, timeout=30, maxread=2000, searchwindowsize=None,
+ logfile=None, cwd=None, env=None, ignore_sighup=True, echo=True,
options={}, encoding=None, codec_errors='strict',
debug_command_string=False, use_poll=False):
-
- spawn.__init__(self, None, timeout=timeout, maxread=maxread,
- searchwindowsize=searchwindowsize, logfile=logfile,
- cwd=cwd, env=env, ignore_sighup=ignore_sighup, echo=echo,
+
+ spawn.__init__(self, None, timeout=timeout, maxread=maxread,
+ searchwindowsize=searchwindowsize, logfile=logfile,
+ cwd=cwd, env=env, ignore_sighup=ignore_sighup, echo=echo,
encoding=encoding, codec_errors=codec_errors, use_poll=use_poll)
-
- self.name = '<pxssh>'
-
- #SUBTLE HACK ALERT! Note that the command that SETS the prompt uses a
- #slightly different string than the regular expression to match it. This
- #is because when you set the prompt the command will echo back, but we
- #don't want to match the echoed command. So if we make the set command
- #slightly different than the regex we eliminate the problem. To make the
- #set command different we add a backslash in front of $. The $ doesn't
- #need to be escaped, but it doesn't hurt and serves to make the set
- #prompt command different than the regex.
-
- # used to match the command-line prompt
+
+ self.name = '<pxssh>'
+
+ #SUBTLE HACK ALERT! Note that the command that SETS the prompt uses a
+ #slightly different string than the regular expression to match it. This
+ #is because when you set the prompt the command will echo back, but we
+ #don't want to match the echoed command. So if we make the set command
+ #slightly different than the regex we eliminate the problem. To make the
+ #set command different we add a backslash in front of $. The $ doesn't
+ #need to be escaped, but it doesn't hurt and serves to make the set
+ #prompt command different than the regex.
+
+ # used to match the command-line prompt
self.UNIQUE_PROMPT = r"\[PEXPECT\][\$\#] "
- self.PROMPT = self.UNIQUE_PROMPT
-
- # used to set shell command-line prompt to UNIQUE_PROMPT.
+ self.PROMPT = self.UNIQUE_PROMPT
+
+ # used to set shell command-line prompt to UNIQUE_PROMPT.
self.PROMPT_SET_SH = r"PS1='[PEXPECT]\$ '"
self.PROMPT_SET_CSH = r"set prompt='[PEXPECT]\$ '"
- self.SSH_OPTS = ("-o'RSAAuthentication=no'"
- + " -o 'PubkeyAuthentication=no'")
-# Disabling host key checking, makes you vulnerable to MITM attacks.
-# + " -o 'StrictHostKeyChecking=no'"
-# + " -o 'UserKnownHostsFile /dev/null' ")
- # Disabling X11 forwarding gets rid of the annoying SSH_ASKPASS from
- # displaying a GUI password dialog. I have not figured out how to
- # disable only SSH_ASKPASS without also disabling X11 forwarding.
- # Unsetting SSH_ASKPASS on the remote side doesn't disable it! Annoying!
- #self.SSH_OPTS = "-x -o'RSAAuthentication=no' -o 'PubkeyAuthentication=no'"
- self.force_password = False
+ self.SSH_OPTS = ("-o'RSAAuthentication=no'"
+ + " -o 'PubkeyAuthentication=no'")
+# Disabling host key checking, makes you vulnerable to MITM attacks.
+# + " -o 'StrictHostKeyChecking=no'"
+# + " -o 'UserKnownHostsFile /dev/null' ")
+ # Disabling X11 forwarding gets rid of the annoying SSH_ASKPASS from
+ # displaying a GUI password dialog. I have not figured out how to
+ # disable only SSH_ASKPASS without also disabling X11 forwarding.
+ # Unsetting SSH_ASKPASS on the remote side doesn't disable it! Annoying!
+ #self.SSH_OPTS = "-x -o'RSAAuthentication=no' -o 'PubkeyAuthentication=no'"
+ self.force_password = False
self.debug_command_string = debug_command_string
+
+ # User defined SSH options, eg,
+ # ssh.otions = dict(StrictHostKeyChecking="no",UserKnownHostsFile="/dev/null")
+ self.options = options
+
+ def levenshtein_distance(self, a, b):
+ '''This calculates the Levenshtein distance between a and b.
+ '''
+
+ n, m = len(a), len(b)
+ if n > m:
+ a,b = b,a
+ n,m = m,n
+ current = range(n+1)
+ for i in range(1,m+1):
+ previous, current = current, [i]+[0]*n
+ for j in range(1,n+1):
+ add, delete = previous[j]+1, current[j-1]+1
+ change = previous[j-1]
+ if a[j-1] != b[i-1]:
+ change = change + 1
+ current[j] = min(add, delete, change)
+ return current[n]
+
+ def try_read_prompt(self, timeout_multiplier):
+ '''This facilitates using communication timeouts to perform
+ synchronization as quickly as possible, while supporting high latency
+ connections with a tunable worst case performance. Fast connections
+ should be read almost immediately. Worst case performance for this
+ method is timeout_multiplier * 3 seconds.
+ '''
+
+ # maximum time allowed to read the first response
+ first_char_timeout = timeout_multiplier * 0.5
+
+ # maximum time allowed between subsequent characters
+ inter_char_timeout = timeout_multiplier * 0.1
+
+ # maximum time for reading the entire prompt
+ total_timeout = timeout_multiplier * 3.0
+
+ prompt = self.string_type()
+ begin = time.time()
+ expired = 0.0
+ timeout = first_char_timeout
+
+ while expired < total_timeout:
+ try:
+ prompt += self.read_nonblocking(size=1, timeout=timeout)
+ expired = time.time() - begin # updated total time expired
+ timeout = inter_char_timeout
+ except TIMEOUT:
+ break
+
+ return prompt
+
+ def sync_original_prompt (self, sync_multiplier=1.0):
+ '''This attempts to find the prompt. Basically, press enter and record
+ the response; press enter again and record the response; if the two
+ responses are similar then assume we are at the original prompt.
+ This can be a slow function. Worst case with the default sync_multiplier
+ can take 12 seconds. Low latency connections are more likely to fail
+ with a low sync_multiplier. Best case sync time gets worse with a
+ high sync multiplier (500 ms with default). '''
- # User defined SSH options, eg,
- # ssh.otions = dict(StrictHostKeyChecking="no",UserKnownHostsFile="/dev/null")
- self.options = options
-
- def levenshtein_distance(self, a, b):
- '''This calculates the Levenshtein distance between a and b.
- '''
-
- n, m = len(a), len(b)
- if n > m:
- a,b = b,a
- n,m = m,n
- current = range(n+1)
- for i in range(1,m+1):
- previous, current = current, [i]+[0]*n
- for j in range(1,n+1):
- add, delete = previous[j]+1, current[j-1]+1
- change = previous[j-1]
- if a[j-1] != b[i-1]:
- change = change + 1
- current[j] = min(add, delete, change)
- return current[n]
-
- def try_read_prompt(self, timeout_multiplier):
- '''This facilitates using communication timeouts to perform
- synchronization as quickly as possible, while supporting high latency
- connections with a tunable worst case performance. Fast connections
- should be read almost immediately. Worst case performance for this
- method is timeout_multiplier * 3 seconds.
- '''
-
- # maximum time allowed to read the first response
- first_char_timeout = timeout_multiplier * 0.5
-
- # maximum time allowed between subsequent characters
- inter_char_timeout = timeout_multiplier * 0.1
-
- # maximum time for reading the entire prompt
- total_timeout = timeout_multiplier * 3.0
-
- prompt = self.string_type()
- begin = time.time()
- expired = 0.0
- timeout = first_char_timeout
-
- while expired < total_timeout:
- try:
- prompt += self.read_nonblocking(size=1, timeout=timeout)
- expired = time.time() - begin # updated total time expired
- timeout = inter_char_timeout
- except TIMEOUT:
- break
-
- return prompt
-
- def sync_original_prompt (self, sync_multiplier=1.0):
- '''This attempts to find the prompt. Basically, press enter and record
- the response; press enter again and record the response; if the two
- responses are similar then assume we are at the original prompt.
- This can be a slow function. Worst case with the default sync_multiplier
- can take 12 seconds. Low latency connections are more likely to fail
- with a low sync_multiplier. Best case sync time gets worse with a
- high sync multiplier (500 ms with default). '''
-
- # All of these timing pace values are magic.
- # I came up with these based on what seemed reliable for
- # connecting to a heavily loaded machine I have.
- self.sendline()
- time.sleep(0.1)
-
- try:
- # Clear the buffer before getting the prompt.
- self.try_read_prompt(sync_multiplier)
- except TIMEOUT:
- pass
-
- self.sendline()
- x = self.try_read_prompt(sync_multiplier)
-
- self.sendline()
- a = self.try_read_prompt(sync_multiplier)
-
- self.sendline()
- b = self.try_read_prompt(sync_multiplier)
-
- ld = self.levenshtein_distance(a,b)
- len_a = len(a)
- if len_a == 0:
- return False
- if float(ld)/len_a < 0.4:
- return True
- return False
-
- ### TODO: This is getting messy and I'm pretty sure this isn't perfect.
- ### TODO: I need to draw a flow chart for this.
+ # All of these timing pace values are magic.
+ # I came up with these based on what seemed reliable for
+ # connecting to a heavily loaded machine I have.
+ self.sendline()
+ time.sleep(0.1)
+
+ try:
+ # Clear the buffer before getting the prompt.
+ self.try_read_prompt(sync_multiplier)
+ except TIMEOUT:
+ pass
+
+ self.sendline()
+ x = self.try_read_prompt(sync_multiplier)
+
+ self.sendline()
+ a = self.try_read_prompt(sync_multiplier)
+
+ self.sendline()
+ b = self.try_read_prompt(sync_multiplier)
+
+ ld = self.levenshtein_distance(a,b)
+ len_a = len(a)
+ if len_a == 0:
+ return False
+ if float(ld)/len_a < 0.4:
+ return True
+ return False
+
+ ### TODO: This is getting messy and I'm pretty sure this isn't perfect.
+ ### TODO: I need to draw a flow chart for this.
### TODO: Unit tests for SSH tunnels, remote SSH command exec, disabling original prompt sync
def login (self, server, username=None, password='', terminal_type='ansi',
- original_prompt=r"[#$]", login_timeout=10, port=None,
- auto_prompt_reset=True, ssh_key=None, quiet=True,
+ original_prompt=r"[#$]", login_timeout=10, port=None,
+ auto_prompt_reset=True, ssh_key=None, quiet=True,
sync_multiplier=1, check_local_ip=True,
password_regex=r'(?i)(?:password:)|(?:passphrase for key)',
ssh_tunnels={}, spawn_local_ssh=True,
sync_original_prompt=True, ssh_config=None, cmd='ssh'):
- '''This logs the user into the given server.
-
+ '''This logs the user into the given server.
+
It uses 'original_prompt' to try to find the prompt right after login.
When it finds the prompt it immediately tries to reset the prompt to
something more easily matched. The default 'original_prompt' is very
optimistic and is easily fooled. It's more reliable to try to match the original
- prompt as exactly as possible to prevent false matches by server
- strings such as the "Message Of The Day". On many systems you can
- disable the MOTD on the remote server by creating a zero-length file
- called :file:`~/.hushlogin` on the remote server. If a prompt cannot be found
- then this will not necessarily cause the login to fail. In the case of
- a timeout when looking for the prompt we assume that the original
- prompt was so weird that we could not match it, so we use a few tricks
- to guess when we have reached the prompt. Then we hope for the best and
- blindly try to reset the prompt to something more unique. If that fails
- then login() raises an :class:`ExceptionPxssh` exception.
-
- In some situations it is not possible or desirable to reset the
- original prompt. In this case, pass ``auto_prompt_reset=False`` to
- inhibit setting the prompt to the UNIQUE_PROMPT. Remember that pxssh
- uses a unique prompt in the :meth:`prompt` method. If the original prompt is
- not reset then this will disable the :meth:`prompt` method unless you
- manually set the :attr:`PROMPT` attribute.
+ prompt as exactly as possible to prevent false matches by server
+ strings such as the "Message Of The Day". On many systems you can
+ disable the MOTD on the remote server by creating a zero-length file
+ called :file:`~/.hushlogin` on the remote server. If a prompt cannot be found
+ then this will not necessarily cause the login to fail. In the case of
+ a timeout when looking for the prompt we assume that the original
+ prompt was so weird that we could not match it, so we use a few tricks
+ to guess when we have reached the prompt. Then we hope for the best and
+ blindly try to reset the prompt to something more unique. If that fails
+ then login() raises an :class:`ExceptionPxssh` exception.
+
+ In some situations it is not possible or desirable to reset the
+ original prompt. In this case, pass ``auto_prompt_reset=False`` to
+ inhibit setting the prompt to the UNIQUE_PROMPT. Remember that pxssh
+ uses a unique prompt in the :meth:`prompt` method. If the original prompt is
+ not reset then this will disable the :meth:`prompt` method unless you
+ manually set the :attr:`PROMPT` attribute.
Set ``password_regex`` if there is a MOTD message with `password` in it.
Changing this is like playing in traffic, don't (p)expect it to match straight
@@ -306,27 +306,27 @@ class pxssh (spawn):
Alter the ``cmd`` to change the ssh client used, or to prepend it with network
namespaces. For example ```cmd="ip netns exec vlan2 ssh"``` to execute the ssh in
network namespace named ```vlan```.
- '''
+ '''
session_regex_array = ["(?i)are you sure you want to continue connecting", original_prompt, password_regex, "(?i)permission denied", "(?i)terminal type", TIMEOUT]
session_init_regex_array = []
session_init_regex_array.extend(session_regex_array)
session_init_regex_array.extend(["(?i)connection closed by remote host", EOF])
-
- ssh_options = ''.join([" -o '%s=%s'" % (o, v) for (o, v) in self.options.items()])
- if quiet:
- ssh_options = ssh_options + ' -q'
- if not check_local_ip:
- ssh_options = ssh_options + " -o'NoHostAuthenticationForLocalhost=yes'"
- if self.force_password:
- ssh_options = ssh_options + ' ' + self.SSH_OPTS
+
+ ssh_options = ''.join([" -o '%s=%s'" % (o, v) for (o, v) in self.options.items()])
+ if quiet:
+ ssh_options = ssh_options + ' -q'
+ if not check_local_ip:
+ ssh_options = ssh_options + " -o'NoHostAuthenticationForLocalhost=yes'"
+ if self.force_password:
+ ssh_options = ssh_options + ' ' + self.SSH_OPTS
if ssh_config is not None:
if spawn_local_ssh and not os.path.isfile(ssh_config):
raise ExceptionPxssh('SSH config does not exist or is not a file.')
ssh_options = ssh_options + ' -F ' + ssh_config
- if port is not None:
- ssh_options = ssh_options + ' -p %s'%(str(port))
- if ssh_key is not None:
+ if port is not None:
+ ssh_options = ssh_options + ' -p %s'%(str(port))
+ if ssh_key is not None:
# Allow forwarding our SSH key to the current session
if ssh_key==True:
ssh_options = ssh_options + ' -A'
@@ -395,143 +395,143 @@ class pxssh (spawn):
cmd += " %s %s" % (ssh_options, server)
if self.debug_command_string:
return(cmd)
-
+
# Are we asking for a local ssh command or to spawn one in another session?
if spawn_local_ssh:
spawn._spawn(self, cmd)
else:
self.sendline(cmd)
- # This does not distinguish between a remote server 'password' prompt
- # and a local ssh 'passphrase' prompt (for unlocking a private key).
+ # This does not distinguish between a remote server 'password' prompt
+ # and a local ssh 'passphrase' prompt (for unlocking a private key).
i = self.expect(session_init_regex_array, timeout=login_timeout)
-
- # First phase
- if i==0:
- # New certificate -- always accept it.
- # This is what you get if SSH does not have the remote host's
- # public key stored in the 'known_hosts' cache.
- self.sendline("yes")
+
+ # First phase
+ if i==0:
+ # New certificate -- always accept it.
+ # This is what you get if SSH does not have the remote host's
+ # public key stored in the 'known_hosts' cache.
+ self.sendline("yes")
i = self.expect(session_regex_array)
- if i==2: # password or passphrase
- self.sendline(password)
+ if i==2: # password or passphrase
+ self.sendline(password)
i = self.expect(session_regex_array)
- if i==4:
- self.sendline(terminal_type)
+ if i==4:
+ self.sendline(terminal_type)
i = self.expect(session_regex_array)
if i==7:
self.close()
raise ExceptionPxssh('Could not establish connection to host')
-
- # Second phase
- if i==0:
- # This is weird. This should not happen twice in a row.
- self.close()
- raise ExceptionPxssh('Weird error. Got "are you sure" prompt twice.')
- elif i==1: # can occur if you have a public key pair set to authenticate.
- ### TODO: May NOT be OK if expect() got tricked and matched a false prompt.
- pass
- elif i==2: # password prompt again
- # For incorrect passwords, some ssh servers will
- # ask for the password again, others return 'denied' right away.
- # If we get the password prompt again then this means
- # we didn't get the password right the first time.
- self.close()
- raise ExceptionPxssh('password refused')
- elif i==3: # permission denied -- password was bad.
- self.close()
- raise ExceptionPxssh('permission denied')
- elif i==4: # terminal type again? WTF?
- self.close()
- raise ExceptionPxssh('Weird error. Got "terminal type" prompt twice.')
- elif i==5: # Timeout
- #This is tricky... I presume that we are at the command-line prompt.
- #It may be that the shell prompt was so weird that we couldn't match
- #it. Or it may be that we couldn't log in for some other reason. I
- #can't be sure, but it's safe to guess that we did login because if
- #I presume wrong and we are not logged in then this should be caught
- #later when I try to set the shell prompt.
- pass
- elif i==6: # Connection closed by remote host
- self.close()
- raise ExceptionPxssh('connection closed')
- else: # Unexpected
- self.close()
- raise ExceptionPxssh('unexpected login response')
+
+ # Second phase
+ if i==0:
+ # This is weird. This should not happen twice in a row.
+ self.close()
+ raise ExceptionPxssh('Weird error. Got "are you sure" prompt twice.')
+ elif i==1: # can occur if you have a public key pair set to authenticate.
+ ### TODO: May NOT be OK if expect() got tricked and matched a false prompt.
+ pass
+ elif i==2: # password prompt again
+ # For incorrect passwords, some ssh servers will
+ # ask for the password again, others return 'denied' right away.
+ # If we get the password prompt again then this means
+ # we didn't get the password right the first time.
+ self.close()
+ raise ExceptionPxssh('password refused')
+ elif i==3: # permission denied -- password was bad.
+ self.close()
+ raise ExceptionPxssh('permission denied')
+ elif i==4: # terminal type again? WTF?
+ self.close()
+ raise ExceptionPxssh('Weird error. Got "terminal type" prompt twice.')
+ elif i==5: # Timeout
+ #This is tricky... I presume that we are at the command-line prompt.
+ #It may be that the shell prompt was so weird that we couldn't match
+ #it. Or it may be that we couldn't log in for some other reason. I
+ #can't be sure, but it's safe to guess that we did login because if
+ #I presume wrong and we are not logged in then this should be caught
+ #later when I try to set the shell prompt.
+ pass
+ elif i==6: # Connection closed by remote host
+ self.close()
+ raise ExceptionPxssh('connection closed')
+ else: # Unexpected
+ self.close()
+ raise ExceptionPxssh('unexpected login response')
if sync_original_prompt:
if not self.sync_original_prompt(sync_multiplier):
self.close()
raise ExceptionPxssh('could not synchronize with original prompt')
- # We appear to be in.
- # set shell prompt to something unique.
- if auto_prompt_reset:
- if not self.set_unique_prompt():
- self.close()
- raise ExceptionPxssh('could not set shell prompt '
- '(received: %r, expected: %r).' % (
- self.before, self.PROMPT,))
- return True
-
- def logout (self):
- '''Sends exit to the remote shell.
-
- If there are stopped jobs then this automatically sends exit twice.
- '''
- self.sendline("exit")
- index = self.expect([EOF, "(?i)there are stopped jobs"])
- if index==1:
- self.sendline("exit")
- self.expect(EOF)
- self.close()
-
- def prompt(self, timeout=-1):
- '''Match the next shell prompt.
-
- This is little more than a short-cut to the :meth:`~pexpect.spawn.expect`
- method. Note that if you called :meth:`login` with
- ``auto_prompt_reset=False``, then before calling :meth:`prompt` you must
- set the :attr:`PROMPT` attribute to a regex that it will use for
- matching the prompt.
-
- Calling :meth:`prompt` will erase the contents of the :attr:`before`
- attribute even if no prompt is ever matched. If timeout is not given or
- it is set to -1 then self.timeout is used.
-
- :return: True if the shell prompt was matched, False if the timeout was
- reached.
- '''
-
- if timeout == -1:
- timeout = self.timeout
- i = self.expect([self.PROMPT, TIMEOUT], timeout=timeout)
- if i==1:
- return False
- return True
-
- def set_unique_prompt(self):
- '''This sets the remote prompt to something more unique than ``#`` or ``$``.
- This makes it easier for the :meth:`prompt` method to match the shell prompt
- unambiguously. This method is called automatically by the :meth:`login`
- method, but you may want to call it manually if you somehow reset the
- shell prompt. For example, if you 'su' to a different user then you
- will need to manually reset the prompt. This sends shell commands to
- the remote host to set the prompt, so this assumes the remote host is
- ready to receive commands.
-
- Alternatively, you may use your own prompt pattern. In this case you
- should call :meth:`login` with ``auto_prompt_reset=False``; then set the
- :attr:`PROMPT` attribute to a regular expression. After that, the
- :meth:`prompt` method will try to match your prompt pattern.
- '''
-
- self.sendline("unset PROMPT_COMMAND")
- self.sendline(self.PROMPT_SET_SH) # sh-style
- i = self.expect ([TIMEOUT, self.PROMPT], timeout=10)
- if i == 0: # csh-style
- self.sendline(self.PROMPT_SET_CSH)
- i = self.expect([TIMEOUT, self.PROMPT], timeout=10)
- if i == 0:
- return False
- return True
-
-# vi:ts=4:sw=4:expandtab:ft=python:
+ # We appear to be in.
+ # set shell prompt to something unique.
+ if auto_prompt_reset:
+ if not self.set_unique_prompt():
+ self.close()
+ raise ExceptionPxssh('could not set shell prompt '
+ '(received: %r, expected: %r).' % (
+ self.before, self.PROMPT,))
+ return True
+
+ def logout (self):
+ '''Sends exit to the remote shell.
+
+ If there are stopped jobs then this automatically sends exit twice.
+ '''
+ self.sendline("exit")
+ index = self.expect([EOF, "(?i)there are stopped jobs"])
+ if index==1:
+ self.sendline("exit")
+ self.expect(EOF)
+ self.close()
+
+ def prompt(self, timeout=-1):
+ '''Match the next shell prompt.
+
+ This is little more than a short-cut to the :meth:`~pexpect.spawn.expect`
+ method. Note that if you called :meth:`login` with
+ ``auto_prompt_reset=False``, then before calling :meth:`prompt` you must
+ set the :attr:`PROMPT` attribute to a regex that it will use for
+ matching the prompt.
+
+ Calling :meth:`prompt` will erase the contents of the :attr:`before`
+ attribute even if no prompt is ever matched. If timeout is not given or
+ it is set to -1 then self.timeout is used.
+
+ :return: True if the shell prompt was matched, False if the timeout was
+ reached.
+ '''
+
+ if timeout == -1:
+ timeout = self.timeout
+ i = self.expect([self.PROMPT, TIMEOUT], timeout=timeout)
+ if i==1:
+ return False
+ return True
+
+ def set_unique_prompt(self):
+ '''This sets the remote prompt to something more unique than ``#`` or ``$``.
+ This makes it easier for the :meth:`prompt` method to match the shell prompt
+ unambiguously. This method is called automatically by the :meth:`login`
+ method, but you may want to call it manually if you somehow reset the
+ shell prompt. For example, if you 'su' to a different user then you
+ will need to manually reset the prompt. This sends shell commands to
+ the remote host to set the prompt, so this assumes the remote host is
+ ready to receive commands.
+
+ Alternatively, you may use your own prompt pattern. In this case you
+ should call :meth:`login` with ``auto_prompt_reset=False``; then set the
+ :attr:`PROMPT` attribute to a regular expression. After that, the
+ :meth:`prompt` method will try to match your prompt pattern.
+ '''
+
+ self.sendline("unset PROMPT_COMMAND")
+ self.sendline(self.PROMPT_SET_SH) # sh-style
+ i = self.expect ([TIMEOUT, self.PROMPT], timeout=10)
+ if i == 0: # csh-style
+ self.sendline(self.PROMPT_SET_CSH)
+ i = self.expect([TIMEOUT, self.PROMPT], timeout=10)
+ if i == 0:
+ return False
+ return True
+
+# vi:ts=4:sw=4:expandtab:ft=python:
diff --git a/contrib/python/pexpect/pexpect/replwrap.py b/contrib/python/pexpect/pexpect/replwrap.py
index c930f1e4fe0..79562de4c12 100644
--- a/contrib/python/pexpect/pexpect/replwrap.py
+++ b/contrib/python/pexpect/pexpect/replwrap.py
@@ -1,122 +1,122 @@
-"""Generic wrapper for read-eval-print-loops, a.k.a. interactive shells
-"""
-import os.path
-import signal
-import sys
-
-import pexpect
-
-PY3 = (sys.version_info[0] >= 3)
-
-if PY3:
- basestring = str
-
-PEXPECT_PROMPT = u'[PEXPECT_PROMPT>'
-PEXPECT_CONTINUATION_PROMPT = u'[PEXPECT_PROMPT+'
-
-class REPLWrapper(object):
- """Wrapper for a REPL.
-
- :param cmd_or_spawn: This can either be an instance of :class:`pexpect.spawn`
- in which a REPL has already been started, or a str command to start a new
- REPL process.
- :param str orig_prompt: The prompt to expect at first.
- :param str prompt_change: A command to change the prompt to something more
- unique. If this is ``None``, the prompt will not be changed. This will
- be formatted with the new and continuation prompts as positional
- parameters, so you can use ``{}`` style formatting to insert them into
- the command.
- :param str new_prompt: The more unique prompt to expect after the change.
- :param str extra_init_cmd: Commands to do extra initialisation, such as
- disabling pagers.
- """
- def __init__(self, cmd_or_spawn, orig_prompt, prompt_change,
- new_prompt=PEXPECT_PROMPT,
- continuation_prompt=PEXPECT_CONTINUATION_PROMPT,
- extra_init_cmd=None):
- if isinstance(cmd_or_spawn, basestring):
- self.child = pexpect.spawn(cmd_or_spawn, echo=False, encoding='utf-8')
- else:
- self.child = cmd_or_spawn
- if self.child.echo:
- # Existing spawn instance has echo enabled, disable it
- # to prevent our input from being repeated to output.
- self.child.setecho(False)
- self.child.waitnoecho()
-
- if prompt_change is None:
- self.prompt = orig_prompt
- else:
- self.set_prompt(orig_prompt,
- prompt_change.format(new_prompt, continuation_prompt))
- self.prompt = new_prompt
- self.continuation_prompt = continuation_prompt
-
- self._expect_prompt()
-
- if extra_init_cmd is not None:
- self.run_command(extra_init_cmd)
-
- def set_prompt(self, orig_prompt, prompt_change):
- self.child.expect(orig_prompt)
- self.child.sendline(prompt_change)
-
+"""Generic wrapper for read-eval-print-loops, a.k.a. interactive shells
+"""
+import os.path
+import signal
+import sys
+
+import pexpect
+
+PY3 = (sys.version_info[0] >= 3)
+
+if PY3:
+ basestring = str
+
+PEXPECT_PROMPT = u'[PEXPECT_PROMPT>'
+PEXPECT_CONTINUATION_PROMPT = u'[PEXPECT_PROMPT+'
+
+class REPLWrapper(object):
+ """Wrapper for a REPL.
+
+ :param cmd_or_spawn: This can either be an instance of :class:`pexpect.spawn`
+ in which a REPL has already been started, or a str command to start a new
+ REPL process.
+ :param str orig_prompt: The prompt to expect at first.
+ :param str prompt_change: A command to change the prompt to something more
+ unique. If this is ``None``, the prompt will not be changed. This will
+ be formatted with the new and continuation prompts as positional
+ parameters, so you can use ``{}`` style formatting to insert them into
+ the command.
+ :param str new_prompt: The more unique prompt to expect after the change.
+ :param str extra_init_cmd: Commands to do extra initialisation, such as
+ disabling pagers.
+ """
+ def __init__(self, cmd_or_spawn, orig_prompt, prompt_change,
+ new_prompt=PEXPECT_PROMPT,
+ continuation_prompt=PEXPECT_CONTINUATION_PROMPT,
+ extra_init_cmd=None):
+ if isinstance(cmd_or_spawn, basestring):
+ self.child = pexpect.spawn(cmd_or_spawn, echo=False, encoding='utf-8')
+ else:
+ self.child = cmd_or_spawn
+ if self.child.echo:
+ # Existing spawn instance has echo enabled, disable it
+ # to prevent our input from being repeated to output.
+ self.child.setecho(False)
+ self.child.waitnoecho()
+
+ if prompt_change is None:
+ self.prompt = orig_prompt
+ else:
+ self.set_prompt(orig_prompt,
+ prompt_change.format(new_prompt, continuation_prompt))
+ self.prompt = new_prompt
+ self.continuation_prompt = continuation_prompt
+
+ self._expect_prompt()
+
+ if extra_init_cmd is not None:
+ self.run_command(extra_init_cmd)
+
+ def set_prompt(self, orig_prompt, prompt_change):
+ self.child.expect(orig_prompt)
+ self.child.sendline(prompt_change)
+
def _expect_prompt(self, timeout=-1, async_=False):
- return self.child.expect_exact([self.prompt, self.continuation_prompt],
+ return self.child.expect_exact([self.prompt, self.continuation_prompt],
timeout=timeout, async_=async_)
-
+
def run_command(self, command, timeout=-1, async_=False):
- """Send a command to the REPL, wait for and return output.
-
- :param str command: The command to send. Trailing newlines are not needed.
- This should be a complete block of input that will trigger execution;
- if a continuation prompt is found after sending input, :exc:`ValueError`
- will be raised.
- :param int timeout: How long to wait for the next prompt. -1 means the
- default from the :class:`pexpect.spawn` object (default 30 seconds).
- None means to wait indefinitely.
+ """Send a command to the REPL, wait for and return output.
+
+ :param str command: The command to send. Trailing newlines are not needed.
+ This should be a complete block of input that will trigger execution;
+ if a continuation prompt is found after sending input, :exc:`ValueError`
+ will be raised.
+ :param int timeout: How long to wait for the next prompt. -1 means the
+ default from the :class:`pexpect.spawn` object (default 30 seconds).
+ None means to wait indefinitely.
:param bool async_: On Python 3.4, or Python 3.3 with asyncio
installed, passing ``async_=True`` will make this return an
:mod:`asyncio` Future, which you can yield from to get the same
result that this method would normally give directly.
- """
- # Split up multiline commands and feed them in bit-by-bit
- cmdlines = command.splitlines()
- # splitlines ignores trailing newlines - add it back in manually
- if command.endswith('\n'):
- cmdlines.append('')
- if not cmdlines:
- raise ValueError("No command was given")
-
+ """
+ # Split up multiline commands and feed them in bit-by-bit
+ cmdlines = command.splitlines()
+ # splitlines ignores trailing newlines - add it back in manually
+ if command.endswith('\n'):
+ cmdlines.append('')
+ if not cmdlines:
+ raise ValueError("No command was given")
+
if async_:
from ._async import repl_run_command_async
return repl_run_command_async(self, cmdlines, timeout)
- res = []
- self.child.sendline(cmdlines[0])
- for line in cmdlines[1:]:
- self._expect_prompt(timeout=timeout)
- res.append(self.child.before)
- self.child.sendline(line)
-
- # Command was fully submitted, now wait for the next prompt
- if self._expect_prompt(timeout=timeout) == 1:
- # We got the continuation prompt - command was incomplete
- self.child.kill(signal.SIGINT)
- self._expect_prompt(timeout=1)
- raise ValueError("Continuation prompt found - input was incomplete:\n"
- + command)
- return u''.join(res + [self.child.before])
-
-def python(command="python"):
- """Start a Python shell and return a :class:`REPLWrapper` object."""
- return REPLWrapper(command, u">>> ", u"import sys; sys.ps1={0!r}; sys.ps2={1!r}")
-
-def bash(command="bash"):
- """Start a bash shell and return a :class:`REPLWrapper` object."""
- bashrc = os.path.join(os.path.dirname(__file__), 'bashrc.sh')
- child = pexpect.spawn(command, ['--rcfile', bashrc], echo=False,
- encoding='utf-8')
+ res = []
+ self.child.sendline(cmdlines[0])
+ for line in cmdlines[1:]:
+ self._expect_prompt(timeout=timeout)
+ res.append(self.child.before)
+ self.child.sendline(line)
+
+ # Command was fully submitted, now wait for the next prompt
+ if self._expect_prompt(timeout=timeout) == 1:
+ # We got the continuation prompt - command was incomplete
+ self.child.kill(signal.SIGINT)
+ self._expect_prompt(timeout=1)
+ raise ValueError("Continuation prompt found - input was incomplete:\n"
+ + command)
+ return u''.join(res + [self.child.before])
+
+def python(command="python"):
+ """Start a Python shell and return a :class:`REPLWrapper` object."""
+ return REPLWrapper(command, u">>> ", u"import sys; sys.ps1={0!r}; sys.ps2={1!r}")
+
+def bash(command="bash"):
+ """Start a bash shell and return a :class:`REPLWrapper` object."""
+ bashrc = os.path.join(os.path.dirname(__file__), 'bashrc.sh')
+ child = pexpect.spawn(command, ['--rcfile', bashrc], echo=False,
+ encoding='utf-8')
# If the user runs 'env', the value of PS1 will be in the output. To avoid
# replwrap seeing that as the next prompt, we'll embed the marker characters
@@ -127,4 +127,4 @@ def bash(command="bash"):
prompt_change = u"PS1='{0}' PS2='{1}' PROMPT_COMMAND=''".format(ps1, ps2)
return REPLWrapper(child, u'\\$', prompt_change,
- extra_init_cmd="export PAGER=cat")
+ extra_init_cmd="export PAGER=cat")
diff --git a/contrib/python/pexpect/pexpect/run.py b/contrib/python/pexpect/pexpect/run.py
index ff288a12461..ccfd6050d64 100644
--- a/contrib/python/pexpect/pexpect/run.py
+++ b/contrib/python/pexpect/pexpect/run.py
@@ -1,157 +1,157 @@
-import sys
-import types
+import sys
+import types
+
+from .exceptions import EOF, TIMEOUT
+from .pty_spawn import spawn
+
+def run(command, timeout=30, withexitstatus=False, events=None,
+ extra_args=None, logfile=None, cwd=None, env=None, **kwargs):
+
+ '''
+ This function runs the given command; waits for it to finish; then
+ returns all output as a string. STDERR is included in output. If the full
+ path to the command is not given then the path is searched.
+
+ Note that lines are terminated by CR/LF (\\r\\n) combination even on
+ UNIX-like systems because this is the standard for pseudottys. If you set
+ 'withexitstatus' to true, then run will return a tuple of (command_output,
+ exitstatus). If 'withexitstatus' is false then this returns just
+ command_output.
+
+ The run() function can often be used instead of creating a spawn instance.
+ For example, the following code uses spawn::
+
+ from pexpect import *
+ child = spawn('scp foo [email protected]:.')
+ child.expect('(?i)password')
+ child.sendline(mypassword)
+
+ The previous code can be replace with the following::
+
+ from pexpect import *
+ run('scp foo [email protected]:.', events={'(?i)password': mypassword})
+
+ **Examples**
+
+ Start the apache daemon on the local machine::
+
+ from pexpect import *
+ run("/usr/local/apache/bin/apachectl start")
+
+ Check in a file using SVN::
+
+ from pexpect import *
+ run("svn ci -m 'automatic commit' my_file.py")
+
+ Run a command and capture exit status::
+
+ from pexpect import *
+ (command_output, exitstatus) = run('ls -l /bin', withexitstatus=1)
+
+ The following will run SSH and execute 'ls -l' on the remote machine. The
+ password 'secret' will be sent if the '(?i)password' pattern is ever seen::
+
+ run("ssh [email protected] 'ls -l'",
+ events={'(?i)password':'secret\\n'})
+
+ This will start mencoder to rip a video from DVD. This will also display
+ progress ticks every 5 seconds as it runs. For example::
+
+ from pexpect import *
+ def print_ticks(d):
+ print d['event_count'],
+ run("mencoder dvd://1 -o video.avi -oac copy -ovc copy",
+ events={TIMEOUT:print_ticks}, timeout=5)
+
+ The 'events' argument should be either a dictionary or a tuple list that
+ contains patterns and responses. Whenever one of the patterns is seen
+ in the command output, run() will send the associated response string.
+ So, run() in the above example can be also written as:
-from .exceptions import EOF, TIMEOUT
-from .pty_spawn import spawn
-
-def run(command, timeout=30, withexitstatus=False, events=None,
- extra_args=None, logfile=None, cwd=None, env=None, **kwargs):
-
- '''
- This function runs the given command; waits for it to finish; then
- returns all output as a string. STDERR is included in output. If the full
- path to the command is not given then the path is searched.
-
- Note that lines are terminated by CR/LF (\\r\\n) combination even on
- UNIX-like systems because this is the standard for pseudottys. If you set
- 'withexitstatus' to true, then run will return a tuple of (command_output,
- exitstatus). If 'withexitstatus' is false then this returns just
- command_output.
-
- The run() function can often be used instead of creating a spawn instance.
- For example, the following code uses spawn::
-
- from pexpect import *
- child = spawn('scp foo [email protected]:.')
- child.expect('(?i)password')
- child.sendline(mypassword)
-
- The previous code can be replace with the following::
-
- from pexpect import *
- run('scp foo [email protected]:.', events={'(?i)password': mypassword})
-
- **Examples**
-
- Start the apache daemon on the local machine::
-
- from pexpect import *
- run("/usr/local/apache/bin/apachectl start")
-
- Check in a file using SVN::
-
- from pexpect import *
- run("svn ci -m 'automatic commit' my_file.py")
-
- Run a command and capture exit status::
-
- from pexpect import *
- (command_output, exitstatus) = run('ls -l /bin', withexitstatus=1)
-
- The following will run SSH and execute 'ls -l' on the remote machine. The
- password 'secret' will be sent if the '(?i)password' pattern is ever seen::
-
- run("ssh [email protected] 'ls -l'",
- events={'(?i)password':'secret\\n'})
-
- This will start mencoder to rip a video from DVD. This will also display
- progress ticks every 5 seconds as it runs. For example::
-
- from pexpect import *
- def print_ticks(d):
- print d['event_count'],
- run("mencoder dvd://1 -o video.avi -oac copy -ovc copy",
- events={TIMEOUT:print_ticks}, timeout=5)
-
- The 'events' argument should be either a dictionary or a tuple list that
- contains patterns and responses. Whenever one of the patterns is seen
- in the command output, run() will send the associated response string.
- So, run() in the above example can be also written as:
-
- run("mencoder dvd://1 -o video.avi -oac copy -ovc copy",
- events=[(TIMEOUT,print_ticks)], timeout=5)
-
- Use a tuple list for events if the command output requires a delicate
- control over what pattern should be matched, since the tuple list is passed
- to pexpect() as its pattern list, with the order of patterns preserved.
-
- Note that you should put newlines in your string if Enter is necessary.
-
- Like the example above, the responses may also contain a callback, either
- a function or method. It should accept a dictionary value as an argument.
- The dictionary contains all the locals from the run() function, so you can
- access the child spawn object or any other variable defined in run()
- (event_count, child, and extra_args are the most useful). A callback may
- return True to stop the current run process. Otherwise run() continues
- until the next event. A callback may also return a string which will be
- sent to the child. 'extra_args' is not used by directly run(). It provides
- a way to pass data to a callback function through run() through the locals
- dictionary passed to a callback.
-
- Like :class:`spawn`, passing *encoding* will make it work with unicode
- instead of bytes. You can pass *codec_errors* to control how errors in
- encoding and decoding are handled.
- '''
- if timeout == -1:
- child = spawn(command, maxread=2000, logfile=logfile, cwd=cwd, env=env,
- **kwargs)
- else:
- child = spawn(command, timeout=timeout, maxread=2000, logfile=logfile,
- cwd=cwd, env=env, **kwargs)
- if isinstance(events, list):
- patterns= [x for x,y in events]
- responses = [y for x,y in events]
- elif isinstance(events, dict):
- patterns = list(events.keys())
- responses = list(events.values())
- else:
- # This assumes EOF or TIMEOUT will eventually cause run to terminate.
- patterns = None
- responses = None
- child_result_list = []
- event_count = 0
- while True:
- try:
- index = child.expect(patterns)
- if isinstance(child.after, child.allowed_string_types):
- child_result_list.append(child.before + child.after)
- else:
- # child.after may have been a TIMEOUT or EOF,
- # which we don't want appended to the list.
- child_result_list.append(child.before)
- if isinstance(responses[index], child.allowed_string_types):
- child.send(responses[index])
- elif (isinstance(responses[index], types.FunctionType) or
- isinstance(responses[index], types.MethodType)):
- callback_result = responses[index](locals())
- sys.stdout.flush()
- if isinstance(callback_result, child.allowed_string_types):
- child.send(callback_result)
- elif callback_result:
- break
- else:
- raise TypeError("parameter `event' at index {index} must be "
- "a string, method, or function: {value!r}"
- .format(index=index, value=responses[index]))
- event_count = event_count + 1
- except TIMEOUT:
- child_result_list.append(child.before)
- break
- except EOF:
- child_result_list.append(child.before)
- break
- child_result = child.string_type().join(child_result_list)
- if withexitstatus:
- child.close()
- return (child_result, child.exitstatus)
- else:
- return child_result
-
-def runu(command, timeout=30, withexitstatus=False, events=None,
- extra_args=None, logfile=None, cwd=None, env=None, **kwargs):
- """Deprecated: pass encoding to run() instead.
- """
- kwargs.setdefault('encoding', 'utf-8')
- return run(command, timeout=timeout, withexitstatus=withexitstatus,
- events=events, extra_args=extra_args, logfile=logfile, cwd=cwd,
- env=env, **kwargs)
+ run("mencoder dvd://1 -o video.avi -oac copy -ovc copy",
+ events=[(TIMEOUT,print_ticks)], timeout=5)
+
+ Use a tuple list for events if the command output requires a delicate
+ control over what pattern should be matched, since the tuple list is passed
+ to pexpect() as its pattern list, with the order of patterns preserved.
+
+ Note that you should put newlines in your string if Enter is necessary.
+
+ Like the example above, the responses may also contain a callback, either
+ a function or method. It should accept a dictionary value as an argument.
+ The dictionary contains all the locals from the run() function, so you can
+ access the child spawn object or any other variable defined in run()
+ (event_count, child, and extra_args are the most useful). A callback may
+ return True to stop the current run process. Otherwise run() continues
+ until the next event. A callback may also return a string which will be
+ sent to the child. 'extra_args' is not used by directly run(). It provides
+ a way to pass data to a callback function through run() through the locals
+ dictionary passed to a callback.
+
+ Like :class:`spawn`, passing *encoding* will make it work with unicode
+ instead of bytes. You can pass *codec_errors* to control how errors in
+ encoding and decoding are handled.
+ '''
+ if timeout == -1:
+ child = spawn(command, maxread=2000, logfile=logfile, cwd=cwd, env=env,
+ **kwargs)
+ else:
+ child = spawn(command, timeout=timeout, maxread=2000, logfile=logfile,
+ cwd=cwd, env=env, **kwargs)
+ if isinstance(events, list):
+ patterns= [x for x,y in events]
+ responses = [y for x,y in events]
+ elif isinstance(events, dict):
+ patterns = list(events.keys())
+ responses = list(events.values())
+ else:
+ # This assumes EOF or TIMEOUT will eventually cause run to terminate.
+ patterns = None
+ responses = None
+ child_result_list = []
+ event_count = 0
+ while True:
+ try:
+ index = child.expect(patterns)
+ if isinstance(child.after, child.allowed_string_types):
+ child_result_list.append(child.before + child.after)
+ else:
+ # child.after may have been a TIMEOUT or EOF,
+ # which we don't want appended to the list.
+ child_result_list.append(child.before)
+ if isinstance(responses[index], child.allowed_string_types):
+ child.send(responses[index])
+ elif (isinstance(responses[index], types.FunctionType) or
+ isinstance(responses[index], types.MethodType)):
+ callback_result = responses[index](locals())
+ sys.stdout.flush()
+ if isinstance(callback_result, child.allowed_string_types):
+ child.send(callback_result)
+ elif callback_result:
+ break
+ else:
+ raise TypeError("parameter `event' at index {index} must be "
+ "a string, method, or function: {value!r}"
+ .format(index=index, value=responses[index]))
+ event_count = event_count + 1
+ except TIMEOUT:
+ child_result_list.append(child.before)
+ break
+ except EOF:
+ child_result_list.append(child.before)
+ break
+ child_result = child.string_type().join(child_result_list)
+ if withexitstatus:
+ child.close()
+ return (child_result, child.exitstatus)
+ else:
+ return child_result
+
+def runu(command, timeout=30, withexitstatus=False, events=None,
+ extra_args=None, logfile=None, cwd=None, env=None, **kwargs):
+ """Deprecated: pass encoding to run() instead.
+ """
+ kwargs.setdefault('encoding', 'utf-8')
+ return run(command, timeout=timeout, withexitstatus=withexitstatus,
+ events=events, extra_args=extra_args, logfile=logfile, cwd=cwd,
+ env=env, **kwargs)
diff --git a/contrib/python/pexpect/pexpect/screen.py b/contrib/python/pexpect/pexpect/screen.py
index 79f95c4e542..21055841af3 100644
--- a/contrib/python/pexpect/pexpect/screen.py
+++ b/contrib/python/pexpect/pexpect/screen.py
@@ -1,431 +1,431 @@
-'''This implements a virtual screen. This is used to support ANSI terminal
-emulation. The screen representation and state is implemented in this class.
-Most of the methods are inspired by ANSI screen control codes. The
-:class:`~pexpect.ANSI.ANSI` class extends this class to add parsing of ANSI
-escape codes.
-
-PEXPECT LICENSE
-
- This license is approved by the OSI and FSF as GPL-compatible.
- http://opensource.org/licenses/isc-license.txt
-
- Copyright (c) 2012, Noah Spurrier <[email protected]>
- PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
- PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
- COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-'''
-
-import codecs
-import copy
-import sys
-
-import warnings
-
-warnings.warn(("pexpect.screen and pexpect.ANSI are deprecated. "
- "We recommend using pyte to emulate a terminal screen: "
- "https://pypi.python.org/pypi/pyte"),
- stacklevel=2)
-
-NUL = 0 # Fill character; ignored on input.
-ENQ = 5 # Transmit answerback message.
-BEL = 7 # Ring the bell.
-BS = 8 # Move cursor left.
-HT = 9 # Move cursor to next tab stop.
-LF = 10 # Line feed.
-VT = 11 # Same as LF.
-FF = 12 # Same as LF.
-CR = 13 # Move cursor to left margin or newline.
-SO = 14 # Invoke G1 character set.
-SI = 15 # Invoke G0 character set.
-XON = 17 # Resume transmission.
-XOFF = 19 # Halt transmission.
-CAN = 24 # Cancel escape sequence.
-SUB = 26 # Same as CAN.
-ESC = 27 # Introduce a control sequence.
-DEL = 127 # Fill character; ignored on input.
-SPACE = u' ' # Space or blank character.
-
-PY3 = (sys.version_info[0] >= 3)
-if PY3:
- unicode = str
-
-def constrain (n, min, max):
-
- '''This returns a number, n constrained to the min and max bounds. '''
-
- if n < min:
- return min
- if n > max:
- return max
- return n
-
-class screen:
- '''This object maintains the state of a virtual text screen as a
+'''This implements a virtual screen. This is used to support ANSI terminal
+emulation. The screen representation and state is implemented in this class.
+Most of the methods are inspired by ANSI screen control codes. The
+:class:`~pexpect.ANSI.ANSI` class extends this class to add parsing of ANSI
+escape codes.
+
+PEXPECT LICENSE
+
+ This license is approved by the OSI and FSF as GPL-compatible.
+ http://opensource.org/licenses/isc-license.txt
+
+ Copyright (c) 2012, Noah Spurrier <[email protected]>
+ PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
+ PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
+ COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+'''
+
+import codecs
+import copy
+import sys
+
+import warnings
+
+warnings.warn(("pexpect.screen and pexpect.ANSI are deprecated. "
+ "We recommend using pyte to emulate a terminal screen: "
+ "https://pypi.python.org/pypi/pyte"),
+ stacklevel=2)
+
+NUL = 0 # Fill character; ignored on input.
+ENQ = 5 # Transmit answerback message.
+BEL = 7 # Ring the bell.
+BS = 8 # Move cursor left.
+HT = 9 # Move cursor to next tab stop.
+LF = 10 # Line feed.
+VT = 11 # Same as LF.
+FF = 12 # Same as LF.
+CR = 13 # Move cursor to left margin or newline.
+SO = 14 # Invoke G1 character set.
+SI = 15 # Invoke G0 character set.
+XON = 17 # Resume transmission.
+XOFF = 19 # Halt transmission.
+CAN = 24 # Cancel escape sequence.
+SUB = 26 # Same as CAN.
+ESC = 27 # Introduce a control sequence.
+DEL = 127 # Fill character; ignored on input.
+SPACE = u' ' # Space or blank character.
+
+PY3 = (sys.version_info[0] >= 3)
+if PY3:
+ unicode = str
+
+def constrain (n, min, max):
+
+ '''This returns a number, n constrained to the min and max bounds. '''
+
+ if n < min:
+ return min
+ if n > max:
+ return max
+ return n
+
+class screen:
+ '''This object maintains the state of a virtual text screen as a
rectangular array. This maintains a virtual cursor position and handles
- scrolling as characters are added. This supports most of the methods needed
- by an ANSI text screen. Row and column indexes are 1-based (not zero-based,
- like arrays).
-
- Characters are represented internally using unicode. Methods that accept
- input characters, when passed 'bytes' (which in Python 2 is equivalent to
- 'str'), convert them from the encoding specified in the 'encoding'
- parameter to the constructor. Methods that return screen contents return
- unicode strings, with the exception of __str__() under Python 2. Passing
- ``encoding=None`` limits the API to only accept unicode input, so passing
- bytes in will raise :exc:`TypeError`.
- '''
- def __init__(self, r=24, c=80, encoding='latin-1', encoding_errors='replace'):
- '''This initializes a blank screen of the given dimensions.'''
-
- self.rows = r
- self.cols = c
- self.encoding = encoding
- self.encoding_errors = encoding_errors
- if encoding is not None:
+ scrolling as characters are added. This supports most of the methods needed
+ by an ANSI text screen. Row and column indexes are 1-based (not zero-based,
+ like arrays).
+
+ Characters are represented internally using unicode. Methods that accept
+ input characters, when passed 'bytes' (which in Python 2 is equivalent to
+ 'str'), convert them from the encoding specified in the 'encoding'
+ parameter to the constructor. Methods that return screen contents return
+ unicode strings, with the exception of __str__() under Python 2. Passing
+ ``encoding=None`` limits the API to only accept unicode input, so passing
+ bytes in will raise :exc:`TypeError`.
+ '''
+ def __init__(self, r=24, c=80, encoding='latin-1', encoding_errors='replace'):
+ '''This initializes a blank screen of the given dimensions.'''
+
+ self.rows = r
+ self.cols = c
+ self.encoding = encoding
+ self.encoding_errors = encoding_errors
+ if encoding is not None:
self.decoder = codecs.getincrementaldecoder(encoding)(encoding_errors)
- else:
- self.decoder = None
- self.cur_r = 1
- self.cur_c = 1
- self.cur_saved_r = 1
- self.cur_saved_c = 1
- self.scroll_row_start = 1
- self.scroll_row_end = self.rows
- self.w = [ [SPACE] * self.cols for _ in range(self.rows)]
-
- def _decode(self, s):
- '''This converts from the external coding system (as passed to
- the constructor) to the internal one (unicode). '''
- if self.decoder is not None:
- return self.decoder.decode(s)
- else:
- raise TypeError("This screen was constructed with encoding=None, "
- "so it does not handle bytes.")
-
- def _unicode(self):
- '''This returns a printable representation of the screen as a unicode
- string (which, under Python 3.x, is the same as 'str'). The end of each
- screen line is terminated by a newline.'''
-
- return u'\n'.join ([ u''.join(c) for c in self.w ])
-
- if PY3:
- __str__ = _unicode
- else:
- __unicode__ = _unicode
-
- def __str__(self):
- '''This returns a printable representation of the screen. The end of
- each screen line is terminated by a newline. '''
- encoding = self.encoding or 'ascii'
- return self._unicode().encode(encoding, 'replace')
-
- def dump (self):
- '''This returns a copy of the screen as a unicode string. This is similar to
- __str__/__unicode__ except that lines are not terminated with line
- feeds.'''
-
- return u''.join ([ u''.join(c) for c in self.w ])
-
- def pretty (self):
- '''This returns a copy of the screen as a unicode string with an ASCII
- text box around the screen border. This is similar to
- __str__/__unicode__ except that it adds a box.'''
-
- top_bot = u'+' + u'-'*self.cols + u'+\n'
- return top_bot + u'\n'.join([u'|'+line+u'|' for line in unicode(self).split(u'\n')]) + u'\n' + top_bot
-
- def fill (self, ch=SPACE):
-
- if isinstance(ch, bytes):
- ch = self._decode(ch)
-
- self.fill_region (1,1,self.rows,self.cols, ch)
-
- def fill_region (self, rs,cs, re,ce, ch=SPACE):
-
- if isinstance(ch, bytes):
- ch = self._decode(ch)
-
- rs = constrain (rs, 1, self.rows)
- re = constrain (re, 1, self.rows)
- cs = constrain (cs, 1, self.cols)
- ce = constrain (ce, 1, self.cols)
- if rs > re:
- rs, re = re, rs
- if cs > ce:
- cs, ce = ce, cs
- for r in range (rs, re+1):
- for c in range (cs, ce + 1):
- self.put_abs (r,c,ch)
-
- def cr (self):
- '''This moves the cursor to the beginning (col 1) of the current row.
- '''
-
- self.cursor_home (self.cur_r, 1)
-
- def lf (self):
- '''This moves the cursor down with scrolling.
- '''
-
- old_r = self.cur_r
- self.cursor_down()
- if old_r == self.cur_r:
- self.scroll_up ()
- self.erase_line()
-
- def crlf (self):
- '''This advances the cursor with CRLF properties.
- The cursor will line wrap and the screen may scroll.
- '''
-
- self.cr ()
- self.lf ()
-
- def newline (self):
- '''This is an alias for crlf().
- '''
-
- self.crlf()
-
- def put_abs (self, r, c, ch):
- '''Screen array starts at 1 index.'''
-
- r = constrain (r, 1, self.rows)
- c = constrain (c, 1, self.cols)
- if isinstance(ch, bytes):
- ch = self._decode(ch)[0]
- else:
- ch = ch[0]
- self.w[r-1][c-1] = ch
-
- def put (self, ch):
- '''This puts a characters at the current cursor position.
- '''
-
- if isinstance(ch, bytes):
- ch = self._decode(ch)
-
- self.put_abs (self.cur_r, self.cur_c, ch)
-
- def insert_abs (self, r, c, ch):
- '''This inserts a character at (r,c). Everything under
- and to the right is shifted right one character.
- The last character of the line is lost.
- '''
-
- if isinstance(ch, bytes):
- ch = self._decode(ch)
-
- r = constrain (r, 1, self.rows)
- c = constrain (c, 1, self.cols)
- for ci in range (self.cols, c, -1):
- self.put_abs (r,ci, self.get_abs(r,ci-1))
- self.put_abs (r,c,ch)
-
- def insert (self, ch):
-
- if isinstance(ch, bytes):
- ch = self._decode(ch)
-
- self.insert_abs (self.cur_r, self.cur_c, ch)
-
- def get_abs (self, r, c):
-
- r = constrain (r, 1, self.rows)
- c = constrain (c, 1, self.cols)
- return self.w[r-1][c-1]
-
- def get (self):
-
- self.get_abs (self.cur_r, self.cur_c)
-
- def get_region (self, rs,cs, re,ce):
- '''This returns a list of lines representing the region.
- '''
-
- rs = constrain (rs, 1, self.rows)
- re = constrain (re, 1, self.rows)
- cs = constrain (cs, 1, self.cols)
- ce = constrain (ce, 1, self.cols)
- if rs > re:
- rs, re = re, rs
- if cs > ce:
- cs, ce = ce, cs
- sc = []
- for r in range (rs, re+1):
- line = u''
- for c in range (cs, ce + 1):
- ch = self.get_abs (r,c)
- line = line + ch
- sc.append (line)
- return sc
-
- def cursor_constrain (self):
- '''This keeps the cursor within the screen area.
- '''
-
- self.cur_r = constrain (self.cur_r, 1, self.rows)
- self.cur_c = constrain (self.cur_c, 1, self.cols)
-
- def cursor_home (self, r=1, c=1): # <ESC>[{ROW};{COLUMN}H
-
- self.cur_r = r
- self.cur_c = c
- self.cursor_constrain ()
-
- def cursor_back (self,count=1): # <ESC>[{COUNT}D (not confused with down)
-
- self.cur_c = self.cur_c - count
- self.cursor_constrain ()
-
- def cursor_down (self,count=1): # <ESC>[{COUNT}B (not confused with back)
-
- self.cur_r = self.cur_r + count
- self.cursor_constrain ()
-
- def cursor_forward (self,count=1): # <ESC>[{COUNT}C
-
- self.cur_c = self.cur_c + count
- self.cursor_constrain ()
-
- def cursor_up (self,count=1): # <ESC>[{COUNT}A
-
- self.cur_r = self.cur_r - count
- self.cursor_constrain ()
-
- def cursor_up_reverse (self): # <ESC> M (called RI -- Reverse Index)
-
- old_r = self.cur_r
- self.cursor_up()
- if old_r == self.cur_r:
- self.scroll_up()
-
- def cursor_force_position (self, r, c): # <ESC>[{ROW};{COLUMN}f
- '''Identical to Cursor Home.'''
-
- self.cursor_home (r, c)
-
- def cursor_save (self): # <ESC>[s
- '''Save current cursor position.'''
-
- self.cursor_save_attrs()
-
- def cursor_unsave (self): # <ESC>[u
- '''Restores cursor position after a Save Cursor.'''
-
- self.cursor_restore_attrs()
-
- def cursor_save_attrs (self): # <ESC>7
- '''Save current cursor position.'''
-
- self.cur_saved_r = self.cur_r
- self.cur_saved_c = self.cur_c
-
- def cursor_restore_attrs (self): # <ESC>8
- '''Restores cursor position after a Save Cursor.'''
-
- self.cursor_home (self.cur_saved_r, self.cur_saved_c)
-
- def scroll_constrain (self):
- '''This keeps the scroll region within the screen region.'''
-
- if self.scroll_row_start <= 0:
- self.scroll_row_start = 1
- if self.scroll_row_end > self.rows:
- self.scroll_row_end = self.rows
-
- def scroll_screen (self): # <ESC>[r
- '''Enable scrolling for entire display.'''
-
- self.scroll_row_start = 1
- self.scroll_row_end = self.rows
-
- def scroll_screen_rows (self, rs, re): # <ESC>[{start};{end}r
- '''Enable scrolling from row {start} to row {end}.'''
-
- self.scroll_row_start = rs
- self.scroll_row_end = re
- self.scroll_constrain()
-
- def scroll_down (self): # <ESC>D
- '''Scroll display down one line.'''
-
- # Screen is indexed from 1, but arrays are indexed from 0.
- s = self.scroll_row_start - 1
- e = self.scroll_row_end - 1
- self.w[s+1:e+1] = copy.deepcopy(self.w[s:e])
-
- def scroll_up (self): # <ESC>M
- '''Scroll display up one line.'''
-
- # Screen is indexed from 1, but arrays are indexed from 0.
- s = self.scroll_row_start - 1
- e = self.scroll_row_end - 1
- self.w[s:e] = copy.deepcopy(self.w[s+1:e+1])
-
- def erase_end_of_line (self): # <ESC>[0K -or- <ESC>[K
- '''Erases from the current cursor position to the end of the current
- line.'''
-
- self.fill_region (self.cur_r, self.cur_c, self.cur_r, self.cols)
-
- def erase_start_of_line (self): # <ESC>[1K
- '''Erases from the current cursor position to the start of the current
- line.'''
-
- self.fill_region (self.cur_r, 1, self.cur_r, self.cur_c)
-
- def erase_line (self): # <ESC>[2K
- '''Erases the entire current line.'''
-
- self.fill_region (self.cur_r, 1, self.cur_r, self.cols)
-
- def erase_down (self): # <ESC>[0J -or- <ESC>[J
- '''Erases the screen from the current line down to the bottom of the
- screen.'''
-
- self.erase_end_of_line ()
- self.fill_region (self.cur_r + 1, 1, self.rows, self.cols)
-
- def erase_up (self): # <ESC>[1J
- '''Erases the screen from the current line up to the top of the
- screen.'''
-
- self.erase_start_of_line ()
- self.fill_region (self.cur_r-1, 1, 1, self.cols)
-
- def erase_screen (self): # <ESC>[2J
- '''Erases the screen with the background color.'''
-
- self.fill ()
-
- def set_tab (self): # <ESC>H
- '''Sets a tab at the current position.'''
-
- pass
-
- def clear_tab (self): # <ESC>[g
- '''Clears tab at the current position.'''
-
- pass
-
- def clear_all_tabs (self): # <ESC>[3g
- '''Clears all tabs.'''
-
- pass
-
-# Insert line Esc [ Pn L
-# Delete line Esc [ Pn M
-# Delete character Esc [ Pn P
-# Scrolling region Esc [ Pn(top);Pn(bot) r
-
+ else:
+ self.decoder = None
+ self.cur_r = 1
+ self.cur_c = 1
+ self.cur_saved_r = 1
+ self.cur_saved_c = 1
+ self.scroll_row_start = 1
+ self.scroll_row_end = self.rows
+ self.w = [ [SPACE] * self.cols for _ in range(self.rows)]
+
+ def _decode(self, s):
+ '''This converts from the external coding system (as passed to
+ the constructor) to the internal one (unicode). '''
+ if self.decoder is not None:
+ return self.decoder.decode(s)
+ else:
+ raise TypeError("This screen was constructed with encoding=None, "
+ "so it does not handle bytes.")
+
+ def _unicode(self):
+ '''This returns a printable representation of the screen as a unicode
+ string (which, under Python 3.x, is the same as 'str'). The end of each
+ screen line is terminated by a newline.'''
+
+ return u'\n'.join ([ u''.join(c) for c in self.w ])
+
+ if PY3:
+ __str__ = _unicode
+ else:
+ __unicode__ = _unicode
+
+ def __str__(self):
+ '''This returns a printable representation of the screen. The end of
+ each screen line is terminated by a newline. '''
+ encoding = self.encoding or 'ascii'
+ return self._unicode().encode(encoding, 'replace')
+
+ def dump (self):
+ '''This returns a copy of the screen as a unicode string. This is similar to
+ __str__/__unicode__ except that lines are not terminated with line
+ feeds.'''
+
+ return u''.join ([ u''.join(c) for c in self.w ])
+
+ def pretty (self):
+ '''This returns a copy of the screen as a unicode string with an ASCII
+ text box around the screen border. This is similar to
+ __str__/__unicode__ except that it adds a box.'''
+
+ top_bot = u'+' + u'-'*self.cols + u'+\n'
+ return top_bot + u'\n'.join([u'|'+line+u'|' for line in unicode(self).split(u'\n')]) + u'\n' + top_bot
+
+ def fill (self, ch=SPACE):
+
+ if isinstance(ch, bytes):
+ ch = self._decode(ch)
+
+ self.fill_region (1,1,self.rows,self.cols, ch)
+
+ def fill_region (self, rs,cs, re,ce, ch=SPACE):
+
+ if isinstance(ch, bytes):
+ ch = self._decode(ch)
+
+ rs = constrain (rs, 1, self.rows)
+ re = constrain (re, 1, self.rows)
+ cs = constrain (cs, 1, self.cols)
+ ce = constrain (ce, 1, self.cols)
+ if rs > re:
+ rs, re = re, rs
+ if cs > ce:
+ cs, ce = ce, cs
+ for r in range (rs, re+1):
+ for c in range (cs, ce + 1):
+ self.put_abs (r,c,ch)
+
+ def cr (self):
+ '''This moves the cursor to the beginning (col 1) of the current row.
+ '''
+
+ self.cursor_home (self.cur_r, 1)
+
+ def lf (self):
+ '''This moves the cursor down with scrolling.
+ '''
+
+ old_r = self.cur_r
+ self.cursor_down()
+ if old_r == self.cur_r:
+ self.scroll_up ()
+ self.erase_line()
+
+ def crlf (self):
+ '''This advances the cursor with CRLF properties.
+ The cursor will line wrap and the screen may scroll.
+ '''
+
+ self.cr ()
+ self.lf ()
+
+ def newline (self):
+ '''This is an alias for crlf().
+ '''
+
+ self.crlf()
+
+ def put_abs (self, r, c, ch):
+ '''Screen array starts at 1 index.'''
+
+ r = constrain (r, 1, self.rows)
+ c = constrain (c, 1, self.cols)
+ if isinstance(ch, bytes):
+ ch = self._decode(ch)[0]
+ else:
+ ch = ch[0]
+ self.w[r-1][c-1] = ch
+
+ def put (self, ch):
+ '''This puts a characters at the current cursor position.
+ '''
+
+ if isinstance(ch, bytes):
+ ch = self._decode(ch)
+
+ self.put_abs (self.cur_r, self.cur_c, ch)
+
+ def insert_abs (self, r, c, ch):
+ '''This inserts a character at (r,c). Everything under
+ and to the right is shifted right one character.
+ The last character of the line is lost.
+ '''
+
+ if isinstance(ch, bytes):
+ ch = self._decode(ch)
+
+ r = constrain (r, 1, self.rows)
+ c = constrain (c, 1, self.cols)
+ for ci in range (self.cols, c, -1):
+ self.put_abs (r,ci, self.get_abs(r,ci-1))
+ self.put_abs (r,c,ch)
+
+ def insert (self, ch):
+
+ if isinstance(ch, bytes):
+ ch = self._decode(ch)
+
+ self.insert_abs (self.cur_r, self.cur_c, ch)
+
+ def get_abs (self, r, c):
+
+ r = constrain (r, 1, self.rows)
+ c = constrain (c, 1, self.cols)
+ return self.w[r-1][c-1]
+
+ def get (self):
+
+ self.get_abs (self.cur_r, self.cur_c)
+
+ def get_region (self, rs,cs, re,ce):
+ '''This returns a list of lines representing the region.
+ '''
+
+ rs = constrain (rs, 1, self.rows)
+ re = constrain (re, 1, self.rows)
+ cs = constrain (cs, 1, self.cols)
+ ce = constrain (ce, 1, self.cols)
+ if rs > re:
+ rs, re = re, rs
+ if cs > ce:
+ cs, ce = ce, cs
+ sc = []
+ for r in range (rs, re+1):
+ line = u''
+ for c in range (cs, ce + 1):
+ ch = self.get_abs (r,c)
+ line = line + ch
+ sc.append (line)
+ return sc
+
+ def cursor_constrain (self):
+ '''This keeps the cursor within the screen area.
+ '''
+
+ self.cur_r = constrain (self.cur_r, 1, self.rows)
+ self.cur_c = constrain (self.cur_c, 1, self.cols)
+
+ def cursor_home (self, r=1, c=1): # <ESC>[{ROW};{COLUMN}H
+
+ self.cur_r = r
+ self.cur_c = c
+ self.cursor_constrain ()
+
+ def cursor_back (self,count=1): # <ESC>[{COUNT}D (not confused with down)
+
+ self.cur_c = self.cur_c - count
+ self.cursor_constrain ()
+
+ def cursor_down (self,count=1): # <ESC>[{COUNT}B (not confused with back)
+
+ self.cur_r = self.cur_r + count
+ self.cursor_constrain ()
+
+ def cursor_forward (self,count=1): # <ESC>[{COUNT}C
+
+ self.cur_c = self.cur_c + count
+ self.cursor_constrain ()
+
+ def cursor_up (self,count=1): # <ESC>[{COUNT}A
+
+ self.cur_r = self.cur_r - count
+ self.cursor_constrain ()
+
+ def cursor_up_reverse (self): # <ESC> M (called RI -- Reverse Index)
+
+ old_r = self.cur_r
+ self.cursor_up()
+ if old_r == self.cur_r:
+ self.scroll_up()
+
+ def cursor_force_position (self, r, c): # <ESC>[{ROW};{COLUMN}f
+ '''Identical to Cursor Home.'''
+
+ self.cursor_home (r, c)
+
+ def cursor_save (self): # <ESC>[s
+ '''Save current cursor position.'''
+
+ self.cursor_save_attrs()
+
+ def cursor_unsave (self): # <ESC>[u
+ '''Restores cursor position after a Save Cursor.'''
+
+ self.cursor_restore_attrs()
+
+ def cursor_save_attrs (self): # <ESC>7
+ '''Save current cursor position.'''
+
+ self.cur_saved_r = self.cur_r
+ self.cur_saved_c = self.cur_c
+
+ def cursor_restore_attrs (self): # <ESC>8
+ '''Restores cursor position after a Save Cursor.'''
+
+ self.cursor_home (self.cur_saved_r, self.cur_saved_c)
+
+ def scroll_constrain (self):
+ '''This keeps the scroll region within the screen region.'''
+
+ if self.scroll_row_start <= 0:
+ self.scroll_row_start = 1
+ if self.scroll_row_end > self.rows:
+ self.scroll_row_end = self.rows
+
+ def scroll_screen (self): # <ESC>[r
+ '''Enable scrolling for entire display.'''
+
+ self.scroll_row_start = 1
+ self.scroll_row_end = self.rows
+
+ def scroll_screen_rows (self, rs, re): # <ESC>[{start};{end}r
+ '''Enable scrolling from row {start} to row {end}.'''
+
+ self.scroll_row_start = rs
+ self.scroll_row_end = re
+ self.scroll_constrain()
+
+ def scroll_down (self): # <ESC>D
+ '''Scroll display down one line.'''
+
+ # Screen is indexed from 1, but arrays are indexed from 0.
+ s = self.scroll_row_start - 1
+ e = self.scroll_row_end - 1
+ self.w[s+1:e+1] = copy.deepcopy(self.w[s:e])
+
+ def scroll_up (self): # <ESC>M
+ '''Scroll display up one line.'''
+
+ # Screen is indexed from 1, but arrays are indexed from 0.
+ s = self.scroll_row_start - 1
+ e = self.scroll_row_end - 1
+ self.w[s:e] = copy.deepcopy(self.w[s+1:e+1])
+
+ def erase_end_of_line (self): # <ESC>[0K -or- <ESC>[K
+ '''Erases from the current cursor position to the end of the current
+ line.'''
+
+ self.fill_region (self.cur_r, self.cur_c, self.cur_r, self.cols)
+
+ def erase_start_of_line (self): # <ESC>[1K
+ '''Erases from the current cursor position to the start of the current
+ line.'''
+
+ self.fill_region (self.cur_r, 1, self.cur_r, self.cur_c)
+
+ def erase_line (self): # <ESC>[2K
+ '''Erases the entire current line.'''
+
+ self.fill_region (self.cur_r, 1, self.cur_r, self.cols)
+
+ def erase_down (self): # <ESC>[0J -or- <ESC>[J
+ '''Erases the screen from the current line down to the bottom of the
+ screen.'''
+
+ self.erase_end_of_line ()
+ self.fill_region (self.cur_r + 1, 1, self.rows, self.cols)
+
+ def erase_up (self): # <ESC>[1J
+ '''Erases the screen from the current line up to the top of the
+ screen.'''
+
+ self.erase_start_of_line ()
+ self.fill_region (self.cur_r-1, 1, 1, self.cols)
+
+ def erase_screen (self): # <ESC>[2J
+ '''Erases the screen with the background color.'''
+
+ self.fill ()
+
+ def set_tab (self): # <ESC>H
+ '''Sets a tab at the current position.'''
+
+ pass
+
+ def clear_tab (self): # <ESC>[g
+ '''Clears tab at the current position.'''
+
+ pass
+
+ def clear_all_tabs (self): # <ESC>[3g
+ '''Clears all tabs.'''
+
+ pass
+
+# Insert line Esc [ Pn L
+# Delete line Esc [ Pn M
+# Delete character Esc [ Pn P
+# Scrolling region Esc [ Pn(top);Pn(bot) r
+
diff --git a/contrib/python/pexpect/pexpect/spawnbase.py b/contrib/python/pexpect/pexpect/spawnbase.py
index 59e905764cd..b33eadd069a 100644
--- a/contrib/python/pexpect/pexpect/spawnbase.py
+++ b/contrib/python/pexpect/pexpect/spawnbase.py
@@ -1,121 +1,121 @@
from io import StringIO, BytesIO
-import codecs
-import os
-import sys
-import re
-import errno
-from .exceptions import ExceptionPexpect, EOF, TIMEOUT
-from .expect import Expecter, searcher_string, searcher_re
-
-PY3 = (sys.version_info[0] >= 3)
-text_type = str if PY3 else unicode
-
-class _NullCoder(object):
- """Pass bytes through unchanged."""
- @staticmethod
- def encode(b, final=False):
- return b
-
- @staticmethod
- def decode(b, final=False):
- return b
-
-class SpawnBase(object):
- """A base class providing the backwards-compatible spawn API for Pexpect.
-
- This should not be instantiated directly: use :class:`pexpect.spawn` or
- :class:`pexpect.fdpexpect.fdspawn`.
- """
- encoding = None
- pid = None
- flag_eof = False
-
- def __init__(self, timeout=30, maxread=2000, searchwindowsize=None,
- logfile=None, encoding=None, codec_errors='strict'):
- self.stdin = sys.stdin
- self.stdout = sys.stdout
- self.stderr = sys.stderr
-
- self.searcher = None
- self.ignorecase = False
- self.before = None
- self.after = None
- self.match = None
- self.match_index = None
- self.terminated = True
- self.exitstatus = None
- self.signalstatus = None
- # status returned by os.waitpid
- self.status = None
- # the child file descriptor is initially closed
- self.child_fd = -1
- self.timeout = timeout
- self.delimiter = EOF
- self.logfile = logfile
- # input from child (read_nonblocking)
- self.logfile_read = None
- # output to send (send, sendline)
- self.logfile_send = None
- # max bytes to read at one time into buffer
- self.maxread = maxread
- # Data before searchwindowsize point is preserved, but not searched.
- self.searchwindowsize = searchwindowsize
- # Delay used before sending data to child. Time in seconds.
+import codecs
+import os
+import sys
+import re
+import errno
+from .exceptions import ExceptionPexpect, EOF, TIMEOUT
+from .expect import Expecter, searcher_string, searcher_re
+
+PY3 = (sys.version_info[0] >= 3)
+text_type = str if PY3 else unicode
+
+class _NullCoder(object):
+ """Pass bytes through unchanged."""
+ @staticmethod
+ def encode(b, final=False):
+ return b
+
+ @staticmethod
+ def decode(b, final=False):
+ return b
+
+class SpawnBase(object):
+ """A base class providing the backwards-compatible spawn API for Pexpect.
+
+ This should not be instantiated directly: use :class:`pexpect.spawn` or
+ :class:`pexpect.fdpexpect.fdspawn`.
+ """
+ encoding = None
+ pid = None
+ flag_eof = False
+
+ def __init__(self, timeout=30, maxread=2000, searchwindowsize=None,
+ logfile=None, encoding=None, codec_errors='strict'):
+ self.stdin = sys.stdin
+ self.stdout = sys.stdout
+ self.stderr = sys.stderr
+
+ self.searcher = None
+ self.ignorecase = False
+ self.before = None
+ self.after = None
+ self.match = None
+ self.match_index = None
+ self.terminated = True
+ self.exitstatus = None
+ self.signalstatus = None
+ # status returned by os.waitpid
+ self.status = None
+ # the child file descriptor is initially closed
+ self.child_fd = -1
+ self.timeout = timeout
+ self.delimiter = EOF
+ self.logfile = logfile
+ # input from child (read_nonblocking)
+ self.logfile_read = None
+ # output to send (send, sendline)
+ self.logfile_send = None
+ # max bytes to read at one time into buffer
+ self.maxread = maxread
+ # Data before searchwindowsize point is preserved, but not searched.
+ self.searchwindowsize = searchwindowsize
+ # Delay used before sending data to child. Time in seconds.
# Set this to None to skip the time.sleep() call completely.
- self.delaybeforesend = 0.05
- # Used by close() to give kernel time to update process status.
- # Time in seconds.
- self.delayafterclose = 0.1
- # Used by terminate() to give kernel time to update process status.
- # Time in seconds.
- self.delayafterterminate = 0.1
+ self.delaybeforesend = 0.05
+ # Used by close() to give kernel time to update process status.
+ # Time in seconds.
+ self.delayafterclose = 0.1
+ # Used by terminate() to give kernel time to update process status.
+ # Time in seconds.
+ self.delayafterterminate = 0.1
# Delay in seconds to sleep after each call to read_nonblocking().
# Set this to None to skip the time.sleep() call completely: that
# would restore the behavior from pexpect-2.0 (for performance
# reasons or because you don't want to release Python's global
# interpreter lock).
self.delayafterread = 0.0001
- self.softspace = False
- self.name = '<' + repr(self) + '>'
- self.closed = True
-
- # Unicode interface
- self.encoding = encoding
- self.codec_errors = codec_errors
- if encoding is None:
- # bytes mode (accepts some unicode for backwards compatibility)
- self._encoder = self._decoder = _NullCoder()
- self.string_type = bytes
+ self.softspace = False
+ self.name = '<' + repr(self) + '>'
+ self.closed = True
+
+ # Unicode interface
+ self.encoding = encoding
+ self.codec_errors = codec_errors
+ if encoding is None:
+ # bytes mode (accepts some unicode for backwards compatibility)
+ self._encoder = self._decoder = _NullCoder()
+ self.string_type = bytes
self.buffer_type = BytesIO
- self.crlf = b'\r\n'
- if PY3:
- self.allowed_string_types = (bytes, str)
- self.linesep = os.linesep.encode('ascii')
- def write_to_stdout(b):
- try:
- return sys.stdout.buffer.write(b)
- except AttributeError:
- # If stdout has been replaced, it may not have .buffer
- return sys.stdout.write(b.decode('ascii', 'replace'))
- self.write_to_stdout = write_to_stdout
- else:
- self.allowed_string_types = (basestring,) # analysis:ignore
- self.linesep = os.linesep
- self.write_to_stdout = sys.stdout.write
- else:
- # unicode mode
- self._encoder = codecs.getincrementalencoder(encoding)(codec_errors)
- self._decoder = codecs.getincrementaldecoder(encoding)(codec_errors)
- self.string_type = text_type
+ self.crlf = b'\r\n'
+ if PY3:
+ self.allowed_string_types = (bytes, str)
+ self.linesep = os.linesep.encode('ascii')
+ def write_to_stdout(b):
+ try:
+ return sys.stdout.buffer.write(b)
+ except AttributeError:
+ # If stdout has been replaced, it may not have .buffer
+ return sys.stdout.write(b.decode('ascii', 'replace'))
+ self.write_to_stdout = write_to_stdout
+ else:
+ self.allowed_string_types = (basestring,) # analysis:ignore
+ self.linesep = os.linesep
+ self.write_to_stdout = sys.stdout.write
+ else:
+ # unicode mode
+ self._encoder = codecs.getincrementalencoder(encoding)(codec_errors)
+ self._decoder = codecs.getincrementaldecoder(encoding)(codec_errors)
+ self.string_type = text_type
self.buffer_type = StringIO
- self.crlf = u'\r\n'
- self.allowed_string_types = (text_type, )
- if PY3:
- self.linesep = os.linesep
- else:
- self.linesep = os.linesep.decode('ascii')
- # This can handle unicode in both Python 2 and 3
- self.write_to_stdout = sys.stdout.write
+ self.crlf = u'\r\n'
+ self.allowed_string_types = (text_type, )
+ if PY3:
+ self.linesep = os.linesep
+ else:
+ self.linesep = os.linesep.decode('ascii')
+ # This can handle unicode in both Python 2 and 3
+ self.write_to_stdout = sys.stdout.write
# storage for async transport
self.async_pw_transport = None
# This is the read buffer. See maxread.
@@ -123,29 +123,29 @@ class SpawnBase(object):
# The buffer may be trimmed for efficiency reasons. This is the
# untrimmed buffer, used to create the before attribute.
self._before = self.buffer_type()
-
- def _log(self, s, direction):
- if self.logfile is not None:
- self.logfile.write(s)
- self.logfile.flush()
- second_log = self.logfile_send if (direction=='send') else self.logfile_read
- if second_log is not None:
- second_log.write(s)
- second_log.flush()
-
- # For backwards compatibility, in bytes mode (when encoding is None)
- # unicode is accepted for send and expect. Unicode mode is strictly unicode
- # only.
- def _coerce_expect_string(self, s):
- if self.encoding is None and not isinstance(s, bytes):
- return s.encode('ascii')
- return s
-
- def _coerce_send_string(self, s):
- if self.encoding is None and not isinstance(s, bytes):
- return s.encode('utf-8')
- return s
-
+
+ def _log(self, s, direction):
+ if self.logfile is not None:
+ self.logfile.write(s)
+ self.logfile.flush()
+ second_log = self.logfile_send if (direction=='send') else self.logfile_read
+ if second_log is not None:
+ second_log.write(s)
+ second_log.flush()
+
+ # For backwards compatibility, in bytes mode (when encoding is None)
+ # unicode is accepted for send and expect. Unicode mode is strictly unicode
+ # only.
+ def _coerce_expect_string(self, s):
+ if self.encoding is None and not isinstance(s, bytes):
+ return s.encode('ascii')
+ return s
+
+ def _coerce_send_string(self, s):
+ if self.encoding is None and not isinstance(s, bytes):
+ return s.encode('utf-8')
+ return s
+
def _get_buffer(self):
return self._buffer.getvalue()
@@ -157,369 +157,369 @@ class SpawnBase(object):
# to be a string/bytes object)
buffer = property(_get_buffer, _set_buffer)
- def read_nonblocking(self, size=1, timeout=None):
- """This reads data from the file descriptor.
-
- This is a simple implementation suitable for a regular file. Subclasses using ptys or pipes should override it.
-
- The timeout parameter is ignored.
- """
-
- try:
- s = os.read(self.child_fd, size)
- except OSError as err:
- if err.args[0] == errno.EIO:
- # Linux-style EOF
- self.flag_eof = True
- raise EOF('End Of File (EOF). Exception style platform.')
- raise
- if s == b'':
- # BSD-style EOF
- self.flag_eof = True
- raise EOF('End Of File (EOF). Empty string style platform.')
-
- s = self._decoder.decode(s, final=False)
- self._log(s, 'read')
- return s
-
- def _pattern_type_err(self, pattern):
- raise TypeError('got {badtype} ({badobj!r}) as pattern, must be one'
- ' of: {goodtypes}, pexpect.EOF, pexpect.TIMEOUT'\
- .format(badtype=type(pattern),
- badobj=pattern,
- goodtypes=', '.join([str(ast)\
- for ast in self.allowed_string_types])
- )
- )
-
- def compile_pattern_list(self, patterns):
- '''This compiles a pattern-string or a list of pattern-strings.
- Patterns must be a StringType, EOF, TIMEOUT, SRE_Pattern, or a list of
- those. Patterns may also be None which results in an empty list (you
- might do this if waiting for an EOF or TIMEOUT condition without
- expecting any pattern).
-
- This is used by expect() when calling expect_list(). Thus expect() is
- nothing more than::
-
- cpl = self.compile_pattern_list(pl)
- return self.expect_list(cpl, timeout)
-
- If you are using expect() within a loop it may be more
- efficient to compile the patterns first and then call expect_list().
- This avoid calls in a loop to compile_pattern_list()::
-
- cpl = self.compile_pattern_list(my_pattern)
- while some_condition:
- ...
- i = self.expect_list(cpl, timeout)
- ...
- '''
-
- if patterns is None:
- return []
- if not isinstance(patterns, list):
- patterns = [patterns]
-
- # Allow dot to match \n
- compile_flags = re.DOTALL
- if self.ignorecase:
- compile_flags = compile_flags | re.IGNORECASE
- compiled_pattern_list = []
- for idx, p in enumerate(patterns):
- if isinstance(p, self.allowed_string_types):
- p = self._coerce_expect_string(p)
- compiled_pattern_list.append(re.compile(p, compile_flags))
- elif p is EOF:
- compiled_pattern_list.append(EOF)
- elif p is TIMEOUT:
- compiled_pattern_list.append(TIMEOUT)
- elif isinstance(p, type(re.compile(''))):
- compiled_pattern_list.append(p)
- else:
- self._pattern_type_err(p)
- return compiled_pattern_list
-
+ def read_nonblocking(self, size=1, timeout=None):
+ """This reads data from the file descriptor.
+
+ This is a simple implementation suitable for a regular file. Subclasses using ptys or pipes should override it.
+
+ The timeout parameter is ignored.
+ """
+
+ try:
+ s = os.read(self.child_fd, size)
+ except OSError as err:
+ if err.args[0] == errno.EIO:
+ # Linux-style EOF
+ self.flag_eof = True
+ raise EOF('End Of File (EOF). Exception style platform.')
+ raise
+ if s == b'':
+ # BSD-style EOF
+ self.flag_eof = True
+ raise EOF('End Of File (EOF). Empty string style platform.')
+
+ s = self._decoder.decode(s, final=False)
+ self._log(s, 'read')
+ return s
+
+ def _pattern_type_err(self, pattern):
+ raise TypeError('got {badtype} ({badobj!r}) as pattern, must be one'
+ ' of: {goodtypes}, pexpect.EOF, pexpect.TIMEOUT'\
+ .format(badtype=type(pattern),
+ badobj=pattern,
+ goodtypes=', '.join([str(ast)\
+ for ast in self.allowed_string_types])
+ )
+ )
+
+ def compile_pattern_list(self, patterns):
+ '''This compiles a pattern-string or a list of pattern-strings.
+ Patterns must be a StringType, EOF, TIMEOUT, SRE_Pattern, or a list of
+ those. Patterns may also be None which results in an empty list (you
+ might do this if waiting for an EOF or TIMEOUT condition without
+ expecting any pattern).
+
+ This is used by expect() when calling expect_list(). Thus expect() is
+ nothing more than::
+
+ cpl = self.compile_pattern_list(pl)
+ return self.expect_list(cpl, timeout)
+
+ If you are using expect() within a loop it may be more
+ efficient to compile the patterns first and then call expect_list().
+ This avoid calls in a loop to compile_pattern_list()::
+
+ cpl = self.compile_pattern_list(my_pattern)
+ while some_condition:
+ ...
+ i = self.expect_list(cpl, timeout)
+ ...
+ '''
+
+ if patterns is None:
+ return []
+ if not isinstance(patterns, list):
+ patterns = [patterns]
+
+ # Allow dot to match \n
+ compile_flags = re.DOTALL
+ if self.ignorecase:
+ compile_flags = compile_flags | re.IGNORECASE
+ compiled_pattern_list = []
+ for idx, p in enumerate(patterns):
+ if isinstance(p, self.allowed_string_types):
+ p = self._coerce_expect_string(p)
+ compiled_pattern_list.append(re.compile(p, compile_flags))
+ elif p is EOF:
+ compiled_pattern_list.append(EOF)
+ elif p is TIMEOUT:
+ compiled_pattern_list.append(TIMEOUT)
+ elif isinstance(p, type(re.compile(''))):
+ compiled_pattern_list.append(p)
+ else:
+ self._pattern_type_err(p)
+ return compiled_pattern_list
+
def expect(self, pattern, timeout=-1, searchwindowsize=-1, async_=False, **kw):
- '''This seeks through the stream until a pattern is matched. The
- pattern is overloaded and may take several types. The pattern can be a
- StringType, EOF, a compiled re, or a list of any of those types.
- Strings will be compiled to re types. This returns the index into the
- pattern list. If the pattern was not a list this returns index 0 on a
- successful match. This may raise exceptions for EOF or TIMEOUT. To
- avoid the EOF or TIMEOUT exceptions add EOF or TIMEOUT to the pattern
- list. That will cause expect to match an EOF or TIMEOUT condition
- instead of raising an exception.
-
- If you pass a list of patterns and more than one matches, the first
- match in the stream is chosen. If more than one pattern matches at that
- point, the leftmost in the pattern list is chosen. For example::
-
- # the input is 'foobar'
- index = p.expect(['bar', 'foo', 'foobar'])
- # returns 1('foo') even though 'foobar' is a "better" match
-
- Please note, however, that buffering can affect this behavior, since
- input arrives in unpredictable chunks. For example::
-
- # the input is 'foobar'
- index = p.expect(['foobar', 'foo'])
- # returns 0('foobar') if all input is available at once,
+ '''This seeks through the stream until a pattern is matched. The
+ pattern is overloaded and may take several types. The pattern can be a
+ StringType, EOF, a compiled re, or a list of any of those types.
+ Strings will be compiled to re types. This returns the index into the
+ pattern list. If the pattern was not a list this returns index 0 on a
+ successful match. This may raise exceptions for EOF or TIMEOUT. To
+ avoid the EOF or TIMEOUT exceptions add EOF or TIMEOUT to the pattern
+ list. That will cause expect to match an EOF or TIMEOUT condition
+ instead of raising an exception.
+
+ If you pass a list of patterns and more than one matches, the first
+ match in the stream is chosen. If more than one pattern matches at that
+ point, the leftmost in the pattern list is chosen. For example::
+
+ # the input is 'foobar'
+ index = p.expect(['bar', 'foo', 'foobar'])
+ # returns 1('foo') even though 'foobar' is a "better" match
+
+ Please note, however, that buffering can affect this behavior, since
+ input arrives in unpredictable chunks. For example::
+
+ # the input is 'foobar'
+ index = p.expect(['foobar', 'foo'])
+ # returns 0('foobar') if all input is available at once,
# but returns 1('foo') if parts of the final 'bar' arrive late
-
- When a match is found for the given pattern, the class instance
- attribute *match* becomes an re.MatchObject result. Should an EOF
- or TIMEOUT pattern match, then the match attribute will be an instance
- of that exception class. The pairing before and after class
- instance attributes are views of the data preceding and following
- the matching pattern. On general exception, class attribute
- *before* is all data received up to the exception, while *match* and
- *after* attributes are value None.
-
- When the keyword argument timeout is -1 (default), then TIMEOUT will
- raise after the default value specified by the class timeout
- attribute. When None, TIMEOUT will not be raised and may block
- indefinitely until match.
-
- When the keyword argument searchwindowsize is -1 (default), then the
- value specified by the class maxread attribute is used.
-
- A list entry may be EOF or TIMEOUT instead of a string. This will
- catch these exceptions and return the index of the list entry instead
- of raising the exception. The attribute 'after' will be set to the
- exception type. The attribute 'match' will be None. This allows you to
- write code like this::
-
- index = p.expect(['good', 'bad', pexpect.EOF, pexpect.TIMEOUT])
- if index == 0:
- do_something()
- elif index == 1:
- do_something_else()
- elif index == 2:
- do_some_other_thing()
- elif index == 3:
- do_something_completely_different()
-
- instead of code like this::
-
- try:
- index = p.expect(['good', 'bad'])
- if index == 0:
- do_something()
- elif index == 1:
- do_something_else()
- except EOF:
- do_some_other_thing()
- except TIMEOUT:
- do_something_completely_different()
-
- These two forms are equivalent. It all depends on what you want. You
- can also just expect the EOF if you are waiting for all output of a
- child to finish. For example::
-
- p = pexpect.spawn('/bin/ls')
- p.expect(pexpect.EOF)
- print p.before
-
- If you are trying to optimize for speed then see expect_list().
-
- On Python 3.4, or Python 3.3 with asyncio installed, passing
+
+ When a match is found for the given pattern, the class instance
+ attribute *match* becomes an re.MatchObject result. Should an EOF
+ or TIMEOUT pattern match, then the match attribute will be an instance
+ of that exception class. The pairing before and after class
+ instance attributes are views of the data preceding and following
+ the matching pattern. On general exception, class attribute
+ *before* is all data received up to the exception, while *match* and
+ *after* attributes are value None.
+
+ When the keyword argument timeout is -1 (default), then TIMEOUT will
+ raise after the default value specified by the class timeout
+ attribute. When None, TIMEOUT will not be raised and may block
+ indefinitely until match.
+
+ When the keyword argument searchwindowsize is -1 (default), then the
+ value specified by the class maxread attribute is used.
+
+ A list entry may be EOF or TIMEOUT instead of a string. This will
+ catch these exceptions and return the index of the list entry instead
+ of raising the exception. The attribute 'after' will be set to the
+ exception type. The attribute 'match' will be None. This allows you to
+ write code like this::
+
+ index = p.expect(['good', 'bad', pexpect.EOF, pexpect.TIMEOUT])
+ if index == 0:
+ do_something()
+ elif index == 1:
+ do_something_else()
+ elif index == 2:
+ do_some_other_thing()
+ elif index == 3:
+ do_something_completely_different()
+
+ instead of code like this::
+
+ try:
+ index = p.expect(['good', 'bad'])
+ if index == 0:
+ do_something()
+ elif index == 1:
+ do_something_else()
+ except EOF:
+ do_some_other_thing()
+ except TIMEOUT:
+ do_something_completely_different()
+
+ These two forms are equivalent. It all depends on what you want. You
+ can also just expect the EOF if you are waiting for all output of a
+ child to finish. For example::
+
+ p = pexpect.spawn('/bin/ls')
+ p.expect(pexpect.EOF)
+ print p.before
+
+ If you are trying to optimize for speed then see expect_list().
+
+ On Python 3.4, or Python 3.3 with asyncio installed, passing
``async_=True`` will make this return an :mod:`asyncio` coroutine,
- which you can yield from to get the same result that this method would
- normally give directly. So, inside a coroutine, you can replace this code::
-
- index = p.expect(patterns)
-
- With this non-blocking form::
-
+ which you can yield from to get the same result that this method would
+ normally give directly. So, inside a coroutine, you can replace this code::
+
+ index = p.expect(patterns)
+
+ With this non-blocking form::
+
index = yield from p.expect(patterns, async_=True)
- '''
+ '''
if 'async' in kw:
async_ = kw.pop('async')
if kw:
raise TypeError("Unknown keyword arguments: {}".format(kw))
-
- compiled_pattern_list = self.compile_pattern_list(pattern)
- return self.expect_list(compiled_pattern_list,
+
+ compiled_pattern_list = self.compile_pattern_list(pattern)
+ return self.expect_list(compiled_pattern_list,
timeout, searchwindowsize, async_)
-
- def expect_list(self, pattern_list, timeout=-1, searchwindowsize=-1,
+
+ def expect_list(self, pattern_list, timeout=-1, searchwindowsize=-1,
async_=False, **kw):
- '''This takes a list of compiled regular expressions and returns the
- index into the pattern_list that matched the child output. The list may
- also contain EOF or TIMEOUT(which are not compiled regular
- expressions). This method is similar to the expect() method except that
- expect_list() does not recompile the pattern list on every call. This
- may help if you are trying to optimize for speed, otherwise just use
- the expect() method. This is called by expect().
-
-
+ '''This takes a list of compiled regular expressions and returns the
+ index into the pattern_list that matched the child output. The list may
+ also contain EOF or TIMEOUT(which are not compiled regular
+ expressions). This method is similar to the expect() method except that
+ expect_list() does not recompile the pattern list on every call. This
+ may help if you are trying to optimize for speed, otherwise just use
+ the expect() method. This is called by expect().
+
+
Like :meth:`expect`, passing ``async_=True`` will make this return an
- asyncio coroutine.
- '''
- if timeout == -1:
- timeout = self.timeout
+ asyncio coroutine.
+ '''
+ if timeout == -1:
+ timeout = self.timeout
if 'async' in kw:
async_ = kw.pop('async')
if kw:
raise TypeError("Unknown keyword arguments: {}".format(kw))
-
- exp = Expecter(self, searcher_re(pattern_list), searchwindowsize)
+
+ exp = Expecter(self, searcher_re(pattern_list), searchwindowsize)
if async_:
from ._async import expect_async
- return expect_async(exp, timeout)
- else:
- return exp.expect_loop(timeout)
-
- def expect_exact(self, pattern_list, timeout=-1, searchwindowsize=-1,
+ return expect_async(exp, timeout)
+ else:
+ return exp.expect_loop(timeout)
+
+ def expect_exact(self, pattern_list, timeout=-1, searchwindowsize=-1,
async_=False, **kw):
-
- '''This is similar to expect(), but uses plain string matching instead
- of compiled regular expressions in 'pattern_list'. The 'pattern_list'
- may be a string; a list or other sequence of strings; or TIMEOUT and
- EOF.
-
- This call might be faster than expect() for two reasons: string
- searching is faster than RE matching and it is possible to limit the
- search to just the end of the input buffer.
-
- This method is also useful when you don't want to have to worry about
- escaping regular expression characters that you want to match.
-
+
+ '''This is similar to expect(), but uses plain string matching instead
+ of compiled regular expressions in 'pattern_list'. The 'pattern_list'
+ may be a string; a list or other sequence of strings; or TIMEOUT and
+ EOF.
+
+ This call might be faster than expect() for two reasons: string
+ searching is faster than RE matching and it is possible to limit the
+ search to just the end of the input buffer.
+
+ This method is also useful when you don't want to have to worry about
+ escaping regular expression characters that you want to match.
+
Like :meth:`expect`, passing ``async_=True`` will make this return an
- asyncio coroutine.
- '''
- if timeout == -1:
- timeout = self.timeout
+ asyncio coroutine.
+ '''
+ if timeout == -1:
+ timeout = self.timeout
if 'async' in kw:
async_ = kw.pop('async')
if kw:
raise TypeError("Unknown keyword arguments: {}".format(kw))
-
- if (isinstance(pattern_list, self.allowed_string_types) or
- pattern_list in (TIMEOUT, EOF)):
- pattern_list = [pattern_list]
-
- def prepare_pattern(pattern):
- if pattern in (TIMEOUT, EOF):
- return pattern
- if isinstance(pattern, self.allowed_string_types):
- return self._coerce_expect_string(pattern)
- self._pattern_type_err(pattern)
-
- try:
- pattern_list = iter(pattern_list)
- except TypeError:
- self._pattern_type_err(pattern_list)
- pattern_list = [prepare_pattern(p) for p in pattern_list]
-
- exp = Expecter(self, searcher_string(pattern_list), searchwindowsize)
+
+ if (isinstance(pattern_list, self.allowed_string_types) or
+ pattern_list in (TIMEOUT, EOF)):
+ pattern_list = [pattern_list]
+
+ def prepare_pattern(pattern):
+ if pattern in (TIMEOUT, EOF):
+ return pattern
+ if isinstance(pattern, self.allowed_string_types):
+ return self._coerce_expect_string(pattern)
+ self._pattern_type_err(pattern)
+
+ try:
+ pattern_list = iter(pattern_list)
+ except TypeError:
+ self._pattern_type_err(pattern_list)
+ pattern_list = [prepare_pattern(p) for p in pattern_list]
+
+ exp = Expecter(self, searcher_string(pattern_list), searchwindowsize)
if async_:
from ._async import expect_async
- return expect_async(exp, timeout)
- else:
- return exp.expect_loop(timeout)
-
- def expect_loop(self, searcher, timeout=-1, searchwindowsize=-1):
- '''This is the common loop used inside expect. The 'searcher' should be
- an instance of searcher_re or searcher_string, which describes how and
- what to search for in the input.
-
- See expect() for other arguments, return value and exceptions. '''
-
- exp = Expecter(self, searcher, searchwindowsize)
- return exp.expect_loop(timeout)
-
- def read(self, size=-1):
- '''This reads at most "size" bytes from the file (less if the read hits
- EOF before obtaining size bytes). If the size argument is negative or
- omitted, read all data until EOF is reached. The bytes are returned as
- a string object. An empty string is returned when EOF is encountered
- immediately. '''
-
- if size == 0:
- return self.string_type()
- if size < 0:
- # delimiter default is EOF
- self.expect(self.delimiter)
- return self.before
-
- # I could have done this more directly by not using expect(), but
- # I deliberately decided to couple read() to expect() so that
+ return expect_async(exp, timeout)
+ else:
+ return exp.expect_loop(timeout)
+
+ def expect_loop(self, searcher, timeout=-1, searchwindowsize=-1):
+ '''This is the common loop used inside expect. The 'searcher' should be
+ an instance of searcher_re or searcher_string, which describes how and
+ what to search for in the input.
+
+ See expect() for other arguments, return value and exceptions. '''
+
+ exp = Expecter(self, searcher, searchwindowsize)
+ return exp.expect_loop(timeout)
+
+ def read(self, size=-1):
+ '''This reads at most "size" bytes from the file (less if the read hits
+ EOF before obtaining size bytes). If the size argument is negative or
+ omitted, read all data until EOF is reached. The bytes are returned as
+ a string object. An empty string is returned when EOF is encountered
+ immediately. '''
+
+ if size == 0:
+ return self.string_type()
+ if size < 0:
+ # delimiter default is EOF
+ self.expect(self.delimiter)
+ return self.before
+
+ # I could have done this more directly by not using expect(), but
+ # I deliberately decided to couple read() to expect() so that
# I would catch any bugs early and ensure consistent behavior.
- # It's a little less efficient, but there is less for me to
- # worry about if I have to later modify read() or expect().
- # Note, it's OK if size==-1 in the regex. That just means it
- # will never match anything in which case we stop only on EOF.
- cre = re.compile(self._coerce_expect_string('.{%d}' % size), re.DOTALL)
- # delimiter default is EOF
- index = self.expect([cre, self.delimiter])
- if index == 0:
- ### FIXME self.before should be ''. Should I assert this?
- return self.after
- return self.before
-
- def readline(self, size=-1):
- '''This reads and returns one entire line. The newline at the end of
- line is returned as part of the string, unless the file ends without a
- newline. An empty string is returned if EOF is encountered immediately.
- This looks for a newline as a CR/LF pair (\\r\\n) even on UNIX because
- this is what the pseudotty device returns. So contrary to what you may
- expect you will receive newlines as \\r\\n.
-
- If the size argument is 0 then an empty string is returned. In all
- other cases the size argument is ignored, which is not standard
- behavior for a file-like object. '''
-
- if size == 0:
- return self.string_type()
- # delimiter default is EOF
- index = self.expect([self.crlf, self.delimiter])
- if index == 0:
- return self.before + self.crlf
- else:
- return self.before
-
- def __iter__(self):
- '''This is to support iterators over a file-like object.
- '''
- return iter(self.readline, self.string_type())
-
- def readlines(self, sizehint=-1):
- '''This reads until EOF using readline() and returns a list containing
- the lines thus read. The optional 'sizehint' argument is ignored.
- Remember, because this reads until EOF that means the child
- process should have closed its stdout. If you run this method on
- a child that is still running with its stdout open then this
- method will block until it timesout.'''
-
- lines = []
- while True:
- line = self.readline()
- if not line:
- break
- lines.append(line)
- return lines
-
- def fileno(self):
- '''Expose file descriptor for a file-like interface
- '''
- return self.child_fd
-
- def flush(self):
- '''This does nothing. It is here to support the interface for a
- File-like object. '''
- pass
-
- def isatty(self):
- """Overridden in subclass using tty"""
- return False
-
- # For 'with spawn(...) as child:'
- def __enter__(self):
- return self
+ # It's a little less efficient, but there is less for me to
+ # worry about if I have to later modify read() or expect().
+ # Note, it's OK if size==-1 in the regex. That just means it
+ # will never match anything in which case we stop only on EOF.
+ cre = re.compile(self._coerce_expect_string('.{%d}' % size), re.DOTALL)
+ # delimiter default is EOF
+ index = self.expect([cre, self.delimiter])
+ if index == 0:
+ ### FIXME self.before should be ''. Should I assert this?
+ return self.after
+ return self.before
+
+ def readline(self, size=-1):
+ '''This reads and returns one entire line. The newline at the end of
+ line is returned as part of the string, unless the file ends without a
+ newline. An empty string is returned if EOF is encountered immediately.
+ This looks for a newline as a CR/LF pair (\\r\\n) even on UNIX because
+ this is what the pseudotty device returns. So contrary to what you may
+ expect you will receive newlines as \\r\\n.
+
+ If the size argument is 0 then an empty string is returned. In all
+ other cases the size argument is ignored, which is not standard
+ behavior for a file-like object. '''
+
+ if size == 0:
+ return self.string_type()
+ # delimiter default is EOF
+ index = self.expect([self.crlf, self.delimiter])
+ if index == 0:
+ return self.before + self.crlf
+ else:
+ return self.before
+
+ def __iter__(self):
+ '''This is to support iterators over a file-like object.
+ '''
+ return iter(self.readline, self.string_type())
+
+ def readlines(self, sizehint=-1):
+ '''This reads until EOF using readline() and returns a list containing
+ the lines thus read. The optional 'sizehint' argument is ignored.
+ Remember, because this reads until EOF that means the child
+ process should have closed its stdout. If you run this method on
+ a child that is still running with its stdout open then this
+ method will block until it timesout.'''
+
+ lines = []
+ while True:
+ line = self.readline()
+ if not line:
+ break
+ lines.append(line)
+ return lines
+
+ def fileno(self):
+ '''Expose file descriptor for a file-like interface
+ '''
+ return self.child_fd
+
+ def flush(self):
+ '''This does nothing. It is here to support the interface for a
+ File-like object. '''
+ pass
+
+ def isatty(self):
+ """Overridden in subclass using tty"""
+ return False
+
+ # For 'with spawn(...) as child:'
+ def __enter__(self):
+ return self
- def __exit__(self, etype, evalue, tb):
- # We rely on subclasses to implement close(). If they don't, it's not
- # clear what a context manager should do.
- self.close()
+ def __exit__(self, etype, evalue, tb):
+ # We rely on subclasses to implement close(). If they don't, it's not
+ # clear what a context manager should do.
+ self.close()
diff --git a/contrib/python/pexpect/pexpect/utils.py b/contrib/python/pexpect/pexpect/utils.py
index f7745196090..13a7849a0e1 100644
--- a/contrib/python/pexpect/pexpect/utils.py
+++ b/contrib/python/pexpect/pexpect/utils.py
@@ -1,130 +1,130 @@
-import os
-import sys
-import stat
+import os
+import sys
+import stat
import select
import time
import errno
-
+
try:
InterruptedError
except NameError:
# Alias Python2 exception to Python3
InterruptedError = select.error
-
+
if sys.version_info[0] >= 3:
string_types = (str,)
else:
string_types = (unicode, str)
-def is_executable_file(path):
- """Checks that path is an executable regular file, or a symlink towards one.
-
- This is roughly ``os.path isfile(path) and os.access(path, os.X_OK)``.
- """
- # follow symlinks,
- fpath = os.path.realpath(path)
-
- if not os.path.isfile(fpath):
- # non-files (directories, fifo, etc.)
- return False
-
- mode = os.stat(fpath).st_mode
-
- if (sys.platform.startswith('sunos')
- and os.getuid() == 0):
- # When root on Solaris, os.X_OK is True for *all* files, irregardless
- # of their executability -- instead, any permission bit of any user,
- # group, or other is fine enough.
- #
- # (This may be true for other "Unix98" OS's such as HP-UX and AIX)
- return bool(mode & (stat.S_IXUSR |
- stat.S_IXGRP |
- stat.S_IXOTH))
-
- return os.access(fpath, os.X_OK)
-
-
+def is_executable_file(path):
+ """Checks that path is an executable regular file, or a symlink towards one.
+
+ This is roughly ``os.path isfile(path) and os.access(path, os.X_OK)``.
+ """
+ # follow symlinks,
+ fpath = os.path.realpath(path)
+
+ if not os.path.isfile(fpath):
+ # non-files (directories, fifo, etc.)
+ return False
+
+ mode = os.stat(fpath).st_mode
+
+ if (sys.platform.startswith('sunos')
+ and os.getuid() == 0):
+ # When root on Solaris, os.X_OK is True for *all* files, irregardless
+ # of their executability -- instead, any permission bit of any user,
+ # group, or other is fine enough.
+ #
+ # (This may be true for other "Unix98" OS's such as HP-UX and AIX)
+ return bool(mode & (stat.S_IXUSR |
+ stat.S_IXGRP |
+ stat.S_IXOTH))
+
+ return os.access(fpath, os.X_OK)
+
+
def which(filename, env=None):
- '''This takes a given filename; tries to find it in the environment path;
- then checks if it is executable. This returns the full path to the filename
- if found and executable. Otherwise this returns None.'''
-
- # Special case where filename contains an explicit path.
- if os.path.dirname(filename) != '' and is_executable_file(filename):
- return filename
+ '''This takes a given filename; tries to find it in the environment path;
+ then checks if it is executable. This returns the full path to the filename
+ if found and executable. Otherwise this returns None.'''
+
+ # Special case where filename contains an explicit path.
+ if os.path.dirname(filename) != '' and is_executable_file(filename):
+ return filename
if env is None:
env = os.environ
p = env.get('PATH')
if not p:
- p = os.defpath
- pathlist = p.split(os.pathsep)
- for path in pathlist:
- ff = os.path.join(path, filename)
- if is_executable_file(ff):
- return ff
- return None
-
-
-def split_command_line(command_line):
-
- '''This splits a command line into a list of arguments. It splits arguments
- on spaces, but handles embedded quotes, doublequotes, and escaped
- characters. It's impossible to do this with a regular expression, so I
- wrote a little state machine to parse the command line. '''
-
- arg_list = []
- arg = ''
-
- # Constants to name the states we can be in.
- state_basic = 0
- state_esc = 1
- state_singlequote = 2
- state_doublequote = 3
- # The state when consuming whitespace between commands.
- state_whitespace = 4
- state = state_basic
-
- for c in command_line:
- if state == state_basic or state == state_whitespace:
- if c == '\\':
- # Escape the next character
- state = state_esc
- elif c == r"'":
- # Handle single quote
- state = state_singlequote
- elif c == r'"':
- # Handle double quote
- state = state_doublequote
- elif c.isspace():
- # Add arg to arg_list if we aren't in the middle of whitespace.
- if state == state_whitespace:
- # Do nothing.
- None
- else:
- arg_list.append(arg)
- arg = ''
- state = state_whitespace
- else:
- arg = arg + c
- state = state_basic
- elif state == state_esc:
- arg = arg + c
- state = state_basic
- elif state == state_singlequote:
- if c == r"'":
- state = state_basic
- else:
- arg = arg + c
- elif state == state_doublequote:
- if c == r'"':
- state = state_basic
- else:
- arg = arg + c
-
- if arg != '':
- arg_list.append(arg)
- return arg_list
+ p = os.defpath
+ pathlist = p.split(os.pathsep)
+ for path in pathlist:
+ ff = os.path.join(path, filename)
+ if is_executable_file(ff):
+ return ff
+ return None
+
+
+def split_command_line(command_line):
+
+ '''This splits a command line into a list of arguments. It splits arguments
+ on spaces, but handles embedded quotes, doublequotes, and escaped
+ characters. It's impossible to do this with a regular expression, so I
+ wrote a little state machine to parse the command line. '''
+
+ arg_list = []
+ arg = ''
+
+ # Constants to name the states we can be in.
+ state_basic = 0
+ state_esc = 1
+ state_singlequote = 2
+ state_doublequote = 3
+ # The state when consuming whitespace between commands.
+ state_whitespace = 4
+ state = state_basic
+
+ for c in command_line:
+ if state == state_basic or state == state_whitespace:
+ if c == '\\':
+ # Escape the next character
+ state = state_esc
+ elif c == r"'":
+ # Handle single quote
+ state = state_singlequote
+ elif c == r'"':
+ # Handle double quote
+ state = state_doublequote
+ elif c.isspace():
+ # Add arg to arg_list if we aren't in the middle of whitespace.
+ if state == state_whitespace:
+ # Do nothing.
+ None
+ else:
+ arg_list.append(arg)
+ arg = ''
+ state = state_whitespace
+ else:
+ arg = arg + c
+ state = state_basic
+ elif state == state_esc:
+ arg = arg + c
+ state = state_basic
+ elif state == state_singlequote:
+ if c == r"'":
+ state = state_basic
+ else:
+ arg = arg + c
+ elif state == state_doublequote:
+ if c == r'"':
+ state = state_basic
+ else:
+ arg = arg + c
+
+ if arg != '':
+ arg_list.append(arg)
+ return arg_list
def select_ignore_interrupts(iwtd, owtd, ewtd, timeout=None):
diff --git a/contrib/python/pexpect/ya.make b/contrib/python/pexpect/ya.make
index a5bb92fcacb..2fdba71fba3 100644
--- a/contrib/python/pexpect/ya.make
+++ b/contrib/python/pexpect/ya.make
@@ -1,35 +1,35 @@
PY23_LIBRARY()
-
+
LICENSE(ISC)
OWNER(g:python-contrib borman)
VERSION(4.8.0)
-PEERDIR(
+PEERDIR(
contrib/python/ptyprocess
-)
-
+)
+
NO_LINT()
-PY_SRCS(
- TOP_LEVEL
- pexpect/ANSI.py
- pexpect/FSM.py
- pexpect/__init__.py
- pexpect/exceptions.py
- pexpect/expect.py
- pexpect/fdpexpect.py
- pexpect/popen_spawn.py
- pexpect/pty_spawn.py
- pexpect/pxssh.py
- pexpect/replwrap.py
- pexpect/run.py
- pexpect/screen.py
- pexpect/spawnbase.py
- pexpect/utils.py
-)
-
+PY_SRCS(
+ TOP_LEVEL
+ pexpect/ANSI.py
+ pexpect/FSM.py
+ pexpect/__init__.py
+ pexpect/exceptions.py
+ pexpect/expect.py
+ pexpect/fdpexpect.py
+ pexpect/popen_spawn.py
+ pexpect/pty_spawn.py
+ pexpect/pxssh.py
+ pexpect/replwrap.py
+ pexpect/run.py
+ pexpect/screen.py
+ pexpect/spawnbase.py
+ pexpect/utils.py
+)
+
IF (PYTHON3)
PY_SRCS(
TOP_LEVEL
@@ -43,4 +43,4 @@ RESOURCE_FILES(
.dist-info/top_level.txt
)
-END()
+END()