From 87d354e1a013806ef37f11e22f015e5cc43e533d Mon Sep 17 00:00:00 2001 From: Michal Vyskocil Date: Tue, 9 Apr 2013 12:36:42 +0200 Subject: [PATCH] python3 compatibility: import proper modules Some modules (httplib, StringIO, ...) were renamed in python3. This patch try to import the proper symbols from python3 and then fallback to python2 in a case ImportError will appear. There is one exception, python 2.7 got the io module with StringIO, but it allow unicode arguments only. Therefor the old module is poked before new one. --- osc/OscConfigParser.py | 28 ++++++++++++++++------------ osc/babysitter.py | 6 +++++- osc/build.py | 8 ++++++-- osc/commandline.py | 8 ++++++-- osc/conf.py | 32 ++++++++++++++++++++------------ osc/core.py | 27 ++++++++++++++++++--------- osc/oscssl.py | 16 +++++++++++----- osc/util/ar.py | 12 +++++++++--- 8 files changed, 91 insertions(+), 46 deletions(-) diff --git a/osc/OscConfigParser.py b/osc/OscConfigParser.py index 3408c8d7..d144dd54 100644 --- a/osc/OscConfigParser.py +++ b/osc/OscConfigParser.py @@ -14,7 +14,11 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -import ConfigParser +try: + import configparser +except ImportError: + #python 2.x + import ConfigParser as configparser import re # inspired from http://code.google.com/p/iniparse/ - although their implementation is @@ -106,9 +110,9 @@ class SectionLine(Line): def _add_option(self, optname, value = None, line = None, sep = '='): if value is None and line is None: - raise ConfigParser.Error('Either value or line must be passed in') + raise configparser.Error('Either value or line must be passed in') elif value and line: - raise ConfigParser.Error('value and line are mutually exclusive') + raise configparser.Error('value and line are mutually exclusive') if value is not None: line = '%s%s%s' % (optname, sep, value) @@ -182,7 +186,7 @@ class OptionLine(Line): self.format(line) def format(self, line): - mo = ConfigParser.ConfigParser.OPTCRE.match(line.strip()) + mo = configparser.ConfigParser.OPTCRE.match(line.strip()) key, val = mo.group('option', 'value') self.frmt = line.replace(key.strip(), '%s', 1) pos = val.find(' ;') @@ -195,7 +199,7 @@ class OptionLine(Line): return self.value -class OscConfigParser(ConfigParser.SafeConfigParser): +class OscConfigParser(configparser.SafeConfigParser): """ OscConfigParser() behaves like a normal ConfigParser() object. The only differences is that it preserves the order+format of configuration entries @@ -204,7 +208,7 @@ class OscConfigParser(ConfigParser.SafeConfigParser): class. """ def __init__(self, defaults={}): - ConfigParser.SafeConfigParser.__init__(self, defaults) + configparser.SafeConfigParser.__init__(self, defaults) self._sections = ConfigLineOrder() # XXX: unfortunately we have to override the _read() method from the ConfigParser() @@ -245,7 +249,7 @@ class OscConfigParser(ConfigParser.SafeConfigParser): if value: #cursect[optname] = "%s\n%s" % (cursect[optname], value) #self.set(cursect, optname, "%s\n%s" % (self.get(cursect, optname), value)) - if cursect == ConfigParser.DEFAULTSECT: + if cursect == configparser.DEFAULTSECT: self._defaults[optname] = "%s\n%s" % (self._defaults[optname], value) else: # use the raw value here (original version uses raw=False) @@ -258,7 +262,7 @@ class OscConfigParser(ConfigParser.SafeConfigParser): sectname = mo.group('header') if sectname in self._sections: cursect = self._sections[sectname] - elif sectname == ConfigParser.DEFAULTSECT: + elif sectname == configparser.DEFAULTSECT: cursect = self._defaults else: #cursect = {'__name__': sectname} @@ -270,7 +274,7 @@ class OscConfigParser(ConfigParser.SafeConfigParser): optname = None # no section header in the file? elif cursect is None: - raise ConfigParser.MissingSectionHeaderError(fpname, lineno, line) + raise configparser.MissingSectionHeaderError(fpname, lineno, line) # an option line? else: mo = self.OPTCRE.match(line) @@ -287,7 +291,7 @@ class OscConfigParser(ConfigParser.SafeConfigParser): if optval == '""': optval = '' optname = self.optionxform(optname.rstrip()) - if cursect == ConfigParser.DEFAULTSECT: + if cursect == configparser.DEFAULTSECT: self._defaults[optname] = optval else: self._sections[cursect]._add_option(optname, line=line) @@ -297,7 +301,7 @@ class OscConfigParser(ConfigParser.SafeConfigParser): # raised at the end of the file and will contain a # list of all bogus lines if not e: - e = ConfigParser.ParsingError(fpname) + e = configparser.ParsingError(fpname) e.append(lineno, repr(line)) # if any parsing errors occurred, raise an exception if e: @@ -313,7 +317,7 @@ class OscConfigParser(ConfigParser.SafeConfigParser): fp.write(str(self)) fp.write('\n') else: - ConfigParser.SafeConfigParser.write(self, fp) + configparser.SafeConfigParser.write(self, fp) # XXX: simplify! def __str__(self): diff --git a/osc/babysitter.py b/osc/babysitter.py index d1cbdc3f..53661bdb 100644 --- a/osc/babysitter.py +++ b/osc/babysitter.py @@ -29,7 +29,11 @@ except: # if rpm-python isn't installed (we might be on a debian system): RPMError = None -from httplib import HTTPException, BadStatusLine +try: + from http.client import HTTPException, BadStatusLine +except ImportError: + #python 2.x + from httplib import HTTPException, BadStatusLine from urllib2 import URLError, HTTPError # the good things are stolen from Matt Mackall's mercurial diff --git a/osc/build.py b/osc/build.py index 0cba1e04..b2464029 100644 --- a/osc/build.py +++ b/osc/build.py @@ -9,7 +9,11 @@ import os import re import sys import shutil -import urlparse +try: + from urllib.parse import urlsplit +except ImportError: + #python 2.x + from urlparse import urlsplit from tempfile import NamedTemporaryFile, mkdtemp from osc.fetch import * from osc.core import get_buildinfo, store_read_apiurl, store_read_project, store_read_package, meta_exists, quote_plus, get_buildconfig, is_package_dir @@ -491,7 +495,7 @@ def main(apiurl, opts, argv): opts.local_package = True if opts.local_package: pacname = os.path.splitext(build_descr)[0] - apihost = urlparse.urlsplit(apiurl)[1] + apihost = urlsplit(apiurl)[1] if not build_root: try: build_root = config['build-root'] % {'repo': repo, 'arch': arch, diff --git a/osc/commandline.py b/osc/commandline.py index 4523adfa..d0f6bcff 100644 --- a/osc/commandline.py +++ b/osc/commandline.py @@ -9,7 +9,11 @@ from . import conf from . import oscerr import sys import time -import urlparse +try: + from urllib.parse import urlsplit +except ImportError: + #python 2.x + from urlparse import urlsplit from optparse import SUPPRESS_HELP @@ -5552,7 +5556,7 @@ Please submit there instead, or use --nodevelproject to force direct submission. package = os.path.splitext(descr)[0] else: package = store_read_package('.') - apihost = urlparse.urlsplit(self.get_api_url())[1] + apihost = urlsplit(self.get_api_url())[1] buildroot = os.environ.get('OSC_BUILD_ROOT', conf.config['build-root']) \ % {'repo': repository, 'arch': arch, 'project': project, 'package': package, 'apihost': apihost} if not os.path.isdir(buildroot): diff --git a/osc/conf.py b/osc/conf.py index 902e0acf..a8183238 100644 --- a/osc/conf.py +++ b/osc/conf.py @@ -35,15 +35,23 @@ The configuration dictionary could look like this: """ import base64 -import cookielib -import httplib import os import re import sys -import StringIO import urllib import urllib2 -import urlparse + +try: + from http.cookiejar import LWPCookieJar, CookieJar + from http.client import HTTPConnection, HTTPResponse + from io import StringIO + from urllib.parse import urlsplit +except ImportError: + #python 2.x + from cookielib import LWPCookieJar, CookieJar + from httplib import HTTPConnection, HTTPResponse + from StringIO import StringIO + from urlparse import urlsplit from . import OscConfigParser from osc import oscerr @@ -358,10 +366,10 @@ cookiejar = None def parse_apisrv_url(scheme, apisrv): if apisrv.startswith('http://') or apisrv.startswith('https://'): - return urlparse.urlsplit(apisrv)[0:2] + return urlsplit(apisrv)[0:2] elif scheme != None: # the split/join is needed to get a proper url (e.g. without a trailing slash) - return urlparse.urlsplit(urljoin(scheme, apisrv))[0:2] + return urlsplit(urljoin(scheme, apisrv))[0:2] else: msg = 'invalid apiurl \'%s\' (specify the protocol (http:// or https://))' % apisrv raise urllib2.URLError(msg) @@ -518,7 +526,7 @@ def init_basicauth(config): # a logger object or such def new_method(*args, **kwargs): stdout = sys.stdout - sys.stdout = StringIO.StringIO() + sys.stdout = StringIO() meth(*args, **kwargs) hdr = sys.stdout.getvalue() sys.stdout = stdout @@ -532,8 +540,8 @@ def init_basicauth(config): return new_method if config['http_debug'] and not config['http_full_debug']: - httplib.HTTPConnection.send = filterhdrs(httplib.HTTPConnection.send, True, 'Cookie', 'Authorization') - httplib.HTTPResponse.begin = filterhdrs(httplib.HTTPResponse.begin, False, 'header: Set-Cookie.*\n') + HTTPConnection.send = filterhdrs(HTTPConnection.send, True, 'Cookie', 'Authorization') + HTTPResponse.begin = filterhdrs(HTTPResponse.begin, False, 'header: Set-Cookie.*\n') if sys.version_info < (2, 6): # HTTPS proxy is not supported in old urllib2. It only leads to an error @@ -551,7 +559,7 @@ def init_basicauth(config): cookie_file = os.path.expanduser(config['cookiejar']) global cookiejar - cookiejar = cookielib.LWPCookieJar(cookie_file) + cookiejar = LWPCookieJar(cookie_file) try: cookiejar.load(ignore_discard=True) except IOError: @@ -560,7 +568,7 @@ def init_basicauth(config): os.chmod(cookie_file, 0600) except: #print 'Unable to create cookiejar file: \'%s\'. Using RAM-based cookies.' % cookie_file - cookiejar = cookielib.CookieJar() + cookiejar = CookieJar() def get_configParser(conffile=None, force_read=False): @@ -682,7 +690,7 @@ def write_initial_config(conffile, entries, custom_template=''): else: config['passx'] = base64.b64encode(config['pass'].encode('bz2')) - sio = StringIO.StringIO(conf_template.strip() % config) + sio = StringIO(conf_template.strip() % config) cp = OscConfigParser.OscConfigParser(DEFAULTS) cp.readfp(sio) write_config(conffile, cp) diff --git a/osc/core.py b/osc/core.py index 8564595d..f9fce61f 100644 --- a/osc/core.py +++ b/osc/core.py @@ -16,11 +16,14 @@ import os.path import sys import urllib2 from urllib import pathname2url, quote_plus, urlencode, unquote -from urlparse import urlsplit, urlunsplit -from cStringIO import StringIO +try: + from urllib.parse import urlsplit, urlunsplit, urlparse + from io import StringIO +except ImportError: + #python 2.x + from urlparse import urlsplit, urlunsplit, urlparse + from cStringIO import StringIO import shutil -from . import oscerr -from . import conf import subprocess import re import socket @@ -30,6 +33,9 @@ try: except ImportError: import cElementTree as ET +from . import oscerr +from . import conf + # python 2.6 don't have memoryview try: memoryview @@ -298,7 +304,6 @@ class Serviceinfo: def addDownloadUrl(self, serviceinfo_node, url_string): - from urlparse import urlparse url = urlparse( url_string ) protocol = url.scheme host = url.netloc @@ -5164,8 +5169,7 @@ def streamfile(url, http_meth = http_GET, bufsize=8192, data=None, progress_obj= cl = int(cl) if progress_obj: - import urlparse - basename = os.path.basename(urlparse.urlsplit(url)[2]) + basename = os.path.basename(urlsplit(url)[2]) progress_obj.start(basename=basename, text=text, size=cl) data = f.read(bufsize) read = len(data) @@ -6546,9 +6550,14 @@ def get_user_projpkgs(apiurl, user, role=None, exclude_projects=[], proj=True, p return res def raw_input(*args): - import __builtin__ try: - return __builtin__.raw_input(*args) + import builtins + except ImportError: + #python 2.7 + import __builtin__ as builtins + + try: + return builtins.raw_input(*args) except EOFError: # interpret ctrl-d as user abort raise oscerr.UserAbort() diff --git a/osc/oscssl.py b/osc/oscssl.py index 32641a29..d7ebf5b9 100644 --- a/osc/oscssl.py +++ b/osc/oscssl.py @@ -7,12 +7,18 @@ import M2Crypto.httpslib from M2Crypto.SSL.Checker import SSLVerificationError from M2Crypto import m2, SSL import M2Crypto.m2urllib2 -import urlparse import socket import urllib -import httplib import sys +try: + from urllib.parse import urlparse + from http.client import HTTPSConnection +except ImportError: + #python 2.x + from urlparse import urlparse + from httplib import HTTPSConnection + class TrustedCertStore: _tmptrusted = {} @@ -182,7 +188,7 @@ class myHTTPSHandler(M2Crypto.m2urllib2.HTTPSHandler): # Our change: Check to see if we're using a proxy. # Then create an appropriate ssl-aware connection. full_url = req.get_full_url() - target_host = urlparse.urlparse(full_url)[1] + target_host = urlparse(full_url)[1] if (target_host != host): h = myProxyHTTPSConnection(host = host, appname = self.appname, ssl_context = self.ctx) @@ -249,7 +255,7 @@ class myHTTPSConnection(M2Crypto.httpslib.HTTPSConnection): def getPort(self): return self.port -class myProxyHTTPSConnection(M2Crypto.httpslib.ProxyHTTPSConnection, httplib.HTTPSConnection): +class myProxyHTTPSConnection(M2Crypto.httpslib.ProxyHTTPSConnection, HTTPSConnection): def __init__(self, *args, **kwargs): self.appname = kwargs.pop('appname', 'generic') M2Crypto.httpslib.ProxyHTTPSConnection.__init__(self, *args, **kwargs) @@ -261,7 +267,7 @@ class myProxyHTTPSConnection(M2Crypto.httpslib.ProxyHTTPSConnection, httplib.HTT def endheaders(self, *args, **kwargs): if self._proxy_auth is None: self._proxy_auth = self._encode_auth() - httplib.HTTPSConnection.endheaders(self, *args, **kwargs) + HTTPSConnection.endheaders(self, *args, **kwargs) # broken in m2crypto: port needs to be an int def putrequest(self, method, url, skip_host=0, skip_accept_encoding=0): diff --git a/osc/util/ar.py b/osc/util/ar.py index 09f6a1ac..d316f657 100644 --- a/osc/util/ar.py +++ b/osc/util/ar.py @@ -16,9 +16,15 @@ import os import re import sys -import StringIO import stat +#XXX: python 2.7 contains io.StringIO, which needs unicode instead of str +#therefor try to import old stuff before new one here +try: + from cStringIO import StringIO +except ImportError: + from io import StringIO + # workaround for python24 if not hasattr(os, 'SEEK_SET'): os.SEEK_SET = 0 @@ -49,10 +55,10 @@ class ArHdr: def __str__(self): return '%16s %d' % (self.file, self.size) -class ArFile(StringIO.StringIO): +class ArFile(StringIO): """Represents a file which resides in the archive""" def __init__(self, fn, uid, gid, mode, buf): - StringIO.StringIO.__init__(self, buf) + StringIO.__init__(self, buf) self.name = fn self.uid = uid self.gid = gid