Add Python3 support.

This commit is contained in:
Bastian Kleineidam 2012-11-19 20:58:42 +01:00
parent a12a5adb35
commit d7f453cc34
9 changed files with 97 additions and 76 deletions

View File

@ -1,6 +1,7 @@
0.18 "" (released xx.xx.xxxx) 0.18 "" (released xx.xx.xxxx)
* Fixed unadf archive listing. * Fixed unadf archive listing.
* Added support for Python 3.x and depend on Python >= 2.7.
0.17 "I am Bruce Lee" (released 4.8.2012) 0.17 "I am Bruce Lee" (released 4.8.2012)

View File

@ -3,7 +3,7 @@ Installation
First, install the required software. First, install the required software.
1. Python >= 2.5 from http://www.python.org/ 1. Python >= 2.7 from http://www.python.org/
Be sure to also have installed the included distutils module. Be sure to also have installed the included distutils module.
On most distributions, the distutils module is included in On most distributions, the distutils module is included in

7
patool
View File

@ -17,6 +17,7 @@
""" """
patool [extract|list|create|formats] [sub-command-options] <command-args> patool [extract|list|create|formats] [sub-command-options] <command-args>
""" """
from __future__ import print_function
import os import os
import sys import sys
from patoolib import handle_archive, list_formats, baker from patoolib import handle_archive, list_formats, baker
@ -35,7 +36,7 @@ def handle_multi_archive(archives, cmd, **kwargs):
if not os.path.isfile(archive): if not os.path.isfile(archive):
res = 1 res = 1
msg = "archive %r is not a file" % archive msg = "archive %r is not a file" % archive
print >>sys.stderr, "patool error:", msg print("patool error:", msg, file=sys.stderr)
else: else:
newres = handle_archive(archive, cmd, **kwargs) newres = handle_archive(archive, cmd, **kwargs)
# return error if one of the archives could not be extracted # return error if one of the archives could not be extracted
@ -94,7 +95,7 @@ def formats ():
try: try:
sys.exit(baker.run()) sys.exit(baker.run())
except baker.CommandError, msg: except baker.CommandError as msg:
print >>sys.stderr, "patool error:", msg print("patool error:", msg, file=sys.stderr)
baker.help(sys.argv[0]) baker.help(sys.argv[0])
sys.exit(1) sys.exit(1)

View File

@ -13,12 +13,14 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import sys import sys
if not hasattr(sys, "version_info") or sys.version_info < (2, 5, 0, "final", 0): if not hasattr(sys, "version_info") or sys.version_info < (2, 7, 0, "final", 0):
raise SystemExit("This program requires Python 2.5 or later.") raise SystemExit("This program requires Python 2.7 or later.")
import os import os
import shutil import shutil
import stat import stat
import importlib
from . import util from . import util
# Supported archive commands # Supported archive commands
@ -310,29 +312,29 @@ def program_supports_compression (program, compression):
def list_formats (): def list_formats ():
"""Print information about available archive formats to stdout.""" """Print information about available archive formats to stdout."""
for format in ArchiveFormats: for format in ArchiveFormats:
print format, "files:" print(format, "files:")
for command in ArchiveCommands: for command in ArchiveCommands:
programs = ArchivePrograms[format] programs = ArchivePrograms[format]
if command not in programs and None not in programs: if command not in programs and None not in programs:
print " %8s: - (not supported)" % command print(" %8s: - (not supported)" % command)
continue continue
try: try:
program = find_archive_program(format, command) program = find_archive_program(format, command)
print " %8s: %s" % (command, program), print(" %8s: %s" % (command, program), end=' ')
if format == 'tar': if format == 'tar':
encs = [x for x in ArchiveCompressions if util.find_program(x)] encs = [x for x in ArchiveCompressions if util.find_program(x)]
if encs: if encs:
print "(supported compressions: %s)" % ", ".join(encs), print("(supported compressions: %s)" % ", ".join(encs), end=' ')
elif format == '7z': elif format == '7z':
if util.p7zip_supports_rar(): if util.p7zip_supports_rar():
print "(rar archives supported)", print("(rar archives supported)", end=' ')
else: else:
print "(rar archives not supported)", print("(rar archives not supported)", end=' ')
print print()
except util.PatoolError: except util.PatoolError:
handlers = programs.get(None, programs.get(command)) handlers = programs.get(None, programs.get(command))
print " %8s: - (no program found; install %s)" % \ print(" %8s: - (no program found; install %s)" %
(command, util.strlist_with_or(handlers)) (command, util.strlist_with_or(handlers)))
return 0 return 0
@ -521,15 +523,17 @@ def _handle_archive (archive, command, *args, **kwargs):
def get_archive_cmdlist_func (program, command, format): def get_archive_cmdlist_func (program, command, format):
# get python module for given archive program # get python module for given archive program
key = util.stripext(os.path.basename(program).lower()) key = util.stripext(os.path.basename(program).lower())
module = ProgramModules.get(key, key) modulename = ".programs." + ProgramModules.get(key, key)
# import archive handler function (eg. patoolib.programs.star.extract_tar) # import the module
args = (module, command, format)
import_cmd = "from .programs.%s import %s_%s as func" % args
try: try:
exec import_cmd module = importlib.import_module(modulename, __name__)
except ImportError: except ImportError as msg:
raise util.PatoolError('ImportError executing %r' % import_cmd) raise util.PatoolError(msg)
return locals()['func'] # get archive handler function (eg. patoolib.programs.star.extract_tar)
try:
return getattr(module, '%s_%s' % (command, format))
except AttributeError as msg:
raise util.PatoolError(msg)
def rmtree_log_error (func, path, exc): def rmtree_log_error (func, path, exc):
@ -542,7 +546,7 @@ def _diff_archives (archive1, archive2, **kwargs):
"""Show differences between two archives.""" """Show differences between two archives."""
if util.is_same_file(archive1, archive2): if util.is_same_file(archive1, archive2):
msg = "no differences found: archive `%s' and `%s' are the same files" msg = "no differences found: archive `%s' and `%s' are the same files"
print msg % (archive1, archive2) print(msg % (archive1, archive2))
return 0 return 0
diff = util.find_program("diff") diff = util.find_program("diff")
if not diff: if not diff:
@ -588,10 +592,10 @@ def handle_archive (archive, command, *args, **kwargs):
except KeyboardInterrupt: except KeyboardInterrupt:
util.log_error("aborted") util.log_error("aborted")
res = 1 res = 1
except util.PatoolError, msg: except util.PatoolError as msg:
util.log_error(msg) util.log_error(msg)
res = 1 res = 1
except StandardError, msg: except Exception as msg:
util.log_internal_error() util.log_internal_error()
res = 1 res = 1
return res return res

View File

@ -82,6 +82,11 @@ def format_paras(paras, width, indent=0):
def totype(v, default): def totype(v, default):
"""Tries to convert the value 'v' into the same type as 'default'. """Tries to convert the value 'v' into the same type as 'default'.
""" """
# Python3 does not have long, so fake it
try:
long
except NameError:
long = int
t = type(default) t = type(default)
if t is int: if t is int:
@ -188,10 +193,10 @@ class Baker(object):
if defaults: if defaults:
# Zip up the keyword argument names with their defaults # Zip up the keyword argument names with their defaults
keywords = dict(zip(arglist[0-len(defaults):], defaults)) keywords = dict(list(zip(arglist[0-len(defaults):], defaults)))
elif has_kwargs: elif has_kwargs:
# Allow keyword arguments specified by params. # Allow keyword arguments specified by params.
keywords = dict(zip(params.keys(), [""]*len(params))) keywords = dict(list(zip(params.keys(), [""]*len(params))))
# But set a flag to detect this # But set a flag to detect this
self.param_keywords = True self.param_keywords = True
else: else:
@ -409,7 +414,7 @@ class Baker(object):
# Process short option(s) # Process short option(s)
# For each character after the '-'... # For each character after the '-'...
for i in xrange(1, len(arg)): for i in range(1, len(arg)):
char = arg[i] char = arg[i]
if char not in shortchars: if char not in shortchars:
continue continue

View File

@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Archive commands echoing data, implemented by the Python print """Archive commands echoing data, implemented by the Python print
statement.""" statement."""
from __future__ import print_function
from .. import util from .. import util
@ -60,5 +61,5 @@ def list_flac (archive, compression, cmd, **kwargs):
def stripext (cmd, archive, extension=""): def stripext (cmd, archive, extension=""):
"""Print the name without suffix.""" """Print the name without suffix."""
print util.stripext(archive)+extension print(util.stripext(archive)+extension)
return None return None

View File

@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Utility functions.""" """Utility functions."""
from __future__ import print_function
import os import os
import sys import sys
import subprocess import subprocess
@ -30,7 +31,7 @@ def init_mimedb():
global mimedb global mimedb
try: try:
mimedb = mimetypes.MimeTypes(strict=False) mimedb = mimetypes.MimeTypes(strict=False)
except StandardError, msg: except Exception as msg:
log_error("could not initialize MIME database: %s" % msg) log_error("could not initialize MIME database: %s" % msg)
return return
add_mimedb_data(mimedb) add_mimedb_data(mimedb)
@ -78,7 +79,7 @@ def add_mimetype(mimedb, mimetype, extension):
mimedb.add_type(mimetype, extension, strict=strict) mimedb.add_type(mimetype, extension, strict=strict)
class PatoolError (StandardError): class PatoolError (Exception):
"""Raised when errors occur.""" """Raised when errors occur."""
pass pass
@ -324,7 +325,7 @@ def set_mode (filename, flags):
if not (mode & flags): if not (mode & flags):
try: try:
os.chmod(filename, flags | mode) os.chmod(filename, flags | mode)
except OSError, msg: except OSError as msg:
log_error("could not set mode flags for `%s': %s" % (filename, msg)) log_error("could not set mode flags for `%s': %s" % (filename, msg))
@ -375,20 +376,20 @@ def get_single_outfile (directory, archive, extension=""):
def log_error (msg, out=sys.stderr): def log_error (msg, out=sys.stderr):
"""Print error message to stderr (or any other given output).""" """Print error message to stderr (or any other given output)."""
print >> out, "patool error:", msg print("patool error:", msg, file=out)
def log_info (msg, out=sys.stdout): def log_info (msg, out=sys.stdout):
"""Print info message to stdout (or any other given output).""" """Print info message to stdout (or any other given output)."""
print >> out, "patool:", msg print("patool:", msg, file=out)
def log_internal_error (out=sys.stderr): def log_internal_error (out=sys.stderr):
"""Print internal error message to stderr.""" """Print internal error message to stderr."""
print >> out, "patool: internal error" print("patool: internal error", file=out)
traceback.print_exc() traceback.print_exc()
print >> out, "System info:" print("System info:", file=out)
print >> out, "Python %s on %s" % (sys.version, sys.platform) print("Python %s on %s" % (sys.version, sys.platform), file=out)
def p7zip_supports_rar (): def p7zip_supports_rar ():
@ -421,13 +422,17 @@ def append_to_path (path, directory):
def get_nt_7z_dir (): def get_nt_7z_dir ():
"""Return 7-Zip directory from registry, or an empty string.""" """Return 7-Zip directory from registry, or an empty string."""
# Python 3.x renamed the _winreg module to winreg
try: try:
import _winreg import _winreg as winreg
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\7-Zip") except ImportError:
import winreg
try: try:
return _winreg.QueryValueEx(key, "Path")[0] key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\7-Zip")
try:
return winreg.QueryValueEx(key, "Path")[0]
finally: finally:
_winreg.CloseKey(key) winreg.CloseKey(key)
except WindowsError: except WindowsError:
return "" return ""

View File

@ -17,10 +17,10 @@
""" """
Setup file for the distuils module. Setup file for the distuils module.
""" """
from __future__ import print_function
import sys import sys
if not hasattr(sys, "version_info") or sys.version_info < (2, 4, 0, "final", 0): if not hasattr(sys, "version_info") or sys.version_info < (2, 7, 0, "final", 0):
raise SystemExit("This program requires Python 2.4 or later.") raise SystemExit("This program requires Python 2.7 or later.")
import os import os
import shutil import shutil
import glob import glob
@ -164,37 +164,37 @@ class InnoScript:
def write_inno_script (self, fd): def write_inno_script (self, fd):
"""Write Inno script contents.""" """Write Inno script contents."""
print >> fd, "; WARNING: This script has been created by py2exe. Changes to this script" print("; WARNING: This script has been created by py2exe. Changes to this script", file=fd)
print >> fd, "; will be overwritten the next time py2exe is run!" print("; will be overwritten the next time py2exe is run!", file=fd)
print >> fd, "[Setup]" print("[Setup]", file=fd)
print >> fd, "AppName=%s" % self.name print("AppName=%s" % self.name, file=fd)
print >> fd, "AppVerName=%s %s" % (self.name, self.version) print("AppVerName=%s %s" % (self.name, self.version), file=fd)
print >> fd, r"DefaultDirName={pf}\%s" % self.name print(r"DefaultDirName={pf}\%s" % self.name, file=fd)
print >> fd, "DefaultGroupName=%s" % self.name print("DefaultGroupName=%s" % self.name, file=fd)
print >> fd, "OutputBaseFilename=%s" % self.distfilebase print("OutputBaseFilename=%s" % self.distfilebase, file=fd)
print >> fd, "OutputDir=.." print("OutputDir=..", file=fd)
print >> fd, "SetupIconFile=%s" % self.icon print("SetupIconFile=%s" % self.icon, file=fd)
print >> fd print(file=fd)
# List of source files # List of source files
files = self.windows_exe_files + \ files = self.windows_exe_files + \
self.console_exe_files + \ self.console_exe_files + \
self.service_exe_files + \ self.service_exe_files + \
self.comserver_files + \ self.comserver_files + \
self.lib_files self.lib_files
print >> fd, '[Files]' print('[Files]', file=fd)
for path in files: for path in files:
print >> fd, r'Source: "%s"; DestDir: "{app}\%s"; Flags: ignoreversion' % (path, os.path.dirname(path)) print(r'Source: "%s"; DestDir: "{app}\%s"; Flags: ignoreversion' % (path, os.path.dirname(path)), file=fd)
# Set icon filename # Set icon filename
print >> fd, '[Icons]' print('[Icons]', file=fd)
for path in self.windows_exe_files: for path in self.windows_exe_files:
print >> fd, r'Name: "{group}\%s"; Filename: "{app}\%s"' % \ print(r'Name: "{group}\%s"; Filename: "{app}\%s"' %
(self.name, path) (self.name, path), file=fd)
print >> fd, r'Name: "{group}\Uninstall %s"; Filename: "{uninstallexe}"' % self.name print(r'Name: "{group}\Uninstall %s"; Filename: "{uninstallexe}"' % self.name, file=fd)
print >> fd print(file=fd)
# Uninstall optional log files # Uninstall optional log files
print >> fd, '[UninstallDelete]' print('[UninstallDelete]', file=fd)
print >> fd, r'Type: files; Name: "{pf}\%s\patool*.exe.log"' % self.name print(r'Type: files; Name: "{pf}\%s\patool*.exe.log"' % self.name, file=fd)
print >> fd print(file=fd)
def compile (self): def compile (self):
"""Compile Inno script with iscc.exe.""" """Compile Inno script with iscc.exe."""
@ -209,7 +209,7 @@ class InnoScript:
cmd = ['signtool.exe', 'sign', '/f', pfxfile, self.distfile] cmd = ['signtool.exe', 'sign', '/f', pfxfile, self.distfile]
subprocess.check_call(cmd) subprocess.check_call(cmd)
else: else:
print "No signed installer: certificate %s not found." % pfxfile print("No signed installer: certificate %s not found." % pfxfile)
try: try:
from py2exe.build_exe import py2exe as py2exe_build from py2exe.build_exe import py2exe as py2exe_build
@ -222,16 +222,16 @@ try:
"""Generate py2exe installer.""" """Generate py2exe installer."""
# First, let py2exe do it's work. # First, let py2exe do it's work.
py2exe_build.run(self) py2exe_build.run(self)
print "*** preparing the inno setup script ***" print("*** preparing the inno setup script ***")
lib_dir = self.lib_dir lib_dir = self.lib_dir
dist_dir = self.dist_dir dist_dir = self.dist_dir
# create the Installer, using the files py2exe has created. # create the Installer, using the files py2exe has created.
script = InnoScript(lib_dir, dist_dir, self.windows_exe_files, script = InnoScript(lib_dir, dist_dir, self.windows_exe_files,
self.console_exe_files, self.service_exe_files, self.console_exe_files, self.service_exe_files,
self.comserver_files, self.lib_files) self.comserver_files, self.lib_files)
print "*** creating the inno setup script ***" print("*** creating the inno setup script ***")
script.create() script.create()
print "*** compiling the inno setup script ***" print("*** compiling the inno setup script ***")
script.compile() script.compile()
script.sign() script.sign()
except ImportError: except ImportError:

View File

@ -14,12 +14,18 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import os import os
import sys
import patoolib import patoolib
import pytest import pytest
basedir = os.path.dirname(__file__) basedir = os.path.dirname(__file__)
datadir = os.path.join(basedir, 'data') datadir = os.path.join(basedir, 'data')
# Python 3.x renamed the function name attribute
if sys.version_info[0] > 2:
fnameattr = '__name__'
else:
fnameattr = 'func_name'
def needs_os (name): def needs_os (name):
"""Decorator skipping test if given program is not available.""" """Decorator skipping test if given program is not available."""
@ -28,7 +34,7 @@ def needs_os (name):
if os.name != name: if os.name != name:
raise pytest.skip("operating system %s not found" % name) raise pytest.skip("operating system %s not found" % name)
return f(*args, **kwargs) return f(*args, **kwargs)
newfunc.func_name = f.func_name setattr(newfunc, fnameattr, getattr(f, fnameattr))
return newfunc return newfunc
return check_prog return check_prog
@ -40,7 +46,7 @@ def needs_program (program):
if not patoolib.util.find_program(program): if not patoolib.util.find_program(program):
raise pytest.skip("program `%s' not available" % program) raise pytest.skip("program `%s' not available" % program)
return f(*args, **kwargs) return f(*args, **kwargs)
newfunc.func_name = f.func_name setattr(newfunc, fnameattr, getattr(f, fnameattr))
return newfunc return newfunc
return check_prog return check_prog
@ -55,7 +61,7 @@ def needs_one_program (programs):
else: else:
raise pytest.skip("None of programs %s available" % programs) raise pytest.skip("None of programs %s available" % programs)
return f(*args, **kwargs) return f(*args, **kwargs)
newfunc.func_name = f.func_name setattr(newfunc, fnameattr, getattr(f, fnameattr))
return newfunc return newfunc
return check_prog return check_prog
@ -69,7 +75,7 @@ def needs_codec (program, codec):
if not has_codec(program, codec): if not has_codec(program, codec):
raise pytest.skip("codec `%s' for program `%s' not available" % (codec, program)) raise pytest.skip("codec `%s' for program `%s' not available" % (codec, program))
return f(*args, **kwargs) return f(*args, **kwargs)
newfunc.func_name = f.func_name setattr(newfunc, fnameattr, getattr(f, fnameattr))
return newfunc return newfunc
return check_prog return check_prog
@ -81,5 +87,3 @@ def has_codec (program, codec):
if patoolib.program_supports_compression(program, codec): if patoolib.program_supports_compression(program, codec):
return True return True
return patoolib.util.find_program(codec) return patoolib.util.find_program(codec)