diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..d3f166c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +sudo: false +language: python +python: + - "2.7" + - "3.5" + - "3.6" + - "3.7-dev" # 3.7 development branch + +before_install: + - pip install codecov + +install: + - "pip install -r requirements.txt" + - "python setup.py install" + - "python setup.py test" + +after_success: + - codecov \ No newline at end of file diff --git a/README.rst b/README.md similarity index 97% rename from README.rst rename to README.md index 75c2986..47c505f 100644 --- a/README.rst +++ b/README.md @@ -1,3 +1,6 @@ +## Travis CI client +[![Build Status](https://travis-ci.org/travis-ci/travis-web.svg?branch=master)](https://travis-ci.org/Python3pkg/0bin) + 0bin ==== diff --git a/docs/conf.py b/docs/conf.py index 398e588..b4275de 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -40,8 +40,8 @@ master_doc = 'index' # General information about the project. -project = u'0bin' -copyright = u'2012, Sam et Max' +project = '0bin' +copyright = '2012, Sam et Max' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -183,8 +183,8 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', '0bin.tex', u'0bin Documentation', - u'Sam et Max', 'manual'), + ('index', '0bin.tex', '0bin Documentation', + 'Sam et Max', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -213,8 +213,8 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', '0bin', u'0bin Documentation', - [u'Sam et Max'], 1) + ('index', '0bin', '0bin Documentation', + ['Sam et Max'], 1) ] # If true, show URL addresses after external links. @@ -227,8 +227,8 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', '0bin', u'0bin Documentation', - u'Sam et Max', '0bin', 'One line description of project.', + ('index', '0bin', '0bin Documentation', + 'Sam et Max', '0bin', 'One line description of project.', 'Miscellaneous'), ] diff --git a/libs/bottle.py b/libs/bottle.py index c40ad9a..bebd00d 100644 --- a/libs/bottle.py +++ b/libs/bottle.py @@ -13,7 +13,7 @@ License: MIT (see LICENSE for details) """ -from __future__ import with_statement + __author__ = 'Marcel Hellkamp' __version__ = '0.13-dev' @@ -53,6 +53,7 @@ from traceback import format_exc, print_exc from inspect import getargspec from unicodedata import normalize +import collections try: from simplejson import dumps as json_dumps, loads as json_lds @@ -102,8 +103,8 @@ def _e(): import pickle from io import BytesIO from configparser import ConfigParser - basestring = str - unicode = str + str = str + str = str json_loads = lambda s: json_lds(touni(s)) callable = lambda x: hasattr(x, '__call__') imap = map @@ -111,41 +112,41 @@ def _e(): def _raise(*a): raise a[0](a[1]).with_traceback(a[2]) else: # 2.x - import httplib - import thread - from urlparse import urljoin, SplitResult as UrlSplitResult - from urllib import urlencode, quote as urlquote, unquote as urlunquote - from Cookie import SimpleCookie - from itertools import imap - import cPickle as pickle - from StringIO import StringIO as BytesIO - from ConfigParser import SafeConfigParser as ConfigParser + import http.client + import _thread + from urllib.parse import urljoin, SplitResult as UrlSplitResult + from urllib.parse import urlencode, quote as urlquote, unquote as urlunquote + from http.cookies import SimpleCookie + + import pickle as pickle + from io import StringIO as BytesIO + from configparser import SafeConfigParser as ConfigParser if py25: msg = "Python 2.5 support may be dropped in future versions of Bottle." warnings.warn(msg, DeprecationWarning) from UserDict import DictMixin def next(it): - return it.next() + return next(it) bytes = str else: # 2.6, 2.7 from collections import MutableMapping as DictMixin - unicode = unicode + str = str json_loads = json_lds eval(compile('def _raise(*a): raise a[0], a[1], a[2]', '', 'exec')) # Some helpers for string/byte handling def tob(s, enc='utf8'): - return s.encode(enc) if isinstance(s, unicode) else bytes(s) + return s.encode(enc) if isinstance(s, str) else bytes(s) def touni(s, enc='utf8', err='strict'): if isinstance(s, bytes): return s.decode(enc, err) else: - return unicode(s or ("" if s is None else s)) + return str(s or ("" if s is None else s)) tonat = touni if py3k else tob @@ -567,8 +568,7 @@ def get_undecorated_callback(self): # in case of decorators with multiple arguments if not isinstance(func, FunctionType): # pick first FunctionType instance from multiple arguments - func = filter(lambda x: isinstance(x, FunctionType), - map(lambda x: x.cell_contents, attributes)) + func = [x for x in [x.cell_contents for x in attributes] if isinstance(x, FunctionType)] func = list(func)[0] # py3 support return func @@ -734,7 +734,7 @@ def install(self, plugin): decorator or an object that implements the :class:`Plugin` API. """ if hasattr(plugin, 'setup'): plugin.setup(self) - if not callable(plugin) and not hasattr(plugin, 'apply'): + if not isinstance(plugin, collections.Callable) and not hasattr(plugin, 'apply'): raise TypeError("Plugins must be callable or implement .apply()") self.plugins.append(plugin) self.reset() @@ -829,12 +829,12 @@ def hello(name): Any additional keyword arguments are stored as route-specific configuration and passed to plugins (see :meth:`Plugin.apply`). """ - if callable(path): path, callback = None, path + if isinstance(path, collections.Callable): path, callback = None, path plugins = makelist(apply) skiplist = makelist(skip) def decorator(callback): - if isinstance(callback, basestring): callback = load(callback) + if isinstance(callback, str): callback = load(callback) for rule in makelist(path) or yieldroutes(callback): for verb in makelist(method): verb = verb.upper() @@ -927,10 +927,10 @@ def _cast(self, out, peek=None): return [] # Join lists of byte or unicode strings. Mixed lists are NOT supported if isinstance(out, (tuple, list))\ - and isinstance(out[0], (bytes, unicode)): + and isinstance(out[0], (bytes, str)): out = out[0][0:0].join(out) # b'abc'[0:0] -> b'' # Encode unicode strings - if isinstance(out, unicode): + if isinstance(out, str): out = out.encode(response.charset) # Byte Strings are just returned if isinstance(out, bytes): @@ -976,9 +976,9 @@ def _cast(self, out, peek=None): return self._cast(first) elif isinstance(first, bytes): new_iter = itertools.chain([first], iout) - elif isinstance(first, unicode): + elif isinstance(first, str): encoder = lambda x: x.encode(response.charset) - new_iter = imap(encoder, itertools.chain([first], iout)) + new_iter = list(map(encoder, itertools.chain([first], iout))) else: msg = 'Unsupported response type: %s' % type(first) return self._cast(HTTPError(500, msg)) @@ -1090,7 +1090,7 @@ def get_header(self, name, default=None): def cookies(self): """ Cookies parsed into a :class:`FormsDict`. Signed cookies are NOT decoded. Use :meth:`get_cookie` if you expect signed cookies. """ - cookies = SimpleCookie(self.environ.get('HTTP_COOKIE', '')).values() + cookies = list(SimpleCookie(self.environ.get('HTTP_COOKIE', '')).values()) return FormsDict((c.key, c.value) for c in cookies) def get_cookie(self, key, default=None, secret=None): @@ -1424,7 +1424,7 @@ def __len__(self): return len(self.environ) def keys(self): - return self.environ.keys() + return list(self.environ.keys()) def __setitem__(self, key, value): """ Change an environ value and clear all caches that depend on it. """ @@ -1518,11 +1518,11 @@ def __init__(self, body='', status=None, headers=None, **more_headers): self.status = status or self.default_status if headers: if isinstance(headers, dict): - headers = headers.items() + headers = list(headers.items()) for name, value in headers: self.add_header(name, value) if more_headers: - for name, value in more_headers.items(): + for name, value in list(more_headers.items()): self.add_header(name, value) def copy(self, cls=None): @@ -1531,7 +1531,7 @@ def copy(self, cls=None): assert issubclass(cls, BaseResponse) copy = cls() copy.status = self.status - copy._headers = dict((k, v[:]) for (k, v) in self._headers.items()) + copy._headers = dict((k, v[:]) for (k, v) in list(self._headers.items())) if self._cookies: copy._cookies = SimpleCookie() copy._cookies.load(self._cookies.output(header='')) @@ -1597,7 +1597,7 @@ def __getitem__(self, name): return self._headers[_hkey(name)][-1] def __setitem__(self, name, value): - self._headers[_hkey(name)] = [value if isinstance(value, unicode) else + self._headers[_hkey(name)] = [value if isinstance(value, str) else str(value)] def get_header(self, name, default=None): @@ -1608,13 +1608,13 @@ def get_header(self, name, default=None): def set_header(self, name, value): """ Create a new response header, replacing any previously defined headers with the same name. """ - self._headers[_hkey(name)] = [value if isinstance(value, unicode) + self._headers[_hkey(name)] = [value if isinstance(value, str) else str(value)] def add_header(self, name, value): """ Add an additional response header, not removing duplicates. """ self._headers.setdefault(_hkey(name), []).append( - value if isinstance(value, unicode) else str(value)) + value if isinstance(value, str) else str(value)) def iter_headers(self): """ Yield (header, value) tuples, skipping headers that are not @@ -1633,12 +1633,12 @@ def headerlist(self): headers = [h for h in headers if h[0] not in bad_headers] out += [(name, val) for (name, vals) in headers for val in vals] if self._cookies: - for c in self._cookies.values(): + for c in list(self._cookies.values()): out.append(('Set-Cookie', c.OutputString())) if py3k: return [(k, v.encode('utf8').decode('latin1')) for (k, v) in out] else: - return [(k, v.encode('utf8') if isinstance(v, unicode) else v) + return [(k, v.encode('utf8') if isinstance(v, str) else v) for (k, v) in out] content_type = HeaderProperty('Content-Type') @@ -1693,13 +1693,13 @@ def set_cookie(self, name, value, secret=None, **options): if secret: value = touni(cookie_encode((name, value), secret)) - elif not isinstance(value, basestring): + elif not isinstance(value, str): raise TypeError('Secret key missing for non-string Cookie.') if len(value) > 4096: raise ValueError('Cookie value to long.') self._cookies[name] = value - for key, value in options.items(): + for key, value in list(options.items()): if key == 'max_age': if isinstance(value, timedelta): value = value.seconds + value.days * 24 * 3600 @@ -1896,7 +1896,7 @@ class MultiDict(DictMixin): """ def __init__(self, *a, **k): - self.dict = dict((k, [v]) for (k, v) in dict(*a, **k).items()) + self.dict = dict((k, [v]) for (k, v) in list(dict(*a, **k).items())) def __len__(self): return len(self.dict) @@ -1917,18 +1917,18 @@ def __setitem__(self, key, value): self.append(key, value) def keys(self): - return self.dict.keys() + return list(self.dict.keys()) if py3k: def values(self): - return (v[-1] for v in self.dict.values()) + return (v[-1] for v in list(self.dict.values())) def items(self): - return ((k, v[-1]) for k, v in self.dict.items()) + return ((k, v[-1]) for k, v in list(self.dict.items())) def allitems(self): - return ((k, v) for k, vl in self.dict.items() for v in vl) + return ((k, v) for k, vl in list(self.dict.items()) for v in vl) iterkeys = keys itervalues = values @@ -1938,25 +1938,25 @@ def allitems(self): else: def values(self): - return [v[-1] for v in self.dict.values()] + return [v[-1] for v in list(self.dict.values())] def items(self): - return [(k, v[-1]) for k, v in self.dict.items()] + return [(k, v[-1]) for k, v in list(self.dict.items())] def iterkeys(self): - return self.dict.iterkeys() + return iter(list(self.dict.keys())) def itervalues(self): - return (v[-1] for v in self.dict.itervalues()) + return (v[-1] for v in list(self.dict.values())) def iteritems(self): - return ((k, v[-1]) for k, v in self.dict.iteritems()) + return ((k, v[-1]) for k, v in list(self.dict.items())) def iterallitems(self): - return ((k, v) for k, vl in self.dict.iteritems() for v in vl) + return ((k, v) for k, vl in list(self.dict.items()) for v in vl) def allitems(self): - return [(k, v) for k, vl in self.dict.iteritems() for v in vl] + return [(k, v) for k, vl in list(self.dict.items()) for v in vl] def get(self, key, default=None, index=-1, type=None): """ Return the most recent value for a key. @@ -2007,7 +2007,7 @@ class FormsDict(MultiDict): recode_unicode = True def _fix(self, s, encoding=None): - if isinstance(s, unicode) and self.recode_unicode: # Python 3 WSGI + if isinstance(s, str) and self.recode_unicode: # Python 3 WSGI return s.encode('latin1').decode(encoding or self.input_encoding) elif isinstance(s, bytes): # Python 2 WSGI return s.decode(encoding or self.input_encoding) @@ -2032,7 +2032,7 @@ def getunicode(self, name, default=None, encoding=None): except (UnicodeError, KeyError): return default - def __getattr__(self, name, default=unicode()): + def __getattr__(self, name, default=str()): # Without this guard, pickle generates a cryptic TypeError: if name.startswith('__') and name.endswith('__'): return super(FormsDict, self).__getattr__(name) @@ -2057,15 +2057,15 @@ def __getitem__(self, key): return self.dict[_hkey(key)][-1] def __setitem__(self, key, value): - self.dict[_hkey(key)] = [value if isinstance(value, unicode) else + self.dict[_hkey(key)] = [value if isinstance(value, str) else str(value)] def append(self, key, value): self.dict.setdefault(_hkey(key), []).append( - value if isinstance(value, unicode) else str(value)) + value if isinstance(value, str) else str(value)) def replace(self, key, value): - self.dict[_hkey(key)] = [value if isinstance(value, unicode) else + self.dict[_hkey(key)] = [value if isinstance(value, str) else str(value)] def getall(self, key): @@ -2111,7 +2111,7 @@ def raw(self, key, default=None): def __getitem__(self, key): val = self.environ[self._ekey(key)] if py3k: - if isinstance(val, unicode): + if isinstance(val, str): val = val.encode('latin1').decode('utf8') else: val = val.decode('utf8') @@ -2134,7 +2134,7 @@ def keys(self): return [x for x in self] def __len__(self): - return len(self.keys()) + return len(list(self.keys())) def __contains__(self, key): return self._ekey(key) in self.environ @@ -2175,7 +2175,7 @@ def load_dict(self, source, namespace=''): >>> c.load_dict({'some': {'namespace': {'key': 'value'} } }) {'some.namespace.key': 'value'} """ - for key, value in source.items(): + for key, value in list(source.items()): if isinstance(key, str): nskey = (namespace + '.' + key).strip('.') if isinstance(value, dict): @@ -2194,7 +2194,7 @@ def update(self, *a, **ka): if a and isinstance(a[0], str): prefix = a[0].strip('.') + '.' a = a[1:] - for key, value in dict(*a, **ka).items(): + for key, value in list(dict(*a, **ka).items()): self[prefix + key] = value def setdefault(self, key, value): @@ -2228,7 +2228,7 @@ def meta_set(self, key, metafield, value): def meta_list(self, key): """ Return an iterable of meta field names defined for a key. """ - return self._meta.get(key, {}).keys() + return list(self._meta.get(key, {}).keys()) class AppStack(list): @@ -2388,7 +2388,7 @@ def filename(self): or dashes are removed. The filename is limited to 255 characters. """ fname = self.raw_filename - if not isinstance(fname, unicode): + if not isinstance(fname, str): fname = fname.decode('utf8', 'ignore') fname = normalize('NFKD', fname) fname = fname.encode('ASCII', 'ignore').decode('ASCII') @@ -2414,7 +2414,7 @@ def save(self, destination, overwrite=False, chunk_size=2 ** 16): :param overwrite: If True, replace existing files. (default: False) :param chunk_size: Bytes to read at a time. (default: 64kb) """ - if isinstance(destination, basestring): # Except file-likes here + if isinstance(destination, str): # Except file-likes here if os.path.isdir(destination): destination = os.path.join(destination, self.filename) if not overwrite and os.path.exists(destination): @@ -2552,7 +2552,7 @@ def http_date(value): value = value.utctimetuple() elif isinstance(value, (int, float)): value = time.gmtime(value) - if not isinstance(value, basestring): + if not isinstance(value, str): value = time.strftime("%a, %d %b %Y %H:%M:%S GMT", value) return value @@ -2764,7 +2764,7 @@ def run(self, handler): # pragma: no cover def __repr__(self): args = ', '.join(['%s=%s' % (k, repr(v)) - for k, v in self.options.items()]) + for k, v in list(self.options.items())]) return "%s(%s)" % (self.__class__.__name__, args) @@ -2823,7 +2823,7 @@ class server_cls(server_cls): class CherryPyServer(ServerAdapter): def run(self, handler): # pragma: no cover - from cherrypy import wsgiserver + from .cherrypy import wsgiserver self.options['bind_addr'] = (self.host, self.port) self.options['wsgi_app'] = handler @@ -3140,7 +3140,7 @@ def load_app(target): tmp = default_app.push() # Create a new "default application" try: rv = load(target) # Import the target module - return rv if callable(rv) else tmp + return rv if isinstance(rv, collections.Callable) else tmp finally: default_app.remove(tmp) # Remove the temporary added default application NORUN = nr_old @@ -3203,19 +3203,19 @@ def run(app=None, try: if debug is not None: _debug(debug) app = app or default_app() - if isinstance(app, basestring): + if isinstance(app, str): app = load_app(app) - if not callable(app): + if not isinstance(app, collections.Callable): raise ValueError("Application is not callable: %r" % app) for plugin in plugins or []: - if isinstance(plugin, basestring): + if isinstance(plugin, str): plugin = load(plugin) app.install(plugin) if server in server_names: server = server_names.get(server) - if isinstance(server, basestring): + if isinstance(server, str): server = load(server) if isinstance(server, type): server = server(host=host, port=port, **kargs) @@ -3276,11 +3276,11 @@ def run(self): if not exists(self.lockfile)\ or mtime(self.lockfile) < time.time() - self.interval - 5: self.status = 'error' - thread.interrupt_main() + _thread.interrupt_main() for path, lmtime in list(files.items()): if not exists(path) or mtime(path) > lmtime: self.status = 'reload' - thread.interrupt_main() + _thread.interrupt_main() break time.sleep(self.interval) @@ -3605,8 +3605,8 @@ def set_syntax(self, syntax): self._tokens = syntax.split() if not syntax in self._re_cache: names = 'block_start block_close line_start inline_start inline_end' - etokens = map(re.escape, self._tokens) - pattern_vars = dict(zip(names.split(), etokens)) + etokens = list(map(re.escape, self._tokens)) + pattern_vars = dict(list(zip(names.split(), etokens))) patterns = (self._re_split, self._re_tok, self._re_inl) patterns = [re.compile(p % pattern_vars) for p in patterns] self._re_cache[syntax] = patterns @@ -3795,14 +3795,14 @@ def wrapper(*args, **kwargs): NORUN = False # If set, run() does nothing. Used by load_app() #: A dict to map HTTP status codes (e.g. 404) to phrases (e.g. 'Not Found') -HTTP_CODES = httplib.responses +HTTP_CODES = http.client.responses HTTP_CODES[418] = "I'm a teapot" # RFC 2324 HTTP_CODES[428] = "Precondition Required" HTTP_CODES[429] = "Too Many Requests" HTTP_CODES[431] = "Request Header Fields Too Large" HTTP_CODES[511] = "Network Authentication Required" _HTTP_STATUS_LINES = dict((k, '%d %s' % (k, v)) - for (k, v) in HTTP_CODES.items()) + for (k, v) in list(HTTP_CODES.items())) #: The default template used for error pages. Override with @error() ERROR_PAGE_TEMPLATE = """ diff --git a/libs/cherrypy/__init__.py b/libs/cherrypy/__init__.py index c8c7914..08aa945 100644 --- a/libs/cherrypy/__init__.py +++ b/libs/cherrypy/__init__.py @@ -59,7 +59,7 @@ __version__ = "3.7.0" from cherrypy._cpcompat import urljoin as _urljoin, urlencode as _urlencode -from cherrypy._cpcompat import basestring, unicodestr, set +from cherrypy._cpcompat import str, unicodestr, set from cherrypy._cperror import HTTPError, HTTPRedirect, InternalRedirect from cherrypy._cperror import NotFound, CherryPyException, TimeoutError @@ -261,7 +261,7 @@ def __len__(self): child = getattr(serving, self.__attrname__) return len(child) - def __nonzero__(self): + def __bool__(self): child = getattr(serving, self.__attrname__) return bool(child) # Python 3 @@ -354,7 +354,7 @@ def expose(func=None, alias=None): def expose_(func): func.exposed = True if alias is not None: - if isinstance(alias, basestring): + if isinstance(alias, str): parents[alias.replace(".", "_")] = func else: for a in alias: @@ -474,7 +474,7 @@ def index(self): handler = None handler_call = False - for k, v in kwargs.items(): + for k, v in list(kwargs.items()): if k == 'handler': handler = v else: diff --git a/libs/cherrypy/_cpchecker.py b/libs/cherrypy/_cpchecker.py index 4ef8259..ef3d468 100644 --- a/libs/cherrypy/_cpchecker.py +++ b/libs/cherrypy/_cpchecker.py @@ -50,7 +50,7 @@ def formatwarning(self, message, category, filename, lineno, line=None): def check_app_config_entries_dont_start_with_script_name(self): """Check for Application config with sections that repeat script_name. """ - for sn, app in cherrypy.tree.apps.items(): + for sn, app in list(cherrypy.tree.apps.items()): if not isinstance(app, cherrypy.Application): continue if not app.config: @@ -58,7 +58,7 @@ def check_app_config_entries_dont_start_with_script_name(self): if sn == '': continue sn_atoms = sn.strip("/").split("/") - for key in app.config.keys(): + for key in list(app.config.keys()): key_atoms = key.strip("/").split("/") if key_atoms[:len(sn_atoms)] == sn_atoms: warnings.warn( @@ -91,7 +91,7 @@ def check_site_config_entries_in_app_config(self): def check_skipped_app_config(self): """Check for mounted Applications that have no config.""" - for sn, app in cherrypy.tree.apps.items(): + for sn, app in list(cherrypy.tree.apps.items()): if not isinstance(app, cherrypy.Application): continue if not app.config: @@ -109,12 +109,12 @@ def check_app_config_brackets(self): """Check for Application config with extraneous brackets in section names. """ - for sn, app in cherrypy.tree.apps.items(): + for sn, app in list(cherrypy.tree.apps.items()): if not isinstance(app, cherrypy.Application): continue if not app.config: continue - for key in app.config.keys(): + for key in list(app.config.keys()): if key.startswith("[") or key.endswith("]"): warnings.warn( "The application mounted at %r has config " @@ -126,7 +126,7 @@ def check_static_paths(self): """Check Application config for incorrect static paths.""" # Use the dummy Request object in the main thread. request = cherrypy.request - for sn, app in cherrypy.tree.apps.items(): + for sn, app in list(cherrypy.tree.apps.items()): if not isinstance(app, cherrypy.Application): continue request.app = app @@ -194,9 +194,9 @@ def check_static_paths(self): def _compat(self, config): """Process config and warn on each obsolete or deprecated entry.""" - for section, conf in config.items(): + for section, conf in list(config.items()): if isinstance(conf, dict): - for k, v in conf.items(): + for k, v in list(conf.items()): if k in self.obsolete: warnings.warn("%r is obsolete. Use %r instead.\n" "section: [%s]" % @@ -216,7 +216,7 @@ def _compat(self, config): def check_compatibility(self): """Process config and warn on each obsolete or deprecated entry.""" self._compat(cherrypy.config) - for sn, app in cherrypy.tree.apps.items(): + for sn, app in list(cherrypy.tree.apps.items()): if not isinstance(app, cherrypy.Application): continue self._compat(app.config) @@ -232,10 +232,10 @@ def _known_ns(self, app): ns.extend(copykeys(cherrypy.config.namespaces)) ns += self.extra_config_namespaces - for section, conf in app.config.items(): + for section, conf in list(app.config.items()): is_path_section = section.startswith("/") if is_path_section and isinstance(conf, dict): - for k, v in conf.items(): + for k, v in list(conf.items()): atoms = k.split(".") if len(atoms) > 1: if atoms[0] not in ns: @@ -263,7 +263,7 @@ def _known_ns(self, app): def check_config_namespaces(self): """Process config and warn on each unknown config namespace.""" - for sn, app in cherrypy.tree.apps.items(): + for sn, app in list(cherrypy.tree.apps.items()): if not isinstance(app, cherrypy.Application): continue self._known_ns(app) @@ -272,7 +272,7 @@ def check_config_namespaces(self): known_config_types = {} def _populate_known_types(self): - b = [x for x in vars(builtins).values() + b = [x for x in list(vars(builtins).values()) if type(x) is type(str)] def traverse(obj, namespace): @@ -294,9 +294,9 @@ def _known_types(self, config): msg = ("The config entry %r in section %r is of type %r, " "which does not match the expected type %r.") - for section, conf in config.items(): + for section, conf in list(config.items()): if isinstance(conf, dict): - for k, v in conf.items(): + for k, v in list(conf.items()): if v is not None: expected_type = self.known_config_types.get(k, None) vtype = type(v) @@ -315,7 +315,7 @@ def _known_types(self, config): def check_config_types(self): """Assert that config values are of the same type as default values.""" self._known_types(cherrypy.config) - for sn, app in cherrypy.tree.apps.items(): + for sn, app in list(cherrypy.tree.apps.items()): if not isinstance(app, cherrypy.Application): continue self._known_types(app.config) @@ -323,7 +323,7 @@ def check_config_types(self): # -------------------- Specific config warnings -------------------- # def check_localhost(self): """Warn if any socket_host is 'localhost'. See #711.""" - for k, v in cherrypy.config.items(): + for k, v in list(cherrypy.config.items()): if k == 'server.socket_host' and v == 'localhost': warnings.warn("The use of 'localhost' as a socket host can " "cause problems on newer systems, since " diff --git a/libs/cherrypy/_cpcompat.py b/libs/cherrypy/_cpcompat.py index 8a98b38..38dba5f 100644 --- a/libs/cherrypy/_cpcompat.py +++ b/libs/cherrypy/_cpcompat.py @@ -25,7 +25,7 @@ bytestr = bytes unicodestr = str nativestr = unicodestr - basestring = (bytes, str) + str = (bytes, str) def ntob(n, encoding='ISO-8859-1'): """Return the given native string as a byte string in the given @@ -57,9 +57,9 @@ def tonative(n, encoding='ISO-8859-1'): # Python 2 py3k = False bytestr = str - unicodestr = unicode + unicodestr = str nativestr = bytestr - basestring = basestring + str = str def ntob(n, encoding='ISO-8859-1'): """Return the given native string as a byte string in the given @@ -82,9 +82,9 @@ def ntou(n, encoding='ISO-8859-1'): # escapes, but without having to prefix it with u'' for Python 2, # but no prefix for Python 3. if encoding == 'escape': - return unicode( + return str( re.sub(r'\\u([0-9a-zA-Z]{4})', - lambda m: unichr(int(m.group(1), 16)), + lambda m: chr(int(m.group(1), 16)), n.decode('ISO-8859-1'))) # Assume it's already in the given encoding, which for ISO-8859-1 # is almost always what was intended. @@ -93,15 +93,15 @@ def ntou(n, encoding='ISO-8859-1'): def tonative(n, encoding='ISO-8859-1'): """Return the given string as a native string in the given encoding.""" # In Python 2, the native string type is bytes. - if isinstance(n, unicode): + if isinstance(n, str): return n.encode(encoding) return n try: # type("") - from cStringIO import StringIO + from io import StringIO except ImportError: # type("") - from StringIO import StringIO + from io import StringIO # bytes: BytesIO = StringIO @@ -174,10 +174,11 @@ def reversed(x): from urllib.request import parse_http_list, parse_keqv_list except ImportError: # Python 2 - from urlparse import urljoin - from urllib import urlencode, urlopen - from urllib import quote, quote_plus - from urllib import unquote + from urllib.parse import urljoin + from urllib.parse import urlencode + from urllib.request import urlopen + from urllib.parse import quote, quote_plus + from urllib.parse import unquote from urllib2 import parse_http_list, parse_keqv_list try: @@ -188,31 +189,31 @@ def reversed(x): try: dict.iteritems # Python 2 - iteritems = lambda d: d.iteritems() - copyitems = lambda d: d.items() + iteritems = lambda d: iter(list(d.items())) + copyitems = lambda d: list(d.items()) except AttributeError: # Python 3 - iteritems = lambda d: d.items() + iteritems = lambda d: list(d.items()) copyitems = lambda d: list(d.items()) try: dict.iterkeys # Python 2 - iterkeys = lambda d: d.iterkeys() - copykeys = lambda d: d.keys() + iterkeys = lambda d: iter(list(d.keys())) + copykeys = lambda d: list(d.keys()) except AttributeError: # Python 3 - iterkeys = lambda d: d.keys() + iterkeys = lambda d: list(d.keys()) copykeys = lambda d: list(d.keys()) try: dict.itervalues # Python 2 - itervalues = lambda d: d.itervalues() - copyvalues = lambda d: d.values() + itervalues = lambda d: iter(list(d.values())) + copyvalues = lambda d: list(d.values()) except AttributeError: # Python 3 - itervalues = lambda d: d.values() + itervalues = lambda d: list(d.values()) copyvalues = lambda d: list(d.values()) try: @@ -220,15 +221,15 @@ def reversed(x): import builtins except ImportError: # Python 2 - import __builtin__ as builtins + import builtins as builtins try: # Python 2. We try Python 2 first clients on Python 2 # don't try to import the 'http' module from cherrypy.lib - from Cookie import SimpleCookie, CookieError - from httplib import BadStatusLine, HTTPConnection, IncompleteRead - from httplib import NotConnected - from BaseHTTPServer import BaseHTTPRequestHandler + from http.cookies import SimpleCookie, CookieError + from http.client import BadStatusLine, HTTPConnection, IncompleteRead + from http.client import NotConnected + from http.server import BaseHTTPRequestHandler except ImportError: # Python 3 from http.cookies import SimpleCookie, CookieError @@ -245,7 +246,7 @@ def reversed(x): HTTPSConnection = None else: try: - from httplib import HTTPSConnection + from http.client import HTTPSConnection except ImportError: HTTPSConnection = None @@ -290,7 +291,7 @@ def unquote_qs(atom, encoding, errors='strict'): errors=errors) except ImportError: # Python 2 - from urllib import unquote as parse_unquote + from urllib.parse import unquote as parse_unquote def unquote_qs(atom, encoding, errors='strict'): return parse_unquote(atom.replace('+', ' ')).decode(encoding, errors) @@ -327,7 +328,7 @@ def json_encode(value): try: - import cPickle as pickle + import pickle as pickle except ImportError: # In Python 2, pickle is a Python version. # In Python 3, pickle is the sped-up C version. @@ -349,7 +350,7 @@ def random20(): try: from _thread import get_ident as get_thread_ident except ImportError: - from thread import get_ident as get_thread_ident + from _thread import get_ident as get_thread_ident try: # Python 3 @@ -357,7 +358,7 @@ def random20(): except NameError: # Python 2 def next(i): - return i.next() + return i.__next__() if sys.version_info >= (3, 3): Timer = threading.Timer diff --git a/libs/cherrypy/_cpcompat_subprocess.py b/libs/cherrypy/_cpcompat_subprocess.py index ce36372..28d08b6 100644 --- a/libs/cherrypy/_cpcompat_subprocess.py +++ b/libs/cherrypy/_cpcompat_subprocess.py @@ -1,1544 +1,1544 @@ -# subprocess - Subprocesses with accessible I/O streams -# -# For more information about this module, see PEP 324. -# -# This module should remain compatible with Python 2.2, see PEP 291. -# -# Copyright (c) 2003-2005 by Peter Astrand -# -# Licensed to PSF under a Contributor Agreement. -# See http://www.python.org/2.4/license for licensing details. - -r"""subprocess - Subprocesses with accessible I/O streams - -This module allows you to spawn processes, connect to their -input/output/error pipes, and obtain their return codes. This module -intends to replace several other, older modules and functions, like: - -os.system -os.spawn* -os.popen* -popen2.* -commands.* - -Information about how the subprocess module can be used to replace these -modules and functions can be found below. - - - -Using the subprocess module -=========================== -This module defines one class called Popen: - -class Popen(args, bufsize=0, executable=None, - stdin=None, stdout=None, stderr=None, - preexec_fn=None, close_fds=False, shell=False, - cwd=None, env=None, universal_newlines=False, - startupinfo=None, creationflags=0): - - -Arguments are: - -args should be a string, or a sequence of program arguments. The -program to execute is normally the first item in the args sequence or -string, but can be explicitly set by using the executable argument. - -On UNIX, with shell=False (default): In this case, the Popen class -uses os.execvp() to execute the child program. args should normally -be a sequence. A string will be treated as a sequence with the string -as the only item (the program to execute). - -On UNIX, with shell=True: If args is a string, it specifies the -command string to execute through the shell. If args is a sequence, -the first item specifies the command string, and any additional items -will be treated as additional shell arguments. - -On Windows: the Popen class uses CreateProcess() to execute the child -program, which operates on strings. If args is a sequence, it will be -converted to a string using the list2cmdline method. Please note that -not all MS Windows applications interpret the command line the same -way: The list2cmdline is designed for applications using the same -rules as the MS C runtime. - -bufsize, if given, has the same meaning as the corresponding argument -to the built-in open() function: 0 means unbuffered, 1 means line -buffered, any other positive value means use a buffer of -(approximately) that size. A negative bufsize means to use the system -default, which usually means fully buffered. The default value for -bufsize is 0 (unbuffered). - -stdin, stdout and stderr specify the executed programs' standard -input, standard output and standard error file handles, respectively. -Valid values are PIPE, an existing file descriptor (a positive -integer), an existing file object, and None. PIPE indicates that a -new pipe to the child should be created. With None, no redirection -will occur; the child's file handles will be inherited from the -parent. Additionally, stderr can be STDOUT, which indicates that the -stderr data from the applications should be captured into the same -file handle as for stdout. - -If preexec_fn is set to a callable object, this object will be called -in the child process just before the child is executed. - -If close_fds is true, all file descriptors except 0, 1 and 2 will be -closed before the child process is executed. - -if shell is true, the specified command will be executed through the -shell. - -If cwd is not None, the current directory will be changed to cwd -before the child is executed. - -If env is not None, it defines the environment variables for the new -process. - -If universal_newlines is true, the file objects stdout and stderr are -opened as a text files, but lines may be terminated by any of '\n', -the Unix end-of-line convention, '\r', the Macintosh convention or -'\r\n', the Windows convention. All of these external representations -are seen as '\n' by the Python program. Note: This feature is only -available if Python is built with universal newline support (the -default). Also, the newlines attribute of the file objects stdout, -stdin and stderr are not updated by the communicate() method. - -The startupinfo and creationflags, if given, will be passed to the -underlying CreateProcess() function. They can specify things such as -appearance of the main window and priority for the new process. -(Windows only) - - -This module also defines some shortcut functions: - -call(*popenargs, **kwargs): - Run command with arguments. Wait for command to complete, then - return the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - retcode = call(["ls", "-l"]) - -check_call(*popenargs, **kwargs): - Run command with arguments. Wait for command to complete. If the - exit code was zero then return, otherwise raise - CalledProcessError. The CalledProcessError object will have the - return code in the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - check_call(["ls", "-l"]) - -check_output(*popenargs, **kwargs): - Run command with arguments and return its output as a byte string. - - If the exit code was non-zero it raises a CalledProcessError. The - CalledProcessError object will have the return code in the returncode - attribute and output in the output attribute. - - The arguments are the same as for the Popen constructor. Example: - - output = check_output(["ls", "-l", "/dev/null"]) - - -Exceptions ----------- -Exceptions raised in the child process, before the new program has -started to execute, will be re-raised in the parent. Additionally, -the exception object will have one extra attribute called -'child_traceback', which is a string containing traceback information -from the childs point of view. - -The most common exception raised is OSError. This occurs, for -example, when trying to execute a non-existent file. Applications -should prepare for OSErrors. - -A ValueError will be raised if Popen is called with invalid arguments. - -check_call() and check_output() will raise CalledProcessError, if the -called process returns a non-zero return code. - - -Security --------- -Unlike some other popen functions, this implementation will never call -/bin/sh implicitly. This means that all characters, including shell -metacharacters, can safely be passed to child processes. - - -Popen objects -============= -Instances of the Popen class have the following methods: - -poll() - Check if child process has terminated. Returns returncode - attribute. - -wait() - Wait for child process to terminate. Returns returncode attribute. - -communicate(input=None) - Interact with process: Send data to stdin. Read data from stdout - and stderr, until end-of-file is reached. Wait for process to - terminate. The optional input argument should be a string to be - sent to the child process, or None, if no data should be sent to - the child. - - communicate() returns a tuple (stdout, stderr). - - Note: The data read is buffered in memory, so do not use this - method if the data size is large or unlimited. - -The following attributes are also available: - -stdin - If the stdin argument is PIPE, this attribute is a file object - that provides input to the child process. Otherwise, it is None. - -stdout - If the stdout argument is PIPE, this attribute is a file object - that provides output from the child process. Otherwise, it is - None. - -stderr - If the stderr argument is PIPE, this attribute is file object that - provides error output from the child process. Otherwise, it is - None. - -pid - The process ID of the child process. - -returncode - The child return code. A None value indicates that the process - hasn't terminated yet. A negative value -N indicates that the - child was terminated by signal N (UNIX only). - - -Replacing older functions with the subprocess module -==================================================== -In this section, "a ==> b" means that b can be used as a replacement -for a. - -Note: All functions in this section fail (more or less) silently if -the executed program cannot be found; this module raises an OSError -exception. - -In the following examples, we assume that the subprocess module is -imported with "from subprocess import *". - - -Replacing /bin/sh shell backquote ---------------------------------- -output=`mycmd myarg` -==> -output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0] - - -Replacing shell pipe line -------------------------- -output=`dmesg | grep hda` -==> -p1 = Popen(["dmesg"], stdout=PIPE) -p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) -output = p2.communicate()[0] - - -Replacing os.system() ---------------------- -sts = os.system("mycmd" + " myarg") -==> -p = Popen("mycmd" + " myarg", shell=True) -pid, sts = os.waitpid(p.pid, 0) - -Note: - -* Calling the program through the shell is usually not required. - -* It's easier to look at the returncode attribute than the - exitstatus. - -A more real-world example would look like this: - -try: - retcode = call("mycmd" + " myarg", shell=True) - if retcode < 0: - print >>sys.stderr, "Child was terminated by signal", -retcode - else: - print >>sys.stderr, "Child returned", retcode -except OSError, e: - print >>sys.stderr, "Execution failed:", e - - -Replacing os.spawn* -------------------- -P_NOWAIT example: - -pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") -==> -pid = Popen(["/bin/mycmd", "myarg"]).pid - - -P_WAIT example: - -retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") -==> -retcode = call(["/bin/mycmd", "myarg"]) - - -Vector example: - -os.spawnvp(os.P_NOWAIT, path, args) -==> -Popen([path] + args[1:]) - - -Environment example: - -os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env) -==> -Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) - - -Replacing os.popen* -------------------- -pipe = os.popen("cmd", mode='r', bufsize) -==> -pipe = Popen("cmd", shell=True, bufsize=bufsize, stdout=PIPE).stdout - -pipe = os.popen("cmd", mode='w', bufsize) -==> -pipe = Popen("cmd", shell=True, bufsize=bufsize, stdin=PIPE).stdin - - -(child_stdin, child_stdout) = os.popen2("cmd", mode, bufsize) -==> -p = Popen("cmd", shell=True, bufsize=bufsize, - stdin=PIPE, stdout=PIPE, close_fds=True) -(child_stdin, child_stdout) = (p.stdin, p.stdout) - - -(child_stdin, - child_stdout, - child_stderr) = os.popen3("cmd", mode, bufsize) -==> -p = Popen("cmd", shell=True, bufsize=bufsize, - stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) -(child_stdin, - child_stdout, - child_stderr) = (p.stdin, p.stdout, p.stderr) - - -(child_stdin, child_stdout_and_stderr) = os.popen4("cmd", mode, - bufsize) -==> -p = Popen("cmd", shell=True, bufsize=bufsize, - stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) -(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) - -On Unix, os.popen2, os.popen3 and os.popen4 also accept a sequence as -the command to execute, in which case arguments will be passed -directly to the program without shell intervention. This usage can be -replaced as follows: - -(child_stdin, child_stdout) = os.popen2(["/bin/ls", "-l"], mode, - bufsize) -==> -p = Popen(["/bin/ls", "-l"], bufsize=bufsize, stdin=PIPE, stdout=PIPE) -(child_stdin, child_stdout) = (p.stdin, p.stdout) - -Return code handling translates as follows: - -pipe = os.popen("cmd", 'w') -... -rc = pipe.close() -if rc is not None and rc % 256: - print "There were some errors" -==> -process = Popen("cmd", 'w', shell=True, stdin=PIPE) -... -process.stdin.close() -if process.wait() != 0: - print "There were some errors" - - -Replacing popen2.* ------------------- -(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode) -==> -p = Popen(["somestring"], shell=True, bufsize=bufsize - stdin=PIPE, stdout=PIPE, close_fds=True) -(child_stdout, child_stdin) = (p.stdout, p.stdin) - -On Unix, popen2 also accepts a sequence as the command to execute, in -which case arguments will be passed directly to the program without -shell intervention. This usage can be replaced as follows: - -(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, - mode) -==> -p = Popen(["mycmd", "myarg"], bufsize=bufsize, - stdin=PIPE, stdout=PIPE, close_fds=True) -(child_stdout, child_stdin) = (p.stdout, p.stdin) - -The popen2.Popen3 and popen2.Popen4 basically works as subprocess.Popen, -except that: - -* subprocess.Popen raises an exception if the execution fails -* the capturestderr argument is replaced with the stderr argument. -* stdin=PIPE and stdout=PIPE must be specified. -* popen2 closes all filedescriptors by default, but you have to specify - close_fds=True with subprocess.Popen. -""" - -import sys -mswindows = (sys.platform == "win32") - -import os -import types -import traceback -import gc -import signal -import errno - -try: - set -except NameError: - from sets import Set as set - -# Exception classes used by this module. - - -class CalledProcessError(Exception): - - """This exception is raised when a process run by check_call() or - check_output() returns a non-zero exit status. - The exit status will be stored in the returncode attribute; - check_output() will also store the output in the output attribute. - """ - - def __init__(self, returncode, cmd, output=None): - self.returncode = returncode - self.cmd = cmd - self.output = output - - def __str__(self): - return "Command '%s' returned non-zero exit status %d" % ( - self.cmd, self.returncode) - - -if mswindows: - import threading - import msvcrt - import _subprocess - - class STARTUPINFO: - dwFlags = 0 - hStdInput = None - hStdOutput = None - hStdError = None - wShowWindow = 0 - - class pywintypes: - error = IOError -else: - import select - _has_poll = hasattr(select, 'poll') - import fcntl - import pickle - - # When select or poll has indicated that the file is writable, - # we can write up to _PIPE_BUF bytes without risk of blocking. - # POSIX defines PIPE_BUF as >= 512. - _PIPE_BUF = getattr(select, 'PIPE_BUF', 512) - - -__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", - "check_output", "CalledProcessError"] - -if mswindows: - from _subprocess import CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP, \ - STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, \ - STD_ERROR_HANDLE, SW_HIDE, \ - STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW - - __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP", - "STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE", - "STD_ERROR_HANDLE", "SW_HIDE", - "STARTF_USESTDHANDLES", "STARTF_USESHOWWINDOW"]) -try: - MAXFD = os.sysconf("SC_OPEN_MAX") -except: - MAXFD = 256 - -_active = [] - - -def _cleanup(): - for inst in _active[:]: - res = inst._internal_poll(_deadstate=sys.maxint) - if res is not None: - try: - _active.remove(inst) - except ValueError: - # This can happen if two threads create a new Popen instance. - # It's harmless that it was already removed, so ignore. - pass - -PIPE = -1 -STDOUT = -2 - - -def _eintr_retry_call(func, *args): - while True: - try: - return func(*args) - except (OSError, IOError), e: - if e.errno == errno.EINTR: - continue - raise - - -def call(*popenargs, **kwargs): - """Run command with arguments. Wait for command to complete, then - return the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - retcode = call(["ls", "-l"]) - """ - return Popen(*popenargs, **kwargs).wait() - - -def check_call(*popenargs, **kwargs): - """Run command with arguments. Wait for command to complete. If - the exit code was zero then return, otherwise raise - CalledProcessError. The CalledProcessError object will have the - return code in the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - check_call(["ls", "-l"]) - """ - retcode = call(*popenargs, **kwargs) - if retcode: - cmd = kwargs.get("args") - if cmd is None: - cmd = popenargs[0] - raise CalledProcessError(retcode, cmd) - return 0 - - -def check_output(*popenargs, **kwargs): - r"""Run command with arguments and return its output as a byte string. - - If the exit code was non-zero it raises a CalledProcessError. The - CalledProcessError object will have the return code in the returncode - attribute and output in the output attribute. - - The arguments are the same as for the Popen constructor. Example: - - >>> check_output(["ls", "-l", "/dev/null"]) - 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n' - - The stdout argument is not allowed as it is used internally. - To capture standard error in the result, use stderr=STDOUT. - - >>> check_output(["/bin/sh", "-c", - ... "ls -l non_existent_file ; exit 0"], - ... stderr=STDOUT) - 'ls: non_existent_file: No such file or directory\n' - """ - if 'stdout' in kwargs: - raise ValueError('stdout argument not allowed, it will be overridden.') - process = Popen(stdout=PIPE, *popenargs, **kwargs) - output, unused_err = process.communicate() - retcode = process.poll() - if retcode: - cmd = kwargs.get("args") - if cmd is None: - cmd = popenargs[0] - raise CalledProcessError(retcode, cmd, output=output) - return output - - -def list2cmdline(seq): - """ - Translate a sequence of arguments into a command line - string, using the same rules as the MS C runtime: - - 1) Arguments are delimited by white space, which is either a - space or a tab. - - 2) A string surrounded by double quotation marks is - interpreted as a single argument, regardless of white space - contained within. A quoted string can be embedded in an - argument. - - 3) A double quotation mark preceded by a backslash is - interpreted as a literal double quotation mark. - - 4) Backslashes are interpreted literally, unless they - immediately precede a double quotation mark. - - 5) If backslashes immediately precede a double quotation mark, - every pair of backslashes is interpreted as a literal - backslash. If the number of backslashes is odd, the last - backslash escapes the next double quotation mark as - described in rule 3. - """ - - # See - # http://msdn.microsoft.com/en-us/library/17w5ykft.aspx - # or search http://msdn.microsoft.com for - # "Parsing C++ Command-Line Arguments" - result = [] - needquote = False - for arg in seq: - bs_buf = [] - - # Add a space to separate this argument from the others - if result: - result.append(' ') - - needquote = (" " in arg) or ("\t" in arg) or not arg - if needquote: - result.append('"') - - for c in arg: - if c == '\\': - # Don't know if we need to double yet. - bs_buf.append(c) - elif c == '"': - # Double backslashes. - result.append('\\' * len(bs_buf) * 2) - bs_buf = [] - result.append('\\"') - else: - # Normal char - if bs_buf: - result.extend(bs_buf) - bs_buf = [] - result.append(c) - - # Add remaining backslashes, if any. - if bs_buf: - result.extend(bs_buf) - - if needquote: - result.extend(bs_buf) - result.append('"') - - return ''.join(result) - - -class Popen(object): - - def __init__(self, args, bufsize=0, executable=None, - stdin=None, stdout=None, stderr=None, - preexec_fn=None, close_fds=False, shell=False, - cwd=None, env=None, universal_newlines=False, - startupinfo=None, creationflags=0): - """Create new Popen instance.""" - _cleanup() - - self._child_created = False - if not isinstance(bufsize, (int, long)): - raise TypeError("bufsize must be an integer") - - if mswindows: - if preexec_fn is not None: - raise ValueError("preexec_fn is not supported on Windows " - "platforms") - if close_fds and (stdin is not None or stdout is not None or - stderr is not None): - raise ValueError("close_fds is not supported on Windows " - "platforms if you redirect " - "stdin/stdout/stderr") - else: - # POSIX - if startupinfo is not None: - raise ValueError("startupinfo is only supported on Windows " - "platforms") - if creationflags != 0: - raise ValueError("creationflags is only supported on Windows " - "platforms") - - self.stdin = None - self.stdout = None - self.stderr = None - self.pid = None - self.returncode = None - self.universal_newlines = universal_newlines - - # Input and output objects. The general principle is like - # this: - # - # Parent Child - # ------ ----- - # p2cwrite ---stdin---> p2cread - # c2pread <--stdout--- c2pwrite - # errread <--stderr--- errwrite - # - # On POSIX, the child objects are file descriptors. On - # Windows, these are Windows file handles. The parent objects - # are file descriptors on both platforms. The parent objects - # are None when not using PIPEs. The child objects are None - # when not redirecting. - - (p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite) = self._get_handles(stdin, stdout, stderr) - - self._execute_child(args, executable, preexec_fn, close_fds, - cwd, env, universal_newlines, - startupinfo, creationflags, shell, - p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite) - - if mswindows: - if p2cwrite is not None: - p2cwrite = msvcrt.open_osfhandle(p2cwrite.Detach(), 0) - if c2pread is not None: - c2pread = msvcrt.open_osfhandle(c2pread.Detach(), 0) - if errread is not None: - errread = msvcrt.open_osfhandle(errread.Detach(), 0) - - if p2cwrite is not None: - self.stdin = os.fdopen(p2cwrite, 'wb', bufsize) - if c2pread is not None: - if universal_newlines: - self.stdout = os.fdopen(c2pread, 'rU', bufsize) - else: - self.stdout = os.fdopen(c2pread, 'rb', bufsize) - if errread is not None: - if universal_newlines: - self.stderr = os.fdopen(errread, 'rU', bufsize) - else: - self.stderr = os.fdopen(errread, 'rb', bufsize) - - def _translate_newlines(self, data): - data = data.replace("\r\n", "\n") - data = data.replace("\r", "\n") - return data - - def __del__(self, _maxint=sys.maxint, _active=_active): - # If __init__ hasn't had a chance to execute (e.g. if it - # was passed an undeclared keyword argument), we don't - # have a _child_created attribute at all. - if not getattr(self, '_child_created', False): - # We didn't get to successfully create a child process. - return - # In case the child hasn't been waited on, check if it's done. - self._internal_poll(_deadstate=_maxint) - if self.returncode is None and _active is not None: - # Child is still running, keep us alive until we can wait on it. - _active.append(self) - - def communicate(self, input=None): - """Interact with process: Send data to stdin. Read data from - stdout and stderr, until end-of-file is reached. Wait for - process to terminate. The optional input argument should be a - string to be sent to the child process, or None, if no data - should be sent to the child. - - communicate() returns a tuple (stdout, stderr).""" - - # Optimization: If we are only using one pipe, or no pipe at - # all, using select() or threads is unnecessary. - if [self.stdin, self.stdout, self.stderr].count(None) >= 2: - stdout = None - stderr = None - if self.stdin: - if input: - try: - self.stdin.write(input) - except IOError, e: - if e.errno != errno.EPIPE and e.errno != errno.EINVAL: - raise - self.stdin.close() - elif self.stdout: - stdout = _eintr_retry_call(self.stdout.read) - self.stdout.close() - elif self.stderr: - stderr = _eintr_retry_call(self.stderr.read) - self.stderr.close() - self.wait() - return (stdout, stderr) - - return self._communicate(input) - - def poll(self): - return self._internal_poll() - - if mswindows: - # - # Windows methods - # - def _get_handles(self, stdin, stdout, stderr): - """Construct and return tuple with IO objects: - p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite - """ - if stdin is None and stdout is None and stderr is None: - return (None, None, None, None, None, None) - - p2cread, p2cwrite = None, None - c2pread, c2pwrite = None, None - errread, errwrite = None, None - - if stdin is None: - p2cread = _subprocess.GetStdHandle( - _subprocess.STD_INPUT_HANDLE) - if p2cread is None: - p2cread, _ = _subprocess.CreatePipe(None, 0) - elif stdin == PIPE: - p2cread, p2cwrite = _subprocess.CreatePipe(None, 0) - elif isinstance(stdin, int): - p2cread = msvcrt.get_osfhandle(stdin) - else: - # Assuming file-like object - p2cread = msvcrt.get_osfhandle(stdin.fileno()) - p2cread = self._make_inheritable(p2cread) - - if stdout is None: - c2pwrite = _subprocess.GetStdHandle( - _subprocess.STD_OUTPUT_HANDLE) - if c2pwrite is None: - _, c2pwrite = _subprocess.CreatePipe(None, 0) - elif stdout == PIPE: - c2pread, c2pwrite = _subprocess.CreatePipe(None, 0) - elif isinstance(stdout, int): - c2pwrite = msvcrt.get_osfhandle(stdout) - else: - # Assuming file-like object - c2pwrite = msvcrt.get_osfhandle(stdout.fileno()) - c2pwrite = self._make_inheritable(c2pwrite) - - if stderr is None: - errwrite = _subprocess.GetStdHandle( - _subprocess.STD_ERROR_HANDLE) - if errwrite is None: - _, errwrite = _subprocess.CreatePipe(None, 0) - elif stderr == PIPE: - errread, errwrite = _subprocess.CreatePipe(None, 0) - elif stderr == STDOUT: - errwrite = c2pwrite - elif isinstance(stderr, int): - errwrite = msvcrt.get_osfhandle(stderr) - else: - # Assuming file-like object - errwrite = msvcrt.get_osfhandle(stderr.fileno()) - errwrite = self._make_inheritable(errwrite) - - return (p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite) - - def _make_inheritable(self, handle): - """Return a duplicate of handle, which is inheritable""" - return _subprocess.DuplicateHandle( - _subprocess.GetCurrentProcess(), - handle, - _subprocess.GetCurrentProcess(), - 0, - 1, - _subprocess.DUPLICATE_SAME_ACCESS - ) - - def _find_w9xpopen(self): - """Find and return absolut path to w9xpopen.exe""" - w9xpopen = os.path.join( - os.path.dirname(_subprocess.GetModuleFileName(0)), - "w9xpopen.exe") - if not os.path.exists(w9xpopen): - # Eeek - file-not-found - possibly an embedding - # situation - see if we can locate it in sys.exec_prefix - w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix), - "w9xpopen.exe") - if not os.path.exists(w9xpopen): - raise RuntimeError("Cannot locate w9xpopen.exe, which is " - "needed for Popen to work with your " - "shell or platform.") - return w9xpopen - - def _execute_child(self, args, executable, preexec_fn, close_fds, - cwd, env, universal_newlines, - startupinfo, creationflags, shell, - p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite): - """Execute program (MS Windows version)""" - - if not isinstance(args, types.StringTypes): - args = list2cmdline(args) - - # Process startup details - if startupinfo is None: - startupinfo = STARTUPINFO() - if None not in (p2cread, c2pwrite, errwrite): - startupinfo.dwFlags |= _subprocess.STARTF_USESTDHANDLES - startupinfo.hStdInput = p2cread - startupinfo.hStdOutput = c2pwrite - startupinfo.hStdError = errwrite - - if shell: - startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW - startupinfo.wShowWindow = _subprocess.SW_HIDE - comspec = os.environ.get("COMSPEC", "cmd.exe") - args = '{} /c "{}"'.format(comspec, args) - if (_subprocess.GetVersion() >= 0x80000000 or - os.path.basename(comspec).lower() == "command.com"): - # Win9x, or using command.com on NT. We need to - # use the w9xpopen intermediate program. For more - # information, see KB Q150956 - # (http://web.archive.org/web/20011105084002/http://support.microsoft.com/support/kb/articles/Q150/9/56.asp) - w9xpopen = self._find_w9xpopen() - args = '"%s" %s' % (w9xpopen, args) - # Not passing CREATE_NEW_CONSOLE has been known to - # cause random failures on win9x. Specifically a - # dialog: "Your program accessed mem currently in - # use at xxx" and a hopeful warning about the - # stability of your system. Cost is Ctrl+C wont - # kill children. - creationflags |= _subprocess.CREATE_NEW_CONSOLE - - # Start the process - try: - try: - hp, ht, pid, tid = _subprocess.CreateProcess( - executable, args, - # no special - # security - None, None, - int(not close_fds), - creationflags, - env, - cwd, - startupinfo) - except pywintypes.error, e: - # Translate pywintypes.error to WindowsError, which is - # a subclass of OSError. FIXME: We should really - # translate errno using _sys_errlist (or similar), but - # how can this be done from Python? - raise WindowsError(*e.args) - finally: - # Child is launched. Close the parent's copy of those pipe - # handles that only the child should have open. You need - # to make sure that no handles to the write end of the - # output pipe are maintained in this process or else the - # pipe will not close when the child process exits and the - # ReadFile will hang. - if p2cread is not None: - p2cread.Close() - if c2pwrite is not None: - c2pwrite.Close() - if errwrite is not None: - errwrite.Close() - - # Retain the process handle, but close the thread handle - self._child_created = True - self._handle = hp - self.pid = pid - ht.Close() - - def _internal_poll( - self, _deadstate=None, - _WaitForSingleObject=_subprocess.WaitForSingleObject, - _WAIT_OBJECT_0=_subprocess.WAIT_OBJECT_0, - _GetExitCodeProcess=_subprocess.GetExitCodeProcess - ): - """Check if child process has terminated. Returns returncode - attribute. - - This method is called by __del__, so it can only refer to objects - in its local scope. - - """ - if self.returncode is None: - if _WaitForSingleObject(self._handle, 0) == _WAIT_OBJECT_0: - self.returncode = _GetExitCodeProcess(self._handle) - return self.returncode - - def wait(self): - """Wait for child process to terminate. Returns returncode - attribute.""" - if self.returncode is None: - _subprocess.WaitForSingleObject(self._handle, - _subprocess.INFINITE) - self.returncode = _subprocess.GetExitCodeProcess(self._handle) - return self.returncode - - def _readerthread(self, fh, buffer): - buffer.append(fh.read()) - - def _communicate(self, input): - stdout = None # Return - stderr = None # Return - - if self.stdout: - stdout = [] - stdout_thread = threading.Thread(target=self._readerthread, - args=(self.stdout, stdout)) - stdout_thread.setDaemon(True) - stdout_thread.start() - if self.stderr: - stderr = [] - stderr_thread = threading.Thread(target=self._readerthread, - args=(self.stderr, stderr)) - stderr_thread.setDaemon(True) - stderr_thread.start() - - if self.stdin: - if input is not None: - try: - self.stdin.write(input) - except IOError, e: - if e.errno != errno.EPIPE: - raise - self.stdin.close() - - if self.stdout: - stdout_thread.join() - if self.stderr: - stderr_thread.join() - - # All data exchanged. Translate lists into strings. - if stdout is not None: - stdout = stdout[0] - if stderr is not None: - stderr = stderr[0] - - # Translate newlines, if requested. We cannot let the file - # object do the translation: It is based on stdio, which is - # impossible to combine with select (unless forcing no - # buffering). - if self.universal_newlines and hasattr(file, 'newlines'): - if stdout: - stdout = self._translate_newlines(stdout) - if stderr: - stderr = self._translate_newlines(stderr) - - self.wait() - return (stdout, stderr) - - def send_signal(self, sig): - """Send a signal to the process - """ - if sig == signal.SIGTERM: - self.terminate() - elif sig == signal.CTRL_C_EVENT: - os.kill(self.pid, signal.CTRL_C_EVENT) - elif sig == signal.CTRL_BREAK_EVENT: - os.kill(self.pid, signal.CTRL_BREAK_EVENT) - else: - raise ValueError("Unsupported signal: {}".format(sig)) - - def terminate(self): - """Terminates the process - """ - _subprocess.TerminateProcess(self._handle, 1) - - kill = terminate - - else: - # - # POSIX methods - # - def _get_handles(self, stdin, stdout, stderr): - """Construct and return tuple with IO objects: - p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite - """ - p2cread, p2cwrite = None, None - c2pread, c2pwrite = None, None - errread, errwrite = None, None - - if stdin is None: - pass - elif stdin == PIPE: - p2cread, p2cwrite = self.pipe_cloexec() - elif isinstance(stdin, int): - p2cread = stdin - else: - # Assuming file-like object - p2cread = stdin.fileno() - - if stdout is None: - pass - elif stdout == PIPE: - c2pread, c2pwrite = self.pipe_cloexec() - elif isinstance(stdout, int): - c2pwrite = stdout - else: - # Assuming file-like object - c2pwrite = stdout.fileno() - - if stderr is None: - pass - elif stderr == PIPE: - errread, errwrite = self.pipe_cloexec() - elif stderr == STDOUT: - errwrite = c2pwrite - elif isinstance(stderr, int): - errwrite = stderr - else: - # Assuming file-like object - errwrite = stderr.fileno() - - return (p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite) - - def _set_cloexec_flag(self, fd, cloexec=True): - try: - cloexec_flag = fcntl.FD_CLOEXEC - except AttributeError: - cloexec_flag = 1 - - old = fcntl.fcntl(fd, fcntl.F_GETFD) - if cloexec: - fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag) - else: - fcntl.fcntl(fd, fcntl.F_SETFD, old & ~cloexec_flag) - - def pipe_cloexec(self): - """Create a pipe with FDs set CLOEXEC.""" - # Pipes' FDs are set CLOEXEC by default because we don't want them - # to be inherited by other subprocesses: the CLOEXEC flag is - # removed from the child's FDs by _dup2(), between fork() and - # exec(). - # This is not atomic: we would need the pipe2() syscall for that. - r, w = os.pipe() - self._set_cloexec_flag(r) - self._set_cloexec_flag(w) - return r, w - - def _close_fds(self, but): - if hasattr(os, 'closerange'): - os.closerange(3, but) - os.closerange(but + 1, MAXFD) - else: - for i in xrange(3, MAXFD): - if i == but: - continue - try: - os.close(i) - except: - pass - - def _execute_child(self, args, executable, preexec_fn, close_fds, - cwd, env, universal_newlines, - startupinfo, creationflags, shell, - p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite): - """Execute program (POSIX version)""" - - if isinstance(args, types.StringTypes): - args = [args] - else: - args = list(args) - - if shell: - args = ["/bin/sh", "-c"] + args - if executable: - args[0] = executable - - if executable is None: - executable = args[0] - - # For transferring possible exec failure from child to parent - # The first char specifies the exception type: 0 means - # OSError, 1 means some other error. - errpipe_read, errpipe_write = self.pipe_cloexec() - try: - try: - gc_was_enabled = gc.isenabled() - # Disable gc to avoid bug where gc -> file_dealloc -> - # write to stderr -> hang. - # http://bugs.python.org/issue1336 - gc.disable() - try: - self.pid = os.fork() - except: - if gc_was_enabled: - gc.enable() - raise - self._child_created = True - if self.pid == 0: - # Child - try: - # Close parent's pipe ends - if p2cwrite is not None: - os.close(p2cwrite) - if c2pread is not None: - os.close(c2pread) - if errread is not None: - os.close(errread) - os.close(errpipe_read) - - # When duping fds, if there arises a situation - # where one of the fds is either 0, 1 or 2, it - # is possible that it is overwritten (#12607). - if c2pwrite == 0: - c2pwrite = os.dup(c2pwrite) - if errwrite == 0 or errwrite == 1: - errwrite = os.dup(errwrite) - - # Dup fds for child - def _dup2(a, b): - # dup2() removes the CLOEXEC flag but - # we must do it ourselves if dup2() - # would be a no-op (issue #10806). - if a == b: - self._set_cloexec_flag(a, False) - elif a is not None: - os.dup2(a, b) - _dup2(p2cread, 0) - _dup2(c2pwrite, 1) - _dup2(errwrite, 2) - - # Close pipe fds. Make sure we don't close the - # same fd more than once, or standard fds. - closed = set([None]) - for fd in [p2cread, c2pwrite, errwrite]: - if fd not in closed and fd > 2: - os.close(fd) - closed.add(fd) - - # Close all other fds, if asked for - if close_fds: - self._close_fds(but=errpipe_write) - - if cwd is not None: - os.chdir(cwd) - - if preexec_fn: - preexec_fn() - - if env is None: - os.execvp(executable, args) - else: - os.execvpe(executable, args, env) - - except: - exc_type, exc_value, tb = sys.exc_info() - # Save the traceback and attach it to the exception - # object - exc_lines = traceback.format_exception(exc_type, - exc_value, - tb) - exc_value.child_traceback = ''.join(exc_lines) - os.write(errpipe_write, pickle.dumps(exc_value)) - - # This exitcode won't be reported to applications, - # so it really doesn't matter what we return. - os._exit(255) - - # Parent - if gc_was_enabled: - gc.enable() - finally: - # be sure the FD is closed no matter what - os.close(errpipe_write) - - if p2cread is not None and p2cwrite is not None: - os.close(p2cread) - if c2pwrite is not None and c2pread is not None: - os.close(c2pwrite) - if errwrite is not None and errread is not None: - os.close(errwrite) - - # Wait for exec to fail or succeed; possibly raising exception - # Exception limited to 1M - data = _eintr_retry_call(os.read, errpipe_read, 1048576) - finally: - # be sure the FD is closed no matter what - os.close(errpipe_read) - - if data != "": - try: - _eintr_retry_call(os.waitpid, self.pid, 0) - except OSError, e: - if e.errno != errno.ECHILD: - raise - child_exception = pickle.loads(data) - for fd in (p2cwrite, c2pread, errread): - if fd is not None: - os.close(fd) - raise child_exception - - def _handle_exitstatus(self, sts, _WIFSIGNALED=os.WIFSIGNALED, - _WTERMSIG=os.WTERMSIG, _WIFEXITED=os.WIFEXITED, - _WEXITSTATUS=os.WEXITSTATUS): - # This method is called (indirectly) by __del__, so it cannot - # refer to anything outside of its local scope.""" - if _WIFSIGNALED(sts): - self.returncode = -_WTERMSIG(sts) - elif _WIFEXITED(sts): - self.returncode = _WEXITSTATUS(sts) - else: - # Should never happen - raise RuntimeError("Unknown child exit status!") - - def _internal_poll(self, _deadstate=None, _waitpid=os.waitpid, - _WNOHANG=os.WNOHANG, _os_error=os.error): - """Check if child process has terminated. Returns returncode - attribute. - - This method is called by __del__, so it cannot reference anything - outside of the local scope (nor can any methods it calls). - - """ - if self.returncode is None: - try: - pid, sts = _waitpid(self.pid, _WNOHANG) - if pid == self.pid: - self._handle_exitstatus(sts) - except _os_error: - if _deadstate is not None: - self.returncode = _deadstate - return self.returncode - - def wait(self): - """Wait for child process to terminate. Returns returncode - attribute.""" - if self.returncode is None: - try: - pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0) - except OSError, e: - if e.errno != errno.ECHILD: - raise - # This happens if SIGCLD is set to be ignored or waiting - # for child processes has otherwise been disabled for our - # process. This child is dead, we can't get the status. - sts = 0 - self._handle_exitstatus(sts) - return self.returncode - - def _communicate(self, input): - if self.stdin: - # Flush stdio buffer. This might block, if the user has - # been writing to .stdin in an uncontrolled fashion. - self.stdin.flush() - if not input: - self.stdin.close() - - if _has_poll: - stdout, stderr = self._communicate_with_poll(input) - else: - stdout, stderr = self._communicate_with_select(input) - - # All data exchanged. Translate lists into strings. - if stdout is not None: - stdout = ''.join(stdout) - if stderr is not None: - stderr = ''.join(stderr) - - # Translate newlines, if requested. We cannot let the file - # object do the translation: It is based on stdio, which is - # impossible to combine with select (unless forcing no - # buffering). - if self.universal_newlines and hasattr(file, 'newlines'): - if stdout: - stdout = self._translate_newlines(stdout) - if stderr: - stderr = self._translate_newlines(stderr) - - self.wait() - return (stdout, stderr) - - def _communicate_with_poll(self, input): - stdout = None # Return - stderr = None # Return - fd2file = {} - fd2output = {} - - poller = select.poll() - - def register_and_append(file_obj, eventmask): - poller.register(file_obj.fileno(), eventmask) - fd2file[file_obj.fileno()] = file_obj - - def close_unregister_and_remove(fd): - poller.unregister(fd) - fd2file[fd].close() - fd2file.pop(fd) - - if self.stdin and input: - register_and_append(self.stdin, select.POLLOUT) - - select_POLLIN_POLLPRI = select.POLLIN | select.POLLPRI - if self.stdout: - register_and_append(self.stdout, select_POLLIN_POLLPRI) - fd2output[self.stdout.fileno()] = stdout = [] - if self.stderr: - register_and_append(self.stderr, select_POLLIN_POLLPRI) - fd2output[self.stderr.fileno()] = stderr = [] - - input_offset = 0 - while fd2file: - try: - ready = poller.poll() - except select.error, e: - if e.args[0] == errno.EINTR: - continue - raise - - for fd, mode in ready: - if mode & select.POLLOUT: - chunk = input[input_offset: input_offset + _PIPE_BUF] - try: - input_offset += os.write(fd, chunk) - except OSError, e: - if e.errno == errno.EPIPE: - close_unregister_and_remove(fd) - else: - raise - else: - if input_offset >= len(input): - close_unregister_and_remove(fd) - elif mode & select_POLLIN_POLLPRI: - data = os.read(fd, 4096) - if not data: - close_unregister_and_remove(fd) - fd2output[fd].append(data) - else: - # Ignore hang up or errors. - close_unregister_and_remove(fd) - - return (stdout, stderr) - - def _communicate_with_select(self, input): - read_set = [] - write_set = [] - stdout = None # Return - stderr = None # Return - - if self.stdin and input: - write_set.append(self.stdin) - if self.stdout: - read_set.append(self.stdout) - stdout = [] - if self.stderr: - read_set.append(self.stderr) - stderr = [] - - input_offset = 0 - while read_set or write_set: - try: - rlist, wlist, xlist = select.select( - read_set, write_set, []) - except select.error, e: - if e.args[0] == errno.EINTR: - continue - raise - - if self.stdin in wlist: - chunk = input[input_offset: input_offset + _PIPE_BUF] - try: - bytes_written = os.write(self.stdin.fileno(), chunk) - except OSError, e: - if e.errno == errno.EPIPE: - self.stdin.close() - write_set.remove(self.stdin) - else: - raise - else: - input_offset += bytes_written - if input_offset >= len(input): - self.stdin.close() - write_set.remove(self.stdin) - - if self.stdout in rlist: - data = os.read(self.stdout.fileno(), 1024) - if data == "": - self.stdout.close() - read_set.remove(self.stdout) - stdout.append(data) - - if self.stderr in rlist: - data = os.read(self.stderr.fileno(), 1024) - if data == "": - self.stderr.close() - read_set.remove(self.stderr) - stderr.append(data) - - return (stdout, stderr) - - def send_signal(self, sig): - """Send a signal to the process - """ - os.kill(self.pid, sig) - - def terminate(self): - """Terminate the process with SIGTERM - """ - self.send_signal(signal.SIGTERM) - - def kill(self): - """Kill the process with SIGKILL - """ - self.send_signal(signal.SIGKILL) - - -def _demo_posix(): - # - # Example 1: Simple redirection: Get process list - # - plist = Popen(["ps"], stdout=PIPE).communicate()[0] - print "Process list:" - print plist - - # - # Example 2: Change uid before executing child - # - if os.getuid() == 0: - p = Popen(["id"], preexec_fn=lambda: os.setuid(100)) - p.wait() - - # - # Example 3: Connecting several subprocesses - # - print "Looking for 'hda'..." - p1 = Popen(["dmesg"], stdout=PIPE) - p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) - print repr(p2.communicate()[0]) - - # - # Example 4: Catch execution error - # - print - print "Trying a weird file..." - try: - print Popen(["/this/path/does/not/exist"]).communicate() - except OSError, e: - if e.errno == errno.ENOENT: - print "The file didn't exist. I thought so..." - print "Child traceback:" - print e.child_traceback - else: - print "Error", e.errno - else: - print >>sys.stderr, "Gosh. No error." - - -def _demo_windows(): - # - # Example 1: Connecting several subprocesses - # - print "Looking for 'PROMPT' in set output..." - p1 = Popen("set", stdout=PIPE, shell=True) - p2 = Popen('find "PROMPT"', stdin=p1.stdout, stdout=PIPE) - print repr(p2.communicate()[0]) - - # - # Example 2: Simple execution of program - # - print "Executing calc..." - p = Popen("calc") - p.wait() - - -if __name__ == "__main__": - if mswindows: - _demo_windows() - else: - _demo_posix() +# subprocess - Subprocesses with accessible I/O streams +# +# For more information about this module, see PEP 324. +# +# This module should remain compatible with Python 2.2, see PEP 291. +# +# Copyright (c) 2003-2005 by Peter Astrand +# +# Licensed to PSF under a Contributor Agreement. +# See http://www.python.org/2.4/license for licensing details. + +r"""subprocess - Subprocesses with accessible I/O streams + +This module allows you to spawn processes, connect to their +input/output/error pipes, and obtain their return codes. This module +intends to replace several other, older modules and functions, like: + +os.system +os.spawn* +os.popen* +popen2.* +commands.* + +Information about how the subprocess module can be used to replace these +modules and functions can be found below. + + + +Using the subprocess module +=========================== +This module defines one class called Popen: + +class Popen(args, bufsize=0, executable=None, + stdin=None, stdout=None, stderr=None, + preexec_fn=None, close_fds=False, shell=False, + cwd=None, env=None, universal_newlines=False, + startupinfo=None, creationflags=0): + + +Arguments are: + +args should be a string, or a sequence of program arguments. The +program to execute is normally the first item in the args sequence or +string, but can be explicitly set by using the executable argument. + +On UNIX, with shell=False (default): In this case, the Popen class +uses os.execvp() to execute the child program. args should normally +be a sequence. A string will be treated as a sequence with the string +as the only item (the program to execute). + +On UNIX, with shell=True: If args is a string, it specifies the +command string to execute through the shell. If args is a sequence, +the first item specifies the command string, and any additional items +will be treated as additional shell arguments. + +On Windows: the Popen class uses CreateProcess() to execute the child +program, which operates on strings. If args is a sequence, it will be +converted to a string using the list2cmdline method. Please note that +not all MS Windows applications interpret the command line the same +way: The list2cmdline is designed for applications using the same +rules as the MS C runtime. + +bufsize, if given, has the same meaning as the corresponding argument +to the built-in open() function: 0 means unbuffered, 1 means line +buffered, any other positive value means use a buffer of +(approximately) that size. A negative bufsize means to use the system +default, which usually means fully buffered. The default value for +bufsize is 0 (unbuffered). + +stdin, stdout and stderr specify the executed programs' standard +input, standard output and standard error file handles, respectively. +Valid values are PIPE, an existing file descriptor (a positive +integer), an existing file object, and None. PIPE indicates that a +new pipe to the child should be created. With None, no redirection +will occur; the child's file handles will be inherited from the +parent. Additionally, stderr can be STDOUT, which indicates that the +stderr data from the applications should be captured into the same +file handle as for stdout. + +If preexec_fn is set to a callable object, this object will be called +in the child process just before the child is executed. + +If close_fds is true, all file descriptors except 0, 1 and 2 will be +closed before the child process is executed. + +if shell is true, the specified command will be executed through the +shell. + +If cwd is not None, the current directory will be changed to cwd +before the child is executed. + +If env is not None, it defines the environment variables for the new +process. + +If universal_newlines is true, the file objects stdout and stderr are +opened as a text files, but lines may be terminated by any of '\n', +the Unix end-of-line convention, '\r', the Macintosh convention or +'\r\n', the Windows convention. All of these external representations +are seen as '\n' by the Python program. Note: This feature is only +available if Python is built with universal newline support (the +default). Also, the newlines attribute of the file objects stdout, +stdin and stderr are not updated by the communicate() method. + +The startupinfo and creationflags, if given, will be passed to the +underlying CreateProcess() function. They can specify things such as +appearance of the main window and priority for the new process. +(Windows only) + + +This module also defines some shortcut functions: + +call(*popenargs, **kwargs): + Run command with arguments. Wait for command to complete, then + return the returncode attribute. + + The arguments are the same as for the Popen constructor. Example: + + retcode = call(["ls", "-l"]) + +check_call(*popenargs, **kwargs): + Run command with arguments. Wait for command to complete. If the + exit code was zero then return, otherwise raise + CalledProcessError. The CalledProcessError object will have the + return code in the returncode attribute. + + The arguments are the same as for the Popen constructor. Example: + + check_call(["ls", "-l"]) + +check_output(*popenargs, **kwargs): + Run command with arguments and return its output as a byte string. + + If the exit code was non-zero it raises a CalledProcessError. The + CalledProcessError object will have the return code in the returncode + attribute and output in the output attribute. + + The arguments are the same as for the Popen constructor. Example: + + output = check_output(["ls", "-l", "/dev/null"]) + + +Exceptions +---------- +Exceptions raised in the child process, before the new program has +started to execute, will be re-raised in the parent. Additionally, +the exception object will have one extra attribute called +'child_traceback', which is a string containing traceback information +from the childs point of view. + +The most common exception raised is OSError. This occurs, for +example, when trying to execute a non-existent file. Applications +should prepare for OSErrors. + +A ValueError will be raised if Popen is called with invalid arguments. + +check_call() and check_output() will raise CalledProcessError, if the +called process returns a non-zero return code. + + +Security +-------- +Unlike some other popen functions, this implementation will never call +/bin/sh implicitly. This means that all characters, including shell +metacharacters, can safely be passed to child processes. + + +Popen objects +============= +Instances of the Popen class have the following methods: + +poll() + Check if child process has terminated. Returns returncode + attribute. + +wait() + Wait for child process to terminate. Returns returncode attribute. + +communicate(input=None) + Interact with process: Send data to stdin. Read data from stdout + and stderr, until end-of-file is reached. Wait for process to + terminate. The optional input argument should be a string to be + sent to the child process, or None, if no data should be sent to + the child. + + communicate() returns a tuple (stdout, stderr). + + Note: The data read is buffered in memory, so do not use this + method if the data size is large or unlimited. + +The following attributes are also available: + +stdin + If the stdin argument is PIPE, this attribute is a file object + that provides input to the child process. Otherwise, it is None. + +stdout + If the stdout argument is PIPE, this attribute is a file object + that provides output from the child process. Otherwise, it is + None. + +stderr + If the stderr argument is PIPE, this attribute is file object that + provides error output from the child process. Otherwise, it is + None. + +pid + The process ID of the child process. + +returncode + The child return code. A None value indicates that the process + hasn't terminated yet. A negative value -N indicates that the + child was terminated by signal N (UNIX only). + + +Replacing older functions with the subprocess module +==================================================== +In this section, "a ==> b" means that b can be used as a replacement +for a. + +Note: All functions in this section fail (more or less) silently if +the executed program cannot be found; this module raises an OSError +exception. + +In the following examples, we assume that the subprocess module is +imported with "from subprocess import *". + + +Replacing /bin/sh shell backquote +--------------------------------- +output=`mycmd myarg` +==> +output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0] + + +Replacing shell pipe line +------------------------- +output=`dmesg | grep hda` +==> +p1 = Popen(["dmesg"], stdout=PIPE) +p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) +output = p2.communicate()[0] + + +Replacing os.system() +--------------------- +sts = os.system("mycmd" + " myarg") +==> +p = Popen("mycmd" + " myarg", shell=True) +pid, sts = os.waitpid(p.pid, 0) + +Note: + +* Calling the program through the shell is usually not required. + +* It's easier to look at the returncode attribute than the + exitstatus. + +A more real-world example would look like this: + +try: + retcode = call("mycmd" + " myarg", shell=True) + if retcode < 0: + print >>sys.stderr, "Child was terminated by signal", -retcode + else: + print >>sys.stderr, "Child returned", retcode +except OSError, e: + print >>sys.stderr, "Execution failed:", e + + +Replacing os.spawn* +------------------- +P_NOWAIT example: + +pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") +==> +pid = Popen(["/bin/mycmd", "myarg"]).pid + + +P_WAIT example: + +retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") +==> +retcode = call(["/bin/mycmd", "myarg"]) + + +Vector example: + +os.spawnvp(os.P_NOWAIT, path, args) +==> +Popen([path] + args[1:]) + + +Environment example: + +os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env) +==> +Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) + + +Replacing os.popen* +------------------- +pipe = os.popen("cmd", mode='r', bufsize) +==> +pipe = Popen("cmd", shell=True, bufsize=bufsize, stdout=PIPE).stdout + +pipe = os.popen("cmd", mode='w', bufsize) +==> +pipe = Popen("cmd", shell=True, bufsize=bufsize, stdin=PIPE).stdin + + +(child_stdin, child_stdout) = os.popen2("cmd", mode, bufsize) +==> +p = Popen("cmd", shell=True, bufsize=bufsize, + stdin=PIPE, stdout=PIPE, close_fds=True) +(child_stdin, child_stdout) = (p.stdin, p.stdout) + + +(child_stdin, + child_stdout, + child_stderr) = os.popen3("cmd", mode, bufsize) +==> +p = Popen("cmd", shell=True, bufsize=bufsize, + stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) +(child_stdin, + child_stdout, + child_stderr) = (p.stdin, p.stdout, p.stderr) + + +(child_stdin, child_stdout_and_stderr) = os.popen4("cmd", mode, + bufsize) +==> +p = Popen("cmd", shell=True, bufsize=bufsize, + stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) +(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) + +On Unix, os.popen2, os.popen3 and os.popen4 also accept a sequence as +the command to execute, in which case arguments will be passed +directly to the program without shell intervention. This usage can be +replaced as follows: + +(child_stdin, child_stdout) = os.popen2(["/bin/ls", "-l"], mode, + bufsize) +==> +p = Popen(["/bin/ls", "-l"], bufsize=bufsize, stdin=PIPE, stdout=PIPE) +(child_stdin, child_stdout) = (p.stdin, p.stdout) + +Return code handling translates as follows: + +pipe = os.popen("cmd", 'w') +... +rc = pipe.close() +if rc is not None and rc % 256: + print "There were some errors" +==> +process = Popen("cmd", 'w', shell=True, stdin=PIPE) +... +process.stdin.close() +if process.wait() != 0: + print "There were some errors" + + +Replacing popen2.* +------------------ +(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode) +==> +p = Popen(["somestring"], shell=True, bufsize=bufsize + stdin=PIPE, stdout=PIPE, close_fds=True) +(child_stdout, child_stdin) = (p.stdout, p.stdin) + +On Unix, popen2 also accepts a sequence as the command to execute, in +which case arguments will be passed directly to the program without +shell intervention. This usage can be replaced as follows: + +(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, + mode) +==> +p = Popen(["mycmd", "myarg"], bufsize=bufsize, + stdin=PIPE, stdout=PIPE, close_fds=True) +(child_stdout, child_stdin) = (p.stdout, p.stdin) + +The popen2.Popen3 and popen2.Popen4 basically works as subprocess.Popen, +except that: + +* subprocess.Popen raises an exception if the execution fails +* the capturestderr argument is replaced with the stderr argument. +* stdin=PIPE and stdout=PIPE must be specified. +* popen2 closes all filedescriptors by default, but you have to specify + close_fds=True with subprocess.Popen. +""" + +import sys +mswindows = (sys.platform == "win32") + +import os +import types +import traceback +import gc +import signal +import errno + +try: + set +except NameError: + from sets import Set as set + +# Exception classes used by this module. + + +class CalledProcessError(Exception): + + """This exception is raised when a process run by check_call() or + check_output() returns a non-zero exit status. + The exit status will be stored in the returncode attribute; + check_output() will also store the output in the output attribute. + """ + + def __init__(self, returncode, cmd, output=None): + self.returncode = returncode + self.cmd = cmd + self.output = output + + def __str__(self): + return "Command '%s' returned non-zero exit status %d" % ( + self.cmd, self.returncode) + + +if mswindows: + import threading + import msvcrt + import _subprocess + + class STARTUPINFO: + dwFlags = 0 + hStdInput = None + hStdOutput = None + hStdError = None + wShowWindow = 0 + + class pywintypes: + error = IOError +else: + import select + _has_poll = hasattr(select, 'poll') + import fcntl + import pickle + + # When select or poll has indicated that the file is writable, + # we can write up to _PIPE_BUF bytes without risk of blocking. + # POSIX defines PIPE_BUF as >= 512. + _PIPE_BUF = getattr(select, 'PIPE_BUF', 512) + + +__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", + "check_output", "CalledProcessError"] + +if mswindows: + from _subprocess import CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP, \ + STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, \ + STD_ERROR_HANDLE, SW_HIDE, \ + STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW + + __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP", + "STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE", + "STD_ERROR_HANDLE", "SW_HIDE", + "STARTF_USESTDHANDLES", "STARTF_USESHOWWINDOW"]) +try: + MAXFD = os.sysconf("SC_OPEN_MAX") +except: + MAXFD = 256 + +_active = [] + + +def _cleanup(): + for inst in _active[:]: + res = inst._internal_poll(_deadstate=sys.maxsize) + if res is not None: + try: + _active.remove(inst) + except ValueError: + # This can happen if two threads create a new Popen instance. + # It's harmless that it was already removed, so ignore. + pass + +PIPE = -1 +STDOUT = -2 + + +def _eintr_retry_call(func, *args): + while True: + try: + return func(*args) + except (OSError, IOError) as e: + if e.errno == errno.EINTR: + continue + raise + + +def call(*popenargs, **kwargs): + """Run command with arguments. Wait for command to complete, then + return the returncode attribute. + + The arguments are the same as for the Popen constructor. Example: + + retcode = call(["ls", "-l"]) + """ + return Popen(*popenargs, **kwargs).wait() + + +def check_call(*popenargs, **kwargs): + """Run command with arguments. Wait for command to complete. If + the exit code was zero then return, otherwise raise + CalledProcessError. The CalledProcessError object will have the + return code in the returncode attribute. + + The arguments are the same as for the Popen constructor. Example: + + check_call(["ls", "-l"]) + """ + retcode = call(*popenargs, **kwargs) + if retcode: + cmd = kwargs.get("args") + if cmd is None: + cmd = popenargs[0] + raise CalledProcessError(retcode, cmd) + return 0 + + +def check_output(*popenargs, **kwargs): + r"""Run command with arguments and return its output as a byte string. + + If the exit code was non-zero it raises a CalledProcessError. The + CalledProcessError object will have the return code in the returncode + attribute and output in the output attribute. + + The arguments are the same as for the Popen constructor. Example: + + >>> check_output(["ls", "-l", "/dev/null"]) + 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n' + + The stdout argument is not allowed as it is used internally. + To capture standard error in the result, use stderr=STDOUT. + + >>> check_output(["/bin/sh", "-c", + ... "ls -l non_existent_file ; exit 0"], + ... stderr=STDOUT) + 'ls: non_existent_file: No such file or directory\n' + """ + if 'stdout' in kwargs: + raise ValueError('stdout argument not allowed, it will be overridden.') + process = Popen(stdout=PIPE, *popenargs, **kwargs) + output, unused_err = process.communicate() + retcode = process.poll() + if retcode: + cmd = kwargs.get("args") + if cmd is None: + cmd = popenargs[0] + raise CalledProcessError(retcode, cmd, output=output) + return output + + +def list2cmdline(seq): + """ + Translate a sequence of arguments into a command line + string, using the same rules as the MS C runtime: + + 1) Arguments are delimited by white space, which is either a + space or a tab. + + 2) A string surrounded by double quotation marks is + interpreted as a single argument, regardless of white space + contained within. A quoted string can be embedded in an + argument. + + 3) A double quotation mark preceded by a backslash is + interpreted as a literal double quotation mark. + + 4) Backslashes are interpreted literally, unless they + immediately precede a double quotation mark. + + 5) If backslashes immediately precede a double quotation mark, + every pair of backslashes is interpreted as a literal + backslash. If the number of backslashes is odd, the last + backslash escapes the next double quotation mark as + described in rule 3. + """ + + # See + # http://msdn.microsoft.com/en-us/library/17w5ykft.aspx + # or search http://msdn.microsoft.com for + # "Parsing C++ Command-Line Arguments" + result = [] + needquote = False + for arg in seq: + bs_buf = [] + + # Add a space to separate this argument from the others + if result: + result.append(' ') + + needquote = (" " in arg) or ("\t" in arg) or not arg + if needquote: + result.append('"') + + for c in arg: + if c == '\\': + # Don't know if we need to double yet. + bs_buf.append(c) + elif c == '"': + # Double backslashes. + result.append('\\' * len(bs_buf) * 2) + bs_buf = [] + result.append('\\"') + else: + # Normal char + if bs_buf: + result.extend(bs_buf) + bs_buf = [] + result.append(c) + + # Add remaining backslashes, if any. + if bs_buf: + result.extend(bs_buf) + + if needquote: + result.extend(bs_buf) + result.append('"') + + return ''.join(result) + + +class Popen(object): + + def __init__(self, args, bufsize=0, executable=None, + stdin=None, stdout=None, stderr=None, + preexec_fn=None, close_fds=False, shell=False, + cwd=None, env=None, universal_newlines=False, + startupinfo=None, creationflags=0): + """Create new Popen instance.""" + _cleanup() + + self._child_created = False + if not isinstance(bufsize, int): + raise TypeError("bufsize must be an integer") + + if mswindows: + if preexec_fn is not None: + raise ValueError("preexec_fn is not supported on Windows " + "platforms") + if close_fds and (stdin is not None or stdout is not None or + stderr is not None): + raise ValueError("close_fds is not supported on Windows " + "platforms if you redirect " + "stdin/stdout/stderr") + else: + # POSIX + if startupinfo is not None: + raise ValueError("startupinfo is only supported on Windows " + "platforms") + if creationflags != 0: + raise ValueError("creationflags is only supported on Windows " + "platforms") + + self.stdin = None + self.stdout = None + self.stderr = None + self.pid = None + self.returncode = None + self.universal_newlines = universal_newlines + + # Input and output objects. The general principle is like + # this: + # + # Parent Child + # ------ ----- + # p2cwrite ---stdin---> p2cread + # c2pread <--stdout--- c2pwrite + # errread <--stderr--- errwrite + # + # On POSIX, the child objects are file descriptors. On + # Windows, these are Windows file handles. The parent objects + # are file descriptors on both platforms. The parent objects + # are None when not using PIPEs. The child objects are None + # when not redirecting. + + (p2cread, p2cwrite, + c2pread, c2pwrite, + errread, errwrite) = self._get_handles(stdin, stdout, stderr) + + self._execute_child(args, executable, preexec_fn, close_fds, + cwd, env, universal_newlines, + startupinfo, creationflags, shell, + p2cread, p2cwrite, + c2pread, c2pwrite, + errread, errwrite) + + if mswindows: + if p2cwrite is not None: + p2cwrite = msvcrt.open_osfhandle(p2cwrite.Detach(), 0) + if c2pread is not None: + c2pread = msvcrt.open_osfhandle(c2pread.Detach(), 0) + if errread is not None: + errread = msvcrt.open_osfhandle(errread.Detach(), 0) + + if p2cwrite is not None: + self.stdin = os.fdopen(p2cwrite, 'wb', bufsize) + if c2pread is not None: + if universal_newlines: + self.stdout = os.fdopen(c2pread, 'rU', bufsize) + else: + self.stdout = os.fdopen(c2pread, 'rb', bufsize) + if errread is not None: + if universal_newlines: + self.stderr = os.fdopen(errread, 'rU', bufsize) + else: + self.stderr = os.fdopen(errread, 'rb', bufsize) + + def _translate_newlines(self, data): + data = data.replace("\r\n", "\n") + data = data.replace("\r", "\n") + return data + + def __del__(self, _maxint=sys.maxsize, _active=_active): + # If __init__ hasn't had a chance to execute (e.g. if it + # was passed an undeclared keyword argument), we don't + # have a _child_created attribute at all. + if not getattr(self, '_child_created', False): + # We didn't get to successfully create a child process. + return + # In case the child hasn't been waited on, check if it's done. + self._internal_poll(_deadstate=_maxint) + if self.returncode is None and _active is not None: + # Child is still running, keep us alive until we can wait on it. + _active.append(self) + + def communicate(self, input=None): + """Interact with process: Send data to stdin. Read data from + stdout and stderr, until end-of-file is reached. Wait for + process to terminate. The optional input argument should be a + string to be sent to the child process, or None, if no data + should be sent to the child. + + communicate() returns a tuple (stdout, stderr).""" + + # Optimization: If we are only using one pipe, or no pipe at + # all, using select() or threads is unnecessary. + if [self.stdin, self.stdout, self.stderr].count(None) >= 2: + stdout = None + stderr = None + if self.stdin: + if input: + try: + self.stdin.write(input) + except IOError as e: + if e.errno != errno.EPIPE and e.errno != errno.EINVAL: + raise + self.stdin.close() + elif self.stdout: + stdout = _eintr_retry_call(self.stdout.read) + self.stdout.close() + elif self.stderr: + stderr = _eintr_retry_call(self.stderr.read) + self.stderr.close() + self.wait() + return (stdout, stderr) + + return self._communicate(input) + + def poll(self): + return self._internal_poll() + + if mswindows: + # + # Windows methods + # + def _get_handles(self, stdin, stdout, stderr): + """Construct and return tuple with IO objects: + p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite + """ + if stdin is None and stdout is None and stderr is None: + return (None, None, None, None, None, None) + + p2cread, p2cwrite = None, None + c2pread, c2pwrite = None, None + errread, errwrite = None, None + + if stdin is None: + p2cread = _subprocess.GetStdHandle( + _subprocess.STD_INPUT_HANDLE) + if p2cread is None: + p2cread, _ = _subprocess.CreatePipe(None, 0) + elif stdin == PIPE: + p2cread, p2cwrite = _subprocess.CreatePipe(None, 0) + elif isinstance(stdin, int): + p2cread = msvcrt.get_osfhandle(stdin) + else: + # Assuming file-like object + p2cread = msvcrt.get_osfhandle(stdin.fileno()) + p2cread = self._make_inheritable(p2cread) + + if stdout is None: + c2pwrite = _subprocess.GetStdHandle( + _subprocess.STD_OUTPUT_HANDLE) + if c2pwrite is None: + _, c2pwrite = _subprocess.CreatePipe(None, 0) + elif stdout == PIPE: + c2pread, c2pwrite = _subprocess.CreatePipe(None, 0) + elif isinstance(stdout, int): + c2pwrite = msvcrt.get_osfhandle(stdout) + else: + # Assuming file-like object + c2pwrite = msvcrt.get_osfhandle(stdout.fileno()) + c2pwrite = self._make_inheritable(c2pwrite) + + if stderr is None: + errwrite = _subprocess.GetStdHandle( + _subprocess.STD_ERROR_HANDLE) + if errwrite is None: + _, errwrite = _subprocess.CreatePipe(None, 0) + elif stderr == PIPE: + errread, errwrite = _subprocess.CreatePipe(None, 0) + elif stderr == STDOUT: + errwrite = c2pwrite + elif isinstance(stderr, int): + errwrite = msvcrt.get_osfhandle(stderr) + else: + # Assuming file-like object + errwrite = msvcrt.get_osfhandle(stderr.fileno()) + errwrite = self._make_inheritable(errwrite) + + return (p2cread, p2cwrite, + c2pread, c2pwrite, + errread, errwrite) + + def _make_inheritable(self, handle): + """Return a duplicate of handle, which is inheritable""" + return _subprocess.DuplicateHandle( + _subprocess.GetCurrentProcess(), + handle, + _subprocess.GetCurrentProcess(), + 0, + 1, + _subprocess.DUPLICATE_SAME_ACCESS + ) + + def _find_w9xpopen(self): + """Find and return absolut path to w9xpopen.exe""" + w9xpopen = os.path.join( + os.path.dirname(_subprocess.GetModuleFileName(0)), + "w9xpopen.exe") + if not os.path.exists(w9xpopen): + # Eeek - file-not-found - possibly an embedding + # situation - see if we can locate it in sys.exec_prefix + w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix), + "w9xpopen.exe") + if not os.path.exists(w9xpopen): + raise RuntimeError("Cannot locate w9xpopen.exe, which is " + "needed for Popen to work with your " + "shell or platform.") + return w9xpopen + + def _execute_child(self, args, executable, preexec_fn, close_fds, + cwd, env, universal_newlines, + startupinfo, creationflags, shell, + p2cread, p2cwrite, + c2pread, c2pwrite, + errread, errwrite): + """Execute program (MS Windows version)""" + + if not isinstance(args, str): + args = list2cmdline(args) + + # Process startup details + if startupinfo is None: + startupinfo = STARTUPINFO() + if None not in (p2cread, c2pwrite, errwrite): + startupinfo.dwFlags |= _subprocess.STARTF_USESTDHANDLES + startupinfo.hStdInput = p2cread + startupinfo.hStdOutput = c2pwrite + startupinfo.hStdError = errwrite + + if shell: + startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW + startupinfo.wShowWindow = _subprocess.SW_HIDE + comspec = os.environ.get("COMSPEC", "cmd.exe") + args = '{} /c "{}"'.format(comspec, args) + if (_subprocess.GetVersion() >= 0x80000000 or + os.path.basename(comspec).lower() == "command.com"): + # Win9x, or using command.com on NT. We need to + # use the w9xpopen intermediate program. For more + # information, see KB Q150956 + # (http://web.archive.org/web/20011105084002/http://support.microsoft.com/support/kb/articles/Q150/9/56.asp) + w9xpopen = self._find_w9xpopen() + args = '"%s" %s' % (w9xpopen, args) + # Not passing CREATE_NEW_CONSOLE has been known to + # cause random failures on win9x. Specifically a + # dialog: "Your program accessed mem currently in + # use at xxx" and a hopeful warning about the + # stability of your system. Cost is Ctrl+C wont + # kill children. + creationflags |= _subprocess.CREATE_NEW_CONSOLE + + # Start the process + try: + try: + hp, ht, pid, tid = _subprocess.CreateProcess( + executable, args, + # no special + # security + None, None, + int(not close_fds), + creationflags, + env, + cwd, + startupinfo) + except pywintypes.error as e: + # Translate pywintypes.error to WindowsError, which is + # a subclass of OSError. FIXME: We should really + # translate errno using _sys_errlist (or similar), but + # how can this be done from Python? + raise WindowsError(*e.args) + finally: + # Child is launched. Close the parent's copy of those pipe + # handles that only the child should have open. You need + # to make sure that no handles to the write end of the + # output pipe are maintained in this process or else the + # pipe will not close when the child process exits and the + # ReadFile will hang. + if p2cread is not None: + p2cread.Close() + if c2pwrite is not None: + c2pwrite.Close() + if errwrite is not None: + errwrite.Close() + + # Retain the process handle, but close the thread handle + self._child_created = True + self._handle = hp + self.pid = pid + ht.Close() + + def _internal_poll( + self, _deadstate=None, + _WaitForSingleObject=_subprocess.WaitForSingleObject, + _WAIT_OBJECT_0=_subprocess.WAIT_OBJECT_0, + _GetExitCodeProcess=_subprocess.GetExitCodeProcess + ): + """Check if child process has terminated. Returns returncode + attribute. + + This method is called by __del__, so it can only refer to objects + in its local scope. + + """ + if self.returncode is None: + if _WaitForSingleObject(self._handle, 0) == _WAIT_OBJECT_0: + self.returncode = _GetExitCodeProcess(self._handle) + return self.returncode + + def wait(self): + """Wait for child process to terminate. Returns returncode + attribute.""" + if self.returncode is None: + _subprocess.WaitForSingleObject(self._handle, + _subprocess.INFINITE) + self.returncode = _subprocess.GetExitCodeProcess(self._handle) + return self.returncode + + def _readerthread(self, fh, buffer): + buffer.append(fh.read()) + + def _communicate(self, input): + stdout = None # Return + stderr = None # Return + + if self.stdout: + stdout = [] + stdout_thread = threading.Thread(target=self._readerthread, + args=(self.stdout, stdout)) + stdout_thread.setDaemon(True) + stdout_thread.start() + if self.stderr: + stderr = [] + stderr_thread = threading.Thread(target=self._readerthread, + args=(self.stderr, stderr)) + stderr_thread.setDaemon(True) + stderr_thread.start() + + if self.stdin: + if input is not None: + try: + self.stdin.write(input) + except IOError as e: + if e.errno != errno.EPIPE: + raise + self.stdin.close() + + if self.stdout: + stdout_thread.join() + if self.stderr: + stderr_thread.join() + + # All data exchanged. Translate lists into strings. + if stdout is not None: + stdout = stdout[0] + if stderr is not None: + stderr = stderr[0] + + # Translate newlines, if requested. We cannot let the file + # object do the translation: It is based on stdio, which is + # impossible to combine with select (unless forcing no + # buffering). + if self.universal_newlines and hasattr(file, 'newlines'): + if stdout: + stdout = self._translate_newlines(stdout) + if stderr: + stderr = self._translate_newlines(stderr) + + self.wait() + return (stdout, stderr) + + def send_signal(self, sig): + """Send a signal to the process + """ + if sig == signal.SIGTERM: + self.terminate() + elif sig == signal.CTRL_C_EVENT: + os.kill(self.pid, signal.CTRL_C_EVENT) + elif sig == signal.CTRL_BREAK_EVENT: + os.kill(self.pid, signal.CTRL_BREAK_EVENT) + else: + raise ValueError("Unsupported signal: {}".format(sig)) + + def terminate(self): + """Terminates the process + """ + _subprocess.TerminateProcess(self._handle, 1) + + kill = terminate + + else: + # + # POSIX methods + # + def _get_handles(self, stdin, stdout, stderr): + """Construct and return tuple with IO objects: + p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite + """ + p2cread, p2cwrite = None, None + c2pread, c2pwrite = None, None + errread, errwrite = None, None + + if stdin is None: + pass + elif stdin == PIPE: + p2cread, p2cwrite = self.pipe_cloexec() + elif isinstance(stdin, int): + p2cread = stdin + else: + # Assuming file-like object + p2cread = stdin.fileno() + + if stdout is None: + pass + elif stdout == PIPE: + c2pread, c2pwrite = self.pipe_cloexec() + elif isinstance(stdout, int): + c2pwrite = stdout + else: + # Assuming file-like object + c2pwrite = stdout.fileno() + + if stderr is None: + pass + elif stderr == PIPE: + errread, errwrite = self.pipe_cloexec() + elif stderr == STDOUT: + errwrite = c2pwrite + elif isinstance(stderr, int): + errwrite = stderr + else: + # Assuming file-like object + errwrite = stderr.fileno() + + return (p2cread, p2cwrite, + c2pread, c2pwrite, + errread, errwrite) + + def _set_cloexec_flag(self, fd, cloexec=True): + try: + cloexec_flag = fcntl.FD_CLOEXEC + except AttributeError: + cloexec_flag = 1 + + old = fcntl.fcntl(fd, fcntl.F_GETFD) + if cloexec: + fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag) + else: + fcntl.fcntl(fd, fcntl.F_SETFD, old & ~cloexec_flag) + + def pipe_cloexec(self): + """Create a pipe with FDs set CLOEXEC.""" + # Pipes' FDs are set CLOEXEC by default because we don't want them + # to be inherited by other subprocesses: the CLOEXEC flag is + # removed from the child's FDs by _dup2(), between fork() and + # exec(). + # This is not atomic: we would need the pipe2() syscall for that. + r, w = os.pipe() + self._set_cloexec_flag(r) + self._set_cloexec_flag(w) + return r, w + + def _close_fds(self, but): + if hasattr(os, 'closerange'): + os.closerange(3, but) + os.closerange(but + 1, MAXFD) + else: + for i in range(3, MAXFD): + if i == but: + continue + try: + os.close(i) + except: + pass + + def _execute_child(self, args, executable, preexec_fn, close_fds, + cwd, env, universal_newlines, + startupinfo, creationflags, shell, + p2cread, p2cwrite, + c2pread, c2pwrite, + errread, errwrite): + """Execute program (POSIX version)""" + + if isinstance(args, str): + args = [args] + else: + args = list(args) + + if shell: + args = ["/bin/sh", "-c"] + args + if executable: + args[0] = executable + + if executable is None: + executable = args[0] + + # For transferring possible exec failure from child to parent + # The first char specifies the exception type: 0 means + # OSError, 1 means some other error. + errpipe_read, errpipe_write = self.pipe_cloexec() + try: + try: + gc_was_enabled = gc.isenabled() + # Disable gc to avoid bug where gc -> file_dealloc -> + # write to stderr -> hang. + # http://bugs.python.org/issue1336 + gc.disable() + try: + self.pid = os.fork() + except: + if gc_was_enabled: + gc.enable() + raise + self._child_created = True + if self.pid == 0: + # Child + try: + # Close parent's pipe ends + if p2cwrite is not None: + os.close(p2cwrite) + if c2pread is not None: + os.close(c2pread) + if errread is not None: + os.close(errread) + os.close(errpipe_read) + + # When duping fds, if there arises a situation + # where one of the fds is either 0, 1 or 2, it + # is possible that it is overwritten (#12607). + if c2pwrite == 0: + c2pwrite = os.dup(c2pwrite) + if errwrite == 0 or errwrite == 1: + errwrite = os.dup(errwrite) + + # Dup fds for child + def _dup2(a, b): + # dup2() removes the CLOEXEC flag but + # we must do it ourselves if dup2() + # would be a no-op (issue #10806). + if a == b: + self._set_cloexec_flag(a, False) + elif a is not None: + os.dup2(a, b) + _dup2(p2cread, 0) + _dup2(c2pwrite, 1) + _dup2(errwrite, 2) + + # Close pipe fds. Make sure we don't close the + # same fd more than once, or standard fds. + closed = set([None]) + for fd in [p2cread, c2pwrite, errwrite]: + if fd not in closed and fd > 2: + os.close(fd) + closed.add(fd) + + # Close all other fds, if asked for + if close_fds: + self._close_fds(but=errpipe_write) + + if cwd is not None: + os.chdir(cwd) + + if preexec_fn: + preexec_fn() + + if env is None: + os.execvp(executable, args) + else: + os.execvpe(executable, args, env) + + except: + exc_type, exc_value, tb = sys.exc_info() + # Save the traceback and attach it to the exception + # object + exc_lines = traceback.format_exception(exc_type, + exc_value, + tb) + exc_value.child_traceback = ''.join(exc_lines) + os.write(errpipe_write, pickle.dumps(exc_value)) + + # This exitcode won't be reported to applications, + # so it really doesn't matter what we return. + os._exit(255) + + # Parent + if gc_was_enabled: + gc.enable() + finally: + # be sure the FD is closed no matter what + os.close(errpipe_write) + + if p2cread is not None and p2cwrite is not None: + os.close(p2cread) + if c2pwrite is not None and c2pread is not None: + os.close(c2pwrite) + if errwrite is not None and errread is not None: + os.close(errwrite) + + # Wait for exec to fail or succeed; possibly raising exception + # Exception limited to 1M + data = _eintr_retry_call(os.read, errpipe_read, 1048576) + finally: + # be sure the FD is closed no matter what + os.close(errpipe_read) + + if data != "": + try: + _eintr_retry_call(os.waitpid, self.pid, 0) + except OSError as e: + if e.errno != errno.ECHILD: + raise + child_exception = pickle.loads(data) + for fd in (p2cwrite, c2pread, errread): + if fd is not None: + os.close(fd) + raise child_exception + + def _handle_exitstatus(self, sts, _WIFSIGNALED=os.WIFSIGNALED, + _WTERMSIG=os.WTERMSIG, _WIFEXITED=os.WIFEXITED, + _WEXITSTATUS=os.WEXITSTATUS): + # This method is called (indirectly) by __del__, so it cannot + # refer to anything outside of its local scope.""" + if _WIFSIGNALED(sts): + self.returncode = -_WTERMSIG(sts) + elif _WIFEXITED(sts): + self.returncode = _WEXITSTATUS(sts) + else: + # Should never happen + raise RuntimeError("Unknown child exit status!") + + def _internal_poll(self, _deadstate=None, _waitpid=os.waitpid, + _WNOHANG=os.WNOHANG, _os_error=os.error): + """Check if child process has terminated. Returns returncode + attribute. + + This method is called by __del__, so it cannot reference anything + outside of the local scope (nor can any methods it calls). + + """ + if self.returncode is None: + try: + pid, sts = _waitpid(self.pid, _WNOHANG) + if pid == self.pid: + self._handle_exitstatus(sts) + except _os_error: + if _deadstate is not None: + self.returncode = _deadstate + return self.returncode + + def wait(self): + """Wait for child process to terminate. Returns returncode + attribute.""" + if self.returncode is None: + try: + pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0) + except OSError as e: + if e.errno != errno.ECHILD: + raise + # This happens if SIGCLD is set to be ignored or waiting + # for child processes has otherwise been disabled for our + # process. This child is dead, we can't get the status. + sts = 0 + self._handle_exitstatus(sts) + return self.returncode + + def _communicate(self, input): + if self.stdin: + # Flush stdio buffer. This might block, if the user has + # been writing to .stdin in an uncontrolled fashion. + self.stdin.flush() + if not input: + self.stdin.close() + + if _has_poll: + stdout, stderr = self._communicate_with_poll(input) + else: + stdout, stderr = self._communicate_with_select(input) + + # All data exchanged. Translate lists into strings. + if stdout is not None: + stdout = ''.join(stdout) + if stderr is not None: + stderr = ''.join(stderr) + + # Translate newlines, if requested. We cannot let the file + # object do the translation: It is based on stdio, which is + # impossible to combine with select (unless forcing no + # buffering). + if self.universal_newlines and hasattr(file, 'newlines'): + if stdout: + stdout = self._translate_newlines(stdout) + if stderr: + stderr = self._translate_newlines(stderr) + + self.wait() + return (stdout, stderr) + + def _communicate_with_poll(self, input): + stdout = None # Return + stderr = None # Return + fd2file = {} + fd2output = {} + + poller = select.poll() + + def register_and_append(file_obj, eventmask): + poller.register(file_obj.fileno(), eventmask) + fd2file[file_obj.fileno()] = file_obj + + def close_unregister_and_remove(fd): + poller.unregister(fd) + fd2file[fd].close() + fd2file.pop(fd) + + if self.stdin and input: + register_and_append(self.stdin, select.POLLOUT) + + select_POLLIN_POLLPRI = select.POLLIN | select.POLLPRI + if self.stdout: + register_and_append(self.stdout, select_POLLIN_POLLPRI) + fd2output[self.stdout.fileno()] = stdout = [] + if self.stderr: + register_and_append(self.stderr, select_POLLIN_POLLPRI) + fd2output[self.stderr.fileno()] = stderr = [] + + input_offset = 0 + while fd2file: + try: + ready = poller.poll() + except select.error as e: + if e.args[0] == errno.EINTR: + continue + raise + + for fd, mode in ready: + if mode & select.POLLOUT: + chunk = input[input_offset: input_offset + _PIPE_BUF] + try: + input_offset += os.write(fd, chunk) + except OSError as e: + if e.errno == errno.EPIPE: + close_unregister_and_remove(fd) + else: + raise + else: + if input_offset >= len(input): + close_unregister_and_remove(fd) + elif mode & select_POLLIN_POLLPRI: + data = os.read(fd, 4096) + if not data: + close_unregister_and_remove(fd) + fd2output[fd].append(data) + else: + # Ignore hang up or errors. + close_unregister_and_remove(fd) + + return (stdout, stderr) + + def _communicate_with_select(self, input): + read_set = [] + write_set = [] + stdout = None # Return + stderr = None # Return + + if self.stdin and input: + write_set.append(self.stdin) + if self.stdout: + read_set.append(self.stdout) + stdout = [] + if self.stderr: + read_set.append(self.stderr) + stderr = [] + + input_offset = 0 + while read_set or write_set: + try: + rlist, wlist, xlist = select.select( + read_set, write_set, []) + except select.error as e: + if e.args[0] == errno.EINTR: + continue + raise + + if self.stdin in wlist: + chunk = input[input_offset: input_offset + _PIPE_BUF] + try: + bytes_written = os.write(self.stdin.fileno(), chunk) + except OSError as e: + if e.errno == errno.EPIPE: + self.stdin.close() + write_set.remove(self.stdin) + else: + raise + else: + input_offset += bytes_written + if input_offset >= len(input): + self.stdin.close() + write_set.remove(self.stdin) + + if self.stdout in rlist: + data = os.read(self.stdout.fileno(), 1024) + if data == "": + self.stdout.close() + read_set.remove(self.stdout) + stdout.append(data) + + if self.stderr in rlist: + data = os.read(self.stderr.fileno(), 1024) + if data == "": + self.stderr.close() + read_set.remove(self.stderr) + stderr.append(data) + + return (stdout, stderr) + + def send_signal(self, sig): + """Send a signal to the process + """ + os.kill(self.pid, sig) + + def terminate(self): + """Terminate the process with SIGTERM + """ + self.send_signal(signal.SIGTERM) + + def kill(self): + """Kill the process with SIGKILL + """ + self.send_signal(signal.SIGKILL) + + +def _demo_posix(): + # + # Example 1: Simple redirection: Get process list + # + plist = Popen(["ps"], stdout=PIPE).communicate()[0] + print("Process list:") + print(plist) + + # + # Example 2: Change uid before executing child + # + if os.getuid() == 0: + p = Popen(["id"], preexec_fn=lambda: os.setuid(100)) + p.wait() + + # + # Example 3: Connecting several subprocesses + # + print("Looking for 'hda'...") + p1 = Popen(["dmesg"], stdout=PIPE) + p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) + print(repr(p2.communicate()[0])) + + # + # Example 4: Catch execution error + # + print() + print("Trying a weird file...") + try: + print(Popen(["/this/path/does/not/exist"]).communicate()) + except OSError as e: + if e.errno == errno.ENOENT: + print("The file didn't exist. I thought so...") + print("Child traceback:") + print(e.child_traceback) + else: + print("Error", e.errno) + else: + print("Gosh. No error.", file=sys.stderr) + + +def _demo_windows(): + # + # Example 1: Connecting several subprocesses + # + print("Looking for 'PROMPT' in set output...") + p1 = Popen("set", stdout=PIPE, shell=True) + p2 = Popen('find "PROMPT"', stdin=p1.stdout, stdout=PIPE) + print(repr(p2.communicate()[0])) + + # + # Example 2: Simple execution of program + # + print("Executing calc...") + p = Popen("calc") + p.wait() + + +if __name__ == "__main__": + if mswindows: + _demo_windows() + else: + _demo_posix() diff --git a/libs/cherrypy/_cpconfig.py b/libs/cherrypy/_cpconfig.py index c11bc1d..4025200 100644 --- a/libs/cherrypy/_cpconfig.py +++ b/libs/cherrypy/_cpconfig.py @@ -119,7 +119,7 @@ def index(self): """ import cherrypy -from cherrypy._cpcompat import set, basestring +from cherrypy._cpcompat import set, str from cherrypy.lib import reprconf # Deprecated in CherryPy 3.2--remove in 3.3 @@ -132,11 +132,11 @@ def merge(base, other): If the given config is a filename, it will be appended to the list of files to monitor for "autoreload" changes. """ - if isinstance(other, basestring): + if isinstance(other, str): cherrypy.engine.autoreload.files.add(other) # Load other into base - for section, value_map in reprconf.as_dict(other).items(): + for section, value_map in list(reprconf.as_dict(other).items()): if not isinstance(value_map, dict): raise ValueError( "Application config must include section headers, but the " @@ -152,7 +152,7 @@ class Config(reprconf.Config): def update(self, config): """Update self from a dict, file or filename.""" - if isinstance(config, basestring): + if isinstance(config, str): # Filename cherrypy.engine.autoreload.files.add(config) reprconf.Config.update(self, config) @@ -177,7 +177,7 @@ def __call__(self, *args, **kwargs): def tool_decorator(f): if not hasattr(f, "_cp_config"): f._cp_config = {} - for k, v in kwargs.items(): + for k, v in list(kwargs.items()): f._cp_config[k] = v return f return tool_decorator @@ -307,7 +307,7 @@ def _engine_namespace_handler(k, v): def _tree_namespace_handler(k, v): """Namespace handler for the 'tree' config namespace.""" if isinstance(v, dict): - for script_name, app in v.items(): + for script_name, app in list(v.items()): cherrypy.tree.graft(app, script_name) cherrypy.engine.log("Mounted: %s on %s" % (app, script_name or "/")) diff --git a/libs/cherrypy/_cpdispatch.py b/libs/cherrypy/_cpdispatch.py index 1c2d7df..652d1a0 100644 --- a/libs/cherrypy/_cpdispatch.py +++ b/libs/cherrypy/_cpdispatch.py @@ -13,7 +13,7 @@ import sys import types try: - classtype = (type, types.ClassType) + classtype = (type, type) except AttributeError: classtype = type @@ -117,7 +117,7 @@ def test_callable_spec(callable, callable_args, callable_kwargs): except IndexError: vararg_usage += 1 - for key in callable_kwargs.keys(): + for key in list(callable_kwargs.keys()): try: arg_usage[key] += 1 except KeyError: @@ -133,7 +133,7 @@ def test_callable_spec(callable, callable_args, callable_kwargs): missing_args = [] multiple_args = [] - for key, usage in arg_usage.items(): + for key, usage in list(arg_usage.items()): if usage == 0: missing_args.append(key) elif usage > 1: diff --git a/libs/cherrypy/_cperror.py b/libs/cherrypy/_cperror.py index 6256595..ee41190 100644 --- a/libs/cherrypy/_cperror.py +++ b/libs/cherrypy/_cperror.py @@ -118,7 +118,7 @@ class Root: from cgi import escape as _escape from sys import exc_info as _exc_info from traceback import format_exception as _format_exception -from cherrypy._cpcompat import basestring, bytestr, iteritems, ntob +from cherrypy._cpcompat import str, bytestr, iteritems, ntob from cherrypy._cpcompat import tonative, urljoin as _urljoin from cherrypy.lib import httputil as _httputil @@ -206,7 +206,7 @@ def __init__(self, urls, status=None, encoding=None): import cherrypy request = cherrypy.serving.request - if isinstance(urls, basestring): + if isinstance(urls, str): urls = [urls] abs_urls = [] diff --git a/libs/cherrypy/_cplogging.py b/libs/cherrypy/_cplogging.py index 554fd7e..4a8bbdf 100644 --- a/libs/cherrypy/_cplogging.py +++ b/libs/cherrypy/_cplogging.py @@ -259,7 +259,7 @@ def access(self): 'o': dict.get(inheaders, 'Host', '-'), } if py3k: - for k, v in atoms.items(): + for k, v in list(atoms.items()): if not isinstance(v, str): v = str(v) v = v.replace('"', '\\"').encode('utf8') @@ -281,8 +281,8 @@ def access(self): except: self(traceback=True) else: - for k, v in atoms.items(): - if isinstance(v, unicode): + for k, v in list(atoms.items()): + if isinstance(v, str): v = v.encode('utf8') elif not isinstance(v, str): v = str(v) diff --git a/libs/cherrypy/_cpmodpy.py b/libs/cherrypy/_cpmodpy.py index 02154d6..2dbb563 100644 --- a/libs/cherrypy/_cpmodpy.py +++ b/libs/cherrypy/_cpmodpy.py @@ -261,7 +261,7 @@ def send_response(req, status, headers, body, stream=False): req.flush() # Set response body - if isinstance(body, basestring): + if isinstance(body, str): req.write(body) else: for seg in body: diff --git a/libs/cherrypy/_cpnative_server.py b/libs/cherrypy/_cpnative_server.py index e303573..87f8484 100644 --- a/libs/cherrypy/_cpnative_server.py +++ b/libs/cherrypy/_cpnative_server.py @@ -32,7 +32,7 @@ def respond(self): method = req.method path = req.path qs = req.qs or "" - headers = req.inheaders.items() + headers = list(req.inheaders.items()) rfile = req.rfile prev = None diff --git a/libs/cherrypy/_cpreqbody.py b/libs/cherrypy/_cpreqbody.py index d2dbbc9..0c2de6b 100644 --- a/libs/cherrypy/_cpreqbody.py +++ b/libs/cherrypy/_cpreqbody.py @@ -116,7 +116,7 @@ def json_processor(entity): import sys import tempfile try: - from urllib import unquote_plus + from urllib.parse import unquote_plus except ImportError: def unquote_plus(bs): """Bytes version of urllib.parse.unquote_plus.""" @@ -132,7 +132,7 @@ def unquote_plus(bs): return ntob('').join(atoms) import cherrypy -from cherrypy._cpcompat import basestring, ntob, ntou +from cherrypy._cpcompat import str, ntob, ntou from cherrypy.lib import httputil @@ -174,7 +174,7 @@ def process_urlencoded(entity): # Now that all values have been successfully parsed and decoded, # apply them to the entity.params dict. - for key, value in params.items(): + for key, value in list(params.items()): if key in entity.params: if not isinstance(entity.params[key], list): entity.params[key] = [entity.params[key]] @@ -491,7 +491,7 @@ def __next__(self): raise StopIteration return line - def next(self): + def __next__(self): return self.__next__() def read_into_file(self, fp_out=None): @@ -710,7 +710,7 @@ def default_proc(self): self.file = self.read_into_file() else: result = self.read_lines_to_boundary() - if isinstance(result, basestring): + if isinstance(result, str): self.value = result else: self.file = result @@ -998,11 +998,11 @@ def process(self): # Body params should also be a part of the request_params # add them in here. request_params = self.request_params - for key, value in self.params.items(): + for key, value in list(self.params.items()): # Python 2 only: keyword arguments must be byte strings (type # 'str'). if sys.version_info < (3, 0): - if isinstance(key, unicode): + if isinstance(key, str): key = key.encode('ISO-8859-1') if key in request_params: diff --git a/libs/cherrypy/_cprequest.py b/libs/cherrypy/_cprequest.py index 290bd2e..ba2a450 100644 --- a/libs/cherrypy/_cprequest.py +++ b/libs/cherrypy/_cprequest.py @@ -5,7 +5,7 @@ import warnings import cherrypy -from cherrypy._cpcompat import basestring, copykeys, ntob, unicodestr +from cherrypy._cpcompat import str, copykeys, ntob, unicodestr from cherrypy._cpcompat import SimpleCookie, CookieError, py3k from cherrypy import _cpreqbody, _cpconfig from cherrypy._cperror import format_exc, bare_error @@ -68,7 +68,7 @@ def __repr__(self): % (cls.__module__, cls.__name__, self.callback, self.failsafe, self.priority, ", ".join(['%s=%r' % (k, v) - for k, v in self.kwargs.items()]))) + for k, v in list(self.kwargs.items())]))) class HookMap(dict): @@ -117,7 +117,7 @@ def __copy__(self): newmap = self.__class__() # We can't just use 'update' because we want copies of the # mutable values (each is a list) as well. - for k, v in self.items(): + for k, v in list(self.items()): newmap[k] = v[:] return newmap copy = __copy__ @@ -139,7 +139,7 @@ def hooks_namespace(k, v): # hookpoint per path (e.g. "hooks.before_handler.1"). # Little-known fact you only get from reading source ;) hookpoint = k.split(".", 1)[0] - if isinstance(v, basestring): + if isinstance(v, str): v = cherrypy.lib.attributes(v) if not isinstance(v, Hook): v = Hook(v) @@ -702,8 +702,8 @@ def process_query_string(self): # Python 2 only: keyword arguments must be byte strings (type 'str'). if not py3k: - for key, value in p.items(): - if isinstance(key, unicode): + for key, value in list(p.items()): + if isinstance(key, str): del p[key] p[key.encode(self.query_string_encoding)] = value self.params.update(p) @@ -815,7 +815,7 @@ def __set__(self, obj, value): if py3k and isinstance(value, str): raise ValueError(self.unicode_err) - if isinstance(value, basestring): + if isinstance(value, str): # strings get wrapped in a list because iterating over a single # item list is much faster than iterating over every character # in a long string. @@ -901,7 +901,7 @@ def __init__(self): def collapse_body(self): """Collapse self.body to a single string; replace it and return it.""" - if isinstance(self.body, basestring): + if isinstance(self.body, str): return self.body newbody = [] diff --git a/libs/cherrypy/_cpserver.py b/libs/cherrypy/_cpserver.py index a31e742..8413925 100644 --- a/libs/cherrypy/_cpserver.py +++ b/libs/cherrypy/_cpserver.py @@ -4,7 +4,7 @@ import cherrypy from cherrypy.lib import attributes -from cherrypy._cpcompat import basestring, py3k +from cherrypy._cpcompat import str, py3k # We import * because we want to export check_port # et al as attributes of this module. @@ -156,7 +156,7 @@ def httpserver_from_self(self, httpserver=None): if httpserver is None: from cherrypy import _cpwsgi_server httpserver = _cpwsgi_server.CPWSGIServer(self) - if isinstance(httpserver, basestring): + if isinstance(httpserver, str): # Is anyone using this? Can I add an arg? httpserver = attributes(httpserver)(self) return httpserver, self.bind_addr @@ -180,7 +180,7 @@ def _set_bind_addr(self, value): self.socket_file = None self.socket_host = None self.socket_port = None - elif isinstance(value, basestring): + elif isinstance(value, str): self.socket_file = value self.socket_host = None self.socket_port = None diff --git a/libs/cherrypy/_cptools.py b/libs/cherrypy/_cptools.py index 06a56e8..5ae3e05 100644 --- a/libs/cherrypy/_cptools.py +++ b/libs/cherrypy/_cptools.py @@ -38,8 +38,8 @@ def _getargs(func): co = func.__code__ else: if isinstance(func, types.MethodType): - func = func.im_func - co = func.func_code + func = func.__func__ + co = func.__code__ return co.co_varnames[:co.co_argcount] @@ -128,7 +128,7 @@ def tool_decorator(f): f._cp_config = {} subspace = self.namespace + "." + self._name + "." f._cp_config[subspace + "on"] = True - for k, v in kwargs.items(): + for k, v in list(kwargs.items()): f._cp_config[subspace + k] = v return f return tool_decorator @@ -321,7 +321,7 @@ def regenerate(self): sess.regenerate() # Grab cookie-relevant tool args - conf = dict([(k, v) for k, v in self._merged_args().items() + conf = dict([(k, v) for k, v in list(self._merged_args().items()) if k in ('path', 'path_header', 'name', 'timeout', 'domain', 'secure')]) _sessions.set_response_cookie(**conf) @@ -455,7 +455,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): """Run tool._setup() for each tool in our toolmap.""" map = cherrypy.serving.request.toolmaps.get(self.namespace) if map: - for name, settings in map.items(): + for name, settings in list(map.items()): if settings.get("on", False): tool = getattr(self, name) tool._setup() diff --git a/libs/cherrypy/_cptree.py b/libs/cherrypy/_cptree.py index a31b279..6b42afc 100644 --- a/libs/cherrypy/_cptree.py +++ b/libs/cherrypy/_cptree.py @@ -124,7 +124,7 @@ def get_serving(self, local, remote, scheme, sproto): req = self.request_class(local, remote, scheme, sproto) req.app = self - for name, toolbox in self.toolboxes.items(): + for name, toolbox in list(self.toolboxes.items()): req.namespaces[name] = toolbox resp = self.response_class() diff --git a/libs/cherrypy/_cpwsgi.py b/libs/cherrypy/_cpwsgi.py index f6db68b..cf9d8a6 100644 --- a/libs/cherrypy/_cpwsgi.py +++ b/libs/cherrypy/_cpwsgi.py @@ -169,7 +169,7 @@ def __next__(self): return self.trap(next, self.iter_response) else: def next(self): - return self.trap(self.iter_response.next) + return self.trap(self.iter_response.__next__) def close(self): if hasattr(self.response, 'close'): @@ -274,7 +274,7 @@ def __next__(self): return next(self.iter_response) else: def next(self): - return self.iter_response.next() + return next(self.iter_response) def close(self): """Close and de-reference the current request and response. (Core)""" diff --git a/libs/cherrypy/daemon.py b/libs/cherrypy/daemon.py index d71e632..ac00b8c 100644 --- a/libs/cherrypy/daemon.py +++ b/libs/cherrypy/daemon.py @@ -19,7 +19,7 @@ def start(configfiles=None, daemonize=False, environment=None, cherrypy.config.update(c) # If there's only one app mounted, merge config into it. if len(cherrypy.tree.apps) == 1: - for app in cherrypy.tree.apps.values(): + for app in list(cherrypy.tree.apps.values()): if isinstance(app, Application): app.merge(c) diff --git a/libs/cherrypy/lib/__init__.py b/libs/cherrypy/lib/__init__.py index a75a53d..5c71d40 100644 --- a/libs/cherrypy/lib/__init__.py +++ b/libs/cherrypy/lib/__init__.py @@ -2,6 +2,7 @@ # Deprecated in CherryPy 3.2 -- remove in CherryPy 3.3 from cherrypy.lib.reprconf import unrepr, modules, attributes +import collections def is_iterator(obj): '''Returns a boolean indicating if the object provided implements @@ -29,7 +30,7 @@ def is_closable_iterator(obj): return True # A custom iterator. Look for a close method... - if not (hasattr(obj, 'close') and callable(obj.close)): + if not (hasattr(obj, 'close') and isinstance(obj.close, collections.Callable)): return False # ... which doesn't require any arguments. diff --git a/libs/cherrypy/lib/caching.py b/libs/cherrypy/lib/caching.py index fab6b56..5a5a82a 100644 --- a/libs/cherrypy/lib/caching.py +++ b/libs/cherrypy/lib/caching.py @@ -296,7 +296,7 @@ def get(invalid_methods=("POST", "PUT", "DELETE"), debug=False, **kwargs): cherrypy._cache = kwargs.pop("cache_class", MemoryCache)() # Take all remaining kwargs and set them on the Cache object. - for k, v in kwargs.items(): + for k, v in list(kwargs.items()): setattr(cherrypy._cache, k, v) cherrypy._cache.debug = debug diff --git a/libs/cherrypy/lib/covercp.py b/libs/cherrypy/lib/covercp.py index a74ec34..332adaa 100644 --- a/libs/cherrypy/lib/covercp.py +++ b/libs/cherrypy/lib/covercp.py @@ -197,7 +197,7 @@ def _show_branch(root, base, path, pct=0, showpct=False, exclude="", coverage=the_coverage): # Show the directory name and any of our children - dirs = [k for k, v in root.items() if v] + dirs = [k for k, v in list(root.items()) if v] dirs.sort() for name in dirs: newpath = os.path.join(path, name) @@ -220,7 +220,7 @@ def _show_branch(root, base, path, pct=0, showpct=False, exclude="", # Now list the files if path.lower().startswith(base): relpath = path[len(base):] - files = [k for k, v in root.items() if not v] + files = [k for k, v in list(root.items()) if not v] files.sort() for name in files: newpath = os.path.join(path, name) diff --git a/libs/cherrypy/lib/cpstats.py b/libs/cherrypy/lib/cpstats.py index a8661a1..7e8d111 100644 --- a/libs/cherrypy/lib/cpstats.py +++ b/libs/cherrypy/lib/cpstats.py @@ -285,8 +285,8 @@ def close(self): def __iter__(self): return self - def next(self): - data = self.rfile.next() + def __next__(self): + data = next(self.rfile) self.bytes_read += len(data) return data @@ -605,7 +605,7 @@ def get_dict_collection(self, v, formatting): """Return ([headers], [rows]) for the given collection.""" # E.g., the 'Requests' dict. headers = [] - for record in v.itervalues(): + for record in list(v.values()): for k3 in record: format = formatting.get(k3, missing) if format is None: diff --git a/libs/cherrypy/lib/cptools.py b/libs/cherrypy/lib/cptools.py index f376282..700c9ec 100644 --- a/libs/cherrypy/lib/cptools.py +++ b/libs/cherrypy/lib/cptools.py @@ -4,7 +4,7 @@ import re import cherrypy -from cherrypy._cpcompat import basestring, md5, set, unicodestr +from cherrypy._cpcompat import str, md5, set, unicodestr from cherrypy.lib import httputil as _httputil from cherrypy.lib import is_iterator @@ -404,7 +404,7 @@ def run(self): def session_auth(**kwargs): sa = SessionAuth() - for k, v in kwargs.items(): + for k, v in list(kwargs.items()): setattr(sa, k, v) return sa.run() session_auth.__doc__ = """Session authentication hook. @@ -435,7 +435,7 @@ def log_hooks(debug=False): # Sort by the standard points if possible. from cherrypy import _cprequest points = _cprequest.hookpoints - for k in request.hooks.keys(): + for k in list(request.hooks.keys()): if k not in points: points.append(k) @@ -531,7 +531,7 @@ def accept(media=None, debug=False): """ if not media: return - if isinstance(media, basestring): + if isinstance(media, str): media = [media] request = cherrypy.serving.request diff --git a/libs/cherrypy/lib/encoding.py b/libs/cherrypy/lib/encoding.py index a4c2cbd..9631b9d 100644 --- a/libs/cherrypy/lib/encoding.py +++ b/libs/cherrypy/lib/encoding.py @@ -2,7 +2,7 @@ import time import cherrypy -from cherrypy._cpcompat import basestring, BytesIO, ntob, set, unicodestr +from cherrypy._cpcompat import str, BytesIO, ntob, set, unicodestr from cherrypy.lib import file_generator from cherrypy.lib import is_closable_iterator from cherrypy.lib import set_vary_header @@ -41,7 +41,7 @@ def __init__(self, iterator): def __iter__(self): return self - def next(self): + def __next__(self): return self.__next__() def __next__(self): @@ -71,7 +71,7 @@ class ResponseEncoder: debug = False def __init__(self, **kwargs): - for k, v in kwargs.items(): + for k, v in list(kwargs.items()): setattr(self, k, v) self.attempted_charsets = set() @@ -216,7 +216,7 @@ def __call__(self, *args, **kwargs): response = cherrypy.serving.response self.body = self.oldhandler(*args, **kwargs) - if isinstance(self.body, basestring): + if isinstance(self.body, str): # strings get wrapped in a list because iterating over a single # item list is much faster than iterating over every character # in a long string. diff --git a/libs/cherrypy/lib/gctools.py b/libs/cherrypy/lib/gctools.py index 4b616c5..9f920fb 100644 --- a/libs/cherrypy/lib/gctools.py +++ b/libs/cherrypy/lib/gctools.py @@ -41,7 +41,7 @@ def ascend(self, obj, depth=1): try: ascendcode = self.ascend.__code__ except AttributeError: - ascendcode = self.ascend.im_func.func_code + ascendcode = self.ascend.__func__.__code__ for parent in refs: if inspect.isframe(parent) and parent.f_code is ascendcode: continue @@ -74,7 +74,7 @@ def _format(self, obj, descend=True): if isinstance(obj, dict): return "{" + ", ".join(["%s: %s" % (self._format(k, descend=False), self._format(v, descend=False)) - for k, v in obj.items()]) + "}" + for k, v in list(obj.items())]) + "}" elif isinstance(obj, list): return "[" + ", ".join([self._format(item, descend=False) for item in obj]) + "]" @@ -174,7 +174,7 @@ def stats(self): trash[type(x)] = trash.get(type(x), 0) + 1 if trash: output.insert(0, "\n%s unreachable objects:" % unreachable) - trash = [(v, k) for k, v in trash.items()] + trash = [(v, k) for k, v in list(trash.items())] trash.sort() for pair in trash: output.append(" " + repr(pair)) diff --git a/libs/cherrypy/lib/httputil.py b/libs/cherrypy/lib/httputil.py index 69a18d4..c1e7ff6 100644 --- a/libs/cherrypy/lib/httputil.py +++ b/libs/cherrypy/lib/httputil.py @@ -9,7 +9,7 @@ from binascii import b2a_base64 from cherrypy._cpcompat import BaseHTTPRequestHandler, HTTPDate, ntob, ntou -from cherrypy._cpcompat import basestring, bytestr, iteritems, nativestr +from cherrypy._cpcompat import str, bytestr, iteritems, nativestr from cherrypy._cpcompat import reversed, sorted, unicodestr, unquote_qs response_codes = BaseHTTPRequestHandler.responses.copy() @@ -23,7 +23,7 @@ 'maintenance of the server.') import re -import urllib +import urllib.request, urllib.parse, urllib.error def urljoin(*atoms): @@ -393,7 +393,7 @@ def has_key(self, key): return str(key).title() in self def update(self, E): - for k in E.keys(): + for k in list(E.keys()): self[str(k).title()] = E[k] def fromkeys(cls, seq, value=None): @@ -421,12 +421,12 @@ def pop(self, key, default): # field continuation. It is expected that the folding LWS will be # replaced with a single SP before interpretation of the TEXT value." if nativestr == bytestr: - header_translate_table = ''.join([chr(i) for i in xrange(256)]) + header_translate_table = ''.join([chr(i) for i in range(256)]) header_translate_deletechars = ''.join( - [chr(i) for i in xrange(32)]) + chr(127) + [chr(i) for i in range(32)]) + chr(127) else: header_translate_table = None - header_translate_deletechars = bytes(range(32)) + bytes([127]) + header_translate_deletechars = bytes(list(range(32))) + bytes([127]) class HeaderMap(CaseInsensitiveDict): @@ -461,7 +461,7 @@ def values(self, key): def output(self): """Transform self into a list of (name, value) tuples.""" - return list(self.encode_header_items(self.items())) + return list(self.encode_header_items(list(self.items()))) def encode_header_items(cls, header_items): """ @@ -472,7 +472,7 @@ def encode_header_items(cls, header_items): if isinstance(k, unicodestr): k = cls.encode(k) - if not isinstance(v, basestring): + if not isinstance(v, str): v = str(v) if isinstance(v, unicodestr): diff --git a/libs/cherrypy/lib/jsontools.py b/libs/cherrypy/lib/jsontools.py index 90b3ff8..89c8719 100644 --- a/libs/cherrypy/lib/jsontools.py +++ b/libs/cherrypy/lib/jsontools.py @@ -1,5 +1,5 @@ import cherrypy -from cherrypy._cpcompat import basestring, ntou, json_encode, json_decode +from cherrypy._cpcompat import str, ntou, json_encode, json_decode def json_processor(entity): @@ -41,13 +41,13 @@ def json_in(content_type=[ntou('application/json'), ntou('text/javascript')], package importable; otherwise, ValueError is raised during processing. """ request = cherrypy.serving.request - if isinstance(content_type, basestring): + if isinstance(content_type, str): content_type = [content_type] if force: if debug: cherrypy.log('Removing body processors %s' % - repr(request.body.processors.keys()), 'TOOLS.JSON_IN') + repr(list(request.body.processors.keys())), 'TOOLS.JSON_IN') request.body.processors.clear() request.body.default_proc = cherrypy.HTTPError( 415, 'Expected an entity of content type %s' % diff --git a/libs/cherrypy/lib/reprconf.py b/libs/cherrypy/lib/reprconf.py index 6e70b5e..a45ea2b 100644 --- a/libs/cherrypy/lib/reprconf.py +++ b/libs/cherrypy/lib/reprconf.py @@ -22,7 +22,7 @@ # Python 3.0+ from configparser import ConfigParser except ImportError: - from ConfigParser import ConfigParser + from configparser import ConfigParser try: set @@ -30,16 +30,16 @@ from sets import Set as set try: - basestring + str except NameError: - basestring = str + str = str try: # Python 3 import builtins except ImportError: # Python 2 - import __builtin__ as builtins + import builtins as builtins import operator as _operator import sys @@ -47,7 +47,7 @@ def as_dict(config): """Return a dict from 'config' whether it is a dict, file, or filename.""" - if isinstance(config, basestring): + if isinstance(config, str): config = Parser().dict_from_file(config) elif hasattr(config, 'read'): config = Parser().dict_from_file(config) @@ -94,14 +94,14 @@ def __call__(self, config): # with handler as callable: # for k, v in ns_confs.get(ns, {}).iteritems(): # callable(k, v) - for ns, handler in self.items(): + for ns, handler in list(self.items()): exit = getattr(handler, "__exit__", None) if exit: callable = handler.__enter__() no_exc = True try: try: - for k, v in ns_confs.get(ns, {}).items(): + for k, v in list(ns_confs.get(ns, {}).items()): callable(k, v) except: # The exceptional case is handled here @@ -116,7 +116,7 @@ def __call__(self, config): if no_exc and exit: exit(None, None, None) else: - for k, v in ns_confs.get(ns, {}).items(): + for k, v in list(ns_confs.get(ns, {}).items()): handler(k, v) def __repr__(self): @@ -155,7 +155,7 @@ def reset(self): def update(self, config): """Update self from a dict, file or filename.""" - if isinstance(config, basestring): + if isinstance(config, str): # Filename config = Parser().dict_from_file(config) elif hasattr(config, 'read'): @@ -192,7 +192,7 @@ def optionxform(self, optionstr): return optionstr def read(self, filenames): - if isinstance(filenames, basestring): + if isinstance(filenames, str): filenames = [filenames] for filename in filenames: # try: @@ -290,7 +290,7 @@ def build_Keyword(self, o): return kw_dict def build_List(self, o): - return map(self.build, o.getChildren()) + return list(map(self.build, o.getChildren())) def build_Const(self, o): return o.value @@ -299,7 +299,7 @@ def build_Dict(self, o): d = {} i = iter(map(self.build, o.getChildren())) for el in i: - d[el] = i.next() + d[el] = next(i) return d def build_Tuple(self, o): @@ -329,11 +329,11 @@ def build_Name(self, o): raise TypeError("unrepr could not resolve the name %s" % repr(name)) def build_Add(self, o): - left, right = map(self.build, o.getChildren()) + left, right = list(map(self.build, o.getChildren())) return left + right def build_Mul(self, o): - left, right = map(self.build, o.getChildren()) + left, right = list(map(self.build, o.getChildren())) return left * right def build_Getattr(self, o): @@ -441,11 +441,11 @@ def build_NameConstant(self, o): return o.value def build_UnaryOp(self, o): - op, operand = map(self.build, [o.op, o.operand]) + op, operand = list(map(self.build, [o.op, o.operand])) return op(operand) def build_BinOp(self, o): - left, op, right = map(self.build, [o.left, o.op, o.right]) + left, op, right = list(map(self.build, [o.left, o.op, o.right])) return op(left, right) def build_Add(self, o): diff --git a/libs/cherrypy/lib/sessions.py b/libs/cherrypy/lib/sessions.py index 3755636..ee707dc 100644 --- a/libs/cherrypy/lib/sessions.py +++ b/libs/cherrypy/lib/sessions.py @@ -163,7 +163,7 @@ def __init__(self, id=None, **kwargs): self.id_observers = [] self._data = {} - for k, v in kwargs.items(): + for k, v in list(kwargs.items()): setattr(self, k, v) self.originalid = id @@ -370,19 +370,19 @@ def keys(self): """D.keys() -> list of D's keys.""" if not self.loaded: self.load() - return self._data.keys() + return list(self._data.keys()) def items(self): """D.items() -> list of D's (key, value) pairs, as 2-tuples.""" if not self.loaded: self.load() - return self._data.items() + return list(self._data.items()) def values(self): """D.values() -> list of D's values.""" if not self.loaded: self.load() - return self._data.values() + return list(self._data.values()) class RamSession(Session): @@ -483,7 +483,7 @@ def setup(cls, **kwargs): # The 'storage_path' arg is required for file-based sessions. kwargs['storage_path'] = os.path.abspath(kwargs['storage_path']) - for k, v in kwargs.items(): + for k, v in list(kwargs.items()): setattr(cls, k, v) setup = classmethod(setup) @@ -617,7 +617,7 @@ def setup(cls, **kwargs): This should only be called once per process; this will be done automatically when using sessions.init (as the built-in Tool does). """ - for k, v in kwargs.items(): + for k, v in list(kwargs.items()): setattr(cls, k, v) self.db = self.get_db() @@ -695,7 +695,7 @@ def setup(cls, **kwargs): This should only be called once per process; this will be done automatically when using sessions.init (as the built-in Tool does). """ - for k, v in kwargs.items(): + for k, v in list(kwargs.items()): setattr(cls, k, v) import memcache diff --git a/libs/cherrypy/lib/xmlrpcutil.py b/libs/cherrypy/lib/xmlrpcutil.py index 9fc9564..2c8e5de 100644 --- a/libs/cherrypy/lib/xmlrpcutil.py +++ b/libs/cherrypy/lib/xmlrpcutil.py @@ -8,7 +8,7 @@ def get_xmlrpclib(): try: import xmlrpc.client as x except ImportError: - import xmlrpclib as x + import xmlrpc.client as x return x diff --git a/libs/cherrypy/process/plugins.py b/libs/cherrypy/process/plugins.py index c787ba9..5238a37 100644 --- a/libs/cherrypy/process/plugins.py +++ b/libs/cherrypy/process/plugins.py @@ -7,7 +7,7 @@ import time import threading -from cherrypy._cpcompat import basestring, get_daemon, get_thread_ident +from cherrypy._cpcompat import str, get_daemon, get_thread_ident from cherrypy._cpcompat import ntob, set, Timer, SetDaemonProperty # _module__file__base is used by Autoreload to make @@ -88,7 +88,7 @@ class SignalHandler(object): signals = {} """A map from signal numbers to names.""" - for k, v in vars(_signal).items(): + for k, v in list(vars(_signal).items()): if k.startswith('SIG') and not k.startswith('SIG_'): signals[v] = k del k, v @@ -117,7 +117,7 @@ def _jython_SIGINT_handler(self, signum=None, frame=None): def subscribe(self): """Subscribe self.handlers to signals.""" - for sig, func in self.handlers.items(): + for sig, func in list(self.handlers.items()): try: self.set_handler(sig, func) except ValueError: @@ -125,7 +125,7 @@ def subscribe(self): def unsubscribe(self): """Unsubscribe self.handlers from signals.""" - for signum, handler in self._previous_handlers.items(): + for signum, handler in list(self._previous_handlers.items()): signame = self.signals[signum] if handler is None: @@ -153,7 +153,7 @@ def set_handler(self, signal, listener=None): If the given signal name or number is not available on the current platform, ValueError is raised. """ - if isinstance(signal, basestring): + if isinstance(signal, str): signum = getattr(_signal, signal, None) if signum is None: raise ValueError("No such signal: %r" % signal) @@ -219,7 +219,7 @@ def _set_uid(self, val): self.bus.log("pwd module not available; ignoring uid.", level=30) val = None - elif isinstance(val, basestring): + elif isinstance(val, str): val = pwd.getpwnam(val)[2] self._uid = val uid = property(_get_uid, _set_uid, @@ -234,7 +234,7 @@ def _set_gid(self, val): self.bus.log("grp module not available; ignoring gid.", level=30) val = None - elif isinstance(val, basestring): + elif isinstance(val, str): val = grp.getgrnam(val)[2] self._gid = val gid = property(_get_gid, _set_gid, @@ -711,7 +711,7 @@ def release_thread(self): def stop(self): """Release all threads and run all 'stop_thread' listeners.""" - for thread_ident, i in self.threads.items(): + for thread_ident, i in list(self.threads.items()): self.bus.publish('stop_thread', i) self.threads.clear() graceful = stop diff --git a/libs/cherrypy/process/win32.py b/libs/cherrypy/process/win32.py index 4afd3f1..110a59d 100644 --- a/libs/cherrypy/process/win32.py +++ b/libs/cherrypy/process/win32.py @@ -132,7 +132,7 @@ class _ControlCodes(dict): def key_for(self, obj): """For the given value, return its corresponding key.""" - for key, val in self.items(): + for key, val in list(self.items()): if val is obj: return key raise ValueError("The given object could not be found: %r" % obj) diff --git a/libs/cherrypy/process/wspbus.py b/libs/cherrypy/process/wspbus.py index 5409d03..125b823 100644 --- a/libs/cherrypy/process/wspbus.py +++ b/libs/cherrypy/process/wspbus.py @@ -100,7 +100,7 @@ def get_instances(self): return self._exceptions[:] def __str__(self): - exception_strings = map(repr, self.get_instances()) + exception_strings = list(map(repr, self.get_instances())) return self.delimiter.join(exception_strings) __repr__ = __str__ diff --git a/libs/cherrypy/test/benchmark.py b/libs/cherrypy/test/benchmark.py index cb3ce9f..0ab0028 100644 --- a/libs/cherrypy/test/benchmark.py +++ b/libs/cherrypy/test/benchmark.py @@ -224,7 +224,7 @@ def run(self): try: self.output = _cpmodpy.read_process(AB_PATH or "ab", self.args()) except: - print(_cperror.format_exc()) + print((_cperror.format_exc())) raise for attr, name, pattern in self.parse_patterns: @@ -255,7 +255,7 @@ def thread_report(path=SCRIPT_NAME + "/hello", concurrency=safe_threads): for attr in attrs: val = getattr(sess, attr) if val is None: - print(sess.output) + print((sess.output)) row = None break val = float(val) @@ -289,18 +289,18 @@ def print_report(rows): def run_standard_benchmarks(): print("") - print("Client Thread Report (1000 requests, 14 byte response body, " - "%s server threads):" % cherrypy.server.thread_pool) + print(("Client Thread Report (1000 requests, 14 byte response body, " + "%s server threads):" % cherrypy.server.thread_pool)) print_report(thread_report()) print("") - print("Client Thread Report (1000 requests, 14 bytes via staticdir, " - "%s server threads):" % cherrypy.server.thread_pool) + print(("Client Thread Report (1000 requests, 14 bytes via staticdir, " + "%s server threads):" % cherrypy.server.thread_pool)) print_report(thread_report("%s/static/index.html" % SCRIPT_NAME)) print("") - print("Size Report (1000 requests, 50 client threads, " - "%s server threads):" % cherrypy.server.thread_pool) + print(("Size Report (1000 requests, 50 client threads, " + "%s server threads):" % cherrypy.server.thread_pool)) print_report(size_report()) @@ -377,22 +377,22 @@ def run_modpython(use_wsgi=False): # can be tested from a standard web browser. def run(): port = cherrypy.server.socket_port - print("You may now open http://127.0.0.1:%s%s/" % - (port, SCRIPT_NAME)) + print(("You may now open http://127.0.0.1:%s%s/" % + (port, SCRIPT_NAME))) if "--null" in opts: print("Using null Request object") else: def run(): end = time.time() - start - print("Started in %s seconds" % end) + print(("Started in %s seconds" % end)) if "--null" in opts: print("\nUsing null Request object") try: try: run_standard_benchmarks() except: - print(_cperror.format_exc()) + print((_cperror.format_exc())) raise finally: cherrypy.engine.exit() diff --git a/libs/cherrypy/test/helper.py b/libs/cherrypy/test/helper.py index fd8bb91..8ce60bf 100644 --- a/libs/cherrypy/test/helper.py +++ b/libs/cherrypy/test/helper.py @@ -14,7 +14,7 @@ import warnings import cherrypy -from cherrypy._cpcompat import basestring, copyitems, HTTPSConnection, ntob +from cherrypy._cpcompat import str, copyitems, HTTPSConnection, ntob from cherrypy.lib import httputil from cherrypy.lib import gctools from cherrypy.lib.reprconf import unrepr @@ -47,8 +47,8 @@ def get_tst_config(overconf={}): import testconfig _conf = testconfig.config.get('supervisor', None) if _conf is not None: - for k, v in _conf.items(): - if isinstance(v, basestring): + for k, v in list(_conf.items()): + if isinstance(v, str): _conf[k] = unrepr(v) conf.update(_conf) except ImportError: @@ -65,7 +65,7 @@ class Supervisor(object): """Base class for modeling and controlling servers during testing.""" def __init__(self, **kwargs): - for k, v in kwargs.items(): + for k, v in list(kwargs.items()): if k == 'port': setattr(self, k, int(v)) setattr(self, k, v) @@ -89,7 +89,7 @@ class LocalSupervisor(Supervisor): using_wsgi = False def __init__(self, **kwargs): - for k, v in kwargs.items(): + for k, v in list(kwargs.items()): setattr(self, k, v) cherrypy.server.httpserver = self.httpserver_class @@ -253,7 +253,7 @@ def _setup_server(cls, supervisor, conf): if sys.platform[:4] == 'java': cherrypy.config.update({'server.nodelay': False}) - if isinstance(conf, basestring): + if isinstance(conf, str): parser = cherrypy.lib.reprconf.Parser() conf = parser.dict_from_file(conf).get('global', {}) else: diff --git a/libs/cherrypy/test/logtest.py b/libs/cherrypy/test/logtest.py index cc59499..7ab2d8f 100644 --- a/libs/cherrypy/test/logtest.py +++ b/libs/cherrypy/test/logtest.py @@ -4,7 +4,7 @@ import time import cherrypy -from cherrypy._cpcompat import basestring, ntob, unicodestr +from cherrypy._cpcompat import str, ntob, unicodestr try: @@ -49,7 +49,7 @@ class LogCase(object): def _handleLogError(self, msg, data, marker, pattern): print("") - print(" ERROR: %s" % msg) + print((" ERROR: %s" % msg)) if not self.interactive: raise self.failureException(msg) @@ -64,7 +64,7 @@ def _handleLogError(self, msg, data, marker, pattern): i = getchar().upper() if i not in "MPLIRX": continue - print(i.upper()) # Also prints new line + print((i.upper())) # Also prints new line if i == "L": for x, line in enumerate(data): if (x + 1) % self.console_height == 0: @@ -75,11 +75,11 @@ def _handleLogError(self, msg, data, marker, pattern): sys.stdout.write(" \r ") if m == "q": break - print(line.rstrip()) + print((line.rstrip())) elif i == "M": - print(repr(marker or self.lastmarker)) + print((repr(marker or self.lastmarker))) elif i == "P": - print(repr(pattern)) + print((repr(pattern))) elif i == "I": # return without raising the normal exception return @@ -186,7 +186,7 @@ def assertLog(self, sliceargs, lines, marker=None): # Multiple args. Use __getslice__ and require lines to be list. if isinstance(lines, tuple): lines = list(lines) - elif isinstance(lines, basestring): + elif isinstance(lines, str): raise TypeError("The 'lines' arg must be a list when " "'sliceargs' is a tuple.") diff --git a/libs/cherrypy/test/test_caching.py b/libs/cherrypy/test/test_caching.py index be1950d..eb9dd57 100644 --- a/libs/cherrypy/test/test_caching.py +++ b/libs/cherrypy/test/test_caching.py @@ -6,7 +6,7 @@ import sys import threading import time -import urllib +import urllib.request, urllib.parse, urllib.error import cherrypy from cherrypy._cpcompat import next, ntob, quote, xrange @@ -309,7 +309,7 @@ def run(): self.getPage("/long_process?seconds=%d" % SECONDS) # The response should be the same every time self.assertBody('success!') - ts = [threading.Thread(target=run) for i in xrange(100)] + ts = [threading.Thread(target=run) for i in range(100)] for t in ts: t.start() for t in ts: diff --git a/libs/cherrypy/test/test_compat.py b/libs/cherrypy/test/test_compat.py index 62cb3b4..53a4ade 100644 --- a/libs/cherrypy/test/test_compat.py +++ b/libs/cherrypy/test/test_compat.py @@ -16,4 +16,4 @@ def test_ntob_non_native(self): """ if compat.py3k: raise nose.SkipTest("Only useful on Python 2") - self.assertRaises(Exception, compat.ntob, unicode('fight')) + self.assertRaises(Exception, compat.ntob, str('fight')) diff --git a/libs/cherrypy/test/test_config.py b/libs/cherrypy/test/test_config.py index f9831b1..cc05b53 100644 --- a/libs/cherrypy/test/test_config.py +++ b/libs/cherrypy/test/test_config.py @@ -183,7 +183,7 @@ def testConfig(self): 'foo': 'this3', 'bax': 'this4', } - for key, expected in expectedconf.items(): + for key, expected in list(expectedconf.items()): self.getPage("/foo/bar?key=" + key) self.assertBody(repr(expected)) @@ -206,7 +206,7 @@ def testUnrepr(self): if not compat.py3k: self.getPage("/repr?key=thing3") - self.assertBody(repr(unicode('test'))) + self.assertBody(repr(str('test'))) self.getPage("/repr?key=complex") self.assertBody("(3+2j)") diff --git a/libs/cherrypy/test/test_dynamicobjectmapping.py b/libs/cherrypy/test/test_dynamicobjectmapping.py index a64e992..41446bf 100644 --- a/libs/cherrypy/test/test_dynamicobjectmapping.py +++ b/libs/cherrypy/test/test_dynamicobjectmapping.py @@ -79,7 +79,7 @@ def __init__(self, id, name): self.name = name def __unicode__(self): - return unicode(self.name) + return str(self.name) def __str__(self): return str(self.name) diff --git a/libs/cherrypy/test/test_encoding.py b/libs/cherrypy/test/test_encoding.py index 85869a9..65af3b6 100644 --- a/libs/cherrypy/test/test_encoding.py +++ b/libs/cherrypy/test/test_encoding.py @@ -88,7 +88,7 @@ class Decode: def extra_charset(self, *args, **kwargs): return ', '.join([": ".join((k, v)) - for k, v in cherrypy.request.params.items()]) + for k, v in list(cherrypy.request.params.items())]) extra_charset.exposed = True extra_charset._cp_config = { 'tools.decode.on': True, @@ -97,7 +97,7 @@ def extra_charset(self, *args, **kwargs): def force_charset(self, *args, **kwargs): return ', '.join([": ".join((k, v)) - for k, v in cherrypy.request.params.items()]) + for k, v in list(cherrypy.request.params.items())]) force_charset.exposed = True force_charset._cp_config = { 'tools.decode.on': True, diff --git a/libs/cherrypy/test/test_iterator.py b/libs/cherrypy/test/test_iterator.py index dcf4bc9..c09a7cf 100644 --- a/libs/cherrypy/test/test_iterator.py +++ b/libs/cherrypy/test/test_iterator.py @@ -4,7 +4,7 @@ class IteratorBase(object): created = 0 - datachunk = u'butternut squash' * 256 + datachunk = 'butternut squash' * 256 @classmethod def incr(cls): diff --git a/libs/cherrypy/test/test_misc_tools.py b/libs/cherrypy/test/test_misc_tools.py index df3e2e6..587a243 100644 --- a/libs/cherrypy/test/test_misc_tools.py +++ b/libs/cherrypy/test/test_misc_tools.py @@ -70,7 +70,7 @@ def index(self): # Read a header directly with 'has_key' if hasattr(dict, 'has_key'): # Python 2 - has = cherrypy.request.headers.has_key('Range') + has = 'Range' in cherrypy.request.headers else: # Python 3 has = 'Range' in cherrypy.request.headers diff --git a/libs/cherrypy/test/test_request_obj.py b/libs/cherrypy/test/test_request_obj.py index d9989e9..ad44356 100644 --- a/libs/cherrypy/test/test_request_obj.py +++ b/libs/cherrypy/test/test_request_obj.py @@ -41,7 +41,7 @@ class TestType(type): """ def __init__(cls, name, bases, dct): type.__init__(cls, name, bases, dct) - for value in dct.values(): + for value in list(dct.values()): if isinstance(value, types.FunctionType): value.exposed = True setattr(root, name.lower(), cls()) @@ -257,7 +257,7 @@ class to use your new dispatch mechanism and make sure that: def index(self): yield "

Choose your document

\n" yield "
    \n" - for id, contents in self.documents.items(): + for id, contents in list(self.documents.items()): yield ( "
  • %s:" " %s
  • \n" % (id, id, contents)) diff --git a/libs/cherrypy/test/test_states.py b/libs/cherrypy/test/test_states.py index d86e5cf..971c5f7 100644 --- a/libs/cherrypy/test/test_states.py +++ b/libs/cherrypy/test/test_states.py @@ -210,7 +210,7 @@ def test_2_KeyboardInterrupt(self): except BadStatusLine: pass else: - print(self.body) + print((self.body)) self.fail("AssertionError: BadStatusLine not raised") engine.block() diff --git a/libs/cherrypy/test/test_tools.py b/libs/cherrypy/test/test_tools.py index 4fb1a55..63ce724 100644 --- a/libs/cherrypy/test/test_tools.py +++ b/libs/cherrypy/test/test_tools.py @@ -209,7 +209,7 @@ def err_in_onstart(self): return "success!" def stream(self, id=None): - for x in xrange(100000000): + for x in range(100000000): yield str(x) stream._cp_config = {'response.stream': True} diff --git a/libs/cherrypy/test/test_wsgi_ns.py b/libs/cherrypy/test/test_wsgi_ns.py index 0df2365..8cd1751 100644 --- a/libs/cherrypy/test/test_wsgi_ns.py +++ b/libs/cherrypy/test/test_wsgi_ns.py @@ -16,8 +16,8 @@ def __init__(self, appresults): def __iter__(self): return self - def next(self): - return self.iter.next() + def __next__(self): + return next(self.iter) def __next__(self): return next(self.iter) @@ -37,8 +37,8 @@ def __call__(self, environ, start_response): class CaseResults(WSGIResponse): - def next(this): - return getattr(this.iter.next(), self.to)() + def __next__(this): + return getattr(next(this.iter), self.to)() def __next__(this): return getattr(next(this.iter), self.to)() @@ -55,15 +55,15 @@ def __call__(self, environ, start_response): class ReplaceResults(WSGIResponse): - def next(this): - line = this.iter.next() - for k, v in self.map.iteritems(): + def __next__(this): + line = next(this.iter) + for k, v in list(self.map.items()): line = line.replace(k, v) return line def __next__(this): line = next(this.iter) - for k, v in self.map.items(): + for k, v in list(self.map.items()): line = line.replace(k, v) return line return ReplaceResults(res) diff --git a/libs/cherrypy/test/test_wsgiapps.py b/libs/cherrypy/test/test_wsgiapps.py index ac65c1e..e84fe0c 100644 --- a/libs/cherrypy/test/test_wsgiapps.py +++ b/libs/cherrypy/test/test_wsgiapps.py @@ -46,7 +46,7 @@ def __next__(self): return next(self.iter) else: def next(self): - return self.iter.next() + return next(self.iter) def close(self): if hasattr(self.appresults, "close"): @@ -69,7 +69,7 @@ def __next__(this): return bytes(line) else: def next(this): - line = list(this.iter.next()) + line = list(next(this.iter)) line.reverse() return "".join(line) diff --git a/libs/cherrypy/test/test_xmlrpc.py b/libs/cherrypy/test/test_xmlrpc.py index 8f091ff..83c394c 100644 --- a/libs/cherrypy/test/test_xmlrpc.py +++ b/libs/cherrypy/test/test_xmlrpc.py @@ -2,8 +2,8 @@ from cherrypy._cpcompat import py3k try: - from xmlrpclib import DateTime, Fault, ProtocolError, ServerProxy - from xmlrpclib import SafeTransport + from xmlrpc.client import DateTime, Fault, ProtocolError, ServerProxy + from xmlrpc.client import SafeTransport except ImportError: from xmlrpc.client import DateTime, Fault, ProtocolError, ServerProxy from xmlrpc.client import SafeTransport diff --git a/libs/cherrypy/test/webtest.py b/libs/cherrypy/test/webtest.py index 1fa3f96..ccbddc3 100644 --- a/libs/cherrypy/test/webtest.py +++ b/libs/cherrypy/test/webtest.py @@ -27,7 +27,7 @@ from unittest import * from unittest import _TextTestResult -from cherrypy._cpcompat import basestring, ntob, py3k, HTTPConnection +from cherrypy._cpcompat import str, ntob, py3k, HTTPConnection from cherrypy._cpcompat import HTTPSConnection, unicodestr @@ -124,14 +124,14 @@ def loadTestsFromName(self, name, module=None): if isinstance(obj, types.ModuleType): return self.loadTestsFromModule(obj) elif (((py3k and isinstance(obj, type)) - or isinstance(obj, (type, types.ClassType))) + or isinstance(obj, type)) and issubclass(obj, TestCase)): return self.loadTestsFromTestCase(obj) elif isinstance(obj, types.UnboundMethodType): if py3k: return obj.__self__.__class__(obj.__name__) else: - return obj.im_class(obj.__name__) + return obj.__self__.__class__(obj.__name__) elif hasattr(obj, '__call__'): test = obj() if not isinstance(test, TestCase) and \ @@ -269,7 +269,7 @@ def getPage(self, url, headers=None, method="GET", body=None, def _handlewebError(self, msg): print("") - print(" ERROR: %s" % msg) + print((" ERROR: %s" % msg)) if not self.interactive: raise self.failureException(msg) @@ -285,7 +285,7 @@ def _handlewebError(self, msg): i = i.decode('ascii') if i not in "BHSUIRX": continue - print(i.upper()) # Also prints new line + print((i.upper())) # Also prints new line if i == "B": for x, line in enumerate(self.body.splitlines()): if (x + 1) % self.console_height == 0: @@ -300,9 +300,9 @@ def _handlewebError(self, msg): elif i == "H": pprint.pprint(self.headers) elif i == "S": - print(self.status) + print((self.status)) elif i == "U": - print(self.url) + print((self.url)) elif i == "I": # return without raising the normal exception return @@ -318,7 +318,7 @@ def exit(self): def assertStatus(self, status, msg=None): """Fail if self.status != status.""" - if isinstance(status, basestring): + if isinstance(status, str): if not self.status == status: if msg is None: msg = 'Status (%r) != %r' % (self.status, status) @@ -333,7 +333,7 @@ def assertStatus(self, status, msg=None): # status is a tuple or list. match = False for s in status: - if isinstance(s, basestring): + if isinstance(s, str): if self.status == s: match = True break @@ -376,7 +376,7 @@ def assertHeaderIn(self, key, values, msg=None): def assertHeaderItemValue(self, key, value, msg=None): """Fail if the header does not contain the specified value""" actual_value = self.assertHeader(key, msg=msg) - header_values = map(str.strip, actual_value.split(',')) + header_values = list(map(str.strip, actual_value.split(','))) if value in header_values: return value @@ -604,5 +604,5 @@ def server_error(exc=None): else: ServerError.on = True print("") - print("".join(traceback.format_exception(*exc))) + print(("".join(traceback.format_exception(*exc)))) return True diff --git a/libs/cherrypy/wsgiserver/__init__.py b/libs/cherrypy/wsgiserver/__init__.py index ee6190f..f3b2d66 100644 --- a/libs/cherrypy/wsgiserver/__init__.py +++ b/libs/cherrypy/wsgiserver/__init__.py @@ -8,7 +8,7 @@ import sys if sys.version_info < (3, 0): - from wsgiserver2 import * + from .wsgiserver2 import * else: # Le sigh. Boo for backward-incompatible syntax. exec('from .wsgiserver3 import *') diff --git a/libs/cherrypy/wsgiserver/ssl_pyopenssl.py b/libs/cherrypy/wsgiserver/ssl_pyopenssl.py index f8f2daf..62ede26 100644 --- a/libs/cherrypy/wsgiserver/ssl_pyopenssl.py +++ b/libs/cherrypy/wsgiserver/ssl_pyopenssl.py @@ -68,7 +68,7 @@ def _safe_call(self, is_reader, call, *args, **kwargs): time.sleep(self.ssl_retry) except SSL.WantWriteError: time.sleep(self.ssl_retry) - except SSL.SysCallError, e: + except SSL.SysCallError as e: if is_reader and e.args == (-1, 'Unexpected EOF'): return "" @@ -76,7 +76,7 @@ def _safe_call(self, is_reader, call, *args, **kwargs): if is_reader and errnum in wsgiserver.socket_errors_to_ignore: return "" raise socket.error(errnum) - except SSL.Error, e: + except SSL.Error as e: if is_reader and e.args == (-1, 'Unexpected EOF'): return "" diff --git a/libs/cherrypy/wsgiserver/wsgiserver2.py b/libs/cherrypy/wsgiserver/wsgiserver2.py index 416d553..3c4ccc7 100644 --- a/libs/cherrypy/wsgiserver/wsgiserver2.py +++ b/libs/cherrypy/wsgiserver/wsgiserver2.py @@ -78,10 +78,11 @@ def my_crazy_app(environ, start_response): 'WSGIPathInfoDispatcher', 'get_ssl_adapter_class'] import os +from functools import reduce try: import queue except: - import Queue as queue + import queue as queue import re import rfc822 import socket @@ -92,9 +93,9 @@ def my_crazy_app(environ, start_response): if not hasattr(socket, 'IPV6_V6ONLY'): socket.IPV6_V6ONLY = 27 try: - import cStringIO as StringIO + import io as StringIO except ImportError: - import StringIO + import io DEFAULT_BUFFER_SIZE = -1 @@ -106,7 +107,7 @@ def _reuse(self): pass _fileobject_uses_str_type = isinstance( - socket._fileobject(FauxSocket())._rbuf, basestring) + socket._fileobject(FauxSocket())._rbuf, str) del FauxSocket # this class is not longer required for anything. import threading @@ -124,13 +125,13 @@ def format_exc(limit=None): import operator -from urllib import unquote +from urllib.parse import unquote import warnings if sys.version_info >= (3, 0): bytestr = bytes unicodestr = str - basestring = (bytes, str) + str = (bytes, str) def ntob(n, encoding='ISO-8859-1'): """Return the given native string as a byte string in the given @@ -140,8 +141,8 @@ def ntob(n, encoding='ISO-8859-1'): return n.encode(encoding) else: bytestr = str - unicodestr = unicode - basestring = basestring + unicodestr = str + str = str def ntob(n, encoding='ISO-8859-1'): """Return the given native string as a byte string in the given @@ -331,8 +332,8 @@ def __next__(self): self._check_length() return data - def next(self): - data = self.rfile.next() + def __next__(self): + data = next(self.rfile) self.bytes_read += len(data) self._check_length() return data @@ -1009,7 +1010,7 @@ def sendall(self, data): try: bytes_sent = self.send(data) data = data[bytes_sent:] - except socket.error, e: + except socket.error as e: if e.args[0] not in socket_errors_nonblocking: raise @@ -1030,7 +1031,7 @@ def recv(self, size): data = self._sock.recv(size) self.bytes_read += len(data) return data - except socket.error, e: + except socket.error as e: if (e.args[0] not in socket_errors_nonblocking and e.args[0] not in socket_error_eintr): raise @@ -1051,7 +1052,7 @@ def read(self, size=-1): if size < 0: # Read until EOF # reset _rbuf. we consume it via buf. - self._rbuf = StringIO.StringIO() + self._rbuf = io.StringIO() while True: data = self.recv(rbufsize) if not data: @@ -1066,12 +1067,12 @@ def read(self, size=-1): # return. buf.seek(0) rv = buf.read(size) - self._rbuf = StringIO.StringIO() + self._rbuf = io.StringIO() self._rbuf.write(buf.read()) return rv # reset _rbuf. we consume it via buf. - self._rbuf = StringIO.StringIO() + self._rbuf = io.StringIO() while True: left = size - buf_len # recv() will malloc the amount of memory given as its @@ -1109,7 +1110,7 @@ def readline(self, size=-1): buf.seek(0) bline = buf.readline(size) if bline.endswith('\n') or len(bline) == size: - self._rbuf = StringIO.StringIO() + self._rbuf = io.StringIO() self._rbuf.write(buf.read()) return bline del bline @@ -1120,7 +1121,7 @@ def readline(self, size=-1): buf.seek(0) buffers = [buf.read()] # reset _rbuf. we consume it via buf. - self._rbuf = StringIO.StringIO() + self._rbuf = io.StringIO() data = None recv = self.recv while data != "\n": @@ -1132,7 +1133,7 @@ def readline(self, size=-1): buf.seek(0, 2) # seek end # reset _rbuf. we consume it via buf. - self._rbuf = StringIO.StringIO() + self._rbuf = io.StringIO() while True: data = self.recv(self._rbufsize) if not data: @@ -1154,11 +1155,11 @@ def readline(self, size=-1): if buf_len >= size: buf.seek(0) rv = buf.read(size) - self._rbuf = StringIO.StringIO() + self._rbuf = io.StringIO() self._rbuf.write(buf.read()) return rv # reset _rbuf. we consume it via buf. - self._rbuf = StringIO.StringIO() + self._rbuf = io.StringIO() while True: data = self.recv(self._rbufsize) if not data: @@ -1812,20 +1813,20 @@ def clear_stats(self): 'Threads Idle': lambda s: getattr(self.requests, "idle", None), 'Socket Errors': 0, 'Requests': lambda s: (not s['Enabled']) and -1 or sum( - [w['Requests'](w) for w in s['Worker Threads'].values()], 0), + [w['Requests'](w) for w in list(s['Worker Threads'].values())], 0), 'Bytes Read': lambda s: (not s['Enabled']) and -1 or sum( - [w['Bytes Read'](w) for w in s['Worker Threads'].values()], 0), + [w['Bytes Read'](w) for w in list(s['Worker Threads'].values())], 0), 'Bytes Written': lambda s: (not s['Enabled']) and -1 or sum( - [w['Bytes Written'](w) for w in s['Worker Threads'].values()], + [w['Bytes Written'](w) for w in list(s['Worker Threads'].values())], 0), 'Work Time': lambda s: (not s['Enabled']) and -1 or sum( - [w['Work Time'](w) for w in s['Worker Threads'].values()], 0), + [w['Work Time'](w) for w in list(s['Worker Threads'].values())], 0), 'Read Throughput': lambda s: (not s['Enabled']) and -1 or sum( [w['Bytes Read'](w) / (w['Work Time'](w) or 1e-6) - for w in s['Worker Threads'].values()], 0), + for w in list(s['Worker Threads'].values())], 0), 'Write Throughput': lambda s: (not s['Enabled']) and -1 or sum( [w['Bytes Written'](w) / (w['Work Time'](w) or 1e-6) - for w in s['Worker Threads'].values()], 0), + for w in list(s['Worker Threads'].values())], 0), 'Worker Threads': {}, } logging.statistics["CherryPy HTTPServer %d" % id(self)] = self.stats @@ -1904,7 +1905,7 @@ def start(self): getattr(self, 'ssl_certificate_chain', None)) # Select the appropriate socket - if isinstance(self.bind_addr, basestring): + if isinstance(self.bind_addr, str): # AF_UNIX socket # So we can reuse the socket... @@ -1944,7 +1945,7 @@ def start(self): af, socktype, proto, canonname, sa = res try: self.bind(af, socktype, proto) - except socket.error, serr: + except socket.error as serr: msg = "%s -- (%s: %s)" % (msg, sa, serr) if self.socket: self.socket.close() @@ -2058,7 +2059,7 @@ def tick(self): conn = self.ConnectionClass(self, s, makefile) - if not isinstance(self.bind_addr, basestring): + if not isinstance(self.bind_addr, str): # optional values # Until we do DNS lookups, omit REMOTE_HOST if addr is None: # sometimes this can happen @@ -2127,7 +2128,7 @@ def stop(self): sock = getattr(self, "socket", None) if sock: - if not isinstance(self.bind_addr, basestring): + if not isinstance(self.bind_addr, str): # Touch our own socket to make accept() return immediately. try: host, port = sock.getsockname()[:2] @@ -2189,7 +2190,7 @@ def respond(self): def get_ssl_adapter_class(name='pyopenssl'): """Return an SSL adapter class for the given name.""" adapter = ssl_adapters[name.lower()] - if isinstance(adapter, basestring): + if isinstance(adapter, str): last_dot = adapter.rfind(".") attr_name = adapter[last_dot + 1:] mod_path = adapter[:last_dot] @@ -2295,7 +2296,7 @@ def start_response(self, status, headers, exc_info=None): # exc_info tuple." if self.req.sent_headers: try: - raise exc_info[0], exc_info[1], exc_info[2] + raise exc_info[0](exc_info[1]).with_traceback(exc_info[2]) finally: exc_info = None @@ -2381,7 +2382,7 @@ def get_environ(self): 'wsgi.version': (1, 0), } - if isinstance(req.server.bind_addr, basestring): + if isinstance(req.server.bind_addr, str): # AF_UNIX. This isn't really allowed by WSGI, which doesn't # address unix domain sockets. But it's better than nothing. env["SERVER_PORT"] = "" @@ -2389,7 +2390,7 @@ def get_environ(self): env["SERVER_PORT"] = str(req.server.bind_addr[1]) # Request headers - for k, v in req.inheaders.iteritems(): + for k, v in list(req.inheaders.items()): env["HTTP_" + k.upper().replace("-", "_")] = v # CONTENT_TYPE/CONTENT_LENGTH @@ -2419,19 +2420,19 @@ def get_environ(self): req = self.req env_10 = WSGIGateway_10.get_environ(self) env = dict([(k.decode('ISO-8859-1'), v) - for k, v in env_10.iteritems()]) - env[u'wsgi.version'] = ('u', 0) + for k, v in list(env_10.items())]) + env['wsgi.version'] = ('u', 0) # Request-URI - env.setdefault(u'wsgi.url_encoding', u'utf-8') + env.setdefault('wsgi.url_encoding', 'utf-8') try: - for key in [u"PATH_INFO", u"SCRIPT_NAME", u"QUERY_STRING"]: - env[key] = env_10[str(key)].decode(env[u'wsgi.url_encoding']) + for key in ["PATH_INFO", "SCRIPT_NAME", "QUERY_STRING"]: + env[key] = env_10[str(key)].decode(env['wsgi.url_encoding']) except UnicodeDecodeError: # Fall back to latin 1 so apps can transcode if needed. - env[u'wsgi.url_encoding'] = u'ISO-8859-1' - for key in [u"PATH_INFO", u"SCRIPT_NAME", u"QUERY_STRING"]: - env[key] = env_10[str(key)].decode(env[u'wsgi.url_encoding']) + env['wsgi.url_encoding'] = 'ISO-8859-1' + for key in ["PATH_INFO", "SCRIPT_NAME", "QUERY_STRING"]: + env[key] = env_10[str(key)].decode(env['wsgi.url_encoding']) for k, v in sorted(env.items()): if isinstance(v, str) and k not in ('REQUEST_URI', 'wsgi.input'): diff --git a/libs/cherrypy/wsgiserver/wsgiserver3.py b/libs/cherrypy/wsgiserver/wsgiserver3.py index c60ddd9..65ed5f0 100644 --- a/libs/cherrypy/wsgiserver/wsgiserver3.py +++ b/libs/cherrypy/wsgiserver/wsgiserver3.py @@ -81,7 +81,7 @@ def my_crazy_app(environ, start_response): try: import queue except: - import Queue as queue + import queue as queue import re import email.utils import socket @@ -104,7 +104,7 @@ def my_crazy_app(environ, start_response): if sys.version_info >= (3, 0): bytestr = bytes unicodestr = str - basestring = (bytes, str) + str = (bytes, str) def ntob(n, encoding='ISO-8859-1'): """Return the given native string as a byte string in the given @@ -114,8 +114,8 @@ def ntob(n, encoding='ISO-8859-1'): return n.encode(encoding) else: bytestr = str - unicodestr = unicode - basestring = basestring + unicodestr = str + str = str def ntob(n, encoding='ISO-8859-1'): """Return the given native string as a byte string in the given @@ -305,8 +305,8 @@ def __next__(self): self._check_length() return data - def next(self): - data = self.rfile.next() + def __next__(self): + data = next(self.rfile) self.bytes_read += len(data) self._check_length() return data @@ -1524,20 +1524,20 @@ def clear_stats(self): 'Threads Idle': lambda s: getattr(self.requests, "idle", None), 'Socket Errors': 0, 'Requests': lambda s: (not s['Enabled']) and -1 or sum( - [w['Requests'](w) for w in s['Worker Threads'].values()], 0), + [w['Requests'](w) for w in list(s['Worker Threads'].values())], 0), 'Bytes Read': lambda s: (not s['Enabled']) and -1 or sum( - [w['Bytes Read'](w) for w in s['Worker Threads'].values()], 0), + [w['Bytes Read'](w) for w in list(s['Worker Threads'].values())], 0), 'Bytes Written': lambda s: (not s['Enabled']) and -1 or sum( - [w['Bytes Written'](w) for w in s['Worker Threads'].values()], + [w['Bytes Written'](w) for w in list(s['Worker Threads'].values())], 0), 'Work Time': lambda s: (not s['Enabled']) and -1 or sum( - [w['Work Time'](w) for w in s['Worker Threads'].values()], 0), + [w['Work Time'](w) for w in list(s['Worker Threads'].values())], 0), 'Read Throughput': lambda s: (not s['Enabled']) and -1 or sum( [w['Bytes Read'](w) / (w['Work Time'](w) or 1e-6) - for w in s['Worker Threads'].values()], 0), + for w in list(s['Worker Threads'].values())], 0), 'Write Throughput': lambda s: (not s['Enabled']) and -1 or sum( [w['Bytes Written'](w) / (w['Work Time'](w) or 1e-6) - for w in s['Worker Threads'].values()], 0), + for w in list(s['Worker Threads'].values())], 0), 'Worker Threads': {}, } logging.statistics["CherryPy HTTPServer %d" % id(self)] = self.stats @@ -1597,7 +1597,7 @@ def start(self): self.software = "%s Server" % self.version # Select the appropriate socket - if isinstance(self.bind_addr, basestring): + if isinstance(self.bind_addr, str): # AF_UNIX socket # So we can reuse the socket... @@ -1750,7 +1750,7 @@ def tick(self): conn = self.ConnectionClass(self, s, makefile) - if not isinstance(self.bind_addr, basestring): + if not isinstance(self.bind_addr, str): # optional values # Until we do DNS lookups, omit REMOTE_HOST if addr is None: # sometimes this can happen @@ -1819,7 +1819,7 @@ def stop(self): sock = getattr(self, "socket", None) if sock: - if not isinstance(self.bind_addr, basestring): + if not isinstance(self.bind_addr, str): # Touch our own socket to make accept() return immediately. try: host, port = sock.getsockname()[:2] @@ -1880,7 +1880,7 @@ def respond(self): def get_ssl_adapter_class(name='builtin'): """Return an SSL adapter class for the given name.""" adapter = ssl_adapters[name.lower()] - if isinstance(adapter, basestring): + if isinstance(adapter, str): last_dot = adapter.rfind(".") attr_name = adapter[last_dot + 1:] mod_path = adapter[:last_dot] @@ -2079,7 +2079,7 @@ def get_environ(self): 'wsgi.url_scheme': req.scheme.decode('ISO-8859-1'), 'wsgi.version': (1, 0), } - if isinstance(req.server.bind_addr, basestring): + if isinstance(req.server.bind_addr, str): # AF_UNIX. This isn't really allowed by WSGI, which doesn't # address unix domain sockets. But it's better than nothing. env["SERVER_PORT"] = "" @@ -2087,7 +2087,7 @@ def get_environ(self): env["SERVER_PORT"] = str(req.server.bind_addr[1]) # Request headers - for k, v in req.inheaders.items(): + for k, v in list(req.inheaders.items()): k = k.decode('ISO-8859-1').upper().replace("-", "_") env["HTTP_" + k] = v.decode('ISO-8859-1') diff --git a/libs/clize.py b/libs/clize.py index bbfdc04..d5d2835 100644 --- a/libs/clize.py +++ b/libs/clize.py @@ -1,4 +1,4 @@ -from __future__ import print_function + from functools import wraps, partial from collections import namedtuple import re @@ -9,6 +9,7 @@ import os import inspect from gettext import gettext as _, ngettext as _n +import collections class ArgumentError(TypeError): @@ -242,7 +243,7 @@ def coerce_option(val, option, key, command, name): ) def set_arg_value(val, option, key, params, name, command): - if callable(option.source): + if isinstance(option.source, collections.Callable): return option.source(name=name, command=command, val=val, params=params) else: @@ -400,7 +401,7 @@ def _getopts(*input): raise ArgumentError(_("Too many arguments."), command, name) for option in command.options: - if not callable(option.source): + if not isinstance(option.source, collections.Callable): kwargs.setdefault(option.source, option.default) fn_args = inspect.getargspec(fn).args diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/setup.py b/setup.py index c881f02..bff3e9e 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ author="Sam et Max", author_email="lesametlemax@gmail.com", description="An client side encrypted pastebin", - long_description=open('README.rst').read(), + long_description=open('README.md').read(), install_requires=[ 'cherrypy', 'bottle', diff --git a/zerobin/__init__.py b/zerobin/__init__.py index 90eaaba..0bd1106 100644 --- a/zerobin/__init__.py +++ b/zerobin/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # coding: utf-8 -from __future__ import absolute_import + from zerobin.default_settings import VERSION diff --git a/zerobin/cmd.py b/zerobin/cmd.py index f109f02..1ad6295 100644 --- a/zerobin/cmd.py +++ b/zerobin/cmd.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # coding: utf-8 -from __future__ import unicode_literals, absolute_import, print_function + """ Main script including runserver and delete-paste. @@ -13,7 +13,7 @@ import re try: - import thread + import _thread except ImportError: import _thread as thread @@ -47,7 +47,7 @@ def runserver(host='', port='', debug=None, user='', group='', print('Configuration error: %s' % err.message, file=sys.stderr) sys.exit(1) - thread.start_new_thread(drop_privileges, (settings.USER, settings.GROUP)) + _thread.start_new_thread(drop_privileges, (settings.USER, settings.GROUP)) if settings.DEBUG: run(app, host=settings.HOST, port=settings.PORT, reloader=True, @@ -95,7 +95,7 @@ def delete_paste(quiet=False, *pastes): def main(): subcommands = [runserver, delete_paste] subcommand_names = [clize.util.name_py2cli(name) - for name in clize.util.dict_from_names(subcommands).keys()] + for name in list(clize.util.dict_from_names(subcommands).keys())] if len(sys.argv) < 2 or sys.argv[1] not in subcommand_names: sys.argv.insert(1, subcommand_names[0]) clize.run(runserver, delete_paste) diff --git a/zerobin/default_settings.py b/zerobin/default_settings.py index 8704632..a20f78a 100644 --- a/zerobin/default_settings.py +++ b/zerobin/default_settings.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # coding: utf-8 -from __future__ import unicode_literals, absolute_import + ######## NOT SETTINGS, JUST BOILER PLATE ############## diff --git a/zerobin/paste.py b/zerobin/paste.py index 5662332..b018523 100644 --- a/zerobin/paste.py +++ b/zerobin/paste.py @@ -1,6 +1,6 @@ # coding: utf-8 -from __future__ import unicode_literals, absolute_import + import os import hashlib diff --git a/zerobin/privilege.py b/zerobin/privilege.py index c0b0e79..23843c9 100644 --- a/zerobin/privilege.py +++ b/zerobin/privilege.py @@ -182,8 +182,8 @@ class proc_credentials: This obtains and represents the credentials associated with a process. """ def __init__(self): - self.uids = apply(res_ids, getresuid()) - self.gids = apply(res_ids, getresgid()) + self.uids = res_ids(*getresuid()) + self.gids = res_ids(*getresgid()) self.sups = sort_uniq(os.getgroups()) def get_fs_ids(): @@ -217,7 +217,7 @@ def drop_privileges_permanently(uid, gid, sups): uid = coerce_user(uid) gid = coerce_group(gid) - sups = map(coerce_group, sups) + sups = list(map(coerce_group, sups)) # This does some syntax checking ucred = user_credentials(uid, gid, sups) diff --git a/zerobin/routes.py b/zerobin/routes.py index 1031766..623a6a3 100644 --- a/zerobin/routes.py +++ b/zerobin/routes.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # coding: utf-8 -from __future__ import unicode_literals, absolute_import, print_function + """ Script including controller, rooting, and dependency management. @@ -11,12 +11,12 @@ import sys try: - import thread + import _thread except ImportError: import _thread as thread try: - import urlparse + import urllib.parse except ImportError: import urllib.parse as urlparse @@ -56,7 +56,7 @@ def faq(): @app.route('/paste/create', method='POST') def create_paste(): try: - body = urlparse.parse_qs(request.body.read(int(settings.MAX_SIZE * 1.1))) + body = urllib.parse.parse_qs(request.body.read(int(settings.MAX_SIZE * 1.1))) except ValueError: return {'status': 'error', 'message': "Wrong data payload."} diff --git a/zerobin/utils.py b/zerobin/utils.py index 0af6d17..b5ef99a 100644 --- a/zerobin/utils.py +++ b/zerobin/utils.py @@ -1,6 +1,6 @@ # coding: utf-8 -from __future__ import print_function, unicode_literals, absolute_import + import time import os @@ -25,7 +25,7 @@ # python-2.6 or earlier - use simplier less-optimized execfile() def run_path(file_path): mod_globals = {'__file__': file_path} - execfile(file_path, mod_globals) + exec(compile(open(file_path).read(), file_path, 'exec'), mod_globals) return mod_globals @@ -89,7 +89,7 @@ def update_with_dict(self, dict): Update settings with values from the given mapping object. (Taking only variable with uppercased name) """ - for name, value in dict.items(): + for name, value in list(dict.items()): if name.isupper(): setattr(self, name, value) return self @@ -142,6 +142,6 @@ def to_ascii(utext): def as_unicode(obj): """ Return the unicode representation of an object """ try: - return unicode(obj) + return str(obj) except NameError: return str(obj)