3232import functools
3333import glob
3434import io
35+ from io import StringIO
3536import os
3637import platform
3738import re
3839import shlex
3940import signal
40- import six
41+ import subprocess
4142import sys
4243import tempfile
4344import traceback
5152
5253import pyparsing
5354import pyperclip
55+ from pyperclip import PyperclipException
56+ import six .moves as sm # Used for sm.input
5457
5558# Collection is a container that is sizable and iterable
5659# It was introduced in Python 3.6. We will try to import it, otherwise use our implementation
5760try :
5861 from collections .abc import Collection , Iterable
5962except ImportError :
60-
61- if six .PY3 :
62- from collections .abc import Sized , Iterable , Container
63- else :
64- from collections import Sized , Iterable , Container
63+ from collections .abc import Sized , Iterable , Container
6564
6665 # noinspection PyAbstractClass
6766 class Collection (Sized , Iterable , Container ):
@@ -78,44 +77,12 @@ def __subclasshook__(cls, C):
7877 return True
7978 return NotImplemented
8079
81- # Newer versions of pyperclip are released as a single file, but older versions had a more complicated structure
82- try :
83- from pyperclip .exceptions import PyperclipException
84- except ImportError :
85- # noinspection PyUnresolvedReferences
86- from pyperclip import PyperclipException
87-
88- # next(it) gets next item of iterator it. This is a replacement for calling it.next() in Python 2 and next(it) in Py3
89- from six import next
90-
91- # Possible types for text data. This is basestring() in Python 2 and str in Python 3.
92- from six import string_types
93-
94- # Used for sm.input: raw_input() for Python 2 or input() for Python 3
95- import six .moves as sm
96-
97- # itertools.zip() for Python 2 or zip() for Python 3 - produces an iterator in both cases
98- from six .moves import zip
99-
100- # If using Python 2.7, try to use the subprocess32 package backported from Python 3.2 due to various improvements
101- # NOTE: The feature to pipe output to a shell command won't work correctly in Python 2.7 without this
102- try :
103- # noinspection PyPackageRequirements
104- import subprocess32 as subprocess
105- except ImportError :
106- import subprocess
107-
108- # Python 3.4 and earlier require contextlib2 for temporarily redirecting stderr and stdout
80+ # Python 3.4 require contextlib2 for temporarily redirecting stderr and stdout
10981if sys .version_info < (3 , 5 ):
11082 from contextlib2 import redirect_stdout , redirect_stderr
11183else :
11284 from contextlib import redirect_stdout , redirect_stderr
11385
114- if six .PY3 :
115- from io import StringIO # Python3
116- else :
117- from io import BytesIO as StringIO # Python2
118-
11986# Detect whether IPython is installed to determine if the built-in "ipy" command should be included
12087ipython_available = True
12188try :
@@ -136,14 +103,12 @@ def __subclasshook__(cls, C):
136103 except ImportError :
137104 pass
138105
139-
140106# Check what implementation of readline we are using
141107class RlType (Enum ):
142108 GNU = 1
143109 PYREADLINE = 2
144110 NONE = 3
145111
146-
147112rl_type = RlType .NONE
148113
149114if 'pyreadline' in sys .modules :
@@ -167,25 +132,6 @@ class RlType(Enum):
167132 rl_basic_quote_characters = ctypes .c_char_p .in_dll (readline_lib , "rl_basic_quote_characters" )
168133 orig_rl_basic_quote_characters_addr = ctypes .cast (rl_basic_quote_characters , ctypes .c_void_p ).value
169134
170-
171- # BrokenPipeError and FileNotFoundError exist only in Python 3. Use IOError for Python 2.
172- if six .PY3 :
173- BROKEN_PIPE_ERROR = BrokenPipeError
174- FILE_NOT_FOUND_ERROR = FileNotFoundError
175- else :
176- BROKEN_PIPE_ERROR = FILE_NOT_FOUND_ERROR = IOError
177-
178- # On some systems, pyperclip will import gtk for its clipboard functionality.
179- # The following code is a workaround for gtk interfering with printing from a background
180- # thread while the CLI thread is blocking in raw_input() in Python 2 on Linux.
181- if six .PY2 and sys .platform .startswith ('lin' ):
182- try :
183- # noinspection PyUnresolvedReferences
184- import gtk
185- gtk .set_interactive (0 )
186- except ImportError :
187- pass
188-
189135__version__ = '0.9.0'
190136
191137# Pyparsing enablePackrat() can greatly speed up parsing, but problems have been seen in Python 3 in the past
@@ -250,8 +196,7 @@ def set_strip_quotes(val):
250196def _which (editor ):
251197 try :
252198 editor_path = subprocess .check_output (['which' , editor ], stderr = subprocess .STDOUT ).strip ()
253- if six .PY3 :
254- editor_path = editor_path .decode ()
199+ editor_path = editor_path .decode ()
255200 except subprocess .CalledProcessError :
256201 editor_path = None
257202 return editor_path
@@ -431,12 +376,6 @@ def get_paste_buffer():
431376 :return: str - contents of the clipboard
432377 """
433378 pb_str = pyperclip .paste ()
434-
435- # If value returned from the clipboard is unicode and this is Python 2, convert to a "normal" Python 2 string first
436- if six .PY2 and not isinstance (pb_str , str ):
437- import unicodedata
438- pb_str = unicodedata .normalize ('NFKD' , pb_str ).encode ('ascii' , 'ignore' )
439-
440379 return pb_str
441380
442381
@@ -659,7 +598,7 @@ def enter_submenu(parent_cmd, line):
659598 if self .persistent_history_file :
660599 try :
661600 readline .read_history_file (self .persistent_history_file )
662- except FILE_NOT_FOUND_ERROR :
601+ except FileNotFoundError :
663602 pass
664603
665604 try :
@@ -843,12 +782,12 @@ def __init__(self, completekey='tab', stdin=None, stdout=None, persistent_histor
843782 readline .read_history_file (persistent_history_file )
844783 # default history len is -1 (infinite), which may grow unruly
845784 readline .set_history_length (persistent_history_length )
846- except FILE_NOT_FOUND_ERROR :
785+ except FileNotFoundError :
847786 pass
848787 atexit .register (readline .write_history_file , persistent_history_file )
849788
850- # Call super class constructor. Need to do it in this way for Python 2 and 3 compatibility
851- cmd . Cmd . __init__ (self , completekey = completekey , stdin = stdin , stdout = stdout )
789+ # Call super class constructor
790+ super (). __init__ (completekey = completekey , stdin = stdin , stdout = stdout )
852791
853792 # Commands to exclude from the help menu and tab completion
854793 self .hidden_commands = ['eof' , 'eos' , '_relative_load' ]
@@ -974,7 +913,7 @@ def poutput(self, msg, end='\n'):
974913 self .stdout .write (msg_str )
975914 if not msg_str .endswith (end ):
976915 self .stdout .write (end )
977- except BROKEN_PIPE_ERROR :
916+ except BrokenPipeError :
978917 # This occurs if a command's output is being piped to another process and that process closes before the
979918 # command is finished. If you would like your application to print a warning message, then set the
980919 # broken_pipe_warning attribute to the message you want printed.
@@ -1066,7 +1005,7 @@ def ppaged(self, msg, end='\n'):
10661005 self .pipe_proc = None
10671006 else :
10681007 self .stdout .write (msg_str )
1069- except BROKEN_PIPE_ERROR :
1008+ except BrokenPipeError :
10701009 # This occurs if a command's output is being piped to another process and that process closes before the
10711010 # command is finished. If you would like your application to print a warning message, then set the
10721011 # broken_pipe_warning attribute to the message you want printed.
@@ -1708,12 +1647,8 @@ def _display_matches_gnu_readline(self, substitution, matches, longest_match_len
17081647
17091648 # We will use readline's display function (rl_display_match_list()), so we
17101649 # need to encode our string as bytes to place in a C array.
1711- if six .PY3 :
1712- encoded_substitution = bytes (substitution , encoding = 'utf-8' )
1713- encoded_matches = [bytes (cur_match , encoding = 'utf-8' ) for cur_match in matches_to_display ]
1714- else :
1715- encoded_substitution = bytes (substitution )
1716- encoded_matches = [bytes (cur_match ) for cur_match in matches_to_display ]
1650+ encoded_substitution = bytes (substitution , encoding = 'utf-8' )
1651+ encoded_matches = [bytes (cur_match , encoding = 'utf-8' ) for cur_match in matches_to_display ]
17171652
17181653 # rl_display_match_list() expects matches to be in argv format where
17191654 # substitution is the first element, followed by the matches, and then a NULL.
@@ -2300,19 +2235,12 @@ def _redirect_output(self, statement):
23002235 # Create a pipe with read and write sides
23012236 read_fd , write_fd = os .pipe ()
23022237
2303- # Make sure that self.poutput() expects unicode strings in Python 3 and byte strings in Python 2
2304- write_mode = 'w'
2305- read_mode = 'r'
2306- if six .PY2 :
2307- write_mode = 'wb'
2308- read_mode = 'rb'
2309-
23102238 # Open each side of the pipe and set stdout accordingly
23112239 # noinspection PyTypeChecker
2312- self .stdout = io .open (write_fd , write_mode )
2240+ self .stdout = io .open (write_fd , 'w' )
23132241 self .redirecting = True
23142242 # noinspection PyTypeChecker
2315- subproc_stdin = io .open (read_fd , read_mode )
2243+ subproc_stdin = io .open (read_fd , 'r' )
23162244
23172245 # We want Popen to raise an exception if it fails to open the process. Thus we don't set shell to True.
23182246 try :
@@ -2359,7 +2287,7 @@ def _restore_output(self, statement):
23592287 try :
23602288 # Close the file or pipe that stdout was redirected to
23612289 self .stdout .close ()
2362- except BROKEN_PIPE_ERROR :
2290+ except BrokenPipeError :
23632291 pass
23642292 finally :
23652293 # Restore self.stdout
@@ -2584,9 +2512,8 @@ def _cmdloop(self):
25842512 elif rl_type == RlType .PYREADLINE :
25852513 readline .rl .mode ._display_completions = orig_pyreadline_display
25862514
2587- # Need to set empty list this way because Python 2 doesn't support the clear() method on lists
2588- self .cmdqueue = []
2589- self ._script_dir = []
2515+ self .cmdqueue .clear ()
2516+ self ._script_dir .clear ()
25902517
25912518 return stop
25922519
@@ -2857,11 +2784,11 @@ def select(self, opts, prompt='Your choice? '):
28572784 that the return value can differ from
28582785 the text advertised to the user """
28592786 local_opts = opts
2860- if isinstance (opts , string_types ):
2787+ if isinstance (opts , str ):
28612788 local_opts = list (zip (opts .split (), opts .split ()))
28622789 fulloptions = []
28632790 for opt in local_opts :
2864- if isinstance (opt , string_types ):
2791+ if isinstance (opt , str ):
28652792 fulloptions .append ((opt , opt ))
28662793 else :
28672794 try :
@@ -3422,10 +3349,8 @@ def do_load(self, arglist):
34223349 try :
34233350 # Read all lines of the script and insert into the head of the
34243351 # command queue. Add an "end of script (eos)" command to cleanup the
3425- # self._script_dir list when done. Specify file encoding in Python
3426- # 3, but Python 2 doesn't allow that argument to open().
3427- kwargs = {'encoding' : 'utf-8' } if six .PY3 else {}
3428- with open (expanded_path , ** kwargs ) as target :
3352+ # self._script_dir list when done.
3353+ with open (expanded_path , encoding = 'utf-8' ) as target :
34293354 self .cmdqueue = target .read ().splitlines () + ['eos' ] + self .cmdqueue
34303355 except IOError as e :
34313356 self .perror ('Problem accessing script from {}:\n {}' .format (expanded_path , e ))
@@ -4129,10 +4054,6 @@ def __bool__(self):
41294054 """If err is an empty string, treat the result as a success; otherwise treat it as a failure."""
41304055 return not self .err
41314056
4132- def __nonzero__ (self ):
4133- """Python 2 uses this method for determining Truthiness"""
4134- return self .__bool__ ()
4135-
41364057
41374058if __name__ == '__main__' :
41384059 # If run as the main application, simply start a bare-bones cmd2 application with only built-in functionality.
0 commit comments