83 lines
2.6 KiB
Python
Executable File
83 lines
2.6 KiB
Python
Executable File
""" generate a single-file self-contained version of pytest """
|
|
import py
|
|
import sys
|
|
|
|
|
|
def find_toplevel(name):
|
|
for syspath in sys.path:
|
|
base = py.path.local(syspath)
|
|
lib = base/name
|
|
if lib.check(dir=1):
|
|
return lib
|
|
mod = base.join("%s.py" % name)
|
|
if mod.check(file=1):
|
|
return mod
|
|
raise LookupError(name)
|
|
|
|
def pkgname(toplevel, rootpath, path):
|
|
parts = path.parts()[len(rootpath.parts()):]
|
|
return '.'.join([toplevel] + [x.purebasename for x in parts])
|
|
|
|
def pkg_to_mapping(name):
|
|
toplevel = find_toplevel(name)
|
|
name2src = {}
|
|
if toplevel.check(file=1): # module
|
|
name2src[toplevel.purebasename] = toplevel.read()
|
|
else: # package
|
|
for pyfile in toplevel.visit('*.py'):
|
|
pkg = pkgname(name, toplevel, pyfile)
|
|
name2src[pkg] = pyfile.read()
|
|
return name2src
|
|
|
|
def compress_mapping(mapping):
|
|
import base64, pickle, zlib
|
|
data = pickle.dumps(mapping, 2)
|
|
data = zlib.compress(data, 9)
|
|
data = base64.encodestring(data)
|
|
data = data.decode('ascii')
|
|
return data
|
|
|
|
|
|
def compress_packages(names):
|
|
mapping = {}
|
|
for name in names:
|
|
mapping.update(pkg_to_mapping(name))
|
|
return compress_mapping(mapping)
|
|
|
|
def generate_script(entry, packages):
|
|
data = compress_packages(packages)
|
|
tmpl = py.path.local(__file__).dirpath().join('standalonetemplate.py')
|
|
exe = tmpl.read()
|
|
exe = exe.replace('@SOURCES@', data)
|
|
exe = exe.replace('@ENTRY@', entry)
|
|
return exe
|
|
|
|
|
|
def pytest_addoption(parser):
|
|
group = parser.getgroup("debugconfig")
|
|
group.addoption("--genscript", action="store", default=None,
|
|
dest="genscript", metavar="path",
|
|
help="create standalone pytest script at given target path.")
|
|
|
|
def pytest_cmdline_main(config):
|
|
genscript = config.getvalue("genscript")
|
|
if genscript:
|
|
tw = py.io.TerminalWriter()
|
|
deps = ['py', '_pytest', 'pytest']
|
|
if sys.version_info < (2,7):
|
|
deps.append("argparse")
|
|
tw.line("generated script will run on python2.5-python3.3++")
|
|
else:
|
|
tw.line("WARNING: generated script will not run on python2.6 "
|
|
"or below due to 'argparse' dependency. Use python2.6 "
|
|
"to generate a python2.5/6 compatible script", red=True)
|
|
script = generate_script(
|
|
'import pytest; raise SystemExit(pytest.cmdline.main())',
|
|
deps,
|
|
)
|
|
genscript = py.path.local(genscript)
|
|
genscript.write(script)
|
|
tw.line("generated pytest standalone script: %s" % genscript,
|
|
bold=True)
|
|
return 0
|