diff --git a/PyInstaller/__init__.py b/PyInstaller/__init__.py index dada3d51a3..7e05dcf983 100644 --- a/PyInstaller/__init__.py +++ b/PyInstaller/__init__.py @@ -21,6 +21,8 @@ # Fail hard if Python does not have minimum required version if sys.version_info < (2, 4): raise SystemExit('PyInstaller requires at least Python 2.4, sorry.') +elif sys.version_info >= (3,): + raise SystemExit('Python 3 is not yet supported, sorry.') # Extend PYTHONPATH with 3rd party libraries bundled with PyInstaller. diff --git a/PyInstaller/build.py b/PyInstaller/build.py index abc5ba5bd3..eddc1d031e 100644 --- a/PyInstaller/build.py +++ b/PyInstaller/build.py @@ -69,6 +69,14 @@ _init_code_path = os.path.join(HOMEPATH, 'PyInstaller', 'loader') _fake_code_path = os.path.join(HOMEPATH, 'PyInstaller', 'fake') + +_MISSING_BOOTLOADER_ERRORMSG = """ +Fatal error: PyInstaller does not include a pre-compiled bootloader for your +platform. See +for more details and instructions how to build the bootloader. +""" + + def _save_data(filename, data): dirname = os.path.dirname(filename) if not os.path.exists(dirname): @@ -195,7 +203,7 @@ def _check_guts_eq(attr, old, new, last_build): rebuild is required if values differ """ if old != new: - logger.info("building because %s changed", attr) + logger.info("Building because %s changed", attr) return True return False @@ -209,10 +217,10 @@ def _check_guts_toc_mtime(attr, old, toc, last_build, pyc=0): """ for (nm, fnm, typ) in old: if mtime(fnm) > last_build: - logger.info("building because %s changed", fnm) + logger.info("Building because %s changed", fnm) return True elif pyc and mtime(fnm[:-1]) > last_build: - logger.info("building because %s changed", fnm[:-1]) + logger.info("Building because %s changed", fnm[:-1]) return True return False @@ -323,11 +331,11 @@ def get_guts(self, last_build, missing='missing or bad'): try: data = _load_data(self.out) except: - logger.info("building because %s %s", os.path.basename(self.out), missing) + logger.info("Building because %s %s", os.path.basename(self.out), missing) return None if len(data) != len(self.GUTS): - logger.info("building because %s is bad", self.outnm) + logger.info("Building because %s is bad", self.outnm) return None for i, (attr, func) in enumerate(self.GUTS): if func is None: @@ -487,11 +495,11 @@ def __init__(self, scripts=None, pathex=None, hiddenimports=None, def check_guts(self, last_build): if last_build == 0: - logger.info("building %s because %s non existent", self.__class__.__name__, self.outnm) + logger.info("Building %s because %s non existent", self.__class__.__name__, self.outnm) return True for fnm in self.inputs: if mtime(fnm) > last_build: - logger.info("building because %s changed", fnm) + logger.info("Building because %s changed", fnm) return True data = Target.get_guts(self, last_build) @@ -741,7 +749,7 @@ def __init__(self, toc, name=None, level=9, cipher=None): def check_guts(self, last_build): if not os.path.exists(self.name): - logger.info("rebuilding %s because %s is missing", + logger.info("Rebuilding %s because %s is missing", self.outnm, os.path.basename(self.name)) return True @@ -751,7 +759,7 @@ def check_guts(self, last_build): return False def assemble(self): - logger.info("building PYZ (ZlibArchive) %s", os.path.basename(self.out)) + logger.info("Building PYZ (ZlibArchive) %s", os.path.basename(self.out)) pyz = pyi_archive.ZlibArchive(level=self.level, cipher=self.cipher) toc = self.toc - config['PYZ_dependencies'] pyz.build(self.name, toc) @@ -805,7 +813,12 @@ def checkCache(fnm, strip=False, upx=False, dist_nm=None): cache_index = {} # Verify if the file we're looking for is present in the cache. - basenm = os.path.normcase(os.path.basename(fnm)) + # Use the dist_mn if given to avoid different extension modules + # sharing the same basename get corrupted. + if dist_nm: + basenm = os.path.normcase(dist_nm) + else: + basenm = os.path.normcase(os.path.basename(fnm)) digest = cacheDigest(fnm) cachedfile = os.path.join(cachedir, basenm) cmd = None @@ -984,7 +997,7 @@ def __init__(self, toc, name=None, cdict=None, exclude_binaries=0, def check_guts(self, last_build): if not os.path.exists(self.name): - logger.info("rebuilding %s because %s is missing", + logger.info("Rebuilding %s because %s is missing", self.outnm, os.path.basename(self.name)) return 1 @@ -995,7 +1008,7 @@ def check_guts(self, last_build): return False def assemble(self): - logger.info("building PKG (CArchive) %s", os.path.basename(self.name)) + logger.info("Building PKG (CArchive) %s", os.path.basename(self.name)) trash = [] mytoc = [] seen = {} @@ -1075,6 +1088,12 @@ def __init__(self, *args, **kwargs): a version resource from an executable and then edit the output to create your own. (The syntax of version resources is so arcane that I wouldn't attempt to write one from scratch). + uac_admin + Windows only. Setting to True creates a Manifest with will request + elevation upon application restart + uac_uiaccess + Windows only. Setting to True allows an elevated application to + work with Remote Desktop """ Target.__init__(self) @@ -1092,6 +1111,10 @@ def __init__(self, *args, **kwargs): # to the exe, but copied beside it. self.append_pkg = kwargs.get('append_pkg', True) + # On Windows allows the exe to request admin privileges. + self.uac_admin = kwargs.get('uac_admin', False) + self.uac_uiaccess = kwargs.get('uac_uiaccess', False) + if config['hasUPX']: self.upx = kwargs.get('upx', False) else: @@ -1126,12 +1149,14 @@ def __init__(self, *args, **kwargs): self.toc.extend(arg.dependencies) else: self.toc.extend(arg) + if is_win: filename = os.path.join(WORKPATH, specnm + ".exe.manifest") self.manifest = winmanifest.create_manifest(filename, self.manifest, - self.console) + self.console, self.uac_admin, self.uac_uiaccess) self.toc.append((os.path.basename(self.name) + ".manifest", filename, 'BINARY')) + self.pkg = PKG(self.toc, cdict=kwargs.get('cdict', None), exclude_binaries=self.exclude_binaries, strip_binaries=self.strip, upx_binaries=self.upx, @@ -1152,11 +1177,11 @@ def __init__(self, *args, **kwargs): def check_guts(self, last_build): if not os.path.exists(self.name): - logger.info("rebuilding %s because %s missing", + logger.info("Rebuilding %s because %s missing", self.outnm, os.path.basename(self.name)) return 1 if not self.append_pkg and not os.path.exists(self.pkgname): - logger.info("rebuilding because %s missing", + logger.info("Rebuilding because %s missing", os.path.basename(self.pkgname)) return 1 @@ -1171,10 +1196,10 @@ def check_guts(self, last_build): mtm = data[-1] if mtm != mtime(self.name): - logger.info("rebuilding %s because mtimes don't match", self.outnm) + logger.info("Rebuilding %s because mtimes don't match", self.outnm) return True if mtm < mtime(self.pkg.out): - logger.info("rebuilding %s because pkg is more recent", self.outnm) + logger.info("Rebuilding %s because pkg is more recent", self.outnm) return True return False @@ -1184,18 +1209,31 @@ def _bootloader_file(self, exe): exe = exe + 'w' if self.debug: exe = exe + '_d' - return os.path.join('PyInstaller', 'bootloader', PLATFORM, exe) + return os.path.join(HOMEPATH, 'PyInstaller', 'bootloader', PLATFORM, exe) def assemble(self): - logger.info("building EXE from %s", os.path.basename(self.out)) + logger.info("Building EXE from %s", os.path.basename(self.out)) trash = [] if not os.path.exists(os.path.dirname(self.name)): os.makedirs(os.path.dirname(self.name)) outf = open(self.name, 'wb') exe = self._bootloader_file('run') - exe = os.path.join(HOMEPATH, exe) if is_win or is_cygwin: exe = exe + '.exe' + + if not os.path.exists(exe): + raise SystemExit(_MISSING_BOOTLOADER_ERRORMSG) + + if is_win and not self.exclude_binaries: + # Windows and onefile mode - embed manifest into exe. + logger.info('Onefile Mode - Embedding Manifest into EXE file') + tmpnm = tempfile.mktemp() + shutil.copy2(exe, tmpnm) + os.chmod(tmpnm, 0755) + self.manifest.update_resources(tmpnm, [1]) # 1 for executable + trash.append(tmpnm) + exe = tmpnm + if config['hasRsrcUpdate'] and (self.icon or self.versrsrc or self.resources): tmpnm = tempfile.mktemp() @@ -1291,10 +1329,11 @@ class DLL(EXE): need to write your own dll. """ def assemble(self): - logger.info("building DLL %s", os.path.basename(self.out)) + logger.info("Building DLL %s", os.path.basename(self.out)) outf = open(self.name, 'wb') - dll = self._bootloader_file('inprocsrvr') - dll = os.path.join(HOMEPATH, dll) + '.dll' + dll = self._bootloader_file('inprocsrvr') + '.dll' + if not os.path.exists(dll): + raise SystemExit(_MISSING_BOOTLOADER_ERRORMSG) self.copy(dll, outf) self.copy(self.pkg.name, outf) outf.close() @@ -1367,7 +1406,7 @@ def check_guts(self, last_build): def assemble(self): if _check_path_overlap(self.name) and os.path.isdir(self.name): _rmtree(self.name) - logger.info("building COLLECT %s", os.path.basename(self.out)) + logger.info("Building COLLECT %s", os.path.basename(self.out)) os.makedirs(self.name) toc = addSuffixToExtensions(self.toc) for inm, fnm, typ in toc: @@ -1476,7 +1515,7 @@ def check_guts(self, last_build): def assemble(self): if _check_path_overlap(self.name) and os.path.isdir(self.name): _rmtree(self.name) - logger.info("building BUNDLE %s", os.path.basename(self.out)) + logger.info("Building BUNDLE %s", os.path.basename(self.out)) # Create a minimal Mac bundle structure os.makedirs(os.path.join(self.name, "Contents", "MacOS")) @@ -1603,72 +1642,71 @@ class TOC(UserList.UserList): """ def __init__(self, initlist=None): UserList.UserList.__init__(self) - self.fltr = {} + self.filenames = set() if initlist: - for tpl in initlist: - self.append(tpl) - - def append(self, tpl): - try: - fn = tpl[0] - if tpl[2] in ["BINARY", "DATA"]: - # Normalize the case for binary and data files only (to avoid duplicates - # for different cases under Windows). We can't do that for - # Python files because the import semantic (even at runtime) - # depends on the case. - fn = os.path.normcase(fn) - if not self.fltr.get(fn): - self.data.append(tpl) - self.fltr[fn] = 1 - except TypeError: - logger.info("TOC found a %s, not a tuple", tpl) - raise - - def insert(self, pos, tpl): - fn = tpl[0] - if tpl[2] == "BINARY": - fn = os.path.normcase(fn) - if not self.fltr.get(fn): - self.data.insert(pos, tpl) - self.fltr[fn] = 1 + for entry in initlist: + self.append(entry) + + def _normentry(self, entry): + if not isinstance(entry, tuple): + logger.info("TOC found a %s, not a tuple", entry) + raise TypeError("Expected tuple, not %s." % type(entry).__name__) + name, path, typecode = entry + if typecode == "BINARY": + # Normalize the case for binary files only (to avoid duplicates + # for different cases under Windows). We can't do that for + # Python files because the import semantic (even at runtime) + # depends on the case. + name = os.path.normcase(name) + return (name, path, typecode) + + def append(self, entry): + name, path, typecode = self._normentry(entry) + if name not in self.filenames: + self.data.append((name, path, typecode)) + self.filenames.add(name) + + def insert(self, pos, entry): + name, path, typecode = self._normentry(entry) + if name not in self.filenames: + self.data.insert(pos, (name, path, typecode)) + self.filenames.add(name) def __add__(self, other): - rslt = TOC(self.data) - rslt.extend(other) - return rslt + result = TOC(self) + result.extend(other) + return result def __radd__(self, other): - rslt = TOC(other) - rslt.extend(self.data) - return rslt + result = TOC(other) + result.extend(self) + return result def extend(self, other): - for tpl in other: - self.append(tpl) + for entry in other: + self.append(entry) def __sub__(self, other): - fd = self.fltr.copy() - # remove from fd if it's in other - for tpl in other: - if fd.get(tpl[0], 0): - del fd[tpl[0]] - rslt = TOC() - # return only those things still in fd (preserve order) - for tpl in self.data: - if fd.get(tpl[0], 0): - rslt.append(tpl) - return rslt + other = TOC(other) + filenames = self.filenames - other.filenames + result = TOC() + for name, path, typecode in self: + if name in filenames: + result.data.append((name, path, typecode)) + return result def __rsub__(self, other): - rslt = TOC(other) - return rslt.__sub__(self) + result = TOC(other) + return result.__sub__(self) def intersect(self, other): - rslt = TOC() - for tpl in other: - if self.fltr.get(tpl[0], 0): - rslt.append(tpl) - return rslt + other = TOC(other) + filenames = self.filenames.intersection(other.filenames) + result = TOC() + for name, path, typecode in other: + if name in filenames: + result.data.append((name, path, typecode)) + return result class Tree(Target, TOC): @@ -1715,7 +1753,7 @@ def check_guts(self, last_build): while stack: d = stack.pop() if mtime(d) > last_build: - logger.info("building %s because directory %s changed", + logger.info("Building %s because directory %s changed", self.outnm, d) return True for nm in os.listdir(d): @@ -1726,7 +1764,7 @@ def check_guts(self, last_build): return False def assemble(self): - logger.info("building Tree %s", os.path.basename(self.out)) + logger.info("Building Tree %s", os.path.basename(self.out)) stack = [(self.root, self.prefix)] excludes = {} xexcludes = {} @@ -1948,4 +1986,7 @@ def main(pyi_config, specfile, noconfirm, ascii=False, **kw): if config['hasUPX']: setupUPXFlags() + config['ui_admin'] = kw.get('ui_admin', False) + config['ui_access'] = kw.get('ui_uiaccess', False) + build(specfile, kw.get('distpath'), kw.get('workpath'), kw.get('clean_build')) diff --git a/PyInstaller/cliutils/__init__.py b/PyInstaller/cliutils/__init__.py index e69de29bb2..792d600548 100644 --- a/PyInstaller/cliutils/__init__.py +++ b/PyInstaller/cliutils/__init__.py @@ -0,0 +1 @@ +# diff --git a/PyInstaller/cliutils/archive_viewer.py b/PyInstaller/cliutils/archive_viewer.py index eccc5f9f16..9ba68874f0 100644 --- a/PyInstaller/cliutils/archive_viewer.py +++ b/PyInstaller/cliutils/archive_viewer.py @@ -12,6 +12,7 @@ Viewer for archives packaged by archive.py """ +from __future__ import print_function import optparse import os @@ -46,7 +47,7 @@ def main(opts, args): rec_debug = opts.rec brief = opts.brief if not os.path.isfile(name): - print "%s is an invalid file name!" % name + print(name, "is an invalid file name!") return 1 arch = get_archive(name) @@ -62,7 +63,7 @@ def main(opts, args): toks = raw_input('? ').split(None, 1) except EOFError: # Ctrl-D - print # Clear line. + print() # Clear line. break if not toks: usage() @@ -86,7 +87,7 @@ def main(opts, args): arg = arg.strip() arch = get_archive(arg) if arch is None: - print arg, "not found" + print(arg, "not found") continue stack.append((arg, arch)) show(arg, arch) @@ -96,11 +97,11 @@ def main(opts, args): arg = arg.strip() data = get_data(arg, arch) if data is None: - print "Not found" + print("Not found") continue fnm = raw_input('to filename? ') if not fnm: - print repr(data) + print(repr(data)) else: open(fnm, 'wb').write(data) elif cmd == 'Q': @@ -114,14 +115,14 @@ def main(opts, args): try: os.remove(fnm) except Exception, e: - print "couldn't delete", fnm, e.args + print("couldn't delete", fnm, e.args) def usage(): - print "U: go Up one level" - print "O : open embedded archive nm" - print "X : extract nm" - print "Q: quit" + print("U: go Up one level") + print("O : open embedded archive nm") + print("X : extract nm") + print("Q: quit") def get_archive(nm): @@ -162,10 +163,10 @@ def get_data(nm, arch): def show(nm, arch): if type(arch.toc) == type({}): - print " Name: (ispkg, pos, len)" + print(" Name: (ispkg, pos, len)") toc = arch.toc else: - print " pos, length, uncompressed, iscompressed, type, name" + print(" pos, length, uncompressed, iscompressed, type, name") toc = arch.toc.data pprint.pprint(toc) @@ -204,7 +205,7 @@ def checkmagic(self): raise RuntimeError("%s is not a valid %s archive file" % (self.path, self.__class__.__name__)) if self.lib.read(len(self.pymagic)) != self.pymagic: - print "Warning: pyz is from a different Python version" + print("Warning: pyz is from a different Python version") self.lib.read(4) diff --git a/PyInstaller/cliutils/bindepend.py b/PyInstaller/cliutils/bindepend.py index 4caef52d6e..f688a8332a 100644 --- a/PyInstaller/cliutils/bindepend.py +++ b/PyInstaller/cliutils/bindepend.py @@ -12,6 +12,7 @@ Show dll dependencies of executable files or other dynamic libraries. """ +from __future__ import print_function import glob import optparse @@ -47,6 +48,6 @@ def run(): if is_win: assemblies = PyInstaller.bindepend.getAssemblies(fn) imports.update([a.getid() for a in assemblies]) - print fn, imports + print(fn, imports) except KeyboardInterrupt: raise SystemExit("Aborted by user request.") diff --git a/PyInstaller/cliutils/grab_version.py b/PyInstaller/cliutils/grab_version.py index a1b7f1f5b2..2aef4139d3 100644 --- a/PyInstaller/cliutils/grab_version.py +++ b/PyInstaller/cliutils/grab_version.py @@ -24,14 +24,14 @@ def run(): out_filename = os.path.abspath('file_version_info.txt') if len(sys.argv) < 2: - print 'Usage: python grab_version.py [ out.txt ]' - print ' where: is the fullpathname of a Windows executable and' - print ' is the optional pathname where the grabbed ' - print ' version info will be saved.' - print ' default out filename: file_version_info.txt ' - print ' The printed output may be saved to a file, edited and ' - print ' used as the input for a version resource on any of the ' - print ' executable targets in an Installer spec file.' + print('Usage: python grab_version.py [ out.txt ]') + print(' where: is the fullpathname of a Windows executable and') + print(' is the optional pathname where the grabbed') + print(' version info will be saved.') + print(' default out filename: file_version_info.txt') + print(' The printed output may be saved to a file, edited and') + print(' used as the input for a version resource on any of the') + print(' executable targets in an Installer spec file.') raise SystemExit(1) if len(sys.argv) == 3: diff --git a/PyInstaller/cliutils/make_comserver.py b/PyInstaller/cliutils/make_comserver.py index bb8a9ef9df..359532641e 100644 --- a/PyInstaller/cliutils/make_comserver.py +++ b/PyInstaller/cliutils/make_comserver.py @@ -7,6 +7,7 @@ # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- +from __future__ import print_function import optparse import os @@ -91,11 +92,11 @@ def create(scripts, debug, verbose, workdir, ascii=0): d = {'modules': modimports, 'klasses': klassspecs} outf.write(tmplt % d) outf.close() - print "**********************************" - print "Driver script %s created" % outfnm + print("**********************************") + print("Driver script", outfnm, "created") specfnm = PyInstaller.makespec.main([outfnm], console=debug, debug=debug, workdir=workdir, pathex=paths, comserver=1, ascii=ascii) - print "Spec file %s created" % specfnm + print("Spec file", specfnm, "created") def analscriptname(script): @@ -144,7 +145,7 @@ def run(): parser = optparse.OptionParser( usage='python %s [options] .py [.py ...]', epilog="The next step is to run pyi-build against the generated" - "spec file." + " spec file." ) parser.add_option('--debug', default=False, action='store_true', help='Enable bootloader debug messages, and register COM servers with debug') @@ -154,14 +155,16 @@ def run(): metavar='DIR', dest='workdir', help='Where to write the generated script and spec file') - parser.add_option('--ascii', default=False, action='store_true') + parser.add_option("-a", "--ascii", action="store_true", + help="Do not include unicode encoding support " + "(default: included if available)") opts, args = parser.parse_args() if not args: parser.error('Requires at least one script filename') try: - print - print epilog + print() + print(epilog) except KeyboardInterrupt: raise SystemExit("Aborted by user request.") diff --git a/PyInstaller/cliutils/makespec.py b/PyInstaller/cliutils/makespec.py index d89822bb14..8bacba42cb 100644 --- a/PyInstaller/cliutils/makespec.py +++ b/PyInstaller/cliutils/makespec.py @@ -46,7 +46,7 @@ def run(): try: name = PyInstaller.makespec.main(args, **opts.__dict__) - print 'wrote %s' % name - print 'now run pyinstaller.py to build the executable' + print('wrote %s' % name) + print('now run pyinstaller.py to build the executable') except KeyboardInterrupt: raise SystemExit("Aborted by user request.") diff --git a/PyInstaller/cliutils/set_version.py b/PyInstaller/cliutils/set_version.py index fe990a9a17..705317df0d 100644 --- a/PyInstaller/cliutils/set_version.py +++ b/PyInstaller/cliutils/set_version.py @@ -22,9 +22,9 @@ def run(): out_filename = os.path.abspath('file_version_info.txt') if len(sys.argv) < 3: - print 'Usage: python set_version.py ' - print ' where: is file containing version info' - print ' and is the fullpathname of a Windows executable.' + print('Usage: python set_version.py ') + print(' where: is file containing version info') + print(' and is the fullpathname of a Windows executable.') raise SystemExit(1) info_file = os.path.abspath(sys.argv[1]) diff --git a/PyInstaller/depend/__init__.py b/PyInstaller/depend/__init__.py index e69de29bb2..792d600548 100644 --- a/PyInstaller/depend/__init__.py +++ b/PyInstaller/depend/__init__.py @@ -0,0 +1 @@ +# diff --git a/PyInstaller/depend/imptracker.py b/PyInstaller/depend/imptracker.py index 6bfb77d0db..0d95a83f18 100644 --- a/PyInstaller/depend/imptracker.py +++ b/PyInstaller/depend/imptracker.py @@ -127,7 +127,7 @@ def analyze_one(self, nm, importernm=None, imptyp=0, level=-1): break the name being imported up so we get: a.b.c -> [a, b, c] ; ..z -> ['', '', z] """ - #print '## analyze_one', nm, importernm, imptyp, level + #print('## analyze_one', nm, importernm, imptyp, level) if not nm: nm = importernm importernm = None @@ -241,7 +241,7 @@ def doimport(self, nm, ctx, fqname): Return dict containing collected information about module ( """ - #print "doimport", nm, ctx, fqname + #print("doimport", nm, ctx, fqname) # NOTE that nm is NEVER a dotted name at this point assert ("." not in nm), nm if fqname in self.excludes: diff --git a/PyInstaller/fake/__init__.py b/PyInstaller/fake/__init__.py index e69de29bb2..792d600548 100644 --- a/PyInstaller/fake/__init__.py +++ b/PyInstaller/fake/__init__.py @@ -0,0 +1 @@ +# diff --git a/PyInstaller/hooks/__init__.py b/PyInstaller/hooks/__init__.py index 8b13789179..792d600548 100644 --- a/PyInstaller/hooks/__init__.py +++ b/PyInstaller/hooks/__init__.py @@ -1 +1 @@ - +# diff --git a/PyInstaller/hooks/hook-PyQt4.Qwt5.py b/PyInstaller/hooks/hook-PyQt4.Qwt5.py index 81f7285d97..5d80a60f7c 100644 --- a/PyInstaller/hooks/hook-PyQt4.Qwt5.py +++ b/PyInstaller/hooks/hook-PyQt4.Qwt5.py @@ -12,9 +12,9 @@ hiddenimports = ["PyQt4.QtCore", "PyQt4.QtGui", "PyQt4.QtSvg"] -if eval_statement("from PyQt4 import Qwt5; print hasattr(Qwt5, 'toNumpy')"): +if eval_statement("from PyQt4 import Qwt5; print(hasattr(Qwt5, 'toNumpy'))"): hiddenimports.append("numpy") -if eval_statement("from PyQt4 import Qwt5; print hasattr(Qwt5, 'toNumeric')"): +if eval_statement("from PyQt4 import Qwt5; print(hasattr(Qwt5, 'toNumeric'))"): hiddenimports.append("Numeric") -if eval_statement("from PyQt4 import Qwt5; print hasattr(Qwt5, 'toNumarray')"): +if eval_statement("from PyQt4 import Qwt5; print(hasattr(Qwt5, 'toNumarray'))"): hiddenimports.append("numarray") diff --git a/PyInstaller/hooks/hook-PyQt4.uic.py b/PyInstaller/hooks/hook-PyQt4.uic.py index 3fa0f1e04c..f488e76781 100644 --- a/PyInstaller/hooks/hook-PyQt4.uic.py +++ b/PyInstaller/hooks/hook-PyQt4.uic.py @@ -7,35 +7,42 @@ # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- - -# Because this is PyQt4.uic, note the .. required in order to get back to the hooks subdirectory. -from PyInstaller.hooks.hookutils import collect_submodules, get_package_paths +# Because this is PyQt4.uic, note the fully qualified package name required in +# order to refer to hookutils. +from PyInstaller.hooks.hookutils import collect_submodules, collect_data_files from PyInstaller.compat import is_linux -import os - - -# Need to include modules in PyQt4.uic.widget-plugins, so they will be -# dnamically loaded by uic. They should both be included in the Python archive -# and as separate (data-like) files, so they can be found by os.listdir and -# friends. However, this directory isn't a package, so we can't collect -# submodules('PyQt4.uic.widget-plugins'). Instead, collect the parent directory -# for simplicity, since all the parent directory (uic) code will already be included. -hiddenimports = collect_submodules('PyQt4.uic') - - -# On Linux PyQt4.uic could use PyKDE4 package for some rendering. +# On Linux PyQt4.uic might use the PyKDE4 package for some rendering. If it +# isn't installed, the the following exception is raised:: +# +# File "/usr/local/lib/python2.7/dist-packages/PyInstaller-2.1.1dev_9e9d21b-py2.7.egg/PyInstaller/hooks/hook-PyQt4.uic.py", line 29, in +# hiddenimports += collect_submodules('PyKDE4') + ['PyQt4.QtSvg', 'PyQt4.QtXml'] +# File "/usr/local/lib/python2.7/dist-packages/PyInstaller-2.1.1dev_9e9d21b-py2.7.egg/PyInstaller/hooks/hookutils.py", line 679, in collect_submodules +# pkg_base, pkg_dir = get_package_paths(package) +# File "/usr/local/lib/python2.7/dist-packages/PyInstaller-2.1.1dev_9e9d21b-py2.7.egg/PyInstaller/hooks/hookutils.py", line 646, in get_package_paths +# assert is_package, 'Package %s does not have __path__ attribute' % package +# AssertionError: Package PyKDE4 does not have __path__ attribute +# +# Therefeore, catch this exception and ignore it. When this happends, a message +# is still generated:: +# +# 2141 INFO: Processing hook hook-PyQt4.QtCore +# Traceback (most recent call last): +# File "", line 1, in +# ImportError: No module named PyKDE4 +# 2862 INFO: Processing hook hook-PyQt4.uic +# +# Note that the warning comes BEFORE hook-PyQt4.uic is listed, not after; +# however, the raised assertion caught by the try/except block below produces +# it, not any code in hook-PyQt4.QtCore. if is_linux: - hiddenimports += collect_submodules('PyKDE4') + ['PyQt4.QtSvg', 'PyQt4.QtXml'] - - -# Likewise, a call to collect_data_files('PyQt4.uic.widget-plugins', True) -# would be very convenient, but again this isn't a package. Hand-code this -# to collect fewer files. -datas = [] -pkg_base, pkg_dir = get_package_paths('PyQt4.uic') -widgets_dir = pkg_dir + '/widget-plugins/' - - -for f in os.listdir(widgets_dir): - datas.append([widgets_dir + f, 'PyQt4/uic/widget-plugins']) + try: + hiddenimports = collect_submodules('PyKDE4') + ['PyQt4.QtSvg', 'PyQt4.QtXml'] + except AssertionError: + pass +# Need to include modules in PyQt4.uic.widget-plugins, so they can be +# dynamically loaded by uic. They should both be included as separate +# (data-like) files, so they can be found by os.listdir and friends. However, +# this directory isn't a package, refer to it using the package (PyQt4.uic) +# followed by the subdirectory name (widget-plugins/). +datas = collect_data_files('PyQt4.uic', True, 'widget-plugins') diff --git a/PyInstaller/hooks/hook-PyQt5.Qwt5.py b/PyInstaller/hooks/hook-PyQt5.Qwt5.py index 22747a703d..c99e5730a4 100644 --- a/PyInstaller/hooks/hook-PyQt5.Qwt5.py +++ b/PyInstaller/hooks/hook-PyQt5.Qwt5.py @@ -15,9 +15,9 @@ "PyQt5.QtGui", "PyQt5.QtSvg"] -if eval_statement("from PyQt5 import Qwt5; print hasattr(Qwt5, 'toNumpy')"): +if eval_statement("from PyQt5 import Qwt5; print(hasattr(Qwt5, 'toNumpy'))"): hiddenimports.append("numpy") -if eval_statement("from PyQt5 import Qwt5; print hasattr(Qwt5, 'toNumeric')"): +if eval_statement("from PyQt5 import Qwt5; print(hasattr(Qwt5, 'toNumeric'))"): hiddenimports.append("Numeric") -if eval_statement("from PyQt5 import Qwt5; print hasattr(Qwt5, 'toNumarray')"): +if eval_statement("from PyQt5 import Qwt5; print(hasattr(Qwt5, 'toNumarray'))"): hiddenimports.append("numarray") diff --git a/PyInstaller/hooks/hook-PyQt5.uic.py b/PyInstaller/hooks/hook-PyQt5.uic.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/PyInstaller/hooks/hook-_tkinter.py b/PyInstaller/hooks/hook-_tkinter.py index e987d27ecf..c020bd3a08 100644 --- a/PyInstaller/hooks/hook-_tkinter.py +++ b/PyInstaller/hooks/hook-_tkinter.py @@ -69,10 +69,10 @@ def _find_tk_tclshell(): tcl_root = tk_root = None # Python code to get path to TCL_LIBRARY. - code = 'from Tkinter import Tcl; t = Tcl(); print t.eval("info library")' + code = 'from Tkinter import Tcl; t = Tcl(); print(t.eval("info library"))' tcl_root = exec_statement(code) - tk_version = exec_statement('from _tkinter import TK_VERSION as v; print v') + tk_version = exec_statement('from _tkinter import TK_VERSION as v; print(v)') # TK_LIBRARY is in the same prefix as Tcl. tk_root = os.path.join(os.path.dirname(tcl_root), 'tk%s' % tk_version) return tcl_root, tk_root diff --git a/PyInstaller/hooks/hook-astroid.py b/PyInstaller/hooks/hook-astroid.py new file mode 100644 index 0000000000..5533ee8b72 --- /dev/null +++ b/PyInstaller/hooks/hook-astroid.py @@ -0,0 +1,36 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- +# +# *************************************************** +# hook-astriod.py - PyInstaller hook file for astriod +# *************************************************** +# The astriod package, in __pkginfo__.py, is version 1.1.1. Looking at its +# source: +# +# From __init__.py, starting at line 111:: +# +# BRAIN_MODULES_DIR = join(dirname(__file__), 'brain') +# if BRAIN_MODULES_DIR not in sys.path: +# # add it to the end of the list so user path take precedence +# sys.path.append(BRAIN_MODULES_DIR) +# # load modules in this directory +# for module in listdir(BRAIN_MODULES_DIR): +# if module.endswith('.py'): +# __import__(module[:-3]) +# +# So, we need all the Python source in the ``brain/`` subdirectory, +# since this is run-time discovered and loaded. Therefore, these +# files are all data files. + +from hookutils import collect_data_files + +# Note that brain/ isn't a module (it lacks an __init__.py, so it can't be +# referred to as astroid.brain; instead, locate it as package astriod, +# subdirectory brain/. +datas = collect_data_files('astroid', True, 'brain') diff --git a/PyInstaller/hooks/hook-django.contrib.py b/PyInstaller/hooks/hook-django.contrib.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/PyInstaller/hooks/hook-django.core.py b/PyInstaller/hooks/hook-django.core.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/PyInstaller/hooks/hook-django.db.backends.mysql.py b/PyInstaller/hooks/hook-django.db.backends.mysql.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/PyInstaller/hooks/hook-django.db.backends.oracle.py b/PyInstaller/hooks/hook-django.db.backends.oracle.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/PyInstaller/hooks/hook-django.db.py b/PyInstaller/hooks/hook-django.db.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/PyInstaller/hooks/hook-enchant.checker.py b/PyInstaller/hooks/hook-enchant.checker.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/PyInstaller/hooks/hook-gst._gst.py b/PyInstaller/hooks/hook-gst._gst.py index ced045472d..f98fc4c343 100644 --- a/PyInstaller/hooks/hook-gst._gst.py +++ b/PyInstaller/hooks/hook-gst._gst.py @@ -29,7 +29,7 @@ def hook(mod): reg = gst.registry_get_default() plug = reg.find_plugin('coreelements') pth = plug.get_filename() -print os.path.dirname(pth) +print(os.path.dirname(pth)) """ plugin_path = exec_statement(statement) diff --git a/PyInstaller/hooks/hook-jinja2.py b/PyInstaller/hooks/hook-jinja2.py index 6142a9244b..cf0da644bc 100644 --- a/PyInstaller/hooks/hook-jinja2.py +++ b/PyInstaller/hooks/hook-jinja2.py @@ -1 +1,10 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + hiddenimports = ['ext'] diff --git a/PyInstaller/hooks/hook-pyexcelerate.py b/PyInstaller/hooks/hook-keyring.backends.py similarity index 62% rename from PyInstaller/hooks/hook-pyexcelerate.py rename to PyInstaller/hooks/hook-keyring.backends.py index c7d354f2b2..e9d7b5054f 100644 --- a/PyInstaller/hooks/hook-pyexcelerate.py +++ b/PyInstaller/hooks/hook-keyring.backends.py @@ -1,5 +1,5 @@ #----------------------------------------------------------------------------- -# Copyright (c) 2013, PyInstaller Development Team. +# Copyright (c) 2014, PyInstaller Development Team. # # Distributed under the terms of the GNU General Public License with exception # for distributing bootloader. @@ -7,4 +7,10 @@ # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- -# empty (just need to keep Python import machinery happy) +""" +Testing with keyring 3.7 on MacOS. +""" + +from PyInstaller.hooks.hookutils import collect_submodules + +hiddenimports = collect_submodules('keyring.backends') diff --git a/PyInstaller/hooks/hook-markdown.py b/PyInstaller/hooks/hook-markdown.py index bef4eeba93..24e66d950a 100644 --- a/PyInstaller/hooks/hook-markdown.py +++ b/PyInstaller/hooks/hook-markdown.py @@ -1,3 +1,12 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + from PyInstaller.hooks.hookutils import collect_submodules, collect_data_files hiddenimports = collect_submodules('markdown.extensions') diff --git a/PyInstaller/hooks/hook-matplotlib.py b/PyInstaller/hooks/hook-matplotlib.py index 9293120c6d..15319ee6a6 100644 --- a/PyInstaller/hooks/hook-matplotlib.py +++ b/PyInstaller/hooks/hook-matplotlib.py @@ -11,7 +11,7 @@ from PyInstaller.hooks.hookutils import exec_statement mpl_data_dir = exec_statement( - "import matplotlib; print matplotlib._get_data_path()") + "import matplotlib; print(matplotlib._get_data_path())") datas = [ (mpl_data_dir, ""), diff --git a/PyInstaller/hooks/hook-patsy.py b/PyInstaller/hooks/hook-patsy.py index e4033475f7..e8f7ce02de 100644 --- a/PyInstaller/hooks/hook-patsy.py +++ b/PyInstaller/hooks/hook-patsy.py @@ -1,2 +1,10 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- hiddenimports = ['patsy.builtins'] diff --git a/PyInstaller/hooks/hook-pyexcelerate.Writer.py b/PyInstaller/hooks/hook-pyexcelerate.Writer.py index b5502a0edd..9e04213c81 100644 --- a/PyInstaller/hooks/hook-pyexcelerate.Writer.py +++ b/PyInstaller/hooks/hook-pyexcelerate.Writer.py @@ -10,7 +10,7 @@ import os from PyInstaller.hooks.hookutils import exec_statement -template_path = exec_statement('from pyexcelerate.Writer import _TEMPLATE_PATH as tp; print tp') +template_path = exec_statement('from pyexcelerate.Writer import _TEMPLATE_PATH as tp; print(tp)') datas = [ (os.path.join(template_path, '*'), os.path.join('pyexcelerate', 'templates')) diff --git a/PyInstaller/hooks/hook-pylint.py b/PyInstaller/hooks/hook-pylint.py new file mode 100644 index 0000000000..385a9ab997 --- /dev/null +++ b/PyInstaller/hooks/hook-pylint.py @@ -0,0 +1,58 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- +# +# ************************************************* +# hook-pylint.py - PyInstaller hook file for pylint +# ************************************************* +# The pylint package, in __pkginfo__.py, is version 1.2.1. Looking at its +# source: +# +# From checkers/__init__.py, starting at line 141:: +# +# def initialize(linter): +# """initialize linter with checkers in this package """ +# register_plugins(linter, __path__[0]) +# +# From reporters/__init__.py, starting at line 136:: +# +# def initialize(linter): +# """initialize linter with reporters in this package """ +# utils.register_plugins(linter, __path__[0]) +# +# From utils.py, starting at line 722:: +# +# def register_plugins(linter, directory): +# """load all module and package in the given directory, looking for a +# 'register' function in each one, used to register pylint checkers +# """ +# imported = {} +# for filename in os.listdir(directory): +# base, extension = splitext(filename) +# if base in imported or base == '__pycache__': +# continue +# if extension in PY_EXTS and base != '__init__' or ( +# not extension and isdir(join(directory, base))): +# try: +# module = load_module_from_file(join(directory, filename)) +# +# +# So, we need all the Python source in the ``checkers/`` and ``reporters/`` +# subdirectories, since thiese are run-time discovered and loaded. Therefore, +# these files are all data files. In addition, since this is a module, the +# pylint/__init__.py file must be included, since submodules must be children of +# a module. + +from hookutils import collect_data_files +import pylint + +datas = ( + [(pylint.__file__, 'pylint')] + + collect_data_files('pylint.checkers', True) + + collect_data_files('pylint.reporters', True) + ) diff --git a/PyInstaller/hooks/hook-pywinauto.py b/PyInstaller/hooks/hook-pywinauto.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/PyInstaller/hooks/hook-scapy.layers.all.py b/PyInstaller/hooks/hook-scapy.layers.all.py new file mode 100644 index 0000000000..3e6b72ae64 --- /dev/null +++ b/PyInstaller/hooks/hook-scapy.layers.all.py @@ -0,0 +1,18 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +from PyInstaller.hooks.hookutils import collect_submodules + +# The layers to load can be configured using scapy's conf.load_layers. +# from scapy.config import conf; print(conf.load_layers) +# I decided not to use this, but to include all layer modules. The +# reason is: When building the package, load_layers may not include +# all the layer modules the program will use later. + +hiddenimports = collect_submodules('scapy.layers') diff --git a/PyInstaller/hooks/hook-sqlalchemy.py b/PyInstaller/hooks/hook-sqlalchemy.py index 10561990cc..f1b95f5b78 100644 --- a/PyInstaller/hooks/hook-sqlalchemy.py +++ b/PyInstaller/hooks/hook-sqlalchemy.py @@ -16,18 +16,18 @@ hiddenimports = ['pysqlite2', 'MySQLdb', 'psycopg2'] # sqlalchemy.databases package from pre 0.6 sqlachemy versions -databases = exec_statement("import sqlalchemy.databases;print sqlalchemy.databases.__all__") +databases = exec_statement("import sqlalchemy.databases; print(sqlalchemy.databases.__all__)") databases = eval(databases.strip()) for n in databases: hiddenimports.append("sqlalchemy.databases." + n) # sqlalchemy.dialects package from 0.6 and newer sqlachemy versions -version = exec_statement('import sqlalchemy; print sqlalchemy.__version__') +version = exec_statement('import sqlalchemy; print(sqlalchemy.__version__)') is_alch06 = version >= '0.6' if is_alch06: - dialects = exec_statement("import sqlalchemy.dialects;print sqlalchemy.dialects.__all__") + dialects = exec_statement("import sqlalchemy.dialects; print(sqlalchemy.dialects.__all__)") dialects = eval(dialects.strip()) for n in databases: diff --git a/PyInstaller/hooks/hook-sysconfig.py b/PyInstaller/hooks/hook-sysconfig.py index e9b3e4dd51..ba09b91e8b 100644 --- a/PyInstaller/hooks/hook-sysconfig.py +++ b/PyInstaller/hooks/hook-sysconfig.py @@ -26,7 +26,7 @@ def _find_prefix(filename): if not compat.is_virtualenv: return sys.prefix - prefixes = [sys.prefix, compat.venv_real_prefix] + prefixes = [os.path.abspath(sys.prefix), compat.venv_real_prefix] possible_prefixes = [] for prefix in prefixes: common = os.path.commonprefix([prefix, filename]) diff --git a/PyInstaller/hooks/hook-xml.py b/PyInstaller/hooks/hook-xml.py index 01ccdde9e4..0a8bbb02c1 100644 --- a/PyInstaller/hooks/hook-xml.py +++ b/PyInstaller/hooks/hook-xml.py @@ -17,7 +17,7 @@ def hook(mod): from PyInstaller.hooks.hookutils import exec_statement import marshal - txt = exec_statement("import xml;print xml.__file__") + txt = exec_statement("import xml; print(xml.__file__)") if txt.find('_xmlplus') > -1: if txt.endswith(".py"): diff --git a/PyInstaller/hooks/hookutils.py b/PyInstaller/hooks/hookutils.py index a12ea006c7..24b9173dc8 100755 --- a/PyInstaller/hooks/hookutils.py +++ b/PyInstaller/hooks/hookutils.py @@ -10,6 +10,7 @@ import glob import os +import os.path import sys import PyInstaller import PyInstaller.compat as compat @@ -147,7 +148,7 @@ def get_pyextension_imports(modname): # Module list contain original modname. We do not need it there. diff.discard('%(modname)s') # Print module list to stdout. -print list(diff) +print(list(diff)) """ % {'modname': modname} module_imports = eval_statement(statement) @@ -162,7 +163,7 @@ def qt4_plugins_dir(): qt4_plugin_dirs = eval_statement( "from PyQt4.QtCore import QCoreApplication;" "app=QCoreApplication([]);" - "print map(unicode,app.libraryPaths())") + "print(map(unicode,app.libraryPaths()))") if not qt4_plugin_dirs: logger.error("Cannot find PyQt4 plugin directories") return "" @@ -179,7 +180,7 @@ def qt4_phonon_plugins_dir(): "app=QApplication([]); app.setApplicationName('pyinstaller');" "from PyQt4.phonon import Phonon;" "v=Phonon.VideoPlayer(Phonon.VideoCategory);" - "print map(unicode,app.libraryPaths())") + "print(map(unicode,app.libraryPaths()))") if not qt4_plugin_dirs: logger.error("Cannot find PyQt4 phonon plugin directories") return "" @@ -277,7 +278,7 @@ def qt5_plugins_dir(): qt5_plugin_dirs = eval_statement( "from PyQt5.QtCore import QCoreApplication;" "app=QCoreApplication([]);" - "print map(unicode,app.libraryPaths())") + "print(map(unicode,app.libraryPaths()))") if not qt5_plugin_dirs: logger.error("Cannot find PyQt5 plugin directories") return "" @@ -294,7 +295,7 @@ def qt5_phonon_plugins_dir(): "app=QApplication([]); app.setApplicationName('pyinstaller');" "from PyQt5.phonon import Phonon;" "v=Phonon.VideoPlayer(Phonon.VideoCategory);" - "print map(unicode,app.libraryPaths())") + "print(map(unicode,app.libraryPaths()))") if not qt5_plugin_dirs: logger.error("Cannot find PyQt5 phonon plugin directories") return "" @@ -535,13 +536,13 @@ def matplotlib_backends(): All matplotlib backends are hardcoded. We have to try import them and return the list of successfully imported backends. """ - all_bk = eval_statement('import matplotlib; print matplotlib.rcsetup.all_backends') + all_bk = eval_statement('import matplotlib; print(matplotlib.rcsetup.all_backends)') avail_bk = [] import_statement = """ try: __import__('matplotlib.backends.backend_%s') except ImportError, e: - print str(e) + print(e) """ # CocoaAgg backend causes subprocess to exit and thus detection @@ -567,7 +568,7 @@ def opengl_arrays_modules(): e.g. 'OpenGL.arrays.vbo' """ - statement = 'import OpenGL; print OpenGL.__path__[0]' + statement = 'import OpenGL; print(OpenGL.__path__[0])' opengl_mod_path = PyInstaller.hooks.hookutils.exec_statement(statement) arrays_mod_path = os.path.join(opengl_mod_path, 'arrays') files = glob.glob(arrays_mod_path + '/*.py') @@ -625,7 +626,7 @@ def get_module_file_attribute(package): # Statement to return __file__ attribute of a package. __file__statement = """ import %s as p -print p.__file__ +print(p.__file__) """ return exec_statement(__file__statement % package) @@ -640,7 +641,7 @@ def get_package_paths(package): """ # A package must have a path -- check for this, in case the package # parameter is actually a module. - is_pkg_statement = 'import %s as p; print hasattr(p, "__path__")' + is_pkg_statement = 'import %s as p; print(hasattr(p, "__path__"))' is_package = eval_statement(is_pkg_statement % package) assert is_package, 'Package %s does not have __path__ attribute' % package @@ -650,14 +651,14 @@ def get_package_paths(package): # Search for Python files in /abs/path/to/package/subpackage; pkg_dir # stores this path. pkg_dir = os.path.dirname(file_attr) - # When found, remove /abs/path/to/ from the filename; mod_base stores + # When found, remove /abs/path/to/ from the filename; pkg_base stores # this path to be removed. pkg_base = remove_suffix(pkg_dir, package.replace('.', os.sep)) return pkg_base, pkg_dir -def collect_submodules(package): +def collect_submodules(package, subdir=None): """ The following two functions were originally written by Ryan Welsh (welchr AT umich.edu). @@ -665,7 +666,10 @@ def collect_submodules(package): This produces a list of strings which specify all the modules in package. Its results can be directly assigned to ``hiddenimports`` in a hook script; see, for example, hook-sphinx.py. The - package parameter must be a string which names the package. + package parameter must be a string which names the package. The + optional subdir give a subdirectory relative to package to search, + which is helpful when submodules are imported at run-time from a + directory lacking __init__.py. See hook-astroid.py for an example. This function does not work on zipped Python eggs. @@ -673,6 +677,8 @@ def collect_submodules(package): PyInstaller. """ pkg_base, pkg_dir = get_package_paths(package) + if subdir: + pkg_dir = os.path.join(pkg_dir, subdir) # Walk through all file in the given package, looking for submodules. mods = set() for dirpath, dirnames, filenames in os.walk(pkg_dir): @@ -700,7 +706,7 @@ def collect_submodules(package): -def collect_data_files(package, allow_py_extensions=False): +def collect_data_files(package, allow_py_extensions=False, subdir=None): """ This routine produces a list of (source, dest) non-Python (i.e. data) files which reside in package. Its results can be directly assigned to @@ -711,7 +717,7 @@ def collect_data_files(package, allow_py_extensions=False): argument to True collects these files as well. This is typically used with Python routines (such as those in pkgutil) that search a given directory for Python executable files then load them as extensions or - plugins. + plugins. See collect_submodules for a description of the subdir parameter. This function does not work on zipped Python eggs. @@ -719,6 +725,8 @@ def collect_data_files(package, allow_py_extensions=False): PyInstaller. """ pkg_base, pkg_dir = get_package_paths(package) + if subdir: + pkg_dir = os.path.join(pkg_dir, subdir) # Walk through all file in the given package, looking for data files. datas = [] for dirpath, dirnames, files in os.walk(pkg_dir): diff --git a/PyInstaller/hooks/shared_PIL_Image.py b/PyInstaller/hooks/shared_PIL_Image.py index a7351cd4ed..71696ad100 100644 --- a/PyInstaller/hooks/shared_PIL_Image.py +++ b/PyInstaller/hooks/shared_PIL_Image.py @@ -32,7 +32,7 @@ def hook(mod): for name in sys.modules: if name.endswith('ImagePlugin'): # Modules are printed to stdout and the output is then parsed. - print name + print(name) """ % {'modname': mod.__name__} out = hookutils.exec_statement(statement) hiddenimports = out.strip().splitlines() diff --git a/PyInstaller/hooks/utils/__init__.py b/PyInstaller/hooks/utils/__init__.py index e69de29bb2..792d600548 100644 --- a/PyInstaller/hooks/utils/__init__.py +++ b/PyInstaller/hooks/utils/__init__.py @@ -0,0 +1 @@ +# diff --git a/PyInstaller/hooks/utils/django-import-finder.py b/PyInstaller/hooks/utils/django-import-finder.py index aa45ac2fd3..5a5464602d 100644 --- a/PyInstaller/hooks/utils/django-import-finder.py +++ b/PyInstaller/hooks/utils/django-import-finder.py @@ -53,7 +53,7 @@ def find_url_callbacks(urls_module): hiddenimports += find_url_callbacks(urls) # This print statement is then parsed and evaluated as Python code. -print hiddenimports +print(hiddenimports) logger.debug('%r', sorted(set(hiddenimports))) diff --git a/PyInstaller/hooks/utils/enchant-datafiles-finder.py b/PyInstaller/hooks/utils/enchant-datafiles-finder.py index c041422353..42b2bb4422 100644 --- a/PyInstaller/hooks/utils/enchant-datafiles-finder.py +++ b/PyInstaller/hooks/utils/enchant-datafiles-finder.py @@ -35,4 +35,4 @@ def _win32_data_files(): # fall back to the function above win32_data_files = _win32_data_files -print win32_data_files() +print(win32_data_files()) diff --git a/PyInstaller/lib/unittest2/__init__.py b/PyInstaller/lib/unittest2/__init__.py index ba6fc31db4..d0035da124 100644 --- a/PyInstaller/lib/unittest2/__init__.py +++ b/PyInstaller/lib/unittest2/__init__.py @@ -2,7 +2,7 @@ unittest2 unittest2 is a backport of the new features added to the unittest testing -framework in Python 2.7. It is tested to run on Python 2.4 - 2.6. +framework in Python 2.7 and beyond. It is tested to run on Python 2.4 - 2.7. To use unittest2 instead of unittest simply replace ``import unittest`` with ``import unittest2``. @@ -31,7 +31,7 @@ 'defaultTestLoader', 'SkipTest', 'skip', 'skipIf', 'skipUnless', 'expectedFailure', 'TextTestResult', '__version__', 'collector'] -__version__ = '0.5.1' +__version__ = '0.8.0' # Expose obsolete functions for backwards compatibility __all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases']) @@ -39,29 +39,49 @@ from unittest2.collector import collector from unittest2.result import TestResult -from unittest2.case import \ - TestCase, FunctionTestCase, SkipTest, skip, skipIf,\ +from unittest2.case import ( + TestCase, FunctionTestCase, SkipTest, skip, skipIf, skipUnless, expectedFailure - +) from unittest2.suite import BaseTestSuite, TestSuite -from unittest2.loader import \ - TestLoader, defaultTestLoader, makeSuite, getTestCaseNames,\ +from unittest2.loader import ( + TestLoader, defaultTestLoader, makeSuite, getTestCaseNames, findTestCases - -from unittest2.main import TestProgram, main, main_ +) +from unittest2.main import TestProgram, main from unittest2.runner import TextTestRunner, TextTestResult try: - from unittest2.signals import\ + from unittest2.signals import ( installHandler, registerResult, removeResult, removeHandler + ) except ImportError: # Compatibility with platforms that don't have the signal module pass else: - __all__.extend(['installHandler', 'registerResult', 'removeResult', + __all__.extend(['installHandler', 'registerResult', 'removeResult', 'removeHandler']) # deprecated _TextTestResult = TextTestResult +# There are no tests here, so don't try to run anything discovered from +# introspecting the symbols (e.g. FunctionTestCase). Instead, all our +# tests come from within unittest.test. +def load_tests(loader, tests, pattern): + import os.path + # top level directory cached on loader instance + this_dir = os.path.dirname(__file__) + return loader.discover(start_dir=this_dir, pattern=pattern) + __unittest = True + +def load_tests(loader, tests, pattern): + # All our tests are in test/ - the test objects found in unittest2 itself + # are base classes not intended to be executed. This load_tests intercepts + # discovery to prevent that. + import unittest2.test + result = loader.suiteClass() + for path in unittest2.test.__path__: + result.addTests(loader.discover(path, pattern=pattern)) + return result diff --git a/PyInstaller/lib/unittest2/__main__.py b/PyInstaller/lib/unittest2/__main__.py index 04ed982df0..85dabc458c 100644 --- a/PyInstaller/lib/unittest2/__main__.py +++ b/PyInstaller/lib/unittest2/__main__.py @@ -2,9 +2,20 @@ import sys if sys.argv[0].endswith("__main__.py"): - sys.argv[0] = "unittest2" + import os.path + # We change sys.argv[0] to make help message more useful + # use executable without path, unquoted + # (it's just a hint anyway) + # (if you have spaces in your executable you get what you deserve!) + executable = os.path.basename(sys.executable) + sys.argv[0] = executable + " -m unittest2" + del os __unittest = True -from unittest2.main import main_ -main_() +from unittest2.main import main, TestProgram +def main_(): + main(module=None) + +if __name__=="__main__": + main_() diff --git a/PyInstaller/lib/unittest2/case.py b/PyInstaller/lib/unittest2/case.py index dc94463dd0..5952de700c 100644 --- a/PyInstaller/lib/unittest2/case.py +++ b/PyInstaller/lib/unittest2/case.py @@ -1,22 +1,29 @@ """Test case implementation""" import sys +import collections +import contextlib import difflib +import logging import pprint import re +import traceback +import types import unittest import warnings -if sys.version_info[:2] == (2,3): - from sets import Set as set - from sets import ImmutableSet as frozenset +import six +from six.moves import range from unittest2 import result -from unittest2.util import\ - safe_repr, safe_str, strclass,\ - unorderable_list_difference +from unittest2.util import ( + safe_repr, safe_str, strclass, + unorderable_list_difference, _common_shorten_repr +) -from unittest2.compatibility import wraps +from unittest2.compatibility import ( + wraps, with_context, catch_warnings, raise_from +) __unittest = True @@ -28,41 +35,80 @@ class SkipTest(Exception): """ Raise this exception in a test to skip it. - Usually you can use TestResult.skip() or one of the skipping decorators + Usually you can use TestCase.skipTest() or one of the skipping decorators instead of raising this directly. """ -class _ExpectedFailure(Exception): +class _ShouldStop(Exception): """ - Raise this when a test is expected to fail. - - This is an implementation detail. + The test should stop. """ - def __init__(self, exc_info): - # can't use super because Python 2.4 exceptions are old style - Exception.__init__(self) - self.exc_info = exc_info - class _UnexpectedSuccess(Exception): """ The test was supposed to fail, but it didn't! """ +class _Outcome(object): + def __init__(self, result=None): + self.expecting_failure = False + self.result = result + self.result_supports_subtests = hasattr(result, "addSubTest") + self.success = True + self.skipped = [] + self.expectedFailure = None + self.errors = [] + + @contextlib.contextmanager + def testPartExecutor(self, test_case, isTest=False): + old_success = self.success + self.success = True + try: + yield + except KeyboardInterrupt: + raise + except SkipTest as e: + self.success = False + self.skipped.append((test_case, str(e))) + except _ShouldStop: + pass + except: + exc_info = sys.exc_info() + if self.expecting_failure: + self.expectedFailure = exc_info + else: + self.success = False + self.errors.append((test_case, exc_info)) + # explicitly break a reference cycle: + # exc_info -> frame -> exc_info + exc_info = None + else: + if self.result_supports_subtests and self.success: + self.errors.append((test_case, None)) + finally: + self.success = self.success and old_success + def _id(obj): return obj + +class_types = [type] +if getattr(types, 'ClassType', None): + class_types.append(types.ClassType) +class_types = tuple(class_types) + + def skip(reason): """ Unconditionally skip a test. """ def decorator(test_item): - if not (isinstance(test_item, type) and issubclass(test_item, TestCase)): + if not isinstance(test_item, class_types): + @wraps(test_item) def skip_wrapper(*args, **kwargs): raise SkipTest(reason) - skip_wrapper = wraps(test_item)(skip_wrapper) test_item = skip_wrapper - + test_item.__unittest_skip__ = True test_item.__unittest_skip_why__ = reason return test_item @@ -85,24 +131,55 @@ def skipUnless(condition, reason): return _id -def expectedFailure(func): - def wrapper(*args, **kwargs): - try: - func(*args, **kwargs) - except Exception: - raise _ExpectedFailure(sys.exc_info()) - raise _UnexpectedSuccess - wrapper = wraps(func)(wrapper) - return wrapper +def expectedFailure(test_item): + test_item.__unittest_expecting_failure__ = True + return test_item -class _AssertRaisesContext(object): - """A context manager used to implement TestCase.assertRaises* methods.""" +class _BaseTestCaseContext: + + def __init__(self, test_case): + self.test_case = test_case + + def _raiseFailure(self, standardMsg): + msg = self.test_case._formatMessage(self.msg, standardMsg) + raise self.test_case.failureException(msg) - def __init__(self, expected, test_case, expected_regexp=None): + +class _AssertRaisesBaseContext(_BaseTestCaseContext): + + def __init__(self, expected, test_case, callable_obj=None, + expected_regex=None): + _BaseTestCaseContext.__init__(self, test_case) self.expected = expected self.failureException = test_case.failureException - self.expected_regexp = expected_regexp + if callable_obj is not None: + try: + self.obj_name = callable_obj.__name__ + except AttributeError: + self.obj_name = str(callable_obj) + else: + self.obj_name = None + if expected_regex is not None: + expected_regex = re.compile(expected_regex) + self.expected_regex = expected_regex + self.msg = None + + def handle(self, name, callable_obj, args, kwargs): + """ + If callable_obj is None, assertRaises/Warns is being used as a + context manager, so check for a 'msg' kwarg and return self. + If callable_obj is not None, call it passing args and kwargs. + """ + if callable_obj is None: + self.msg = kwargs.pop('msg', None) + return self + with self: + callable_obj(*args, **kwargs) + + +class _AssertRaisesContext(_AssertRaisesBaseContext): + """A context manager used to implement TestCase.assertRaises* methods.""" def __enter__(self): return self @@ -115,43 +192,162 @@ def __exit__(self, exc_type, exc_value, tb): exc_name = str(self.expected) raise self.failureException( "%s not raised" % (exc_name,)) + #else: + # if getattr(traceback, 'clear_frames', None): + # traceback.clear_frames(tb) if not issubclass(exc_type, self.expected): # let unexpected exceptions pass through return False self.exception = exc_value # store for later retrieval - if self.expected_regexp is None: + if self.expected_regex is None: return True - expected_regexp = self.expected_regexp - if isinstance(expected_regexp, basestring): - expected_regexp = re.compile(expected_regexp) - if not expected_regexp.search(str(exc_value)): + expected_regex = self.expected_regex + if not expected_regex.search(str(exc_value)): raise self.failureException('"%s" does not match "%s"' % - (expected_regexp.pattern, str(exc_value))) + (expected_regex.pattern, str(exc_value))) return True +class _AssertWarnsContext(_AssertRaisesBaseContext): + """A context manager used to implement TestCase.assertWarns* methods.""" + + def __enter__(self): + # The __warningregistry__'s need to be in a pristine state for tests + # to work properly. + for v in sys.modules.values(): + if getattr(v, '__warningregistry__', None): + v.__warningregistry__ = {} + self.warnings_manager = catch_warnings(record=True) + self.warnings = self.warnings_manager.__enter__() + warnings.simplefilter("always", self.expected) + return self + + def __exit__(self, exc_type, exc_value, tb): + self.warnings_manager.__exit__(exc_type, exc_value, tb) + if exc_type is not None: + # let unexpected exceptions pass through + return + try: + exc_name = self.expected.__name__ + except AttributeError: + exc_name = str(self.expected) + first_matching = None + for m in self.warnings: + w = m.message + if not isinstance(w, self.expected): + continue + if first_matching is None: + first_matching = w + if (self.expected_regex is not None and + not self.expected_regex.search(str(w))): + continue + # store warning for later retrieval + self.warning = w + self.filename = m.filename + self.lineno = m.lineno + return + # Now we simply try to choose a helpful failure message + if first_matching is not None: + raise self.failureException('%r does not match %r' % + (self.expected_regex.pattern, str(first_matching))) + if self.obj_name: + raise self.failureException("%s not triggered by %s" + % (exc_name, self.obj_name)) + else: + raise self.failureException("%s not triggered" + % exc_name ) + + class _TypeEqualityDict(object): - + def __init__(self, testcase): self.testcase = testcase self._store = {} - + def __setitem__(self, key, value): self._store[key] = value - + def __getitem__(self, key): value = self._store[key] - if isinstance(value, basestring): + if isinstance(value, six.string_types): return getattr(self.testcase, value) return value - + def get(self, key, default=None): if key in self._store: return self[key] return default +_LoggingWatcher = collections.namedtuple("_LoggingWatcher", + ["records", "output"]) + + +class _CapturingHandler(logging.Handler): + """ + A logging handler capturing all (raw and formatted) logging output. + """ + + def __init__(self): + logging.Handler.__init__(self) + self.watcher = _LoggingWatcher([], []) + + def flush(self): + pass + + def emit(self, record): + self.watcher.records.append(record) + msg = self.format(record) + self.watcher.output.append(msg) + + + +class _AssertLogsContext(_BaseTestCaseContext): + """A context manager used to implement TestCase.assertLogs().""" + + LOGGING_FORMAT = "%(levelname)s:%(name)s:%(message)s" + + def __init__(self, test_case, logger_name, level): + _BaseTestCaseContext.__init__(self, test_case) + self.logger_name = logger_name + if level: + self.level = getattr(logging, str(level), level) + else: + self.level = logging.INFO + self.msg = None + + def __enter__(self): + if isinstance(self.logger_name, logging.Logger): + logger = self.logger = self.logger_name + else: + logger = self.logger = logging.getLogger(self.logger_name) + formatter = logging.Formatter(self.LOGGING_FORMAT) + handler = _CapturingHandler() + handler.setFormatter(formatter) + self.watcher = handler.watcher + self.old_handlers = logger.handlers[:] + self.old_level = logger.level + self.old_propagate = logger.propagate + logger.handlers = [handler] + logger.setLevel(self.level) + logger.propagate = False + return handler.watcher + + def __exit__(self, exc_type, exc_value, tb): + self.logger.handlers = self.old_handlers + self.logger.propagate = self.old_propagate + self.logger.setLevel(self.old_level) + if exc_type is not None: + # let unexpected exceptions pass through + return False + if len(self.watcher.records) == 0: + self._raiseFailure( + "no logs of level {0} or higher triggered on {1}" + .format(logging.getLevelName(self.level), self.logger.name)) + + + class TestCase(unittest.TestCase): """A class whose instances are single test cases. @@ -172,28 +368,31 @@ class TestCase(unittest.TestCase): should not change the signature of their __init__ method, since instances of the classes are instantiated automatically by parts of the framework in order to be run. - """ - # This attribute determines which exception will be raised when - # the instance's assertion methods fail; test methods raising this - # exception will be deemed to have 'failed' rather than 'errored' + When subclassing TestCase, you can set these attributes: + * failureException: determines which exception will be raised when + the instance's assertion methods fail; test methods raising this + exception will be deemed to have 'failed' rather than 'errored'. + * longMessage: determines whether long messages (including repr of + objects used in assert methods) will be printed on failure in *addition* + to any explicit message passed. + * maxDiff: sets the maximum length of a diff in failure messages + by assert methods using difflib. It is looked up as an instance + attribute so can be configured by individual tests if required. + """ failureException = AssertionError - # This attribute sets the maximum length of a diff in failure messages - # by assert methods using difflib. It is looked up as an instance attribute - # so can be configured by individual tests if required. + longMessage = True maxDiff = 80*8 - # This attribute determines whether long messages (including repr of - # objects used in assert methods) will be printed on failure in *addition* - # to any explicit message passed. + # If a string is longer than _diffThreshold, use normal comparison instead + # of difflib. See #11763. + _diffThreshold = 2**16 - longMessage = True - # Attribute used by TestSuite for classSetUp - + _classSetupFailed = False def __init__(self, methodName='runTest'): @@ -202,7 +401,7 @@ def __init__(self, methodName='runTest'): not have a method with the specified name. """ self._testMethodName = methodName - self._resultForDoCleanups = None + self._outcome = None try: testMethod = getattr(self, methodName) except AttributeError: @@ -210,6 +409,7 @@ def __init__(self, methodName='runTest'): (self.__class__, methodName)) self._testMethodDoc = testMethod.__doc__ self._cleanups = [] + self._subtest = None # Map types to custom assertEqual functions that will compare # instances of said type in more detail to generate a more useful @@ -220,7 +420,9 @@ def __init__(self, methodName='runTest'): self.addTypeEqualityFunc(tuple, 'assertTupleEqual') self.addTypeEqualityFunc(set, 'assertSetEqual') self.addTypeEqualityFunc(frozenset, 'assertSetEqual') - self.addTypeEqualityFunc(unicode, 'assertMultiLineEqual') + if six.PY2: + self.addTypeEqualityFunc(str, 'assertMultiLineEqual') + self.addTypeEqualityFunc(six.text_type, 'assertMultiLineEqual') def addTypeEqualityFunc(self, typeobj, function): """Add a type specific assertEqual style function to compare a type. @@ -245,22 +447,13 @@ def addCleanup(self, function, *args, **kwargs): Cleanup items are called even if setUp fails (unlike tearDown).""" self._cleanups.append((function, args, kwargs)) - def setUp(self): - "Hook method for setting up the test fixture before exercising it." - + @classmethod def setUpClass(cls): "Hook method for setting up class fixture before running tests in the class." - setUpClass = classmethod(setUpClass) - + + @classmethod def tearDownClass(cls): "Hook method for deconstructing the class fixture after running all tests in the class." - tearDownClass = classmethod(tearDownClass) - - def tearDown(self): - "Hook method for deconstructing the test fixture after testing it." - - def countTestCases(self): - return 1 def defaultTestResult(self): return result.TestResult() @@ -297,15 +490,81 @@ def __str__(self): def __repr__(self): return "<%s testMethod=%s>" % \ (strclass(self.__class__), self._testMethodName) - - def _addSkip(self, result, reason): + + def _addSkip(self, result, test_case, reason): addSkip = getattr(result, 'addSkip', None) if addSkip is not None: - addSkip(self, reason) + addSkip(test_case, reason) else: - warnings.warn("Use of a TestResult without an addSkip method is deprecated", - DeprecationWarning, 2) + warnings.warn("TestResult has no addSkip method, skips not reported", + RuntimeWarning, 2) + result.addSuccess(test_case) + + @contextlib.contextmanager + def subTest(self, msg=None, **params): + """Return a context manager that will return the enclosed block + of code in a subtest identified by the optional message and + keyword parameters. A failure in the subtest marks the test + case as failed but resumes execution at the end of the enclosed + block, allowing further test code to be executed. + """ + if not self._outcome.result_supports_subtests: + yield + return + parent = self._subtest + if parent is None: + params_map = collections.ChainMap(params) + else: + params_map = parent.params.new_child(params) + self._subtest = _SubTest(self, msg, params_map) + try: + with self._outcome.testPartExecutor(self._subtest, isTest=True): + yield + if not self._outcome.success: + result = self._outcome.result + if result is not None and result.failfast: + raise _ShouldStop + elif self._outcome.expectedFailure: + # If the test is expecting a failure, we really want to + # stop now and register the expected failure. + raise _ShouldStop + finally: + self._subtest = parent + + def _feedErrorsToResult(self, result, errors): + for test, exc_info in errors: + if isinstance(test, _SubTest): + result.addSubTest(test.test_case, test, exc_info) + elif exc_info is not None: + if issubclass(exc_info[0], self.failureException): + result.addFailure(test, exc_info) + else: + result.addError(test, exc_info) + + def _addExpectedFailure(self, result, exc_info): + try: + addExpectedFailure = result.addExpectedFailure + except AttributeError: + warnings.warn("TestResult has no addExpectedFailure method, reporting as passes", + RuntimeWarning) result.addSuccess(self) + else: + addExpectedFailure(self, exc_info) + + def _addUnexpectedSuccess(self, result): + try: + addUnexpectedSuccess = result.addUnexpectedSuccess + except AttributeError: + warnings.warn("TestResult has no addUnexpectedSuccess method, reporting as failure", + RuntimeWarning) + # We need to pass an actual exception and traceback to addFailure, + # otherwise the legacy result can choke. + try: + raise_from(_UnexpectedSuccess, None) + except _UnexpectedSuccess: + result.addFailure(self, sys.exc_info()) + else: + addUnexpectedSuccess(self) def run(self, result=None): orig_result = result @@ -315,67 +574,48 @@ def run(self, result=None): if startTestRun is not None: startTestRun() - self._resultForDoCleanups = result result.startTest(self) - + testMethod = getattr(self, self._testMethodName) - - if (getattr(self.__class__, "__unittest_skip__", False) or + if (getattr(self.__class__, "__unittest_skip__", False) or getattr(testMethod, "__unittest_skip__", False)): # If the class or method was skipped. try: skip_why = (getattr(self.__class__, '__unittest_skip_why__', '') or getattr(testMethod, '__unittest_skip_why__', '')) - self._addSkip(result, skip_why) + self._addSkip(result, self, skip_why) finally: result.stopTest(self) return + expecting_failure = getattr(testMethod, + "__unittest_expecting_failure__", False) + outcome = _Outcome(result) try: - success = False - try: + self._outcome = outcome + + with outcome.testPartExecutor(self): self.setUp() - except SkipTest, e: - self._addSkip(result, str(e)) - except Exception: - result.addError(self, sys.exc_info()) - else: - try: + if outcome.success: + outcome.expecting_failure = expecting_failure + with outcome.testPartExecutor(self, isTest=True): testMethod() - except self.failureException: - result.addFailure(self, sys.exc_info()) - except _ExpectedFailure, e: - addExpectedFailure = getattr(result, 'addExpectedFailure', None) - if addExpectedFailure is not None: - addExpectedFailure(self, e.exc_info) - else: - warnings.warn("Use of a TestResult without an addExpectedFailure method is deprecated", - DeprecationWarning) - result.addSuccess(self) - except _UnexpectedSuccess: - addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None) - if addUnexpectedSuccess is not None: - addUnexpectedSuccess(self) + outcome.expecting_failure = False + with outcome.testPartExecutor(self): + self.tearDown() + + self.doCleanups() + for test, reason in outcome.skipped: + self._addSkip(result, test, reason) + self._feedErrorsToResult(result, outcome.errors) + if outcome.success: + if expecting_failure: + if outcome.expectedFailure: + self._addExpectedFailure(result, outcome.expectedFailure) else: - warnings.warn("Use of a TestResult without an addUnexpectedSuccess method is deprecated", - DeprecationWarning) - result.addFailure(self, sys.exc_info()) - except SkipTest, e: - self._addSkip(result, str(e)) - except Exception: - result.addError(self, sys.exc_info()) + self._addUnexpectedSuccess(result) else: - success = True - - try: - self.tearDown() - except Exception: - result.addError(self, sys.exc_info()) - success = False - - cleanUpSuccess = self.doCleanups() - success = success and cleanUpSuccess - if success: - result.addSuccess(self) + result.addSuccess(self) + return result finally: result.stopTest(self) if orig_result is None: @@ -383,19 +623,27 @@ def run(self, result=None): if stopTestRun is not None: stopTestRun() + # explicitly break reference cycles: + # outcome.errors -> frame -> outcome -> outcome.errors + # outcome.expectedFailure -> frame -> outcome -> outcome.expectedFailure + del outcome.errors[:] + outcome.expectedFailure = None + + # clear the outcome, no more needed + self._outcome = None + def doCleanups(self): """Execute all cleanup functions. Normally called for you after tearDown.""" - result = self._resultForDoCleanups - ok = True + outcome = self._outcome or _Outcome() while self._cleanups: - function, args, kwargs = self._cleanups.pop(-1) - try: + function, args, kwargs = self._cleanups.pop() + with outcome.testPartExecutor(self): function(*args, **kwargs) - except Exception: - ok = False - result.addError(self, sys.exc_info()) - return ok + + # return this for backwards compatibility + # even though we no longer us it internally + return outcome.success def __call__(self, *args, **kwds): return self.run(*args, **kwds) @@ -420,13 +668,13 @@ def fail(self, msg=None): def assertFalse(self, expr, msg=None): "Fail the test if the expression is true." if expr: - msg = self._formatMessage(msg, "%s is not False" % safe_repr(expr)) + msg = self._formatMessage(msg, "%s is not false" % safe_repr(expr)) raise self.failureException(msg) def assertTrue(self, expr, msg=None): """Fail the test unless the expression is true.""" if not expr: - msg = self._formatMessage(msg, "%s is not True" % safe_repr(expr)) + msg = self._formatMessage(msg, "%s is not true" % safe_repr(expr)) raise self.failureException(msg) def _formatMessage(self, msg, standardMsg): @@ -450,10 +698,10 @@ def _formatMessage(self, msg, standardMsg): def assertRaises(self, excClass, callableObj=None, *args, **kwargs): - """Fail unless an exception of class excClass is thrown + """Fail unless an exception of class excClass is raised by callableObj when invoked with arguments args and keyword arguments kwargs. If a different type of exception is - thrown, it will not be caught, and the test case will be + raised, it will not be caught, and the test case will be deemed to have suffered an error, exactly as for an unexpected exception. @@ -478,12 +726,73 @@ def assertRaises(self, excClass, callableObj=None, *args, **kwargs): callableObj(*args, **kwargs) except excClass: return - + if hasattr(excClass,'__name__'): excName = excClass.__name__ else: excName = str(excClass) - raise self.failureException, "%s not raised" % excName + raise self.failureException("%s not raised" % excName) + + def assertWarns(self, expected_warning, callable_obj=None, *args, **kwargs): + """Fail unless a warning of class warnClass is triggered + by callableObj when invoked with arguments args and keyword + arguments kwargs. If a different type of warning is + triggered, it will not be handled: depending on the other + warning filtering rules in effect, it might be silenced, printed + out, or raised as an exception. + + If called with callableObj omitted or None, will return a + context object used like this:: + + with self.assertWarns(SomeWarning): + do_something() + + The context manager keeps a reference to the first matching + warning as the 'warning' attribute; similarly, the 'filename' + and 'lineno' attributes give you information about the line + of Python code from which the warning was triggered. + This allows you to inspect the warning after the assertion:: + + with self.assertWarns(SomeWarning) as cm: + do_something() + the_warning = cm.warning + self.assertEqual(the_warning.some_attribute, 147) + """ + context = _AssertWarnsContext(expected_warning, self, callable_obj) + if callable_obj is None: + return context + context.__enter__() + try: + callable_obj(*args, **kwargs) + except: + if not context.__exit__(*sys.exc_info()): + raise + else: + return + else: + context.__exit__(None, None, None) + + def assertLogs(self, logger=None, level=None): + """Fail unless a log message of level *level* or higher is emitted + on *logger_name* or its children. If omitted, *level* defaults to + INFO and *logger* defaults to the root logger. + + This method must be used as a context manager, and will yield + a recording object with two attributes: `output` and `records`. + At the end of the context manager, the `output` attribute will + be a list of the matching formatted log messages and the + `records` attribute will be a list of the corresponding LogRecord + objects. + + Example:: + + with self.assertLogs('foo', level='INFO') as cm: + logging.getLogger('foo').info('first message') + logging.getLogger('foo.bar').error('second message') + self.assertEqual(cm.output, ['INFO:foo:first message', + 'ERROR:foo.bar:second message']) + """ + return _AssertLogsContext(self, logger, level) def _getAssertEqualityFunc(self, first, second): """Get a detailed comparison function for the types of the two args. @@ -512,7 +821,7 @@ def _getAssertEqualityFunc(self, first, second): def _baseAssertEqual(self, first, second, msg=None): """The default assertEqual implementation, not type specific.""" if not first == second: - standardMsg = '%s != %s' % (safe_repr(first), safe_repr(second)) + standardMsg = '%s != %s' % _common_shorten_repr(first, second) msg = self._formatMessage(msg, standardMsg) raise self.failureException(msg) @@ -524,11 +833,11 @@ def assertEqual(self, first, second, msg=None): assertion_func(first, second, msg=msg) def assertNotEqual(self, first, second, msg=None): - """Fail if the two objects are equal as determined by the '==' + """Fail if the two objects are equal as determined by the '!=' operator. """ if not first != second: - msg = self._formatMessage(msg, '%s == %s' % (safe_repr(first), + msg = self._formatMessage(msg, '%s == %s' % (safe_repr(first), safe_repr(second))) raise self.failureException(msg) @@ -549,23 +858,23 @@ def assertAlmostEqual(self, first, second, places=None, msg=None, delta=None): return if delta is not None and places is not None: raise TypeError("specify delta or places not both") - + if delta is not None: if abs(first - second) <= delta: return - - standardMsg = '%s != %s within %s delta' % (safe_repr(first), - safe_repr(second), + + standardMsg = '%s != %s within %s delta' % (safe_repr(first), + safe_repr(second), safe_repr(delta)) else: if places is None: places = 7 - + if round(abs(second-first), places) == 0: return - - standardMsg = '%s != %s within %r places' % (safe_repr(first), - safe_repr(second), + + standardMsg = '%s != %s within %r places' % (safe_repr(first), + safe_repr(second), places) msg = self._formatMessage(msg, standardMsg) raise self.failureException(msg) @@ -586,7 +895,7 @@ def assertNotAlmostEqual(self, first, second, places=None, msg=None, delta=None) if delta is not None: if not (first == second) and abs(first - second) > delta: return - standardMsg = '%s == %s within %s delta' % (safe_repr(first), + standardMsg = '%s == %s within %s delta' % (safe_repr(first), safe_repr(second), safe_repr(delta)) else: @@ -594,44 +903,15 @@ def assertNotAlmostEqual(self, first, second, places=None, msg=None, delta=None) places = 7 if not (first == second) and round(abs(second-first), places) != 0: return - standardMsg = '%s == %s within %r places' % (safe_repr(first), + standardMsg = '%s == %s within %r places' % (safe_repr(first), safe_repr(second), places) msg = self._formatMessage(msg, standardMsg) raise self.failureException(msg) - # Synonyms for assertion methods - - # The plurals are undocumented. Keep them that way to discourage use. - # Do not add more. Do not remove. - # Going through a deprecation cycle on these would annoy many people. - assertEquals = assertEqual - assertNotEquals = assertNotEqual - assertAlmostEquals = assertAlmostEqual - assertNotAlmostEquals = assertNotAlmostEqual - assert_ = assertTrue - - # These fail* assertion method names are pending deprecation and will - # be a DeprecationWarning in 3.2; http://bugs.python.org/issue2578 - def _deprecate(original_func): - def deprecated_func(*args, **kwargs): - warnings.warn( - ('Please use %s instead.' % original_func.__name__), - PendingDeprecationWarning, 2) - return original_func(*args, **kwargs) - return deprecated_func - - failUnlessEqual = _deprecate(assertEqual) - failIfEqual = _deprecate(assertNotEqual) - failUnlessAlmostEqual = _deprecate(assertAlmostEqual) - failIfAlmostEqual = _deprecate(assertNotAlmostEqual) - failUnless = _deprecate(assertTrue) - failUnlessRaises = _deprecate(assertRaises) - failIf = _deprecate(assertFalse) - def assertSequenceEqual(self, seq1, seq2, - msg=None, seq_type=None, max_diff=80*8): + def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None): """An equality assertion for ordered sequences (like lists and tuples). For the purposes of this function, a valid ordered sequence type is one @@ -644,7 +924,6 @@ def assertSequenceEqual(self, seq1, seq2, datatype should be enforced. msg: Optional message to use on failure instead of a list of differences. - max_diff: Maximum size off the diff, larger diffs are not shown """ if seq_type is not None: seq_type_name = seq_type.__name__ @@ -675,16 +954,11 @@ def assertSequenceEqual(self, seq1, seq2, if seq1 == seq2: return - seq1_repr = repr(seq1) - seq2_repr = repr(seq2) - if len(seq1_repr) > 30: - seq1_repr = seq1_repr[:30] + '...' - if len(seq2_repr) > 30: - seq2_repr = seq2_repr[:30] + '...' - elements = (seq_type_name.capitalize(), seq1_repr, seq2_repr) - differing = '%ss differ: %s != %s\n' % elements + differing = '%ss differ: %s != %s\n' % ( + (seq_type_name.capitalize(),) + + _common_shorten_repr(seq1, seq2)) - for i in xrange(min(len1, len2)): + for i in range(min(len1, len2)): try: item1 = seq1[i] except (TypeError, IndexError, NotImplementedError): @@ -780,16 +1054,20 @@ def assertSetEqual(self, set1, set2, msg=None): """ try: difference1 = set1.difference(set2) - except TypeError, e: + except TypeError: + e = sys.exc_info()[1] self.fail('invalid type when attempting set difference: %s' % e) - except AttributeError, e: + except AttributeError: + e = sys.exc_info()[1] self.fail('first argument does not support set difference: %s' % e) try: difference2 = set2.difference(set1) - except TypeError, e: + except TypeError: + e = sys.exc_info()[1] self.fail('invalid type when attempting set difference: %s' % e) - except AttributeError, e: + except AttributeError: + e = sys.exc_info()[1] self.fail('second argument does not support set difference: %s' % e) if not (difference1 or difference2): @@ -811,14 +1089,14 @@ def assertSetEqual(self, set1, set2, msg=None): def assertIn(self, member, container, msg=None): """Just like self.assertTrue(a in b), but with a nicer default message.""" if member not in container: - standardMsg = '%s not found in %s' % (safe_repr(member), + standardMsg = '%s not found in %s' % (safe_repr(member), safe_repr(container)) self.fail(self._formatMessage(msg, standardMsg)) def assertNotIn(self, member, container, msg=None): """Just like self.assertTrue(a not in b), but with a nicer default message.""" if member in container: - standardMsg = '%s unexpectedly found in %s' % (safe_repr(member), + standardMsg = '%s unexpectedly found in %s' % (safe_repr(member), safe_repr(container)) self.fail(self._formatMessage(msg, standardMsg)) @@ -835,11 +1113,11 @@ def assertIsNot(self, expr1, expr2, msg=None): self.fail(self._formatMessage(msg, standardMsg)) def assertDictEqual(self, d1, d2, msg=None): - self.assert_(isinstance(d1, dict), 'First argument is not a dictionary') - self.assert_(isinstance(d2, dict), 'Second argument is not a dictionary') + self.assertIsInstance(d1, dict, 'First argument is not a dictionary') + self.assertIsInstance(d2, dict, 'Second argument is not a dictionary') if d1 != d2: - standardMsg = '%s != %s' % (safe_repr(d1, True), safe_repr(d2, True)) + standardMsg = '%s != %s' % _common_shorten_repr(d1, d2) diff = ('\n' + '\n'.join(difflib.ndiff( pprint.pformat(d1).splitlines(), pprint.pformat(d2).splitlines()))) @@ -850,26 +1128,21 @@ def assertDictContainsSubset(self, expected, actual, msg=None): """Checks whether actual is a superset of expected.""" missing = [] mismatched = [] - for key, value in expected.iteritems(): + for key, value in expected.items(): if key not in actual: missing.append(key) - else: - try: - are_equal = (value == actual[key]) - except UnicodeDecodeError: - are_equal = False - if not are_equal: - mismatched.append('%s, expected: %s, actual: %s' % - (safe_repr(key), safe_repr(value), - safe_repr(actual[key]))) + elif value != actual[key]: + mismatched.append('%s, expected: %s, actual: %s' % + (safe_repr(key), safe_repr(value), + safe_repr(actual[key]))) if not (missing or mismatched): return standardMsg = '' if missing: - standardMsg = 'Missing: %s' % ','.join([safe_repr(m) for m in - missing]) + standardMsg = 'Missing: %s' % ','.join(safe_repr(m) for m in + missing) if mismatched: if standardMsg: standardMsg += '; ' @@ -881,23 +1154,20 @@ def assertItemsEqual(self, expected_seq, actual_seq, msg=None): """An unordered sequence specific comparison. It asserts that expected_seq and actual_seq contain the same elements. It is the equivalent of:: - + self.assertEqual(sorted(expected_seq), sorted(actual_seq)) Raises with an error message listing which elements of expected_seq are missing from actual_seq and vice versa if any. - + Asserts that each element has the same count in both sequences. Example: - [0, 1, 1] and [1, 0, 1] compare equal. - [0, 0, 1] and [0, 1] compare unequal. """ try: - - expected = expected_seq[:] - expected.sort() - actual = actual_seq[:] - actual.sort() + expected = sorted(expected_seq) + actual = sorted(actual_seq) except TypeError: # Unsortable items (example: set(), complex(), ...) expected = list(expected_seq) @@ -910,10 +1180,10 @@ def assertItemsEqual(self, expected_seq, actual_seq, msg=None): errors = [] if missing: - errors.append('Expected, but missing:\n %s' % + errors.append('Expected, but missing:\n %s' % safe_repr(missing)) if unexpected: - errors.append('Unexpected, but present:\n %s' % + errors.append('Unexpected, but present:\n %s' % safe_repr(unexpected)) if errors: standardMsg = '\n'.join(errors) @@ -921,15 +1191,23 @@ def assertItemsEqual(self, expected_seq, actual_seq, msg=None): def assertMultiLineEqual(self, first, second, msg=None): """Assert that two multi-line strings are equal.""" - self.assert_(isinstance(first, basestring), ( + self.assertIsInstance(first, six.string_types, ( 'First argument is not a string')) - self.assert_(isinstance(second, basestring), ( + self.assertIsInstance(second, six.string_types, ( 'Second argument is not a string')) if first != second: - standardMsg = '%s != %s' % (safe_repr(first, True), safe_repr(second, True)) - diff = '\n' + ''.join(difflib.ndiff(first.splitlines(True), - second.splitlines(True))) + # don't use difflib if the strings are too long + if (len(first) > self._diffThreshold or + len(second) > self._diffThreshold): + self._baseAssertEqual(first, second, msg) + firstlines = first.splitlines(True) + secondlines = second.splitlines(True) + if len(firstlines) == 1 and first.strip('\r\n') == first: + firstlines = [first + '\n'] + secondlines = [second + '\n'] + standardMsg = '%s != %s' % _common_shorten_repr(first, second) + diff = '\n' + ''.join(difflib.ndiff(firstlines, secondlines)) standardMsg = self._truncateMessage(standardMsg, diff) self.fail(self._formatMessage(msg, standardMsg)) @@ -982,58 +1260,85 @@ def assertNotIsInstance(self, obj, cls, msg=None): standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls) self.fail(self._formatMessage(msg, standardMsg)) - def assertRaisesRegexp(self, expected_exception, expected_regexp, - callable_obj=None, *args, **kwargs): - """Asserts that the message in a raised exception matches a regexp. + def assertRaisesRegex(self, expected_exception, expected_regex, + callable_obj=None, *args, **kwargs): + """Asserts that the message in a raised exception matches a regex. Args: expected_exception: Exception class expected to be raised. - expected_regexp: Regexp (re pattern object or string) expected + expected_regex: Regex (re pattern object or string) expected to be found in error message. callable_obj: Function to be called. args: Extra args. kwargs: Extra kwargs. """ - if callable_obj is None: - return _AssertRaisesContext(expected_exception, self, expected_regexp) - try: - callable_obj(*args, **kwargs) - except expected_exception, exc_value: - if isinstance(expected_regexp, basestring): - expected_regexp = re.compile(expected_regexp) - if not expected_regexp.search(str(exc_value)): - raise self.failureException('"%s" does not match "%s"' % - (expected_regexp.pattern, str(exc_value))) - else: - if hasattr(expected_exception, '__name__'): - excName = expected_exception.__name__ - else: - excName = str(expected_exception) - raise self.failureException, "%s not raised" % excName + context = _AssertRaisesContext(expected_exception, self, callable_obj, + expected_regex) + return context.handle('assertRaisesRegex', callable_obj, args, kwargs) + def assertWarnsRegex(self, expected_warning, expected_regex, + callable_obj=None, *args, **kwargs): + """Asserts that the message in a triggered warning matches a regex. + Basic functioning is similar to assertWarns() with the addition + that only warnings whose messages also match the regular expression + are considered successful matches. - def assertRegexpMatches(self, text, expected_regexp, msg=None): + Args: + expected_warning: Warning class expected to be triggered. + expected_regex: Regex (re pattern object or string) expected + to be found in error message. + callable_obj: Function to be called. + args: Extra args. + kwargs: Extra kwargs. + """ + context = _AssertWarnsContext(expected_warning, self, callable_obj, + expected_regex) + return context.handle('assertWarnsRegex', callable_obj, args, kwargs) + + + def assertRegex(self, text, expected_regex, msg=None): """Fail the test unless the text matches the regular expression.""" - if isinstance(expected_regexp, basestring): - expected_regexp = re.compile(expected_regexp) - if not expected_regexp.search(text): - msg = msg or "Regexp didn't match" - msg = '%s: %r not found in %r' % (msg, expected_regexp.pattern, text) + if isinstance(expected_regex, six.string_types): + expected_regex = re.compile(expected_regex) + if not expected_regex.search(text): + msg = msg or "Regex didn't match" + msg = '%s: %r not found in %r' % (msg, expected_regex.pattern, text) raise self.failureException(msg) - def assertNotRegexpMatches(self, text, unexpected_regexp, msg=None): + def assertNotRegex(self, text, unexpected_regex, msg=None): """Fail the test if the text matches the regular expression.""" - if isinstance(unexpected_regexp, basestring): - unexpected_regexp = re.compile(unexpected_regexp) - match = unexpected_regexp.search(text) + if isinstance(unexpected_regex, six.string_types): + unexpected_regex = re.compile(unexpected_regex) + match = unexpected_regex.search(text) if match: - msg = msg or "Regexp matched" + msg = msg or "Regex matched" msg = '%s: %r matches %r in %r' % (msg, text[match.start():match.end()], - unexpected_regexp.pattern, + unexpected_regex.pattern, text) raise self.failureException(msg) + + def _deprecate(original_func): + def deprecated_func(*args, **kwargs): + warnings.warn( + ('Please use %s instead.' % original_func.__name__), + PendingDeprecationWarning, 2) + return original_func(*args, **kwargs) + return deprecated_func + + failUnlessEqual = assertEquals = _deprecate(assertEqual) + failIfEqual = assertNotEquals = _deprecate(assertNotEqual) + failUnlessAlmostEqual = assertAlmostEquals = _deprecate(assertAlmostEqual) + failIfAlmostEqual = assertNotAlmostEquals = _deprecate(assertNotAlmostEqual) + failUnless = assert_ = _deprecate(assertTrue) + failUnlessRaises = _deprecate(assertRaises) + failIf = _deprecate(assertFalse) + assertRaisesRegexp = _deprecate(assertRaisesRegex) + assertRegexpMatches = _deprecate(assertRegex) + assertNotRegexpMatches = _deprecate(assertNotRegex) + + class FunctionTestCase(TestCase): """A test case that wraps a test function. @@ -1093,3 +1398,39 @@ def shortDescription(self): return self._description doc = self._testFunc.__doc__ return doc and doc.split("\n")[0].strip() or None + + +class _SubTest(TestCase): + + def __init__(self, test_case, message, params): + super(_SubTest, self).__init__() + self._message = message + self.test_case = test_case + self.params = params + self.failureException = test_case.failureException + + def runTest(self): + raise NotImplementedError("subtests cannot be run directly") + + def _subDescription(self): + parts = [] + if self._message: + parts.append("[{0}]".format(self._message)) + if self.params: + params_desc = ', '.join( + "{0}={1!r}".format(k, v) + for (k, v) in sorted(self.params.items())) + parts.append("({0})".format(params_desc)) + return " ".join(parts) or '()' + + def id(self): + return "{0} {1}".format(self.test_case.id(), self._subDescription()) + + def shortDescription(self): + """Returns a one-line description of the subtest, or None if no + description has been provided. + """ + return self.test_case.shortDescription() + + def __str__(self): + return "{0} {1}".format(self.test_case, self._subDescription()) diff --git a/PyInstaller/lib/unittest2/compatibility.py b/PyInstaller/lib/unittest2/compatibility.py index b8f15dd142..9e5f1a5829 100644 --- a/PyInstaller/lib/unittest2/compatibility.py +++ b/PyInstaller/lib/unittest2/compatibility.py @@ -1,6 +1,9 @@ +import collections import os import sys +import six + try: from functools import wraps except ImportError: @@ -46,7 +49,7 @@ def _relpath_posix(path, start=os.path.curdir): if not path: raise ValueError("no path specified") - + start_list = os.path.abspath(start).split(os.path.sep) path_list = os.path.abspath(path).split(os.path.sep) @@ -62,3 +65,199 @@ def _relpath_posix(path, start=os.path.curdir): relpath = _relpath_nt else: relpath = _relpath_posix + + +def with_context(context, callableobj, *args, **kwargs): + """ + Execute a callable utilizing a context object + in the same way that the 'with' statement would + """ + context.__enter__() + try: + callableobj(*args, **kwargs) + except: + if not context.__exit__(*sys.exc_info()): + raise + else: + return + else: + context.__exit__(None, None, None) + + +# copied from Python 2.6 +try: + from warnings import catch_warnings +except ImportError: + class catch_warnings(object): + def __init__(self, record=False, module=None): + self._record = record + self._module = sys.modules['warnings'] + self._entered = False + + def __repr__(self): + args = [] + if self._record: + args.append("record=True") + name = type(self).__name__ + return "%s(%s)" % (name, ", ".join(args)) + + def __enter__(self): + if self._entered: + raise RuntimeError("Cannot enter %r twice" % self) + self._entered = True + self._filters = self._module.filters + self._module.filters = self._filters[:] + self._showwarning = self._module.showwarning + if self._record: + log = [] + def showwarning(*args, **kwargs): + log.append(WarningMessage(*args, **kwargs)) + self._module.showwarning = showwarning + return log + else: + return None + + def __exit__(self, *exc_info): + if not self._entered: + raise RuntimeError("Cannot exit %r without entering first" % self) + self._module.filters = self._filters + self._module.showwarning = self._showwarning + + class WarningMessage(object): + _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file", + "line") + def __init__(self, message, category, filename, lineno, file=None, + line=None): + local_values = locals() + for attr in self._WARNING_DETAILS: + setattr(self, attr, local_values[attr]) + self._category_name = None + if category.__name__: + self._category_name = category.__name__ + +# Copied from 3.5 +######################################################################## +### ChainMap (helper for configparser and string.Template) +######################################################################## + +class ChainMap(collections.MutableMapping): + ''' A ChainMap groups multiple dicts (or other mappings) together + to create a single, updateable view. + + The underlying mappings are stored in a list. That list is public and can + accessed or updated using the *maps* attribute. There is no other state. + + Lookups search the underlying mappings successively until a key is found. + In contrast, writes, updates, and deletions only operate on the first + mapping. + + ''' + + def __init__(self, *maps): + '''Initialize a ChainMap by setting *maps* to the given mappings. + If no mappings are provided, a single empty dictionary is used. + + ''' + self.maps = list(maps) or [{}] # always at least one map + + def __missing__(self, key): + raise KeyError(key) + + def __getitem__(self, key): + for mapping in self.maps: + try: + return mapping[key] # can't use 'key in mapping' with defaultdict + except KeyError: + pass + return self.__missing__(key) # support subclasses that define __missing__ + + def get(self, key, default=None): + return self[key] if key in self else default + + def __len__(self): + return len(set().union(*self.maps)) # reuses stored hash values if possible + + def __iter__(self): + return iter(set().union(*self.maps)) + + def __contains__(self, key): + return any(key in m for m in self.maps) + + def __bool__(self): + return any(self.maps) + + if getattr(collections, '_recursive_repr', None): + @collections._recursive_repr() + def __repr__(self): + return '{0.__class__.__name__}({1})'.format( + self, ', '.join(map(repr, self.maps))) + else: + def __repr__(self): + return '{0.__class__.__name__}({1})'.format( + self, ', '.join(map(repr, self.maps))) + + @classmethod + def fromkeys(cls, iterable, *args): + 'Create a ChainMap with a single dict created from the iterable.' + return cls(dict.fromkeys(iterable, *args)) + + def copy(self): + 'New ChainMap or subclass with a new copy of maps[0] and refs to maps[1:]' + return self.__class__(self.maps[0].copy(), *self.maps[1:]) + + __copy__ = copy + + def new_child(self, m=None): # like Django's Context.push() + ''' + New ChainMap with a new map followed by all previous maps. If no + map is provided, an empty dict is used. + ''' + if m is None: + m = {} + return self.__class__(m, *self.maps) + + @property + def parents(self): # like Django's Context.pop() + 'New ChainMap from maps[1:].' + return self.__class__(*self.maps[1:]) + + def __setitem__(self, key, value): + self.maps[0][key] = value + + def __delitem__(self, key): + try: + del self.maps[0][key] + except KeyError: + raise KeyError('Key not found in the first mapping: {!r}'.format(key)) + + def popitem(self): + 'Remove and return an item pair from maps[0]. Raise KeyError is maps[0] is empty.' + try: + return self.maps[0].popitem() + except KeyError: + raise KeyError('No keys found in the first mapping.') + + def pop(self, key, *args): + 'Remove *key* from maps[0] and return its value. Raise KeyError if *key* not in maps[0].' + try: + return self.maps[0].pop(key, *args) + except KeyError: + raise KeyError('Key not found in the first mapping: {!r}'.format(key)) + + def clear(self): + 'Clear maps[0], leaving maps[1:] intact.' + self.maps[0].clear() + +if sys.version_info[:2] < (3, 4): + collections.ChainMap = ChainMap + + +# support raise_from on 3.x: +# submitted to six: https://bitbucket.org/gutworth/six/issue/102/raise-foo-from-bar-is-a-syntax-error-on-27 +if sys.version_info[:2] > (3, 2): + six.exec_("""def raise_from(value, from_value): + raise value from from_value +""") +else: + def raise_from(value, from_value): + raise value diff --git a/PyInstaller/lib/unittest2/loader.py b/PyInstaller/lib/unittest2/loader.py index 8f2753fffe..ad58ba0caa 100644 --- a/PyInstaller/lib/unittest2/loader.py +++ b/PyInstaller/lib/unittest2/loader.py @@ -6,10 +6,12 @@ import traceback import types import unittest +import warnings from fnmatch import fnmatch -from unittest2 import case, suite +from unittest2 import case, suite, util +from unittest2.compatibility import raise_from try: from os.path import relpath @@ -36,24 +38,38 @@ def __lt__(self, other): def _make_failed_import_test(name, suiteClass): - message = 'Failed to import test module: %s' % name - if hasattr(traceback, 'format_exc'): - # Python 2.3 compatibility - # format_exc returns two frames of discover.py as well - message += '\n%s' % traceback.format_exc() + message = 'Failed to import test module: %s\n%s' % ( + name, traceback.format_exc()) return _make_failed_test('ModuleImportFailure', name, ImportError(message), - suiteClass) + suiteClass, message) def _make_failed_load_tests(name, exception, suiteClass): - return _make_failed_test('LoadTestsFailure', name, exception, suiteClass) + message = 'Failed to call load_tests:\n%s' % (traceback.format_exc(),) + return _make_failed_test( + 'LoadTestsFailure', name, exception, suiteClass, message) -def _make_failed_test(classname, methodname, exception, suiteClass): +def _make_failed_test(classname, methodname, exception, suiteClass, message): def testFailure(self): raise exception attrs = {methodname: testFailure} TestClass = type(classname, (case.TestCase,), attrs) + return suiteClass((TestClass(methodname),)), message + + +def _make_skipped_test(methodname, exception, suiteClass): + @case.skip(str(exception)) + def testSkipped(self): + pass + attrs = {methodname: testSkipped} + TestClass = type("ModuleSkipped", (case.TestCase,), attrs) return suiteClass((TestClass(methodname),)) - + +def _jython_aware_splitext(path): + if path.lower().endswith('$py.class'): + return path[:-9] + return os.path.splitext(path)[0] + + class TestLoader(unittest.TestLoader): """ @@ -61,23 +77,52 @@ class TestLoader(unittest.TestLoader): and returning them wrapped in a TestSuite """ testMethodPrefix = 'test' - sortTestMethodsUsing = cmp + sortTestMethodsUsing = staticmethod(util.three_way_cmp) suiteClass = suite.TestSuite _top_level_dir = None + def __init__(self): + super(TestLoader, self).__init__() + self.errors = [] + # Tracks packages which we have called into via load_tests, to + # avoid infinite re-entrancy. + self._loading_packages = set() + def loadTestsFromTestCase(self, testCaseClass): """Return a suite of all tests cases contained in testCaseClass""" if issubclass(testCaseClass, suite.TestSuite): - raise TypeError("Test cases should not be derived from TestSuite." - " Maybe you meant to derive from TestCase?") + raise TypeError("Test cases should not be derived from " + "TestSuite. Maybe you meant to derive from " + "TestCase?") testCaseNames = self.getTestCaseNames(testCaseClass) if not testCaseNames and hasattr(testCaseClass, 'runTest'): testCaseNames = ['runTest'] loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames)) return loaded_suite - def loadTestsFromModule(self, module, use_load_tests=True): + # XXX After Python 3.5, remove backward compatibility hacks for + # use_load_tests deprecation via *args and **kws. See issue 16662. + def loadTestsFromModule(self, module, use_load_tests=None, pattern=None, *args, **kws): """Return a suite of all tests cases contained in the given module""" + # This method used to take an undocumented and unofficial + # use_load_tests argument. For backward compatibility, we still + # accept the argument (which can also be the first position) but we + # ignore it and issue a deprecation warning if it's present. + if use_load_tests is not None: + warnings.warn('use_load_tests is deprecated and ignored', + DeprecationWarning) + if len(args) > 0: + # Complain about the number of arguments, but don't forget the + # required `module` argument. + complaint = len(args) + 1 + raise TypeError('loadTestsFromModule() takes 1 positional argument but {0} were given'.format(complaint)) + if len(kws) != 0: + # Since the keyword arguments are unsorted (see PEP 468), just + # pick the alphabetically sorted first argument to complain about, + # if multiple were given. At least the error message will be + # predictable. + complaint = sorted(kws)[0] + raise TypeError("loadTestsFromModule() got an unexpected keyword argument '{0}'".format(complaint)) tests = [] for name in dir(module): obj = getattr(module, name) @@ -86,12 +131,15 @@ def loadTestsFromModule(self, module, use_load_tests=True): load_tests = getattr(module, 'load_tests', None) tests = self.suiteClass(tests) - if use_load_tests and load_tests is not None: + if load_tests is not None: try: - return load_tests(self, tests, None) - except Exception, e: - return _make_failed_load_tests(module.__name__, e, - self.suiteClass) + return load_tests(self, tests, pattern) + except Exception: + e = sys.exc_info()[1] + error_case, error_message = _make_failed_load_tests( + module.__name__, e, self.suiteClass) + self.errors.append(error_message) + return error_case return tests def loadTestsFromName(self, name, module=None): @@ -104,32 +152,70 @@ def loadTestsFromName(self, name, module=None): The method optionally resolves the names relative to a given module. """ parts = name.split('.') + error_case, error_message = None, None if module is None: parts_copy = parts[:] while parts_copy: try: - module = __import__('.'.join(parts_copy)) + module_name = '.'.join(parts_copy) + module = __import__(module_name) break except ImportError: - del parts_copy[-1] + next_attribute = parts_copy.pop() + # Last error so we can give it to the user if needed. + error_case, error_message = _make_failed_import_test( + next_attribute, self.suiteClass) if not parts_copy: - raise + # Even the top level import failed: report that error. + self.errors.append(error_message) + return error_case parts = parts[1:] obj = module for part in parts: - parent, obj = obj, getattr(obj, part) + try: + parent, obj = obj, getattr(obj, part) + except AttributeError as e: + # We can't traverse some part of the name. + if (getattr(obj, '__path__', None) is not None + and error_case is not None): + # This is a package (no __path__ per importlib docs), and we + # encountered an error importing something. We cannot tell + # the difference between package.WrongNameTestClass and + # package.wrong_module_name so we just report the + # ImportError - it is more informative. + self.errors.append(error_message) + return error_case + else: + # Otherwise, we signal that an AttributeError has occurred. + error_case, error_message = _make_failed_test( + 'AttributeError', part, e, self.suiteClass, + 'Failed to access attribute:\n%s' % ( + traceback.format_exc(),)) + self.errors.append(error_message) + return error_case if isinstance(obj, types.ModuleType): return self.loadTestsFromModule(obj) elif isinstance(obj, type) and issubclass(obj, unittest.TestCase): return self.loadTestsFromTestCase(obj) - elif (isinstance(obj, types.UnboundMethodType) and + elif ((hasattr(types, 'UnboundMethodType') + and isinstance(obj, types.UnboundMethodType)) and isinstance(parent, type) and issubclass(parent, case.TestCase)): - return self.suiteClass([parent(obj.__name__)]) + name = parts[-1] + inst = parent(name) + return self.suiteClass([inst]) + elif (isinstance(obj, types.FunctionType) and + isinstance(parent, type) and + issubclass(parent, case.TestCase)): + name = parts[-1] + inst = parent(name) + # static methods follow a different path + if not isinstance(getattr(inst, name), types.FunctionType): + return self.suiteClass([inst]) elif isinstance(obj, unittest.TestSuite): return obj - elif hasattr(obj, '__call__'): + if callable(obj): test = obj() if isinstance(test, unittest.TestSuite): return test @@ -155,17 +241,16 @@ def isTestMethod(attrname, testCaseClass=testCaseClass, prefix=self.testMethodPrefix): return attrname.startswith(prefix) and \ hasattr(getattr(testCaseClass, attrname), '__call__') - testFnNames = filter(isTestMethod, dir(testCaseClass)) + testFnNames = list(filter(isTestMethod, dir(testCaseClass))) if self.sortTestMethodsUsing: - # testFnNames.sort(key=_CmpToKey(self.sortTestMethodsUsing)) - testFnNames.sort(self.sortTestMethodsUsing) + testFnNames.sort(key=_CmpToKey(self.sortTestMethodsUsing)) return testFnNames def discover(self, start_dir, pattern='test*.py', top_level_dir=None): """Find and return all test modules from the specified start - directory, recursing into subdirectories to find them. Only test files - that match the pattern will be loaded. (Using shell style pattern - matching.) + directory, recursing into subdirectories to find them and return all + tests found within them. Only test files that match the pattern will + be loaded. (Using shell style pattern matching.) All test modules must be importable from the top level of the project. If the start directory is not the top level directory then the top @@ -173,14 +258,21 @@ def discover(self, start_dir, pattern='test*.py', top_level_dir=None): If a test package name (directory with '__init__.py') matches the pattern then the package will be checked for a 'load_tests' function. If - this exists then it will be called with loader, tests, pattern. + this exists then it will be called with (loader, tests, pattern) unless + the package has already had load_tests called from the same discovery + invocation, in which case the package module object is not scanned for + tests - this ensures that when a package uses discover to further + discover child tests that infinite recursion does not happen. - If load_tests exists then discovery does *not* recurse into the package, + If load_tests exists then discovery does *not* recurse into the package, load_tests is responsible for loading all tests in the package. The pattern is deliberately not stored as a loader attribute so that packages can continue discovery themselves. top_level_dir is stored so load_tests does not need to pass this argument in to loader.discover(). + + Paths are sorted before being imported to ensure reproducible execution + order even on filesystems with non-alphabetical ordering like ext3/4. """ set_implicit_top = False if top_level_dir is None and self._top_level_dir is not None: @@ -201,6 +293,8 @@ def discover(self, start_dir, pattern='test*.py', top_level_dir=None): self._top_level_dir = top_level_dir is_not_importable = False + is_namespace = False + tests = [] if os.path.isdir(os.path.abspath(start_dir)): start_dir = os.path.abspath(start_dir) if start_dir != top_level_dir: @@ -214,19 +308,70 @@ def discover(self, start_dir, pattern='test*.py', top_level_dir=None): else: the_module = sys.modules[start_dir] top_part = start_dir.split('.')[0] - start_dir = os.path.abspath(os.path.dirname((the_module.__file__))) + try: + start_dir = os.path.abspath( + os.path.dirname((the_module.__file__))) + except AttributeError: + # look for namespace packages + try: + spec = the_module.__spec__ + except AttributeError: + spec = None + + if spec and spec.loader is None: + if spec.submodule_search_locations is not None: + is_namespace = True + + for path in the_module.__path__: + if (not set_implicit_top and + not path.startswith(top_level_dir)): + continue + self._top_level_dir = \ + (path.split(the_module.__name__ + .replace(".", os.path.sep))[0]) + tests.extend(self._find_tests(path, + pattern, + namespace=True)) + elif the_module.__name__ in sys.builtin_module_names: + # builtin module + raise_from(TypeError('Can not use builtin modules ' + 'as dotted module names'), None) + else: + raise_from(TypeError( + 'don\'t know how to discover from {0!r}' + .format(the_module)), None) + if set_implicit_top: - self._top_level_dir = os.path.abspath(os.path.dirname(os.path.dirname(sys.modules[top_part].__file__))) - sys.path.remove(top_level_dir) + if not is_namespace: + self._top_level_dir = \ + self._get_directory_containing_module(top_part) + sys.path.remove(top_level_dir) + else: + sys.path.remove(top_level_dir) if is_not_importable: raise ImportError('Start directory is not importable: %r' % start_dir) - tests = list(self._find_tests(start_dir, pattern)) + if not is_namespace: + tests = list(self._find_tests(start_dir, pattern)) return self.suiteClass(tests) + def _get_directory_containing_module(self, module_name): + module = sys.modules[module_name] + full_path = os.path.abspath(module.__file__) + + if os.path.basename(full_path).lower().startswith('__init__.py'): + return os.path.dirname(os.path.dirname(full_path)) + else: + # here we have been given a module rather than a package - so + # all we can do is search the *same* directory the module is in + # should an exception be raised instead + return os.path.dirname(full_path) + def _get_name_from_path(self, path): - path = os.path.splitext(os.path.normpath(path))[0] + if path == self._top_level_dir: + return '.' + path = _jython_aware_splitext(os.path.normpath(path)) _relpath = relpath(path, self._top_level_dir) assert not os.path.isabs(_relpath), "Path must be within the project" @@ -242,63 +387,116 @@ def _get_module_from_name(self, name): def _match_path(self, path, full_path, pattern): # override this method to use alternative matching strategy return fnmatch(path, pattern) - - def _find_tests(self, start_dir, pattern): - """Used by discovery. Yields test suites it loads.""" - paths = os.listdir(start_dir) + def _find_tests(self, start_dir, pattern, namespace=False): + """Used by discovery. Yields test suites it loads.""" + # Handle the __init__ in this package + name = self._get_name_from_path(start_dir) + # name is '.' when start_dir == top_level_dir (and top_level_dir is by + # definition not a package). + if name != '.' and name not in self._loading_packages: + # name is in self._loading_packages while we have called into + # loadTestsFromModule with name. + tests, should_recurse = self._find_test_path( + start_dir, pattern, namespace) + if tests is not None: + yield tests + if not should_recurse: + # Either an error occured, or load_tests was used by the + # package. + return + # Handle the contents. + paths = sorted(os.listdir(start_dir)) for path in paths: full_path = os.path.join(start_dir, path) - if os.path.isfile(full_path): - if not VALID_MODULE_NAME.match(path): - # valid Python identifiers only - continue - if not self._match_path(path, full_path, pattern): - continue - # if the test file matches, load it + tests, should_recurse = self._find_test_path( + full_path, pattern, namespace) + if tests is not None: + yield tests + if should_recurse: + # we found a package that didn't use load_tests. name = self._get_name_from_path(full_path) + self._loading_packages.add(name) try: - module = self._get_module_from_name(name) - except: - yield _make_failed_import_test(name, self.suiteClass) - else: - mod_file = os.path.abspath(getattr(module, '__file__', full_path)) - realpath = os.path.splitext(mod_file)[0] - fullpath_noext = os.path.splitext(full_path)[0] - if realpath.lower() != fullpath_noext.lower(): - module_dir = os.path.dirname(realpath) - mod_name = os.path.splitext(os.path.basename(full_path))[0] - expected_dir = os.path.dirname(full_path) - msg = ("%r module incorrectly imported from %r. Expected %r. " - "Is this module globally installed?") - raise ImportError(msg % (mod_name, module_dir, expected_dir)) - yield self.loadTestsFromModule(module) - elif os.path.isdir(full_path): - if not os.path.isfile(os.path.join(full_path, '__init__.py')): - continue - - load_tests = None - tests = None - if fnmatch(path, pattern): - # only check load_tests if the package directory itself matches the filter - name = self._get_name_from_path(full_path) - package = self._get_module_from_name(name) - load_tests = getattr(package, 'load_tests', None) - tests = self.loadTestsFromModule(package, use_load_tests=False) - - if load_tests is None: - if tests is not None: - # tests loaded from package file - yield tests - # recurse into the package - for test in self._find_tests(full_path, pattern): + path_tests = self._find_tests(full_path, pattern, namespace) + for test in path_tests: yield test - else: - try: - yield load_tests(self, tests, pattern) - except Exception, e: - yield _make_failed_load_tests(package.__name__, e, - self.suiteClass) + finally: + self._loading_packages.discard(name) + + def _find_test_path(self, full_path, pattern, namespace=False): + """Used by discovery. + + Loads tests from a single file, or a directories' __init__.py when + passed the directory. + + Returns a tuple (None_or_tests_from_file, should_recurse). + """ + basename = os.path.basename(full_path) + if os.path.isfile(full_path): + if not VALID_MODULE_NAME.match(basename): + # valid Python identifiers only + return None, False + if not self._match_path(basename, full_path, pattern): + return None, False + # if the test file matches, load it + name = self._get_name_from_path(full_path) + try: + module = self._get_module_from_name(name) + except case.SkipTest as e: + return _make_skipped_test(name, e, self.suiteClass), False + except: + error_case, error_message = \ + _make_failed_import_test(name, self.suiteClass) + self.errors.append(error_message) + return error_case, False + else: + mod_file = os.path.abspath( + getattr(module, '__file__', full_path)) + realpath = _jython_aware_splitext( + os.path.realpath(mod_file)) + fullpath_noext = _jython_aware_splitext( + os.path.realpath(full_path)) + if realpath.lower() != fullpath_noext.lower(): + module_dir = os.path.dirname(realpath) + mod_name = _jython_aware_splitext( + os.path.basename(full_path)) + expected_dir = os.path.dirname(full_path) + msg = ("%r module incorrectly imported from %r. Expected " + "%r. Is this module globally installed?") + raise ImportError( + msg % (mod_name, module_dir, expected_dir)) + return self.loadTestsFromModule(module, pattern=pattern), False + elif os.path.isdir(full_path): + if (not namespace and + not os.path.isfile(os.path.join(full_path, '__init__.py'))): + return None, False + + load_tests = None + tests = None + name = self._get_name_from_path(full_path) + try: + package = self._get_module_from_name(name) + except case.SkipTest as e: + return _make_skipped_test(name, e, self.suiteClass), False + except: + error_case, error_message = \ + _make_failed_import_test(name, self.suiteClass) + self.errors.append(error_message) + return error_case, False + else: + load_tests = getattr(package, 'load_tests', None) + # Mark this package as being in load_tests (possibly ;)) + self._loading_packages.add(name) + try: + tests = self.loadTestsFromModule(package, pattern=pattern) + if load_tests is not None: + # loadTestsFromModule(package) has loaded tests for us. + return tests, False + return tests, True + finally: + self._loading_packages.discard(name) + defaultTestLoader = TestLoader() @@ -311,13 +509,13 @@ def _makeLoader(prefix, sortUsing, suiteClass=None): loader.suiteClass = suiteClass return loader -def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp): +def getTestCaseNames(testCaseClass, prefix, sortUsing=util.three_way_cmp): return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass) -def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, +def makeSuite(testCaseClass, prefix='test', sortUsing=util.three_way_cmp, suiteClass=suite.TestSuite): return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass) -def findTestCases(module, prefix='test', sortUsing=cmp, +def findTestCases(module, prefix='test', sortUsing=util.three_way_cmp, suiteClass=suite.TestSuite): return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module) diff --git a/PyInstaller/lib/unittest2/main.py b/PyInstaller/lib/unittest2/main.py index 9db1d307bf..833fdce6ad 100644 --- a/PyInstaller/lib/unittest2/main.py +++ b/PyInstaller/lib/unittest2/main.py @@ -1,9 +1,12 @@ """Unittest main program""" import sys +import argparse import os import types +import six + from unittest2 import loader, runner try: from unittest2.signals import installHandler @@ -12,71 +15,58 @@ __unittest = True -FAILFAST = " -f, --failfast Stop on first failure\n" -CATCHBREAK = " -c, --catch Catch control-C and display results\n" -BUFFEROUTPUT = " -b, --buffer Buffer stdout and stderr during test runs\n" - -USAGE_AS_MAIN = """\ -Usage: %(progName)s [options] [tests] - -Options: - -h, --help Show this message - -v, --verbose Verbose output - -q, --quiet Minimal output -%(failfast)s%(catchbreak)s%(buffer)s +MAIN_EXAMPLES = """\ Examples: - %(progName)s test_module - run tests from test_module - %(progName)s test_module.TestClass - run tests from - test_module.TestClass - %(progName)s test_module.TestClass.test_method - run specified test method - -[tests] can be a list of any number of test modules, classes and test -methods. - -Alternative Usage: %(progName)s discover [options] - -Options: - -v, --verbose Verbose output -%(failfast)s%(catchbreak)s%(buffer)s -s directory Directory to start discovery ('.' default) - -p pattern Pattern to match test files ('test*.py' default) - -t directory Top level directory of project (default to - start directory) - -For test discovery all test modules must be importable from the top -level directory of the project. + %(prog)s test_module - run tests from test_module + %(prog)s module.TestClass - run tests from module.TestClass + %(prog)s module.Class.test_method - run specified test method """ -USAGE_FROM_MODULE = """\ -Usage: %(progName)s [options] [test] [...] - -Options: - -h, --help Show this message - -v, --verbose Verbose output - -q, --quiet Minimal output -%(failfast)s%(catchbreak)s%(buffer)s +MODULE_EXAMPLES = """\ Examples: - %(progName)s - run default set of tests - %(progName)s MyTestSuite - run suite 'MyTestSuite' - %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething - %(progName)s MyTestCase - run all 'test*' test methods - in MyTestCase + %(prog)s - run default set of tests + %(prog)s MyTestSuite - run suite 'MyTestSuite' + %(prog)s MyTestCase.testSomething - run MyTestCase.testSomething + %(prog)s MyTestCase - run all 'test*' test methods + in MyTestCase """ +def _convert_name(name): + # on Linux / Mac OS X 'foo.PY' is not importable, but on + # Windows it is. Simpler to do a case insensitive match + # a better check would be to check that the name is a + # valid Python module name. + if os.path.isfile(name) and name.lower().endswith('.py'): + if os.path.isabs(name): + rel_path = os.path.relpath(name, os.getcwd()) + if os.path.isabs(rel_path) or rel_path.startswith(os.pardir): + return name + name = rel_path + # on Windows both '\' and '/' are used as path + # separators. Better to replace both than rely on os.path.sep + return name[:-3].replace('\\', '.').replace('/', '.') + return name + +def _convert_names(names): + return [_convert_name(name) for name in names] + + class TestProgram(object): """A command-line program that runs a set of tests; this is primarily for making test modules conveniently executable. """ - USAGE = USAGE_FROM_MODULE - # defaults for testing + module=None + verbosity = 1 failfast = catchbreak = buffer = progName = None + _discovery_parser = None def __init__(self, module='__main__', defaultTest=None, argv=None, testRunner=None, testLoader=loader.defaultTestLoader, exit=True, verbosity=1, failfast=None, catchbreak=None, buffer=None): - if isinstance(module, basestring): + if isinstance(module, six.string_types): self.module = __import__(module) for part in module.split('.')[1:]: self.module = getattr(self.module, part) @@ -99,59 +89,48 @@ def __init__(self, module='__main__', defaultTest=None, def usageExit(self, msg=None): if msg: - print msg - usage = {'progName': self.progName, 'catchbreak': '', 'failfast': '', - 'buffer': ''} - if self.failfast != False: - usage['failfast'] = FAILFAST - if self.catchbreak != False and installHandler is not None: - usage['catchbreak'] = CATCHBREAK - if self.buffer != False: - usage['buffer'] = BUFFEROUTPUT - print self.USAGE % usage + print(msg) + if self._discovery_parser is None: + self._initArgParsers() + self._print_help() sys.exit(2) + def _print_help(self, *args, **kwargs): + if self.module is None: + print(self._main_parser.format_help()) + print(MAIN_EXAMPLES % {'prog': self.progName}) + self._discovery_parser.print_help() + else: + print(self._main_parser.format_help()) + print(MODULE_EXAMPLES % {'prog': self.progName}) + def parseArgs(self, argv): - if len(argv) > 1 and argv[1].lower() == 'discover': - self._do_discovery(argv[2:]) - return - - import getopt - long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer'] - try: - options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts) - for opt, value in options: - if opt in ('-h','-H','--help'): - self.usageExit() - if opt in ('-q','--quiet'): - self.verbosity = 0 - if opt in ('-v','--verbose'): - self.verbosity = 2 - if opt in ('-f','--failfast'): - if self.failfast is None: - self.failfast = True - # Should this raise an exception if -f is not valid? - if opt in ('-c','--catch'): - if self.catchbreak is None and installHandler is not None: - self.catchbreak = True - # Should this raise an exception if -c is not valid? - if opt in ('-b','--buffer'): - if self.buffer is None: - self.buffer = True - # Should this raise an exception if -b is not valid? - if len(args) == 0 and self.defaultTest is None: - # createTests will load tests from self.module - self.testNames = None - elif len(args) > 0: - self.testNames = args - if __name__ == '__main__': - # to support python -m unittest ... - self.module = None - else: - self.testNames = (self.defaultTest,) - self.createTests() - except getopt.error, msg: - self.usageExit(msg) + self._initArgParsers() + if self.module is None: + if len(argv) > 1 and argv[1].lower() == 'discover': + self._do_discovery(argv[2:]) + return + self._main_parser.parse_args(argv[1:], self) + if not self.tests: + # this allows "python -m unittest -v" to still work for + # test discovery. + self._do_discovery([]) + return + else: + self._main_parser.parse_args(argv[1:], self) + if self.tests: + self.testNames = _convert_names(self.tests) + if __name__ == '__main__': + # to support python -m unittest ... + self.module = None + elif self.defaultTest is None: + # createTests will load tests from self.module + self.testNames = None + elif isinstance(self.defaultTest, str): + self.testNames = (self.defaultTest,) + else: + self.testNames = list(self.defaultTest) + self.createTests() def createTests(self): if self.testNames is None: @@ -160,65 +139,91 @@ def createTests(self): self.test = self.testLoader.loadTestsFromNames(self.testNames, self.module) - def _do_discovery(self, argv, Loader=loader.TestLoader): - # handle command line args for test discovery - self.progName = '%s discover' % self.progName - import optparse - parser = optparse.OptionParser() - parser.prog = self.progName - parser.add_option('-v', '--verbose', dest='verbose', default=False, - help='Verbose output', action='store_true') - if self.failfast != False: - parser.add_option('-f', '--failfast', dest='failfast', default=False, - help='Stop on first fail or error', - action='store_true') - if self.catchbreak != False and installHandler is not None: - parser.add_option('-c', '--catch', dest='catchbreak', default=False, - help='Catch ctrl-C and display results so far', - action='store_true') - if self.buffer != False: - parser.add_option('-b', '--buffer', dest='buffer', default=False, - help='Buffer stdout and stderr during tests', - action='store_true') - parser.add_option('-s', '--start-directory', dest='start', default='.', - help="Directory to start discovery ('.' default)") - parser.add_option('-p', '--pattern', dest='pattern', default='test*.py', - help="Pattern to match tests ('test*.py' default)") - parser.add_option('-t', '--top-level-directory', dest='top', default=None, - help='Top level directory of project (defaults to start directory)') - - options, args = parser.parse_args(argv) - if len(args) > 3: - self.usageExit() - - for name, value in zip(('start', 'pattern', 'top'), args): - setattr(options, name, value) - - # only set options from the parsing here - # if they weren't set explicitly in the constructor + def _initArgParsers(self): + parent_parser = self._getParentArgParser() + self._main_parser = self._getMainArgParser(parent_parser) + self._discovery_parser = self._getDiscoveryArgParser(parent_parser) + + def _getParentArgParser(self): + parser = argparse.ArgumentParser(add_help=False) + + parser.add_argument('-v', '--verbose', dest='verbosity', + action='store_const', const=2, + help='Verbose output') + parser.add_argument('-q', '--quiet', dest='verbosity', + action='store_const', const=0, + help='Quiet output') + if self.failfast is None: - self.failfast = options.failfast - if self.catchbreak is None and installHandler is not None: - self.catchbreak = options.catchbreak + parser.add_argument('-f', '--failfast', dest='failfast', + action='store_true', + help='Stop on first fail or error') + self.failfast = False + if self.catchbreak is None: + parser.add_argument('-c', '--catch', dest='catchbreak', + action='store_true', + help='Catch ctrl-C and display results so far') + self.catchbreak = False if self.buffer is None: - self.buffer = options.buffer - - if options.verbose: - self.verbosity = 2 + parser.add_argument('-b', '--buffer', dest='buffer', + action='store_true', + help='Buffer stdout and stderr during tests') + self.buffer = False - start_dir = options.start - pattern = options.pattern - top_level_dir = options.top + return parser - loader = Loader() - self.test = loader.discover(start_dir, pattern, top_level_dir) + def _getMainArgParser(self, parent): + parser = argparse.ArgumentParser(parents=[parent]) + parser.prog = self.progName + parser.print_help = self._print_help + + parser.add_argument('tests', nargs='*', + help='a list of any number of test modules, ' + 'classes and test methods.') + + return parser + + def _getDiscoveryArgParser(self, parent): + parser = argparse.ArgumentParser(parents=[parent]) + parser.prog = '%s discover' % self.progName + parser.epilog = ('For test discovery all test modules must be ' + 'importable from the top level directory of the ' + 'project.') + + parser.add_argument('-s', '--start-directory', dest='start', + help="Directory to start discovery ('.' default)") + parser.add_argument('-p', '--pattern', dest='pattern', + help="Pattern to match tests ('test*.py' default)") + parser.add_argument('-t', '--top-level-directory', dest='top', + help='Top level directory of project (defaults to ' + 'start directory)') + for arg in ('start', 'pattern', 'top'): + parser.add_argument(arg, nargs='?', + default=argparse.SUPPRESS, + help=argparse.SUPPRESS) + + return parser + + def _do_discovery(self, argv, Loader=None): + self.start = '.' + self.pattern = 'test*.py' + self.top = None + if argv is not None: + # handle command line args for test discovery + if self._discovery_parser is None: + # for testing + self._initArgParsers() + self._discovery_parser.parse_args(argv, self) + + loader = self.testLoader if Loader is None else Loader() + self.test = loader.discover(self.start, self.pattern, self.top) def runTests(self): if self.catchbreak: installHandler() if self.testRunner is None: self.testRunner = runner.TextTestRunner - if isinstance(self.testRunner, (type, types.ClassType)): + if isinstance(self.testRunner, six.class_types): try: testRunner = self.testRunner(verbosity=self.verbosity, failfast=self.failfast, @@ -234,8 +239,3 @@ def runTests(self): sys.exit(not self.result.wasSuccessful()) main = TestProgram - -def main_(): - TestProgram.USAGE = USAGE_AS_MAIN - main(module=None) - diff --git a/PyInstaller/lib/unittest2/result.py b/PyInstaller/lib/unittest2/result.py index e238c7561c..752da07898 100644 --- a/PyInstaller/lib/unittest2/result.py +++ b/PyInstaller/lib/unittest2/result.py @@ -4,7 +4,7 @@ import traceback import unittest -from StringIO import StringIO +from six.moves import StringIO from unittest2 import util from unittest2.compatibility import wraps @@ -12,11 +12,11 @@ __unittest = True def failfast(method): + @wraps(method) def inner(self, *args, **kw): if getattr(self, 'failfast', False): self.stop() return method(self, *args, **kw) - inner = wraps(method)(inner) return inner @@ -36,8 +36,8 @@ class TestResult(unittest.TestResult): """ _previousTestClass = None _moduleSetUpFailed = False - - def __init__(self): + + def __init__(self, stream=None, descriptions=None, verbosity=None): self.failfast = False self.failures = [] self.errors = [] @@ -52,7 +52,7 @@ def __init__(self): self._original_stdout = sys.stdout self._original_stderr = sys.stderr self._mirrorOutput = False - + def startTest(self, test): "Called when the given test is about to be run" self.testsRun += 1 @@ -84,7 +84,7 @@ def stopTest(self, test): if not error.endswith('\n'): error += '\n' self._original_stderr.write(STDERR_LINE % error) - + sys.stdout = self._original_stdout sys.stderr = self._original_stderr self._stdout_buffer.seek(0) @@ -92,7 +92,7 @@ def stopTest(self, test): self._stderr_buffer.seek(0) self._stderr_buffer.truncate() self._mirrorOutput = False - + def stopTestRun(self): """Called once after all tests are executed. @@ -100,22 +100,37 @@ def stopTestRun(self): See stopTest for a method called after each test. """ - + @failfast def addError(self, test, err): """Called when an error has occurred. 'err' is a tuple of values as returned by sys.exc_info(). """ self.errors.append((test, self._exc_info_to_string(err, test))) self._mirrorOutput = True - addError = failfast(addError) + @failfast def addFailure(self, test, err): """Called when an error has occurred. 'err' is a tuple of values as returned by sys.exc_info().""" self.failures.append((test, self._exc_info_to_string(err, test))) self._mirrorOutput = True - addFailure = failfast(addFailure) - + + @failfast + def addSubTest(self, test, subtest, err): + """Called at the end of a subtest. + 'err' is None if the subtest ended successfully, otherwise it's a + tuple of values as returned by sys.exc_info(). + """ + # By default, we don't do anything with successful subtests, but + # more sophisticated test results might want to record them. + if err is not None: + if issubclass(err[0], test.failureException): + errors = self.failures + else: + errors = self.errors + errors.append((subtest, self._exc_info_to_string(err, test))) + self._mirrorOutput = True + def addSuccess(self, test): "Called when a test has completed successfully" pass @@ -129,17 +144,22 @@ def addExpectedFailure(self, test, err): self.expectedFailures.append( (test, self._exc_info_to_string(err, test))) + @failfast def addUnexpectedSuccess(self, test): """Called when a test was expected to fail, but succeed.""" self.unexpectedSuccesses.append(test) - addUnexpectedSuccess = failfast(addUnexpectedSuccess) def wasSuccessful(self): - "Tells whether or not this result was a success" - return (len(self.failures) + len(self.errors) == 0) + """Tells whether or not this result was a success.""" + # The hasattr check is for test_result's OldResult test. That + # way this method works on objects that lack the attribute. + # (where would such result intances come from? old stored pickles?) + return ((len(self.failures) == len(self.errors) == 0) and + (not hasattr(self, 'unexpectedSuccesses') or + len(self.unexpectedSuccesses) == 0)) def stop(self): - "Indicates that the tests should be aborted" + """Indicates that the tests should be aborted.""" self.shouldStop = True def _exc_info_to_string(self, err, test): @@ -154,10 +174,10 @@ def _exc_info_to_string(self, err, test): msgLines = traceback.format_exception(exctype, value, tb, length) else: msgLines = traceback.format_exception(exctype, value, tb) - + if self.buffer: output = sys.stdout.getvalue() - error = sys.stderr.getvalue() + error = sys.stderr.getvalue() if output: if not output.endswith('\n'): output += '\n' diff --git a/PyInstaller/lib/unittest2/runner.py b/PyInstaller/lib/unittest2/runner.py index 15a6f88ec7..b940e59459 100644 --- a/PyInstaller/lib/unittest2/runner.py +++ b/PyInstaller/lib/unittest2/runner.py @@ -11,19 +11,19 @@ except ImportError: def registerResult(_): pass - + __unittest = True class _WritelnDecorator(object): """Used to decorate file-like objects with a handy 'writeln' method""" - def __init__(self,stream): + def __init__(self, stream): self.stream = stream def __getattr__(self, attr): if attr in ('stream', '__getstate__'): raise AttributeError(attr) - return getattr(self.stream,attr) + return getattr(self.stream, attr) def writeln(self, arg=None): if arg: @@ -40,7 +40,7 @@ class TextTestResult(result.TestResult): separator2 = '-' * 70 def __init__(self, stream, descriptions, verbosity): - super(TextTestResult, self).__init__() + super(TextTestResult, self).__init__(stream, descriptions, verbosity) self.stream = stream self.showAll = verbosity > 1 self.dots = verbosity == 1 @@ -153,7 +153,7 @@ def run(self, test): result.failfast = self.failfast result.buffer = self.buffer registerResult(result) - + startTime = time.time() startTestRun = getattr(result, 'startTestRun', None) if startTestRun is not None: @@ -174,15 +174,16 @@ def run(self, test): self.stream.writeln("Ran %d test%s in %.3fs" % (run, run != 1 and "s" or "", timeTaken)) self.stream.writeln() - + expectedFails = unexpectedSuccesses = skipped = 0 try: results = map(len, (result.expectedFailures, result.unexpectedSuccesses, result.skipped)) - expectedFails, unexpectedSuccesses, skipped = results except AttributeError: pass + else: + expectedFails, unexpectedSuccesses, skipped = results infos = [] if not result.wasSuccessful(): self.stream.write("FAILED") diff --git a/PyInstaller/lib/unittest2/signals.py b/PyInstaller/lib/unittest2/signals.py index 5a3128b0d9..393b8c536d 100644 --- a/PyInstaller/lib/unittest2/signals.py +++ b/PyInstaller/lib/unittest2/signals.py @@ -9,6 +9,20 @@ class _InterruptHandler(object): def __init__(self, default_handler): self.called = False + self.original_handler = default_handler + if isinstance(default_handler, int): + if default_handler == signal.SIG_DFL: + # Pretend it's signal.default_int_handler instead. + default_handler = signal.default_int_handler + elif default_handler == signal.SIG_IGN: + # Not quite the same thing as SIG_IGN, but the closest we + # can make it: do nothing. + def default_handler(unused_signum, unused_frame): + pass + else: + raise TypeError("expected SIGINT signal handler to be " + "signal.SIG_IGN, signal.SIG_DFL, or a " + "callable object") self.default_handler = default_handler def __call__(self, signum, frame): @@ -17,7 +31,7 @@ def __call__(self, signum, frame): # if we aren't the installed handler, then delegate immediately # to the default handler self.default_handler(signum, frame) - + if self.called: self.default_handler(signum, frame) self.called = True @@ -42,6 +56,7 @@ def installHandler(): def removeHandler(method=None): if method is not None: + @wraps(method) def inner(*args, **kwargs): initial = signal.getsignal(signal.SIGINT) removeHandler() @@ -49,9 +64,8 @@ def inner(*args, **kwargs): return method(*args, **kwargs) finally: signal.signal(signal.SIGINT, initial) - inner = wraps(method)(inner) return inner global _interrupt_handler if _interrupt_handler is not None: - signal.signal(signal.SIGINT, _interrupt_handler.default_handler) + signal.signal(signal.SIGINT, _interrupt_handler.original_handler) diff --git a/PyInstaller/lib/unittest2/suite.py b/PyInstaller/lib/unittest2/suite.py index 370ca5f13e..da9cbd52b0 100644 --- a/PyInstaller/lib/unittest2/suite.py +++ b/PyInstaller/lib/unittest2/suite.py @@ -2,6 +2,9 @@ import sys import unittest + +import six + from unittest2 import case, util __unittest = True @@ -10,8 +13,11 @@ class BaseTestSuite(unittest.TestSuite): """A simple test suite that doesn't provide class or module shared fixtures. """ + _cleanup = True + def __init__(self, tests=()): self._tests = [] + self._removed_tests = 0 self.addTests(tests) def __repr__(self): @@ -32,9 +38,10 @@ def __iter__(self): return iter(self._tests) def countTestCases(self): - cases = 0 + cases = self._removed_tests for test in self: - cases += test.countTestCases() + if test: + cases += test.countTestCases() return cases def addTest(self, test): @@ -48,18 +55,34 @@ def addTest(self, test): self._tests.append(test) def addTests(self, tests): - if isinstance(tests, basestring): + if isinstance(tests, six.string_types): raise TypeError("tests must be an iterable of tests, not a string") for test in tests: self.addTest(test) def run(self, result): - for test in self: + for index, test in enumerate(self): if result.shouldStop: break test(result) + if self._cleanup: + self._removeTestAtIndex(index) return result + def _removeTestAtIndex(self, index): + """Stop holding a reference to the TestCase at index.""" + try: + test = self._tests[index] + except TypeError: + # support for suite implementations that have overriden self._tests + pass + else: + # Some unittest tests add non TestCase/TestSuite objects to + # the suite. + if hasattr(test, 'countTestCases'): + self._removed_tests += test.countTestCases() + self._tests[index] = None + def __call__(self, *args, **kwds): return self.run(*args, **kwds) @@ -78,45 +101,47 @@ class TestSuite(BaseTestSuite): in the order in which they were added, aggregating the results. When subclassing, do not forget to call the base class constructor. """ - - def run(self, result): - self._wrapped_run(result) - self._tearDownPreviousClass(None, result) - self._handleModuleTearDown(result) - return result - def debug(self): - """Run the tests without collecting errors in a TestResult""" - debug = _DebugResult() - self._wrapped_run(debug, True) - self._tearDownPreviousClass(None, debug) - self._handleModuleTearDown(debug) + def run(self, result, debug=False): + topLevel = False + if getattr(result, '_testRunEntered', False) is False: + result._testRunEntered = topLevel = True - ################################ - # private methods - def _wrapped_run(self, result, debug=False): - for test in self: + for index, test in enumerate(self): if result.shouldStop: break - + if _isnotsuite(test): self._tearDownPreviousClass(test, result) self._handleModuleFixture(test, result) self._handleClassSetUp(test, result) result._previousTestClass = test.__class__ - - if (getattr(test.__class__, '_classSetupFailed', False) or + + if (getattr(test.__class__, '_classSetupFailed', False) or getattr(result, '_moduleSetUpFailed', False)): continue - - if hasattr(test, '_wrapped_run'): - test._wrapped_run(result, debug) - elif not debug: + + if not debug: test(result) else: test.debug() - + + if self._cleanup: + self._removeTestAtIndex(index) + + if topLevel: + self._tearDownPreviousClass(None, result) + self._handleModuleTearDown(result) + return result + + def debug(self): + """Run the tests without collecting errors in a TestResult""" + debug = _DebugResult() + self.run(debug, True) + + ################################ + def _handleClassSetUp(self, test, result): previousClass = getattr(result, '_previousTestClass', None) currentClass = test.__class__ @@ -126,43 +151,44 @@ def _handleClassSetUp(self, test, result): return if getattr(currentClass, "__unittest_skip__", False): return - + try: currentClass._classSetupFailed = False except TypeError: # test may actually be a function # so its class will be a builtin-type pass - + setUpClass = getattr(currentClass, 'setUpClass', None) if setUpClass is not None: try: setUpClass() - except Exception, e: + except Exception: + e = sys.exc_info()[1] if isinstance(result, _DebugResult): raise currentClass._classSetupFailed = True className = util.strclass(currentClass) errorName = 'setUpClass (%s)' % className self._addClassOrModuleLevelException(result, e, errorName) - + def _get_previous_module(self, result): previousModule = None previousClass = getattr(result, '_previousTestClass', None) if previousClass is not None: previousModule = previousClass.__module__ return previousModule - - + + def _handleModuleFixture(self, test, result): previousModule = self._get_previous_module(result) currentModule = test.__class__.__module__ if currentModule == previousModule: return - + self._handleModuleTearDown(result) - + result._moduleSetUpFailed = False try: module = sys.modules[currentModule] @@ -172,7 +198,8 @@ def _handleModuleFixture(self, test, result): if setUpModule is not None: try: setUpModule() - except Exception, e: + except Exception: + e = sys.exc_info()[1] if isinstance(result, _DebugResult): raise result._moduleSetUpFailed = True @@ -186,14 +213,14 @@ def _addClassOrModuleLevelException(self, result, exception, errorName): addSkip(error, str(exception)) else: result.addError(error, sys.exc_info()) - + def _handleModuleTearDown(self, result): previousModule = self._get_previous_module(result) if previousModule is None: return if result._moduleSetUpFailed: return - + try: module = sys.modules[previousModule] except KeyError: @@ -203,12 +230,13 @@ def _handleModuleTearDown(self, result): if tearDownModule is not None: try: tearDownModule() - except Exception, e: + except Exception: + e = sys.exc_info()[1] if isinstance(result, _DebugResult): raise errorName = 'tearDownModule (%s)' % previousModule self._addClassOrModuleLevelException(result, e, errorName) - + def _tearDownPreviousClass(self, test, result): previousClass = getattr(result, '_previousTestClass', None) currentClass = test.__class__ @@ -220,12 +248,13 @@ def _tearDownPreviousClass(self, test, result): return if getattr(previousClass, "__unittest_skip__", False): return - + tearDownClass = getattr(previousClass, 'tearDownClass', None) if tearDownClass is not None: try: tearDownClass() - except Exception, e: + except Exception: + e = sys.exc_info()[1] if isinstance(result, _DebugResult): raise className = util.strclass(previousClass) diff --git a/PyInstaller/lib/unittest2/test/__init__.py b/PyInstaller/lib/unittest2/test/__init__.py deleted file mode 100644 index 4287ca8617..0000000000 --- a/PyInstaller/lib/unittest2/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# \ No newline at end of file diff --git a/PyInstaller/lib/unittest2/test/dummy.py b/PyInstaller/lib/unittest2/test/dummy.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/PyInstaller/lib/unittest2/test/support.py b/PyInstaller/lib/unittest2/test/support.py deleted file mode 100644 index a006b4526d..0000000000 --- a/PyInstaller/lib/unittest2/test/support.py +++ /dev/null @@ -1,177 +0,0 @@ -import sys -import warnings - -import unittest2 - - -def resultFactory(*_): - return unittest2.TestResult() - -class OldTestResult(object): - """An object honouring TestResult before startTestRun/stopTestRun.""" - - def __init__(self, *_): - self.failures = [] - self.errors = [] - self.testsRun = 0 - self.shouldStop = False - - def startTest(self, test): - pass - - def stopTest(self, test): - pass - - def addError(self, test, err): - self.errors.append((test, err)) - - def addFailure(self, test, err): - self.failures.append((test, err)) - - def addSuccess(self, test): - pass - - def wasSuccessful(self): - return True - - def printErrors(self): - pass - -class LoggingResult(unittest2.TestResult): - def __init__(self, log): - self._events = log - super(LoggingResult, self).__init__() - - def startTest(self, test): - self._events.append('startTest') - super(LoggingResult, self).startTest(test) - - def startTestRun(self): - self._events.append('startTestRun') - super(LoggingResult, self).startTestRun() - - def stopTest(self, test): - self._events.append('stopTest') - super(LoggingResult, self).stopTest(test) - - def stopTestRun(self): - self._events.append('stopTestRun') - super(LoggingResult, self).stopTestRun() - - def addFailure(self, *args): - self._events.append('addFailure') - super(LoggingResult, self).addFailure(*args) - - def addSuccess(self, *args): - self._events.append('addSuccess') - super(LoggingResult, self).addSuccess(*args) - - def addError(self, *args): - self._events.append('addError') - super(LoggingResult, self).addError(*args) - - def addSkip(self, *args): - self._events.append('addSkip') - super(LoggingResult, self).addSkip(*args) - - def addExpectedFailure(self, *args): - self._events.append('addExpectedFailure') - super(LoggingResult, self).addExpectedFailure(*args) - - def addUnexpectedSuccess(self, *args): - self._events.append('addUnexpectedSuccess') - super(LoggingResult, self).addUnexpectedSuccess(*args) - - -class EqualityMixin(object): - """Used as a mixin for TestCase""" - - # Check for a valid __eq__ implementation - def test_eq(self): - for obj_1, obj_2 in self.eq_pairs: - self.assertEqual(obj_1, obj_2) - self.assertEqual(obj_2, obj_1) - - # Check for a valid __ne__ implementation - def test_ne(self): - for obj_1, obj_2 in self.ne_pairs: - self.assertNotEqual(obj_1, obj_2) - self.assertNotEqual(obj_2, obj_1) - -class HashingMixin(object): - """Used as a mixin for TestCase""" - - # Check for a valid __hash__ implementation - def test_hash(self): - for obj_1, obj_2 in self.eq_pairs: - try: - if not hash(obj_1) == hash(obj_2): - self.fail("%r and %r do not hash equal" % (obj_1, obj_2)) - except KeyboardInterrupt: - raise - except Exception, e: - self.fail("Problem hashing %r and %r: %s" % (obj_1, obj_2, e)) - - for obj_1, obj_2 in self.ne_pairs: - try: - if hash(obj_1) == hash(obj_2): - self.fail("%s and %s hash equal, but shouldn't" % - (obj_1, obj_2)) - except KeyboardInterrupt: - raise - except Exception, e: - self.fail("Problem hashing %s and %s: %s" % (obj_1, obj_2, e)) - - - -# copied from Python 2.6 -try: - from warnings import catch_warnings -except ImportError: - class catch_warnings(object): - def __init__(self, record=False, module=None): - self._record = record - self._module = sys.modules['warnings'] - self._entered = False - - def __repr__(self): - args = [] - if self._record: - args.append("record=True") - name = type(self).__name__ - return "%s(%s)" % (name, ", ".join(args)) - - def __enter__(self): - if self._entered: - raise RuntimeError("Cannot enter %r twice" % self) - self._entered = True - self._filters = self._module.filters - self._module.filters = self._filters[:] - self._showwarning = self._module.showwarning - if self._record: - log = [] - def showwarning(*args, **kwargs): - log.append(WarningMessage(*args, **kwargs)) - self._module.showwarning = showwarning - return log - else: - return None - - def __exit__(self, *exc_info): - if not self._entered: - raise RuntimeError("Cannot exit %r without entering first" % self) - self._module.filters = self._filters - self._module.showwarning = self._showwarning - - class WarningMessage(object): - _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file", - "line") - def __init__(self, message, category, filename, lineno, file=None, - line=None): - local_values = locals() - for attr in self._WARNING_DETAILS: - setattr(self, attr, local_values[attr]) - self._category_name = None - if category.__name__: - self._category_name = category.__name__ - diff --git a/PyInstaller/lib/unittest2/test/test_assertions.py b/PyInstaller/lib/unittest2/test/test_assertions.py deleted file mode 100644 index 63abbc47d6..0000000000 --- a/PyInstaller/lib/unittest2/test/test_assertions.py +++ /dev/null @@ -1,259 +0,0 @@ - -import sys -import datetime -if sys.version_info[:2] == (2,3): - from sets import Set as set - from sets import ImmutableSet as frozenset - -import unittest2 - - -class Test_Assertions(unittest2.TestCase): - def test_AlmostEqual(self): - self.assertAlmostEqual(1.00000001, 1.0) - self.assertNotAlmostEqual(1.0000001, 1.0) - self.assertRaises(self.failureException, - self.assertAlmostEqual, 1.0000001, 1.0) - self.assertRaises(self.failureException, - self.assertNotAlmostEqual, 1.00000001, 1.0) - - self.assertAlmostEqual(1.1, 1.0, places=0) - self.assertRaises(self.failureException, - self.assertAlmostEqual, 1.1, 1.0, places=1) - - self.assertAlmostEqual(0, .1+.1j, places=0) - self.assertNotAlmostEqual(0, .1+.1j, places=1) - self.assertRaises(self.failureException, - self.assertAlmostEqual, 0, .1+.1j, places=1) - self.assertRaises(self.failureException, - self.assertNotAlmostEqual, 0, .1+.1j, places=0) - - try: - self.assertAlmostEqual(float('inf'), float('inf')) - self.assertRaises(self.failureException, self.assertNotAlmostEqual, - float('inf'), float('inf')) - except ValueError: - # float('inf') is invalid on Windows in Python 2.4 / 2.5 - x = object() - self.assertAlmostEqual(x, x) - self.assertRaises(self.failureException, self.assertNotAlmostEqual, - x, x) - - - def test_AmostEqualWithDelta(self): - self.assertAlmostEqual(1.1, 1.0, delta=0.5) - self.assertAlmostEqual(1.0, 1.1, delta=0.5) - self.assertNotAlmostEqual(1.1, 1.0, delta=0.05) - self.assertNotAlmostEqual(1.0, 1.1, delta=0.05) - - self.assertRaises(self.failureException, self.assertAlmostEqual, - 1.1, 1.0, delta=0.05) - self.assertRaises(self.failureException, self.assertNotAlmostEqual, - 1.1, 1.0, delta=0.5) - - self.assertRaises(TypeError, self.assertAlmostEqual, - 1.1, 1.0, places=2, delta=2) - self.assertRaises(TypeError, self.assertNotAlmostEqual, - 1.1, 1.0, places=2, delta=2) - - first = datetime.datetime.now() - second = first + datetime.timedelta(seconds=10) - self.assertAlmostEqual(first, second, - delta=datetime.timedelta(seconds=20)) - self.assertNotAlmostEqual(first, second, - delta=datetime.timedelta(seconds=5)) - - def testAssertNotRegexpMatches(self): - self.assertNotRegexpMatches('Ala ma kota', r'r+') - try: - self.assertNotRegexpMatches('Ala ma kota', r'k.t', 'Message') - except self.failureException, e: - self.assertIn("'kot'", e.args[0]) - self.assertIn('Message', e.args[0]) - else: - self.fail('assertNotRegexpMatches should have failed.') - - -class TestLongMessage(unittest2.TestCase): - """Test that the individual asserts honour longMessage. - This actually tests all the message behaviour for - asserts that use longMessage.""" - - def setUp(self): - class TestableTestFalse(unittest2.TestCase): - longMessage = False - failureException = self.failureException - - def testTest(self): - pass - - class TestableTestTrue(unittest2.TestCase): - longMessage = True - failureException = self.failureException - - def testTest(self): - pass - - self.testableTrue = TestableTestTrue('testTest') - self.testableFalse = TestableTestFalse('testTest') - - def testDefault(self): - self.assertTrue(unittest2.TestCase.longMessage) - - def test_formatMsg(self): - self.assertEquals(self.testableFalse._formatMessage(None, "foo"), "foo") - self.assertEquals(self.testableFalse._formatMessage("foo", "bar"), "foo") - - self.assertEquals(self.testableTrue._formatMessage(None, "foo"), "foo") - self.assertEquals(self.testableTrue._formatMessage("foo", "bar"), "bar : foo") - - # This blows up if _formatMessage uses string concatenation - self.testableTrue._formatMessage(object(), 'foo') - - def assertMessages(self, methodName, args, errors): - def getMethod(i): - useTestableFalse = i < 2 - if useTestableFalse: - test = self.testableFalse - else: - test = self.testableTrue - return getattr(test, methodName) - - for i, expected_regexp in enumerate(errors): - testMethod = getMethod(i) - kwargs = {} - withMsg = i % 2 - if withMsg: - kwargs = {"msg": "oops"} - - self.assertRaisesRegexp(self.failureException, - expected_regexp, - lambda: testMethod(*args, **kwargs)) - - def testAssertTrue(self): - self.assertMessages('assertTrue', (False,), - ["^False is not True$", "^oops$", "^False is not True$", - "^False is not True : oops$"]) - - def testAssertFalse(self): - self.assertMessages('assertFalse', (True,), - ["^True is not False$", "^oops$", "^True is not False$", - "^True is not False : oops$"]) - - def testNotEqual(self): - self.assertMessages('assertNotEqual', (1, 1), - ["^1 == 1$", "^oops$", "^1 == 1$", - "^1 == 1 : oops$"]) - - def testAlmostEqual(self): - self.assertMessages('assertAlmostEqual', (1, 2), - ["^1 != 2 within 7 places$", "^oops$", - "^1 != 2 within 7 places$", "^1 != 2 within 7 places : oops$"]) - - def testNotAlmostEqual(self): - self.assertMessages('assertNotAlmostEqual', (1, 1), - ["^1 == 1 within 7 places$", "^oops$", - "^1 == 1 within 7 places$", "^1 == 1 within 7 places : oops$"]) - - def test_baseAssertEqual(self): - self.assertMessages('_baseAssertEqual', (1, 2), - ["^1 != 2$", "^oops$", "^1 != 2$", "^1 != 2 : oops$"]) - - def testAssertSequenceEqual(self): - # Error messages are multiline so not testing on full message - # assertTupleEqual and assertListEqual delegate to this method - self.assertMessages('assertSequenceEqual', ([], [None]), - ["\+ \[None\]$", "^oops$", r"\+ \[None\]$", - r"\+ \[None\] : oops$"]) - - def testAssertSetEqual(self): - self.assertMessages('assertSetEqual', (set(), set([None])), - ["None$", "^oops$", "None$", - "None : oops$"]) - - def testAssertIn(self): - self.assertMessages('assertIn', (None, []), - ['^None not found in \[\]$', "^oops$", - '^None not found in \[\]$', - '^None not found in \[\] : oops$']) - - def testAssertNotIn(self): - self.assertMessages('assertNotIn', (None, [None]), - ['^None unexpectedly found in \[None\]$', "^oops$", - '^None unexpectedly found in \[None\]$', - '^None unexpectedly found in \[None\] : oops$']) - - def testAssertDictEqual(self): - self.assertMessages('assertDictEqual', ({}, {'key': 'value'}), - [r"\+ \{'key': 'value'\}$", "^oops$", - "\+ \{'key': 'value'\}$", - "\+ \{'key': 'value'\} : oops$"]) - - def testAssertDictContainsSubset(self): - self.assertMessages('assertDictContainsSubset', ({'key': 'value'}, {}), - ["^Missing: 'key'$", "^oops$", - "^Missing: 'key'$", - "^Missing: 'key' : oops$"]) - - def testAssertItemsEqual(self): - self.assertMessages('assertItemsEqual', ([], [None]), - [r"\[None\]$", "^oops$", - r"\[None\]$", - r"\[None\] : oops$"]) - - def testAssertMultiLineEqual(self): - self.assertMessages('assertMultiLineEqual', ("", "foo"), - [r"\+ foo$", "^oops$", - r"\+ foo$", - r"\+ foo : oops$"]) - - def testAssertLess(self): - self.assertMessages('assertLess', (2, 1), - ["^2 not less than 1$", "^oops$", - "^2 not less than 1$", "^2 not less than 1 : oops$"]) - - def testAssertLessEqual(self): - self.assertMessages('assertLessEqual', (2, 1), - ["^2 not less than or equal to 1$", "^oops$", - "^2 not less than or equal to 1$", - "^2 not less than or equal to 1 : oops$"]) - - def testAssertGreater(self): - self.assertMessages('assertGreater', (1, 2), - ["^1 not greater than 2$", "^oops$", - "^1 not greater than 2$", - "^1 not greater than 2 : oops$"]) - - def testAssertGreaterEqual(self): - self.assertMessages('assertGreaterEqual', (1, 2), - ["^1 not greater than or equal to 2$", "^oops$", - "^1 not greater than or equal to 2$", - "^1 not greater than or equal to 2 : oops$"]) - - def testAssertIsNone(self): - self.assertMessages('assertIsNone', ('not None',), - ["^'not None' is not None$", "^oops$", - "^'not None' is not None$", - "^'not None' is not None : oops$"]) - - def testAssertIsNotNone(self): - self.assertMessages('assertIsNotNone', (None,), - ["^unexpectedly None$", "^oops$", - "^unexpectedly None$", - "^unexpectedly None : oops$"]) - - def testAssertIs(self): - self.assertMessages('assertIs', (None, 'foo'), - ["^None is not 'foo'$", "^oops$", - "^None is not 'foo'$", - "^None is not 'foo' : oops$"]) - - def testAssertIsNot(self): - self.assertMessages('assertIsNot', (None, None), - ["^unexpectedly identical: None$", "^oops$", - "^unexpectedly identical: None$", - "^unexpectedly identical: None : oops$"]) - - -if __name__ == '__main__': - unittest2.main() diff --git a/PyInstaller/lib/unittest2/test/test_break.py b/PyInstaller/lib/unittest2/test/test_break.py deleted file mode 100644 index 0c5b5abda8..0000000000 --- a/PyInstaller/lib/unittest2/test/test_break.py +++ /dev/null @@ -1,260 +0,0 @@ -import gc -import os -import weakref - -from cStringIO import StringIO - -try: - import signal -except ImportError: - signal = None - -import unittest2 - - -class TestBreak(unittest2.TestCase): - - def setUp(self): - self._default_handler = signal.getsignal(signal.SIGINT) - - def tearDown(self): - signal.signal(signal.SIGINT, self._default_handler) - unittest2.signals._results = weakref.WeakKeyDictionary() - unittest2.signals._interrupt_handler = None - - - def testInstallHandler(self): - default_handler = signal.getsignal(signal.SIGINT) - unittest2.installHandler() - self.assertNotEqual(signal.getsignal(signal.SIGINT), default_handler) - - try: - pid = os.getpid() - os.kill(pid, signal.SIGINT) - except KeyboardInterrupt: - self.fail("KeyboardInterrupt not handled") - - self.assertTrue(unittest2.signals._interrupt_handler.called) - - def testRegisterResult(self): - result = unittest2.TestResult() - unittest2.registerResult(result) - - for ref in unittest2.signals._results: - if ref is result: - break - elif ref is not result: - self.fail("odd object in result set") - else: - self.fail("result not found") - - - def testInterruptCaught(self): - default_handler = signal.getsignal(signal.SIGINT) - - result = unittest2.TestResult() - unittest2.installHandler() - unittest2.registerResult(result) - - self.assertNotEqual(signal.getsignal(signal.SIGINT), default_handler) - - def test(result): - pid = os.getpid() - os.kill(pid, signal.SIGINT) - result.breakCaught = True - self.assertTrue(result.shouldStop) - - try: - test(result) - except KeyboardInterrupt: - self.fail("KeyboardInterrupt not handled") - self.assertTrue(result.breakCaught) - - - def testSecondInterrupt(self): - result = unittest2.TestResult() - unittest2.installHandler() - unittest2.registerResult(result) - - def test(result): - pid = os.getpid() - os.kill(pid, signal.SIGINT) - result.breakCaught = True - self.assertTrue(result.shouldStop) - os.kill(pid, signal.SIGINT) - self.fail("Second KeyboardInterrupt not raised") - - try: - test(result) - except KeyboardInterrupt: - pass - else: - self.fail("Second KeyboardInterrupt not raised") - self.assertTrue(result.breakCaught) - - - def testTwoResults(self): - unittest2.installHandler() - - result = unittest2.TestResult() - unittest2.registerResult(result) - new_handler = signal.getsignal(signal.SIGINT) - - result2 = unittest2.TestResult() - unittest2.registerResult(result2) - self.assertEqual(signal.getsignal(signal.SIGINT), new_handler) - - result3 = unittest2.TestResult() - - def test(result): - pid = os.getpid() - os.kill(pid, signal.SIGINT) - - try: - test(result) - except KeyboardInterrupt: - self.fail("KeyboardInterrupt not handled") - - self.assertTrue(result.shouldStop) - self.assertTrue(result2.shouldStop) - self.assertFalse(result3.shouldStop) - - - def testHandlerReplacedButCalled(self): - # If our handler has been replaced (is no longer installed) but is - # called by the *new* handler, then it isn't safe to delay the - # SIGINT and we should immediately delegate to the default handler - unittest2.installHandler() - - handler = signal.getsignal(signal.SIGINT) - def new_handler(frame, signum): - handler(frame, signum) - signal.signal(signal.SIGINT, new_handler) - - try: - pid = os.getpid() - os.kill(pid, signal.SIGINT) - except KeyboardInterrupt: - pass - else: - self.fail("replaced but delegated handler doesn't raise interrupt") - - def testRunner(self): - # Creating a TextTestRunner with the appropriate argument should - # register the TextTestResult it creates - runner = unittest2.TextTestRunner(stream=StringIO()) - - result = runner.run(unittest2.TestSuite()) - self.assertIn(result, unittest2.signals._results) - - def testWeakReferences(self): - # Calling registerResult on a result should not keep it alive - result = unittest2.TestResult() - unittest2.registerResult(result) - - ref = weakref.ref(result) - del result - - # For non-reference counting implementations - gc.collect();gc.collect() - self.assertIsNone(ref()) - - - def testRemoveResult(self): - result = unittest2.TestResult() - unittest2.registerResult(result) - - unittest2.installHandler() - self.assertTrue(unittest2.removeResult(result)) - - # Should this raise an error instead? - self.assertFalse(unittest2.removeResult(unittest2.TestResult())) - - try: - pid = os.getpid() - os.kill(pid, signal.SIGINT) - except KeyboardInterrupt: - pass - - self.assertFalse(result.shouldStop) - - def testMainInstallsHandler(self): - failfast = object() - test = object() - verbosity = object() - result = object() - default_handler = signal.getsignal(signal.SIGINT) - - class FakeRunner(object): - initArgs = [] - runArgs = [] - def __init__(self, *args, **kwargs): - self.initArgs.append((args, kwargs)) - def run(self, test): - self.runArgs.append(test) - return result - - class Program(unittest2.TestProgram): - def __init__(self, catchbreak): - self.exit = False - self.verbosity = verbosity - self.failfast = failfast - self.catchbreak = catchbreak - self.testRunner = FakeRunner - self.test = test - self.result = None - - p = Program(False) - p.runTests() - - self.assertEqual(FakeRunner.initArgs, [((), {'verbosity': verbosity, - 'failfast': failfast, - 'buffer': None})]) - self.assertEqual(FakeRunner.runArgs, [test]) - self.assertEqual(p.result, result) - - self.assertEqual(signal.getsignal(signal.SIGINT), default_handler) - - FakeRunner.initArgs = [] - FakeRunner.runArgs = [] - p = Program(True) - p.runTests() - - self.assertEqual(FakeRunner.initArgs, [((), {'verbosity': verbosity, - 'failfast': failfast, - 'buffer': None})]) - self.assertEqual(FakeRunner.runArgs, [test]) - self.assertEqual(p.result, result) - - self.assertNotEqual(signal.getsignal(signal.SIGINT), default_handler) - - - def testRemoveHandler(self): - default_handler = signal.getsignal(signal.SIGINT) - unittest2.installHandler() - unittest2.removeHandler() - self.assertEqual(signal.getsignal(signal.SIGINT), default_handler) - - # check that calling removeHandler multiple times has no ill-effect - unittest2.removeHandler() - self.assertEqual(signal.getsignal(signal.SIGINT), default_handler) - - def testRemoveHandlerAsDecorator(self): - default_handler = signal.getsignal(signal.SIGINT) - unittest2.installHandler() - - def test(): - self.assertEqual(signal.getsignal(signal.SIGINT), default_handler) - test = unittest2.removeHandler(test) - - test() - self.assertNotEqual(signal.getsignal(signal.SIGINT), default_handler) - - -# Should also skip some tests on Jython -skipper = unittest2.skipUnless(hasattr(os, 'kill') and signal is not None, - "test uses os.kill(...) and the signal module") -TestBreak = skipper(TestBreak) - -if __name__ == '__main__': - unittest2.main() diff --git a/PyInstaller/lib/unittest2/test/test_case.py b/PyInstaller/lib/unittest2/test/test_case.py deleted file mode 100644 index e68ce69889..0000000000 --- a/PyInstaller/lib/unittest2/test/test_case.py +++ /dev/null @@ -1,1070 +0,0 @@ -import difflib -import pprint -import re -import sys - -from copy import deepcopy - -import unittest2 - -from unittest2.test.support import\ - OldTestResult, EqualityMixin, HashingMixin, LoggingResult - -if sys.version_info[:2] == (2,3): - from sets import Set as set - from sets import ImmutableSet as frozenset - -class MyException(Exception): - pass - - -class Test(object): - "Keep these TestCase classes out of the main namespace" - - class Foo(unittest2.TestCase): - def runTest(self): pass - def test1(self): pass - - class Bar(Foo): - def test2(self): pass - - class LoggingTestCase(unittest2.TestCase): - """A test case which logs its calls.""" - - def __init__(self, events): - super(Test.LoggingTestCase, self).__init__('test') - self.events = events - - def setUp(self): - self.events.append('setUp') - - def test(self): - self.events.append('test') - - def tearDown(self): - self.events.append('tearDown') - - - -class TestCleanUp(unittest2.TestCase): - - def testCleanUp(self): - class TestableTest(unittest2.TestCase): - def testNothing(self): - pass - - test = TestableTest('testNothing') - self.assertEqual(test._cleanups, []) - - cleanups = [] - - def cleanup1(*args, **kwargs): - cleanups.append((1, args, kwargs)) - - def cleanup2(*args, **kwargs): - cleanups.append((2, args, kwargs)) - - test.addCleanup(cleanup1, 1, 2, 3, four='hello', five='goodbye') - test.addCleanup(cleanup2) - - self.assertEqual(test._cleanups, - [(cleanup1, (1, 2, 3), dict(four='hello', five='goodbye')), - (cleanup2, (), {})]) - - result = test.doCleanups() - self.assertTrue(result) - - self.assertEqual(cleanups, [(2, (), {}), (1, (1, 2, 3), dict(four='hello', five='goodbye'))]) - - def testCleanUpWithErrors(self): - class TestableTest(unittest2.TestCase): - def testNothing(self): - pass - - class MockResult(object): - errors = [] - def addError(self, test, exc_info): - self.errors.append((test, exc_info)) - - result = MockResult() - test = TestableTest('testNothing') - test._resultForDoCleanups = result - - exc1 = Exception('foo') - exc2 = Exception('bar') - def cleanup1(): - raise exc1 - - def cleanup2(): - raise exc2 - - test.addCleanup(cleanup1) - test.addCleanup(cleanup2) - - self.assertFalse(test.doCleanups()) - - errors = MockResult.errors[:] - errors.reverse() - (test1, (Type1, instance1, _)), (test2, (Type2, instance2, _)) = errors - self.assertEqual((test1, Type1, instance1), (test, Exception, exc1)) - self.assertEqual((test2, Type2, instance2), (test, Exception, exc2)) - - def testCleanupInRun(self): - blowUp = False - ordering = [] - - class TestableTest(unittest2.TestCase): - def setUp(self): - ordering.append('setUp') - if blowUp: - raise Exception('foo') - - def testNothing(self): - ordering.append('test') - - def tearDown(self): - ordering.append('tearDown') - - test = TestableTest('testNothing') - - def cleanup1(): - ordering.append('cleanup1') - def cleanup2(): - ordering.append('cleanup2') - test.addCleanup(cleanup1) - test.addCleanup(cleanup2) - - def success(some_test): - self.assertEqual(some_test, test) - ordering.append('success') - - result = unittest2.TestResult() - result.addSuccess = success - - test.run(result) - self.assertEqual(ordering, ['setUp', 'test', 'tearDown', - 'cleanup2', 'cleanup1', 'success']) - - blowUp = True - ordering = [] - test = TestableTest('testNothing') - test.addCleanup(cleanup1) - test.run(result) - self.assertEqual(ordering, ['setUp', 'cleanup1']) - - def testTestCaseDebugExecutesCleanups(self): - ordering = [] - - class TestableTest(unittest2.TestCase): - def setUp(self): - ordering.append('setUp') - self.addCleanup(cleanup1) - - def testNothing(self): - ordering.append('test') - - def tearDown(self): - ordering.append('tearDown') - - test = TestableTest('testNothing') - - def cleanup1(): - ordering.append('cleanup1') - test.addCleanup(cleanup2) - def cleanup2(): - ordering.append('cleanup2') - - test.debug() - self.assertEqual(ordering, ['setUp', 'test', 'tearDown', 'cleanup1', 'cleanup2']) - - -class Test_TestCase(unittest2.TestCase, EqualityMixin, HashingMixin): - - ### Set up attributes used by inherited tests - ################################################################ - - # Used by HashingMixin.test_hash and EqualityMixin.test_eq - eq_pairs = [(Test.Foo('test1'), Test.Foo('test1'))] - - # Used by EqualityMixin.test_ne - ne_pairs = [(Test.Foo('test1'), Test.Foo('runTest')), - (Test.Foo('test1'), Test.Bar('test1')), - (Test.Foo('test1'), Test.Bar('test2'))] - - ################################################################ - ### /Set up attributes used by inherited tests - - - # "class TestCase([methodName])" - # ... - # "Each instance of TestCase will run a single test method: the - # method named methodName." - # ... - # "methodName defaults to "runTest"." - # - # Make sure it really is optional, and that it defaults to the proper - # thing. - def test_init__no_test_name(self): - class Test(unittest2.TestCase): - def runTest(self): raise MyException() - def test(self): pass - - self.assertEqual(Test().id()[-13:], '.Test.runTest') - - # "class TestCase([methodName])" - # ... - # "Each instance of TestCase will run a single test method: the - # method named methodName." - def test_init__test_name__valid(self): - class Test(unittest2.TestCase): - def runTest(self): raise MyException() - def test(self): pass - - self.assertEqual(Test('test').id()[-10:], '.Test.test') - - # "class unittest2.TestCase([methodName])" - # ... - # "Each instance of TestCase will run a single test method: the - # method named methodName." - def test_init__test_name__invalid(self): - class Test(unittest2.TestCase): - def runTest(self): raise MyException() - def test(self): pass - - try: - Test('testfoo') - except ValueError: - pass - else: - self.fail("Failed to raise ValueError") - - # "Return the number of tests represented by the this test object. For - # TestCase instances, this will always be 1" - def test_countTestCases(self): - class Foo(unittest2.TestCase): - def test(self): pass - - self.assertEqual(Foo('test').countTestCases(), 1) - - # "Return the default type of test result object to be used to run this - # test. For TestCase instances, this will always be - # unittest2.TestResult; subclasses of TestCase should - # override this as necessary." - def test_defaultTestResult(self): - class Foo(unittest2.TestCase): - def runTest(self): - pass - - result = Foo().defaultTestResult() - self.assertEqual(type(result), unittest2.TestResult) - - # "When a setUp() method is defined, the test runner will run that method - # prior to each test. Likewise, if a tearDown() method is defined, the - # test runner will invoke that method after each test. In the example, - # setUp() was used to create a fresh sequence for each test." - # - # Make sure the proper call order is maintained, even if setUp() raises - # an exception. - def test_run_call_order__error_in_setUp(self): - events = [] - result = LoggingResult(events) - - class Foo(Test.LoggingTestCase): - def setUp(self): - super(Foo, self).setUp() - raise RuntimeError('raised by Foo.setUp') - - Foo(events).run(result) - expected = ['startTest', 'setUp', 'addError', 'stopTest'] - self.assertEqual(events, expected) - - # "With a temporary result stopTestRun is called when setUp errors. - def test_run_call_order__error_in_setUp_default_result(self): - events = [] - - class Foo(Test.LoggingTestCase): - def defaultTestResult(self): - return LoggingResult(self.events) - - def setUp(self): - super(Foo, self).setUp() - raise RuntimeError('raised by Foo.setUp') - - Foo(events).run() - expected = ['startTestRun', 'startTest', 'setUp', 'addError', - 'stopTest', 'stopTestRun'] - self.assertEqual(events, expected) - - # "When a setUp() method is defined, the test runner will run that method - # prior to each test. Likewise, if a tearDown() method is defined, the - # test runner will invoke that method after each test. In the example, - # setUp() was used to create a fresh sequence for each test." - # - # Make sure the proper call order is maintained, even if the test raises - # an error (as opposed to a failure). - def test_run_call_order__error_in_test(self): - events = [] - result = LoggingResult(events) - - class Foo(Test.LoggingTestCase): - def test(self): - super(Foo, self).test() - raise RuntimeError('raised by Foo.test') - - expected = ['startTest', 'setUp', 'test', 'addError', 'tearDown', - 'stopTest'] - Foo(events).run(result) - self.assertEqual(events, expected) - - # "With a default result, an error in the test still results in stopTestRun - # being called." - def test_run_call_order__error_in_test_default_result(self): - events = [] - - class Foo(Test.LoggingTestCase): - def defaultTestResult(self): - return LoggingResult(self.events) - - def test(self): - super(Foo, self).test() - raise RuntimeError('raised by Foo.test') - - expected = ['startTestRun', 'startTest', 'setUp', 'test', 'addError', - 'tearDown', 'stopTest', 'stopTestRun'] - Foo(events).run() - self.assertEqual(events, expected) - - # "When a setUp() method is defined, the test runner will run that method - # prior to each test. Likewise, if a tearDown() method is defined, the - # test runner will invoke that method after each test. In the example, - # setUp() was used to create a fresh sequence for each test." - # - # Make sure the proper call order is maintained, even if the test signals - # a failure (as opposed to an error). - def test_run_call_order__failure_in_test(self): - events = [] - result = LoggingResult(events) - - class Foo(Test.LoggingTestCase): - def test(self): - super(Foo, self).test() - self.fail('raised by Foo.test') - - expected = ['startTest', 'setUp', 'test', 'addFailure', 'tearDown', - 'stopTest'] - Foo(events).run(result) - self.assertEqual(events, expected) - - # "When a test fails with a default result stopTestRun is still called." - def test_run_call_order__failure_in_test_default_result(self): - - class Foo(Test.LoggingTestCase): - def defaultTestResult(self): - return LoggingResult(self.events) - def test(self): - super(Foo, self).test() - self.fail('raised by Foo.test') - - expected = ['startTestRun', 'startTest', 'setUp', 'test', 'addFailure', - 'tearDown', 'stopTest', 'stopTestRun'] - events = [] - Foo(events).run() - self.assertEqual(events, expected) - - # "When a setUp() method is defined, the test runner will run that method - # prior to each test. Likewise, if a tearDown() method is defined, the - # test runner will invoke that method after each test. In the example, - # setUp() was used to create a fresh sequence for each test." - # - # Make sure the proper call order is maintained, even if tearDown() raises - # an exception. - def test_run_call_order__error_in_tearDown(self): - events = [] - result = LoggingResult(events) - - class Foo(Test.LoggingTestCase): - def tearDown(self): - super(Foo, self).tearDown() - raise RuntimeError('raised by Foo.tearDown') - - Foo(events).run(result) - expected = ['startTest', 'setUp', 'test', 'tearDown', 'addError', - 'stopTest'] - self.assertEqual(events, expected) - - # "When tearDown errors with a default result stopTestRun is still called." - def test_run_call_order__error_in_tearDown_default_result(self): - - class Foo(Test.LoggingTestCase): - def defaultTestResult(self): - return LoggingResult(self.events) - def tearDown(self): - super(Foo, self).tearDown() - raise RuntimeError('raised by Foo.tearDown') - - events = [] - Foo(events).run() - expected = ['startTestRun', 'startTest', 'setUp', 'test', 'tearDown', - 'addError', 'stopTest', 'stopTestRun'] - self.assertEqual(events, expected) - - # "TestCase.run() still works when the defaultTestResult is a TestResult - # that does not support startTestRun and stopTestRun. - def test_run_call_order_default_result(self): - - class Foo(unittest2.TestCase): - def defaultTestResult(self): - return OldTestResult() - def test(self): - pass - - Foo('test').run() - - # "This class attribute gives the exception raised by the test() method. - # If a test framework needs to use a specialized exception, possibly to - # carry additional information, it must subclass this exception in - # order to ``play fair'' with the framework. The initial value of this - # attribute is AssertionError" - def test_failureException__default(self): - class Foo(unittest2.TestCase): - def test(self): - pass - - self.assertTrue(Foo('test').failureException is AssertionError) - - # "This class attribute gives the exception raised by the test() method. - # If a test framework needs to use a specialized exception, possibly to - # carry additional information, it must subclass this exception in - # order to ``play fair'' with the framework." - # - # Make sure TestCase.run() respects the designated failureException - def test_failureException__subclassing__explicit_raise(self): - events = [] - result = LoggingResult(events) - - class Foo(unittest2.TestCase): - def test(self): - raise RuntimeError() - - failureException = RuntimeError - - self.assertTrue(Foo('test').failureException is RuntimeError) - - - Foo('test').run(result) - expected = ['startTest', 'addFailure', 'stopTest'] - self.assertEqual(events, expected) - - # "This class attribute gives the exception raised by the test() method. - # If a test framework needs to use a specialized exception, possibly to - # carry additional information, it must subclass this exception in - # order to ``play fair'' with the framework." - # - # Make sure TestCase.run() respects the designated failureException - def test_failureException__subclassing__implicit_raise(self): - events = [] - result = LoggingResult(events) - - class Foo(unittest2.TestCase): - def test(self): - self.fail("foo") - - failureException = RuntimeError - - self.assertTrue(Foo('test').failureException is RuntimeError) - - - Foo('test').run(result) - expected = ['startTest', 'addFailure', 'stopTest'] - self.assertEqual(events, expected) - - # "The default implementation does nothing." - def test_setUp(self): - class Foo(unittest2.TestCase): - def runTest(self): - pass - - # ... and nothing should happen - Foo().setUp() - - # "The default implementation does nothing." - def test_tearDown(self): - class Foo(unittest2.TestCase): - def runTest(self): - pass - - # ... and nothing should happen - Foo().tearDown() - - # "Return a string identifying the specific test case." - # - # Because of the vague nature of the docs, I'm not going to lock this - # test down too much. Really all that can be asserted is that the id() - # will be a string (either 8-byte or unicode -- again, because the docs - # just say "string") - def test_id(self): - class Foo(unittest2.TestCase): - def runTest(self): - pass - - self.assertIsInstance(Foo().id(), basestring) - - # "If result is omitted or None, a temporary result object is created - # and used, but is not made available to the caller. As TestCase owns the - # temporary result startTestRun and stopTestRun are called. - - def test_run__uses_defaultTestResult(self): - events = [] - - class Foo(unittest2.TestCase): - def test(self): - events.append('test') - - def defaultTestResult(self): - return LoggingResult(events) - - # Make run() find a result object on its own - Foo('test').run() - - expected = ['startTestRun', 'startTest', 'test', 'addSuccess', - 'stopTest', 'stopTestRun'] - self.assertEqual(events, expected) - - def testShortDescriptionWithoutDocstring(self): - self.assertIsNone(self.shortDescription()) - - def testShortDescriptionWithOneLineDocstring(self): - """Tests shortDescription() for a method with a docstring.""" - self.assertEqual( - self.shortDescription(), - 'Tests shortDescription() for a method with a docstring.') - - def testShortDescriptionWithMultiLineDocstring(self): - """Tests shortDescription() for a method with a longer docstring. - - This method ensures that only the first line of a docstring is - returned used in the short description, no matter how long the - whole thing is. - """ - self.assertEqual( - self.shortDescription(), - 'Tests shortDescription() for a method with a longer ' - 'docstring.') - - def testAddTypeEqualityFunc(self): - class SadSnake(object): - """Dummy class for test_addTypeEqualityFunc.""" - s1, s2 = SadSnake(), SadSnake() - self.assertNotEqual(s1, s2) - def AllSnakesCreatedEqual(a, b, msg=None): - return type(a) is type(b) is SadSnake - self.addTypeEqualityFunc(SadSnake, AllSnakesCreatedEqual) - self.assertEqual(s1, s2) - # No this doesn't clean up and remove the SadSnake equality func - # from this TestCase instance but since its a local nothing else - # will ever notice that. - - def testAssertIs(self): - thing = object() - self.assertIs(thing, thing) - self.assertRaises(self.failureException, self.assertIs, thing, object()) - - def testAssertIsNot(self): - thing = object() - self.assertIsNot(thing, object()) - self.assertRaises(self.failureException, self.assertIsNot, thing, thing) - - def testAssertIsInstance(self): - thing = [] - self.assertIsInstance(thing, list) - self.assertRaises(self.failureException, self.assertIsInstance, - thing, dict) - - def testAssertNotIsInstance(self): - thing = [] - self.assertNotIsInstance(thing, dict) - self.assertRaises(self.failureException, self.assertNotIsInstance, - thing, list) - - def testAssertIn(self): - animals = {'monkey': 'banana', 'cow': 'grass', 'seal': 'fish'} - - self.assertIn('a', 'abc') - self.assertIn(2, [1, 2, 3]) - self.assertIn('monkey', animals) - - self.assertNotIn('d', 'abc') - self.assertNotIn(0, [1, 2, 3]) - self.assertNotIn('otter', animals) - - self.assertRaises(self.failureException, self.assertIn, 'x', 'abc') - self.assertRaises(self.failureException, self.assertIn, 4, [1, 2, 3]) - self.assertRaises(self.failureException, self.assertIn, 'elephant', - animals) - - self.assertRaises(self.failureException, self.assertNotIn, 'c', 'abc') - self.assertRaises(self.failureException, self.assertNotIn, 1, [1, 2, 3]) - self.assertRaises(self.failureException, self.assertNotIn, 'cow', - animals) - - def testAssertDictContainsSubset(self): - self.assertDictContainsSubset({}, {}) - self.assertDictContainsSubset({}, {'a': 1}) - self.assertDictContainsSubset({'a': 1}, {'a': 1}) - self.assertDictContainsSubset({'a': 1}, {'a': 1, 'b': 2}) - self.assertDictContainsSubset({'a': 1, 'b': 2}, {'a': 1, 'b': 2}) - - self.assertRaises(unittest2.TestCase.failureException, - self.assertDictContainsSubset, {'a': 2}, {'a': 1}, - '.*Mismatched values:.*') - - self.assertRaises(unittest2.TestCase.failureException, - self.assertDictContainsSubset, {'c': 1}, {'a': 1}, - '.*Missing:.*') - - self.assertRaises(unittest2.TestCase.failureException, - self.assertDictContainsSubset, {'a': 1, 'c': 1}, - {'a': 1}, '.*Missing:.*') - - self.assertRaises(unittest2.TestCase.failureException, - self.assertDictContainsSubset, {'a': 1, 'c': 1}, - {'a': 1}, '.*Missing:.*Mismatched values:.*') - - self.assertRaises(self.failureException, - self.assertDictContainsSubset, {1: "one"}, {}) - - def testAssertEqual(self): - equal_pairs = [ - ((), ()), - ({}, {}), - ([], []), - (set(), set()), - (frozenset(), frozenset())] - for a, b in equal_pairs: - # This mess of try excepts is to test the assertEqual behavior - # itself. - try: - self.assertEqual(a, b) - except self.failureException: - self.fail('assertEqual(%r, %r) failed' % (a, b)) - try: - self.assertEqual(a, b, msg='foo') - except self.failureException: - self.fail('assertEqual(%r, %r) with msg= failed' % (a, b)) - try: - self.assertEqual(a, b, 'foo') - except self.failureException: - self.fail('assertEqual(%r, %r) with third parameter failed' % - (a, b)) - - unequal_pairs = [ - ((), []), - ({}, set()), - (set([4,1]), frozenset([4,2])), - (frozenset([4,5]), set([2,3])), - (set([3,4]), set([5,4]))] - for a, b in unequal_pairs: - self.assertRaises(self.failureException, self.assertEqual, a, b) - self.assertRaises(self.failureException, self.assertEqual, a, b, - 'foo') - self.assertRaises(self.failureException, self.assertEqual, a, b, - msg='foo') - - def testEquality(self): - self.assertListEqual([], []) - self.assertTupleEqual((), ()) - self.assertSequenceEqual([], ()) - - a = [0, 'a', []] - b = [] - self.assertRaises(unittest2.TestCase.failureException, - self.assertListEqual, a, b) - self.assertRaises(unittest2.TestCase.failureException, - self.assertListEqual, tuple(a), tuple(b)) - self.assertRaises(unittest2.TestCase.failureException, - self.assertSequenceEqual, a, tuple(b)) - - b.extend(a) - self.assertListEqual(a, b) - self.assertTupleEqual(tuple(a), tuple(b)) - self.assertSequenceEqual(a, tuple(b)) - self.assertSequenceEqual(tuple(a), b) - - self.assertRaises(self.failureException, self.assertListEqual, - a, tuple(b)) - self.assertRaises(self.failureException, self.assertTupleEqual, - tuple(a), b) - self.assertRaises(self.failureException, self.assertListEqual, None, b) - self.assertRaises(self.failureException, self.assertTupleEqual, None, - tuple(b)) - self.assertRaises(self.failureException, self.assertSequenceEqual, - None, tuple(b)) - self.assertRaises(self.failureException, self.assertListEqual, 1, 1) - self.assertRaises(self.failureException, self.assertTupleEqual, 1, 1) - self.assertRaises(self.failureException, self.assertSequenceEqual, - 1, 1) - - self.assertDictEqual({}, {}) - - c = { 'x': 1 } - d = {} - self.assertRaises(unittest2.TestCase.failureException, - self.assertDictEqual, c, d) - - d.update(c) - self.assertDictEqual(c, d) - - d['x'] = 0 - self.assertRaises(unittest2.TestCase.failureException, - self.assertDictEqual, c, d, 'These are unequal') - - self.assertRaises(self.failureException, self.assertDictEqual, None, d) - self.assertRaises(self.failureException, self.assertDictEqual, [], d) - self.assertRaises(self.failureException, self.assertDictEqual, 1, 1) - - def testAssertItemsEqual(self): - self.assertItemsEqual([1, 2, 3], [3, 2, 1]) - self.assertItemsEqual(['foo', 'bar', 'baz'], ['bar', 'baz', 'foo']) - self.assertRaises(self.failureException, self.assertItemsEqual, - [10], [10, 11]) - self.assertRaises(self.failureException, self.assertItemsEqual, - [10, 11], [10]) - self.assertRaises(self.failureException, self.assertItemsEqual, - [10, 11, 10], [10, 11]) - - # Test that sequences of unhashable objects can be tested for sameness: - self.assertItemsEqual([[1, 2], [3, 4]], [[3, 4], [1, 2]]) - - self.assertItemsEqual([{'a': 1}, {'b': 2}], [{'b': 2}, {'a': 1}]) - self.assertRaises(self.failureException, self.assertItemsEqual, - [[1]], [[2]]) - - # Test unsortable objects - self.assertItemsEqual([2j, None], [None, 2j]) - self.assertRaises(self.failureException, self.assertItemsEqual, - [2j, None], [None, 3j]) - - def testAssertSetEqual(self): - set1 = set() - set2 = set() - self.assertSetEqual(set1, set2) - - self.assertRaises(self.failureException, self.assertSetEqual, None, set2) - self.assertRaises(self.failureException, self.assertSetEqual, [], set2) - self.assertRaises(self.failureException, self.assertSetEqual, set1, None) - self.assertRaises(self.failureException, self.assertSetEqual, set1, []) - - set1 = set(['a']) - set2 = set() - self.assertRaises(self.failureException, self.assertSetEqual, set1, set2) - - set1 = set(['a']) - set2 = set(['a']) - self.assertSetEqual(set1, set2) - - set1 = set(['a']) - set2 = set(['a', 'b']) - self.assertRaises(self.failureException, self.assertSetEqual, set1, set2) - - set1 = set(['a']) - set2 = frozenset(['a', 'b']) - self.assertRaises(self.failureException, self.assertSetEqual, set1, set2) - - set1 = set(['a', 'b']) - set2 = frozenset(['a', 'b']) - self.assertSetEqual(set1, set2) - - set1 = set() - set2 = "foo" - self.assertRaises(self.failureException, self.assertSetEqual, set1, set2) - self.assertRaises(self.failureException, self.assertSetEqual, set2, set1) - - # make sure any string formatting is tuple-safe - set1 = set([(0, 1), (2, 3)]) - set2 = set([(4, 5)]) - self.assertRaises(self.failureException, self.assertSetEqual, set1, set2) - - def testInequality(self): - # Try ints - self.assertGreater(2, 1) - self.assertGreaterEqual(2, 1) - self.assertGreaterEqual(1, 1) - self.assertLess(1, 2) - self.assertLessEqual(1, 2) - self.assertLessEqual(1, 1) - self.assertRaises(self.failureException, self.assertGreater, 1, 2) - self.assertRaises(self.failureException, self.assertGreater, 1, 1) - self.assertRaises(self.failureException, self.assertGreaterEqual, 1, 2) - self.assertRaises(self.failureException, self.assertLess, 2, 1) - self.assertRaises(self.failureException, self.assertLess, 1, 1) - self.assertRaises(self.failureException, self.assertLessEqual, 2, 1) - - # Try Floats - self.assertGreater(1.1, 1.0) - self.assertGreaterEqual(1.1, 1.0) - self.assertGreaterEqual(1.0, 1.0) - self.assertLess(1.0, 1.1) - self.assertLessEqual(1.0, 1.1) - self.assertLessEqual(1.0, 1.0) - self.assertRaises(self.failureException, self.assertGreater, 1.0, 1.1) - self.assertRaises(self.failureException, self.assertGreater, 1.0, 1.0) - self.assertRaises(self.failureException, self.assertGreaterEqual, 1.0, 1.1) - self.assertRaises(self.failureException, self.assertLess, 1.1, 1.0) - self.assertRaises(self.failureException, self.assertLess, 1.0, 1.0) - self.assertRaises(self.failureException, self.assertLessEqual, 1.1, 1.0) - - # Try Strings - self.assertGreater('bug', 'ant') - self.assertGreaterEqual('bug', 'ant') - self.assertGreaterEqual('ant', 'ant') - self.assertLess('ant', 'bug') - self.assertLessEqual('ant', 'bug') - self.assertLessEqual('ant', 'ant') - self.assertRaises(self.failureException, self.assertGreater, 'ant', 'bug') - self.assertRaises(self.failureException, self.assertGreater, 'ant', 'ant') - self.assertRaises(self.failureException, self.assertGreaterEqual, 'ant', 'bug') - self.assertRaises(self.failureException, self.assertLess, 'bug', 'ant') - self.assertRaises(self.failureException, self.assertLess, 'ant', 'ant') - self.assertRaises(self.failureException, self.assertLessEqual, 'bug', 'ant') - - # Try Unicode - self.assertGreater(u'bug', u'ant') - self.assertGreaterEqual(u'bug', u'ant') - self.assertGreaterEqual(u'ant', u'ant') - self.assertLess(u'ant', u'bug') - self.assertLessEqual(u'ant', u'bug') - self.assertLessEqual(u'ant', u'ant') - self.assertRaises(self.failureException, self.assertGreater, u'ant', u'bug') - self.assertRaises(self.failureException, self.assertGreater, u'ant', u'ant') - self.assertRaises(self.failureException, self.assertGreaterEqual, u'ant', - u'bug') - self.assertRaises(self.failureException, self.assertLess, u'bug', u'ant') - self.assertRaises(self.failureException, self.assertLess, u'ant', u'ant') - self.assertRaises(self.failureException, self.assertLessEqual, u'bug', u'ant') - - # Try Mixed String/Unicode - self.assertGreater('bug', u'ant') - self.assertGreater(u'bug', 'ant') - self.assertGreaterEqual('bug', u'ant') - self.assertGreaterEqual(u'bug', 'ant') - self.assertGreaterEqual('ant', u'ant') - self.assertGreaterEqual(u'ant', 'ant') - self.assertLess('ant', u'bug') - self.assertLess(u'ant', 'bug') - self.assertLessEqual('ant', u'bug') - self.assertLessEqual(u'ant', 'bug') - self.assertLessEqual('ant', u'ant') - self.assertLessEqual(u'ant', 'ant') - self.assertRaises(self.failureException, self.assertGreater, 'ant', u'bug') - self.assertRaises(self.failureException, self.assertGreater, u'ant', 'bug') - self.assertRaises(self.failureException, self.assertGreater, 'ant', u'ant') - self.assertRaises(self.failureException, self.assertGreater, u'ant', 'ant') - self.assertRaises(self.failureException, self.assertGreaterEqual, 'ant', - u'bug') - self.assertRaises(self.failureException, self.assertGreaterEqual, u'ant', - 'bug') - self.assertRaises(self.failureException, self.assertLess, 'bug', u'ant') - self.assertRaises(self.failureException, self.assertLess, u'bug', 'ant') - self.assertRaises(self.failureException, self.assertLess, 'ant', u'ant') - self.assertRaises(self.failureException, self.assertLess, u'ant', 'ant') - self.assertRaises(self.failureException, self.assertLessEqual, 'bug', u'ant') - self.assertRaises(self.failureException, self.assertLessEqual, u'bug', 'ant') - - def testAssertMultiLineEqual(self): - sample_text = """\ -http://www.python.org/doc/2.3/lib/module-unittest.html -test case - A test case is the smallest unit of testing. [...] -""" - revised_sample_text = """\ -http://www.python.org/doc/2.4.1/lib/module-unittest.html -test case - A test case is the smallest unit of testing. [...] You may provide your - own implementation that does not subclass from TestCase, of course. -""" - sample_text_error = """\ -- http://www.python.org/doc/2.3/lib/module-unittest.html -? ^ -+ http://www.python.org/doc/2.4.1/lib/module-unittest.html -? ^^^ - test case -- A test case is the smallest unit of testing. [...] -+ A test case is the smallest unit of testing. [...] You may provide your -? +++++++++++++++++++++ -+ own implementation that does not subclass from TestCase, of course. -""" - self.maxDiff = None - for type_changer in (lambda x: x, lambda x: x.decode('utf8')): - try: - self.assertMultiLineEqual(type_changer(sample_text), - type_changer(revised_sample_text)) - except self.failureException, e: - # need to remove the first line of the error message - error = str(e).encode('utf8').split('\n', 1)[1] - - # assertMultiLineEqual is hooked up as the default for - # unicode strings - so we can't use it for this check - self.assertTrue(sample_text_error == error) - - def testAssertSequenceEqualMaxDiff(self): - self.assertEqual(self.maxDiff, 80*8) - seq1 = 'a' + 'x' * 80**2 - seq2 = 'b' + 'x' * 80**2 - diff = '\n'.join(difflib.ndiff(pprint.pformat(seq1).splitlines(), - pprint.pformat(seq2).splitlines())) - # the +1 is the leading \n added by assertSequenceEqual - omitted = unittest2.case.DIFF_OMITTED % (len(diff) + 1,) - - self.maxDiff = len(diff)//2 - try: - self.assertSequenceEqual(seq1, seq2) - except self.failureException, e: - msg = e.args[0] - else: - self.fail('assertSequenceEqual did not fail.') - self.assertTrue(len(msg) < len(diff)) - self.assertIn(omitted, msg) - - self.maxDiff = len(diff) * 2 - try: - self.assertSequenceEqual(seq1, seq2) - except self.failureException, e: - msg = e.args[0] - else: - self.fail('assertSequenceEqual did not fail.') - self.assertTrue(len(msg) > len(diff)) - self.assertNotIn(omitted, msg) - - self.maxDiff = None - try: - self.assertSequenceEqual(seq1, seq2) - except self.failureException, e: - msg = e.args[0] - else: - self.fail('assertSequenceEqual did not fail.') - self.assertTrue(len(msg) > len(diff)) - self.assertNotIn(omitted, msg) - - def testTruncateMessage(self): - self.maxDiff = 1 - message = self._truncateMessage('foo', 'bar') - omitted = unittest2.case.DIFF_OMITTED % len('bar') - self.assertEqual(message, 'foo' + omitted) - - self.maxDiff = None - message = self._truncateMessage('foo', 'bar') - self.assertEqual(message, 'foobar') - - self.maxDiff = 4 - message = self._truncateMessage('foo', 'bar') - self.assertEqual(message, 'foobar') - - def testAssertDictEqualTruncates(self): - test = unittest2.TestCase('assertEqual') - def truncate(msg, diff): - return 'foo' - test._truncateMessage = truncate - try: - test.assertDictEqual({}, {1: 0}) - except self.failureException, e: - self.assertEqual(str(e), 'foo') - else: - self.fail('assertDictEqual did not fail') - - def testAssertMultiLineEqualTruncates(self): - test = unittest2.TestCase('assertEqual') - def truncate(msg, diff): - return 'foo' - test._truncateMessage = truncate - try: - test.assertMultiLineEqual('foo', 'bar') - except self.failureException, e: - self.assertEqual(str(e), 'foo') - else: - self.fail('assertMultiLineEqual did not fail') - - def testAssertIsNone(self): - self.assertIsNone(None) - self.assertRaises(self.failureException, self.assertIsNone, False) - self.assertIsNotNone('DjZoPloGears on Rails') - self.assertRaises(self.failureException, self.assertIsNotNone, None) - - def testAssertRegexpMatches(self): - self.assertRegexpMatches('asdfabasdf', r'ab+') - self.assertRaises(self.failureException, self.assertRegexpMatches, - 'saaas', r'aaaa') - - def testAssertRaisesRegexp(self): - class ExceptionMock(Exception): - pass - - def Stub(): - raise ExceptionMock('We expect') - - self.assertRaisesRegexp(ExceptionMock, re.compile('expect$'), Stub) - self.assertRaisesRegexp(ExceptionMock, 'expect$', Stub) - self.assertRaisesRegexp(ExceptionMock, u'expect$', Stub) - - def testAssertNotRaisesRegexp(self): - self.assertRaisesRegexp( - self.failureException, '^Exception not raised$', - self.assertRaisesRegexp, Exception, re.compile('x'), - lambda: None) - self.assertRaisesRegexp( - self.failureException, '^Exception not raised$', - self.assertRaisesRegexp, Exception, 'x', - lambda: None) - self.assertRaisesRegexp( - self.failureException, '^Exception not raised$', - self.assertRaisesRegexp, Exception, u'x', - lambda: None) - - def testAssertRaisesRegexpMismatch(self): - def Stub(): - raise Exception('Unexpected') - - self.assertRaisesRegexp( - self.failureException, - r'"\^Expected\$" does not match "Unexpected"', - self.assertRaisesRegexp, Exception, '^Expected$', - Stub) - self.assertRaisesRegexp( - self.failureException, - r'"\^Expected\$" does not match "Unexpected"', - self.assertRaisesRegexp, Exception, u'^Expected$', - Stub) - self.assertRaisesRegexp( - self.failureException, - r'"\^Expected\$" does not match "Unexpected"', - self.assertRaisesRegexp, Exception, - re.compile('^Expected$'), Stub) - - - def testSynonymAssertMethodNames(self): - """Test undocumented method name synonyms. - - Please do not use these methods names in your own code. - - This test confirms their continued existence and functionality - in order to avoid breaking existing code. - """ - self.assertNotEquals(3, 5) - self.assertEquals(3, 3) - self.assertAlmostEquals(2.0, 2.0) - self.assertNotAlmostEquals(3.0, 5.0) - self.assert_(True) - - def testDeepcopy(self): - # Issue: 5660 - class TestableTest(unittest2.TestCase): - def testNothing(self): - pass - - test = TestableTest('testNothing') - - # This shouldn't blow up - deepcopy(test) - - -if __name__ == "__main__": - unittest2.main() diff --git a/PyInstaller/lib/unittest2/test/test_discovery.py b/PyInstaller/lib/unittest2/test/test_discovery.py deleted file mode 100644 index 2cd265b529..0000000000 --- a/PyInstaller/lib/unittest2/test/test_discovery.py +++ /dev/null @@ -1,372 +0,0 @@ -import os -import re -import sys - -import unittest2 - - -class TestDiscovery(unittest2.TestCase): - - # Heavily mocked tests so I can avoid hitting the filesystem - def test_get_name_from_path(self): - loader = unittest2.TestLoader() - - loader._top_level_dir = '/foo' - name = loader._get_name_from_path('/foo/bar/baz.py') - self.assertEqual(name, 'bar.baz') - - if not __debug__: - # asserts are off - return - - self.assertRaises(AssertionError, - loader._get_name_from_path, - '/bar/baz.py') - - def test_find_tests(self): - loader = unittest2.TestLoader() - - original_listdir = os.listdir - def restore_listdir(): - os.listdir = original_listdir - original_isfile = os.path.isfile - def restore_isfile(): - os.path.isfile = original_isfile - original_isdir = os.path.isdir - def restore_isdir(): - os.path.isdir = original_isdir - - path_lists = [['test1.py', 'test2.py', 'not_a_test.py', 'test_dir', - 'test.foo', 'test-not-a-module.py', 'another_dir'], - ['test3.py', 'test4.py', ]] - os.listdir = lambda path: path_lists.pop(0) - self.addCleanup(restore_listdir) - - def isdir(path): - return path.endswith('dir') - os.path.isdir = isdir - self.addCleanup(restore_isdir) - - def isfile(path): - # another_dir is not a package and so shouldn't be recursed into - return not path.endswith('dir') and not 'another_dir' in path - os.path.isfile = isfile - self.addCleanup(restore_isfile) - - loader._get_module_from_name = lambda path: path + ' module' - loader.loadTestsFromModule = lambda module: module + ' tests' - - top_level = os.path.abspath('/foo') - loader._top_level_dir = top_level - suite = list(loader._find_tests(top_level, 'test*.py')) - - expected = [name + ' module tests' for name in - ('test1', 'test2')] - expected.extend([('test_dir.%s' % name) + ' module tests' for name in - ('test3', 'test4')]) - self.assertEqual(suite, expected) - - def test_find_tests_with_package(self): - loader = unittest2.TestLoader() - - original_listdir = os.listdir - def restore_listdir(): - os.listdir = original_listdir - original_isfile = os.path.isfile - def restore_isfile(): - os.path.isfile = original_isfile - original_isdir = os.path.isdir - def restore_isdir(): - os.path.isdir = original_isdir - - directories = ['a_directory', 'test_directory', 'test_directory2'] - path_lists = [directories, [], [], []] - os.listdir = lambda path: path_lists.pop(0) - self.addCleanup(restore_listdir) - - os.path.isdir = lambda path: True - self.addCleanup(restore_isdir) - - os.path.isfile = lambda path: os.path.basename(path) not in directories - self.addCleanup(restore_isfile) - - class Module(object): - paths = [] - load_tests_args = [] - - def __init__(self, path): - self.path = path - self.paths.append(path) - if os.path.basename(path) == 'test_directory': - def load_tests(loader, tests, pattern): - self.load_tests_args.append((loader, tests, pattern)) - return 'load_tests' - self.load_tests = load_tests - - def __eq__(self, other): - return self.path == other.path - - # Silence py3k warning - __hash__ = None - - loader._get_module_from_name = lambda name: Module(name) - def loadTestsFromModule(module, use_load_tests): - if use_load_tests: - raise self.failureException('use_load_tests should be False for packages') - return module.path + ' module tests' - loader.loadTestsFromModule = loadTestsFromModule - - loader._top_level_dir = '/foo' - # this time no '.py' on the pattern so that it can match - # a test package - suite = list(loader._find_tests('/foo', 'test*')) - - # We should have loaded tests from the test_directory package by calling load_tests - # and directly from the test_directory2 package - self.assertEqual(suite, - ['load_tests', 'test_directory2' + ' module tests']) - self.assertEqual(Module.paths, ['test_directory', 'test_directory2']) - - # load_tests should have been called once with loader, tests and pattern - self.assertEqual(Module.load_tests_args, - [(loader, 'test_directory' + ' module tests', 'test*')]) - - def test_discover(self): - loader = unittest2.TestLoader() - - original_isfile = os.path.isfile - original_isdir = os.path.isdir - def restore_isfile(): - os.path.isfile = original_isfile - - os.path.isfile = lambda path: False - self.addCleanup(restore_isfile) - - orig_sys_path = sys.path[:] - def restore_path(): - sys.path[:] = orig_sys_path - self.addCleanup(restore_path) - - full_path = os.path.abspath(os.path.normpath('/foo')) - self.assertRaises(ImportError, - loader.discover, - '/foo/bar', top_level_dir='/foo') - - self.assertEqual(loader._top_level_dir, full_path) - self.assertIn(full_path, sys.path) - - os.path.isfile = lambda path: True - os.path.isdir = lambda path: True - - def restore_isdir(): - os.path.isdir = original_isdir - self.addCleanup(restore_isdir) - - _find_tests_args = [] - def _find_tests(start_dir, pattern): - _find_tests_args.append((start_dir, pattern)) - return ['tests'] - loader._find_tests = _find_tests - loader.suiteClass = str - - suite = loader.discover('/foo/bar/baz', 'pattern', '/foo/bar') - - top_level_dir = os.path.abspath(os.path.normpath('/foo/bar')) - start_dir = os.path.abspath(os.path.normpath('/foo/bar/baz')) - self.assertEqual(suite, "['tests']") - self.assertEqual(loader._top_level_dir, top_level_dir) - self.assertEqual(_find_tests_args, [(start_dir, 'pattern')]) - self.assertIn(top_level_dir, sys.path) - - def test_discover_with_modules_that_fail_to_import(self): - loader = unittest2.TestLoader() - - listdir = os.listdir - os.listdir = lambda _: ['test_this_does_not_exist.py'] - isfile = os.path.isfile - os.path.isfile = lambda _: True - orig_sys_path = sys.path[:] - def restore(): - os.path.isfile = isfile - os.listdir = listdir - sys.path[:] = orig_sys_path - self.addCleanup(restore) - - suite = loader.discover('.') - self.assertIn(os.getcwd(), sys.path) - self.assertEqual(suite.countTestCases(), 1) - test = list(list(suite)[0])[0] # extract test from suite - - self.assertRaises(ImportError, - lambda: test.test_this_does_not_exist()) - - def test_command_line_handling_parseArgs(self): - # Haha - take that uninstantiable class - program = object.__new__(unittest2.TestProgram) - - args = [] - def do_discovery(argv): - args.extend(argv) - program._do_discovery = do_discovery - program.parseArgs(['something', 'discover']) - self.assertEqual(args, []) - - program.parseArgs(['something', 'discover', 'foo', 'bar']) - self.assertEqual(args, ['foo', 'bar']) - - def test_command_line_handling_do_discovery_too_many_arguments(self): - class Stop(Exception): - pass - def usageExit(): - raise Stop - - program = object.__new__(unittest2.TestProgram) - program.usageExit = usageExit - - self.assertRaises(Stop, - # too many args - lambda: program._do_discovery(['one', 'two', 'three', 'four'])) - - - def test_command_line_handling_do_discovery_calls_loader(self): - program = object.__new__(unittest2.TestProgram) - - class Loader(object): - args = [] - def discover(self, start_dir, pattern, top_level_dir): - self.args.append((start_dir, pattern, top_level_dir)) - return 'tests' - - program._do_discovery(['-v'], Loader=Loader) - self.assertEqual(program.verbosity, 2) - self.assertEqual(program.test, 'tests') - self.assertEqual(Loader.args, [('.', 'test*.py', None)]) - - Loader.args = [] - program = object.__new__(unittest2.TestProgram) - program._do_discovery(['--verbose'], Loader=Loader) - self.assertEqual(program.test, 'tests') - self.assertEqual(Loader.args, [('.', 'test*.py', None)]) - - Loader.args = [] - program = object.__new__(unittest2.TestProgram) - program._do_discovery([], Loader=Loader) - self.assertEqual(program.test, 'tests') - self.assertEqual(Loader.args, [('.', 'test*.py', None)]) - - Loader.args = [] - program = object.__new__(unittest2.TestProgram) - program._do_discovery(['fish'], Loader=Loader) - self.assertEqual(program.test, 'tests') - self.assertEqual(Loader.args, [('fish', 'test*.py', None)]) - - Loader.args = [] - program = object.__new__(unittest2.TestProgram) - program._do_discovery(['fish', 'eggs'], Loader=Loader) - self.assertEqual(program.test, 'tests') - self.assertEqual(Loader.args, [('fish', 'eggs', None)]) - - Loader.args = [] - program = object.__new__(unittest2.TestProgram) - program._do_discovery(['fish', 'eggs', 'ham'], Loader=Loader) - self.assertEqual(program.test, 'tests') - self.assertEqual(Loader.args, [('fish', 'eggs', 'ham')]) - - Loader.args = [] - program = object.__new__(unittest2.TestProgram) - program._do_discovery(['-s', 'fish'], Loader=Loader) - self.assertEqual(program.test, 'tests') - self.assertEqual(Loader.args, [('fish', 'test*.py', None)]) - - Loader.args = [] - program = object.__new__(unittest2.TestProgram) - program._do_discovery(['-t', 'fish'], Loader=Loader) - self.assertEqual(program.test, 'tests') - self.assertEqual(Loader.args, [('.', 'test*.py', 'fish')]) - - Loader.args = [] - program = object.__new__(unittest2.TestProgram) - program._do_discovery(['-p', 'fish'], Loader=Loader) - self.assertEqual(program.test, 'tests') - self.assertEqual(Loader.args, [('.', 'fish', None)]) - self.assertFalse(program.failfast) - self.assertFalse(program.catchbreak) - - args = ['-p', 'eggs', '-s', 'fish', '-v', '-f'] - try: - import signal - except ImportError: - signal = None - else: - args.append('-c') - Loader.args = [] - program = object.__new__(unittest2.TestProgram) - program._do_discovery(args, Loader=Loader) - self.assertEqual(program.test, 'tests') - self.assertEqual(Loader.args, [('fish', 'eggs', None)]) - self.assertEqual(program.verbosity, 2) - self.assertTrue(program.failfast) - if signal is not None: - self.assertTrue(program.catchbreak) - - def test_detect_module_clash(self): - class Module(object): - __file__ = 'bar/foo.py' - sys.modules['foo'] = Module - full_path = os.path.abspath('foo') - original_listdir = os.listdir - original_isfile = os.path.isfile - original_isdir = os.path.isdir - - def cleanup(): - os.listdir = original_listdir - os.path.isfile = original_isfile - os.path.isdir = original_isdir - del sys.modules['foo'] - if full_path in sys.path: - sys.path.remove(full_path) - self.addCleanup(cleanup) - - def listdir(_): - return ['foo.py'] - def isfile(_): - return True - def isdir(_): - return True - os.listdir = listdir - os.path.isfile = isfile - os.path.isdir = isdir - - loader = unittest2.TestLoader() - - mod_dir = os.path.abspath('bar') - expected_dir = os.path.abspath('foo') - msg = re.escape(r"'foo' module incorrectly imported from %r. Expected %r. " - "Is this module globally installed?" % (mod_dir, expected_dir)) - self.assertRaisesRegexp( - ImportError, '^%s$' % msg, loader.discover, - start_dir='foo', pattern='foo.py' - ) - self.assertEqual(sys.path[0], full_path) - - - def test_discovery_from_dotted_path(self): - loader = unittest2.TestLoader() - - tests = [self] - from unittest2 import test - expectedPath = os.path.abspath(os.path.dirname(test.__file__)) - - self.wasRun = False - def _find_tests(start_dir, pattern): - self.wasRun = True - self.assertEqual(start_dir, expectedPath) - return tests - loader._find_tests = _find_tests - suite = loader.discover('unittest2.test') - self.assertTrue(self.wasRun) - self.assertEqual(suite._tests, tests) - - -if __name__ == '__main__': - unittest2.main() diff --git a/PyInstaller/lib/unittest2/test/test_functiontestcase.py b/PyInstaller/lib/unittest2/test/test_functiontestcase.py deleted file mode 100644 index 295aec37fd..0000000000 --- a/PyInstaller/lib/unittest2/test/test_functiontestcase.py +++ /dev/null @@ -1,149 +0,0 @@ -import unittest2 - -from unittest2.test.support import LoggingResult - - -class Test_FunctionTestCase(unittest2.TestCase): - - # "Return the number of tests represented by the this test object. For - # unittest2.TestCase instances, this will always be 1" - def test_countTestCases(self): - test = unittest2.FunctionTestCase(lambda: None) - - self.assertEqual(test.countTestCases(), 1) - - # "When a setUp() method is defined, the test runner will run that method - # prior to each test. Likewise, if a tearDown() method is defined, the - # test runner will invoke that method after each test. In the example, - # setUp() was used to create a fresh sequence for each test." - # - # Make sure the proper call order is maintained, even if setUp() raises - # an exception. - def test_run_call_order__error_in_setUp(self): - events = [] - result = LoggingResult(events) - - def setUp(): - events.append('setUp') - raise RuntimeError('raised by setUp') - - def test(): - events.append('test') - - def tearDown(): - events.append('tearDown') - - expected = ['startTest', 'setUp', 'addError', 'stopTest'] - unittest2.FunctionTestCase(test, setUp, tearDown).run(result) - self.assertEqual(events, expected) - - # "When a setUp() method is defined, the test runner will run that method - # prior to each test. Likewise, if a tearDown() method is defined, the - # test runner will invoke that method after each test. In the example, - # setUp() was used to create a fresh sequence for each test." - # - # Make sure the proper call order is maintained, even if the test raises - # an error (as opposed to a failure). - def test_run_call_order__error_in_test(self): - events = [] - result = LoggingResult(events) - - def setUp(): - events.append('setUp') - - def test(): - events.append('test') - raise RuntimeError('raised by test') - - def tearDown(): - events.append('tearDown') - - expected = ['startTest', 'setUp', 'test', 'addError', 'tearDown', - 'stopTest'] - unittest2.FunctionTestCase(test, setUp, tearDown).run(result) - self.assertEqual(events, expected) - - # "When a setUp() method is defined, the test runner will run that method - # prior to each test. Likewise, if a tearDown() method is defined, the - # test runner will invoke that method after each test. In the example, - # setUp() was used to create a fresh sequence for each test." - # - # Make sure the proper call order is maintained, even if the test signals - # a failure (as opposed to an error). - def test_run_call_order__failure_in_test(self): - events = [] - result = LoggingResult(events) - - def setUp(): - events.append('setUp') - - def test(): - events.append('test') - self.fail('raised by test') - - def tearDown(): - events.append('tearDown') - - expected = ['startTest', 'setUp', 'test', 'addFailure', 'tearDown', - 'stopTest'] - unittest2.FunctionTestCase(test, setUp, tearDown).run(result) - self.assertEqual(events, expected) - - # "When a setUp() method is defined, the test runner will run that method - # prior to each test. Likewise, if a tearDown() method is defined, the - # test runner will invoke that method after each test. In the example, - # setUp() was used to create a fresh sequence for each test." - # - # Make sure the proper call order is maintained, even if tearDown() raises - # an exception. - def test_run_call_order__error_in_tearDown(self): - events = [] - result = LoggingResult(events) - - def setUp(): - events.append('setUp') - - def test(): - events.append('test') - - def tearDown(): - events.append('tearDown') - raise RuntimeError('raised by tearDown') - - expected = ['startTest', 'setUp', 'test', 'tearDown', 'addError', - 'stopTest'] - unittest2.FunctionTestCase(test, setUp, tearDown).run(result) - self.assertEqual(events, expected) - - # "Return a string identifying the specific test case." - # - # Because of the vague nature of the docs, I'm not going to lock this - # test down too much. Really all that can be asserted is that the id() - # will be a string (either 8-byte or unicode -- again, because the docs - # just say "string") - def test_id(self): - test = unittest2.FunctionTestCase(lambda: None) - - self.assertIsInstance(test.id(), basestring) - - # "Returns a one-line description of the test, or None if no description - # has been provided. The default implementation of this method returns - # the first line of the test method's docstring, if available, or None." - def test_shortDescription__no_docstring(self): - test = unittest2.FunctionTestCase(lambda: None) - - self.assertEqual(test.shortDescription(), None) - - # "Returns a one-line description of the test, or None if no description - # has been provided. The default implementation of this method returns - # the first line of the test method's docstring, if available, or None." - def test_shortDescription__singleline_docstring(self): - desc = "this tests foo" - test = unittest2.FunctionTestCase(lambda: None, description=desc) - - self.assertEqual(test.shortDescription(), "this tests foo") - - - -if __name__ == '__main__': - unittest2.main() diff --git a/PyInstaller/lib/unittest2/test/test_loader.py b/PyInstaller/lib/unittest2/test/test_loader.py deleted file mode 100644 index 60b66d3683..0000000000 --- a/PyInstaller/lib/unittest2/test/test_loader.py +++ /dev/null @@ -1,1289 +0,0 @@ -import sys -import types - -import unittest2 - -if sys.version_info[:2] == (2,3): - from sets import Set as set - from sets import ImmutableSet as frozenset - -class Test_TestLoader(unittest2.TestCase): - - ### Tests for TestLoader.loadTestsFromTestCase - ################################################################ - - # "Return a suite of all tests cases contained in the TestCase-derived - # class testCaseClass" - def test_loadTestsFromTestCase(self): - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - def foo_bar(self): pass - - tests = unittest2.TestSuite([Foo('test_1'), Foo('test_2')]) - - loader = unittest2.TestLoader() - self.assertEqual(loader.loadTestsFromTestCase(Foo), tests) - - # "Return a suite of all tests cases contained in the TestCase-derived - # class testCaseClass" - # - # Make sure it does the right thing even if no tests were found - def test_loadTestsFromTestCase__no_matches(self): - class Foo(unittest2.TestCase): - def foo_bar(self): pass - - empty_suite = unittest2.TestSuite() - - loader = unittest2.TestLoader() - self.assertEqual(loader.loadTestsFromTestCase(Foo), empty_suite) - - # "Return a suite of all tests cases contained in the TestCase-derived - # class testCaseClass" - # - # What happens if loadTestsFromTestCase() is given an object - # that isn't a subclass of TestCase? Specifically, what happens - # if testCaseClass is a subclass of TestSuite? - # - # This is checked for specifically in the code, so we better add a - # test for it. - def test_loadTestsFromTestCase__TestSuite_subclass(self): - class NotATestCase(unittest2.TestSuite): - pass - - loader = unittest2.TestLoader() - try: - loader.loadTestsFromTestCase(NotATestCase) - except TypeError: - pass - else: - self.fail('Should raise TypeError') - - # "Return a suite of all tests cases contained in the TestCase-derived - # class testCaseClass" - # - # Make sure loadTestsFromTestCase() picks up the default test method - # name (as specified by TestCase), even though the method name does - # not match the default TestLoader.testMethodPrefix string - def test_loadTestsFromTestCase__default_method_name(self): - class Foo(unittest2.TestCase): - def runTest(self): - pass - - loader = unittest2.TestLoader() - # This has to be false for the test to succeed - self.assertFalse('runTest'.startswith(loader.testMethodPrefix)) - - suite = loader.loadTestsFromTestCase(Foo) - self.assertIsInstance(suite, loader.suiteClass) - self.assertEqual(list(suite), [Foo('runTest')]) - - ################################################################ - ### /Tests for TestLoader.loadTestsFromTestCase - - ### Tests for TestLoader.loadTestsFromModule - ################################################################ - - # "This method searches `module` for classes derived from TestCase" - def test_loadTestsFromModule__TestCase_subclass(self): - m = types.ModuleType('m') - class MyTestCase(unittest2.TestCase): - def test(self): - pass - m.testcase_1 = MyTestCase - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromModule(m) - self.assertIsInstance(suite, loader.suiteClass) - - expected = [loader.suiteClass([MyTestCase('test')])] - self.assertEqual(list(suite), expected) - - # "This method searches `module` for classes derived from TestCase" - # - # What happens if no tests are found (no TestCase instances)? - def test_loadTestsFromModule__no_TestCase_instances(self): - m = types.ModuleType('m') - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromModule(m) - self.assertIsInstance(suite, loader.suiteClass) - self.assertEqual(list(suite), []) - - # "This method searches `module` for classes derived from TestCase" - # - # What happens if no tests are found (TestCases instances, but no tests)? - def test_loadTestsFromModule__no_TestCase_tests(self): - m = types.ModuleType('m') - class MyTestCase(unittest2.TestCase): - pass - m.testcase_1 = MyTestCase - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromModule(m) - self.assertIsInstance(suite, loader.suiteClass) - - self.assertEqual(list(suite), [loader.suiteClass()]) - - # "This method searches `module` for classes derived from TestCase"s - # - # What happens if loadTestsFromModule() is given something other - # than a module? - # - # XXX Currently, it succeeds anyway. This flexibility - # should either be documented or loadTestsFromModule() should - # raise a TypeError - # - # XXX Certain people are using this behaviour. We'll add a test for it - def test_loadTestsFromModule__not_a_module(self): - class MyTestCase(unittest2.TestCase): - def test(self): - pass - - class NotAModule(object): - test_2 = MyTestCase - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromModule(NotAModule) - - reference = [unittest2.TestSuite([MyTestCase('test')])] - self.assertEqual(list(suite), reference) - - - # Check that loadTestsFromModule honors (or not) a module - # with a load_tests function. - def test_loadTestsFromModule__load_tests(self): - m = types.ModuleType('m') - class MyTestCase(unittest2.TestCase): - def test(self): - pass - m.testcase_1 = MyTestCase - - load_tests_args = [] - def load_tests(loader, tests, pattern): - self.assertIsInstance(tests, unittest2.TestSuite) - load_tests_args.extend((loader, tests, pattern)) - return tests - m.load_tests = load_tests - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromModule(m) - self.assertIsInstance(suite, unittest2.TestSuite) - self.assertEquals(load_tests_args, [loader, suite, None]) - - load_tests_args = [] - suite = loader.loadTestsFromModule(m, use_load_tests=False) - self.assertEquals(load_tests_args, []) - - def test_loadTestsFromModule__faulty_load_tests(self): - m = types.ModuleType('m') - - def load_tests(loader, tests, pattern): - raise TypeError('some failure') - m.load_tests = load_tests - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromModule(m) - self.assertIsInstance(suite, unittest2.TestSuite) - self.assertEqual(suite.countTestCases(), 1) - test = list(suite)[0] - - self.assertRaisesRegexp(TypeError, "some failure", test.m) - - - ################################################################ - ### /Tests for TestLoader.loadTestsFromModule() - - ### Tests for TestLoader.loadTestsFromName() - ################################################################ - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # - # Is ValueError raised in response to an empty name? - def test_loadTestsFromName__empty_name(self): - loader = unittest2.TestLoader() - - try: - loader.loadTestsFromName('') - except ValueError, e: - self.assertEqual(str(e), "Empty module name") - else: - self.fail("TestLoader.loadTestsFromName failed to raise ValueError") - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # - # What happens when the name contains invalid characters? - def test_loadTestsFromName__malformed_name(self): - loader = unittest2.TestLoader() - - # XXX Should this raise ValueError or ImportError? - try: - loader.loadTestsFromName('abc () //') - except ValueError: - pass - except ImportError: - pass - else: - self.fail("TestLoader.loadTestsFromName failed to raise ValueError") - - # "The specifier name is a ``dotted name'' that may resolve ... to a - # module" - # - # What happens when a module by that name can't be found? - def test_loadTestsFromName__unknown_module_name(self): - loader = unittest2.TestLoader() - - try: - loader.loadTestsFromName('sdasfasfasdf') - except ImportError, e: - self.assertEqual(str(e), "No module named sdasfasfasdf") - else: - self.fail("TestLoader.loadTestsFromName failed to raise ImportError") - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # - # What happens when the module is found, but the attribute can't? - def test_loadTestsFromName__unknown_attr_name(self): - loader = unittest2.TestLoader() - - try: - loader.loadTestsFromName('unittest2.sdasfasfasdf') - except AttributeError, e: - self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'") - else: - self.fail("TestLoader.loadTestsFromName failed to raise AttributeError") - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # - # What happens when we provide the module, but the attribute can't be - # found? - def test_loadTestsFromName__relative_unknown_name(self): - loader = unittest2.TestLoader() - - try: - loader.loadTestsFromName('sdasfasfasdf', unittest2) - except AttributeError, e: - self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'") - else: - self.fail("TestLoader.loadTestsFromName failed to raise AttributeError") - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # ... - # "The method optionally resolves name relative to the given module" - # - # Does loadTestsFromName raise ValueError when passed an empty - # name relative to a provided module? - # - # XXX Should probably raise a ValueError instead of an AttributeError - def test_loadTestsFromName__relative_empty_name(self): - loader = unittest2.TestLoader() - - try: - loader.loadTestsFromName('', unittest2) - except AttributeError: - pass - else: - self.fail("Failed to raise AttributeError") - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # ... - # "The method optionally resolves name relative to the given module" - # - # What happens when an impossible name is given, relative to the provided - # `module`? - def test_loadTestsFromName__relative_malformed_name(self): - loader = unittest2.TestLoader() - - # XXX Should this raise AttributeError or ValueError? - try: - loader.loadTestsFromName('abc () //', unittest2) - except ValueError: - pass - except AttributeError: - pass - else: - self.fail("TestLoader.loadTestsFromName failed to raise ValueError") - - # "The method optionally resolves name relative to the given module" - # - # Does loadTestsFromName raise TypeError when the `module` argument - # isn't a module object? - # - # XXX Accepts the not-a-module object, ignorning the object's type - # This should raise an exception or the method name should be changed - # - # XXX Some people are relying on this, so keep it for now - def test_loadTestsFromName__relative_not_a_module(self): - class MyTestCase(unittest2.TestCase): - def test(self): - pass - - class NotAModule(object): - test_2 = MyTestCase - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromName('test_2', NotAModule) - - reference = [MyTestCase('test')] - self.assertEqual(list(suite), reference) - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # - # Does it raise an exception if the name resolves to an invalid - # object? - def test_loadTestsFromName__relative_bad_object(self): - m = types.ModuleType('m') - m.testcase_1 = object() - - loader = unittest2.TestLoader() - try: - loader.loadTestsFromName('testcase_1', m) - except TypeError: - pass - else: - self.fail("Should have raised TypeError") - - # "The specifier name is a ``dotted name'' that may - # resolve either to ... a test case class" - def test_loadTestsFromName__relative_TestCase_subclass(self): - m = types.ModuleType('m') - class MyTestCase(unittest2.TestCase): - def test(self): - pass - m.testcase_1 = MyTestCase - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromName('testcase_1', m) - self.assertIsInstance(suite, loader.suiteClass) - self.assertEqual(list(suite), [MyTestCase('test')]) - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - def test_loadTestsFromName__relative_TestSuite(self): - m = types.ModuleType('m') - class MyTestCase(unittest2.TestCase): - def test(self): - pass - m.testsuite = unittest2.TestSuite([MyTestCase('test')]) - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromName('testsuite', m) - self.assertIsInstance(suite, loader.suiteClass) - - self.assertEqual(list(suite), [MyTestCase('test')]) - - # "The specifier name is a ``dotted name'' that may resolve ... to - # ... a test method within a test case class" - def test_loadTestsFromName__relative_testmethod(self): - m = types.ModuleType('m') - class MyTestCase(unittest2.TestCase): - def test(self): - pass - m.testcase_1 = MyTestCase - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromName('testcase_1.test', m) - self.assertIsInstance(suite, loader.suiteClass) - - self.assertEqual(list(suite), [MyTestCase('test')]) - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # - # Does loadTestsFromName() raise the proper exception when trying to - # resolve "a test method within a test case class" that doesn't exist - # for the given name (relative to a provided module)? - def test_loadTestsFromName__relative_invalid_testmethod(self): - m = types.ModuleType('m') - class MyTestCase(unittest2.TestCase): - def test(self): - pass - m.testcase_1 = MyTestCase - - loader = unittest2.TestLoader() - try: - loader.loadTestsFromName('testcase_1.testfoo', m) - except AttributeError, e: - self.assertEqual(str(e), "type object 'MyTestCase' has no attribute 'testfoo'") - else: - self.fail("Failed to raise AttributeError") - - # "The specifier name is a ``dotted name'' that may resolve ... to - # ... a callable object which returns a ... TestSuite instance" - def test_loadTestsFromName__callable__TestSuite(self): - m = types.ModuleType('m') - testcase_1 = unittest2.FunctionTestCase(lambda: None) - testcase_2 = unittest2.FunctionTestCase(lambda: None) - def return_TestSuite(): - return unittest2.TestSuite([testcase_1, testcase_2]) - m.return_TestSuite = return_TestSuite - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromName('return_TestSuite', m) - self.assertIsInstance(suite, loader.suiteClass) - self.assertEqual(list(suite), [testcase_1, testcase_2]) - - # "The specifier name is a ``dotted name'' that may resolve ... to - # ... a callable object which returns a TestCase ... instance" - def test_loadTestsFromName__callable__TestCase_instance(self): - m = types.ModuleType('m') - testcase_1 = unittest2.FunctionTestCase(lambda: None) - def return_TestCase(): - return testcase_1 - m.return_TestCase = return_TestCase - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromName('return_TestCase', m) - self.assertIsInstance(suite, loader.suiteClass) - self.assertEqual(list(suite), [testcase_1]) - - # "The specifier name is a ``dotted name'' that may resolve ... to - # ... a callable object which returns a TestCase ... instance" - #***************************************************************** - #Override the suiteClass attribute to ensure that the suiteClass - #attribute is used - def test_loadTestsFromName__callable__TestCase_instance_ProperSuiteClass(self): - class SubTestSuite(unittest2.TestSuite): - pass - m = types.ModuleType('m') - testcase_1 = unittest2.FunctionTestCase(lambda: None) - def return_TestCase(): - return testcase_1 - m.return_TestCase = return_TestCase - - loader = unittest2.TestLoader() - loader.suiteClass = SubTestSuite - suite = loader.loadTestsFromName('return_TestCase', m) - self.assertIsInstance(suite, loader.suiteClass) - self.assertEqual(list(suite), [testcase_1]) - - # "The specifier name is a ``dotted name'' that may resolve ... to - # ... a test method within a test case class" - #***************************************************************** - #Override the suiteClass attribute to ensure that the suiteClass - #attribute is used - def test_loadTestsFromName__relative_testmethod_ProperSuiteClass(self): - class SubTestSuite(unittest2.TestSuite): - pass - m = types.ModuleType('m') - class MyTestCase(unittest2.TestCase): - def test(self): - pass - m.testcase_1 = MyTestCase - - loader = unittest2.TestLoader() - loader.suiteClass=SubTestSuite - suite = loader.loadTestsFromName('testcase_1.test', m) - self.assertIsInstance(suite, loader.suiteClass) - - self.assertEqual(list(suite), [MyTestCase('test')]) - - # "The specifier name is a ``dotted name'' that may resolve ... to - # ... a callable object which returns a TestCase or TestSuite instance" - # - # What happens if the callable returns something else? - def test_loadTestsFromName__callable__wrong_type(self): - m = types.ModuleType('m') - def return_wrong(): - return 6 - m.return_wrong = return_wrong - - loader = unittest2.TestLoader() - try: - loader.loadTestsFromName('return_wrong', m) - except TypeError: - pass - else: - self.fail("TestLoader.loadTestsFromName failed to raise TypeError") - - # "The specifier can refer to modules and packages which have not been - # imported; they will be imported as a side-effect" - def test_loadTestsFromName__module_not_loaded(self): - # We're going to try to load this module as a side-effect, so it - # better not be loaded before we try. - # - module_name = 'unittest2.test.dummy' - sys.modules.pop(module_name, None) - - loader = unittest2.TestLoader() - try: - suite = loader.loadTestsFromName(module_name) - - self.assertIsInstance(suite, loader.suiteClass) - self.assertEqual(list(suite), []) - - # module should now be loaded, thanks to loadTestsFromName() - self.assertIn(module_name, sys.modules) - finally: - if module_name in sys.modules: - del sys.modules[module_name] - - ################################################################ - ### Tests for TestLoader.loadTestsFromName() - - ### Tests for TestLoader.loadTestsFromNames() - ################################################################ - - # "Similar to loadTestsFromName(), but takes a sequence of names rather - # than a single name." - # - # What happens if that sequence of names is empty? - def test_loadTestsFromNames__empty_name_list(self): - loader = unittest2.TestLoader() - - suite = loader.loadTestsFromNames([]) - self.assertIsInstance(suite, loader.suiteClass) - self.assertEqual(list(suite), []) - - # "Similar to loadTestsFromName(), but takes a sequence of names rather - # than a single name." - # ... - # "The method optionally resolves name relative to the given module" - # - # What happens if that sequence of names is empty? - # - # XXX Should this raise a ValueError or just return an empty TestSuite? - def test_loadTestsFromNames__relative_empty_name_list(self): - loader = unittest2.TestLoader() - - suite = loader.loadTestsFromNames([], unittest2) - self.assertIsInstance(suite, loader.suiteClass) - self.assertEqual(list(suite), []) - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # - # Is ValueError raised in response to an empty name? - def test_loadTestsFromNames__empty_name(self): - loader = unittest2.TestLoader() - - try: - loader.loadTestsFromNames(['']) - except ValueError, e: - self.assertEqual(str(e), "Empty module name") - else: - self.fail("TestLoader.loadTestsFromNames failed to raise ValueError") - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # - # What happens when presented with an impossible module name? - def test_loadTestsFromNames__malformed_name(self): - loader = unittest2.TestLoader() - - # XXX Should this raise ValueError or ImportError? - try: - loader.loadTestsFromNames(['abc () //']) - except ValueError: - pass - except ImportError: - pass - else: - self.fail("TestLoader.loadTestsFromNames failed to raise ValueError") - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # - # What happens when no module can be found for the given name? - def test_loadTestsFromNames__unknown_module_name(self): - loader = unittest2.TestLoader() - - try: - loader.loadTestsFromNames(['sdasfasfasdf']) - except ImportError, e: - self.assertEqual(str(e), "No module named sdasfasfasdf") - else: - self.fail("TestLoader.loadTestsFromNames failed to raise ImportError") - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # - # What happens when the module can be found, but not the attribute? - def test_loadTestsFromNames__unknown_attr_name(self): - loader = unittest2.TestLoader() - - try: - loader.loadTestsFromNames(['unittest2.sdasfasfasdf', 'unittest2']) - except AttributeError, e: - self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'") - else: - self.fail("TestLoader.loadTestsFromNames failed to raise AttributeError") - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # ... - # "The method optionally resolves name relative to the given module" - # - # What happens when given an unknown attribute on a specified `module` - # argument? - def test_loadTestsFromNames__unknown_name_relative_1(self): - loader = unittest2.TestLoader() - - try: - loader.loadTestsFromNames(['sdasfasfasdf'], unittest2) - except AttributeError, e: - self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'") - else: - self.fail("TestLoader.loadTestsFromName failed to raise AttributeError") - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # ... - # "The method optionally resolves name relative to the given module" - # - # Do unknown attributes (relative to a provided module) still raise an - # exception even in the presence of valid attribute names? - def test_loadTestsFromNames__unknown_name_relative_2(self): - loader = unittest2.TestLoader() - - try: - loader.loadTestsFromNames(['TestCase', 'sdasfasfasdf'], unittest2) - except AttributeError, e: - self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'") - else: - self.fail("TestLoader.loadTestsFromName failed to raise AttributeError") - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # ... - # "The method optionally resolves name relative to the given module" - # - # What happens when faced with the empty string? - # - # XXX This currently raises AttributeError, though ValueError is probably - # more appropriate - def test_loadTestsFromNames__relative_empty_name(self): - loader = unittest2.TestLoader() - - try: - loader.loadTestsFromNames([''], unittest2) - except AttributeError: - pass - else: - self.fail("Failed to raise ValueError") - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # ... - # "The method optionally resolves name relative to the given module" - # - # What happens when presented with an impossible attribute name? - def test_loadTestsFromNames__relative_malformed_name(self): - loader = unittest2.TestLoader() - - # XXX Should this raise AttributeError or ValueError? - try: - loader.loadTestsFromNames(['abc () //'], unittest2) - except AttributeError: - pass - except ValueError: - pass - else: - self.fail("TestLoader.loadTestsFromNames failed to raise ValueError") - - # "The method optionally resolves name relative to the given module" - # - # Does loadTestsFromNames() make sure the provided `module` is in fact - # a module? - # - # XXX This validation is currently not done. This flexibility should - # either be documented or a TypeError should be raised. - def test_loadTestsFromNames__relative_not_a_module(self): - class MyTestCase(unittest2.TestCase): - def test(self): - pass - - class NotAModule(object): - test_2 = MyTestCase - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromNames(['test_2'], NotAModule) - - reference = [unittest2.TestSuite([MyTestCase('test')])] - self.assertEqual(list(suite), reference) - - # "The specifier name is a ``dotted name'' that may resolve either to - # a module, a test case class, a TestSuite instance, a test method - # within a test case class, or a callable object which returns a - # TestCase or TestSuite instance." - # - # Does it raise an exception if the name resolves to an invalid - # object? - def test_loadTestsFromNames__relative_bad_object(self): - m = types.ModuleType('m') - m.testcase_1 = object() - - loader = unittest2.TestLoader() - try: - loader.loadTestsFromNames(['testcase_1'], m) - except TypeError: - pass - else: - self.fail("Should have raised TypeError") - - # "The specifier name is a ``dotted name'' that may resolve ... to - # ... a test case class" - def test_loadTestsFromNames__relative_TestCase_subclass(self): - m = types.ModuleType('m') - class MyTestCase(unittest2.TestCase): - def test(self): - pass - m.testcase_1 = MyTestCase - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromNames(['testcase_1'], m) - self.assertIsInstance(suite, loader.suiteClass) - - expected = loader.suiteClass([MyTestCase('test')]) - self.assertEqual(list(suite), [expected]) - - # "The specifier name is a ``dotted name'' that may resolve ... to - # ... a TestSuite instance" - def test_loadTestsFromNames__relative_TestSuite(self): - m = types.ModuleType('m') - class MyTestCase(unittest2.TestCase): - def test(self): - pass - m.testsuite = unittest2.TestSuite([MyTestCase('test')]) - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromNames(['testsuite'], m) - self.assertIsInstance(suite, loader.suiteClass) - - self.assertEqual(list(suite), [m.testsuite]) - - # "The specifier name is a ``dotted name'' that may resolve ... to ... a - # test method within a test case class" - def test_loadTestsFromNames__relative_testmethod(self): - m = types.ModuleType('m') - class MyTestCase(unittest2.TestCase): - def test(self): - pass - m.testcase_1 = MyTestCase - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromNames(['testcase_1.test'], m) - self.assertIsInstance(suite, loader.suiteClass) - - ref_suite = unittest2.TestSuite([MyTestCase('test')]) - self.assertEqual(list(suite), [ref_suite]) - - # "The specifier name is a ``dotted name'' that may resolve ... to ... a - # test method within a test case class" - # - # Does the method gracefully handle names that initially look like they - # resolve to "a test method within a test case class" but don't? - def test_loadTestsFromNames__relative_invalid_testmethod(self): - m = types.ModuleType('m') - class MyTestCase(unittest2.TestCase): - def test(self): - pass - m.testcase_1 = MyTestCase - - loader = unittest2.TestLoader() - try: - loader.loadTestsFromNames(['testcase_1.testfoo'], m) - except AttributeError, e: - self.assertEqual(str(e), "type object 'MyTestCase' has no attribute 'testfoo'") - else: - self.fail("Failed to raise AttributeError") - - # "The specifier name is a ``dotted name'' that may resolve ... to - # ... a callable object which returns a ... TestSuite instance" - def test_loadTestsFromNames__callable__TestSuite(self): - m = types.ModuleType('m') - testcase_1 = unittest2.FunctionTestCase(lambda: None) - testcase_2 = unittest2.FunctionTestCase(lambda: None) - def return_TestSuite(): - return unittest2.TestSuite([testcase_1, testcase_2]) - m.return_TestSuite = return_TestSuite - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromNames(['return_TestSuite'], m) - self.assertIsInstance(suite, loader.suiteClass) - - expected = unittest2.TestSuite([testcase_1, testcase_2]) - self.assertEqual(list(suite), [expected]) - - # "The specifier name is a ``dotted name'' that may resolve ... to - # ... a callable object which returns a TestCase ... instance" - def test_loadTestsFromNames__callable__TestCase_instance(self): - m = types.ModuleType('m') - testcase_1 = unittest2.FunctionTestCase(lambda: None) - def return_TestCase(): - return testcase_1 - m.return_TestCase = return_TestCase - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromNames(['return_TestCase'], m) - self.assertIsInstance(suite, loader.suiteClass) - - ref_suite = unittest2.TestSuite([testcase_1]) - self.assertEqual(list(suite), [ref_suite]) - - # "The specifier name is a ``dotted name'' that may resolve ... to - # ... a callable object which returns a TestCase or TestSuite instance" - # - # Are staticmethods handled correctly? - def test_loadTestsFromNames__callable__call_staticmethod(self): - m = types.ModuleType('m') - class Test1(unittest2.TestCase): - def test(self): - pass - - testcase_1 = Test1('test') - class Foo(unittest2.TestCase): - def foo(): - return testcase_1 - foo = staticmethod(foo) - m.Foo = Foo - - loader = unittest2.TestLoader() - suite = loader.loadTestsFromNames(['Foo.foo'], m) - self.assertIsInstance(suite, loader.suiteClass) - - ref_suite = unittest2.TestSuite([testcase_1]) - self.assertEqual(list(suite), [ref_suite]) - - # "The specifier name is a ``dotted name'' that may resolve ... to - # ... a callable object which returns a TestCase or TestSuite instance" - # - # What happens when the callable returns something else? - def test_loadTestsFromNames__callable__wrong_type(self): - m = types.ModuleType('m') - def return_wrong(): - return 6 - m.return_wrong = return_wrong - - loader = unittest2.TestLoader() - try: - loader.loadTestsFromNames(['return_wrong'], m) - except TypeError: - pass - else: - self.fail("TestLoader.loadTestsFromNames failed to raise TypeError") - - # "The specifier can refer to modules and packages which have not been - # imported; they will be imported as a side-effect" - def test_loadTestsFromNames__module_not_loaded(self): - # We're going to try to load this module as a side-effect, so it - # better not be loaded before we try. - # - module_name = 'unittest2.test.dummy' - sys.modules.pop(module_name, None) - - loader = unittest2.TestLoader() - try: - suite = loader.loadTestsFromNames([module_name]) - - self.assertIsInstance(suite, loader.suiteClass) - self.assertEqual(list(suite), [unittest2.TestSuite()]) - - # module should now be loaded, thanks to loadTestsFromName() - self.assertIn(module_name, sys.modules) - finally: - if module_name in sys.modules: - del sys.modules[module_name] - - ################################################################ - ### /Tests for TestLoader.loadTestsFromNames() - - ### Tests for TestLoader.getTestCaseNames() - ################################################################ - - # "Return a sorted sequence of method names found within testCaseClass" - # - # Test.foobar is defined to make sure getTestCaseNames() respects - # loader.testMethodPrefix - def test_getTestCaseNames(self): - class Test(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - def foobar(self): pass - - loader = unittest2.TestLoader() - - self.assertEqual(loader.getTestCaseNames(Test), ['test_1', 'test_2']) - - # "Return a sorted sequence of method names found within testCaseClass" - # - # Does getTestCaseNames() behave appropriately if no tests are found? - def test_getTestCaseNames__no_tests(self): - class Test(unittest2.TestCase): - def foobar(self): pass - - loader = unittest2.TestLoader() - - self.assertEqual(loader.getTestCaseNames(Test), []) - - # "Return a sorted sequence of method names found within testCaseClass" - # - # Are not-TestCases handled gracefully? - # - # XXX This should raise a TypeError, not return a list - # - # XXX It's too late in the 2.5 release cycle to fix this, but it should - # probably be revisited for 2.6 - def test_getTestCaseNames__not_a_TestCase(self): - class BadCase(int): - def test_foo(self): - pass - - loader = unittest2.TestLoader() - names = loader.getTestCaseNames(BadCase) - - self.assertEqual(names, ['test_foo']) - - # "Return a sorted sequence of method names found within testCaseClass" - # - # Make sure inherited names are handled. - # - # TestP.foobar is defined to make sure getTestCaseNames() respects - # loader.testMethodPrefix - def test_getTestCaseNames__inheritance(self): - class TestP(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - def foobar(self): pass - - class TestC(TestP): - def test_1(self): pass - def test_3(self): pass - - loader = unittest2.TestLoader() - - names = ['test_1', 'test_2', 'test_3'] - self.assertEqual(loader.getTestCaseNames(TestC), names) - - ################################################################ - ### /Tests for TestLoader.getTestCaseNames() - - ### Tests for TestLoader.testMethodPrefix - ################################################################ - - # "String giving the prefix of method names which will be interpreted as - # test methods" - # - # Implicit in the documentation is that testMethodPrefix is respected by - # all loadTestsFrom* methods. - def test_testMethodPrefix__loadTestsFromTestCase(self): - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - def foo_bar(self): pass - - tests_1 = unittest2.TestSuite([Foo('foo_bar')]) - tests_2 = unittest2.TestSuite([Foo('test_1'), Foo('test_2')]) - - loader = unittest2.TestLoader() - loader.testMethodPrefix = 'foo' - self.assertEqual(loader.loadTestsFromTestCase(Foo), tests_1) - - loader.testMethodPrefix = 'test' - self.assertEqual(loader.loadTestsFromTestCase(Foo), tests_2) - - # "String giving the prefix of method names which will be interpreted as - # test methods" - # - # Implicit in the documentation is that testMethodPrefix is respected by - # all loadTestsFrom* methods. - def test_testMethodPrefix__loadTestsFromModule(self): - m = types.ModuleType('m') - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - def foo_bar(self): pass - m.Foo = Foo - - tests_1 = [unittest2.TestSuite([Foo('foo_bar')])] - tests_2 = [unittest2.TestSuite([Foo('test_1'), Foo('test_2')])] - - loader = unittest2.TestLoader() - loader.testMethodPrefix = 'foo' - self.assertEqual(list(loader.loadTestsFromModule(m)), tests_1) - - loader.testMethodPrefix = 'test' - self.assertEqual(list(loader.loadTestsFromModule(m)), tests_2) - - # "String giving the prefix of method names which will be interpreted as - # test methods" - # - # Implicit in the documentation is that testMethodPrefix is respected by - # all loadTestsFrom* methods. - def test_testMethodPrefix__loadTestsFromName(self): - m = types.ModuleType('m') - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - def foo_bar(self): pass - m.Foo = Foo - - tests_1 = unittest2.TestSuite([Foo('foo_bar')]) - tests_2 = unittest2.TestSuite([Foo('test_1'), Foo('test_2')]) - - loader = unittest2.TestLoader() - loader.testMethodPrefix = 'foo' - self.assertEqual(loader.loadTestsFromName('Foo', m), tests_1) - - loader.testMethodPrefix = 'test' - self.assertEqual(loader.loadTestsFromName('Foo', m), tests_2) - - # "String giving the prefix of method names which will be interpreted as - # test methods" - # - # Implicit in the documentation is that testMethodPrefix is respected by - # all loadTestsFrom* methods. - def test_testMethodPrefix__loadTestsFromNames(self): - m = types.ModuleType('m') - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - def foo_bar(self): pass - m.Foo = Foo - - tests_1 = unittest2.TestSuite([unittest2.TestSuite([Foo('foo_bar')])]) - tests_2 = unittest2.TestSuite([Foo('test_1'), Foo('test_2')]) - tests_2 = unittest2.TestSuite([tests_2]) - - loader = unittest2.TestLoader() - loader.testMethodPrefix = 'foo' - self.assertEqual(loader.loadTestsFromNames(['Foo'], m), tests_1) - - loader.testMethodPrefix = 'test' - self.assertEqual(loader.loadTestsFromNames(['Foo'], m), tests_2) - - # "The default value is 'test'" - def test_testMethodPrefix__default_value(self): - loader = unittest2.TestLoader() - self.assertTrue(loader.testMethodPrefix == 'test') - - ################################################################ - ### /Tests for TestLoader.testMethodPrefix - - ### Tests for TestLoader.sortTestMethodsUsing - ################################################################ - - # "Function to be used to compare method names when sorting them in - # getTestCaseNames() and all the loadTestsFromX() methods" - def test_sortTestMethodsUsing__loadTestsFromTestCase(self): - def reversed_cmp(x, y): - return -cmp(x, y) - - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - - loader = unittest2.TestLoader() - loader.sortTestMethodsUsing = reversed_cmp - - tests = loader.suiteClass([Foo('test_2'), Foo('test_1')]) - self.assertEqual(loader.loadTestsFromTestCase(Foo), tests) - - # "Function to be used to compare method names when sorting them in - # getTestCaseNames() and all the loadTestsFromX() methods" - def test_sortTestMethodsUsing__loadTestsFromModule(self): - def reversed_cmp(x, y): - return -cmp(x, y) - - m = types.ModuleType('m') - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - m.Foo = Foo - - loader = unittest2.TestLoader() - loader.sortTestMethodsUsing = reversed_cmp - - tests = [loader.suiteClass([Foo('test_2'), Foo('test_1')])] - self.assertEqual(list(loader.loadTestsFromModule(m)), tests) - - # "Function to be used to compare method names when sorting them in - # getTestCaseNames() and all the loadTestsFromX() methods" - def test_sortTestMethodsUsing__loadTestsFromName(self): - def reversed_cmp(x, y): - return -cmp(x, y) - - m = types.ModuleType('m') - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - m.Foo = Foo - - loader = unittest2.TestLoader() - loader.sortTestMethodsUsing = reversed_cmp - - tests = loader.suiteClass([Foo('test_2'), Foo('test_1')]) - self.assertEqual(loader.loadTestsFromName('Foo', m), tests) - - # "Function to be used to compare method names when sorting them in - # getTestCaseNames() and all the loadTestsFromX() methods" - def test_sortTestMethodsUsing__loadTestsFromNames(self): - def reversed_cmp(x, y): - return -cmp(x, y) - - m = types.ModuleType('m') - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - m.Foo = Foo - - loader = unittest2.TestLoader() - loader.sortTestMethodsUsing = reversed_cmp - - tests = [loader.suiteClass([Foo('test_2'), Foo('test_1')])] - self.assertEqual(list(loader.loadTestsFromNames(['Foo'], m)), tests) - - # "Function to be used to compare method names when sorting them in - # getTestCaseNames()" - # - # Does it actually affect getTestCaseNames()? - def test_sortTestMethodsUsing__getTestCaseNames(self): - def reversed_cmp(x, y): - return -cmp(x, y) - - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - - loader = unittest2.TestLoader() - loader.sortTestMethodsUsing = reversed_cmp - - test_names = ['test_2', 'test_1'] - self.assertEqual(loader.getTestCaseNames(Foo), test_names) - - # "The default value is the built-in cmp() function" - def test_sortTestMethodsUsing__default_value(self): - loader = unittest2.TestLoader() - self.assertTrue(loader.sortTestMethodsUsing is cmp) - - # "it can be set to None to disable the sort." - # - # XXX How is this different from reassigning cmp? Are the tests returned - # in a random order or something? This behaviour should die - def test_sortTestMethodsUsing__None(self): - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - - loader = unittest2.TestLoader() - loader.sortTestMethodsUsing = None - - test_names = ['test_2', 'test_1'] - self.assertEqual(set(loader.getTestCaseNames(Foo)), set(test_names)) - - ################################################################ - ### /Tests for TestLoader.sortTestMethodsUsing - - ### Tests for TestLoader.suiteClass - ################################################################ - - # "Callable object that constructs a test suite from a list of tests." - def test_suiteClass__loadTestsFromTestCase(self): - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - def foo_bar(self): pass - - tests = [Foo('test_1'), Foo('test_2')] - - loader = unittest2.TestLoader() - loader.suiteClass = list - self.assertEqual(loader.loadTestsFromTestCase(Foo), tests) - - # It is implicit in the documentation for TestLoader.suiteClass that - # all TestLoader.loadTestsFrom* methods respect it. Let's make sure - def test_suiteClass__loadTestsFromModule(self): - m = types.ModuleType('m') - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - def foo_bar(self): pass - m.Foo = Foo - - tests = [[Foo('test_1'), Foo('test_2')]] - - loader = unittest2.TestLoader() - loader.suiteClass = list - self.assertEqual(loader.loadTestsFromModule(m), tests) - - # It is implicit in the documentation for TestLoader.suiteClass that - # all TestLoader.loadTestsFrom* methods respect it. Let's make sure - def test_suiteClass__loadTestsFromName(self): - m = types.ModuleType('m') - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - def foo_bar(self): pass - m.Foo = Foo - - tests = [Foo('test_1'), Foo('test_2')] - - loader = unittest2.TestLoader() - loader.suiteClass = list - self.assertEqual(loader.loadTestsFromName('Foo', m), tests) - - # It is implicit in the documentation for TestLoader.suiteClass that - # all TestLoader.loadTestsFrom* methods respect it. Let's make sure - def test_suiteClass__loadTestsFromNames(self): - m = types.ModuleType('m') - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - def foo_bar(self): pass - m.Foo = Foo - - tests = [[Foo('test_1'), Foo('test_2')]] - - loader = unittest2.TestLoader() - loader.suiteClass = list - self.assertEqual(loader.loadTestsFromNames(['Foo'], m), tests) - - # "The default value is the TestSuite class" - def test_suiteClass__default_value(self): - loader = unittest2.TestLoader() - self.assertTrue(loader.suiteClass is unittest2.TestSuite) - - -if __name__ == '__main__': - unittest2.main() diff --git a/PyInstaller/lib/unittest2/test/test_new_tests.py b/PyInstaller/lib/unittest2/test/test_new_tests.py deleted file mode 100644 index cc96bcb6a0..0000000000 --- a/PyInstaller/lib/unittest2/test/test_new_tests.py +++ /dev/null @@ -1,46 +0,0 @@ -from cStringIO import StringIO - -import unittest -import unittest2 - -from unittest2.test.support import resultFactory - - -class TestUnittest(unittest2.TestCase): - - def assertIsSubclass(self, actual, klass): - self.assertTrue(issubclass(actual, klass), "Not a subclass.") - - def testInheritance(self): - self.assertIsSubclass(unittest2.TestCase, unittest.TestCase) - self.assertIsSubclass(unittest2.TestResult, unittest.TestResult) - self.assertIsSubclass(unittest2.TestSuite, unittest.TestSuite) - self.assertIsSubclass(unittest2.TextTestRunner, unittest.TextTestRunner) - self.assertIsSubclass(unittest2.TestLoader, unittest.TestLoader) - self.assertIsSubclass(unittest2.TextTestResult, unittest.TestResult) - - def test_new_runner_old_case(self): - runner = unittest2.TextTestRunner(resultclass=resultFactory, - stream=StringIO()) - class Test(unittest.TestCase): - def testOne(self): - pass - suite = unittest2.TestSuite((Test('testOne'),)) - result = runner.run(suite) - self.assertEqual(result.testsRun, 1) - self.assertEqual(len(result.errors), 0) - - def test_old_runner_new_case(self): - runner = unittest.TextTestRunner(stream=StringIO()) - class Test(unittest2.TestCase): - def testOne(self): - self.assertDictEqual({}, {}) - - suite = unittest.TestSuite((Test('testOne'),)) - result = runner.run(suite) - self.assertEqual(result.testsRun, 1) - self.assertEqual(len(result.errors), 0) - - -if __name__ == '__main__': - unittest2.main() \ No newline at end of file diff --git a/PyInstaller/lib/unittest2/test/test_program.py b/PyInstaller/lib/unittest2/test/test_program.py deleted file mode 100644 index 56077a6bb3..0000000000 --- a/PyInstaller/lib/unittest2/test/test_program.py +++ /dev/null @@ -1,239 +0,0 @@ -from cStringIO import StringIO - -import sys -import unittest2 - -hasInstallHandler = hasattr(unittest2, 'installHandler') - -class Test_TestProgram(unittest2.TestCase): - - # Horrible white box test - def testNoExit(self): - result = object() - test = object() - - class FakeRunner(object): - def run(self, test): - self.test = test - return result - - runner = FakeRunner() - - oldParseArgs = unittest2.TestProgram.parseArgs - def restoreParseArgs(): - unittest2.TestProgram.parseArgs = oldParseArgs - unittest2.TestProgram.parseArgs = lambda *args: None - self.addCleanup(restoreParseArgs) - - def removeTest(): - del unittest2.TestProgram.test - unittest2.TestProgram.test = test - self.addCleanup(removeTest) - - program = unittest2.TestProgram(testRunner=runner, exit=False, verbosity=2) - - self.assertEqual(program.result, result) - self.assertEqual(runner.test, test) - self.assertEqual(program.verbosity, 2) - - class FooBar(unittest2.TestCase): - def testPass(self): - assert True - def testFail(self): - assert False - - class FooBarLoader(unittest2.TestLoader): - """Test loader that returns a suite containing FooBar.""" - def loadTestsFromModule(self, module): - return self.suiteClass( - [self.loadTestsFromTestCase(Test_TestProgram.FooBar)]) - - - def test_NonExit(self): - program = unittest2.main(exit=False, - argv=["foobar"], - testRunner=unittest2.TextTestRunner(stream=StringIO()), - testLoader=self.FooBarLoader()) - self.assertTrue(hasattr(program, 'result')) - - - def test_Exit(self): - self.assertRaises( - SystemExit, - unittest2.main, - argv=["foobar"], - testRunner=unittest2.TextTestRunner(stream=StringIO()), - exit=True, - testLoader=self.FooBarLoader()) - - - def test_ExitAsDefault(self): - self.assertRaises( - SystemExit, - unittest2.main, - argv=["foobar"], - testRunner=unittest2.TextTestRunner(stream=StringIO()), - testLoader=self.FooBarLoader()) - - -class InitialisableProgram(unittest2.TestProgram): - exit = False - result = None - verbosity = 1 - defaultTest = None - testRunner = None - testLoader = unittest2.defaultTestLoader - progName = 'test' - test = 'test' - def __init__(self, *args): - pass - -RESULT = object() - -class FakeRunner(object): - initArgs = None - test = None - raiseError = False - - def __init__(self, **kwargs): - FakeRunner.initArgs = kwargs - if FakeRunner.raiseError: - FakeRunner.raiseError = False - raise TypeError - - def run(self, test): - FakeRunner.test = test - return RESULT - -class TestCommandLineArgs(unittest2.TestCase): - - def setUp(self): - self.program = InitialisableProgram() - self.program.createTests = lambda: None - FakeRunner.initArgs = None - FakeRunner.test = None - FakeRunner.raiseError = False - - def testHelpAndUnknown(self): - program = self.program - def usageExit(msg=None): - program.msg = msg - program.exit = True - program.usageExit = usageExit - - for opt in '-h', '-H', '--help': - program.exit = False - program.parseArgs([None, opt]) - self.assertTrue(program.exit) - self.assertIsNone(program.msg) - - program.parseArgs([None, '-$']) - self.assertTrue(program.exit) - self.assertIsNotNone(program.msg) - - def testVerbosity(self): - program = self.program - - for opt in '-q', '--quiet': - program.verbosity = 1 - program.parseArgs([None, opt]) - self.assertEqual(program.verbosity, 0) - - for opt in '-v', '--verbose': - program.verbosity = 1 - program.parseArgs([None, opt]) - self.assertEqual(program.verbosity, 2) - - def testBufferCatchFailfast(self): - program = self.program - for arg, attr in (('buffer', 'buffer'), ('failfast', 'failfast'), - ('catch', 'catchbreak')): - if attr == 'catch' and not hasInstallHandler: - continue - - short_opt = '-%s' % arg[0] - long_opt = '--%s' % arg - for opt in short_opt, long_opt: - setattr(program, attr, None) - - program.parseArgs([None, opt]) - self.assertTrue(getattr(program, attr)) - - for opt in short_opt, long_opt: - not_none = object() - setattr(program, attr, not_none) - - program.parseArgs([None, opt]) - self.assertEqual(getattr(program, attr), not_none) - - def testRunTestsRunnerClass(self): - program = self.program - - program.testRunner = FakeRunner - program.verbosity = 'verbosity' - program.failfast = 'failfast' - program.buffer = 'buffer' - - program.runTests() - - self.assertEqual(FakeRunner.initArgs, {'verbosity': 'verbosity', - 'failfast': 'failfast', - 'buffer': 'buffer'}) - self.assertEqual(FakeRunner.test, 'test') - self.assertIs(program.result, RESULT) - - def testRunTestsRunnerInstance(self): - program = self.program - - program.testRunner = FakeRunner() - FakeRunner.initArgs = None - - program.runTests() - - # A new FakeRunner should not have been instantiated - self.assertIsNone(FakeRunner.initArgs) - - self.assertEqual(FakeRunner.test, 'test') - self.assertIs(program.result, RESULT) - - def testRunTestsOldRunnerClass(self): - program = self.program - - FakeRunner.raiseError = True - program.testRunner = FakeRunner - program.verbosity = 'verbosity' - program.failfast = 'failfast' - program.buffer = 'buffer' - program.test = 'test' - - program.runTests() - - # If initialising raises a type error it should be retried - # without the new keyword arguments - self.assertEqual(FakeRunner.initArgs, {}) - self.assertEqual(FakeRunner.test, 'test') - self.assertIs(program.result, RESULT) - - def testCatchBreakInstallsHandler(self): - module = sys.modules['unittest2.main'] - original = module.installHandler - def restore(): - module.installHandler = original - self.addCleanup(restore) - - self.installed = False - def fakeInstallHandler(): - self.installed = True - module.installHandler = fakeInstallHandler - - program = self.program - program.catchbreak = True - - program.testRunner = FakeRunner - - program.runTests() - self.assertTrue(self.installed) - - -if __name__ == '__main__': - unittest2.main() diff --git a/PyInstaller/lib/unittest2/test/test_result.py b/PyInstaller/lib/unittest2/test/test_result.py deleted file mode 100644 index a6dc16cf79..0000000000 --- a/PyInstaller/lib/unittest2/test/test_result.py +++ /dev/null @@ -1,416 +0,0 @@ -import sys -import textwrap -from StringIO import StringIO - -import unittest2 - - -class Test_TestResult(unittest2.TestCase): - # Note: there are not separate tests for TestResult.wasSuccessful(), - # TestResult.errors, TestResult.failures, TestResult.testsRun or - # TestResult.shouldStop because these only have meaning in terms of - # other TestResult methods. - # - # Accordingly, tests for the aforenamed attributes are incorporated - # in with the tests for the defining methods. - ################################################################ - - def test_init(self): - result = unittest2.TestResult() - - self.assertTrue(result.wasSuccessful()) - self.assertEqual(len(result.errors), 0) - self.assertEqual(len(result.failures), 0) - self.assertEqual(result.testsRun, 0) - self.assertEqual(result.shouldStop, False) - self.assertIsNone(result._stdout_buffer) - self.assertIsNone(result._stderr_buffer) - - # "This method can be called to signal that the set of tests being - # run should be aborted by setting the TestResult's shouldStop - # attribute to True." - def test_stop(self): - result = unittest2.TestResult() - - result.stop() - - self.assertEqual(result.shouldStop, True) - - # "Called when the test case test is about to be run. The default - # implementation simply increments the instance's testsRun counter." - def test_startTest(self): - class Foo(unittest2.TestCase): - def test_1(self): - pass - - test = Foo('test_1') - - result = unittest2.TestResult() - - result.startTest(test) - - self.assertTrue(result.wasSuccessful()) - self.assertEqual(len(result.errors), 0) - self.assertEqual(len(result.failures), 0) - self.assertEqual(result.testsRun, 1) - self.assertEqual(result.shouldStop, False) - - result.stopTest(test) - - # "Called after the test case test has been executed, regardless of - # the outcome. The default implementation does nothing." - def test_stopTest(self): - class Foo(unittest2.TestCase): - def test_1(self): - pass - - test = Foo('test_1') - - result = unittest2.TestResult() - - result.startTest(test) - - self.assertTrue(result.wasSuccessful()) - self.assertEqual(len(result.errors), 0) - self.assertEqual(len(result.failures), 0) - self.assertEqual(result.testsRun, 1) - self.assertEqual(result.shouldStop, False) - - result.stopTest(test) - - # Same tests as above; make sure nothing has changed - self.assertTrue(result.wasSuccessful()) - self.assertEqual(len(result.errors), 0) - self.assertEqual(len(result.failures), 0) - self.assertEqual(result.testsRun, 1) - self.assertEqual(result.shouldStop, False) - - # "Called before and after tests are run. The default implementation does nothing." - def test_startTestRun_stopTestRun(self): - result = unittest2.TestResult() - result.startTestRun() - result.stopTestRun() - - # "addSuccess(test)" - # ... - # "Called when the test case test succeeds" - # ... - # "wasSuccessful() - Returns True if all tests run so far have passed, - # otherwise returns False" - # ... - # "testsRun - The total number of tests run so far." - # ... - # "errors - A list containing 2-tuples of TestCase instances and - # formatted tracebacks. Each tuple represents a test which raised an - # unexpected exception. Contains formatted - # tracebacks instead of sys.exc_info() results." - # ... - # "failures - A list containing 2-tuples of TestCase instances and - # formatted tracebacks. Each tuple represents a test where a failure was - # explicitly signalled using the TestCase.fail*() or TestCase.assert*() - # methods. Contains formatted tracebacks instead - # of sys.exc_info() results." - def test_addSuccess(self): - class Foo(unittest2.TestCase): - def test_1(self): - pass - - test = Foo('test_1') - - result = unittest2.TestResult() - - result.startTest(test) - result.addSuccess(test) - result.stopTest(test) - - self.assertTrue(result.wasSuccessful()) - self.assertEqual(len(result.errors), 0) - self.assertEqual(len(result.failures), 0) - self.assertEqual(result.testsRun, 1) - self.assertEqual(result.shouldStop, False) - - # "addFailure(test, err)" - # ... - # "Called when the test case test signals a failure. err is a tuple of - # the form returned by sys.exc_info(): (type, value, traceback)" - # ... - # "wasSuccessful() - Returns True if all tests run so far have passed, - # otherwise returns False" - # ... - # "testsRun - The total number of tests run so far." - # ... - # "errors - A list containing 2-tuples of TestCase instances and - # formatted tracebacks. Each tuple represents a test which raised an - # unexpected exception. Contains formatted - # tracebacks instead of sys.exc_info() results." - # ... - # "failures - A list containing 2-tuples of TestCase instances and - # formatted tracebacks. Each tuple represents a test where a failure was - # explicitly signalled using the TestCase.fail*() or TestCase.assert*() - # methods. Contains formatted tracebacks instead - # of sys.exc_info() results." - def test_addFailure(self): - class Foo(unittest2.TestCase): - def test_1(self): - pass - - test = Foo('test_1') - try: - test.fail("foo") - except: - exc_info_tuple = sys.exc_info() - - result = unittest2.TestResult() - - result.startTest(test) - result.addFailure(test, exc_info_tuple) - result.stopTest(test) - - self.assertFalse(result.wasSuccessful()) - self.assertEqual(len(result.errors), 0) - self.assertEqual(len(result.failures), 1) - self.assertEqual(result.testsRun, 1) - self.assertEqual(result.shouldStop, False) - - test_case, formatted_exc = result.failures[0] - self.assertTrue(test_case is test) - self.assertIsInstance(formatted_exc, str) - - # "addError(test, err)" - # ... - # "Called when the test case test raises an unexpected exception err - # is a tuple of the form returned by sys.exc_info(): - # (type, value, traceback)" - # ... - # "wasSuccessful() - Returns True if all tests run so far have passed, - # otherwise returns False" - # ... - # "testsRun - The total number of tests run so far." - # ... - # "errors - A list containing 2-tuples of TestCase instances and - # formatted tracebacks. Each tuple represents a test which raised an - # unexpected exception. Contains formatted - # tracebacks instead of sys.exc_info() results." - # ... - # "failures - A list containing 2-tuples of TestCase instances and - # formatted tracebacks. Each tuple represents a test where a failure was - # explicitly signalled using the TestCase.fail*() or TestCase.assert*() - # methods. Contains formatted tracebacks instead - # of sys.exc_info() results." - def test_addError(self): - class Foo(unittest2.TestCase): - def test_1(self): - pass - - test = Foo('test_1') - try: - raise TypeError() - except: - exc_info_tuple = sys.exc_info() - - result = unittest2.TestResult() - - result.startTest(test) - result.addError(test, exc_info_tuple) - result.stopTest(test) - - self.assertFalse(result.wasSuccessful()) - self.assertEqual(len(result.errors), 1) - self.assertEqual(len(result.failures), 0) - self.assertEqual(result.testsRun, 1) - self.assertEqual(result.shouldStop, False) - - test_case, formatted_exc = result.errors[0] - self.assertTrue(test_case is test) - self.assertIsInstance(formatted_exc, str) - - def testGetDescriptionWithoutDocstring(self): - result = unittest2.TextTestResult(None, True, 1) - self.assertEqual( - result.getDescription(self), - 'testGetDescriptionWithoutDocstring (' + __name__ + - '.Test_TestResult)') - - def testGetDescriptionWithOneLineDocstring(self): - """Tests getDescription() for a method with a docstring.""" - result = unittest2.TextTestResult(None, True, 1) - self.assertEqual( - result.getDescription(self), - ('testGetDescriptionWithOneLineDocstring ' - '(' + __name__ + '.Test_TestResult)\n' - 'Tests getDescription() for a method with a docstring.')) - - def testGetDescriptionWithMultiLineDocstring(self): - """Tests getDescription() for a method with a longer docstring. - The second line of the docstring. - """ - result = unittest2.TextTestResult(None, True, 1) - self.assertEqual( - result.getDescription(self), - ('testGetDescriptionWithMultiLineDocstring ' - '(' + __name__ + '.Test_TestResult)\n' - 'Tests getDescription() for a method with a longer ' - 'docstring.')) - - def testStackFrameTrimming(self): - class Frame(object): - class tb_frame(object): - f_globals = {} - result = unittest2.TestResult() - self.assertFalse(result._is_relevant_tb_level(Frame)) - - Frame.tb_frame.f_globals['__unittest'] = True - self.assertTrue(result._is_relevant_tb_level(Frame)) - - def testFailFast(self): - result = unittest2.TestResult() - result._exc_info_to_string = lambda *_: '' - result.failfast = True - result.addError(None, None) - self.assertTrue(result.shouldStop) - - result = unittest2.TestResult() - result._exc_info_to_string = lambda *_: '' - result.failfast = True - result.addFailure(None, None) - self.assertTrue(result.shouldStop) - - result = unittest2.TestResult() - result._exc_info_to_string = lambda *_: '' - result.failfast = True - result.addUnexpectedSuccess(None) - self.assertTrue(result.shouldStop) - - def testFailFastSetByRunner(self): - runner = unittest2.TextTestRunner(stream=StringIO(), failfast=True) - self.testRan = False - def test(result): - self.testRan = True - self.assertTrue(result.failfast) - runner.run(test) - self.assertTrue(self.testRan) - - -class TestOutputBuffering(unittest2.TestCase): - - def setUp(self): - self._real_out = sys.stdout - self._real_err = sys.stderr - - def tearDown(self): - sys.stdout = self._real_out - sys.stderr = self._real_err - - def testBufferOutputOff(self): - real_out = self._real_out - real_err = self._real_err - - result = unittest2.TestResult() - self.assertFalse(result.buffer) - - self.assertIs(real_out, sys.stdout) - self.assertIs(real_err, sys.stderr) - - result.startTest(self) - - self.assertIs(real_out, sys.stdout) - self.assertIs(real_err, sys.stderr) - - def testBufferOutputStartTestAddSuccess(self): - real_out = self._real_out - real_err = self._real_err - - result = unittest2.TestResult() - self.assertFalse(result.buffer) - - result.buffer = True - - self.assertIs(real_out, sys.stdout) - self.assertIs(real_err, sys.stderr) - - result.startTest(self) - - self.assertIsNot(real_out, sys.stdout) - self.assertIsNot(real_err, sys.stderr) - self.assertIsInstance(sys.stdout, StringIO) - self.assertIsInstance(sys.stderr, StringIO) - self.assertIsNot(sys.stdout, sys.stderr) - - out_stream = sys.stdout - err_stream = sys.stderr - - result._original_stdout = StringIO() - result._original_stderr = StringIO() - - print 'foo' - print >> sys.stderr, 'bar' - - self.assertEqual(out_stream.getvalue(), 'foo\n') - self.assertEqual(err_stream.getvalue(), 'bar\n') - - self.assertEqual(result._original_stdout.getvalue(), '') - self.assertEqual(result._original_stderr.getvalue(), '') - - result.addSuccess(self) - result.stopTest(self) - - self.assertIs(sys.stdout, result._original_stdout) - self.assertIs(sys.stderr, result._original_stderr) - - self.assertEqual(result._original_stdout.getvalue(), '') - self.assertEqual(result._original_stderr.getvalue(), '') - - self.assertEqual(out_stream.getvalue(), '') - self.assertEqual(err_stream.getvalue(), '') - - - def getStartedResult(self): - result = unittest2.TestResult() - result.buffer = True - result.startTest(self) - return result - - def testBufferOutputAddErrorOrFailure(self): - for message_attr, add_attr, include_error in [ - ('errors', 'addError', True), - ('failures', 'addFailure', False), - ('errors', 'addError', True), - ('failures', 'addFailure', False) - ]: - result = self.getStartedResult() - result._original_stderr = StringIO() - result._original_stdout = StringIO() - - print >> sys.stdout, 'foo' - if include_error: - print >> sys.stderr, 'bar' - - addFunction = getattr(result, add_attr) - addFunction(self, (None, None, None)) - result.stopTest(self) - - result_list = getattr(result, message_attr) - self.assertEqual(len(result_list), 1) - - test, message = result_list[0] - expectedOutMessage = textwrap.dedent(""" - Stdout: - foo - """) - expectedErrMessage = '' - if include_error: - expectedErrMessage = textwrap.dedent(""" - Stderr: - bar - """) - expectedFullMessage = 'None\n%s%s' % (expectedOutMessage, expectedErrMessage) - - self.assertIs(test, self) - self.assertEqual(result._original_stdout.getvalue(), expectedOutMessage) - self.assertEqual(result._original_stderr.getvalue(), expectedErrMessage) - self.assertMultiLineEqual(message, expectedFullMessage) - - - -if __name__ == '__main__': - unittest2.main() diff --git a/PyInstaller/lib/unittest2/test/test_runner.py b/PyInstaller/lib/unittest2/test/test_runner.py deleted file mode 100644 index 38b39efb00..0000000000 --- a/PyInstaller/lib/unittest2/test/test_runner.py +++ /dev/null @@ -1,129 +0,0 @@ -import pickle - -from cStringIO import StringIO -from unittest2.test.support import LoggingResult, OldTestResult - -import unittest2 - - -class Test_TextTestRunner(unittest2.TestCase): - """Tests for TextTestRunner.""" - - def test_init(self): - runner = unittest2.TextTestRunner() - self.assertFalse(runner.failfast) - self.assertFalse(runner.buffer) - self.assertEqual(runner.verbosity, 1) - self.assertTrue(runner.descriptions) - self.assertEqual(runner.resultclass, unittest2.TextTestResult) - - - def testBufferAndFailfast(self): - class Test(unittest2.TestCase): - def testFoo(self): - pass - result = unittest2.TestResult() - runner = unittest2.TextTestRunner(stream=StringIO(), failfast=True, - buffer=True) - # Use our result object - runner._makeResult = lambda: result - runner.run(Test('testFoo')) - - self.assertTrue(result.failfast) - self.assertTrue(result.buffer) - - def testRunnerRegistersResult(self): - class Test(unittest2.TestCase): - def testFoo(self): - pass - originalRegisterResult = unittest2.runner.registerResult - def cleanup(): - unittest2.runner.registerResult = originalRegisterResult - self.addCleanup(cleanup) - - result = unittest2.TestResult() - runner = unittest2.TextTestRunner(stream=StringIO()) - # Use our result object - runner._makeResult = lambda: result - - self.wasRegistered = 0 - def fakeRegisterResult(thisResult): - self.wasRegistered += 1 - self.assertEqual(thisResult, result) - unittest2.runner.registerResult = fakeRegisterResult - - runner.run(unittest2.TestSuite()) - self.assertEqual(self.wasRegistered, 1) - - def test_works_with_result_without_startTestRun_stopTestRun(self): - class OldTextResult(OldTestResult): - def __init__(self, *_): - super(OldTextResult, self).__init__() - separator2 = '' - def printErrors(self): - pass - - runner = unittest2.TextTestRunner(stream=StringIO(), - resultclass=OldTextResult) - runner.run(unittest2.TestSuite()) - - def test_startTestRun_stopTestRun_called(self): - class LoggingTextResult(LoggingResult): - separator2 = '' - def printErrors(self): - pass - - class LoggingRunner(unittest2.TextTestRunner): - def __init__(self, events): - super(LoggingRunner, self).__init__(StringIO()) - self._events = events - - def _makeResult(self): - return LoggingTextResult(self._events) - - events = [] - runner = LoggingRunner(events) - runner.run(unittest2.TestSuite()) - expected = ['startTestRun', 'stopTestRun'] - self.assertEqual(events, expected) - - def test_pickle_unpickle(self): - # Issue #7197: a TextTestRunner should be (un)pickleable. This is - # required by test_multiprocessing under Windows (in verbose mode). - import StringIO - # cStringIO objects are not pickleable, but StringIO objects are. - stream = StringIO.StringIO("foo") - runner = unittest2.TextTestRunner(stream) - for protocol in range(pickle.HIGHEST_PROTOCOL + 1): - s = pickle.dumps(runner, protocol=protocol) - obj = pickle.loads(s) - # StringIO objects never compare equal, a cheap test instead. - self.assertEqual(obj.stream.getvalue(), stream.getvalue()) - - def test_resultclass(self): - def MockResultClass(*args): - return args - STREAM = object() - DESCRIPTIONS = object() - VERBOSITY = object() - runner = unittest2.TextTestRunner(STREAM, DESCRIPTIONS, VERBOSITY, - resultclass=MockResultClass) - self.assertEqual(runner.resultclass, MockResultClass) - - expectedresult = (runner.stream, DESCRIPTIONS, VERBOSITY) - self.assertEqual(runner._makeResult(), expectedresult) - - - def test_oldresult(self): - class Test(unittest2.TestCase): - def testFoo(self): - pass - runner = unittest2.TextTestRunner(resultclass=OldTestResult, - stream=StringIO()) - # This will raise an exception if TextTestRunner can't handle old - # test result objects - runner.run(Test('testFoo')) - - -if __name__ == '__main__': - unittest2.main() \ No newline at end of file diff --git a/PyInstaller/lib/unittest2/test/test_setups.py b/PyInstaller/lib/unittest2/test/test_setups.py deleted file mode 100644 index 203f72ca2d..0000000000 --- a/PyInstaller/lib/unittest2/test/test_setups.py +++ /dev/null @@ -1,502 +0,0 @@ -import sys - -from cStringIO import StringIO - -import unittest2 -from unittest2.test.support import resultFactory - - -class TestSetups(unittest2.TestCase): - - def getRunner(self): - return unittest2.TextTestRunner(resultclass=resultFactory, - stream=StringIO()) - def runTests(self, *cases): - suite = unittest2.TestSuite() - for case in cases: - tests = unittest2.defaultTestLoader.loadTestsFromTestCase(case) - suite.addTests(tests) - - runner = self.getRunner() - - # creating a nested suite exposes some potential bugs - realSuite = unittest2.TestSuite() - realSuite.addTest(suite) - # adding empty suites to the end exposes potential bugs - suite.addTest(unittest2.TestSuite()) - realSuite.addTest(unittest2.TestSuite()) - return runner.run(realSuite) - - def test_setup_class(self): - class Test(unittest2.TestCase): - setUpCalled = 0 - def setUpClass(cls): - Test.setUpCalled += 1 - unittest2.TestCase.setUpClass() - setUpClass = classmethod(setUpClass) - def test_one(self): - pass - def test_two(self): - pass - - result = self.runTests(Test) - - self.assertEqual(Test.setUpCalled, 1) - self.assertEqual(result.testsRun, 2) - self.assertEqual(len(result.errors), 0) - - def test_teardown_class(self): - class Test(unittest2.TestCase): - tearDownCalled = 0 - def tearDownClass(cls): - Test.tearDownCalled += 1 - unittest2.TestCase.tearDownClass() - tearDownClass = classmethod(tearDownClass) - def test_one(self): - pass - def test_two(self): - pass - - result = self.runTests(Test) - - self.assertEqual(Test.tearDownCalled, 1) - self.assertEqual(result.testsRun, 2) - self.assertEqual(len(result.errors), 0) - - def test_teardown_class_two_classes(self): - class Test(unittest2.TestCase): - tearDownCalled = 0 - def tearDownClass(cls): - Test.tearDownCalled += 1 - unittest2.TestCase.tearDownClass() - tearDownClass = classmethod(tearDownClass) - def test_one(self): - pass - def test_two(self): - pass - - class Test2(unittest2.TestCase): - tearDownCalled = 0 - def tearDownClass(cls): - Test2.tearDownCalled += 1 - unittest2.TestCase.tearDownClass() - tearDownClass = classmethod(tearDownClass) - def test_one(self): - pass - def test_two(self): - pass - - result = self.runTests(Test, Test2) - - self.assertEqual(Test.tearDownCalled, 1) - self.assertEqual(Test2.tearDownCalled, 1) - self.assertEqual(result.testsRun, 4) - self.assertEqual(len(result.errors), 0) - - def test_error_in_setupclass(self): - class BrokenTest(unittest2.TestCase): - def setUpClass(cls): - raise TypeError('foo') - setUpClass = classmethod(setUpClass) - def test_one(self): - pass - def test_two(self): - pass - - result = self.runTests(BrokenTest) - - self.assertEqual(result.testsRun, 0) - self.assertEqual(len(result.errors), 1) - error, _ = result.errors[0] - self.assertEqual(str(error), - 'setUpClass (%s.BrokenTest)' % __name__) - - def test_error_in_teardown_class(self): - class Test(unittest2.TestCase): - tornDown = 0 - def tearDownClass(cls): - Test.tornDown += 1 - raise TypeError('foo') - tearDownClass = classmethod(tearDownClass) - def test_one(self): - pass - def test_two(self): - pass - - class Test2(unittest2.TestCase): - tornDown = 0 - def tearDownClass(cls): - Test2.tornDown += 1 - raise TypeError('foo') - tearDownClass = classmethod(tearDownClass) - def test_one(self): - pass - def test_two(self): - pass - - result = self.runTests(Test, Test2) - self.assertEqual(result.testsRun, 4) - self.assertEqual(len(result.errors), 2) - self.assertEqual(Test.tornDown, 1) - self.assertEqual(Test2.tornDown, 1) - - error, _ = result.errors[0] - self.assertEqual(str(error), - 'tearDownClass (%s.Test)' % __name__) - - def test_class_not_torndown_when_setup_fails(self): - class Test(unittest2.TestCase): - tornDown = False - def setUpClass(cls): - raise TypeError - setUpClass = classmethod(setUpClass) - def tearDownClass(cls): - Test.tornDown = True - raise TypeError('foo') - tearDownClass = classmethod(tearDownClass) - def test_one(self): - pass - - self.runTests(Test) - self.assertFalse(Test.tornDown) - - def test_class_not_setup_or_torndown_when_skipped(self): - class Test(unittest2.TestCase): - classSetUp = False - tornDown = False - def setUpClass(cls): - Test.classSetUp = True - setUpClass = classmethod(setUpClass) - def tearDownClass(cls): - Test.tornDown = True - tearDownClass = classmethod(tearDownClass) - def test_one(self): - pass - - Test = unittest2.skip("hop")(Test) - self.runTests(Test) - self.assertFalse(Test.classSetUp) - self.assertFalse(Test.tornDown) - - def test_setup_teardown_order_with_pathological_suite(self): - results = [] - - class Module1(object): - def setUpModule(): - results.append('Module1.setUpModule') - setUpModule = staticmethod(setUpModule) - def tearDownModule(): - results.append('Module1.tearDownModule') - tearDownModule = staticmethod(tearDownModule) - - class Module2(object): - def setUpModule(): - results.append('Module2.setUpModule') - setUpModule = staticmethod(setUpModule) - def tearDownModule(): - results.append('Module2.tearDownModule') - tearDownModule = staticmethod(tearDownModule) - - class Test1(unittest2.TestCase): - def setUpClass(cls): - results.append('setup 1') - setUpClass = classmethod(setUpClass) - def tearDownClass(cls): - results.append('teardown 1') - tearDownClass = classmethod(tearDownClass) - def testOne(self): - results.append('Test1.testOne') - def testTwo(self): - results.append('Test1.testTwo') - - class Test2(unittest2.TestCase): - def setUpClass(cls): - results.append('setup 2') - setUpClass = classmethod(setUpClass) - def tearDownClass(cls): - results.append('teardown 2') - tearDownClass = classmethod(tearDownClass) - def testOne(self): - results.append('Test2.testOne') - def testTwo(self): - results.append('Test2.testTwo') - - class Test3(unittest2.TestCase): - def setUpClass(cls): - results.append('setup 3') - setUpClass = classmethod(setUpClass) - def tearDownClass(cls): - results.append('teardown 3') - tearDownClass = classmethod(tearDownClass) - def testOne(self): - results.append('Test3.testOne') - def testTwo(self): - results.append('Test3.testTwo') - - Test1.__module__ = Test2.__module__ = 'Module' - Test3.__module__ = 'Module2' - sys.modules['Module'] = Module1 - sys.modules['Module2'] = Module2 - - first = unittest2.TestSuite((Test1('testOne'),)) - second = unittest2.TestSuite((Test1('testTwo'),)) - third = unittest2.TestSuite((Test2('testOne'),)) - fourth = unittest2.TestSuite((Test2('testTwo'),)) - fifth = unittest2.TestSuite((Test3('testOne'),)) - sixth = unittest2.TestSuite((Test3('testTwo'),)) - suite = unittest2.TestSuite((first, second, third, fourth, fifth, sixth)) - - runner = self.getRunner() - result = runner.run(suite) - self.assertEqual(result.testsRun, 6) - self.assertEqual(len(result.errors), 0) - - self.assertEqual(results, - ['Module1.setUpModule', 'setup 1', - 'Test1.testOne', 'Test1.testTwo', 'teardown 1', - 'setup 2', 'Test2.testOne', 'Test2.testTwo', - 'teardown 2', 'Module1.tearDownModule', - 'Module2.setUpModule', 'setup 3', - 'Test3.testOne', 'Test3.testTwo', - 'teardown 3', 'Module2.tearDownModule']) - - def test_setup_module(self): - class Module(object): - moduleSetup = 0 - def setUpModule(): - Module.moduleSetup += 1 - setUpModule = staticmethod(setUpModule) - - class Test(unittest2.TestCase): - def test_one(self): - pass - def test_two(self): - pass - Test.__module__ = 'Module' - sys.modules['Module'] = Module - - result = self.runTests(Test) - self.assertEqual(Module.moduleSetup, 1) - self.assertEqual(result.testsRun, 2) - self.assertEqual(len(result.errors), 0) - - def test_error_in_setup_module(self): - class Module(object): - moduleSetup = 0 - moduleTornDown = 0 - def setUpModule(): - Module.moduleSetup += 1 - raise TypeError('foo') - setUpModule = staticmethod(setUpModule) - def tearDownModule(): - Module.moduleTornDown += 1 - tearDownModule = staticmethod(tearDownModule) - - class Test(unittest2.TestCase): - classSetUp = False - classTornDown = False - def setUpClass(cls): - Test.classSetUp = True - setUpClass = classmethod(setUpClass) - def tearDownClass(cls): - Test.classTornDown = True - tearDownClass = classmethod(tearDownClass) - def test_one(self): - pass - def test_two(self): - pass - - class Test2(unittest2.TestCase): - def test_one(self): - pass - def test_two(self): - pass - Test.__module__ = 'Module' - Test2.__module__ = 'Module' - sys.modules['Module'] = Module - - result = self.runTests(Test, Test2) - self.assertEqual(Module.moduleSetup, 1) - self.assertEqual(Module.moduleTornDown, 0) - self.assertEqual(result.testsRun, 0) - self.assertFalse(Test.classSetUp) - self.assertFalse(Test.classTornDown) - self.assertEqual(len(result.errors), 1) - error, _ = result.errors[0] - self.assertEqual(str(error), 'setUpModule (Module)') - - def test_testcase_with_missing_module(self): - class Test(unittest2.TestCase): - def test_one(self): - pass - def test_two(self): - pass - Test.__module__ = 'Module' - sys.modules.pop('Module', None) - - result = self.runTests(Test) - self.assertEqual(result.testsRun, 2) - - def test_teardown_module(self): - class Module(object): - moduleTornDown = 0 - def tearDownModule(): - Module.moduleTornDown += 1 - tearDownModule = staticmethod(tearDownModule) - - class Test(unittest2.TestCase): - def test_one(self): - pass - def test_two(self): - pass - Test.__module__ = 'Module' - sys.modules['Module'] = Module - - result = self.runTests(Test) - self.assertEqual(Module.moduleTornDown, 1) - self.assertEqual(result.testsRun, 2) - self.assertEqual(len(result.errors), 0) - - def test_error_in_teardown_module(self): - class Module(object): - moduleTornDown = 0 - def tearDownModule(): - Module.moduleTornDown += 1 - raise TypeError('foo') - tearDownModule = staticmethod(tearDownModule) - - class Test(unittest2.TestCase): - classSetUp = False - classTornDown = False - def setUpClass(cls): - Test.classSetUp = True - setUpClass = classmethod(setUpClass) - def tearDownClass(cls): - Test.classTornDown = True - tearDownClass = classmethod(tearDownClass) - def test_one(self): - pass - def test_two(self): - pass - - class Test2(unittest2.TestCase): - def test_one(self): - pass - def test_two(self): - pass - Test.__module__ = 'Module' - Test2.__module__ = 'Module' - sys.modules['Module'] = Module - - result = self.runTests(Test, Test2) - self.assertEqual(Module.moduleTornDown, 1) - self.assertEqual(result.testsRun, 4) - self.assertTrue(Test.classSetUp) - self.assertTrue(Test.classTornDown) - self.assertEqual(len(result.errors), 1) - error, _ = result.errors[0] - self.assertEqual(str(error), 'tearDownModule (Module)') - - def test_skiptest_in_setupclass(self): - class Test(unittest2.TestCase): - def setUpClass(cls): - raise unittest2.SkipTest('foo') - setUpClass = classmethod(setUpClass) - def test_one(self): - pass - def test_two(self): - pass - - result = self.runTests(Test) - self.assertEqual(result.testsRun, 0) - self.assertEqual(len(result.errors), 0) - self.assertEqual(len(result.skipped), 1) - skipped = result.skipped[0][0] - self.assertEqual(str(skipped), 'setUpClass (%s.Test)' % __name__) - - def test_skiptest_in_setupmodule(self): - class Test(unittest2.TestCase): - def test_one(self): - pass - def test_two(self): - pass - - class Module(object): - def setUpModule(): - raise unittest2.SkipTest('foo') - setUpModule = staticmethod(setUpModule) - - Test.__module__ = 'Module' - sys.modules['Module'] = Module - - result = self.runTests(Test) - self.assertEqual(result.testsRun, 0) - self.assertEqual(len(result.errors), 0) - self.assertEqual(len(result.skipped), 1) - skipped = result.skipped[0][0] - self.assertEqual(str(skipped), 'setUpModule (Module)') - - def test_suite_debug_executes_setups_and_teardowns(self): - ordering = [] - - class Module(object): - def setUpModule(): - ordering.append('setUpModule') - setUpModule = staticmethod(setUpModule) - def tearDownModule(): - ordering.append('tearDownModule') - tearDownModule = staticmethod(tearDownModule) - - class Test(unittest2.TestCase): - def setUpClass(cls): - ordering.append('setUpClass') - setUpClass = classmethod(setUpClass) - def tearDownClass(cls): - ordering.append('tearDownClass') - tearDownClass = classmethod(tearDownClass) - def test_something(self): - ordering.append('test_something') - - Test.__module__ = 'Module' - sys.modules['Module'] = Module - - suite = unittest2.defaultTestLoader.loadTestsFromTestCase(Test) - suite.debug() - expectedOrder = ['setUpModule', 'setUpClass', 'test_something', 'tearDownClass', 'tearDownModule'] - self.assertEqual(ordering, expectedOrder) - - def test_suite_debug_propagates_exceptions(self): - class Module(object): - def setUpModule(): - if phase == 0: - raise Exception('setUpModule') - setUpModule = staticmethod(setUpModule) - def tearDownModule(): - if phase == 1: - raise Exception('tearDownModule') - tearDownModule = staticmethod(tearDownModule) - - class Test(unittest2.TestCase): - def setUpClass(cls): - if phase == 2: - raise Exception('setUpClass') - setUpClass = classmethod(setUpClass) - def tearDownClass(cls): - if phase == 3: - raise Exception('tearDownClass') - tearDownClass = classmethod(tearDownClass) - def test_something(self): - if phase == 4: - raise Exception('test_something') - - Test.__module__ = 'Module' - sys.modules['Module'] = Module - - _suite = unittest2.defaultTestLoader.loadTestsFromTestCase(Test) - suite = unittest2.TestSuite() - - # nesting a suite again exposes a bug in the initial implementation - suite.addTest(_suite) - messages = ('setUpModule', 'tearDownModule', 'setUpClass', 'tearDownClass', 'test_something') - for phase, msg in enumerate(messages): - self.assertRaisesRegexp(Exception, msg, suite.debug) diff --git a/PyInstaller/lib/unittest2/test/test_skipping.py b/PyInstaller/lib/unittest2/test/test_skipping.py deleted file mode 100644 index dfe3bef3cd..0000000000 --- a/PyInstaller/lib/unittest2/test/test_skipping.py +++ /dev/null @@ -1,142 +0,0 @@ -from unittest2.test.support import LoggingResult - -import unittest2 - - -class Test_TestSkipping(unittest2.TestCase): - - def test_skipping(self): - class Foo(unittest2.TestCase): - def test_skip_me(self): - self.skipTest("skip") - events = [] - result = LoggingResult(events) - test = Foo("test_skip_me") - test.run(result) - self.assertEqual(events, ['startTest', 'addSkip', 'stopTest']) - self.assertEqual(result.skipped, [(test, "skip")]) - - # Try letting setUp skip the test now. - class Foo(unittest2.TestCase): - def setUp(self): - self.skipTest("testing") - def test_nothing(self): pass - events = [] - result = LoggingResult(events) - test = Foo("test_nothing") - test.run(result) - self.assertEqual(events, ['startTest', 'addSkip', 'stopTest']) - self.assertEqual(result.skipped, [(test, "testing")]) - self.assertEqual(result.testsRun, 1) - - def test_skipping_decorators(self): - op_table = ((unittest2.skipUnless, False, True), - (unittest2.skipIf, True, False)) - for deco, do_skip, dont_skip in op_table: - class Foo(unittest2.TestCase): - def test_skip(self): - pass - test_skip = deco(do_skip, "testing")(test_skip) - - def test_dont_skip(self): - pass - test_dont_skip = deco(dont_skip, "testing")(test_dont_skip) - - test_do_skip = Foo("test_skip") - test_dont_skip = Foo("test_dont_skip") - suite = unittest2.TestSuite([test_do_skip, test_dont_skip]) - events = [] - result = LoggingResult(events) - suite.run(result) - self.assertEqual(len(result.skipped), 1) - expected = ['startTest', 'addSkip', 'stopTest', - 'startTest', 'addSuccess', 'stopTest'] - self.assertEqual(events, expected) - self.assertEqual(result.testsRun, 2) - self.assertEqual(result.skipped, [(test_do_skip, "testing")]) - self.assertTrue(result.wasSuccessful()) - - def test_skip_class(self): - class Foo(unittest2.TestCase): - def test_1(self): - record.append(1) - - # was originally a class decorator... - Foo = unittest2.skip("testing")(Foo) - record = [] - result = unittest2.TestResult() - test = Foo("test_1") - suite = unittest2.TestSuite([test]) - suite.run(result) - self.assertEqual(result.skipped, [(test, "testing")]) - self.assertEqual(record, []) - - def test_expected_failure(self): - class Foo(unittest2.TestCase): - def test_die(self): - self.fail("help me!") - test_die = unittest2.expectedFailure(test_die) - events = [] - result = LoggingResult(events) - test = Foo("test_die") - test.run(result) - self.assertEqual(events, - ['startTest', 'addExpectedFailure', 'stopTest']) - self.assertEqual(result.expectedFailures[0][0], test) - self.assertTrue(result.wasSuccessful()) - - def test_unexpected_success(self): - class Foo(unittest2.TestCase): - def test_die(self): - pass - test_die = unittest2.expectedFailure(test_die) - events = [] - result = LoggingResult(events) - test = Foo("test_die") - test.run(result) - self.assertEqual(events, - ['startTest', 'addUnexpectedSuccess', 'stopTest']) - self.assertFalse(result.failures) - self.assertEqual(result.unexpectedSuccesses, [test]) - self.assertTrue(result.wasSuccessful()) - - def test_skip_doesnt_run_setup(self): - class Foo(unittest2.TestCase): - wasSetUp = False - wasTornDown = False - def setUp(self): - Foo.wasSetUp = True - def tornDown(self): - Foo.wasTornDown = True - def test_1(self): - pass - test_1 = unittest2.skip('testing')(test_1) - - result = unittest2.TestResult() - test = Foo("test_1") - suite = unittest2.TestSuite([test]) - suite.run(result) - self.assertEqual(result.skipped, [(test, "testing")]) - self.assertFalse(Foo.wasSetUp) - self.assertFalse(Foo.wasTornDown) - - def test_decorated_skip(self): - def decorator(func): - def inner(*a): - return func(*a) - return inner - - class Foo(unittest2.TestCase): - def test_1(self): - pass - test_1 = decorator(unittest2.skip('testing')(test_1)) - - result = unittest2.TestResult() - test = Foo("test_1") - suite = unittest2.TestSuite([test]) - suite.run(result) - self.assertEqual(result.skipped, [(test, "testing")]) - - -if __name__ == '__main__': - unittest2.main() diff --git a/PyInstaller/lib/unittest2/test/test_suite.py b/PyInstaller/lib/unittest2/test/test_suite.py deleted file mode 100644 index 8afa199436..0000000000 --- a/PyInstaller/lib/unittest2/test/test_suite.py +++ /dev/null @@ -1,345 +0,0 @@ -from unittest2.test.support import EqualityMixin, LoggingResult - -import sys -import unittest2 - -if sys.version_info[:2] == (2,3): - from sets import Set as set - from sets import ImmutableSet as frozenset - -class Test(object): - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - def test_3(self): pass - def runTest(self): pass - -def _mk_TestSuite(*names): - return unittest2.TestSuite([Test.Foo(n) for n in names]) - - -class Test_TestSuite(unittest2.TestCase, EqualityMixin): - - ### Set up attributes needed by inherited tests - ################################################################ - - # Used by EqualityMixin.test_eq - eq_pairs = [(unittest2.TestSuite(), unittest2.TestSuite()), - (unittest2.TestSuite(), unittest2.TestSuite([])), - (_mk_TestSuite('test_1'), _mk_TestSuite('test_1'))] - - # Used by EqualityMixin.test_ne - ne_pairs = [(unittest2.TestSuite(), _mk_TestSuite('test_1')), - (unittest2.TestSuite([]), _mk_TestSuite('test_1')), - (_mk_TestSuite('test_1', 'test_2'), _mk_TestSuite('test_1', 'test_3')), - (_mk_TestSuite('test_1'), _mk_TestSuite('test_2'))] - - ################################################################ - ### /Set up attributes needed by inherited tests - - ### Tests for TestSuite.__init__ - ################################################################ - - # "class TestSuite([tests])" - # - # The tests iterable should be optional - def test_init__tests_optional(self): - suite = unittest2.TestSuite() - - self.assertEqual(suite.countTestCases(), 0) - - # "class TestSuite([tests])" - # ... - # "If tests is given, it must be an iterable of individual test cases - # or other test suites that will be used to build the suite initially" - # - # TestSuite should deal with empty tests iterables by allowing the - # creation of an empty suite - def test_init__empty_tests(self): - suite = unittest2.TestSuite([]) - - self.assertEqual(suite.countTestCases(), 0) - - # "class TestSuite([tests])" - # ... - # "If tests is given, it must be an iterable of individual test cases - # or other test suites that will be used to build the suite initially" - # - # TestSuite should allow any iterable to provide tests - def test_init__tests_from_any_iterable(self): - def tests(): - yield unittest2.FunctionTestCase(lambda: None) - yield unittest2.FunctionTestCase(lambda: None) - - suite_1 = unittest2.TestSuite(tests()) - self.assertEqual(suite_1.countTestCases(), 2) - - suite_2 = unittest2.TestSuite(suite_1) - self.assertEqual(suite_2.countTestCases(), 2) - - suite_3 = unittest2.TestSuite(set(suite_1)) - self.assertEqual(suite_3.countTestCases(), 2) - - # "class TestSuite([tests])" - # ... - # "If tests is given, it must be an iterable of individual test cases - # or other test suites that will be used to build the suite initially" - # - # Does TestSuite() also allow other TestSuite() instances to be present - # in the tests iterable? - def test_init__TestSuite_instances_in_tests(self): - def tests(): - ftc = unittest2.FunctionTestCase(lambda: None) - yield unittest2.TestSuite([ftc]) - yield unittest2.FunctionTestCase(lambda: None) - - suite = unittest2.TestSuite(tests()) - self.assertEqual(suite.countTestCases(), 2) - - ################################################################ - ### /Tests for TestSuite.__init__ - - # Container types should support the iter protocol - def test_iter(self): - test1 = unittest2.FunctionTestCase(lambda: None) - test2 = unittest2.FunctionTestCase(lambda: None) - suite = unittest2.TestSuite((test1, test2)) - - self.assertEqual(list(suite), [test1, test2]) - - # "Return the number of tests represented by the this test object. - # ...this method is also implemented by the TestSuite class, which can - # return larger [greater than 1] values" - # - # Presumably an empty TestSuite returns 0? - def test_countTestCases_zero_simple(self): - suite = unittest2.TestSuite() - - self.assertEqual(suite.countTestCases(), 0) - - # "Return the number of tests represented by the this test object. - # ...this method is also implemented by the TestSuite class, which can - # return larger [greater than 1] values" - # - # Presumably an empty TestSuite (even if it contains other empty - # TestSuite instances) returns 0? - def test_countTestCases_zero_nested(self): - class Test1(unittest2.TestCase): - def test(self): - pass - - suite = unittest2.TestSuite([unittest2.TestSuite()]) - - self.assertEqual(suite.countTestCases(), 0) - - # "Return the number of tests represented by the this test object. - # ...this method is also implemented by the TestSuite class, which can - # return larger [greater than 1] values" - def test_countTestCases_simple(self): - test1 = unittest2.FunctionTestCase(lambda: None) - test2 = unittest2.FunctionTestCase(lambda: None) - suite = unittest2.TestSuite((test1, test2)) - - self.assertEqual(suite.countTestCases(), 2) - - # "Return the number of tests represented by the this test object. - # ...this method is also implemented by the TestSuite class, which can - # return larger [greater than 1] values" - # - # Make sure this holds for nested TestSuite instances, too - def test_countTestCases_nested(self): - class Test1(unittest2.TestCase): - def test1(self): pass - def test2(self): pass - - test2 = unittest2.FunctionTestCase(lambda: None) - test3 = unittest2.FunctionTestCase(lambda: None) - child = unittest2.TestSuite((Test1('test2'), test2)) - parent = unittest2.TestSuite((test3, child, Test1('test1'))) - - self.assertEqual(parent.countTestCases(), 4) - - # "Run the tests associated with this suite, collecting the result into - # the test result object passed as result." - # - # And if there are no tests? What then? - def test_run__empty_suite(self): - events = [] - result = LoggingResult(events) - - suite = unittest2.TestSuite() - - suite.run(result) - - self.assertEqual(events, []) - - # "Note that unlike TestCase.run(), TestSuite.run() requires the - # "result object to be passed in." - def test_run__requires_result(self): - suite = unittest2.TestSuite() - - try: - suite.run() - except TypeError: - pass - else: - self.fail("Failed to raise TypeError") - - # "Run the tests associated with this suite, collecting the result into - # the test result object passed as result." - def test_run(self): - events = [] - result = LoggingResult(events) - - class LoggingCase(unittest2.TestCase): - def run(self, result): - events.append('run %s' % self._testMethodName) - - def test1(self): pass - def test2(self): pass - - tests = [LoggingCase('test1'), LoggingCase('test2')] - - unittest2.TestSuite(tests).run(result) - - self.assertEqual(events, ['run test1', 'run test2']) - - # "Add a TestCase ... to the suite" - def test_addTest__TestCase(self): - class Foo(unittest2.TestCase): - def test(self): pass - - test = Foo('test') - suite = unittest2.TestSuite() - - suite.addTest(test) - - self.assertEqual(suite.countTestCases(), 1) - self.assertEqual(list(suite), [test]) - - # "Add a ... TestSuite to the suite" - def test_addTest__TestSuite(self): - class Foo(unittest2.TestCase): - def test(self): pass - - suite_2 = unittest2.TestSuite([Foo('test')]) - - suite = unittest2.TestSuite() - suite.addTest(suite_2) - - self.assertEqual(suite.countTestCases(), 1) - self.assertEqual(list(suite), [suite_2]) - - # "Add all the tests from an iterable of TestCase and TestSuite - # instances to this test suite." - # - # "This is equivalent to iterating over tests, calling addTest() for - # each element" - def test_addTests(self): - class Foo(unittest2.TestCase): - def test_1(self): pass - def test_2(self): pass - - test_1 = Foo('test_1') - test_2 = Foo('test_2') - inner_suite = unittest2.TestSuite([test_2]) - - def gen(): - yield test_1 - yield test_2 - yield inner_suite - - suite_1 = unittest2.TestSuite() - suite_1.addTests(gen()) - - self.assertEqual(list(suite_1), list(gen())) - - # "This is equivalent to iterating over tests, calling addTest() for - # each element" - suite_2 = unittest2.TestSuite() - for t in gen(): - suite_2.addTest(t) - - self.assertEqual(suite_1, suite_2) - - # "Add all the tests from an iterable of TestCase and TestSuite - # instances to this test suite." - # - # What happens if it doesn't get an iterable? - def test_addTest__noniterable(self): - suite = unittest2.TestSuite() - - try: - suite.addTests(5) - except TypeError: - pass - else: - self.fail("Failed to raise TypeError") - - def test_addTest__noncallable(self): - suite = unittest2.TestSuite() - self.assertRaises(TypeError, suite.addTest, 5) - - def test_addTest__casesuiteclass(self): - suite = unittest2.TestSuite() - self.assertRaises(TypeError, suite.addTest, Test_TestSuite) - self.assertRaises(TypeError, suite.addTest, unittest2.TestSuite) - - def test_addTests__string(self): - suite = unittest2.TestSuite() - self.assertRaises(TypeError, suite.addTests, "foo") - - def test_function_in_suite(self): - def f(_): - pass - suite = unittest2.TestSuite() - suite.addTest(f) - - # when the bug is fixed this line will not crash - suite.run(unittest2.TestResult()) - - - def test_basetestsuite(self): - class Test(unittest2.TestCase): - wasSetUp = False - wasTornDown = False - def setUpClass(cls): - cls.wasSetUp = True - setUpClass = classmethod(setUpClass) - def tearDownClass(cls): - cls.wasTornDown = True - tearDownClass = classmethod(tearDownClass) - def testPass(self): - pass - def testFail(self): - fail - class Module(object): - wasSetUp = False - wasTornDown = False - def setUpModule(): - Module.wasSetUp = True - setUpModule = classmethod(setUpModule) - def tearDownModule(): - Module.wasTornDown = True - setUpModule = classmethod(tearDownModule) - - Test.__module__ = 'Module' - sys.modules['Module'] = Module - self.addCleanup(sys.modules.pop, 'Module') - - suite = unittest2.BaseTestSuite() - suite.addTests([Test('testPass'), Test('testFail')]) - self.assertEqual(suite.countTestCases(), 2) - - result = unittest2.TestResult() - suite.run(result) - self.assertFalse(Module.wasSetUp) - self.assertFalse(Module.wasTornDown) - self.assertFalse(Test.wasSetUp) - self.assertFalse(Test.wasTornDown) - self.assertEqual(len(result.errors), 1) - self.assertEqual(len(result.failures), 0) - self.assertEqual(result.testsRun, 2) - -if __name__ == '__main__': - unittest2.main() diff --git a/PyInstaller/lib/unittest2/test/test_unittest2_with.py b/PyInstaller/lib/unittest2/test/test_unittest2_with.py deleted file mode 100644 index e46d8f8ff1..0000000000 --- a/PyInstaller/lib/unittest2/test/test_unittest2_with.py +++ /dev/null @@ -1,130 +0,0 @@ - -import sys - -import unittest2 -from unittest2.test.support import OldTestResult, catch_warnings - -import warnings -# needed to enable the deprecation warnings -warnings.simplefilter('default') - -class TestWith(unittest2.TestCase): - """Tests that use the with statement live in this - module so that all other tests can be run with Python 2.4. - """ - - def runContext(self, ctxobj, func, *funcargs, **funckwargs): - bound_to = ctxobj.__enter__() - try: - func(bound_to, *funcargs, **funckwargs) - except Exception, e: - if not ctxobj.__exit__(*sys.exc_info()): - raise - else: - ctxobj.__exit__(None, None, None) - - def testAssertRaisesExcValue(self): - class ExceptionMock(Exception): - pass - - def Stub(foo): - raise ExceptionMock(foo) - v = "particular value" - - ctx = self.assertRaises(ExceptionMock) - self.runContext(ctx, lambda cm: Stub(v)) - e = ctx.exception - self.assertIsInstance(e, ExceptionMock) - self.assertEqual(e.args[0], v) - - def test_assert_dict_unicode_error(self): - def run(cm): - # This causes a UnicodeWarning due to its craziness - one = ''.join([chr(i) for i in range(255)]) - # this used to cause a UnicodeDecodeError constructing the failure msg - ar_cm = self.assertRaises(self.failureException) - innerrun =lambda x: self.assertDictContainsSubset({'foo': one}, {'foo': u'\uFFFD'}) - self.runContext(ar_cm, innerrun) - cm = catch_warnings(record=True) - self.runContext(cm, run) - - def test_formatMessage_unicode_error(self): - def run(cm): - # This causes a UnicodeWarning due to its craziness - one = ''.join([chr(i) for i in range(255)]) - # this used to cause a UnicodeDecodeError constructing msg - self._formatMessage(one, u'\uFFFD') - cm = catch_warnings(record=True) - self.runContext(cm, run) - - def assertOldResultWarning(self, test, failures): - def run(log): - result = OldTestResult() - test.run(result) - self.assertEqual(len(result.failures), failures) - warning, = log - self.assertIs(warning.category, DeprecationWarning) - cm = catch_warnings(record=True) - self.runContext(cm, run) - - def test_old_testresult(self): - class Test(unittest2.TestCase): - def testSkip(self): - self.skipTest('foobar') - def testExpectedFail(self): - raise TypeError - testExpectedFail = unittest2.expectedFailure(testExpectedFail) - def testUnexpectedSuccess(self): - pass - testUnexpectedSuccess = unittest2.expectedFailure(testUnexpectedSuccess) - - for test_name, should_pass in (('testSkip', True), - ('testExpectedFail', True), - ('testUnexpectedSuccess', False)): - test = Test(test_name) - self.assertOldResultWarning(test, int(not should_pass)) - - def test_old_testresult_setup(self): - class Test(unittest2.TestCase): - def setUp(self): - self.skipTest('no reason') - def testFoo(self): - pass - self.assertOldResultWarning(Test('testFoo'), 0) - - def test_old_testresult_class(self): - class Test(unittest2.TestCase): - def testFoo(self): - pass - Test = unittest2.skip('no reason')(Test) - self.assertOldResultWarning(Test('testFoo'), 0) - - def testPendingDeprecationMethodNames(self): - """Test fail* methods pending deprecation, they will warn in 3.2. - - Do not use these methods. They will go away in 3.3. - """ - def run(cm): - self.failIfEqual(3, 5) - self.failUnlessEqual(3, 3) - self.failUnlessAlmostEqual(2.0, 2.0) - self.failIfAlmostEqual(3.0, 5.0) - self.failUnless(True) - self.failUnlessRaises(TypeError, lambda _: 3.14 + u'spam') - self.failIf(False) - cm = catch_warnings(record=True) - self.runContext(cm,run) - - def testAssertDictContainsSubset_UnicodeVsStrValues(self): - def run(cm): - one = ''.join([chr(i) for i in range(255)]) - two = u'\uFFFD' - # this used to cause a UnicodeDecodeError when the values were compared under python 2.3, under - # python 2.6 it causes a UnicodeWarning so wrapping in catch_warnings context manager - self.assertRaises(self.failureException, self.assertDictContainsSubset, {'foo': one}, {'foo': two}) - cm = catch_warnings(record=True) - self.runContext(cm, run) - - -if __name__ == '__main__': - unittest2.main() diff --git a/PyInstaller/lib/unittest2/util.py b/PyInstaller/lib/unittest2/util.py index c45d008cc8..7f7cb70147 100644 --- a/PyInstaller/lib/unittest2/util.py +++ b/PyInstaller/lib/unittest2/util.py @@ -1,9 +1,47 @@ """Various utility functions.""" +from os.path import commonprefix + __unittest = True _MAX_LENGTH = 80 +_PLACEHOLDER_LEN = 12 +_MIN_BEGIN_LEN = 5 +_MIN_END_LEN = 5 +_MIN_COMMON_LEN = 5 +_MIN_DIFF_LEN = _MAX_LENGTH - \ + (_MIN_BEGIN_LEN + _PLACEHOLDER_LEN + _MIN_COMMON_LEN + + _PLACEHOLDER_LEN + _MIN_END_LEN) +assert _MIN_DIFF_LEN >= 0 + +def _shorten(s, prefixlen, suffixlen): + skip = len(s) - prefixlen - suffixlen + if skip > _PLACEHOLDER_LEN: + s = '%s[%d chars]%s' % (s[:prefixlen], skip, s[len(s) - suffixlen:]) + return s + +def _common_shorten_repr(*args): + args = tuple(map(safe_repr, args)) + maxlen = max(map(len, args)) + if maxlen <= _MAX_LENGTH: + return args + + prefix = commonprefix(args) + prefixlen = len(prefix) + + common_len = _MAX_LENGTH - \ + (maxlen - prefixlen + _MIN_BEGIN_LEN + _PLACEHOLDER_LEN) + if common_len > _MIN_COMMON_LEN: + assert _MIN_BEGIN_LEN + _PLACEHOLDER_LEN + _MIN_COMMON_LEN + \ + (maxlen - prefixlen) < _MAX_LENGTH + prefix = _shorten(prefix, _MIN_BEGIN_LEN, common_len) + return tuple(prefix + s[prefixlen:] for s in args) + + prefix = _shorten(prefix, _MIN_BEGIN_LEN, _MIN_COMMON_LEN) + return tuple(prefix + _shorten(s[prefixlen:], _MIN_DIFF_LEN, _MIN_END_LEN) + for s in args) + def safe_repr(obj, short=False): try: result = repr(obj) @@ -20,7 +58,7 @@ def safe_str(obj): return object.__str__(obj) def strclass(cls): - return "%s.%s" % (cls.__module__, cls.__name__) + return "%s.%s" % (cls.__module__, getattr(cls, '__qualname__', cls.__name__)) def sorted_list_difference(expected, actual): """Finds elements in only one or the other of two, sorted input lists. @@ -97,3 +135,9 @@ def unorderable_list_difference(expected, actual, ignore_duplicate=False): # anything left in actual is unexpected return missing, actual + + +def three_way_cmp(x, y): + """Return -1 if x < y, 0 if x == y and 1 if x > y""" + return (x > y) - (x < y) + diff --git a/PyInstaller/loader/__init__.py b/PyInstaller/loader/__init__.py index 8b13789179..792d600548 100644 --- a/PyInstaller/loader/__init__.py +++ b/PyInstaller/loader/__init__.py @@ -1 +1 @@ - +# diff --git a/PyInstaller/loader/_pyi_egg_install.py b/PyInstaller/loader/_pyi_egg_install.py index d4104443f5..48352a6c05 100644 --- a/PyInstaller/loader/_pyi_egg_install.py +++ b/PyInstaller/loader/_pyi_egg_install.py @@ -34,5 +34,10 @@ d = "eggs" d = os.path.join(sys._MEIPASS, d) -for fn in os.listdir(d): - sys.path.append(os.path.join(d, fn)) +# Test if the `eggs´ directory exists. This allows to +# opportunistically including this script into the packaged exe, even +# if no eggs as found when packaging the program. (Which may be a +# use-case, see issue #653. +if os.path.isdir(d): + for fn in os.listdir(d): + sys.path.append(os.path.join(d, fn)) diff --git a/PyInstaller/loader/pyi_archive.py b/PyInstaller/loader/pyi_archive.py index f7b110c379..49003d63c5 100644 --- a/PyInstaller/loader/pyi_archive.py +++ b/PyInstaller/loader/pyi_archive.py @@ -19,6 +19,10 @@ # See pyi_carchive.py for a more general archive (contains anything) # that can be understood by a C program. +# We MUST NOT use anything from __future__, because this will effect +# compilation in ZlibArchive.Add() below. While `compile()` has an +# argument `dont_inherit`, this is not supported in Python 2.7.9. +#from __future__ import print_function _verbose = 0 _listdir = None @@ -353,8 +357,8 @@ def add(self, entry): import os co = compile(txt, self.os.path.join(self.path, nm), 'exec') except SyntaxError, e: - print "Syntax error in", pth[:-1] - print e.args + print("Syntax error in " + pth[:-1]) + print(e.args) raise if self.crypted: obj = self.cipher.encrypt(self._mod_zlib.compress(marshal.dumps(co), self.LEVEL)) diff --git a/PyInstaller/loader/pyi_carchive.py b/PyInstaller/loader/pyi_carchive.py index 5385e9f0ef..525813bfc1 100644 --- a/PyInstaller/loader/pyi_carchive.py +++ b/PyInstaller/loader/pyi_carchive.py @@ -335,7 +335,7 @@ def add(self, entry): postfix = '' ulen = os.fstat(fh.fileno()).st_size except IOError: - print "Cannot find ('%s', '%s', %s, '%s')" % (nm, pathnm, flag, typcd) + print("Cannot find ('%s', '%s', %s, '%s')" % (nm, pathnm, flag, typcd)) raise where = self.lib.tell() diff --git a/PyInstaller/loader/rthooks/__init__.py b/PyInstaller/loader/rthooks/__init__.py index e69de29bb2..792d600548 100644 --- a/PyInstaller/loader/rthooks/__init__.py +++ b/PyInstaller/loader/rthooks/__init__.py @@ -0,0 +1 @@ +# diff --git a/PyInstaller/loader/rthooks/pyi_rth_qml.py b/PyInstaller/loader/rthooks/pyi_rth_qml.py index 56b484e539..46d506a119 100644 --- a/PyInstaller/loader/rthooks/pyi_rth_qml.py +++ b/PyInstaller/loader/rthooks/pyi_rth_qml.py @@ -20,7 +20,7 @@ d = os.path.abspath(os.path.join(sys._MEIPASS, "qml")) -print d +print(d) # We replace the QML_IMPORT_PATH variables because we want # Qt5 to load qml only from the path we set. diff --git a/PyInstaller/main.py b/PyInstaller/main.py index 084badff72..bc53100422 100644 --- a/PyInstaller/main.py +++ b/PyInstaller/main.py @@ -72,7 +72,7 @@ def run(pyi_args=sys.argv[1:], pyi_config=None): # Print program version and exit if opts.version: - print get_version() + print(get_version()) raise SystemExit(0) if not args: diff --git a/PyInstaller/makespec.py b/PyInstaller/makespec.py index 02fe14e7ed..2a87e774db 100644 --- a/PyInstaller/makespec.py +++ b/PyInstaller/makespec.py @@ -32,6 +32,7 @@ hiddenimports=%(hiddenimports)r, hookspath=%(hookspath)r, runtime_hooks=%(runtime_hooks)r, + excludes=%(excludes)s, cipher=block_cipher) pyz = PYZ(a.pure, cipher=block_cipher) @@ -55,6 +56,7 @@ hiddenimports=%(hiddenimports)r, hookspath=%(hookspath)r, runtime_hooks=%(runtime_hooks)r, + excludes=%(excludes)s, cipher=block_cipher) pyz = PYZ(a.pure, cipher=block_cipher) @@ -83,6 +85,7 @@ hiddenimports=%(hiddenimports)r, hookspath=%(hookspath)r, runtime_hooks=%(runtime_hooks)r, + excludes=%(excludes)s, cipher=block_cipher) pyz = PYZ(a.pure, cipher=block_cipher) @@ -213,6 +216,11 @@ def __add_options(parser): 'is executed before any other code or module ' 'to set up special features of the runtime environment. ' 'This option can be used multiple times.') + g.add_option('--exclude-module', dest='excludes', action='append', + help='Optional module or package (his Python names,' + 'not path names) that will be ignored (as though' + 'it was not found).' + 'This option can be used multiple times.') g.add_option('--key', dest='key', help='The key used to encrypt Python bytecode.') @@ -263,6 +271,12 @@ def __add_options(parser): "to the final executable if TYPE, NAME and LANGUAGE " "are omitted or specified as wildcard *." "This option can be used multiple times.") + g.add_option('--uac-admin', dest='uac_admin', action="store_true", default=False, + help='Using this option creates a Manifest ' + 'which will request elevation upon application restart.') + g.add_option('--uac-uiaccess', dest='uac_uiaccess', action="store_true", default=False, + help='Using this option allows an elevated application to ' + 'work with Remote Desktop.') g = parser.add_option_group('Mac OS X specific options') g.add_option('--osx-bundle-identifier', dest='bundle_identifier', @@ -276,8 +290,8 @@ def main(scripts, name=None, onefile=False, console=True, debug=False, strip=False, noupx=False, comserver=False, pathex=[], version_file=None, specpath=DEFAULT_SPECPATH, icon_file=None, manifest=None, resources=[], bundle_identifier=None, - hiddenimports=None, hookspath=None, key=None, runtime_hooks=[],**kwargs): - + hiddenimports=None, hookspath=None, key=None, runtime_hooks=[], + excludes=[], uac_admin=False, uac_uiaccess=False, **kwargs): # If appname is not specified - use the basename of the main script as name. if name is None: name = os.path.splitext(os.path.basename(scripts[0]))[0] @@ -300,10 +314,14 @@ def main(scripts, name=None, onefile=False, pathex = pathex[:] pathex.append(specpath) + # Handle additional EXE options. exe_options = '' if version_file: exe_options = "%s, version='%s'" % (exe_options, quote_win_filepath(version_file)) - + if uac_admin: + exe_options = "%s, uac_admin=%s" % (exe_options, 'True') + if uac_uiaccess: + exe_options = "%s, uac_uiaccess=%s" % (exe_options, 'True') if icon_file: # Icon file for Windows. # On Windows default icon is embedded in the bootloader executable. @@ -371,6 +389,8 @@ def main(scripts, name=None, onefile=False, 'hookspath': hookspath, # List with custom runtime hook files. 'runtime_hooks': runtime_hooks, + # List of modules/pakages to ignore. + 'excludes': excludes, # only Windows and Mac OS X distinguish windowed and console apps 'console': console, # Icon filename. Only OSX uses this item. diff --git a/PyInstaller/utils/__init__.py b/PyInstaller/utils/__init__.py index 8b13789179..792d600548 100644 --- a/PyInstaller/utils/__init__.py +++ b/PyInstaller/utils/__init__.py @@ -1 +1 @@ - +# diff --git a/PyInstaller/utils/git.py b/PyInstaller/utils/git.py index 0c34ec0147..d812433e4f 100644 --- a/PyInstaller/utils/git.py +++ b/PyInstaller/utils/git.py @@ -35,4 +35,4 @@ def get_repo_revision(): if __name__ == '__main__': - print get_repo_revision() + print(get_repo_revision()) diff --git a/PyInstaller/utils/versioninfo.py b/PyInstaller/utils/versioninfo.py index d659a64d28..7c31239881 100644 --- a/PyInstaller/utils/versioninfo.py +++ b/PyInstaller/utils/versioninfo.py @@ -82,14 +82,14 @@ def pefile_read_version(filename): #ffi = pe.VS_FIXEDFILEINFO #vers['FileVersion'] = (ffi.FileVersionMS >> 16, ffi.FileVersionMS & 0xFFFF, ffi.FileVersionLS >> 16, ffi.FileVersionLS & 0xFFFF) #vers['ProductVersion'] = (ffi.ProductVersionMS >> 16, ffi.ProductVersionMS & 0xFFFF, ffi.ProductVersionLS >> 16, ffi.ProductVersionLS & 0xFFFF) - #print pe.VS_FIXEDFILEINFO.FileVersionMS + #print(pe.VS_FIXEDFILEINFO.FileVersionMS) # TODO Only first available language is used for now. #vers = pe.FileInfo[0].StringTable[0].entries from pprint import pprint pprint(pe.VS_FIXEDFILEINFO) - print dir(pe.VS_FIXEDFILEINFO) - print repr(pe.VS_FIXEDFILEINFO) - print pe.dump_info() + print(dir(pe.VS_FIXEDFILEINFO)) + print(repr(pe.VS_FIXEDFILEINFO)) + print(pe.dump_info()) return vers diff --git a/PyInstaller/utils/winmanifest.py b/PyInstaller/utils/winmanifest.py index f4b4f7b372..b0915b994c 100644 --- a/PyInstaller/utils/winmanifest.py +++ b/PyInstaller/utils/winmanifest.py @@ -969,7 +969,7 @@ def UpdateManifestResourcesFromXMLFile(dstpath, srcpath, names=None, languages or [0, "*"]) -def create_manifest(filename, manifest, console): +def create_manifest(filename, manifest, console, uac_admin=False, uac_uiaccess=False): """ Create assembly manifest. """ @@ -1003,6 +1003,10 @@ def create_manifest(filename, manifest, console): version=(6, 0, 0, 0), publicKeyToken="6595b64144ccf1df") ) + if uac_admin: + manifest.requestedExecutionLevel = 'requireAdministrator' + if uac_uiaccess: + manifest.uiAccess = True manifest.writeprettyxml(filename) return manifest diff --git a/bootloader/README.txt b/bootloader/README.txt index fdc764aaad..33f0bcd193 100644 --- a/bootloader/README.txt +++ b/bootloader/README.txt @@ -17,3 +17,12 @@ Directory Structure for Windows. * images PyInstaller icons for Windows bootloaders and the .app bundle on Mac OS X. + +Build instructions +---------------------- + +See . + +In short:: + + ./waf configure build install diff --git a/bootloader/common/pyi_launch.c b/bootloader/common/pyi_launch.c index b5f0ff0c02..012cf9e3dd 100644 --- a/bootloader/common/pyi_launch.c +++ b/bootloader/common/pyi_launch.c @@ -334,6 +334,7 @@ int pyi_pylib_run_scripts(ARCHIVE_STATUS *status) for full compatibility with normal execution. */ strcpy(buf, ptoc->name); strcat(buf, ".py"); + VS("LOADER: Running %s\n", buf); __file__ = PI_PyString_FromStringAndSize(buf, strlen(buf)); PI_PyObject_SetAttrString(__main__, "__file__", __file__); Py_DECREF(__file__); diff --git a/bootloader/wscript b/bootloader/wscript index ba88f1883c..ef320f7e94 100644 --- a/bootloader/wscript +++ b/bootloader/wscript @@ -139,7 +139,7 @@ def configure(conf): # Manifest file will be added in the phase of packaging python application. conf.env.MSVC_MANIFEST = False except Exception, e: - print e + print(e) Utils.pprint('RED', str(e)) Utils.pprint('RED', 'GCC (MinGW) or MSVC compiler not found.') exit(1) diff --git a/develutils/find-empty-hooks.py b/develutils/find-empty-hooks.py new file mode 100755 index 0000000000..97b3af9599 --- /dev/null +++ b/develutils/find-empty-hooks.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +#----------------------------------------------------------------------------- +# Copyright (c) 2013, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- +""" +Prints a list of (maybe) empty hooks. + +A hook is listed here if it does not define any of the meaningful +names (eg. hiddenimports). So beside empty hooks, this will print +hooks which import these name from a shared hook (like PIL.Image) or +are calling functions in hookutils. + +Proposed usage:: + + develutils/find-empty-hooks.py | sort | xargs emacs + # then in emacs, remove all content in hook which are realy empty + # Now delete all hook-file less then 2 bytes in size: + find PyInstaller/hooks/ -size -2c -print -delete + +""" + +from __future__ import print_function + +import glob +import os +import sys +import imp + +# Expand PYTHONPATH with PyInstaller package to support running without +# installation. +pyi_home = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..') +sys.path.insert(0, pyi_home) + +import PyInstaller.hooks + +hookspath = os.path.dirname(os.path.abspath(PyInstaller.hooks.__file__)) + +EXPECTED_NAMES = set('hook hiddenimports attrs binaries datas'.split()) + +for hookfilename in glob.glob(os.path.join(hookspath, 'hook-*.py')): + with open(hookfilename) as fh: + source = fh.read() + mod = compile(source, hookfilename, 'exec') + co_names = set(mod.co_names) + if co_names.isdisjoint(EXPECTED_NAMES): + # none of the meaningful names in a hook is here + print(os.path.relpath(hookfilename, os.getcwd())) diff --git a/doc/pyi-makeCOMServer.html b/doc/pyi-make_comserver.html similarity index 100% rename from doc/pyi-makeCOMServer.html rename to doc/pyi-make_comserver.html diff --git a/doc/source/Makefile b/doc/source/Makefile index 05fcc059de..abf873012a 100644 --- a/doc/source/Makefile +++ b/doc/source/Makefile @@ -14,7 +14,7 @@ all: doc: html pdf man cleanlogs @echo "Documentation generated: Please see ../*.html, ../*.pdf and ../*.1 for files" -manpages := pyinstaller pyi-makespec pyi-build pyi-makeCOMServer +manpages := pyinstaller pyi-makespec pyi-build pyi-make_comserver html: ../Manual.html $(foreach manpage,${manpages},../${manpage}.html) pdf: ../Manual.pdf @@ -40,22 +40,22 @@ Manual.tex: Manual.rst _definitions.txt rm ../_definitions.txt _definitions.txt: - # _definitions.txt is overwritten. - echo '.. -*- mode: rst ; ispell-local-dictionary: "american" -*-' > $@ - echo '' >> $@ # Empty line. - # Append other lines. - echo '.. _PyInstaller: http://www.pyinstaller.org' >> $@ - echo '' >> $@ - echo '.. |Homepage| replace:: http://www.pyinstaller.org' >> $@ - echo '.. |PyInstaller| replace:: `PyInstaller`' >> $@ - # run `pyinstaller.py -v` to get the version - echo '.. |Version| replace::' `python ../../pyinstaller.py -v` >> $@ - echo '.. |PyInstallerVersion| replace:: PyInstaller |Version|' >> $@ - echo '.. |install_path| replace:: /OBSOLETE-REMOVE/' >> $@ - # folder name of package after download and unzip - echo '.. |unzipped_download| replace:: ``pyinstaller``' >> $@ - # how we punctuate boot loader as a proper noun "the bootloader" - echo '.. |bootloader| replace:: bootloader' >> $@ + @echo Overwritung '_definitions.txt' + @echo '.. -*- mode: rst ; ispell-local-dictionary: "american" -*-' > $@ + @echo '' >> $@ # Empty line. + @# Append other lines. + @echo '.. _PyInstaller: http://www.pyinstaller.org' >> $@ + @echo '' >> $@ + @echo '.. |Homepage| replace:: http://www.pyinstaller.org' >> $@ + @echo '.. |PyInstaller| replace:: `PyInstaller`' >> $@ + @# run `pyinstaller.py -v` to get the version + @echo '.. |Version| replace::' `python ../../pyinstaller.py -v` >> $@ + @echo '.. |PyInstallerVersion| replace:: PyInstaller |Version|' >> $@ + @echo '.. |install_path| replace:: /OBSOLETE-REMOVE/' >> $@ + @# folder name of package after download and unzip + @echo '.. |unzipped_download| replace:: ``pyinstaller``' >> $@ + @# how we punctuate boot loader as a proper noun "the bootloader" + @echo '.. |bootloader| replace:: bootloader' >> $@ clean: @echo "make cleanall ===> To clean everything" diff --git a/doc/source/Manual.rst b/doc/source/Manual.rst index 03a3b64722..21a860cdae 100644 --- a/doc/source/Manual.rst +++ b/doc/source/Manual.rst @@ -7,7 +7,7 @@ PyInstaller Manual :Version: |PyInstallerVersion| :Homepage: |Homepage| :Author: David Cortesi (based on structure by Giovanni Bajo & William Caban (based on Gordon McMillan's manual)) -:Contact: rasky@develer.com +:Contact: pyinstaller@googlegroups.com :Revision: $Rev$ :Source URL: $HeadURL$ :Copyright: This document has been placed in the public domain. @@ -531,7 +531,7 @@ General Options Do *not* include Python module ``codecs`` and other Unicode support. The default is to include them if available, whether the script imports them or not. ---distpath=path_to_executable, -o path_to_executable +--distpath=path_to_executable Specify where to put the bundled app. The default is a ``dist`` folder in the same folder as the first script. @@ -589,6 +589,11 @@ Options for Finding Imported Modules and Libraries are discussed under `Changing Runtime Behavior`_ below. This option may be given more than once. +--exclude-module=MODULENAME + Optional module or package name (his Python name, + not path names) that will be ignored. + This option can be used multiple times. + Options for the Executable Output --------------------------------------- @@ -666,6 +671,13 @@ Options for Windows apps if *TYPE*, *NAME* and *LANGUAGE* are omitted or given as ``*``. This option an be used more than once to specify more resources. +--uac-admin + Using this option creates a Manifest which will request elevation upon + application restart. + +--uac-uiaccess + Using this option allows an elevated application to work with Remote Desktop. + Options for Mac OS X apps --------------------------- diff --git a/doc/source/pyi-build.rst b/doc/source/pyi-build.rst index eb4886fb2a..a6408cd98a 100644 --- a/doc/source/pyi-build.rst +++ b/doc/source/pyi-build.rst @@ -43,14 +43,23 @@ OPTIONS ======== -h, --help show this help message and exit ---buildpath=BUILDPATH - Buildpath (default: - SPECPATH/build/pyi.TARGET_PLATFORM/SPECNAME) --y, --noconfirm Remove output directory (default: SPECPATH/dist) - without confirmation ---upx-dir=UPX_DIR Directory containing UPX (default: search in path). ---log-level=LOGLEVEL Log level for Build.py (default: INFO, choose one - of DEBUG, INFO, WARN, ERROR, CRITICAL) +--distpath=DIR Where to put the bundled app (default: + /home/hartmut/projekte/software/pyinstaller/dist) +--workpath=WORKPATH Where to put all the temporary work files, .log, .pyz + and etc. (default: + /home/hartmut/projekte/software/pyinstaller/build) +-y, --noconfirm Replace output directory (default: + SPECPATH/dist/SPECNAME) without asking for + confirmation +--upx-dir=UPX_DIR Path to UPX utility (default: search the execution + path) +-a, --ascii Do not include unicode encoding support (default: + included if available) +--clean Clean PyInstaller cache and remove temporary files + before building. +--log-level=LOGLEVEL Amount of detail in build-time console messages + (default: INFO, choose one of DEBUG, INFO, WARN, + ERROR, CRITICAL) SEE ALSO diff --git a/doc/source/pyi-makeCOMServer.rst b/doc/source/pyi-make_comserver.rst similarity index 95% rename from doc/source/pyi-makeCOMServer.rst rename to doc/source/pyi-make_comserver.rst index 4bd7135331..e6b698e094 100644 --- a/doc/source/pyi-makeCOMServer.rst +++ b/doc/source/pyi-make_comserver.rst @@ -34,6 +34,8 @@ Please see the PyInstaller Manual for more information. OPTIONS ======== +-h, --help show this help message and exit + --debug Use the verbose version of the executable. diff --git a/doc/source/pyi-makespec.rst b/doc/source/pyi-makespec.rst index fe2d34924f..24f87dbddb 100644 --- a/doc/source/pyi-makespec.rst +++ b/doc/source/pyi-makespec.rst @@ -49,81 +49,110 @@ OPTIONS General Options -------------------- --h, --help show this help message and exit - ---log-level=LOGLEVEL Log level for MakeSpec.py (default: INFO, choose - one of DEBUG, INFO, WARN, ERROR, CRITICAL) +-h, --help show this help message and exit +--log-level=LOGLEVEL Amount of detail in build-time console messages + (default: INFO, choose one of DEBUG, INFO, WARN, + ERROR, CRITICAL) What to generate ------------------ --F, --onefile create a single file deployment --D, --onedir create a single directory deployment (default) --o DIR, --out=DIR generate the spec file in the specified directory - (default: current directory) +-F, --onefile Create a one-file bundled executable. +-D, --onedir Create a one-folder bundle containing an executable + (default) +--specpath=DIR Folder to store the generated spec file (default: + current directory) -n NAME, --name=NAME - name to assign to the project (default: first script's - basename) + Name to assign to the bundled app and spec file + (default: first script's basename) What to bundle, where to search --------------------------------- -p DIR, --paths=DIR - set base path for import (like using PYTHONPATH). - Multiple directories are allowed, separating them with - ':', or using this option multiple times ---additional-hooks-dir=HOOKSPATH - additional path to search for hooks (may be given - several times) --a, --ascii do NOT include unicode encodings (default: included if - available) + A path to search for imports (like using PYTHONPATH). + Multiple paths are allowed, separated by ':', or use + this option multiple times --hidden-import=MODULENAME - import hidden in the script(s). This option can be - used multiple times. + Name an import not visible in the code of the + script(s). This option can be used multiple times. +--exclude-module=MODULENAME + Optional module or package name (his Python name, + not path names) that will be ignored (as though + it was not found). + This option can be used multiple times. +--additional-hooks-dir=HOOKSPATH + An additional path to search for hooks. This option + can be used multiple times. +--runtime-hook=RUNTIME_HOOKS + Path to a custom runtime hook file. A runtime hook is + code that is bundled with the executable and is + executed before any other code or module to set up + special features of the runtime environment. This + option can be used multiple times. +--key=KEY The key used to encrypt Python bytecode. How to generate ------------------- --d, --debug use the debug (verbose) build of the executable for - packaging. This will make the packaged executable be - more verbose when run. --s, --strip strip the exe and shared libs (don't try this on - Windows) --X, --upx use UPX if available (works differently between - Windows and \*nix) +-d, --debug Tell the bootloader to issue progress messages while + initializing and starting the bundled app. Used to + diagnose problems with missing imports. +-s, --strip Apply a symbol-table strip to the executable and + shared libs (not recommended for Windows) +--noupx Do not use UPX even if it is available (works + differently between Windows and *nix) -Windows specific options -------------------------- +Windows and Mac OS X specific options +-------------------------------------------- -c, --console, --nowindowed - use a console subsystem executable (Windows only) - (default) + Open a console window for standard i/o (default) -w, --windowed, --noconsole - use a Windows subsystem executable (Windows only) --v FILE, --version=FILE + Windows and Mac OS X: do not provide a console window + for standard i/o. On Mac OS X this also triggers + building an OS X .app bundle.This option is ignored in + *NIX systems. +-i FILE.ico or FILE.exe,ID or FILE.icns, --icon=FILE.ico or FILE.exe,ID or F + FILE.ico: apply that icon to a Windows executable. + FILE.exe,ID, extract the icon with ID from an exe. + FILE.icns: apply the icon to the .app bundle on Mac OS + X + +Windows specific options +------------------------- +--version-file=FILE add a version resource from FILE to the exe - (Windows only) --i ICON_or_FILE_ID, --icon=ICON_or_FILE_ID - If file is an .ico file, add the icon to the final - executable. Otherwise, the syntax 'file.exe,id' to - extract the icon with the specified id from file.exe - and add it to the final executable --m FILE_or_XML, --manifest=FILE_or_XML - add manifest FILE or XML to the exe (Windows only) --r RESOURCE, --resource=RESOURCE - RESOURCE is of format FILE[,TYPE[,NAME[,LANGUAGE]]]. - - Add or update resource of the given type, name and - language from FILE to the final executable. FILE - can be a data file or an exe/dll. For data files, - atleast TYPE and NAME need to be specified, - LANGUAGE defaults to 0 or may be specified as - wildcard \* to update all resources of the given - TYPE and NAME. For exe/dll files, all resources - from FILE will be added/updated to the final - executable if TYPE, NAME and LANGUAGE are omitted - or specified as wildcard \*. Multiple resources - are allowed, using this option multiple times. +-m FILE or XML, --manifest=FILE or XML + add manifest FILE or XML to the exe +-r FILE[,TYPE[,NAME[,LANGUAGE]]], --resource=FILE[,TYPE[,NAME[,LANGUAGE]]] + Add or update a resource of the given type, name and + language from FILE to a Windows executable. FILE can + be a data file or an exe/dll. For data files, at least + TYPE and NAME must be specified. LANGUAGE defaults to + 0 or may be specified as wildcard * to update all + resources of the given TYPE and NAME. For exe/dll + files, all resources from FILE will be added/updated + to the final executable if TYPE, NAME and LANGUAGE are + omitted or specified as wildcard *.This option can be + used multiple times. +--uac-admin Using this option creates a Manifest which will request + elevation upon application restart. +--uac-uiaccess Using this option allows an elevated application to + work with Remote Desktop. + + +Mac OS X specific options +------------------------- + +--osx-bundle-identifier=BUNDLE_IDENTIFIER + Mac OS X .app bundle identifier is used as the default + unique program name for code signing purposes. The + usual form is a hierarchical name in reverse DNS + notation. For example: + com.mycompany.department.appname (default: first + script's basename) + SEE ALSO ============= diff --git a/old/e2etests/win32/NextID.py b/old/e2etests/win32/NextID.py index ed74f4fd33..106b98a955 100644 --- a/old/e2etests/win32/NextID.py +++ b/old/e2etests/win32/NextID.py @@ -72,7 +72,7 @@ def UnRegisterNextID(): elif "/register" in sys.argv: RegisterNextID() else: - print "running as server" + print("running as server") import win32com.server.localserver win32com.server.localserver.main() raw_input("Press any key...") diff --git a/old/e2etests/win32/testEnsureDispatch.py b/old/e2etests/win32/testEnsureDispatch.py index 6476599d84..de2d933752 100644 --- a/old/e2etests/win32/testEnsureDispatch.py +++ b/old/e2etests/win32/testEnsureDispatch.py @@ -4,6 +4,6 @@ import win32com.client.gencache x = win32com.client.gencache.EnsureDispatch('ADOR.Recordset') -print x +print(x) x = None #raw_input("Press any key to continue...") diff --git a/old/e2etests/win32/testMSOffice.py b/old/e2etests/win32/testMSOffice.py index d0731d8652..5a6e76c483 100644 --- a/old/e2etests/win32/testMSOffice.py +++ b/old/e2etests/win32/testMSOffice.py @@ -38,13 +38,13 @@ def TestWord(): # Office 97 - _totally_ different object model! try: # NOTE - using "client.Dispatch" would return an msword8.py instance! - print "Starting Word 8 for dynamic test" + print("Starting Word 8 for dynamic test") word = win32com.client.dynamic.Dispatch("Word.Application") TestWord8(word) word = None # Now we will test Dispatch without the new "lazy" capabilities - print "Starting Word 8 for non-lazy dynamic test" + print("Starting Word 8 for non-lazy dynamic test") dispatch = win32com.client.dynamic._GetGoodDispatch("Word.Application") typeinfo = dispatch.GetTypeInfo() attr = typeinfo.GetTypeAttr() @@ -54,12 +54,12 @@ def TestWord(): TestWord8(word) except pythoncom.com_error: - print "Starting Word 7 for dynamic test" + print("Starting Word 7 for dynamic test") word = win32com.client.Dispatch("Word.Basic") TestWord7(word) try: - print "Starting MSWord for generated test" + print("Starting MSWord for generated test") # Typelib, lcid, major and minor for the typelib try: o = gencache.EnsureModule("{00020905-0000-0000-C000-000000000046}", 1033, 8, 0, bForDemand=1) @@ -70,7 +70,7 @@ def TestWord(): word = win32com.client.Dispatch("Word.Application.8") TestWord8(word) except ImportError, details: - print "Can not test MSWord8 -", details + print("Can not test MSWord8 -", details) def TestWord7(word): word.FileNew() @@ -107,7 +107,7 @@ def TestWord8OldStyle(): try: import win32com.test.Generated4Test.msword8 except ImportError: - print "Can not do old style test" + print("Can not do old style test") def TextExcel(xl): @@ -163,12 +163,12 @@ def TestAll(): try: TestWord() - print "Starting Excel for Dynamic test..." + print("Starting Excel for Dynamic test...") xl = win32com.client.dynamic.Dispatch("Excel.Application") TextExcel(xl) try: - print "Starting Excel 8 for generated excel8.py test..." + print("Starting Excel 8 for generated excel8.py test...") try: mod = gencache.EnsureModule("{00020813-0000-0000-C000-000000000046}", 0, 1, 2, bForDemand=1) except TypeError: @@ -176,19 +176,19 @@ def TestAll(): xl = win32com.client.Dispatch("Excel.Application") TextExcel(xl) except ImportError: - print "Could not import the generated Excel 97 wrapper" + print("Could not import the generated Excel 97 wrapper") try: import xl5en32 mod = gencache.EnsureModule("{00020813-0000-0000-C000-000000000046}", 9, 1, 0) xl = win32com.client.Dispatch("Excel.Application.5") - print "Starting Excel 95 for makepy test..." + print("Starting Excel 95 for makepy test...") TextExcel(xl) except ImportError: - print "Could not import the generated Excel 95 wrapper" + print("Could not import the generated Excel 95 wrapper") except KeyboardInterrupt: - print "*** Interrupted MSOffice test ***" + print("*** Interrupted MSOffice test ***") except: traceback.print_exc() diff --git a/old/e2etests/win32/testcomext.py b/old/e2etests/win32/testcomext.py index 1e186ba2f8..98777ff5f2 100644 --- a/old/e2etests/win32/testcomext.py +++ b/old/e2etests/win32/testcomext.py @@ -15,6 +15,9 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +from __future__ import print_function + from win32com.shell import shell import win32api import pythoncom @@ -39,7 +42,7 @@ def CreateShortCut(Path, Target,Arguments = "", StartIn = "", Icon = ("",0), Des # Save the link itself. persist.Save(Path, 1) - print "Saved to", Path + print("Saved to", Path) if __name__ == "__main__": try: @@ -55,7 +58,7 @@ def CreateShortCut(Path, Target,Arguments = "", StartIn = "", Icon = ("",0), Des CreateShortCut(Path,Target,Arguments,StartIn,Icon,Description) except Exception, e: - print "Failed!", e + print("Failed!", e) import traceback traceback.print_exc() raw_input("Press any key to continue...") diff --git a/tests/basic/pkg1/a.py b/tests/basic/pkg1/a.py index d6f68e8e04..c43487ee55 100644 --- a/tests/basic/pkg1/a.py +++ b/tests/basic/pkg1/a.py @@ -11,5 +11,5 @@ """ pkg1.a.py is never imported """ -print " %s" % __doc__ -print " %s %s" % (__name__, __file__) +print(" %s" % __doc__) +print(" %s %s" % (__name__, __file__)) diff --git a/tests/basic/pkg2/a.py b/tests/basic/pkg2/a.py index 5856a2cbc9..8e2a825c71 100644 --- a/tests/basic/pkg2/a.py +++ b/tests/basic/pkg2/a.py @@ -13,4 +13,4 @@ def a_func(): return "a_func from pkg2.a" -print "pkg2.a imported" +print("pkg2.a imported") diff --git a/tests/basic/pkg3/__init__.py b/tests/basic/pkg3/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/basic/pkg3/pkg_resources-data.txt b/tests/basic/pkg3/pkg_resources-data.txt deleted file mode 100644 index 85c42d638f..0000000000 --- a/tests/basic/pkg3/pkg_resources-data.txt +++ /dev/null @@ -1 +0,0 @@ -This is data text for testing freezing pkg_resources module. diff --git a/tests/basic/test_celementtree.py b/tests/basic/test_celementtree.py index 28da1dd6d1..8443b94425 100644 --- a/tests/basic/test_celementtree.py +++ b/tests/basic/test_celementtree.py @@ -14,7 +14,7 @@ from copy import copy, deepcopy import _elementtree import xml.etree.cElementTree -print dir(xml.etree.cElementTree) +print(dir(xml.etree.cElementTree)) """ diff --git a/tests/basic/test_time.py b/tests/basic/test_time.py index 16944269bd..000f8aa26b 100644 --- a/tests/basic/test_time.py +++ b/tests/basic/test_time.py @@ -9,4 +9,4 @@ import time -print time.strptime(time.ctime()) +print(time.strptime(time.ctime())) diff --git a/tests/import/hook_without_hook_for_package-hooks/hook-hook_without_hook_for_package.sub1.py b/tests/import/hook_without_hook_for_package-hooks/hook-hook_without_hook_for_package.sub1.py new file mode 100644 index 0000000000..e326d6bdcf --- /dev/null +++ b/tests/import/hook_without_hook_for_package-hooks/hook-hook_without_hook_for_package.sub1.py @@ -0,0 +1,20 @@ +hiddenimports = ['hook_without_hook_for_package.sub1.sub11'] + +NAME = 'hook_without_hook_for_package.sub1' + +# self-test for this test-case: +import PyInstaller.hooks +import imp +# 1. ensure self-test is working by searching for _this_ hook +hookmodnm = 'hook-' + NAME +assert imp.find_module(hookmodnm, PyInstaller.hooks.__path__) is not None +# 2. The actual self-test: there must be no hook for the parent module +hookmodnm = 'hook-hook_without_hook_for_package' +try: + imp.find_module(hookmodnm, PyInstaller.hooks.__path__) + raise Exception('Self-test of hook %s failed: hook for parent exists' + % NAME) +except ImportError, e: + if not e.args[0].endswith(' '+hookmodnm): + raise Exception('Self-test of hook %s failed: hook for parent exists ' + 'and has import errors.' % NAME) diff --git a/tests/import/hook_without_hook_for_package/__init__.py b/tests/import/hook_without_hook_for_package/__init__.py new file mode 100644 index 0000000000..792d600548 --- /dev/null +++ b/tests/import/hook_without_hook_for_package/__init__.py @@ -0,0 +1 @@ +# diff --git a/tests/import/hook_without_hook_for_package/sub1/__init__.py b/tests/import/hook_without_hook_for_package/sub1/__init__.py new file mode 100644 index 0000000000..5c6febcf3f --- /dev/null +++ b/tests/import/hook_without_hook_for_package/sub1/__init__.py @@ -0,0 +1,9 @@ +# + +print ('This is module ' + __name__) + +# Tick: import a package in a way, PyInstaller is not able to track +# it. But we want to import it anyway to make the submodule `sub11` +# print it's name. +sub11 = '7375623131'.decode('hex') +__import__(__name__ + '.' + sub11, level=1) diff --git a/tests/import/hook_without_hook_for_package/sub1/sub11/__init__.py b/tests/import/hook_without_hook_for_package/sub1/sub11/__init__.py new file mode 100644 index 0000000000..4573e12aad --- /dev/null +++ b/tests/import/hook_without_hook_for_package/sub1/sub11/__init__.py @@ -0,0 +1,2 @@ +# +print('This is ' + __name__) diff --git a/tests/import/pkg3/__init__.py b/tests/import/pkg3/__init__.py new file mode 100644 index 0000000000..792d600548 --- /dev/null +++ b/tests/import/pkg3/__init__.py @@ -0,0 +1 @@ +# diff --git a/tests/import/pkg3/sample-data.txt b/tests/import/pkg3/sample-data.txt new file mode 100644 index 0000000000..bfb0f9e71e --- /dev/null +++ b/tests/import/pkg3/sample-data.txt @@ -0,0 +1 @@ +This is data text for testing the packaging module data. diff --git a/tests/import/relimp2/bar/baz.py b/tests/import/relimp2/bar/baz.py index 0dd30a20bb..01e54a96fa 100644 --- a/tests/import/relimp2/bar/baz.py +++ b/tests/import/relimp2/bar/baz.py @@ -9,4 +9,4 @@ def say_hello_please(): - print "Hello World!" + print("Hello World!") diff --git a/tests/import/test_ctypes_cdll_c.py b/tests/import/test_ctypes_cdll_c.py index 3d77525097..439c9fdd7a 100644 --- a/tests/import/test_ctypes_cdll_c.py +++ b/tests/import/test_ctypes_cdll_c.py @@ -14,4 +14,4 @@ # Make sure we are able to load the MSVCRXX.DLL we are currently bound # to through ctypes. lib = ctypes.CDLL(ctypes.util.find_library('c')) -print lib +print(lib) diff --git a/tests/import/test_eggs1.py b/tests/import/test_eggs1.py index 9ba1e8563c..2e939df39d 100644 --- a/tests/import/test_eggs1.py +++ b/tests/import/test_eggs1.py @@ -22,4 +22,4 @@ import unzipped_egg assert unzipped_egg.data == 'This is data file for `unzipped`.' -print 'Okay.' +print('Okay.') diff --git a/tests/import/test_eggs2.py b/tests/import/test_eggs2.py index 28caa09367..7084abe852 100644 --- a/tests/import/test_eggs2.py +++ b/tests/import/test_eggs2.py @@ -22,4 +22,4 @@ import zipped_egg assert zipped_egg.data == 'This is data file for `zipped`.' -print 'Okay.' +print('Okay.') diff --git a/PyInstaller/hooks/hook-gst.py b/tests/import/test_hook_without_hook_for_package.py similarity index 90% rename from PyInstaller/hooks/hook-gst.py rename to tests/import/test_hook_without_hook_for_package.py index b15978680e..b697770684 100644 --- a/PyInstaller/hooks/hook-gst.py +++ b/tests/import/test_hook_without_hook_for_package.py @@ -6,3 +6,5 @@ # # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- + +import hook_without_hook_for_package.sub1 diff --git a/tests/import/test_hook_without_hook_for_package.spec b/tests/import/test_hook_without_hook_for_package.spec new file mode 100644 index 0000000000..aae76fad5a --- /dev/null +++ b/tests/import/test_hook_without_hook_for_package.spec @@ -0,0 +1,29 @@ +# -*- mode: python -*- +#----------------------------------------------------------------------------- +# Copyright (c) 2013, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + + +__testname__ = 'test_hook_without_hook_for_package' + +a = Analysis([__testname__ + '.py'], + hookspath=['hook_without_hook_for_package-hooks']) + +pyz = PYZ(a.pure) +exe = EXE(pyz, + a.scripts, + exclude_binaries=1, + name=__testname__ + '.exe', + debug=0, + console=1) +coll = COLLECT(exe, + a.binaries, + a.zipfiles, + a.datas, + strip=None, + name=__testname__) diff --git a/tests/import/test_hook_without_hook_for_package.toc b/tests/import/test_hook_without_hook_for_package.toc new file mode 100644 index 0000000000..8765ed759f --- /dev/null +++ b/tests/import/test_hook_without_hook_for_package.toc @@ -0,0 +1,3 @@ +[ + 'hook_without_hook_for_package.sub1.sub11', +] diff --git a/tests/import/test_onefile_ctypes_cdll_c.py b/tests/import/test_onefile_ctypes_cdll_c.py index 610119c387..b39083aac0 100644 --- a/tests/import/test_onefile_ctypes_cdll_c.py +++ b/tests/import/test_onefile_ctypes_cdll_c.py @@ -15,4 +15,4 @@ # Make sure we are able to load the MSVCRXX.DLL we are currently bound # to through ctypes. lib = ctypes.CDLL(ctypes.util.find_library('c')) -print lib +print(lib) diff --git a/tests/import/test_onefile_error_during_import.py b/tests/import/test_onefile_error_during_import.py index 8e3791d964..99201293c7 100644 --- a/tests/import/test_onefile_error_during_import.py +++ b/tests/import/test_onefile_error_during_import.py @@ -12,7 +12,7 @@ try: import error_during_import2 except KeyError: - print "OK" + print("OK") else: raise RuntimeError("failure!") diff --git a/tests/basic/test_onefile_pkg_resources.py b/tests/import/test_onefile_pkg_resources.py similarity index 65% rename from tests/basic/test_onefile_pkg_resources.py rename to tests/import/test_onefile_pkg_resources.py index 52bd14a8aa..4f3eeba00d 100644 --- a/tests/basic/test_onefile_pkg_resources.py +++ b/tests/import/test_onefile_pkg_resources.py @@ -7,20 +7,17 @@ # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- - # With module 'pkg_resources' it should not matter if a file is stored # on file system, in zip archive or bundled with frozen app. - - import pkg_resources as res import pkg3 - # With frozen app the resources is available in directory -# os.path.join(sys._MEIPASS, 'pkg3/pkg_resources-data.txt') -data = res.resource_string(pkg3.__name__, 'pkg_resources-data.txt') -data = data.strip() - - -if not data == 'This is data text for testing freezing pkg_resources module.': - raise SystemExit('Could not read data with pkg_resources module.') +# os.path.join(sys._MEIPASS, 'pkg3/sample-data.txt') +data = res.resource_string(pkg3.__name__, 'sample-data.txt') +if data: + data = data.strip() + +if data != 'This is data text for testing the packaging module data.': + raise SystemExit('Error: Could not read data with pkg_resources module.') +print 'Okay: Resource data read.' diff --git a/tests/basic/test_onefile_pkg_resources.spec b/tests/import/test_onefile_pkg_resources.spec similarity index 95% rename from tests/basic/test_onefile_pkg_resources.spec rename to tests/import/test_onefile_pkg_resources.spec index f2af752134..8d10eb9869 100644 --- a/tests/basic/test_onefile_pkg_resources.spec +++ b/tests/import/test_onefile_pkg_resources.spec @@ -39,7 +39,7 @@ def Datafiles(*filenames, **kw): # Include some data files for testing pkg_resources module. -datafile = Datafiles('pkg3/pkg_resources-data.txt', strip_path=False) +datafile = Datafiles('pkg3/sample-data.txt', strip_path=False) exe = EXE(pyz, diff --git a/tests/import/test_onefile_pkgutil-get_data.py b/tests/import/test_onefile_pkgutil-get_data.py new file mode 100644 index 0000000000..ddc1a36825 --- /dev/null +++ b/tests/import/test_onefile_pkgutil-get_data.py @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +import pkgutil +import pkg3 + +data = pkgutil.get_data('pkg3', 'sample-data.txt') +if data: + data = data.strip() + +if data != 'This is data text for testing the packaging module data.': + raise SystemExit('Error: Could not read data with pkgutil.get_data().') +print 'Okay: Resource data read.' diff --git a/tests/import/test_onefile_pkgutil-get_data.spec b/tests/import/test_onefile_pkgutil-get_data.spec new file mode 100644 index 0000000000..cf31847430 --- /dev/null +++ b/tests/import/test_onefile_pkgutil-get_data.spec @@ -0,0 +1,54 @@ +# -*- mode: python -*- +#----------------------------------------------------------------------------- +# Copyright (c) 2013, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + + +__testname__ = 'test_onefile_pkgutil-get_data' + +a = Analysis([__testname__ + '.py'], + pathex=['.'], + hiddenimports=[], + hookspath=None, + runtime_hooks=None) + +pyz = PYZ(a.pure) + + +def Datafiles(*filenames, **kw): + import os + + def datafile(path, strip_path=True): + parts = path.split('/') + path = name = os.path.join(*parts) + if strip_path: + name = os.path.basename(path) + return name, path, 'DATA' + + strip_path = kw.get('strip_path', True) + return TOC( + datafile(filename, strip_path=strip_path) + for filename in filenames + if os.path.isfile(filename)) + + +# Include some data files for testing pkg_resources module. +datafile = Datafiles('pkg3/sample-data.txt', strip_path=False) + + +exe = EXE(pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + datafile, + name= __testname__ + '.exe', + debug=True, + strip=None, + upx=True, + console=True ) diff --git a/tests/import/test_onefile_pkgutil-get_data__main__.py b/tests/import/test_onefile_pkgutil-get_data__main__.py new file mode 100644 index 0000000000..7577175cf3 --- /dev/null +++ b/tests/import/test_onefile_pkgutil-get_data__main__.py @@ -0,0 +1,18 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +import pkgutil + +data = pkgutil.get_data('__main__', 'pkg3/sample-data.txt') +if data: + data = data.strip() + +if data != 'This is data text for testing the packaging module data.': + raise SystemExit('Error: Could not read data with pkgutil.get_data().') +print 'Okay: Resource data read.' diff --git a/tests/import/test_onefile_pkgutil-get_data__main__.spec b/tests/import/test_onefile_pkgutil-get_data__main__.spec new file mode 100644 index 0000000000..5817a3cec3 --- /dev/null +++ b/tests/import/test_onefile_pkgutil-get_data__main__.spec @@ -0,0 +1,54 @@ +# -*- mode: python -*- +#----------------------------------------------------------------------------- +# Copyright (c) 2013, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + + +__testname__ = 'test_onefile_pkgutil-get_data__main__' + +a = Analysis([__testname__ + '.py'], + pathex=['.'], + hiddenimports=[], + hookspath=None, + runtime_hooks=None) + +pyz = PYZ(a.pure) + + +def Datafiles(*filenames, **kw): + import os + + def datafile(path, strip_path=True): + parts = path.split('/') + path = name = os.path.join(*parts) + if strip_path: + name = os.path.basename(path) + return name, path, 'DATA' + + strip_path = kw.get('strip_path', True) + return TOC( + datafile(filename, strip_path=strip_path) + for filename in filenames + if os.path.isfile(filename)) + + +# Include some data files for testing pkg_resources module. +datafile = Datafiles('pkg3/sample-data.txt', strip_path=False) + + +exe = EXE(pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + datafile, + name= __testname__ + '.exe', + debug=True, + strip=None, + upx=True, + console=True ) diff --git a/tests/import/test_onefile_relative_import3.py b/tests/import/test_onefile_relative_import3.py index feeb439519..31968c5ddd 100644 --- a/tests/import/test_onefile_relative_import3.py +++ b/tests/import/test_onefile_relative_import3.py @@ -12,4 +12,4 @@ if __name__ == '__main__': - print a1.getString() + print(a1.getString()) diff --git a/tests/import/test_onefile_zipimport.py b/tests/import/test_onefile_zipimport.py index 63e50ccb8c..d15cd505ab 100644 --- a/tests/import/test_onefile_zipimport.py +++ b/tests/import/test_onefile_zipimport.py @@ -7,6 +7,7 @@ # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- +from __future__ import print_function # Test for zipimport - minimalistic, just import pgk_resource @@ -14,13 +15,13 @@ import os import sys -print __name__, 'is running' -print 'sys.path:', sys.path -print 'dir contents .exe:', os.listdir(os.path.dirname(sys.executable)) -print '-----------' -print 'dir contents sys._MEIPASS:', os.listdir(sys._MEIPASS) +print(__name__, 'is running') +print('sys.path:', sys.path) +print('dir contents .exe:', os.listdir(os.path.dirname(sys.executable))) +print('-----------') +print('dir contents sys._MEIPASS:', os.listdir(sys._MEIPASS)) -print '-----------' -print 'now importing pkg_resources' +print('-----------') +print('now importing pkg_resources') import pkg_resources -print "dir(pkg_resources)", dir(pkg_resources) +print("dir(pkg_resources)", dir(pkg_resources)) diff --git a/tests/import/test_onefile_zipimport2.py b/tests/import/test_onefile_zipimport2.py index 6af7fab922..afe87277e4 100644 --- a/tests/import/test_onefile_zipimport2.py +++ b/tests/import/test_onefile_zipimport2.py @@ -7,6 +7,7 @@ # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- +from __future__ import print_function # Test for zipimport - use a more complex import @@ -14,19 +15,19 @@ import os import sys -print __name__, 'is running' -print 'sys.path:', sys.path -print 'dir contents .exe:', os.listdir(os.path.dirname(sys.executable)) +print(__name__, 'is running') +print('sys.path:', sys.path) +print('dir contents .exe:', os.listdir(os.path.dirname(sys.executable))) if hasattr(sys, 'frozen') and sys.frozen: - print '-----------' - print 'dir contents sys._MEIPASS:', os.listdir(sys._MEIPASS) + print('-----------') + print('dir contents sys._MEIPASS:', os.listdir(sys._MEIPASS)) -print '-----------' -print 'now importing pkg_resources' +print('-----------') +print('now importing pkg_resources') import pkg_resources -print '-----------' -print 'now importing setuptools.dist' +print('-----------') +print('now importing setuptools.dist') import setuptools.dist -print '-----------' -print 'now importing setuptools.command' +print('-----------') +print('now importing setuptools.command') diff --git a/tests/interactive/test_argv_emulation.py b/tests/interactive/test_argv_emulation.py index ebb9e63b1d..e3254ff7e2 100644 --- a/tests/interactive/test_argv_emulation.py +++ b/tests/interactive/test_argv_emulation.py @@ -7,9 +7,10 @@ # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- +from __future__ import print_function import sys -print "Argv from python:", sys.argv +print("Argv from python:", sys.argv) # Testing the argv capturing capability on the Mac is not that easy, but doable. First, build the app bundle diff --git a/tests/interactive/test_keyring.py b/tests/interactive/test_keyring.py new file mode 100644 index 0000000000..360d634f16 --- /dev/null +++ b/tests/interactive/test_keyring.py @@ -0,0 +1,20 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2014, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# ----------------------------------------------------------------------------- + + +import keyring + + +def main(): + keyring.set_password("pyinstaller", "username", "password") + keyring.get_password("pyinstaller", "username") + + +if __name__ == '__main__': + main() diff --git a/tests/interactive/test_onefile_win32_uac_admin.py b/tests/interactive/test_onefile_win32_uac_admin.py new file mode 100644 index 0000000000..a6527a8776 --- /dev/null +++ b/tests/interactive/test_onefile_win32_uac_admin.py @@ -0,0 +1,24 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + + +""" +This test tests on Windows the option --uac-admin with onefile mode. + +1) Upon execution the exe should ask for admin privileges. +2) Only admin user has access to path C:\Windows\Temp and this test + should not fail when accessing this path. + +""" + + +# Accessing directory where only admin has access. +import os +admin_dir = os.path.join(os.environ.get('SystemRoot','C:\\windows'), 'temp') +os.listdir(admin_dir) diff --git a/tests/interactive/test_onefile_win32_uac_admin.spec b/tests/interactive/test_onefile_win32_uac_admin.spec new file mode 100644 index 0000000000..a36e436bbd --- /dev/null +++ b/tests/interactive/test_onefile_win32_uac_admin.spec @@ -0,0 +1,25 @@ +# -*- mode: python -*- +#----------------------------------------------------------------------------- +# Copyright (c) 2014, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + + +__testname__ = 'test_onefile_win32_uac_admin' + +a = Analysis([__testname__ + '.py'], + pathex=[]) +pyz = PYZ(a.pure) +exe = EXE(pyz, + a.scripts, + a.binaries, + name=__testname__ + '.exe', + debug=False, + strip=False, + upx=False, + console=True, + uac_admin=True) diff --git a/tests/interactive/test_pygame.py b/tests/interactive/test_pygame.py index 1fbf3fef2f..ce8c9f8ab3 100644 --- a/tests/interactive/test_pygame.py +++ b/tests/interactive/test_pygame.py @@ -23,10 +23,10 @@ from pygame.locals import * except ImportError, err: - print "Error, couldn't load module. %s" % (err) + print("Error, couldn't load module. %s" % err) sys.exit(2) -if not pygame.mixer: print 'Warning, sound disabled' +if not pygame.mixer: print('Warning, sound disabled') NUM_SPRITES = 10 diff --git a/tests/libraries/test_Image2.py b/tests/libraries/test_Image2.py index 4a05052ead..36ae19ced4 100644 --- a/tests/libraries/test_Image2.py +++ b/tests/libraries/test_Image2.py @@ -15,4 +15,4 @@ from Image import fromstring -print fromstring +print(fromstring) diff --git a/tests/libraries/test_PIL2.py b/tests/libraries/test_PIL2.py index 9b4cd32610..26306b5e50 100644 --- a/tests/libraries/test_PIL2.py +++ b/tests/libraries/test_PIL2.py @@ -15,4 +15,4 @@ from PIL.Image import fromstring -print fromstring +print(fromstring) diff --git a/tests/libraries/test_PyQt4-uic.py b/tests/libraries/test_PyQt4-uic.py index a82ab92e98..a7b4ac9fa1 100644 --- a/tests/libraries/test_PyQt4-uic.py +++ b/tests/libraries/test_PyQt4-uic.py @@ -7,6 +7,8 @@ # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- +import sys + # Not neceesary for the code, but informs PyInstaller of the hidden import of QtWebKit, which is performed inside of uic.loadUi. from PyQt4.QtWebKit import QWebView diff --git a/tests/libraries/test_keyring.py b/tests/libraries/test_keyring.py new file mode 100644 index 0000000000..ab944026cb --- /dev/null +++ b/tests/libraries/test_keyring.py @@ -0,0 +1,10 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2014, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# ----------------------------------------------------------------------------- + +import keyring diff --git a/tests/libraries/test_keyring.toc b/tests/libraries/test_keyring.toc new file mode 100644 index 0000000000..f1c4ac8606 --- /dev/null +++ b/tests/libraries/test_keyring.toc @@ -0,0 +1,4 @@ +[ + # check is we have any of the backend-modules + 'keyring.backends.' +] diff --git a/tests/libraries/test_numpy.py b/tests/libraries/test_numpy.py index 9143bac4c1..6c592d782f 100644 --- a/tests/libraries/test_numpy.py +++ b/tests/libraries/test_numpy.py @@ -7,12 +7,13 @@ # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- +from __future__ import print_function from numpy.core.numeric import dot def main(): - print "dot(3, 4):", dot(3, 4) + print("dot(3, 4):", dot(3, 4)) if __name__ == "__main__": diff --git a/tests/libraries/test_onefile_numpy.py b/tests/libraries/test_onefile_numpy.py index ba32cd2544..48274336e2 100644 --- a/tests/libraries/test_onefile_numpy.py +++ b/tests/libraries/test_onefile_numpy.py @@ -7,13 +7,14 @@ # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- +from __future__ import print_function import numpy from numpy.core.numeric import dot def main(): - print "dot(3, 4):", dot(3, 4) + print("dot(3, 4):", dot(3, 4)) if __name__ == "__main__": diff --git a/tests/libraries/test_pycrypto.py b/tests/libraries/test_pycrypto.py index 1efb62680f..fc94e9f5d8 100644 --- a/tests/libraries/test_pycrypto.py +++ b/tests/libraries/test_pycrypto.py @@ -7,6 +7,7 @@ # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- +from __future__ import print_function import binascii @@ -16,11 +17,11 @@ def main(): - print "AES null encryption, block size", BLOCK_SIZE + print("AES null encryption, block size", BLOCK_SIZE) # Just for testing functionality after all - print "HEX", binascii.hexlify(AES.new("\0" * + print("HEX", binascii.hexlify(AES.new("\0" * BLOCK_SIZE).encrypt("\0" * - BLOCK_SIZE)) + BLOCK_SIZE))) if __name__ == "__main__": diff --git a/tests/libraries/test_pylint.py b/tests/libraries/test_pylint.py new file mode 100644 index 0000000000..81b6374b19 --- /dev/null +++ b/tests/libraries/test_pylint.py @@ -0,0 +1,21 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +from pylint.lint import Run + +# The following more obvious test doesn't work:: +# +# import pylint, sys +# +# pylint.run_pylint() +# sys.exit(0) +# +# because pylint will override the sys.exit value with 32, since a valid command +# line wasn't given. Instead, provide a valid command line below. +Run(['-h']) diff --git a/PyInstaller/hooks/hook-pygments.py b/tests/libraries/test_scapy1.py similarity index 59% rename from PyInstaller/hooks/hook-pygments.py rename to tests/libraries/test_scapy1.py index b7d5c49373..265b9da580 100644 --- a/PyInstaller/hooks/hook-pygments.py +++ b/tests/libraries/test_scapy1.py @@ -6,5 +6,19 @@ # # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- -# This file must exist so that hook-pygments.{lexers, formatters, styles}.py -# will be found. + +# Test-cases taken from issue #834 + +import scapy.all +scapy.all.IP + +from scapy.all import IP + + +# Test-case taken from issue #202. + +from scapy.all import * +DHCP # scapy.layers.dhcp.DHCP +BOOTP # scapy.layers.dhcp.BOOTP +DNS # scapy.layers.dns.DNS +ICMP # scapy.layers.inet.ICMP diff --git a/PyInstaller/hooks/hook-PIL.py b/tests/libraries/test_scapy2.py similarity index 85% rename from PyInstaller/hooks/hook-PIL.py rename to tests/libraries/test_scapy2.py index 6248409500..08eb969187 100644 --- a/PyInstaller/hooks/hook-PIL.py +++ b/tests/libraries/test_scapy2.py @@ -7,5 +7,6 @@ # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- +# Test the hook to scapy.layers.all -# empty (just to need Python import machinery happy) +from scapy.layers.all import DHCP diff --git a/tests/libraries/test_scapy3.py b/tests/libraries/test_scapy3.py new file mode 100644 index 0000000000..2b136ab0ed --- /dev/null +++ b/tests/libraries/test_scapy3.py @@ -0,0 +1,40 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +# Test whether +# a) scapy packet layers are not included if neither scapy.all nor +# scapy.layers.all are imported. +# b) packages are included if imported explicitly + +# This test-case assumes, that layer modules are imported only if + +NAME = 'hook-scapy.layers.all' + +layer_inet = 'scapy.layers.inet' + +def testit(): + try: + __import__(layer_inet) + raise SystemExit('Self-test of hook %s failed: package module found' + % NAME) + except ImportError, e: + if not e.args[0].endswith(' inet'): + raise SystemExit('Self-test of hook %s failed: package module found' + ' and has import errors: %r' % (NAME, e)) + +import scapy +testit() + +import scapy.layers +testit() + +# Explicitly import a single layer module. Note: This module MUST NOT +# import inet (neither directly nor indirectly), otherwise the test +# above fails. +import scapy.layers.ir diff --git a/tests/libraries/test_sysconfig.py b/tests/libraries/test_sysconfig.py index 390d2c03a5..0b2a571f95 100644 --- a/tests/libraries/test_sysconfig.py +++ b/tests/libraries/test_sysconfig.py @@ -34,4 +34,4 @@ for f in files: if not os.path.exists(f): raise SystemExit('File does not exist: %s' % f) -print 'okay' +print('okay') diff --git a/tests/libraries/test_wx_pubsub.py b/tests/libraries/test_wx_pubsub.py index 0ca9b2f7bf..49bf75b2fc 100644 --- a/tests/libraries/test_wx_pubsub.py +++ b/tests/libraries/test_wx_pubsub.py @@ -12,7 +12,7 @@ def on_message(number): - print 'In the handler' + print('In the handler') if not number == 762: raise SystemExit('wx_pubsub failed.') diff --git a/tests/libraries/test_wx_pubsub_arg1.py b/tests/libraries/test_wx_pubsub_arg1.py index 304e3e559d..de8072b99c 100644 --- a/tests/libraries/test_wx_pubsub_arg1.py +++ b/tests/libraries/test_wx_pubsub_arg1.py @@ -13,7 +13,7 @@ def on_message(message): - print ("In the handler") + print("In the handler") # Data is delivered encapsulated in message and # not directly as function argument. if not message.data == 762: diff --git a/tests/libraries/test_wx_pubsub_kwargs.py b/tests/libraries/test_wx_pubsub_kwargs.py index c2d3566b63..abe74d6905 100644 --- a/tests/libraries/test_wx_pubsub_kwargs.py +++ b/tests/libraries/test_wx_pubsub_kwargs.py @@ -13,7 +13,7 @@ def on_message(number): - print 'In the handler' + print('In the handler') if not number == 762: raise SystemExit('wx_pubsub_kwargs failed.') diff --git a/tests/libraries/test_zope_interface.py b/tests/libraries/test_zope_interface.py index 2377d5ed7a..70c93be3b0 100644 --- a/tests/libraries/test_zope_interface.py +++ b/tests/libraries/test_zope_interface.py @@ -2,4 +2,4 @@ import zope print(zope) import zope.interface -print (zope.interface) +print(zope.interface) diff --git a/tests/runtests.py b/tests/runtests.py index 3ad24115c2..d6450bfaef 100755 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -8,12 +8,13 @@ # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- - # This program will execute any file with name test*.py. If your test # need an aditional dependency name it test*.py to be ignored # by this program but be recognizable by any one as a dependency of that # particular test. +from __future__ import print_function + import glob import optparse @@ -98,19 +99,15 @@ def __init__(self): 'basic/test_email': is_py25, # On Mac DYLD_LIBRARY_PATH is not used. 'basic/test_absolute_ld_library_path': not is_win and not is_darwin, + 'import/test_onefile_pkgutil.get_data': is_py26, + 'import/test_onefile_pkgutil.get_data__main__': is_py26 and False, 'import/test_c_extension': is_py25, 'import/test_onefile_c_extension': is_py25, 'import/test_onefile_relative_import': is_py25, 'import/test_onefile_relative_import2': is_py26, 'import/test_onefile_relative_import3': is_py25, + 'interactive/test_onefile_win32_uac_admin': is_win, 'libraries/test_enchant': is_win, - # docutils, a sphinx dependency, fails in - # docutils.utils.__init__.py, function decode_path, where - # sys.getfilesystemencoding() returns None when frozen. - # Docutils doesn't expect this and throws an assertion. - # Untested on Mac, but this shouldn't be a problem, since - # Macs return 'utf-8'. - 'libraries/test_sphinx': is_win or is_darwin, } # Required Python modules for some tests. @@ -139,6 +136,7 @@ def __init__(self): 'libraries/test_pycparser': ['pycparser'], 'libraries/test_pycrypto': ['Crypto'], 'libraries/test_pyexcelerate': ['pyexcelerate'], + 'libraries/test_pylint': ['pylint'], 'libraries/test_pygments': ['pygments'], 'libraries/test_pyodbc': ['pyodbc'], 'libraries/test_pyttsx': ['pyttsx'], @@ -146,6 +144,9 @@ def __init__(self): 'libraries/test_PyQt4-QtWebKit': ['PyQt4'], 'libraries/test_PyQt4-uic': ['PyQt4'], 'libraries/test_sysconfig': ['sysconfig'], + 'libraries/test_scapy1': ['scapy'], + 'libraries/test_scapy2': ['scapy'], + 'libraries/test_scapy3': ['scapy'], 'libraries/test_scipy': ['numpy', 'scipy'], 'libraries/test_sqlite3': ['sqlite3'], 'libraries/test_sqlalchemy': ['sqlalchemy', 'MySQLdb', 'psycopg2'], @@ -249,7 +250,9 @@ def check(self, test_name): SPEC_FILE = set([ 'basic/test_onefile_ctypes', - 'basic/test_onefile_pkg_resources', + 'import/test_onefile_pkg_resources', + 'import/test_onefile_pkgutil-get_data', + 'import/test_onefile_pkgutil-get_data__main__', 'basic/test_option_verbose', 'basic/test_option_wignore', 'basic/test_pkg_structures', @@ -258,7 +261,9 @@ def check(self, test_name): 'import/test_app_with_plugins', 'import/test_eggs2', 'import/test_hiddenimport', + 'import/test_hook_without_hook_for_package', 'interactive/test_matplotlib', # TODO .spec for this test contain win32 specific manifest code. Do we still need it? + 'interactive/test_onefile_win32_uac_admin', 'libraries/test_Image', 'libraries/test_PIL', 'multipackage/test_multipackage1', @@ -351,6 +356,10 @@ def _run_created_exe(self, test, testdir=None): #line = proc.stdout.readline().strip() line = proc.stdout.read(1) self._plain_msg(line, newline=False) + # Print any stdout that wasn't read before the process terminated. + # See the conversation in https://github.com/pyinstaller/pyinstaller/pull/1092 + # for examples of why this is necessary. + self._plain_msg(proc.stdout.read(), newline=False) # Print possible stderr at the end. self._msg('STDERR %s' % self.test_name) self._plain_msg(proc.stderr.read()) @@ -388,7 +397,7 @@ def test_building(self): OPTS.append('--onedir') if self.with_crypto or '_crypto' in self.test_file: - print 'NOTE: Bytecode encryption is enabled for this test.', + print('NOTE: Bytecode encryption is enabled for this test.', end="") OPTS.append('--key=test_key') self._msg("BUILDING TEST " + self.test_name) @@ -665,7 +674,7 @@ def clean(): else: os.remove(pth) except OSError, e: - print e + print(e) # Delete *.spec files for tests without spec file. for pth in glob.glob(os.path.join(directory, '*.spec')): test_name = directory + '/' + os.path.splitext(os.path.basename(pth))[0] @@ -679,7 +688,7 @@ def run_tests(test_suite, xml_file): Run test suite and save output to junit xml file if requested. """ if xml_file: - print 'Writting test results to: %s' % xml_file + print('Writting test results to:', xml_file) fp = open('report.xml', 'w') result = junitxml.JUnitXmlResult(fp) # Text from stdout/stderr should be added to failed test cases. @@ -742,21 +751,21 @@ def main(): test_dir = os.path.dirname(t) test_script = os.path.basename(os.path.splitext(t)[0]) suite.addTest(GenericTestCase(test_dir, test_script)) - print 'Running test: %s' % (test_dir + '/' + test_script) + print('Running test: ', (test_dir + '/' + test_script)) # Run all tests or all interactive tests. else: if opts.interactive_tests: - print 'Running interactive tests...' + print('Running interactive tests...') test_classes = [InteractiveTestCase] elif opts.all_with_crypto: - print 'Running normal tests with bytecode encryption...' + print('Running normal tests with bytecode encryption...') # Make sure to exclude CryptoTestCase here since we are building # everything else with crypto enabled. test_classes = [BasicTestCase, ImportTestCase, LibrariesTestCase, MultipackageTestCase] else: - print 'Running normal tests (-i for interactive tests)...' + print('Running normal tests (-i for interactive tests)...') test_classes = [BasicTestCase, CryptoTestCase, ImportTestCase, LibrariesTestCase, MultipackageTestCase] diff --git a/tests/setupenv_unix.py b/tests/setupenv_unix.py index b38462e1ba..406b7170e1 100644 --- a/tests/setupenv_unix.py +++ b/tests/setupenv_unix.py @@ -7,6 +7,7 @@ # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- +from __future__ import print_function # Install necessary 3rd party Python modules to run all tests. # This script is supposed to be used in a continuous integration system: @@ -37,6 +38,7 @@ _PACKAGES = [ + 'six', 'docutils', 'jinja2', 'MySQL-python', @@ -55,19 +57,12 @@ ] -# TODO remove this block when we support Python 2.6+ only. -# Python 2.4 and 2.5 does not have ssl module. But we need -# it. -if sys.version_info[0:2] < (2,6): - _PACKAGES.append('ssl') - - def main(): for pkg in _PACKAGES: - print 'Installing module... %s' % pkg + print('Installing module...', pkg) retcode = compat.exec_command_rc('pip', 'install', pkg) if retcode: - print ' %s installation failed' % pkg + print(' ', pkg, 'installation failed') if __name__ == '__main__': diff --git a/tests/setupenv_windows.py b/tests/setupenv_windows.py index ccfc4ebad8..b16ac8f72c 100644 --- a/tests/setupenv_windows.py +++ b/tests/setupenv_windows.py @@ -13,6 +13,7 @@ # https://jenkins.shiningpanda.com/pyinstaller/ # Python there is mostly 64bit. Only Python 2.4 is 32bit on Windows 7. +from __future__ import print_function import glob import optparse @@ -104,7 +105,7 @@ def main(): continue try: __import__(k) - print 'Already installed... %s' % k + print('Already installed...', k) # Module is not available - install it. except ImportError: # If not url or module name then look for installers in download area. @@ -116,14 +117,14 @@ def main(): files += glob.glob(pattern) # No file with that pattern was not found - skip it. if not files: - print 'Skipping module... %s' % k + print('Skipping module...', k) continue # Full path to installers in download directory. v = files - print 'Installing module... %s' % k + print('Installing module...', k) # Some modules might require several .exe files to install. for f in v: - print ' %s' % f + print(' ', f) # Use --no-deps ... installing module dependencies might fail # because easy_install tries to install the same module from # PYPI from source code and if fails because of C code that @@ -131,7 +132,7 @@ def main(): try: easy_install.main(['--no-deps', '--always-unzip', f]) except Exception: - print ' %s installation failed' % k + print(' ', k, 'installation failed') if __name__ == '__main__': diff --git a/tests/unit/hookutils_test_files/eight.so b/tests/unit/hookutils_test_files/eight.so index e69de29bb2..792d600548 100644 --- a/tests/unit/hookutils_test_files/eight.so +++ b/tests/unit/hookutils_test_files/eight.so @@ -0,0 +1 @@ +# diff --git a/tests/unit/hookutils_test_files/py_files_not_in_package/data/eleven.dat b/tests/unit/hookutils_test_files/py_files_not_in_package/data/eleven.dat index e69de29bb2..792d600548 100644 --- a/tests/unit/hookutils_test_files/py_files_not_in_package/data/eleven.dat +++ b/tests/unit/hookutils_test_files/py_files_not_in_package/data/eleven.dat @@ -0,0 +1 @@ +# diff --git a/tests/unit/hookutils_test_files/py_files_not_in_package/sub_pkg/__init__.py b/tests/unit/hookutils_test_files/py_files_not_in_package/sub_pkg/__init__.py index e69de29bb2..792d600548 100644 --- a/tests/unit/hookutils_test_files/py_files_not_in_package/sub_pkg/__init__.py +++ b/tests/unit/hookutils_test_files/py_files_not_in_package/sub_pkg/__init__.py @@ -0,0 +1 @@ +# diff --git a/tests/unit/hookutils_test_files/seven.dylib b/tests/unit/hookutils_test_files/seven.dylib index e69de29bb2..792d600548 100644 --- a/tests/unit/hookutils_test_files/seven.dylib +++ b/tests/unit/hookutils_test_files/seven.dylib @@ -0,0 +1 @@ +# diff --git a/tests/unit/hookutils_test_files/six.dll b/tests/unit/hookutils_test_files/six.dll index e69de29bb2..8fa2136f68 100644 --- a/tests/unit/hookutils_test_files/six.dll +++ b/tests/unit/hookutils_test_files/six.dll @@ -0,0 +1,2 @@ +# + diff --git a/tests/unit/hookutils_test_files/subpkg/__init__.py b/tests/unit/hookutils_test_files/subpkg/__init__.py index e69de29bb2..792d600548 100644 --- a/tests/unit/hookutils_test_files/subpkg/__init__.py +++ b/tests/unit/hookutils_test_files/subpkg/__init__.py @@ -0,0 +1 @@ +# diff --git a/tests/unit/hookutils_test_files/subpkg/twelve.py b/tests/unit/hookutils_test_files/subpkg/twelve.py index e69de29bb2..792d600548 100644 --- a/tests/unit/hookutils_test_files/subpkg/twelve.py +++ b/tests/unit/hookutils_test_files/subpkg/twelve.py @@ -0,0 +1 @@ +#