python-3.6.zip added from Github

README.cosmo contains the necessary links.
This commit is contained in:
ahgamut 2021-08-08 09:38:33 +05:30 committed by Justine Tunney
parent 75fc601ff5
commit 0c4c56ff39
4219 changed files with 1968626 additions and 0 deletions

48
third_party/python/Tools/README vendored Normal file
View file

@ -0,0 +1,48 @@
This directory contains a number of Python programs that are useful
while building or extending Python.
buildbot Batchfiles for running on Windows buildslaves.
ccbench A Python threads-based concurrency benchmark. (*)
demo Several Python programming demos.
freeze Create a stand-alone executable from a Python program.
gdb Python code to be run inside gdb, to make it easier to
debug Python itself (by David Malcolm).
i18n Tools for internationalization. pygettext.py
parses Python source code and generates .pot files,
and msgfmt.py generates a binary message catalog
from a catalog in text format.
iobench Benchmark for the new Python I/O system. (*)
msi Support for packaging Python as an MSI package on Windows.
parser Un-parsing tool to generate code from an AST.
pybench Low-level benchmarking for the Python evaluation loop. (*)
pynche A Tkinter-based color editor.
scripts A number of useful single-file programs, e.g. tabnanny.py
by Tim Peters, which checks for inconsistent mixing of
tabs and spaces, and 2to3, which converts Python 2 code
to Python 3 code.
stringbench A suite of micro-benchmarks for various operations on
strings (both 8-bit and unicode). (*)
test2to3 A demonstration of how to use 2to3 transparently in setup.py.
unicode Tools for generating unicodedata and codecs from unicode.org
and other mapping files (by Fredrik Lundh, Marc-Andre Lemburg
and Martin von Loewis).
unittestgui A Tkinter based GUI test runner for unittest, with test
discovery.
(*) A generic benchmark suite is maintained separately at https://github.com/python/performance

View file

@ -0,0 +1,17 @@
@rem Used by the buildbot "compile" step.
@rem Clean up
call "%~dp0clean.bat" %*
@rem If you need the buildbots to start fresh (such as when upgrading to
@rem a new version of an external library, especially Tcl/Tk):
@rem 1) uncomment the following line:
@rem call "%~dp0..\..\PCbuild\get_externals.bat" --clean-only
@rem 2) commit and push
@rem 3) wait for all Windows bots to start a build with that changeset
@rem 4) re-comment, commit and push again
@rem Do the build
call "%~dp0..\..\PCbuild\build.bat" -e -d -k -v %*

View file

@ -0,0 +1,9 @@
@rem Used by the buildbot "buildmsi" step.
setlocal
pushd
@rem build both snapshot MSIs
call "%~dp0..\msi\build.bat" -x86 -x64
popd

View file

@ -0,0 +1,17 @@
@echo off
rem Used by the buildbot "clean" step.
setlocal
set root=%~dp0..\..
set pcbuild=%root%\PCbuild
echo Deleting build
call "%pcbuild%\build.bat" -t Clean -k %*
call "%pcbuild%\build.bat" -t Clean -k -d %*
echo Deleting .pyc/.pyo files ...
del /s "%root%\Lib\*.pyc" "%root%\Lib\*.pyo"
echo Deleting test leftovers ...
rmdir /s /q "%root%\build"
del /s "%pcbuild%\python*.zip"

View file

@ -0,0 +1,19 @@
@echo off
rem Used by the buildbot "test" step.
setlocal
set here=%~dp0
set rt_opts=-q -d
set regrtest_args=-j1
:CheckOpts
if "%1"=="-x64" (set rt_opts=%rt_opts% %1) & shift & goto CheckOpts
if "%1"=="-d" (set rt_opts=%rt_opts% %1) & shift & goto CheckOpts
if "%1"=="-O" (set rt_opts=%rt_opts% %1) & shift & goto CheckOpts
if "%1"=="-q" (set rt_opts=%rt_opts% %1) & shift & goto CheckOpts
if "%1"=="+d" (set rt_opts=%rt_opts:-d=%) & shift & goto CheckOpts
if "%1"=="+q" (set rt_opts=%rt_opts:-q=%) & shift & goto CheckOpts
if NOT "%1"=="" (set regrtest_args=%regrtest_args% %1) & shift & goto CheckOpts
echo on
call "%here%..\..\PCbuild\rt.bat" %rt_opts% -uall -rwW --slowest --timeout=1200 %regrtest_args%

View file

@ -0,0 +1,611 @@
# This file should be kept compatible with both Python 2.6 and Python >= 3.0.
from __future__ import division
from __future__ import print_function
"""
ccbench, a Python concurrency benchmark.
"""
import time
import os
import sys
import itertools
import threading
import subprocess
import socket
from optparse import OptionParser, SUPPRESS_HELP
import platform
# Compatibility
try:
xrange
except NameError:
xrange = range
try:
map = itertools.imap
except AttributeError:
pass
THROUGHPUT_DURATION = 2.0
LATENCY_PING_INTERVAL = 0.1
LATENCY_DURATION = 2.0
BANDWIDTH_PACKET_SIZE = 1024
BANDWIDTH_DURATION = 2.0
def task_pidigits():
"""Pi calculation (Python)"""
_map = map
_count = itertools.count
_islice = itertools.islice
def calc_ndigits(n):
# From http://shootout.alioth.debian.org/
def gen_x():
return _map(lambda k: (k, 4*k + 2, 0, 2*k + 1), _count(1))
def compose(a, b):
aq, ar, as_, at = a
bq, br, bs, bt = b
return (aq * bq,
aq * br + ar * bt,
as_ * bq + at * bs,
as_ * br + at * bt)
def extract(z, j):
q, r, s, t = z
return (q*j + r) // (s*j + t)
def pi_digits():
z = (1, 0, 0, 1)
x = gen_x()
while 1:
y = extract(z, 3)
while y != extract(z, 4):
z = compose(z, next(x))
y = extract(z, 3)
z = compose((10, -10*y, 0, 1), z)
yield y
return list(_islice(pi_digits(), n))
return calc_ndigits, (50, )
def task_regex():
"""regular expression (C)"""
# XXX this task gives horrendous latency results.
import re
# Taken from the `inspect` module
pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)', re.MULTILINE)
with open(__file__, "r") as f:
arg = f.read(2000)
def findall(s):
t = time.time()
try:
return pat.findall(s)
finally:
print(time.time() - t)
return pat.findall, (arg, )
def task_sort():
"""list sorting (C)"""
def list_sort(l):
l = l[::-1]
l.sort()
return list_sort, (list(range(1000)), )
def task_compress_zlib():
"""zlib compression (C)"""
import zlib
with open(__file__, "rb") as f:
arg = f.read(5000) * 3
def compress(s):
zlib.decompress(zlib.compress(s, 5))
return compress, (arg, )
def task_compress_bz2():
"""bz2 compression (C)"""
import bz2
with open(__file__, "rb") as f:
arg = f.read(3000) * 2
def compress(s):
bz2.compress(s)
return compress, (arg, )
def task_hashing():
"""SHA1 hashing (C)"""
import hashlib
with open(__file__, "rb") as f:
arg = f.read(5000) * 30
def compute(s):
hashlib.sha1(s).digest()
return compute, (arg, )
throughput_tasks = [task_pidigits, task_regex]
for mod in 'bz2', 'hashlib':
try:
globals()[mod] = __import__(mod)
except ImportError:
globals()[mod] = None
# For whatever reasons, zlib gives irregular results, so we prefer bz2 or
# hashlib if available.
# (NOTE: hashlib releases the GIL from 2.7 and 3.1 onwards)
if bz2 is not None:
throughput_tasks.append(task_compress_bz2)
elif hashlib is not None:
throughput_tasks.append(task_hashing)
else:
throughput_tasks.append(task_compress_zlib)
latency_tasks = throughput_tasks
bandwidth_tasks = [task_pidigits]
class TimedLoop:
def __init__(self, func, args):
self.func = func
self.args = args
def __call__(self, start_time, min_duration, end_event, do_yield=False):
step = 20
niters = 0
duration = 0.0
_time = time.time
_sleep = time.sleep
_func = self.func
_args = self.args
t1 = start_time
while True:
for i in range(step):
_func(*_args)
t2 = _time()
# If another thread terminated, the current measurement is invalid
# => return the previous one.
if end_event:
return niters, duration
niters += step
duration = t2 - start_time
if duration >= min_duration:
end_event.append(None)
return niters, duration
if t2 - t1 < 0.01:
# Minimize interference of measurement on overall runtime
step = step * 3 // 2
elif do_yield:
# OS scheduling of Python threads is sometimes so bad that we
# have to force thread switching ourselves, otherwise we get
# completely useless results.
_sleep(0.0001)
t1 = t2
def run_throughput_test(func, args, nthreads):
assert nthreads >= 1
# Warm up
func(*args)
results = []
loop = TimedLoop(func, args)
end_event = []
if nthreads == 1:
# Pure single-threaded performance, without any switching or
# synchronization overhead.
start_time = time.time()
results.append(loop(start_time, THROUGHPUT_DURATION,
end_event, do_yield=False))
return results
started = False
ready_cond = threading.Condition()
start_cond = threading.Condition()
ready = []
def run():
with ready_cond:
ready.append(None)
ready_cond.notify()
with start_cond:
while not started:
start_cond.wait()
results.append(loop(start_time, THROUGHPUT_DURATION,
end_event, do_yield=True))
threads = []
for i in range(nthreads):
threads.append(threading.Thread(target=run))
for t in threads:
t.setDaemon(True)
t.start()
# We don't want measurements to include thread startup overhead,
# so we arrange for timing to start after all threads are ready.
with ready_cond:
while len(ready) < nthreads:
ready_cond.wait()
with start_cond:
start_time = time.time()
started = True
start_cond.notify(nthreads)
for t in threads:
t.join()
return results
def run_throughput_tests(max_threads):
for task in throughput_tasks:
print(task.__doc__)
print()
func, args = task()
nthreads = 1
baseline_speed = None
while nthreads <= max_threads:
results = run_throughput_test(func, args, nthreads)
# Taking the max duration rather than average gives pessimistic
# results rather than optimistic.
speed = sum(r[0] for r in results) / max(r[1] for r in results)
print("threads=%d: %d" % (nthreads, speed), end="")
if baseline_speed is None:
print(" iterations/s.")
baseline_speed = speed
else:
print(" ( %d %%)" % (speed / baseline_speed * 100))
nthreads += 1
print()
LAT_END = "END"
def _sendto(sock, s, addr):
sock.sendto(s.encode('ascii'), addr)
def _recv(sock, n):
return sock.recv(n).decode('ascii')
def latency_client(addr, nb_pings, interval):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
_time = time.time
_sleep = time.sleep
def _ping():
_sendto(sock, "%r\n" % _time(), addr)
# The first ping signals the parent process that we are ready.
_ping()
# We give the parent a bit of time to notice.
_sleep(1.0)
for i in range(nb_pings):
_sleep(interval)
_ping()
_sendto(sock, LAT_END + "\n", addr)
finally:
sock.close()
def run_latency_client(**kwargs):
cmd_line = [sys.executable, '-E', os.path.abspath(__file__)]
cmd_line.extend(['--latclient', repr(kwargs)])
return subprocess.Popen(cmd_line) #, stdin=subprocess.PIPE,
#stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
def run_latency_test(func, args, nthreads):
# Create a listening socket to receive the pings. We use UDP which should
# be painlessly cross-platform.
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("127.0.0.1", 0))
addr = sock.getsockname()
interval = LATENCY_PING_INTERVAL
duration = LATENCY_DURATION
nb_pings = int(duration / interval)
results = []
threads = []
end_event = []
start_cond = threading.Condition()
started = False
if nthreads > 0:
# Warm up
func(*args)
results = []
loop = TimedLoop(func, args)
ready = []
ready_cond = threading.Condition()
def run():
with ready_cond:
ready.append(None)
ready_cond.notify()
with start_cond:
while not started:
start_cond.wait()
loop(start_time, duration * 1.5, end_event, do_yield=False)
for i in range(nthreads):
threads.append(threading.Thread(target=run))
for t in threads:
t.setDaemon(True)
t.start()
# Wait for threads to be ready
with ready_cond:
while len(ready) < nthreads:
ready_cond.wait()
# Run the client and wait for the first ping(s) to arrive before
# unblocking the background threads.
chunks = []
process = run_latency_client(addr=sock.getsockname(),
nb_pings=nb_pings, interval=interval)
s = _recv(sock, 4096)
_time = time.time
with start_cond:
start_time = _time()
started = True
start_cond.notify(nthreads)
while LAT_END not in s:
s = _recv(sock, 4096)
t = _time()
chunks.append((t, s))
# Tell the background threads to stop.
end_event.append(None)
for t in threads:
t.join()
process.wait()
sock.close()
for recv_time, chunk in chunks:
# NOTE: it is assumed that a line sent by a client wasn't received
# in two chunks because the lines are very small.
for line in chunk.splitlines():
line = line.strip()
if line and line != LAT_END:
send_time = eval(line)
assert isinstance(send_time, float)
results.append((send_time, recv_time))
return results
def run_latency_tests(max_threads):
for task in latency_tasks:
print("Background CPU task:", task.__doc__)
print()
func, args = task()
nthreads = 0
while nthreads <= max_threads:
results = run_latency_test(func, args, nthreads)
n = len(results)
# We print out milliseconds
lats = [1000 * (t2 - t1) for (t1, t2) in results]
#print(list(map(int, lats)))
avg = sum(lats) / n
dev = (sum((x - avg) ** 2 for x in lats) / n) ** 0.5
print("CPU threads=%d: %d ms. (std dev: %d ms.)" % (nthreads, avg, dev), end="")
print()
#print(" [... from %d samples]" % n)
nthreads += 1
print()
BW_END = "END"
def bandwidth_client(addr, packet_size, duration):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("127.0.0.1", 0))
local_addr = sock.getsockname()
_time = time.time
_sleep = time.sleep
def _send_chunk(msg):
_sendto(sock, ("%r#%s\n" % (local_addr, msg)).rjust(packet_size), addr)
# We give the parent some time to be ready.
_sleep(1.0)
try:
start_time = _time()
end_time = start_time + duration * 2.0
i = 0
while _time() < end_time:
_send_chunk(str(i))
s = _recv(sock, packet_size)
assert len(s) == packet_size
i += 1
_send_chunk(BW_END)
finally:
sock.close()
def run_bandwidth_client(**kwargs):
cmd_line = [sys.executable, '-E', os.path.abspath(__file__)]
cmd_line.extend(['--bwclient', repr(kwargs)])
return subprocess.Popen(cmd_line) #, stdin=subprocess.PIPE,
#stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
def run_bandwidth_test(func, args, nthreads):
# Create a listening socket to receive the packets. We use UDP which should
# be painlessly cross-platform.
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.bind(("127.0.0.1", 0))
addr = sock.getsockname()
duration = BANDWIDTH_DURATION
packet_size = BANDWIDTH_PACKET_SIZE
results = []
threads = []
end_event = []
start_cond = threading.Condition()
started = False
if nthreads > 0:
# Warm up
func(*args)
results = []
loop = TimedLoop(func, args)
ready = []
ready_cond = threading.Condition()
def run():
with ready_cond:
ready.append(None)
ready_cond.notify()
with start_cond:
while not started:
start_cond.wait()
loop(start_time, duration * 1.5, end_event, do_yield=False)
for i in range(nthreads):
threads.append(threading.Thread(target=run))
for t in threads:
t.setDaemon(True)
t.start()
# Wait for threads to be ready
with ready_cond:
while len(ready) < nthreads:
ready_cond.wait()
# Run the client and wait for the first packet to arrive before
# unblocking the background threads.
process = run_bandwidth_client(addr=addr,
packet_size=packet_size,
duration=duration)
_time = time.time
# This will also wait for the parent to be ready
s = _recv(sock, packet_size)
remote_addr = eval(s.partition('#')[0])
with start_cond:
start_time = _time()
started = True
start_cond.notify(nthreads)
n = 0
first_time = None
while not end_event and BW_END not in s:
_sendto(sock, s, remote_addr)
s = _recv(sock, packet_size)
if first_time is None:
first_time = _time()
n += 1
end_time = _time()
end_event.append(None)
for t in threads:
t.join()
process.kill()
return (n - 1) / (end_time - first_time)
def run_bandwidth_tests(max_threads):
for task in bandwidth_tasks:
print("Background CPU task:", task.__doc__)
print()
func, args = task()
nthreads = 0
baseline_speed = None
while nthreads <= max_threads:
results = run_bandwidth_test(func, args, nthreads)
speed = results
#speed = len(results) * 1.0 / results[-1][0]
print("CPU threads=%d: %.1f" % (nthreads, speed), end="")
if baseline_speed is None:
print(" packets/s.")
baseline_speed = speed
else:
print(" ( %d %%)" % (speed / baseline_speed * 100))
nthreads += 1
print()
def main():
usage = "usage: %prog [-h|--help] [options]"
parser = OptionParser(usage=usage)
parser.add_option("-t", "--throughput",
action="store_true", dest="throughput", default=False,
help="run throughput tests")
parser.add_option("-l", "--latency",
action="store_true", dest="latency", default=False,
help="run latency tests")
parser.add_option("-b", "--bandwidth",
action="store_true", dest="bandwidth", default=False,
help="run I/O bandwidth tests")
parser.add_option("-i", "--interval",
action="store", type="int", dest="check_interval", default=None,
help="sys.setcheckinterval() value")
parser.add_option("-I", "--switch-interval",
action="store", type="float", dest="switch_interval", default=None,
help="sys.setswitchinterval() value")
parser.add_option("-n", "--num-threads",
action="store", type="int", dest="nthreads", default=4,
help="max number of threads in tests")
# Hidden option to run the pinging and bandwidth clients
parser.add_option("", "--latclient",
action="store", dest="latclient", default=None,
help=SUPPRESS_HELP)
parser.add_option("", "--bwclient",
action="store", dest="bwclient", default=None,
help=SUPPRESS_HELP)
options, args = parser.parse_args()
if args:
parser.error("unexpected arguments")
if options.latclient:
kwargs = eval(options.latclient)
latency_client(**kwargs)
return
if options.bwclient:
kwargs = eval(options.bwclient)
bandwidth_client(**kwargs)
return
if not options.throughput and not options.latency and not options.bandwidth:
options.throughput = options.latency = options.bandwidth = True
if options.check_interval:
sys.setcheckinterval(options.check_interval)
if options.switch_interval:
sys.setswitchinterval(options.switch_interval)
print("== %s %s (%s) ==" % (
platform.python_implementation(),
platform.python_version(),
platform.python_build()[0],
))
# Processor identification often has repeated spaces
cpu = ' '.join(platform.processor().split())
print("== %s %s on '%s' ==" % (
platform.machine(),
platform.system(),
cpu,
))
print()
if options.throughput:
print("--- Throughput ---")
print()
run_throughput_tests(options.nthreads)
if options.latency:
print("--- Latency ---")
print()
run_latency_tests(options.nthreads)
if options.bandwidth:
print("--- I/O bandwidth ---")
print()
run_bandwidth_tests(options.nthreads)
if __name__ == "__main__":
main()

4384
third_party/python/Tools/clinic/clinic.py vendored Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,791 @@
# Argument Clinic
# Copyright 2012-2013 by Larry Hastings.
# Licensed to the PSF under a contributor agreement.
#
import clinic
from clinic import DSLParser
import collections
import inspect
from test import support
import sys
import unittest
from unittest import TestCase
class FakeConverter:
def __init__(self, name, args):
self.name = name
self.args = args
class FakeConverterFactory:
def __init__(self, name):
self.name = name
def __call__(self, name, default, **kwargs):
return FakeConverter(self.name, kwargs)
class FakeConvertersDict:
def __init__(self):
self.used_converters = {}
def get(self, name, default):
return self.used_converters.setdefault(name, FakeConverterFactory(name))
clinic.Clinic.presets_text = ''
c = clinic.Clinic(language='C')
class FakeClinic:
def __init__(self):
self.converters = FakeConvertersDict()
self.legacy_converters = FakeConvertersDict()
self.language = clinic.CLanguage(None)
self.filename = None
self.block_parser = clinic.BlockParser('', self.language)
self.modules = collections.OrderedDict()
self.classes = collections.OrderedDict()
clinic.clinic = self
self.name = "FakeClinic"
self.line_prefix = self.line_suffix = ''
self.destinations = {}
self.add_destination("block", "buffer")
self.add_destination("file", "buffer")
self.add_destination("suppress", "suppress")
d = self.destinations.get
self.field_destinations = collections.OrderedDict((
('docstring_prototype', d('suppress')),
('docstring_definition', d('block')),
('methoddef_define', d('block')),
('impl_prototype', d('block')),
('parser_prototype', d('suppress')),
('parser_definition', d('block')),
('impl_definition', d('block')),
))
def get_destination(self, name):
d = self.destinations.get(name)
if not d:
sys.exit("Destination does not exist: " + repr(name))
return d
def add_destination(self, name, type, *args):
if name in self.destinations:
sys.exit("Destination already exists: " + repr(name))
self.destinations[name] = clinic.Destination(name, type, self, *args)
def is_directive(self, name):
return name == "module"
def directive(self, name, args):
self.called_directives[name] = args
_module_and_class = clinic.Clinic._module_and_class
class ClinicWholeFileTest(TestCase):
def test_eol(self):
# regression test:
# clinic's block parser didn't recognize
# the "end line" for the block if it
# didn't end in "\n" (as in, the last)
# byte of the file was '/'.
# so it would spit out an end line for you.
# and since you really already had one,
# the last line of the block got corrupted.
c = clinic.Clinic(clinic.CLanguage(None))
raw = "/*[clinic]\nfoo\n[clinic]*/"
cooked = c.parse(raw).splitlines()
end_line = cooked[2].rstrip()
# this test is redundant, it's just here explicitly to catch
# the regression test so we don't forget what it looked like
self.assertNotEqual(end_line, "[clinic]*/[clinic]*/")
self.assertEqual(end_line, "[clinic]*/")
class ClinicGroupPermuterTest(TestCase):
def _test(self, l, m, r, output):
computed = clinic.permute_optional_groups(l, m, r)
self.assertEqual(output, computed)
def test_range(self):
self._test([['start']], ['stop'], [['step']],
(
('stop',),
('start', 'stop',),
('start', 'stop', 'step',),
))
def test_add_window(self):
self._test([['x', 'y']], ['ch'], [['attr']],
(
('ch',),
('ch', 'attr'),
('x', 'y', 'ch',),
('x', 'y', 'ch', 'attr'),
))
def test_ludicrous(self):
self._test([['a1', 'a2', 'a3'], ['b1', 'b2']], ['c1'], [['d1', 'd2'], ['e1', 'e2', 'e3']],
(
('c1',),
('b1', 'b2', 'c1'),
('b1', 'b2', 'c1', 'd1', 'd2'),
('a1', 'a2', 'a3', 'b1', 'b2', 'c1'),
('a1', 'a2', 'a3', 'b1', 'b2', 'c1', 'd1', 'd2'),
('a1', 'a2', 'a3', 'b1', 'b2', 'c1', 'd1', 'd2', 'e1', 'e2', 'e3'),
))
def test_right_only(self):
self._test([], [], [['a'],['b'],['c']],
(
(),
('a',),
('a', 'b'),
('a', 'b', 'c')
))
def test_have_left_options_but_required_is_empty(self):
def fn():
clinic.permute_optional_groups(['a'], [], [])
self.assertRaises(AssertionError, fn)
class ClinicLinearFormatTest(TestCase):
def _test(self, input, output, **kwargs):
computed = clinic.linear_format(input, **kwargs)
self.assertEqual(output, computed)
def test_empty_strings(self):
self._test('', '')
def test_solo_newline(self):
self._test('\n', '\n')
def test_no_substitution(self):
self._test("""
abc
""", """
abc
""")
def test_empty_substitution(self):
self._test("""
abc
{name}
def
""", """
abc
def
""", name='')
def test_single_line_substitution(self):
self._test("""
abc
{name}
def
""", """
abc
GARGLE
def
""", name='GARGLE')
def test_multiline_substitution(self):
self._test("""
abc
{name}
def
""", """
abc
bingle
bungle
def
""", name='bingle\nbungle\n')
class InertParser:
def __init__(self, clinic):
pass
def parse(self, block):
pass
class CopyParser:
def __init__(self, clinic):
pass
def parse(self, block):
block.output = block.input
class ClinicBlockParserTest(TestCase):
def _test(self, input, output):
language = clinic.CLanguage(None)
blocks = list(clinic.BlockParser(input, language))
writer = clinic.BlockPrinter(language)
for block in blocks:
writer.print_block(block)
output = writer.f.getvalue()
assert output == input, "output != input!\n\noutput " + repr(output) + "\n\n input " + repr(input)
def round_trip(self, input):
return self._test(input, input)
def test_round_trip_1(self):
self.round_trip("""
verbatim text here
lah dee dah
""")
def test_round_trip_2(self):
self.round_trip("""
verbatim text here
lah dee dah
/*[inert]
abc
[inert]*/
def
/*[inert checksum: 7b18d017f89f61cf17d47f92749ea6930a3f1deb]*/
xyz
""")
def _test_clinic(self, input, output):
language = clinic.CLanguage(None)
c = clinic.Clinic(language)
c.parsers['inert'] = InertParser(c)
c.parsers['copy'] = CopyParser(c)
computed = c.parse(input)
self.assertEqual(output, computed)
def test_clinic_1(self):
self._test_clinic("""
verbatim text here
lah dee dah
/*[copy input]
def
[copy start generated code]*/
abc
/*[copy end generated code: output=03cfd743661f0797 input=7b18d017f89f61cf]*/
xyz
""", """
verbatim text here
lah dee dah
/*[copy input]
def
[copy start generated code]*/
def
/*[copy end generated code: output=7b18d017f89f61cf input=7b18d017f89f61cf]*/
xyz
""")
class ClinicParserTest(TestCase):
def test_trivial(self):
parser = DSLParser(FakeClinic())
block = clinic.Block("module os\nos.access")
parser.parse(block)
module, function = block.signatures
self.assertEqual("access", function.name)
self.assertEqual("os", module.name)
def test_ignore_line(self):
block = self.parse("#\nmodule os\nos.access")
module, function = block.signatures
self.assertEqual("access", function.name)
self.assertEqual("os", module.name)
def test_param(self):
function = self.parse_function("module os\nos.access\n path: int")
self.assertEqual("access", function.name)
self.assertEqual(2, len(function.parameters))
p = function.parameters['path']
self.assertEqual('path', p.name)
self.assertIsInstance(p.converter, clinic.int_converter)
def test_param_default(self):
function = self.parse_function("module os\nos.access\n follow_symlinks: bool = True")
p = function.parameters['follow_symlinks']
self.assertEqual(True, p.default)
def test_param_with_continuations(self):
function = self.parse_function("module os\nos.access\n follow_symlinks: \\\n bool \\\n =\\\n True")
p = function.parameters['follow_symlinks']
self.assertEqual(True, p.default)
def test_param_default_expression(self):
function = self.parse_function("module os\nos.access\n follow_symlinks: int(c_default='MAXSIZE') = sys.maxsize")
p = function.parameters['follow_symlinks']
self.assertEqual(sys.maxsize, p.default)
self.assertEqual("MAXSIZE", p.converter.c_default)
s = self.parse_function_should_fail("module os\nos.access\n follow_symlinks: int = sys.maxsize")
self.assertEqual(s, "Error on line 0:\nWhen you specify a named constant ('sys.maxsize') as your default value,\nyou MUST specify a valid c_default.\n")
def test_param_no_docstring(self):
function = self.parse_function("""
module os
os.access
follow_symlinks: bool = True
something_else: str = ''""")
p = function.parameters['follow_symlinks']
self.assertEqual(3, len(function.parameters))
self.assertIsInstance(function.parameters['something_else'].converter, clinic.str_converter)
def test_param_default_parameters_out_of_order(self):
s = self.parse_function_should_fail("""
module os
os.access
follow_symlinks: bool = True
something_else: str""")
self.assertEqual(s, """Error on line 0:
Can't have a parameter without a default ('something_else')
after a parameter with a default!
""")
def disabled_test_converter_arguments(self):
function = self.parse_function("module os\nos.access\n path: path_t(allow_fd=1)")
p = function.parameters['path']
self.assertEqual(1, p.converter.args['allow_fd'])
def test_function_docstring(self):
function = self.parse_function("""
module os
os.stat as os_stat_fn
path: str
Path to be examined
Perform a stat system call on the given path.""")
self.assertEqual("""
stat($module, /, path)
--
Perform a stat system call on the given path.
path
Path to be examined
""".strip(), function.docstring)
def test_explicit_parameters_in_docstring(self):
function = self.parse_function("""
module foo
foo.bar
x: int
Documentation for x.
y: int
This is the documentation for foo.
Okay, we're done here.
""")
self.assertEqual("""
bar($module, /, x, y)
--
This is the documentation for foo.
x
Documentation for x.
Okay, we're done here.
""".strip(), function.docstring)
def test_parser_regression_special_character_in_parameter_column_of_docstring_first_line(self):
function = self.parse_function("""
module os
os.stat
path: str
This/used to break Clinic!
""")
self.assertEqual("stat($module, /, path)\n--\n\nThis/used to break Clinic!", function.docstring)
def test_c_name(self):
function = self.parse_function("module os\nos.stat as os_stat_fn")
self.assertEqual("os_stat_fn", function.c_basename)
def test_return_converter(self):
function = self.parse_function("module os\nos.stat -> int")
self.assertIsInstance(function.return_converter, clinic.int_return_converter)
def test_star(self):
function = self.parse_function("module os\nos.access\n *\n follow_symlinks: bool = True")
p = function.parameters['follow_symlinks']
self.assertEqual(inspect.Parameter.KEYWORD_ONLY, p.kind)
self.assertEqual(0, p.group)
def test_group(self):
function = self.parse_function("module window\nwindow.border\n [\n ls : int\n ]\n /\n")
p = function.parameters['ls']
self.assertEqual(1, p.group)
def test_left_group(self):
function = self.parse_function("""
module curses
curses.addch
[
y: int
Y-coordinate.
x: int
X-coordinate.
]
ch: char
Character to add.
[
attr: long
Attributes for the character.
]
/
""")
for name, group in (
('y', -1), ('x', -1),
('ch', 0),
('attr', 1),
):
p = function.parameters[name]
self.assertEqual(p.group, group)
self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
self.assertEqual(function.docstring.strip(), """
addch([y, x,] ch, [attr])
y
Y-coordinate.
x
X-coordinate.
ch
Character to add.
attr
Attributes for the character.
""".strip())
def test_nested_groups(self):
function = self.parse_function("""
module curses
curses.imaginary
[
[
y1: int
Y-coordinate.
y2: int
Y-coordinate.
]
x1: int
X-coordinate.
x2: int
X-coordinate.
]
ch: char
Character to add.
[
attr1: long
Attributes for the character.
attr2: long
Attributes for the character.
attr3: long
Attributes for the character.
[
attr4: long
Attributes for the character.
attr5: long
Attributes for the character.
attr6: long
Attributes for the character.
]
]
/
""")
for name, group in (
('y1', -2), ('y2', -2),
('x1', -1), ('x2', -1),
('ch', 0),
('attr1', 1), ('attr2', 1), ('attr3', 1),
('attr4', 2), ('attr5', 2), ('attr6', 2),
):
p = function.parameters[name]
self.assertEqual(p.group, group)
self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
self.assertEqual(function.docstring.strip(), """
imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5,
attr6]])
y1
Y-coordinate.
y2
Y-coordinate.
x1
X-coordinate.
x2
X-coordinate.
ch
Character to add.
attr1
Attributes for the character.
attr2
Attributes for the character.
attr3
Attributes for the character.
attr4
Attributes for the character.
attr5
Attributes for the character.
attr6
Attributes for the character.
""".strip())
def parse_function_should_fail(self, s):
with support.captured_stdout() as stdout:
with self.assertRaises(SystemExit):
self.parse_function(s)
return stdout.getvalue()
def test_disallowed_grouping__two_top_groups_on_left(self):
s = self.parse_function_should_fail("""
module foo
foo.two_top_groups_on_left
[
group1 : int
]
[
group2 : int
]
param: int
""")
self.assertEqual(s,
('Error on line 0:\n'
'Function two_top_groups_on_left has an unsupported group configuration. (Unexpected state 2.b)\n'))
def test_disallowed_grouping__two_top_groups_on_right(self):
self.parse_function_should_fail("""
module foo
foo.two_top_groups_on_right
param: int
[
group1 : int
]
[
group2 : int
]
""")
def test_disallowed_grouping__parameter_after_group_on_right(self):
self.parse_function_should_fail("""
module foo
foo.parameter_after_group_on_right
param: int
[
[
group1 : int
]
group2 : int
]
""")
def test_disallowed_grouping__group_after_parameter_on_left(self):
self.parse_function_should_fail("""
module foo
foo.group_after_parameter_on_left
[
group2 : int
[
group1 : int
]
]
param: int
""")
def test_disallowed_grouping__empty_group_on_left(self):
self.parse_function_should_fail("""
module foo
foo.empty_group
[
[
]
group2 : int
]
param: int
""")
def test_disallowed_grouping__empty_group_on_right(self):
self.parse_function_should_fail("""
module foo
foo.empty_group
param: int
[
[
]
group2 : int
]
""")
def test_no_parameters(self):
function = self.parse_function("""
module foo
foo.bar
Docstring
""")
self.assertEqual("bar($module, /)\n--\n\nDocstring", function.docstring)
self.assertEqual(1, len(function.parameters)) # self!
def test_init_with_no_parameters(self):
function = self.parse_function("""
module foo
class foo.Bar "unused" "notneeded"
foo.Bar.__init__
Docstring
""", signatures_in_block=3, function_index=2)
# self is not in the signature
self.assertEqual("Bar()\n--\n\nDocstring", function.docstring)
# but it *is* a parameter
self.assertEqual(1, len(function.parameters))
def test_illegal_module_line(self):
self.parse_function_should_fail("""
module foo
foo.bar => int
/
""")
def test_illegal_c_basename(self):
self.parse_function_should_fail("""
module foo
foo.bar as 935
/
""")
def test_single_star(self):
self.parse_function_should_fail("""
module foo
foo.bar
*
*
""")
def test_parameters_required_after_star_without_initial_parameters_or_docstring(self):
self.parse_function_should_fail("""
module foo
foo.bar
*
""")
def test_parameters_required_after_star_without_initial_parameters_with_docstring(self):
self.parse_function_should_fail("""
module foo
foo.bar
*
Docstring here.
""")
def test_parameters_required_after_star_with_initial_parameters_without_docstring(self):
self.parse_function_should_fail("""
module foo
foo.bar
this: int
*
""")
def test_parameters_required_after_star_with_initial_parameters_and_docstring(self):
self.parse_function_should_fail("""
module foo
foo.bar
this: int
*
Docstring.
""")
def test_single_slash(self):
self.parse_function_should_fail("""
module foo
foo.bar
/
/
""")
def test_mix_star_and_slash(self):
self.parse_function_should_fail("""
module foo
foo.bar
x: int
y: int
*
z: int
/
""")
def test_parameters_not_permitted_after_slash_for_now(self):
self.parse_function_should_fail("""
module foo
foo.bar
/
x: int
""")
def test_function_not_at_column_0(self):
function = self.parse_function("""
module foo
foo.bar
x: int
Nested docstring here, goeth.
*
y: str
Not at column 0!
""")
self.assertEqual("""
bar($module, /, x, *, y)
--
Not at column 0!
x
Nested docstring here, goeth.
""".strip(), function.docstring)
def test_directive(self):
c = FakeClinic()
parser = DSLParser(c)
parser.flag = False
parser.directives['setflag'] = lambda : setattr(parser, 'flag', True)
block = clinic.Block("setflag")
parser.parse(block)
self.assertTrue(parser.flag)
def test_legacy_converters(self):
block = self.parse('module os\nos.access\n path: "s"')
module, function = block.signatures
self.assertIsInstance((function.parameters['path']).converter, clinic.str_converter)
def parse(self, text):
c = FakeClinic()
parser = DSLParser(c)
block = clinic.Block(text)
parser.parse(block)
return block
def parse_function(self, text, signatures_in_block=2, function_index=1):
block = self.parse(text)
s = block.signatures
self.assertEqual(len(s), signatures_in_block)
assert isinstance(s[0], clinic.Module)
assert isinstance(s[function_index], clinic.Function)
return s[function_index]
def test_scaffolding(self):
# test repr on special values
self.assertEqual(repr(clinic.unspecified), '<Unspecified>')
self.assertEqual(repr(clinic.NULL), '<Null>')
# test that fail fails
with support.captured_stdout() as stdout:
with self.assertRaises(SystemExit):
clinic.fail('The igloos are melting!', filename='clown.txt', line_number=69)
self.assertEqual(stdout.getvalue(), 'Error in file "clown.txt" on line 69:\nThe igloos are melting!\n')
if __name__ == "__main__":
unittest.main()

191
third_party/python/Tools/clinic/cpp.py vendored Normal file
View file

@ -0,0 +1,191 @@
import re
import sys
def negate(condition):
"""
Returns a CPP conditional that is the opposite of the conditional passed in.
"""
if condition.startswith('!'):
return condition[1:]
return "!" + condition
class Monitor:
"""
A simple C preprocessor that scans C source and computes, line by line,
what the current C preprocessor #if state is.
Doesn't handle everything--for example, if you have /* inside a C string,
without a matching */ (also inside a C string), or with a */ inside a C
string but on another line and with preprocessor macros in between...
the parser will get lost.
Anyway this implementation seems to work well enough for the CPython sources.
"""
is_a_simple_defined = re.compile(r'^defined\s*\(\s*[A-Za-z0-9_]+\s*\)$').match
def __init__(self, filename=None, *, verbose=False):
self.stack = []
self.in_comment = False
self.continuation = None
self.line_number = 0
self.filename = filename
self.verbose = verbose
def __repr__(self):
return ''.join((
'<Monitor ',
str(id(self)),
" line=", str(self.line_number),
" condition=", repr(self.condition()),
">"))
def status(self):
return str(self.line_number).rjust(4) + ": " + self.condition()
def condition(self):
"""
Returns the current preprocessor state, as a single #if condition.
"""
return " && ".join(condition for token, condition in self.stack)
def fail(self, *a):
if self.filename:
filename = " " + self.filename
else:
filename = ''
print("Error at" + filename, "line", self.line_number, ":")
print(" ", ' '.join(str(x) for x in a))
sys.exit(-1)
def close(self):
if self.stack:
self.fail("Ended file while still in a preprocessor conditional block!")
def write(self, s):
for line in s.split("\n"):
self.writeline(line)
def writeline(self, line):
self.line_number += 1
line = line.strip()
def pop_stack():
if not self.stack:
self.fail("#" + token + " without matching #if / #ifdef / #ifndef!")
return self.stack.pop()
if self.continuation:
line = self.continuation + line
self.continuation = None
if not line:
return
if line.endswith('\\'):
self.continuation = line[:-1].rstrip() + " "
return
# we have to ignore preprocessor commands inside comments
#
# we also have to handle this:
# /* start
# ...
# */ /* <-- tricky!
# ...
# */
# and this:
# /* start
# ...
# */ /* also tricky! */
if self.in_comment:
if '*/' in line:
# snip out the comment and continue
#
# GCC allows
# /* comment
# */ #include <stdio.h>
# maybe other compilers too?
_, _, line = line.partition('*/')
self.in_comment = False
while True:
if '/*' in line:
if self.in_comment:
self.fail("Nested block comment!")
before, _, remainder = line.partition('/*')
comment, comment_ends, after = remainder.partition('*/')
if comment_ends:
# snip out the comment
line = before.rstrip() + ' ' + after.lstrip()
continue
# comment continues to eol
self.in_comment = True
line = before.rstrip()
break
# we actually have some // comments
# (but block comments take precedence)
before, line_comment, comment = line.partition('//')
if line_comment:
line = before.rstrip()
if not line.startswith('#'):
return
line = line[1:].lstrip()
assert line
fields = line.split()
token = fields[0].lower()
condition = ' '.join(fields[1:]).strip()
if_tokens = {'if', 'ifdef', 'ifndef'}
all_tokens = if_tokens | {'elif', 'else', 'endif'}
if token not in all_tokens:
return
# cheat a little here, to reuse the implementation of if
if token == 'elif':
pop_stack()
token = 'if'
if token in if_tokens:
if not condition:
self.fail("Invalid format for #" + token + " line: no argument!")
if token == 'if':
if not self.is_a_simple_defined(condition):
condition = "(" + condition + ")"
else:
fields = condition.split()
if len(fields) != 1:
self.fail("Invalid format for #" + token + " line: should be exactly one argument!")
symbol = fields[0]
condition = 'defined(' + symbol + ')'
if token == 'ifndef':
condition = '!' + condition
self.stack.append(("if", condition))
if self.verbose:
print(self.status())
return
previous_token, previous_condition = pop_stack()
if token == 'else':
self.stack.append(('else', negate(previous_condition)))
elif token == 'endif':
pass
if self.verbose:
print(self.status())
if __name__ == '__main__':
for filename in sys.argv[1:]:
with open(filename, "rt") as f:
cpp = Monitor(filename, verbose=True)
print()
print(filename)
for line_number, line in enumerate(f.read().split('\n'), 1):
cpp.writeline(line)

16
third_party/python/Tools/demo/README vendored Normal file
View file

@ -0,0 +1,16 @@
This directory contains a collection of demonstration scripts for
various aspects of Python programming.
beer.py Well-known programming example: Bottles of beer.
eiffel.py Python advanced magic: A metaclass for Eiffel post/preconditions.
hanoi.py Well-known programming example: Towers of Hanoi.
life.py Curses programming: Simple game-of-life.
markov.py Algorithms: Markov chain simulation.
mcast.py Network programming: Send and receive UDP multicast packets.
queens.py Well-known programming example: N-Queens problem.
redemo.py Regular Expressions: GUI script to test regexes.
rpython.py Network programming: Small client for remote code execution.
rpythond.py Network programming: Small server for remote code execution.
sortvisu.py GUI programming: Visualization of different sort algorithms.
ss1.py GUI/Application programming: A simple spreadsheet application.
vector.py Python basics: A vector class with demonstrating special methods.

25
third_party/python/Tools/demo/beer.py vendored Executable file
View file

@ -0,0 +1,25 @@
#!/usr/bin/env python3
"""
A Python version of the classic "bottles of beer on the wall" programming
example.
By Guido van Rossum, demystified after a version by Fredrik Lundh.
"""
import sys
n = 100
if sys.argv[1:]:
n = int(sys.argv[1])
def bottle(n):
if n == 0: return "no more bottles of beer"
if n == 1: return "one bottle of beer"
return str(n) + " bottles of beer"
for i in range(n, 0, -1):
print(bottle(i), "on the wall,")
print(bottle(i) + ".")
print("Take one down, pass it around,")
print(bottle(i-1), "on the wall.")

146
third_party/python/Tools/demo/eiffel.py vendored Executable file
View file

@ -0,0 +1,146 @@
#!/usr/bin/env python3
"""
Support Eiffel-style preconditions and postconditions for functions.
An example for Python metaclasses.
"""
import unittest
from types import FunctionType as function
class EiffelBaseMetaClass(type):
def __new__(meta, name, bases, dict):
meta.convert_methods(dict)
return super(EiffelBaseMetaClass, meta).__new__(
meta, name, bases, dict)
@classmethod
def convert_methods(cls, dict):
"""Replace functions in dict with EiffelMethod wrappers.
The dict is modified in place.
If a method ends in _pre or _post, it is removed from the dict
regardless of whether there is a corresponding method.
"""
# find methods with pre or post conditions
methods = []
for k, v in dict.items():
if k.endswith('_pre') or k.endswith('_post'):
assert isinstance(v, function)
elif isinstance(v, function):
methods.append(k)
for m in methods:
pre = dict.get("%s_pre" % m)
post = dict.get("%s_post" % m)
if pre or post:
dict[m] = cls.make_eiffel_method(dict[m], pre, post)
class EiffelMetaClass1(EiffelBaseMetaClass):
# an implementation of the "eiffel" meta class that uses nested functions
@staticmethod
def make_eiffel_method(func, pre, post):
def method(self, *args, **kwargs):
if pre:
pre(self, *args, **kwargs)
rv = func(self, *args, **kwargs)
if post:
post(self, rv, *args, **kwargs)
return rv
if func.__doc__:
method.__doc__ = func.__doc__
return method
class EiffelMethodWrapper:
def __init__(self, inst, descr):
self._inst = inst
self._descr = descr
def __call__(self, *args, **kwargs):
return self._descr.callmethod(self._inst, args, kwargs)
class EiffelDescriptor:
def __init__(self, func, pre, post):
self._func = func
self._pre = pre
self._post = post
self.__name__ = func.__name__
self.__doc__ = func.__doc__
def __get__(self, obj, cls):
return EiffelMethodWrapper(obj, self)
def callmethod(self, inst, args, kwargs):
if self._pre:
self._pre(inst, *args, **kwargs)
x = self._func(inst, *args, **kwargs)
if self._post:
self._post(inst, x, *args, **kwargs)
return x
class EiffelMetaClass2(EiffelBaseMetaClass):
# an implementation of the "eiffel" meta class that uses descriptors
make_eiffel_method = EiffelDescriptor
class Tests(unittest.TestCase):
def testEiffelMetaClass1(self):
self._test(EiffelMetaClass1)
def testEiffelMetaClass2(self):
self._test(EiffelMetaClass2)
def _test(self, metaclass):
class Eiffel(metaclass=metaclass):
pass
class Test(Eiffel):
def m(self, arg):
"""Make it a little larger"""
return arg + 1
def m2(self, arg):
"""Make it a little larger"""
return arg + 1
def m2_pre(self, arg):
assert arg > 0
def m2_post(self, result, arg):
assert result > arg
class Sub(Test):
def m2(self, arg):
return arg**2
def m2_post(self, Result, arg):
super(Sub, self).m2_post(Result, arg)
assert Result < 100
t = Test()
self.assertEqual(t.m(1), 2)
self.assertEqual(t.m2(1), 2)
self.assertRaises(AssertionError, t.m2, 0)
s = Sub()
self.assertRaises(AssertionError, s.m2, 1)
self.assertRaises(AssertionError, s.m2, 10)
self.assertEqual(s.m2(5), 25)
if __name__ == "__main__":
unittest.main()

154
third_party/python/Tools/demo/hanoi.py vendored Executable file
View file

@ -0,0 +1,154 @@
#!/usr/bin/env python3
"""
Animated Towers of Hanoi using Tk with optional bitmap file in background.
Usage: hanoi.py [n [bitmapfile]]
n is the number of pieces to animate; default is 4, maximum 15.
The bitmap file can be any X11 bitmap file (look in /usr/include/X11/bitmaps for
samples); it is displayed as the background of the animation. Default is no
bitmap.
"""
from tkinter import Tk, Canvas
# Basic Towers-of-Hanoi algorithm: move n pieces from a to b, using c
# as temporary. For each move, call report()
def hanoi(n, a, b, c, report):
if n <= 0: return
hanoi(n-1, a, c, b, report)
report(n, a, b)
hanoi(n-1, c, b, a, report)
# The graphical interface
class Tkhanoi:
# Create our objects
def __init__(self, n, bitmap = None):
self.n = n
self.tk = tk = Tk()
self.canvas = c = Canvas(tk)
c.pack()
width, height = tk.getint(c['width']), tk.getint(c['height'])
# Add background bitmap
if bitmap:
self.bitmap = c.create_bitmap(width//2, height//2,
bitmap=bitmap,
foreground='blue')
# Generate pegs
pegwidth = 10
pegheight = height//2
pegdist = width//3
x1, y1 = (pegdist-pegwidth)//2, height*1//3
x2, y2 = x1+pegwidth, y1+pegheight
self.pegs = []
p = c.create_rectangle(x1, y1, x2, y2, fill='black')
self.pegs.append(p)
x1, x2 = x1+pegdist, x2+pegdist
p = c.create_rectangle(x1, y1, x2, y2, fill='black')
self.pegs.append(p)
x1, x2 = x1+pegdist, x2+pegdist
p = c.create_rectangle(x1, y1, x2, y2, fill='black')
self.pegs.append(p)
self.tk.update()
# Generate pieces
pieceheight = pegheight//16
maxpiecewidth = pegdist*2//3
minpiecewidth = 2*pegwidth
self.pegstate = [[], [], []]
self.pieces = {}
x1, y1 = (pegdist-maxpiecewidth)//2, y2-pieceheight-2
x2, y2 = x1+maxpiecewidth, y1+pieceheight
dx = (maxpiecewidth-minpiecewidth) // (2*max(1, n-1))
for i in range(n, 0, -1):
p = c.create_rectangle(x1, y1, x2, y2, fill='red')
self.pieces[i] = p
self.pegstate[0].append(i)
x1, x2 = x1 + dx, x2-dx
y1, y2 = y1 - pieceheight-2, y2-pieceheight-2
self.tk.update()
self.tk.after(25)
# Run -- never returns
def run(self):
while 1:
hanoi(self.n, 0, 1, 2, self.report)
hanoi(self.n, 1, 2, 0, self.report)
hanoi(self.n, 2, 0, 1, self.report)
hanoi(self.n, 0, 2, 1, self.report)
hanoi(self.n, 2, 1, 0, self.report)
hanoi(self.n, 1, 0, 2, self.report)
# Reporting callback for the actual hanoi function
def report(self, i, a, b):
if self.pegstate[a][-1] != i: raise RuntimeError # Assertion
del self.pegstate[a][-1]
p = self.pieces[i]
c = self.canvas
# Lift the piece above peg a
ax1, ay1, ax2, ay2 = c.bbox(self.pegs[a])
while 1:
x1, y1, x2, y2 = c.bbox(p)
if y2 < ay1: break
c.move(p, 0, -1)
self.tk.update()
# Move it towards peg b
bx1, by1, bx2, by2 = c.bbox(self.pegs[b])
newcenter = (bx1+bx2)//2
while 1:
x1, y1, x2, y2 = c.bbox(p)
center = (x1+x2)//2
if center == newcenter: break
if center > newcenter: c.move(p, -1, 0)
else: c.move(p, 1, 0)
self.tk.update()
# Move it down on top of the previous piece
pieceheight = y2-y1
newbottom = by2 - pieceheight*len(self.pegstate[b]) - 2
while 1:
x1, y1, x2, y2 = c.bbox(p)
if y2 >= newbottom: break
c.move(p, 0, 1)
self.tk.update()
# Update peg state
self.pegstate[b].append(i)
def main():
import sys
# First argument is number of pegs, default 4
if sys.argv[1:]:
n = int(sys.argv[1])
else:
n = 4
# Second argument is bitmap file, default none
if sys.argv[2:]:
bitmap = sys.argv[2]
# Reverse meaning of leading '@' compared to Tk
if bitmap[0] == '@': bitmap = bitmap[1:]
else: bitmap = '@' + bitmap
else:
bitmap = None
# Create the graphical objects...
h = Tkhanoi(n, bitmap)
# ...and run!
h.run()
# Call main when run as script
if __name__ == '__main__':
main()

262
third_party/python/Tools/demo/life.py vendored Executable file
View file

@ -0,0 +1,262 @@
#!/usr/bin/env python3
"""
A curses-based version of Conway's Game of Life.
An empty board will be displayed, and the following commands are available:
E : Erase the board
R : Fill the board randomly
S : Step for a single generation
C : Update continuously until a key is struck
Q : Quit
Cursor keys : Move the cursor around the board
Space or Enter : Toggle the contents of the cursor's position
Contributed by Andrew Kuchling, Mouse support and color by Dafydd Crosby.
"""
import curses
import random
class LifeBoard:
"""Encapsulates a Life board
Attributes:
X,Y : horizontal and vertical size of the board
state : dictionary mapping (x,y) to 0 or 1
Methods:
display(update_board) -- If update_board is true, compute the
next generation. Then display the state
of the board and refresh the screen.
erase() -- clear the entire board
make_random() -- fill the board randomly
set(y,x) -- set the given cell to Live; doesn't refresh the screen
toggle(y,x) -- change the given cell from live to dead, or vice
versa, and refresh the screen display
"""
def __init__(self, scr, char=ord('*')):
"""Create a new LifeBoard instance.
scr -- curses screen object to use for display
char -- character used to render live cells (default: '*')
"""
self.state = {}
self.scr = scr
Y, X = self.scr.getmaxyx()
self.X, self.Y = X - 2, Y - 2 - 1
self.char = char
self.scr.clear()
# Draw a border around the board
border_line = '+' + (self.X * '-') + '+'
self.scr.addstr(0, 0, border_line)
self.scr.addstr(self.Y + 1, 0, border_line)
for y in range(0, self.Y):
self.scr.addstr(1 + y, 0, '|')
self.scr.addstr(1 + y, self.X + 1, '|')
self.scr.refresh()
def set(self, y, x):
"""Set a cell to the live state"""
if x < 0 or self.X <= x or y < 0 or self.Y <= y:
raise ValueError("Coordinates out of range %i,%i" % (y, x))
self.state[x, y] = 1
def toggle(self, y, x):
"""Toggle a cell's state between live and dead"""
if x < 0 or self.X <= x or y < 0 or self.Y <= y:
raise ValueError("Coordinates out of range %i,%i" % (y, x))
if (x, y) in self.state:
del self.state[x, y]
self.scr.addch(y + 1, x + 1, ' ')
else:
self.state[x, y] = 1
if curses.has_colors():
# Let's pick a random color!
self.scr.attrset(curses.color_pair(random.randrange(1, 7)))
self.scr.addch(y + 1, x + 1, self.char)
self.scr.attrset(0)
self.scr.refresh()
def erase(self):
"""Clear the entire board and update the board display"""
self.state = {}
self.display(update_board=False)
def display(self, update_board=True):
"""Display the whole board, optionally computing one generation"""
M, N = self.X, self.Y
if not update_board:
for i in range(0, M):
for j in range(0, N):
if (i, j) in self.state:
self.scr.addch(j + 1, i + 1, self.char)
else:
self.scr.addch(j + 1, i + 1, ' ')
self.scr.refresh()
return
d = {}
self.boring = 1
for i in range(0, M):
L = range(max(0, i - 1), min(M, i + 2))
for j in range(0, N):
s = 0
live = (i, j) in self.state
for k in range(max(0, j - 1), min(N, j + 2)):
for l in L:
if (l, k) in self.state:
s += 1
s -= live
if s == 3:
# Birth
d[i, j] = 1
if curses.has_colors():
# Let's pick a random color!
self.scr.attrset(curses.color_pair(
random.randrange(1, 7)))
self.scr.addch(j + 1, i + 1, self.char)
self.scr.attrset(0)
if not live:
self.boring = 0
elif s == 2 and live:
# Survival
d[i, j] = 1
elif live:
# Death
self.scr.addch(j + 1, i + 1, ' ')
self.boring = 0
self.state = d
self.scr.refresh()
def make_random(self):
"Fill the board with a random pattern"
self.state = {}
for i in range(0, self.X):
for j in range(0, self.Y):
if random.random() > 0.5:
self.set(j, i)
def erase_menu(stdscr, menu_y):
"Clear the space where the menu resides"
stdscr.move(menu_y, 0)
stdscr.clrtoeol()
stdscr.move(menu_y + 1, 0)
stdscr.clrtoeol()
def display_menu(stdscr, menu_y):
"Display the menu of possible keystroke commands"
erase_menu(stdscr, menu_y)
# If color, then light the menu up :-)
if curses.has_colors():
stdscr.attrset(curses.color_pair(1))
stdscr.addstr(menu_y, 4,
'Use the cursor keys to move, and space or Enter to toggle a cell.')
stdscr.addstr(menu_y + 1, 4,
'E)rase the board, R)andom fill, S)tep once or C)ontinuously, Q)uit')
stdscr.attrset(0)
def keyloop(stdscr):
# Clear the screen and display the menu of keys
stdscr.clear()
stdscr_y, stdscr_x = stdscr.getmaxyx()
menu_y = (stdscr_y - 3) - 1
display_menu(stdscr, menu_y)
# If color, then initialize the color pairs
if curses.has_colors():
curses.init_pair(1, curses.COLOR_BLUE, 0)
curses.init_pair(2, curses.COLOR_CYAN, 0)
curses.init_pair(3, curses.COLOR_GREEN, 0)
curses.init_pair(4, curses.COLOR_MAGENTA, 0)
curses.init_pair(5, curses.COLOR_RED, 0)
curses.init_pair(6, curses.COLOR_YELLOW, 0)
curses.init_pair(7, curses.COLOR_WHITE, 0)
# Set up the mask to listen for mouse events
curses.mousemask(curses.BUTTON1_CLICKED)
# Allocate a subwindow for the Life board and create the board object
subwin = stdscr.subwin(stdscr_y - 3, stdscr_x, 0, 0)
board = LifeBoard(subwin, char=ord('*'))
board.display(update_board=False)
# xpos, ypos are the cursor's position
xpos, ypos = board.X // 2, board.Y // 2
# Main loop:
while True:
stdscr.move(1 + ypos, 1 + xpos) # Move the cursor
c = stdscr.getch() # Get a keystroke
if 0 < c < 256:
c = chr(c)
if c in ' \n':
board.toggle(ypos, xpos)
elif c in 'Cc':
erase_menu(stdscr, menu_y)
stdscr.addstr(menu_y, 6, ' Hit any key to stop continuously '
'updating the screen.')
stdscr.refresh()
# Activate nodelay mode; getch() will return -1
# if no keystroke is available, instead of waiting.
stdscr.nodelay(1)
while True:
c = stdscr.getch()
if c != -1:
break
stdscr.addstr(0, 0, '/')
stdscr.refresh()
board.display()
stdscr.addstr(0, 0, '+')
stdscr.refresh()
stdscr.nodelay(0) # Disable nodelay mode
display_menu(stdscr, menu_y)
elif c in 'Ee':
board.erase()
elif c in 'Qq':
break
elif c in 'Rr':
board.make_random()
board.display(update_board=False)
elif c in 'Ss':
board.display()
else:
# Ignore incorrect keys
pass
elif c == curses.KEY_UP and ypos > 0:
ypos -= 1
elif c == curses.KEY_DOWN and ypos + 1 < board.Y:
ypos += 1
elif c == curses.KEY_LEFT and xpos > 0:
xpos -= 1
elif c == curses.KEY_RIGHT and xpos + 1 < board.X:
xpos += 1
elif c == curses.KEY_MOUSE:
mouse_id, mouse_x, mouse_y, mouse_z, button_state = curses.getmouse()
if (mouse_x > 0 and mouse_x < board.X + 1 and
mouse_y > 0 and mouse_y < board.Y + 1):
xpos = mouse_x - 1
ypos = mouse_y - 1
board.toggle(ypos, xpos)
else:
# They've clicked outside the board
curses.flash()
else:
# Ignore incorrect keys
pass
def main(stdscr):
keyloop(stdscr) # Enter the main loop
if __name__ == '__main__':
curses.wrapper(main)

125
third_party/python/Tools/demo/markov.py vendored Executable file
View file

@ -0,0 +1,125 @@
#!/usr/bin/env python3
"""
Markov chain simulation of words or characters.
"""
class Markov:
def __init__(self, histsize, choice):
self.histsize = histsize
self.choice = choice
self.trans = {}
def add(self, state, next):
self.trans.setdefault(state, []).append(next)
def put(self, seq):
n = self.histsize
add = self.add
add(None, seq[:0])
for i in range(len(seq)):
add(seq[max(0, i-n):i], seq[i:i+1])
add(seq[len(seq)-n:], None)
def get(self):
choice = self.choice
trans = self.trans
n = self.histsize
seq = choice(trans[None])
while True:
subseq = seq[max(0, len(seq)-n):]
options = trans[subseq]
next = choice(options)
if not next:
break
seq += next
return seq
def test():
import sys, random, getopt
args = sys.argv[1:]
try:
opts, args = getopt.getopt(args, '0123456789cdwq')
except getopt.error:
print('Usage: %s [-#] [-cddqw] [file] ...' % sys.argv[0])
print('Options:')
print('-#: 1-digit history size (default 2)')
print('-c: characters (default)')
print('-w: words')
print('-d: more debugging output')
print('-q: no debugging output')
print('Input files (default stdin) are split in paragraphs')
print('separated blank lines and each paragraph is split')
print('in words by whitespace, then reconcatenated with')
print('exactly one space separating words.')
print('Output consists of paragraphs separated by blank')
print('lines, where lines are no longer than 72 characters.')
sys.exit(2)
histsize = 2
do_words = False
debug = 1
for o, a in opts:
if '-0' <= o <= '-9': histsize = int(o[1:])
if o == '-c': do_words = False
if o == '-d': debug += 1
if o == '-q': debug = 0
if o == '-w': do_words = True
if not args:
args = ['-']
m = Markov(histsize, random.choice)
try:
for filename in args:
if filename == '-':
f = sys.stdin
if f.isatty():
print('Sorry, need stdin from file')
continue
else:
f = open(filename, 'r')
if debug: print('processing', filename, '...')
text = f.read()
f.close()
paralist = text.split('\n\n')
for para in paralist:
if debug > 1: print('feeding ...')
words = para.split()
if words:
if do_words:
data = tuple(words)
else:
data = ' '.join(words)
m.put(data)
except KeyboardInterrupt:
print('Interrupted -- continue with data read so far')
if not m.trans:
print('No valid input files')
return
if debug: print('done.')
if debug > 1:
for key in m.trans.keys():
if key is None or len(key) < histsize:
print(repr(key), m.trans[key])
if histsize == 0: print(repr(''), m.trans[''])
print()
while True:
data = m.get()
if do_words:
words = data
else:
words = data.split()
n = 0
limit = 72
for w in words:
if n + len(w) > limit:
print()
n = 0
print(w, end=' ')
n += len(w) + 1
print()
print()
if __name__ == "__main__":
test()

82
third_party/python/Tools/demo/mcast.py vendored Executable file
View file

@ -0,0 +1,82 @@
#!/usr/bin/env python3
"""
Send/receive UDP multicast packets.
Requires that your OS kernel supports IP multicast.
Usage:
mcast -s (sender, IPv4)
mcast -s -6 (sender, IPv6)
mcast (receivers, IPv4)
mcast -6 (receivers, IPv6)
"""
MYPORT = 8123
MYGROUP_4 = '225.0.0.250'
MYGROUP_6 = 'ff15:7079:7468:6f6e:6465:6d6f:6d63:6173'
MYTTL = 1 # Increase to reach other networks
import time
import struct
import socket
import sys
def main():
group = MYGROUP_6 if "-6" in sys.argv[1:] else MYGROUP_4
if "-s" in sys.argv[1:]:
sender(group)
else:
receiver(group)
def sender(group):
addrinfo = socket.getaddrinfo(group, None)[0]
s = socket.socket(addrinfo[0], socket.SOCK_DGRAM)
# Set Time-to-live (optional)
ttl_bin = struct.pack('@i', MYTTL)
if addrinfo[0] == socket.AF_INET: # IPv4
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl_bin)
else:
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, ttl_bin)
while True:
data = repr(time.time()).encode('utf-8') + b'\0'
s.sendto(data, (addrinfo[4][0], MYPORT))
time.sleep(1)
def receiver(group):
# Look up multicast group address in name server and find out IP version
addrinfo = socket.getaddrinfo(group, None)[0]
# Create a socket
s = socket.socket(addrinfo[0], socket.SOCK_DGRAM)
# Allow multiple copies of this program on one machine
# (not strictly needed)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Bind it to the port
s.bind(('', MYPORT))
group_bin = socket.inet_pton(addrinfo[0], addrinfo[4][0])
# Join group
if addrinfo[0] == socket.AF_INET: # IPv4
mreq = group_bin + struct.pack('=I', socket.INADDR_ANY)
s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
else:
mreq = group_bin + struct.pack('@I', 0)
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
# Loop, printing any data we receive
while True:
data, sender = s.recvfrom(1500)
while data[-1:] == '\0': data = data[:-1] # Strip trailing \0's
print(str(sender) + ' ' + repr(data))
if __name__ == '__main__':
main()

85
third_party/python/Tools/demo/queens.py vendored Executable file
View file

@ -0,0 +1,85 @@
#!/usr/bin/env python3
"""
N queens problem.
The (well-known) problem is due to Niklaus Wirth.
This solution is inspired by Dijkstra (Structured Programming). It is
a classic recursive backtracking approach.
"""
N = 8 # Default; command line overrides
class Queens:
def __init__(self, n=N):
self.n = n
self.reset()
def reset(self):
n = self.n
self.y = [None] * n # Where is the queen in column x
self.row = [0] * n # Is row[y] safe?
self.up = [0] * (2*n-1) # Is upward diagonal[x-y] safe?
self.down = [0] * (2*n-1) # Is downward diagonal[x+y] safe?
self.nfound = 0 # Instrumentation
def solve(self, x=0): # Recursive solver
for y in range(self.n):
if self.safe(x, y):
self.place(x, y)
if x+1 == self.n:
self.display()
else:
self.solve(x+1)
self.remove(x, y)
def safe(self, x, y):
return not self.row[y] and not self.up[x-y] and not self.down[x+y]
def place(self, x, y):
self.y[x] = y
self.row[y] = 1
self.up[x-y] = 1
self.down[x+y] = 1
def remove(self, x, y):
self.y[x] = None
self.row[y] = 0
self.up[x-y] = 0
self.down[x+y] = 0
silent = 0 # If true, count solutions only
def display(self):
self.nfound = self.nfound + 1
if self.silent:
return
print('+-' + '--'*self.n + '+')
for y in range(self.n-1, -1, -1):
print('|', end=' ')
for x in range(self.n):
if self.y[x] == y:
print("Q", end=' ')
else:
print(".", end=' ')
print('|')
print('+-' + '--'*self.n + '+')
def main():
import sys
silent = 0
n = N
if sys.argv[1:2] == ['-n']:
silent = 1
del sys.argv[1]
if sys.argv[1:]:
n = int(sys.argv[1])
q = Queens(n)
q.silent = silent
q.solve()
print("Found", q.nfound, "solutions.")
if __name__ == "__main__":
main()

172
third_party/python/Tools/demo/redemo.py vendored Executable file
View file

@ -0,0 +1,172 @@
#!/usr/bin/env python3
"""Basic regular expression demonstration facility (Perl style syntax)."""
from tkinter import *
import re
class ReDemo:
def __init__(self, master):
self.master = master
self.promptdisplay = Label(self.master, anchor=W,
text="Enter a Perl-style regular expression:")
self.promptdisplay.pack(side=TOP, fill=X)
self.regexdisplay = Entry(self.master)
self.regexdisplay.pack(fill=X)
self.regexdisplay.focus_set()
self.addoptions()
self.statusdisplay = Label(self.master, text="", anchor=W)
self.statusdisplay.pack(side=TOP, fill=X)
self.labeldisplay = Label(self.master, anchor=W,
text="Enter a string to search:")
self.labeldisplay.pack(fill=X)
self.labeldisplay.pack(fill=X)
self.showframe = Frame(master)
self.showframe.pack(fill=X, anchor=W)
self.showvar = StringVar(master)
self.showvar.set("first")
self.showfirstradio = Radiobutton(self.showframe,
text="Highlight first match",
variable=self.showvar,
value="first",
command=self.recompile)
self.showfirstradio.pack(side=LEFT)
self.showallradio = Radiobutton(self.showframe,
text="Highlight all matches",
variable=self.showvar,
value="all",
command=self.recompile)
self.showallradio.pack(side=LEFT)
self.stringdisplay = Text(self.master, width=60, height=4)
self.stringdisplay.pack(fill=BOTH, expand=1)
self.stringdisplay.tag_configure("hit", background="yellow")
self.grouplabel = Label(self.master, text="Groups:", anchor=W)
self.grouplabel.pack(fill=X)
self.grouplist = Listbox(self.master)
self.grouplist.pack(expand=1, fill=BOTH)
self.regexdisplay.bind('<Key>', self.recompile)
self.stringdisplay.bind('<Key>', self.reevaluate)
self.compiled = None
self.recompile()
btags = self.regexdisplay.bindtags()
self.regexdisplay.bindtags(btags[1:] + btags[:1])
btags = self.stringdisplay.bindtags()
self.stringdisplay.bindtags(btags[1:] + btags[:1])
def addoptions(self):
self.frames = []
self.boxes = []
self.vars = []
for name in ('IGNORECASE',
'MULTILINE',
'DOTALL',
'VERBOSE'):
if len(self.boxes) % 3 == 0:
frame = Frame(self.master)
frame.pack(fill=X)
self.frames.append(frame)
val = getattr(re, name).value
var = IntVar()
box = Checkbutton(frame,
variable=var, text=name,
offvalue=0, onvalue=val,
command=self.recompile)
box.pack(side=LEFT)
self.boxes.append(box)
self.vars.append(var)
def getflags(self):
flags = 0
for var in self.vars:
flags = flags | var.get()
flags = flags
return flags
def recompile(self, event=None):
try:
self.compiled = re.compile(self.regexdisplay.get(),
self.getflags())
bg = self.promptdisplay['background']
self.statusdisplay.config(text="", background=bg)
except re.error as msg:
self.compiled = None
self.statusdisplay.config(
text="re.error: %s" % str(msg),
background="red")
self.reevaluate()
def reevaluate(self, event=None):
try:
self.stringdisplay.tag_remove("hit", "1.0", END)
except TclError:
pass
try:
self.stringdisplay.tag_remove("hit0", "1.0", END)
except TclError:
pass
self.grouplist.delete(0, END)
if not self.compiled:
return
self.stringdisplay.tag_configure("hit", background="yellow")
self.stringdisplay.tag_configure("hit0", background="orange")
text = self.stringdisplay.get("1.0", END)
last = 0
nmatches = 0
while last <= len(text):
m = self.compiled.search(text, last)
if m is None:
break
first, last = m.span()
if last == first:
last = first+1
tag = "hit0"
else:
tag = "hit"
pfirst = "1.0 + %d chars" % first
plast = "1.0 + %d chars" % last
self.stringdisplay.tag_add(tag, pfirst, plast)
if nmatches == 0:
self.stringdisplay.yview_pickplace(pfirst)
groups = list(m.groups())
groups.insert(0, m.group())
for i in range(len(groups)):
g = "%2d: %r" % (i, groups[i])
self.grouplist.insert(END, g)
nmatches = nmatches + 1
if self.showvar.get() == "first":
break
if nmatches == 0:
self.statusdisplay.config(text="(no match)",
background="yellow")
else:
self.statusdisplay.config(text="")
# Main function, run when invoked as a stand-alone Python program.
def main():
root = Tk()
demo = ReDemo(root)
root.protocol('WM_DELETE_WINDOW', root.quit)
root.mainloop()
if __name__ == '__main__':
main()

38
third_party/python/Tools/demo/rpython.py vendored Executable file
View file

@ -0,0 +1,38 @@
#!/usr/bin/env python3
"""
Remote python client.
Execute Python commands remotely and send output back.
"""
import sys
from socket import socket, AF_INET, SOCK_STREAM, SHUT_WR
PORT = 4127
BUFSIZE = 1024
def main():
if len(sys.argv) < 3:
print("usage: rpython host command")
sys.exit(2)
host = sys.argv[1]
port = PORT
i = host.find(':')
if i >= 0:
port = int(port[i+1:])
host = host[:i]
command = ' '.join(sys.argv[2:])
s = socket(AF_INET, SOCK_STREAM)
s.connect((host, port))
s.send(command.encode())
s.shutdown(SHUT_WR)
reply = b''
while True:
data = s.recv(BUFSIZE)
if not data:
break
reply += data
print(reply.decode(), end=' ')
s.close()
main()

58
third_party/python/Tools/demo/rpythond.py vendored Executable file
View file

@ -0,0 +1,58 @@
#!/usr/bin/env python3
"""
Remote python server.
Execute Python commands remotely and send output back.
WARNING: This version has a gaping security hole -- it accepts requests
from any host on the Internet!
"""
import sys
from socket import socket, AF_INET, SOCK_STREAM
import io
import traceback
PORT = 4127
BUFSIZE = 1024
def main():
if len(sys.argv) > 1:
port = int(sys.argv[1])
else:
port = PORT
s = socket(AF_INET, SOCK_STREAM)
s.bind(('', port))
s.listen(1)
while True:
conn, (remotehost, remoteport) = s.accept()
print('connection from', remotehost, remoteport)
request = b''
while 1:
data = conn.recv(BUFSIZE)
if not data:
break
request += data
reply = execute(request.decode())
conn.send(reply.encode())
conn.close()
def execute(request):
stdout = sys.stdout
stderr = sys.stderr
sys.stdout = sys.stderr = fakefile = io.StringIO()
try:
try:
exec(request, {}, {})
except:
print()
traceback.print_exc(100)
finally:
sys.stderr = stderr
sys.stdout = stdout
return fakefile.getvalue()
try:
main()
except KeyboardInterrupt:
pass

635
third_party/python/Tools/demo/sortvisu.py vendored Executable file
View file

@ -0,0 +1,635 @@
#!/usr/bin/env python3
"""
Sorting algorithms visualizer using Tkinter.
This module is comprised of three ``components'':
- an array visualizer with methods that implement basic sorting
operations (compare, swap) as well as methods for ``annotating'' the
sorting algorithm (e.g. to show the pivot element);
- a number of sorting algorithms (currently quicksort, insertion sort,
selection sort and bubble sort, as well as a randomization function),
all using the array visualizer for its basic operations and with calls
to its annotation methods;
- and a ``driver'' class which can be used as a Grail applet or as a
stand-alone application.
"""
from tkinter import *
import random
XGRID = 10
YGRID = 10
WIDTH = 6
class Array:
class Cancelled(BaseException):
pass
def __init__(self, master, data=None):
self.master = master
self.frame = Frame(self.master)
self.frame.pack(fill=X)
self.label = Label(self.frame)
self.label.pack()
self.canvas = Canvas(self.frame)
self.canvas.pack()
self.report = Label(self.frame)
self.report.pack()
self.left = self.canvas.create_line(0, 0, 0, 0)
self.right = self.canvas.create_line(0, 0, 0, 0)
self.pivot = self.canvas.create_line(0, 0, 0, 0)
self.items = []
self.size = self.maxvalue = 0
if data:
self.setdata(data)
def setdata(self, data):
olditems = self.items
self.items = []
for item in olditems:
item.delete()
self.size = len(data)
self.maxvalue = max(data)
self.canvas.config(width=(self.size+1)*XGRID,
height=(self.maxvalue+1)*YGRID)
for i in range(self.size):
self.items.append(ArrayItem(self, i, data[i]))
self.reset("Sort demo, size %d" % self.size)
speed = "normal"
def setspeed(self, speed):
self.speed = speed
def destroy(self):
self.frame.destroy()
in_mainloop = 0
stop_mainloop = 0
def cancel(self):
self.stop_mainloop = 1
if self.in_mainloop:
self.master.quit()
def step(self):
if self.in_mainloop:
self.master.quit()
def wait(self, msecs):
if self.speed == "fastest":
msecs = 0
elif self.speed == "fast":
msecs = msecs//10
elif self.speed == "single-step":
msecs = 1000000000
if not self.stop_mainloop:
self.master.update()
id = self.master.after(msecs, self.master.quit)
self.in_mainloop = 1
self.master.mainloop()
self.master.after_cancel(id)
self.in_mainloop = 0
if self.stop_mainloop:
self.stop_mainloop = 0
self.message("Cancelled")
raise Array.Cancelled
def getsize(self):
return self.size
def show_partition(self, first, last):
for i in range(self.size):
item = self.items[i]
if first <= i < last:
self.canvas.itemconfig(item, fill='red')
else:
self.canvas.itemconfig(item, fill='orange')
self.hide_left_right_pivot()
def hide_partition(self):
for i in range(self.size):
item = self.items[i]
self.canvas.itemconfig(item, fill='red')
self.hide_left_right_pivot()
def show_left(self, left):
if not 0 <= left < self.size:
self.hide_left()
return
x1, y1, x2, y2 = self.items[left].position()
## top, bot = HIRO
self.canvas.coords(self.left, (x1 - 2, 0, x1 - 2, 9999))
self.master.update()
def show_right(self, right):
if not 0 <= right < self.size:
self.hide_right()
return
x1, y1, x2, y2 = self.items[right].position()
self.canvas.coords(self.right, (x2 + 2, 0, x2 + 2, 9999))
self.master.update()
def hide_left_right_pivot(self):
self.hide_left()
self.hide_right()
self.hide_pivot()
def hide_left(self):
self.canvas.coords(self.left, (0, 0, 0, 0))
def hide_right(self):
self.canvas.coords(self.right, (0, 0, 0, 0))
def show_pivot(self, pivot):
x1, y1, x2, y2 = self.items[pivot].position()
self.canvas.coords(self.pivot, (0, y1 - 2, 9999, y1 - 2))
def hide_pivot(self):
self.canvas.coords(self.pivot, (0, 0, 0, 0))
def swap(self, i, j):
if i == j: return
self.countswap()
item = self.items[i]
other = self.items[j]
self.items[i], self.items[j] = other, item
item.swapwith(other)
def compare(self, i, j):
self.countcompare()
item = self.items[i]
other = self.items[j]
return item.compareto(other)
def reset(self, msg):
self.ncompares = 0
self.nswaps = 0
self.message(msg)
self.updatereport()
self.hide_partition()
def message(self, msg):
self.label.config(text=msg)
def countswap(self):
self.nswaps = self.nswaps + 1
self.updatereport()
def countcompare(self):
self.ncompares = self.ncompares + 1
self.updatereport()
def updatereport(self):
text = "%d cmps, %d swaps" % (self.ncompares, self.nswaps)
self.report.config(text=text)
class ArrayItem:
def __init__(self, array, index, value):
self.array = array
self.index = index
self.value = value
self.canvas = array.canvas
x1, y1, x2, y2 = self.position()
self.item_id = array.canvas.create_rectangle(x1, y1, x2, y2,
fill='red', outline='black', width=1)
self.canvas.tag_bind(self.item_id, '<Button-1>', self.mouse_down)
self.canvas.tag_bind(self.item_id, '<Button1-Motion>', self.mouse_move)
self.canvas.tag_bind(self.item_id, '<ButtonRelease-1>', self.mouse_up)
def delete(self):
item_id = self.item_id
self.array = None
self.item_id = None
self.canvas.delete(item_id)
def mouse_down(self, event):
self.lastx = event.x
self.lasty = event.y
self.origx = event.x
self.origy = event.y
self.canvas.tag_raise(self.item_id)
def mouse_move(self, event):
self.canvas.move(self.item_id,
event.x - self.lastx, event.y - self.lasty)
self.lastx = event.x
self.lasty = event.y
def mouse_up(self, event):
i = self.nearestindex(event.x)
if i >= self.array.getsize():
i = self.array.getsize() - 1
if i < 0:
i = 0
other = self.array.items[i]
here = self.index
self.array.items[here], self.array.items[i] = other, self
self.index = i
x1, y1, x2, y2 = self.position()
self.canvas.coords(self.item_id, (x1, y1, x2, y2))
other.setindex(here)
def setindex(self, index):
nsteps = steps(self.index, index)
if not nsteps: return
if self.array.speed == "fastest":
nsteps = 0
oldpts = self.position()
self.index = index
newpts = self.position()
trajectory = interpolate(oldpts, newpts, nsteps)
self.canvas.tag_raise(self.item_id)
for pts in trajectory:
self.canvas.coords(self.item_id, pts)
self.array.wait(50)
def swapwith(self, other):
nsteps = steps(self.index, other.index)
if not nsteps: return
if self.array.speed == "fastest":
nsteps = 0
myoldpts = self.position()
otheroldpts = other.position()
self.index, other.index = other.index, self.index
mynewpts = self.position()
othernewpts = other.position()
myfill = self.canvas.itemcget(self.item_id, 'fill')
otherfill = self.canvas.itemcget(other.item_id, 'fill')
self.canvas.itemconfig(self.item_id, fill='green')
self.canvas.itemconfig(other.item_id, fill='yellow')
self.array.master.update()
if self.array.speed == "single-step":
self.canvas.coords(self.item_id, mynewpts)
self.canvas.coords(other.item_id, othernewpts)
self.array.master.update()
self.canvas.itemconfig(self.item_id, fill=myfill)
self.canvas.itemconfig(other.item_id, fill=otherfill)
self.array.wait(0)
return
mytrajectory = interpolate(myoldpts, mynewpts, nsteps)
othertrajectory = interpolate(otheroldpts, othernewpts, nsteps)
if self.value > other.value:
self.canvas.tag_raise(self.item_id)
self.canvas.tag_raise(other.item_id)
else:
self.canvas.tag_raise(other.item_id)
self.canvas.tag_raise(self.item_id)
try:
for i in range(len(mytrajectory)):
mypts = mytrajectory[i]
otherpts = othertrajectory[i]
self.canvas.coords(self.item_id, mypts)
self.canvas.coords(other.item_id, otherpts)
self.array.wait(50)
finally:
mypts = mytrajectory[-1]
otherpts = othertrajectory[-1]
self.canvas.coords(self.item_id, mypts)
self.canvas.coords(other.item_id, otherpts)
self.canvas.itemconfig(self.item_id, fill=myfill)
self.canvas.itemconfig(other.item_id, fill=otherfill)
def compareto(self, other):
myfill = self.canvas.itemcget(self.item_id, 'fill')
otherfill = self.canvas.itemcget(other.item_id, 'fill')
if self.value < other.value:
myflash = 'white'
otherflash = 'black'
outcome = -1
elif self.value > other.value:
myflash = 'black'
otherflash = 'white'
outcome = 1
else:
myflash = otherflash = 'grey'
outcome = 0
try:
self.canvas.itemconfig(self.item_id, fill=myflash)
self.canvas.itemconfig(other.item_id, fill=otherflash)
self.array.wait(500)
finally:
self.canvas.itemconfig(self.item_id, fill=myfill)
self.canvas.itemconfig(other.item_id, fill=otherfill)
return outcome
def position(self):
x1 = (self.index+1)*XGRID - WIDTH//2
x2 = x1+WIDTH
y2 = (self.array.maxvalue+1)*YGRID
y1 = y2 - (self.value)*YGRID
return x1, y1, x2, y2
def nearestindex(self, x):
return int(round(float(x)/XGRID)) - 1
# Subroutines that don't need an object
def steps(here, there):
nsteps = abs(here - there)
if nsteps <= 3:
nsteps = nsteps * 3
elif nsteps <= 5:
nsteps = nsteps * 2
elif nsteps > 10:
nsteps = 10
return nsteps
def interpolate(oldpts, newpts, n):
if len(oldpts) != len(newpts):
raise ValueError("can't interpolate arrays of different length")
pts = [0]*len(oldpts)
res = [tuple(oldpts)]
for i in range(1, n):
for k in range(len(pts)):
pts[k] = oldpts[k] + (newpts[k] - oldpts[k])*i//n
res.append(tuple(pts))
res.append(tuple(newpts))
return res
# Various (un)sorting algorithms
def uniform(array):
size = array.getsize()
array.setdata([(size+1)//2] * size)
array.reset("Uniform data, size %d" % size)
def distinct(array):
size = array.getsize()
array.setdata(range(1, size+1))
array.reset("Distinct data, size %d" % size)
def randomize(array):
array.reset("Randomizing")
n = array.getsize()
for i in range(n):
j = random.randint(0, n-1)
array.swap(i, j)
array.message("Randomized")
def insertionsort(array):
size = array.getsize()
array.reset("Insertion sort")
for i in range(1, size):
j = i-1
while j >= 0:
if array.compare(j, j+1) <= 0:
break
array.swap(j, j+1)
j = j-1
array.message("Sorted")
def selectionsort(array):
size = array.getsize()
array.reset("Selection sort")
try:
for i in range(size):
array.show_partition(i, size)
for j in range(i+1, size):
if array.compare(i, j) > 0:
array.swap(i, j)
array.message("Sorted")
finally:
array.hide_partition()
def bubblesort(array):
size = array.getsize()
array.reset("Bubble sort")
for i in range(size):
for j in range(1, size):
if array.compare(j-1, j) > 0:
array.swap(j-1, j)
array.message("Sorted")
def quicksort(array):
size = array.getsize()
array.reset("Quicksort")
try:
stack = [(0, size)]
while stack:
first, last = stack[-1]
del stack[-1]
array.show_partition(first, last)
if last-first < 5:
array.message("Insertion sort")
for i in range(first+1, last):
j = i-1
while j >= first:
if array.compare(j, j+1) <= 0:
break
array.swap(j, j+1)
j = j-1
continue
array.message("Choosing pivot")
j, i, k = first, (first+last) // 2, last-1
if array.compare(k, i) < 0:
array.swap(k, i)
if array.compare(k, j) < 0:
array.swap(k, j)
if array.compare(j, i) < 0:
array.swap(j, i)
pivot = j
array.show_pivot(pivot)
array.message("Pivot at left of partition")
array.wait(1000)
left = first
right = last
while 1:
array.message("Sweep right pointer")
right = right-1
array.show_right(right)
while right > first and array.compare(right, pivot) >= 0:
right = right-1
array.show_right(right)
array.message("Sweep left pointer")
left = left+1
array.show_left(left)
while left < last and array.compare(left, pivot) <= 0:
left = left+1
array.show_left(left)
if left > right:
array.message("End of partition")
break
array.message("Swap items")
array.swap(left, right)
array.message("Swap pivot back")
array.swap(pivot, right)
n1 = right-first
n2 = last-left
if n1 > 1: stack.append((first, right))
if n2 > 1: stack.append((left, last))
array.message("Sorted")
finally:
array.hide_partition()
def demosort(array):
while 1:
for alg in [quicksort, insertionsort, selectionsort, bubblesort]:
randomize(array)
alg(array)
# Sort demo class -- usable as a Grail applet
class SortDemo:
def __init__(self, master, size=15):
self.master = master
self.size = size
self.busy = 0
self.array = Array(self.master)
self.botframe = Frame(master)
self.botframe.pack(side=BOTTOM)
self.botleftframe = Frame(self.botframe)
self.botleftframe.pack(side=LEFT, fill=Y)
self.botrightframe = Frame(self.botframe)
self.botrightframe.pack(side=RIGHT, fill=Y)
self.b_qsort = Button(self.botleftframe,
text="Quicksort", command=self.c_qsort)
self.b_qsort.pack(fill=X)
self.b_isort = Button(self.botleftframe,
text="Insertion sort", command=self.c_isort)
self.b_isort.pack(fill=X)
self.b_ssort = Button(self.botleftframe,
text="Selection sort", command=self.c_ssort)
self.b_ssort.pack(fill=X)
self.b_bsort = Button(self.botleftframe,
text="Bubble sort", command=self.c_bsort)
self.b_bsort.pack(fill=X)
# Terrible hack to overcome limitation of OptionMenu...
class MyIntVar(IntVar):
def __init__(self, master, demo):
self.demo = demo
IntVar.__init__(self, master)
def set(self, value):
IntVar.set(self, value)
if str(value) != '0':
self.demo.resize(value)
self.v_size = MyIntVar(self.master, self)
self.v_size.set(size)
sizes = [1, 2, 3, 4] + list(range(5, 55, 5))
if self.size not in sizes:
sizes.append(self.size)
sizes.sort()
self.m_size = OptionMenu(self.botleftframe, self.v_size, *sizes)
self.m_size.pack(fill=X)
self.v_speed = StringVar(self.master)
self.v_speed.set("normal")
self.m_speed = OptionMenu(self.botleftframe, self.v_speed,
"single-step", "normal", "fast", "fastest")
self.m_speed.pack(fill=X)
self.b_step = Button(self.botleftframe,
text="Step", command=self.c_step)
self.b_step.pack(fill=X)
self.b_randomize = Button(self.botrightframe,
text="Randomize", command=self.c_randomize)
self.b_randomize.pack(fill=X)
self.b_uniform = Button(self.botrightframe,
text="Uniform", command=self.c_uniform)
self.b_uniform.pack(fill=X)
self.b_distinct = Button(self.botrightframe,
text="Distinct", command=self.c_distinct)
self.b_distinct.pack(fill=X)
self.b_demo = Button(self.botrightframe,
text="Demo", command=self.c_demo)
self.b_demo.pack(fill=X)
self.b_cancel = Button(self.botrightframe,
text="Cancel", command=self.c_cancel)
self.b_cancel.pack(fill=X)
self.b_cancel.config(state=DISABLED)
self.b_quit = Button(self.botrightframe,
text="Quit", command=self.c_quit)
self.b_quit.pack(fill=X)
def resize(self, newsize):
if self.busy:
self.master.bell()
return
self.size = newsize
self.array.setdata(range(1, self.size+1))
def c_qsort(self):
self.run(quicksort)
def c_isort(self):
self.run(insertionsort)
def c_ssort(self):
self.run(selectionsort)
def c_bsort(self):
self.run(bubblesort)
def c_demo(self):
self.run(demosort)
def c_randomize(self):
self.run(randomize)
def c_uniform(self):
self.run(uniform)
def c_distinct(self):
self.run(distinct)
def run(self, func):
if self.busy:
self.master.bell()
return
self.busy = 1
self.array.setspeed(self.v_speed.get())
self.b_cancel.config(state=NORMAL)
try:
func(self.array)
except Array.Cancelled:
pass
self.b_cancel.config(state=DISABLED)
self.busy = 0
def c_cancel(self):
if not self.busy:
self.master.bell()
return
self.array.cancel()
def c_step(self):
if not self.busy:
self.master.bell()
return
self.v_speed.set("single-step")
self.array.setspeed("single-step")
self.array.step()
def c_quit(self):
if self.busy:
self.array.cancel()
self.master.after_idle(self.master.quit)
# Main program -- for stand-alone operation outside Grail
def main():
root = Tk()
demo = SortDemo(root)
root.protocol('WM_DELETE_WINDOW', demo.c_quit)
root.mainloop()
if __name__ == '__main__':
main()

829
third_party/python/Tools/demo/ss1.py vendored Executable file
View file

@ -0,0 +1,829 @@
#!/usr/bin/env python3
"""
SS1 -- a spreadsheet-like application.
"""
import os
import re
import sys
from xml.parsers import expat
from xml.sax.saxutils import escape
LEFT, CENTER, RIGHT = "LEFT", "CENTER", "RIGHT"
def ljust(x, n):
return x.ljust(n)
def center(x, n):
return x.center(n)
def rjust(x, n):
return x.rjust(n)
align2action = {LEFT: ljust, CENTER: center, RIGHT: rjust}
align2xml = {LEFT: "left", CENTER: "center", RIGHT: "right"}
xml2align = {"left": LEFT, "center": CENTER, "right": RIGHT}
align2anchor = {LEFT: "w", CENTER: "center", RIGHT: "e"}
def sum(seq):
total = 0
for x in seq:
if x is not None:
total += x
return total
class Sheet:
def __init__(self):
self.cells = {} # {(x, y): cell, ...}
self.ns = dict(
cell = self.cellvalue,
cells = self.multicellvalue,
sum = sum,
)
def cellvalue(self, x, y):
cell = self.getcell(x, y)
if hasattr(cell, 'recalc'):
return cell.recalc(self.ns)
else:
return cell
def multicellvalue(self, x1, y1, x2, y2):
if x1 > x2:
x1, x2 = x2, x1
if y1 > y2:
y1, y2 = y2, y1
seq = []
for y in range(y1, y2+1):
for x in range(x1, x2+1):
seq.append(self.cellvalue(x, y))
return seq
def getcell(self, x, y):
return self.cells.get((x, y))
def setcell(self, x, y, cell):
assert x > 0 and y > 0
assert isinstance(cell, BaseCell)
self.cells[x, y] = cell
def clearcell(self, x, y):
try:
del self.cells[x, y]
except KeyError:
pass
def clearcells(self, x1, y1, x2, y2):
for xy in self.selectcells(x1, y1, x2, y2):
del self.cells[xy]
def clearrows(self, y1, y2):
self.clearcells(0, y1, sys.maxsize, y2)
def clearcolumns(self, x1, x2):
self.clearcells(x1, 0, x2, sys.maxsize)
def selectcells(self, x1, y1, x2, y2):
if x1 > x2:
x1, x2 = x2, x1
if y1 > y2:
y1, y2 = y2, y1
return [(x, y) for x, y in self.cells
if x1 <= x <= x2 and y1 <= y <= y2]
def movecells(self, x1, y1, x2, y2, dx, dy):
if dx == 0 and dy == 0:
return
if x1 > x2:
x1, x2 = x2, x1
if y1 > y2:
y1, y2 = y2, y1
assert x1+dx > 0 and y1+dy > 0
new = {}
for x, y in self.cells:
cell = self.cells[x, y]
if hasattr(cell, 'renumber'):
cell = cell.renumber(x1, y1, x2, y2, dx, dy)
if x1 <= x <= x2 and y1 <= y <= y2:
x += dx
y += dy
new[x, y] = cell
self.cells = new
def insertrows(self, y, n):
assert n > 0
self.movecells(0, y, sys.maxsize, sys.maxsize, 0, n)
def deleterows(self, y1, y2):
if y1 > y2:
y1, y2 = y2, y1
self.clearrows(y1, y2)
self.movecells(0, y2+1, sys.maxsize, sys.maxsize, 0, y1-y2-1)
def insertcolumns(self, x, n):
assert n > 0
self.movecells(x, 0, sys.maxsize, sys.maxsize, n, 0)
def deletecolumns(self, x1, x2):
if x1 > x2:
x1, x2 = x2, x1
self.clearcells(x1, x2)
self.movecells(x2+1, 0, sys.maxsize, sys.maxsize, x1-x2-1, 0)
def getsize(self):
maxx = maxy = 0
for x, y in self.cells:
maxx = max(maxx, x)
maxy = max(maxy, y)
return maxx, maxy
def reset(self):
for cell in self.cells.values():
if hasattr(cell, 'reset'):
cell.reset()
def recalc(self):
self.reset()
for cell in self.cells.values():
if hasattr(cell, 'recalc'):
cell.recalc(self.ns)
def display(self):
maxx, maxy = self.getsize()
width, height = maxx+1, maxy+1
colwidth = [1] * width
full = {}
# Add column heading labels in row 0
for x in range(1, width):
full[x, 0] = text, alignment = colnum2name(x), RIGHT
colwidth[x] = max(colwidth[x], len(text))
# Add row labels in column 0
for y in range(1, height):
full[0, y] = text, alignment = str(y), RIGHT
colwidth[0] = max(colwidth[0], len(text))
# Add sheet cells in columns with x>0 and y>0
for (x, y), cell in self.cells.items():
if x <= 0 or y <= 0:
continue
if hasattr(cell, 'recalc'):
cell.recalc(self.ns)
if hasattr(cell, 'format'):
text, alignment = cell.format()
assert isinstance(text, str)
assert alignment in (LEFT, CENTER, RIGHT)
else:
text = str(cell)
if isinstance(cell, str):
alignment = LEFT
else:
alignment = RIGHT
full[x, y] = (text, alignment)
colwidth[x] = max(colwidth[x], len(text))
# Calculate the horizontal separator line (dashes and dots)
sep = ""
for x in range(width):
if sep:
sep += "+"
sep += "-"*colwidth[x]
# Now print The full grid
for y in range(height):
line = ""
for x in range(width):
text, alignment = full.get((x, y)) or ("", LEFT)
text = align2action[alignment](text, colwidth[x])
if line:
line += '|'
line += text
print(line)
if y == 0:
print(sep)
def xml(self):
out = ['<spreadsheet>']
for (x, y), cell in self.cells.items():
if hasattr(cell, 'xml'):
cellxml = cell.xml()
else:
cellxml = '<value>%s</value>' % escape(cell)
out.append('<cell row="%s" col="%s">\n %s\n</cell>' %
(y, x, cellxml))
out.append('</spreadsheet>')
return '\n'.join(out)
def save(self, filename):
text = self.xml()
with open(filename, "w", encoding='utf-8') as f:
f.write(text)
if text and not text.endswith('\n'):
f.write('\n')
def load(self, filename):
with open(filename, 'rb') as f:
SheetParser(self).parsefile(f)
class SheetParser:
def __init__(self, sheet):
self.sheet = sheet
def parsefile(self, f):
parser = expat.ParserCreate()
parser.StartElementHandler = self.startelement
parser.EndElementHandler = self.endelement
parser.CharacterDataHandler = self.data
parser.ParseFile(f)
def startelement(self, tag, attrs):
method = getattr(self, 'start_'+tag, None)
if method:
method(attrs)
self.texts = []
def data(self, text):
self.texts.append(text)
def endelement(self, tag):
method = getattr(self, 'end_'+tag, None)
if method:
method("".join(self.texts))
def start_cell(self, attrs):
self.y = int(attrs.get("row"))
self.x = int(attrs.get("col"))
def start_value(self, attrs):
self.fmt = attrs.get('format')
self.alignment = xml2align.get(attrs.get('align'))
start_formula = start_value
def end_int(self, text):
try:
self.value = int(text)
except (TypeError, ValueError):
self.value = None
end_long = end_int
def end_double(self, text):
try:
self.value = float(text)
except (TypeError, ValueError):
self.value = None
def end_complex(self, text):
try:
self.value = complex(text)
except (TypeError, ValueError):
self.value = None
def end_string(self, text):
self.value = text
def end_value(self, text):
if isinstance(self.value, BaseCell):
self.cell = self.value
elif isinstance(self.value, str):
self.cell = StringCell(self.value,
self.fmt or "%s",
self.alignment or LEFT)
else:
self.cell = NumericCell(self.value,
self.fmt or "%s",
self.alignment or RIGHT)
def end_formula(self, text):
self.cell = FormulaCell(text,
self.fmt or "%s",
self.alignment or RIGHT)
def end_cell(self, text):
self.sheet.setcell(self.x, self.y, self.cell)
class BaseCell:
__init__ = None # Must provide
"""Abstract base class for sheet cells.
Subclasses may but needn't provide the following APIs:
cell.reset() -- prepare for recalculation
cell.recalc(ns) -> value -- recalculate formula
cell.format() -> (value, alignment) -- return formatted value
cell.xml() -> string -- return XML
"""
class NumericCell(BaseCell):
def __init__(self, value, fmt="%s", alignment=RIGHT):
assert isinstance(value, (int, float, complex))
assert alignment in (LEFT, CENTER, RIGHT)
self.value = value
self.fmt = fmt
self.alignment = alignment
def recalc(self, ns):
return self.value
def format(self):
try:
text = self.fmt % self.value
except:
text = str(self.value)
return text, self.alignment
def xml(self):
method = getattr(self, '_xml_' + type(self.value).__name__)
return '<value align="%s" format="%s">%s</value>' % (
align2xml[self.alignment],
self.fmt,
method())
def _xml_int(self):
if -2**31 <= self.value < 2**31:
return '<int>%s</int>' % self.value
else:
return '<long>%s</long>' % self.value
def _xml_float(self):
return '<double>%r</double>' % self.value
def _xml_complex(self):
return '<complex>%r</complex>' % self.value
class StringCell(BaseCell):
def __init__(self, text, fmt="%s", alignment=LEFT):
assert isinstance(text, str)
assert alignment in (LEFT, CENTER, RIGHT)
self.text = text
self.fmt = fmt
self.alignment = alignment
def recalc(self, ns):
return self.text
def format(self):
return self.text, self.alignment
def xml(self):
s = '<value align="%s" format="%s"><string>%s</string></value>'
return s % (
align2xml[self.alignment],
self.fmt,
escape(self.text))
class FormulaCell(BaseCell):
def __init__(self, formula, fmt="%s", alignment=RIGHT):
assert alignment in (LEFT, CENTER, RIGHT)
self.formula = formula
self.translated = translate(self.formula)
self.fmt = fmt
self.alignment = alignment
self.reset()
def reset(self):
self.value = None
def recalc(self, ns):
if self.value is None:
try:
self.value = eval(self.translated, ns)
except:
exc = sys.exc_info()[0]
if hasattr(exc, "__name__"):
self.value = exc.__name__
else:
self.value = str(exc)
return self.value
def format(self):
try:
text = self.fmt % self.value
except:
text = str(self.value)
return text, self.alignment
def xml(self):
return '<formula align="%s" format="%s">%s</formula>' % (
align2xml[self.alignment],
self.fmt,
escape(self.formula))
def renumber(self, x1, y1, x2, y2, dx, dy):
out = []
for part in re.split(r'(\w+)', self.formula):
m = re.match('^([A-Z]+)([1-9][0-9]*)$', part)
if m is not None:
sx, sy = m.groups()
x = colname2num(sx)
y = int(sy)
if x1 <= x <= x2 and y1 <= y <= y2:
part = cellname(x+dx, y+dy)
out.append(part)
return FormulaCell("".join(out), self.fmt, self.alignment)
def translate(formula):
"""Translate a formula containing fancy cell names to valid Python code.
Examples:
B4 -> cell(2, 4)
B4:Z100 -> cells(2, 4, 26, 100)
"""
out = []
for part in re.split(r"(\w+(?::\w+)?)", formula):
m = re.match(r"^([A-Z]+)([1-9][0-9]*)(?::([A-Z]+)([1-9][0-9]*))?$", part)
if m is None:
out.append(part)
else:
x1, y1, x2, y2 = m.groups()
x1 = colname2num(x1)
if x2 is None:
s = "cell(%s, %s)" % (x1, y1)
else:
x2 = colname2num(x2)
s = "cells(%s, %s, %s, %s)" % (x1, y1, x2, y2)
out.append(s)
return "".join(out)
def cellname(x, y):
"Translate a cell coordinate to a fancy cell name (e.g. (1, 1)->'A1')."
assert x > 0 # Column 0 has an empty name, so can't use that
return colnum2name(x) + str(y)
def colname2num(s):
"Translate a column name to number (e.g. 'A'->1, 'Z'->26, 'AA'->27)."
s = s.upper()
n = 0
for c in s:
assert 'A' <= c <= 'Z'
n = n*26 + ord(c) - ord('A') + 1
return n
def colnum2name(n):
"Translate a column number to name (e.g. 1->'A', etc.)."
assert n > 0
s = ""
while n:
n, m = divmod(n-1, 26)
s = chr(m+ord('A')) + s
return s
import tkinter as Tk
class SheetGUI:
"""Beginnings of a GUI for a spreadsheet.
TO DO:
- clear multiple cells
- Insert, clear, remove rows or columns
- Show new contents while typing
- Scroll bars
- Grow grid when window is grown
- Proper menus
- Undo, redo
- Cut, copy and paste
- Formatting and alignment
"""
def __init__(self, filename="sheet1.xml", rows=10, columns=5):
"""Constructor.
Load the sheet from the filename argument.
Set up the Tk widget tree.
"""
# Create and load the sheet
self.filename = filename
self.sheet = Sheet()
if os.path.isfile(filename):
self.sheet.load(filename)
# Calculate the needed grid size
maxx, maxy = self.sheet.getsize()
rows = max(rows, maxy)
columns = max(columns, maxx)
# Create the widgets
self.root = Tk.Tk()
self.root.wm_title("Spreadsheet: %s" % self.filename)
self.beacon = Tk.Label(self.root, text="A1",
font=('helvetica', 16, 'bold'))
self.entry = Tk.Entry(self.root)
self.savebutton = Tk.Button(self.root, text="Save",
command=self.save)
self.cellgrid = Tk.Frame(self.root)
# Configure the widget lay-out
self.cellgrid.pack(side="bottom", expand=1, fill="both")
self.beacon.pack(side="left")
self.savebutton.pack(side="right")
self.entry.pack(side="left", expand=1, fill="x")
# Bind some events
self.entry.bind("<Return>", self.return_event)
self.entry.bind("<Shift-Return>", self.shift_return_event)
self.entry.bind("<Tab>", self.tab_event)
self.entry.bind("<Shift-Tab>", self.shift_tab_event)
self.entry.bind("<Delete>", self.delete_event)
self.entry.bind("<Escape>", self.escape_event)
# Now create the cell grid
self.makegrid(rows, columns)
# Select the top-left cell
self.currentxy = None
self.cornerxy = None
self.setcurrent(1, 1)
# Copy the sheet cells to the GUI cells
self.sync()
def delete_event(self, event):
if self.cornerxy != self.currentxy and self.cornerxy is not None:
self.sheet.clearcells(*(self.currentxy + self.cornerxy))
else:
self.sheet.clearcell(*self.currentxy)
self.sync()
self.entry.delete(0, 'end')
return "break"
def escape_event(self, event):
x, y = self.currentxy
self.load_entry(x, y)
def load_entry(self, x, y):
cell = self.sheet.getcell(x, y)
if cell is None:
text = ""
elif isinstance(cell, FormulaCell):
text = '=' + cell.formula
else:
text, alignment = cell.format()
self.entry.delete(0, 'end')
self.entry.insert(0, text)
self.entry.selection_range(0, 'end')
def makegrid(self, rows, columns):
"""Helper to create the grid of GUI cells.
The edge (x==0 or y==0) is filled with labels; the rest is real cells.
"""
self.rows = rows
self.columns = columns
self.gridcells = {}
# Create the top left corner cell (which selects all)
cell = Tk.Label(self.cellgrid, relief='raised')
cell.grid_configure(column=0, row=0, sticky='NSWE')
cell.bind("<ButtonPress-1>", self.selectall)
# Create the top row of labels, and configure the grid columns
for x in range(1, columns+1):
self.cellgrid.grid_columnconfigure(x, minsize=64)
cell = Tk.Label(self.cellgrid, text=colnum2name(x), relief='raised')
cell.grid_configure(column=x, row=0, sticky='WE')
self.gridcells[x, 0] = cell
cell.__x = x
cell.__y = 0
cell.bind("<ButtonPress-1>", self.selectcolumn)
cell.bind("<B1-Motion>", self.extendcolumn)
cell.bind("<ButtonRelease-1>", self.extendcolumn)
cell.bind("<Shift-Button-1>", self.extendcolumn)
# Create the leftmost column of labels
for y in range(1, rows+1):
cell = Tk.Label(self.cellgrid, text=str(y), relief='raised')
cell.grid_configure(column=0, row=y, sticky='WE')
self.gridcells[0, y] = cell
cell.__x = 0
cell.__y = y
cell.bind("<ButtonPress-1>", self.selectrow)
cell.bind("<B1-Motion>", self.extendrow)
cell.bind("<ButtonRelease-1>", self.extendrow)
cell.bind("<Shift-Button-1>", self.extendrow)
# Create the real cells
for x in range(1, columns+1):
for y in range(1, rows+1):
cell = Tk.Label(self.cellgrid, relief='sunken',
bg='white', fg='black')
cell.grid_configure(column=x, row=y, sticky='NSWE')
self.gridcells[x, y] = cell
cell.__x = x
cell.__y = y
# Bind mouse events
cell.bind("<ButtonPress-1>", self.press)
cell.bind("<B1-Motion>", self.motion)
cell.bind("<ButtonRelease-1>", self.release)
cell.bind("<Shift-Button-1>", self.release)
def selectall(self, event):
self.setcurrent(1, 1)
self.setcorner(sys.maxsize, sys.maxsize)
def selectcolumn(self, event):
x, y = self.whichxy(event)
self.setcurrent(x, 1)
self.setcorner(x, sys.maxsize)
def extendcolumn(self, event):
x, y = self.whichxy(event)
if x > 0:
self.setcurrent(self.currentxy[0], 1)
self.setcorner(x, sys.maxsize)
def selectrow(self, event):
x, y = self.whichxy(event)
self.setcurrent(1, y)
self.setcorner(sys.maxsize, y)
def extendrow(self, event):
x, y = self.whichxy(event)
if y > 0:
self.setcurrent(1, self.currentxy[1])
self.setcorner(sys.maxsize, y)
def press(self, event):
x, y = self.whichxy(event)
if x > 0 and y > 0:
self.setcurrent(x, y)
def motion(self, event):
x, y = self.whichxy(event)
if x > 0 and y > 0:
self.setcorner(x, y)
release = motion
def whichxy(self, event):
w = self.cellgrid.winfo_containing(event.x_root, event.y_root)
if w is not None and isinstance(w, Tk.Label):
try:
return w.__x, w.__y
except AttributeError:
pass
return 0, 0
def save(self):
self.sheet.save(self.filename)
def setcurrent(self, x, y):
"Make (x, y) the current cell."
if self.currentxy is not None:
self.change_cell()
self.clearfocus()
self.beacon['text'] = cellname(x, y)
self.load_entry(x, y)
self.entry.focus_set()
self.currentxy = x, y
self.cornerxy = None
gridcell = self.gridcells.get(self.currentxy)
if gridcell is not None:
gridcell['bg'] = 'yellow'
def setcorner(self, x, y):
if self.currentxy is None or self.currentxy == (x, y):
self.setcurrent(x, y)
return
self.clearfocus()
self.cornerxy = x, y
x1, y1 = self.currentxy
x2, y2 = self.cornerxy or self.currentxy
if x1 > x2:
x1, x2 = x2, x1
if y1 > y2:
y1, y2 = y2, y1
for (x, y), cell in self.gridcells.items():
if x1 <= x <= x2 and y1 <= y <= y2:
cell['bg'] = 'lightBlue'
gridcell = self.gridcells.get(self.currentxy)
if gridcell is not None:
gridcell['bg'] = 'yellow'
self.setbeacon(x1, y1, x2, y2)
def setbeacon(self, x1, y1, x2, y2):
if x1 == y1 == 1 and x2 == y2 == sys.maxsize:
name = ":"
elif (x1, x2) == (1, sys.maxsize):
if y1 == y2:
name = "%d" % y1
else:
name = "%d:%d" % (y1, y2)
elif (y1, y2) == (1, sys.maxsize):
if x1 == x2:
name = "%s" % colnum2name(x1)
else:
name = "%s:%s" % (colnum2name(x1), colnum2name(x2))
else:
name1 = cellname(*self.currentxy)
name2 = cellname(*self.cornerxy)
name = "%s:%s" % (name1, name2)
self.beacon['text'] = name
def clearfocus(self):
if self.currentxy is not None:
x1, y1 = self.currentxy
x2, y2 = self.cornerxy or self.currentxy
if x1 > x2:
x1, x2 = x2, x1
if y1 > y2:
y1, y2 = y2, y1
for (x, y), cell in self.gridcells.items():
if x1 <= x <= x2 and y1 <= y <= y2:
cell['bg'] = 'white'
def return_event(self, event):
"Callback for the Return key."
self.change_cell()
x, y = self.currentxy
self.setcurrent(x, y+1)
return "break"
def shift_return_event(self, event):
"Callback for the Return key with Shift modifier."
self.change_cell()
x, y = self.currentxy
self.setcurrent(x, max(1, y-1))
return "break"
def tab_event(self, event):
"Callback for the Tab key."
self.change_cell()
x, y = self.currentxy
self.setcurrent(x+1, y)
return "break"
def shift_tab_event(self, event):
"Callback for the Tab key with Shift modifier."
self.change_cell()
x, y = self.currentxy
self.setcurrent(max(1, x-1), y)
return "break"
def change_cell(self):
"Set the current cell from the entry widget."
x, y = self.currentxy
text = self.entry.get()
cell = None
if text.startswith('='):
cell = FormulaCell(text[1:])
else:
for cls in int, float, complex:
try:
value = cls(text)
except (TypeError, ValueError):
continue
else:
cell = NumericCell(value)
break
if cell is None and text:
cell = StringCell(text)
if cell is None:
self.sheet.clearcell(x, y)
else:
self.sheet.setcell(x, y, cell)
self.sync()
def sync(self):
"Fill the GUI cells from the sheet cells."
self.sheet.recalc()
for (x, y), gridcell in self.gridcells.items():
if x == 0 or y == 0:
continue
cell = self.sheet.getcell(x, y)
if cell is None:
gridcell['text'] = ""
else:
if hasattr(cell, 'format'):
text, alignment = cell.format()
else:
text, alignment = str(cell), LEFT
gridcell['text'] = text
gridcell['anchor'] = align2anchor[alignment]
def test_basic():
"Basic non-gui self-test."
a = Sheet()
for x in range(1, 11):
for y in range(1, 11):
if x == 1:
cell = NumericCell(y)
elif y == 1:
cell = NumericCell(x)
else:
c1 = cellname(x, 1)
c2 = cellname(1, y)
formula = "%s*%s" % (c1, c2)
cell = FormulaCell(formula)
a.setcell(x, y, cell)
## if os.path.isfile("sheet1.xml"):
## print "Loading from sheet1.xml"
## a.load("sheet1.xml")
a.display()
a.save("sheet1.xml")
def test_gui():
"GUI test."
if sys.argv[1:]:
filename = sys.argv[1]
else:
filename = "sheet1.xml"
g = SheetGUI(filename)
g.root.mainloop()
if __name__ == '__main__':
#test_basic()
test_gui()

74
third_party/python/Tools/demo/vector.py vendored Executable file
View file

@ -0,0 +1,74 @@
#!/usr/bin/env python3
"""
A demonstration of classes and their special methods in Python.
"""
class Vec:
"""A simple vector class.
Instances of the Vec class can be constructed from numbers
>>> a = Vec(1, 2, 3)
>>> b = Vec(3, 2, 1)
added
>>> a + b
Vec(4, 4, 4)
subtracted
>>> a - b
Vec(-2, 0, 2)
and multiplied by a scalar on the left
>>> 3.0 * a
Vec(3.0, 6.0, 9.0)
or on the right
>>> a * 3.0
Vec(3.0, 6.0, 9.0)
"""
def __init__(self, *v):
self.v = list(v)
@classmethod
def fromlist(cls, v):
if not isinstance(v, list):
raise TypeError
inst = cls()
inst.v = v
return inst
def __repr__(self):
args = ', '.join(repr(x) for x in self.v)
return 'Vec({})'.format(args)
def __len__(self):
return len(self.v)
def __getitem__(self, i):
return self.v[i]
def __add__(self, other):
# Element-wise addition
v = [x + y for x, y in zip(self.v, other.v)]
return Vec.fromlist(v)
def __sub__(self, other):
# Element-wise subtraction
v = [x - y for x, y in zip(self.v, other.v)]
return Vec.fromlist(v)
def __mul__(self, scalar):
# Multiply by scalar
v = [x * scalar for x in self.v]
return Vec.fromlist(v)
__rmul__ = __mul__
def test():
import doctest
doctest.testmod()
test()

296
third_party/python/Tools/freeze/README vendored Normal file
View file

@ -0,0 +1,296 @@
THE FREEZE SCRIPT
=================
(Directions for Windows are at the end of this file.)
What is Freeze?
---------------
Freeze make it possible to ship arbitrary Python programs to people
who don't have Python. The shipped file (called a "frozen" version of
your Python program) is an executable, so this only works if your
platform is compatible with that on the receiving end (this is usually
a matter of having the same major operating system revision and CPU
type).
The shipped file contains a Python interpreter and large portions of
the Python run-time. Some measures have been taken to avoid linking
unneeded modules, but the resulting binary is usually not small.
The Python source code of your program (and of the library modules
written in Python that it uses) is not included in the binary --
instead, the compiled byte-code (the instruction stream used
internally by the interpreter) is incorporated. This gives some
protection of your Python source code, though not much -- a
disassembler for Python byte-code is available in the standard Python
library. At least someone running "strings" on your binary won't see
the source.
How does Freeze know which modules to include?
----------------------------------------------
Previous versions of Freeze used a pretty simple-minded algorithm to
find the modules that your program uses, essentially searching for
lines starting with the word "import". It was pretty easy to trick it
into making mistakes, either missing valid import statements, or
mistaking string literals (e.g. doc strings) for import statements.
This has been remedied: Freeze now uses the regular Python parser to
parse the program (and all its modules) and scans the generated byte
code for IMPORT instructions. It may still be confused -- it will not
know about calls to the __import__ built-in function, or about import
statements constructed on the fly and executed using the 'exec'
statement, and it will consider import statements even when they are
unreachable (e.g. "if 0: import foobar").
This new version of Freeze also knows about Python's new package
import mechanism, and uses exactly the same rules to find imported
modules and packages. One exception: if you write 'from package
import *', Python will look into the __all__ variable of the package
to determine which modules are to be imported, while Freeze will do a
directory listing.
One tricky issue: Freeze assumes that the Python interpreter and
environment you're using to run Freeze is the same one that would be
used to run your program, which should also be the same whose sources
and installed files you will learn about in the next section. In
particular, your PYTHONPATH setting should be the same as for running
your program locally. (Tip: if the program doesn't run when you type
"python hello.py" there's little chance of getting the frozen version
to run.)
How do I use Freeze?
--------------------
Normally, you should be able to use it as follows:
python freeze.py hello.py
where hello.py is your program and freeze.py is the main file of
Freeze (in actuality, you'll probably specify an absolute pathname
such as /usr/joe/python/Tools/freeze/freeze.py).
What do I do next?
------------------
Freeze creates a number of files: frozen.c, config.c and Makefile,
plus one file for each Python module that gets included named
M_<module>.c. To produce the frozen version of your program, you can
simply type "make". This should produce a binary file. If the
filename argument to Freeze was "hello.py", the binary will be called
"hello".
Note: you can use the -o option to freeze to specify an alternative
directory where these files are created. This makes it easier to
clean up after you've shipped the frozen binary. You should invoke
"make" in the given directory.
Freezing Tkinter programs
-------------------------
Unfortunately, it is currently not possible to freeze programs that
use Tkinter without a Tcl/Tk installation. The best way to ship a
frozen Tkinter program is to decide in advance where you are going
to place the Tcl and Tk library files in the distributed setup, and
then declare these directories in your frozen Python program using
the TCL_LIBRARY, TK_LIBRARY and TIX_LIBRARY environment variables.
For example, assume you will ship your frozen program in the directory
<root>/bin/windows-x86 and will place your Tcl library files
in <root>/lib/tcl8.2 and your Tk library files in <root>/lib/tk8.2. Then
placing the following lines in your frozen Python script before importing
Tkinter or Tix would set the environment correctly for Tcl/Tk/Tix:
import os
import os.path
RootDir = os.path.dirname(os.path.dirname(os.getcwd()))
import sys
if sys.platform == "win32":
sys.path = ['', '..\\..\\lib\\python-2.0']
os.environ['TCL_LIBRARY'] = RootDir + '\\lib\\tcl8.2'
os.environ['TK_LIBRARY'] = RootDir + '\\lib\\tk8.2'
os.environ['TIX_LIBRARY'] = RootDir + '\\lib\\tix8.1'
elif sys.platform == "linux2":
sys.path = ['', '../../lib/python-2.0']
os.environ['TCL_LIBRARY'] = RootDir + '/lib/tcl8.2'
os.environ['TK_LIBRARY'] = RootDir + '/lib/tk8.2'
os.environ['TIX_LIBRARY'] = RootDir + '/lib/tix8.1'
elif sys.platform == "solaris":
sys.path = ['', '../../lib/python-2.0']
os.environ['TCL_LIBRARY'] = RootDir + '/lib/tcl8.2'
os.environ['TK_LIBRARY'] = RootDir + '/lib/tk8.2'
os.environ['TIX_LIBRARY'] = RootDir + '/lib/tix8.1'
This also adds <root>/lib/python-2.0 to your Python path
for any Python files such as _tkinter.pyd you may need.
Note that the dynamic libraries (such as tcl82.dll tk82.dll python20.dll
under Windows, or libtcl8.2.so and libtcl8.2.so under Unix) are required
at program load time, and are searched by the operating system loader
before Python can be started. Under Windows, the environment
variable PATH is consulted, and under Unix, it may be the
environment variable LD_LIBRARY_PATH and/or the system
shared library cache (ld.so). An additional preferred directory for
finding the dynamic libraries is built into the .dll or .so files at
compile time - see the LIB_RUNTIME_DIR variable in the Tcl makefile.
The OS must find the dynamic libraries or your frozen program won't start.
Usually I make sure that the .so or .dll files are in the same directory
as the executable, but this may not be foolproof.
A workaround to installing your Tcl library files with your frozen
executable would be possible, in which the Tcl/Tk library files are
incorporated in a frozen Python module as string literals and written
to a temporary location when the program runs; this is currently left
as an exercise for the reader. An easier approach is to freeze the
Tcl/Tk/Tix code into the dynamic libraries using the Tcl ET code,
or the Tix Stand-Alone-Module code. Of course, you can also simply
require that Tcl/Tk is required on the target installation, but be
careful that the version corresponds.
There are some caveats using frozen Tkinter applications:
Under Windows if you use the -s windows option, writing
to stdout or stderr is an error.
The Tcl [info nameofexecutable] will be set to where the
program was frozen, not where it is run from.
The global variables argc and argv do not exist.
A warning about shared library modules
--------------------------------------
When your Python installation uses shared library modules such as
_tkinter.pyd, these will not be incorporated in the frozen program.
Again, the frozen program will work when you test it, but it won't
work when you ship it to a site without a Python installation.
Freeze prints a warning when this is the case at the end of the
freezing process:
Warning: unknown modules remain: ...
When this occurs, the best thing to do is usually to rebuild Python
using static linking only. Or use the approach described in the previous
section to declare a library path using sys.path, and place the modules
such as _tkinter.pyd there.
Troubleshooting
---------------
If you have trouble using Freeze for a large program, it's probably
best to start playing with a really simple program first (like the file
hello.py). If you can't get that to work there's something
fundamentally wrong -- perhaps you haven't installed Python. To do a
proper install, you should do "make install" in the Python root
directory.
Usage under Windows 95 or NT
----------------------------
Under Windows 95 or NT, you *must* use the -p option and point it to
the top of the Python source tree.
WARNING: the resulting executable is not self-contained; it requires
the Python DLL, currently PYTHON20.DLL (it does not require the
standard library of .py files though). It may also require one or
more extension modules loaded from .DLL or .PYD files; the module
names are printed in the warning message about remaining unknown
modules.
The driver script generates a Makefile that works with the Microsoft
command line C compiler (CL). To compile, run "nmake"; this will
build a target "hello.exe" if the source was "hello.py". Only the
files frozenmain.c and frozen.c are used; no config.c is generated or
used, since the standard DLL is used.
In order for this to work, you must have built Python using the VC++
(Developer Studio) 5.0 compiler. The provided project builds
python20.lib in the subdirectory pcbuild\Release of thje Python source
tree, and this is where the generated Makefile expects it to be. If
this is not the case, you can edit the Makefile or (probably better)
winmakemakefile.py (e.g., if you are using the 4.2 compiler, the
python20.lib file is generated in the subdirectory vc40 of the Python
source tree).
It is possible to create frozen programs that don't have a console
window, by specifying the option '-s windows'. See the Usage below.
Usage
-----
Here is a list of all of the options (taken from freeze.__doc__):
usage: freeze [options...] script [module]...
Options:
-p prefix: This is the prefix used when you ran ``make install''
in the Python build directory.
(If you never ran this, freeze won't work.)
The default is whatever sys.prefix evaluates to.
It can also be the top directory of the Python source
tree; then -P must point to the build tree.
-P exec_prefix: Like -p but this is the 'exec_prefix', used to
install objects etc. The default is whatever sys.exec_prefix
evaluates to, or the -p argument if given.
If -p points to the Python source tree, -P must point
to the build tree, if different.
-e extension: A directory containing additional .o files that
may be used to resolve modules. This directory
should also have a Setup file describing the .o files.
On Windows, the name of a .INI file describing one
or more extensions is passed.
More than one -e option may be given.
-o dir: Directory where the output files are created; default '.'.
-m: Additional arguments are module names instead of filenames.
-a package=dir: Additional directories to be added to the package's
__path__. Used to simulate directories added by the
package at runtime (eg, by OpenGL and win32com).
More than one -a option may be given for each package.
-l file: Pass the file to the linker (windows only)
-d: Debugging mode for the module finder.
-q: Make the module finder totally quiet.
-h: Print this help message.
-x module Exclude the specified module.
-i filename: Include a file with additional command line options. Used
to prevent command lines growing beyond the capabilities of
the shell/OS. All arguments specified in filename
are read and the -i option replaced with the parsed
params (note - quoting args in this file is NOT supported)
-s subsystem: Specify the subsystem (For Windows only.);
'console' (default), 'windows', 'service' or 'com_dll'
-w: Toggle Windows (NT or 95) behavior.
(For debugging only -- on a win32 platform, win32 behavior
is automatic.)
Arguments:
script: The Python script to be executed by the resulting binary.
module ...: Additional Python modules (referenced by pathname)
that will be included in the resulting binary. These
may be .py or .pyc files. If -m is specified, these are
module names that are search in the path instead.
--Guido van Rossum (home page: http://www.python.org/~guido/)

View file

@ -0,0 +1,26 @@
from builtins import open as _orig_open
def open(file, mode='r', bufsize=-1):
if 'w' not in mode:
return _orig_open(file, mode, bufsize)
import os
backup = file + '~'
try:
os.unlink(backup)
except OSError:
pass
try:
os.rename(file, backup)
except OSError:
return _orig_open(file, mode, bufsize)
f = _orig_open(file, mode, bufsize)
_orig_close = f.close
def close():
_orig_close()
import filecmp
if filecmp.cmp(backup, file, shallow=False):
import os
os.unlink(file)
os.rename(backup, file)
f.close = close
return f

View file

@ -0,0 +1,90 @@
# Check for a module in a set of extension directories.
# An extension directory should contain a Setup file
# and one or more .o files or a lib.a file.
import os
import parsesetup
def checkextensions(unknown, extensions):
files = []
modules = []
edict = {}
for e in extensions:
setup = os.path.join(e, 'Setup')
liba = os.path.join(e, 'lib.a')
if not os.path.isfile(liba):
liba = None
edict[e] = parsesetup.getsetupinfo(setup), liba
for mod in unknown:
for e in extensions:
(mods, vars), liba = edict[e]
if mod not in mods:
continue
modules.append(mod)
if liba:
# If we find a lib.a, use it, ignore the
# .o files, and use *all* libraries for
# *all* modules in the Setup file
if liba in files:
break
files.append(liba)
for m in list(mods.keys()):
files = files + select(e, mods, vars,
m, 1)
break
files = files + select(e, mods, vars, mod, 0)
break
return files, modules
def select(e, mods, vars, mod, skipofiles):
files = []
for w in mods[mod]:
w = treatword(w)
if not w:
continue
w = expandvars(w, vars)
for w in w.split():
if skipofiles and w[-2:] == '.o':
continue
# Assume $var expands to absolute pathname
if w[0] not in ('-', '$') and w[-2:] in ('.o', '.a'):
w = os.path.join(e, w)
if w[:2] in ('-L', '-R') and w[2:3] != '$':
w = w[:2] + os.path.join(e, w[2:])
files.append(w)
return files
cc_flags = ['-I', '-D', '-U']
cc_exts = ['.c', '.C', '.cc', '.c++']
def treatword(w):
if w[:2] in cc_flags:
return None
if w[:1] == '-':
return w # Assume loader flag
head, tail = os.path.split(w)
base, ext = os.path.splitext(tail)
if ext in cc_exts:
tail = base + '.o'
w = os.path.join(head, tail)
return w
def expandvars(str, vars):
i = 0
while i < len(str):
i = k = str.find('$', i)
if i < 0:
break
i = i+1
var = str[i:i+1]
i = i+1
if var == '(':
j = str.find(')', i)
if j < 0:
break
var = str[i:j]
i = j+1
if var in vars:
str = str[:k] + vars[var] + str[i:]
i = k
return str

View file

@ -0,0 +1,188 @@
"""Extension management for Windows.
Under Windows it is unlikely the .obj files are of use, as special compiler options
are needed (primarily to toggle the behavior of "public" symbols.
I don't consider it worth parsing the MSVC makefiles for compiler options. Even if
we get it just right, a specific freeze application may have specific compiler
options anyway (eg, to enable or disable specific functionality)
So my basic strategy is:
* Have some Windows INI files which "describe" one or more extension modules.
(Freeze comes with a default one for all known modules - but you can specify
your own).
* This description can include:
- The MSVC .dsp file for the extension. The .c source file names
are extracted from there.
- Specific compiler/linker options
- Flag to indicate if Unicode compilation is expected.
At the moment the name and location of this INI file is hardcoded,
but an obvious enhancement would be to provide command line options.
"""
import os, sys
try:
import win32api
except ImportError:
win32api = None # User has already been warned
class CExtension:
"""An abstraction of an extension implemented in C/C++
"""
def __init__(self, name, sourceFiles):
self.name = name
# A list of strings defining additional compiler options.
self.sourceFiles = sourceFiles
# A list of special compiler options to be applied to
# all source modules in this extension.
self.compilerOptions = []
# A list of .lib files the final .EXE will need.
self.linkerLibs = []
def GetSourceFiles(self):
return self.sourceFiles
def AddCompilerOption(self, option):
self.compilerOptions.append(option)
def GetCompilerOptions(self):
return self.compilerOptions
def AddLinkerLib(self, lib):
self.linkerLibs.append(lib)
def GetLinkerLibs(self):
return self.linkerLibs
def checkextensions(unknown, extra_inis, prefix):
# Create a table of frozen extensions
defaultMapName = os.path.join( os.path.split(sys.argv[0])[0], "extensions_win32.ini")
if not os.path.isfile(defaultMapName):
sys.stderr.write("WARNING: %s can not be found - standard extensions may not be found\n" % defaultMapName)
else:
# must go on end, so other inis can override.
extra_inis.append(defaultMapName)
ret = []
for mod in unknown:
for ini in extra_inis:
# print "Looking for", mod, "in", win32api.GetFullPathName(ini),"...",
defn = get_extension_defn( mod, ini, prefix )
if defn is not None:
# print "Yay - found it!"
ret.append( defn )
break
# print "Nope!"
else: # For not broken!
sys.stderr.write("No definition of module %s in any specified map file.\n" % (mod))
return ret
def get_extension_defn(moduleName, mapFileName, prefix):
if win32api is None: return None
os.environ['PYTHONPREFIX'] = prefix
dsp = win32api.GetProfileVal(moduleName, "dsp", "", mapFileName)
if dsp=="":
return None
# We allow environment variables in the file name
dsp = win32api.ExpandEnvironmentStrings(dsp)
# If the path to the .DSP file is not absolute, assume it is relative
# to the description file.
if not os.path.isabs(dsp):
dsp = os.path.join( os.path.split(mapFileName)[0], dsp)
# Parse it to extract the source files.
sourceFiles = parse_dsp(dsp)
if sourceFiles is None:
return None
module = CExtension(moduleName, sourceFiles)
# Put the path to the DSP into the environment so entries can reference it.
os.environ['dsp_path'] = os.path.split(dsp)[0]
os.environ['ini_path'] = os.path.split(mapFileName)[0]
cl_options = win32api.GetProfileVal(moduleName, "cl", "", mapFileName)
if cl_options:
module.AddCompilerOption(win32api.ExpandEnvironmentStrings(cl_options))
exclude = win32api.GetProfileVal(moduleName, "exclude", "", mapFileName)
exclude = exclude.split()
if win32api.GetProfileVal(moduleName, "Unicode", 0, mapFileName):
module.AddCompilerOption('/D UNICODE /D _UNICODE')
libs = win32api.GetProfileVal(moduleName, "libs", "", mapFileName).split()
for lib in libs:
module.AddLinkerLib(win32api.ExpandEnvironmentStrings(lib))
for exc in exclude:
if exc in module.sourceFiles:
module.sourceFiles.remove(exc)
return module
# Given an MSVC DSP file, locate C source files it uses
# returns a list of source files.
def parse_dsp(dsp):
# print "Processing", dsp
# For now, only support
ret = []
dsp_path, dsp_name = os.path.split(dsp)
try:
lines = open(dsp, "r").readlines()
except IOError as msg:
sys.stderr.write("%s: %s\n" % (dsp, msg))
return None
for line in lines:
fields = line.strip().split("=", 2)
if fields[0]=="SOURCE":
if os.path.splitext(fields[1])[1].lower() in ['.cpp', '.c']:
ret.append( win32api.GetFullPathName(os.path.join(dsp_path, fields[1] ) ) )
return ret
def write_extension_table(fname, modules):
fp = open(fname, "w")
try:
fp.write (ext_src_header)
# Write fn protos
for module in modules:
# bit of a hack for .pyd's as part of packages.
name = module.name.split('.')[-1]
fp.write('extern void init%s(void);\n' % (name) )
# Write the table
fp.write (ext_tab_header)
for module in modules:
name = module.name.split('.')[-1]
fp.write('\t{"%s", init%s},\n' % (name, name) )
fp.write (ext_tab_footer)
fp.write(ext_src_footer)
finally:
fp.close()
ext_src_header = """\
#include "Python.h"
"""
ext_tab_header = """\
static struct _inittab extensions[] = {
"""
ext_tab_footer = """\
/* Sentinel */
{0, 0}
};
"""
ext_src_footer = """\
extern DL_IMPORT(int) PyImport_ExtendInittab(struct _inittab *newtab);
int PyInitFrozenExtensions()
{
return PyImport_ExtendInittab(extensions);
}
"""

View file

@ -0,0 +1,171 @@
; This is a list of modules generally build as .pyd files.
;
; Each section contains enough information about a module for
; freeze to include the module as a static, built-in module
; in a frozen .EXE/.DLL.
; This is all setup for all the win32 extension modules
; released by Mark Hammond.
; You must ensure that the environment variable PYTHONEX is set
; to point to the root win32 extensions directory
; PYTHONPREFIX must point to the Python build root directory
; (the *parent* of PCbuild); normally the freeze script takes
; care of this.
;--------------------------------------------------------------
;
; Standard Python extension modules
;
; Here are some of the standard Python extensions modules.
; If you need others, add them here
[_socket]
dsp=%PYTHONPREFIX%\PCBuild\_socket.dsp
[_sre]
dsp=%PYTHONPREFIX%\PCBuild\_sre.dsp
[unicodedata]
dsp=%PYTHONPREFIX%\PCBuild\unicodedata.dsp
[mmap]
dsp=%PYTHONPREFIX%\PCBuild\mmap.dsp
[winsound]
dsp=%PYTHONPREFIX%\PCBuild\winsound.dsp
libs=winmm.lib
[parser]
dsp=%PYTHONPREFIX%\PCBuild\parser.dsp
[select]
dsp=%PYTHONPREFIX%\PCBuild\select.dsp
[zlib]
dsp=%PYTHONPREFIX%\PCBuild\zlib.dsp
cl=/I %PYTHONPREFIX%\..\zlib-1.1.4 /D _WINDOWS /D WIN32
libs=%PYTHONPREFIX%\..\zlib-1.1.4\zlib.lib /nodefaultlib:libc
[winreg]
dsp=%PYTHONPREFIX%\PCBuild\winreg.dsp
libs=advapi32.lib
;--------------------------------------------------------------
;
; Win32 Projects.
;
[perfmon]
dsp=%PYTHONEX%\win32\perfmon.dsp
cl=/I %PYTHONEX%\win32\src
Unicode=1
[pywintypes]
dsp=%PYTHONEX%\win32\pywintypes.dsp
cl=/I %PYTHONEX%\win32\src
libs=ole32.lib oleaut32.lib
[win32api]
dsp=%PYTHONEX%\win32\win32api.dsp
cl=/I %PYTHONEX%\win32\src
libs=kernel32.lib user32.lib shell32.lib advapi32.lib
[win32service]
dsp=%PYTHONEX%\win32\win32service.dsp
cl=/I %PYTHONEX%\win32\src
Unicode=1
libs=advapi32.lib
[win32evtlog]
dsp=%PYTHONEX%\win32\win32evtlog.dsp
cl=/I %PYTHONEX%\win32\src
[win32process]
dsp=%PYTHONEX%\win32\win32process.dsp
cl=/I %PYTHONEX%\win32\src
[win32event]
dsp=%PYTHONEX%\win32\win32event.dsp
cl=/I %PYTHONEX%\win32\src
[win32file]
dsp=%PYTHONEX%\win32\win32file.dsp
cl=/I %PYTHONEX%\win32\src
[win32net]
dsp=%PYTHONEX%\win32\win32net.dsp
cl=/I %PYTHONEX%\win32\src
libs=netapi32.lib
[win32pdh]
dsp=%PYTHONEX%\win32\win32pdh.dsp
cl=/I %PYTHONEX%\win32\src
[win32pipe]
dsp=%PYTHONEX%\win32\win32pipe.dsp
cl=/I %PYTHONEX%\win32\src
[win32security]
dsp=%PYTHONEX%\win32\win32security.dsp
cl=/I %PYTHONEX%\win32\src
[win32service]
dsp=%PYTHONEX%\win32\win32service.dsp
cl=/I %PYTHONEX%\win32\src
[win32trace]
dsp=%PYTHONEX%\win32\win32trace.dsp
cl=/I %PYTHONEX%\win32\src
;--------------------------------------------------------------
;
; COM Projects.
;
[pythoncom]
dsp=%PYTHONEX%\com\win32com.dsp
cl=/I %PYTHONEX%\com\win32com\src\include /I %PYTHONEX%\win32\src
libs=uuid.lib
[win32com.axcontrol.axcontrol]
dsp=%PYTHONEX%\com\axcontrol.dsp
cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include
[win32com.axscript.axscript]
dsp=%PYTHONEX%\com\Active Scripting.dsp
cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include
[win32com.axdebug.axdebug]
dsp=%PYTHONEX%\com\Active Debugging.dsp
cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include
[win32com.mapi.mapi]
dsp=%PYTHONEX%\com\mapi.dsp
cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include
libs=MBLOGON.lib ADDRLKUP.LIB mapi32.lib version.lib
[win32com.mapi.exchange]
dsp=%PYTHONEX%\com\exchange.dsp
cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include
libs=MBLOGON.lib ADDRLKUP.LIB exchinst.lib EDKCFG.LIB EDKUTILS.LIB EDKMAPI.LIB mapi32.lib version.lib
[win32com.mapi.exchdapi]
dsp=%PYTHONEX%\com\exchdapi.dsp
cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include
libs=DAPI.LIB
[servicemanager]
dsp=%PYTHONEX%\win32\PythonService EXE.dsp
Unicode = 1
; Pythonwin
[win32ui]
dsp=%PYTHONEX%\Pythonwin\win32ui.dsp
cl=/D _AFXDLL /D FREEZE_WIN32UI /GX /I %PYTHONEX%\win32\src
libs=mfc42.lib

View file

@ -0,0 +1,2 @@
initialized = True
print("Hello world!")

491
third_party/python/Tools/freeze/freeze.py vendored Executable file
View file

@ -0,0 +1,491 @@
#! /usr/bin/env python3
"""Freeze a Python script into a binary.
usage: freeze [options...] script [module]...
Options:
-p prefix: This is the prefix used when you ran ``make install''
in the Python build directory.
(If you never ran this, freeze won't work.)
The default is whatever sys.prefix evaluates to.
It can also be the top directory of the Python source
tree; then -P must point to the build tree.
-P exec_prefix: Like -p but this is the 'exec_prefix', used to
install objects etc. The default is whatever sys.exec_prefix
evaluates to, or the -p argument if given.
If -p points to the Python source tree, -P must point
to the build tree, if different.
-e extension: A directory containing additional .o files that
may be used to resolve modules. This directory
should also have a Setup file describing the .o files.
On Windows, the name of a .INI file describing one
or more extensions is passed.
More than one -e option may be given.
-o dir: Directory where the output files are created; default '.'.
-m: Additional arguments are module names instead of filenames.
-a package=dir: Additional directories to be added to the package's
__path__. Used to simulate directories added by the
package at runtime (eg, by OpenGL and win32com).
More than one -a option may be given for each package.
-l file: Pass the file to the linker (windows only)
-d: Debugging mode for the module finder.
-q: Make the module finder totally quiet.
-h: Print this help message.
-x module Exclude the specified module. It will still be imported
by the frozen binary if it exists on the host system.
-X module Like -x, except the module can never be imported by
the frozen binary.
-E: Freeze will fail if any modules can't be found (that
were not excluded using -x or -X).
-i filename: Include a file with additional command line options. Used
to prevent command lines growing beyond the capabilities of
the shell/OS. All arguments specified in filename
are read and the -i option replaced with the parsed
params (note - quoting args in this file is NOT supported)
-s subsystem: Specify the subsystem (For Windows only.);
'console' (default), 'windows', 'service' or 'com_dll'
-w: Toggle Windows (NT or 95) behavior.
(For debugging only -- on a win32 platform, win32 behavior
is automatic.)
-r prefix=f: Replace path prefix.
Replace prefix with f in the source path references
contained in the resulting binary.
Arguments:
script: The Python script to be executed by the resulting binary.
module ...: Additional Python modules (referenced by pathname)
that will be included in the resulting binary. These
may be .py or .pyc files. If -m is specified, these are
module names that are search in the path instead.
NOTES:
In order to use freeze successfully, you must have built Python and
installed it ("make install").
The script should not use modules provided only as shared libraries;
if it does, the resulting binary is not self-contained.
"""
# Import standard modules
import modulefinder
import getopt
import os
import sys
# Import the freeze-private modules
import checkextensions
import makeconfig
import makefreeze
import makemakefile
import parsesetup
import bkfile
# Main program
def main():
# overridable context
prefix = None # settable with -p option
exec_prefix = None # settable with -P option
extensions = []
exclude = [] # settable with -x option
addn_link = [] # settable with -l, but only honored under Windows.
path = sys.path[:]
modargs = 0
debug = 1
odir = ''
win = sys.platform[:3] == 'win'
replace_paths = [] # settable with -r option
error_if_any_missing = 0
# default the exclude list for each platform
if win: exclude = exclude + [
'dos', 'dospath', 'mac', 'macpath', 'macfs', 'MACFS', 'posix', ]
fail_import = exclude[:]
# output files
frozen_c = 'frozen.c'
config_c = 'config.c'
target = 'a.out' # normally derived from script name
makefile = 'Makefile'
subsystem = 'console'
# parse command line by first replacing any "-i" options with the
# file contents.
pos = 1
while pos < len(sys.argv)-1:
# last option can not be "-i", so this ensures "pos+1" is in range!
if sys.argv[pos] == '-i':
try:
options = open(sys.argv[pos+1]).read().split()
except IOError as why:
usage("File name '%s' specified with the -i option "
"can not be read - %s" % (sys.argv[pos+1], why) )
# Replace the '-i' and the filename with the read params.
sys.argv[pos:pos+2] = options
pos = pos + len(options) - 1 # Skip the name and the included args.
pos = pos + 1
# Now parse the command line with the extras inserted.
try:
opts, args = getopt.getopt(sys.argv[1:], 'r:a:dEe:hmo:p:P:qs:wX:x:l:')
except getopt.error as msg:
usage('getopt error: ' + str(msg))
# process option arguments
for o, a in opts:
if o == '-h':
print(__doc__)
return
if o == '-d':
debug = debug + 1
if o == '-e':
extensions.append(a)
if o == '-m':
modargs = 1
if o == '-o':
odir = a
if o == '-p':
prefix = a
if o == '-P':
exec_prefix = a
if o == '-q':
debug = 0
if o == '-w':
win = not win
if o == '-s':
if not win:
usage("-s subsystem option only on Windows")
subsystem = a
if o == '-x':
exclude.append(a)
if o == '-X':
exclude.append(a)
fail_import.append(a)
if o == '-E':
error_if_any_missing = 1
if o == '-l':
addn_link.append(a)
if o == '-a':
modulefinder.AddPackagePath(*a.split("=", 2))
if o == '-r':
f,r = a.split("=", 2)
replace_paths.append( (f,r) )
# modules that are imported by the Python runtime
implicits = []
for module in ('site', 'warnings', 'encodings.utf_8', 'encodings.latin_1'):
if module not in exclude:
implicits.append(module)
# default prefix and exec_prefix
if not exec_prefix:
if prefix:
exec_prefix = prefix
else:
exec_prefix = sys.exec_prefix
if not prefix:
prefix = sys.prefix
# determine whether -p points to the Python source tree
ishome = os.path.exists(os.path.join(prefix, 'Python', 'ceval.c'))
# locations derived from options
version = '%d.%d' % sys.version_info[:2]
flagged_version = version + sys.abiflags
if win:
extensions_c = 'frozen_extensions.c'
if ishome:
print("(Using Python source directory)")
binlib = exec_prefix
incldir = os.path.join(prefix, 'Include')
config_h_dir = exec_prefix
config_c_in = os.path.join(prefix, 'Modules', 'config.c.in')
frozenmain_c = os.path.join(prefix, 'Python', 'frozenmain.c')
makefile_in = os.path.join(exec_prefix, 'Makefile')
if win:
frozendllmain_c = os.path.join(exec_prefix, 'Pc\\frozen_dllmain.c')
else:
binlib = os.path.join(exec_prefix,
'lib', 'python%s' % version,
'config-%s' % flagged_version)
incldir = os.path.join(prefix, 'include', 'python%s' % flagged_version)
config_h_dir = os.path.join(exec_prefix, 'include',
'python%s' % flagged_version)
config_c_in = os.path.join(binlib, 'config.c.in')
frozenmain_c = os.path.join(binlib, 'frozenmain.c')
makefile_in = os.path.join(binlib, 'Makefile')
frozendllmain_c = os.path.join(binlib, 'frozen_dllmain.c')
supp_sources = []
defines = []
includes = ['-I' + incldir, '-I' + config_h_dir]
# sanity check of directories and files
check_dirs = [prefix, exec_prefix, binlib, incldir]
if not win:
# These are not directories on Windows.
check_dirs = check_dirs + extensions
for dir in check_dirs:
if not os.path.exists(dir):
usage('needed directory %s not found' % dir)
if not os.path.isdir(dir):
usage('%s: not a directory' % dir)
if win:
files = supp_sources + extensions # extensions are files on Windows.
else:
files = [config_c_in, makefile_in] + supp_sources
for file in supp_sources:
if not os.path.exists(file):
usage('needed file %s not found' % file)
if not os.path.isfile(file):
usage('%s: not a plain file' % file)
if not win:
for dir in extensions:
setup = os.path.join(dir, 'Setup')
if not os.path.exists(setup):
usage('needed file %s not found' % setup)
if not os.path.isfile(setup):
usage('%s: not a plain file' % setup)
# check that enough arguments are passed
if not args:
usage('at least one filename argument required')
# check that file arguments exist
for arg in args:
if arg == '-m':
break
# if user specified -m on the command line before _any_
# file names, then nothing should be checked (as the
# very first file should be a module name)
if modargs:
break
if not os.path.exists(arg):
usage('argument %s not found' % arg)
if not os.path.isfile(arg):
usage('%s: not a plain file' % arg)
# process non-option arguments
scriptfile = args[0]
modules = args[1:]
# derive target name from script name
base = os.path.basename(scriptfile)
base, ext = os.path.splitext(base)
if base:
if base != scriptfile:
target = base
else:
target = base + '.bin'
# handle -o option
base_frozen_c = frozen_c
base_config_c = config_c
base_target = target
if odir and not os.path.isdir(odir):
try:
os.mkdir(odir)
print("Created output directory", odir)
except OSError as msg:
usage('%s: mkdir failed (%s)' % (odir, str(msg)))
base = ''
if odir:
base = os.path.join(odir, '')
frozen_c = os.path.join(odir, frozen_c)
config_c = os.path.join(odir, config_c)
target = os.path.join(odir, target)
makefile = os.path.join(odir, makefile)
if win: extensions_c = os.path.join(odir, extensions_c)
# Handle special entry point requirements
# (on Windows, some frozen programs do not use __main__, but
# import the module directly. Eg, DLLs, Services, etc
custom_entry_point = None # Currently only used on Windows
python_entry_is_main = 1 # Is the entry point called __main__?
# handle -s option on Windows
if win:
import winmakemakefile
try:
custom_entry_point, python_entry_is_main = \
winmakemakefile.get_custom_entry_point(subsystem)
except ValueError as why:
usage(why)
# Actual work starts here...
# collect all modules of the program
dir = os.path.dirname(scriptfile)
path[0] = dir
mf = modulefinder.ModuleFinder(path, debug, exclude, replace_paths)
if win and subsystem=='service':
# If a Windows service, then add the "built-in" module.
mod = mf.add_module("servicemanager")
mod.__file__="dummy.pyd" # really built-in to the resulting EXE
for mod in implicits:
mf.import_hook(mod)
for mod in modules:
if mod == '-m':
modargs = 1
continue
if modargs:
if mod[-2:] == '.*':
mf.import_hook(mod[:-2], None, ["*"])
else:
mf.import_hook(mod)
else:
mf.load_file(mod)
# Alias "importlib._bootstrap" to "_frozen_importlib" so that the
# import machinery can bootstrap. Do the same for
# importlib._bootstrap_external.
mf.modules["_frozen_importlib"] = mf.modules["importlib._bootstrap"]
mf.modules["_frozen_importlib_external"] = mf.modules["importlib._bootstrap_external"]
# Add the main script as either __main__, or the actual module name.
if python_entry_is_main:
mf.run_script(scriptfile)
else:
mf.load_file(scriptfile)
if debug > 0:
mf.report()
print()
dict = mf.modules
if error_if_any_missing:
missing = mf.any_missing()
if missing:
sys.exit("There are some missing modules: %r" % missing)
# generate output for frozen modules
files = makefreeze.makefreeze(base, dict, debug, custom_entry_point,
fail_import)
# look for unfrozen modules (builtin and of unknown origin)
builtins = []
unknown = []
mods = sorted(dict.keys())
for mod in mods:
if dict[mod].__code__:
continue
if not dict[mod].__file__:
builtins.append(mod)
else:
unknown.append(mod)
# search for unknown modules in extensions directories (not on Windows)
addfiles = []
frozen_extensions = [] # Windows list of modules.
if unknown or (not win and builtins):
if not win:
addfiles, addmods = \
checkextensions.checkextensions(unknown+builtins,
extensions)
for mod in addmods:
if mod in unknown:
unknown.remove(mod)
builtins.append(mod)
else:
# Do the windows thang...
import checkextensions_win32
# Get a list of CExtension instances, each describing a module
# (including its source files)
frozen_extensions = checkextensions_win32.checkextensions(
unknown, extensions, prefix)
for mod in frozen_extensions:
unknown.remove(mod.name)
# report unknown modules
if unknown:
sys.stderr.write('Warning: unknown modules remain: %s\n' %
' '.join(unknown))
# windows gets different treatment
if win:
# Taking a shortcut here...
import winmakemakefile, checkextensions_win32
checkextensions_win32.write_extension_table(extensions_c,
frozen_extensions)
# Create a module definition for the bootstrap C code.
xtras = [frozenmain_c, os.path.basename(frozen_c),
frozendllmain_c, os.path.basename(extensions_c)] + files
maindefn = checkextensions_win32.CExtension( '__main__', xtras )
frozen_extensions.append( maindefn )
with open(makefile, 'w') as outfp:
winmakemakefile.makemakefile(outfp,
locals(),
frozen_extensions,
os.path.basename(target))
return
# generate config.c and Makefile
builtins.sort()
with open(config_c_in) as infp, bkfile.open(config_c, 'w') as outfp:
makeconfig.makeconfig(infp, outfp, builtins)
cflags = ['$(OPT)']
cppflags = defines + includes
libs = [os.path.join(binlib, '$(LDLIBRARY)')]
somevars = {}
if os.path.exists(makefile_in):
makevars = parsesetup.getmakevars(makefile_in)
for key in makevars:
somevars[key] = makevars[key]
somevars['CFLAGS'] = ' '.join(cflags) # override
somevars['CPPFLAGS'] = ' '.join(cppflags) # override
files = [base_config_c, base_frozen_c] + \
files + supp_sources + addfiles + libs + \
['$(MODLIBS)', '$(LIBS)', '$(SYSLIBS)']
with bkfile.open(makefile, 'w') as outfp:
makemakefile.makemakefile(outfp, somevars, files, base_target)
# Done!
if odir:
print('Now run "make" in', odir, end=' ')
print('to build the target:', base_target)
else:
print('Now run "make" to build the target:', base_target)
# Print usage message and exit
def usage(msg):
sys.stdout = sys.stderr
print("Error:", msg)
print("Use ``%s -h'' for help" % sys.argv[0])
sys.exit(2)
main()

View file

@ -0,0 +1 @@
print('Hello world...')

View file

@ -0,0 +1,59 @@
import re
import sys
# Write the config.c file
never = ['marshal', '_imp', '_ast', '__main__', 'builtins',
'sys', 'gc', '_warnings']
def makeconfig(infp, outfp, modules, with_ifdef=0):
m1 = re.compile('-- ADDMODULE MARKER 1 --')
m2 = re.compile('-- ADDMODULE MARKER 2 --')
for line in infp:
outfp.write(line)
if m1 and m1.search(line):
m1 = None
for mod in modules:
if mod in never:
continue
if with_ifdef:
outfp.write("#ifndef PyInit_%s\n"%mod)
outfp.write('extern PyObject* PyInit_%s(void);\n' % mod)
if with_ifdef:
outfp.write("#endif\n")
elif m2 and m2.search(line):
m2 = None
for mod in modules:
if mod in never:
continue
outfp.write('\t{"%s", PyInit_%s},\n' %
(mod, mod))
if m1:
sys.stderr.write('MARKER 1 never found\n')
elif m2:
sys.stderr.write('MARKER 2 never found\n')
# Test program.
def test():
if not sys.argv[3:]:
print('usage: python makeconfig.py config.c.in outputfile', end=' ')
print('modulename ...')
sys.exit(2)
if sys.argv[1] == '-':
infp = sys.stdin
else:
infp = open(sys.argv[1])
if sys.argv[2] == '-':
outfp = sys.stdout
else:
outfp = open(sys.argv[2], 'w')
makeconfig(infp, outfp, sys.argv[3:])
if outfp != sys.stdout:
outfp.close()
if infp != sys.stdin:
infp.close()
if __name__ == '__main__':
test()

View file

@ -0,0 +1,87 @@
import marshal
import bkfile
# Write a file containing frozen code for the modules in the dictionary.
header = """
#include "Python.h"
static struct _frozen _PyImport_FrozenModules[] = {
"""
trailer = """\
{0, 0, 0} /* sentinel */
};
"""
# if __debug__ == 0 (i.e. -O option given), set Py_OptimizeFlag in frozen app.
default_entry_point = """
int
main(int argc, char **argv)
{
extern int Py_FrozenMain(int, char **);
""" + ((not __debug__ and """
Py_OptimizeFlag++;
""") or "") + """
PyImport_FrozenModules = _PyImport_FrozenModules;
return Py_FrozenMain(argc, argv);
}
"""
def makefreeze(base, dict, debug=0, entry_point=None, fail_import=()):
if entry_point is None: entry_point = default_entry_point
done = []
files = []
mods = sorted(dict.keys())
for mod in mods:
m = dict[mod]
mangled = "__".join(mod.split("."))
if m.__code__:
file = 'M_' + mangled + '.c'
with bkfile.open(base + file, 'w') as outfp:
files.append(file)
if debug:
print("freezing", mod, "...")
str = marshal.dumps(m.__code__)
size = len(str)
if m.__path__:
# Indicate package by negative size
size = -size
done.append((mod, mangled, size))
writecode(outfp, mangled, str)
if debug:
print("generating table of frozen modules")
with bkfile.open(base + 'frozen.c', 'w') as outfp:
for mod, mangled, size in done:
outfp.write('extern unsigned char M_%s[];\n' % mangled)
outfp.write(header)
for mod, mangled, size in done:
outfp.write('\t{"%s", M_%s, %d},\n' % (mod, mangled, size))
outfp.write('\n')
# The following modules have a NULL code pointer, indicating
# that the frozen program should not search for them on the host
# system. Importing them will *always* raise an ImportError.
# The zero value size is never used.
for mod in fail_import:
outfp.write('\t{"%s", NULL, 0},\n' % (mod,))
outfp.write(trailer)
outfp.write(entry_point)
return files
# Write a C initializer for a module containing the frozen python code.
# The array is called M_<mod>.
def writecode(outfp, mod, str):
outfp.write('unsigned char M_%s[] = {' % mod)
for i in range(0, len(str), 16):
outfp.write('\n\t')
for c in bytes(str[i:i+16]):
outfp.write('%d,' % c)
outfp.write('\n};\n')
## def writecode(outfp, mod, str):
## outfp.write('unsigned char M_%s[%d] = "%s";\n' % (mod, len(str),
## '\\"'.join(map(lambda s: repr(s)[1:-1], str.split('"')))))

View file

@ -0,0 +1,28 @@
# Write the actual Makefile.
import os
def makemakefile(outfp, makevars, files, target):
outfp.write("# Makefile generated by freeze.py script\n\n")
keys = sorted(makevars.keys())
for key in keys:
outfp.write("%s=%s\n" % (key, makevars[key]))
outfp.write("\nall: %s\n\n" % target)
deps = []
for i in range(len(files)):
file = files[i]
if file[-2:] == '.c':
base = os.path.basename(file)
dest = base[:-2] + '.o'
outfp.write("%s: %s\n" % (dest, file))
outfp.write("\t$(CC) $(PY_CFLAGS) $(PY_CPPFLAGS) -c %s\n" % file)
files[i] = dest
deps.append(dest)
outfp.write("\n%s: %s\n" % (target, ' '.join(deps)))
outfp.write("\t$(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) %s -o %s $(LDLAST)\n" %
(' '.join(files), target))
outfp.write("\nclean:\n\t-rm -f *.o %s\n" % target)

View file

@ -0,0 +1,111 @@
# Parse Makefiles and Python Setup(.in) files.
import re
# Extract variable definitions from a Makefile.
# Return a dictionary mapping names to values.
# May raise IOError.
makevardef = re.compile('^([a-zA-Z0-9_]+)[ \t]*=(.*)')
def getmakevars(filename):
variables = {}
fp = open(filename)
pendingline = ""
try:
while 1:
line = fp.readline()
if pendingline:
line = pendingline + line
pendingline = ""
if not line:
break
if line.endswith('\\\n'):
pendingline = line[:-2]
matchobj = makevardef.match(line)
if not matchobj:
continue
(name, value) = matchobj.group(1, 2)
# Strip trailing comment
i = value.find('#')
if i >= 0:
value = value[:i]
value = value.strip()
variables[name] = value
finally:
fp.close()
return variables
# Parse a Python Setup(.in) file.
# Return two dictionaries, the first mapping modules to their
# definitions, the second mapping variable names to their values.
# May raise IOError.
setupvardef = re.compile('^([a-zA-Z0-9_]+)=(.*)')
def getsetupinfo(filename):
modules = {}
variables = {}
fp = open(filename)
pendingline = ""
try:
while 1:
line = fp.readline()
if pendingline:
line = pendingline + line
pendingline = ""
if not line:
break
# Strip comments
i = line.find('#')
if i >= 0:
line = line[:i]
if line.endswith('\\\n'):
pendingline = line[:-2]
continue
matchobj = setupvardef.match(line)
if matchobj:
(name, value) = matchobj.group(1, 2)
variables[name] = value.strip()
else:
words = line.split()
if words:
modules[words[0]] = words[1:]
finally:
fp.close()
return modules, variables
# Test the above functions.
def test():
import sys
import os
if not sys.argv[1:]:
print('usage: python parsesetup.py Makefile*|Setup* ...')
sys.exit(2)
for arg in sys.argv[1:]:
base = os.path.basename(arg)
if base[:8] == 'Makefile':
print('Make style parsing:', arg)
v = getmakevars(arg)
prdict(v)
elif base[:5] == 'Setup':
print('Setup style parsing:', arg)
m, v = getsetupinfo(arg)
prdict(m)
prdict(v)
else:
print(arg, 'is neither a Makefile nor a Setup file')
print('(name must begin with "Makefile" or "Setup")')
def prdict(d):
keys = sorted(d.keys())
for key in keys:
value = d[key]
print("%-15s" % key, str(value))
if __name__ == '__main__':
test()

View file

@ -0,0 +1,2 @@
import sys
sys.exit(0)

View file

@ -0,0 +1,119 @@
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
<META NAME="Generator" CONTENT="Microsoft Word 97">
<TITLE>win32</TITLE>
<META NAME="Version" CONTENT="8.0.3410">
<META NAME="Date" CONTENT="10/11/96">
<META NAME="Template" CONTENT="D:\Program Files\Microsoft Office\Office\HTML.DOT">
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#ffffff">
<H1>Freeze for Win32</H1>
<P>This document describes how to use Freeze for the Win32 platform. </P>
<P>Freeze itself is a Python tool for creating stand-alone executables from Python source code. This document does not attempt to document freeze itself - only the win32 specific changes.</P>
<H2>Frozen programs under Win32</H2>
<P>Frozen programs under Win32 can (theoretically) freeze any type of program supported by Python on Win32 - At the moment, Console .EXE and NT Service .EXE programs are supported. GUI Python programs and COM .EXE programs are very nearly all ready to go.</P>
<H3>Program Dependencies</H3>
<P>The person freezing the program has control over what external DLLs are required by a frozen program. The following dependencies are supported:</P>
<H4>Minimal frozen programs</H4>
<P>These programs freeze only .py files in your program. All external DLLs are required at run-time. This includes all .pyd/.dll modules used by your program, Python20.dll, and msvcrt.dll. </P>
<P>A small Python program would typically create a .EXE around 300kb.</P>
<H4>Frozen Extension programs</H4>
<B><I><P>Note:</B></I> For Python1.5.1, you must get a patch from Guido to import.c for this to work.</P>
<P>These programs also freeze in the sources from all .pyd and .dll files used at runtime. This means the resulting .EXE is only dependent on Python20.dll and msvcrt.dll.</P>
<P>A small Python program using win32api, win32con and one or 2 other win32 extensions would typically create a .EXE around 400kb.</P>
<H4>Completely frozen programs</H4>
<P>Completely stand-alone programs, as is the default on Unix systems. These are currently not supported, mainly as the size of a decent Python program gets very large. However, by tweaking the existing Unix support, this would not be difficult to do.</P>
<H2>Freezing Extension Modules</H2>
<P>By default, a file in the main "freeze" directory called "extensions_win32.ini" is used to obtain information about frozen extensions. A typical entry is:</P>
<CODE><P>[win32api]</P>
<P>dsp=%PYTHONEX%\win32\win32api.dsp</P>
<P>cl=/I %PYTHONEX%\win32\src</P>
<P>libs=kernel32.lib user32.lib shell32.lib advapi32.lib</P>
</CODE><P>&nbsp;</P>
<P>This entry indicates that the win32api extension module is defined in the MSVC project file "<CODE>%PYTHONEX%\win32\win32api.dsp</CODE>". Note the use of<CODE> </CODE>"<CODE>%PYTHONEX%" </CODE>- most strings are substituted with environment variables. In this case, it is assumed variable PYTHONEX points to the main "Python Extensions" source directory (which is assumed to be in the same structure as the release of the extension sources).</P>
<P>An entry in a .INI file can also control specific compiler options, and also the .lib files necessary to be linked with the application.</P>
<H3>Freezing Extension Module Considerations</H3>
<P>To prevent freezing extension modules, simply exclude that module using the freeze "-x" switch.</P>
<P>Occasionally, it will be necessary to explicitly include dependent modules. For example, many win32 modules are dependent on the "pywintypes" module - for example, the win32api module. In this case, the module may be explicitly included using the freeze "-m" option.</P>
<H3>Freezing win32com and PythonCOM</H3>
<P>PythonCOM.dll can be frozen as long as you are not implementing COM Servers. Ie, you can freeze programs which control other applications, but can not implement programs that are themselves controlled by other applications.</P>
<P>If you use any of the win32com .pyd extensions (ex, axscript, mapi, internet, axcontrol), then you will need to specify an additional "-a" option to point to the win32comext directory. There is an example below.</P>
<P>The use of the "win32com.client.gencache" module is not supported (although could be quite easily??)</P>
<H2>Examples</H2>
<P>Before we start, we must:</P>
<CODE><P>D:\temp\delme&gt;set PYTHONEX=d:\src\pythonex</P>
</CODE><H3>Helloworld.py</H3>
<H4>Source Code</H4><DIR>
<DIR>
<CODE><P>import sys</P>
<P>&nbsp;</P>
<P>print " ".join( ["Hello", "world"] + sys.argv[1:] )</P></DIR>
</DIR>
</CODE><H4>Command Line used</H4><DIR>
<DIR>
<FONT FACE="Courier New" SIZE=2><P>\src\python-1.5.1\tools\freeze\freeze.py helloworld.py</P>
<P>nmake</P></DIR>
</DIR>
</FONT><P>Resulting helloworld.exe: 114,688 bytes.</P>
<H3>Helloworld2.py</H3>
<P>Uses win32api. Demonstrates requirement for pywintypes, and difference between freezing extensions and not.</P>
<H4>Source Code</H4><DIR>
<DIR>
<P>import win32api</P>
<P>print "Hello from", win32api.GetComputerName()</P></DIR>
</DIR>
<H4>Command Line used</H4>
<P>By default, win32api will be frozen in with the .EXE. If you do not provide the "pywintypes" inclusion, then the link step will fail looking for all the pywintypes modules.</P><DIR>
<DIR>
<FONT FACE="Courier New" SIZE=2><P>\src\python-1.5.1\tools\freeze\freeze.py helloworld2.py -m pywintypes</P>
<P>nmake</P></DIR>
</DIR>
</FONT><P>Resulting helloworld2.exe: 167,936 bytes</P>
<P>Simply adding win32con to the mix gives an EXE of size: 352,768 bytes.</P>
<H4>Command Line used</H4>
<P>Using this build, we are dependent at runtime on the win32api.pyd and pywintypes15.dll files.</P><DIR>
<DIR>
<P>\src\python-1.5.1\tools\freeze\freeze.py -x win32api helloworld.py</P></DIR>
</DIR>
<P>Resulting helloworld2.exe: 114,688</P>
<P>Adding win32con to this build results in a size of: 252,928</P>
<H3>Testmapi.py</H3>
<P>Uses MAPI, a PythonCOM extension, and win32api.</P>
<H4>Source Code</H4>
<P>from win32com.mapi import mapi</P>
<P>import win32api</P>
<P>mapi.MAPIInitialize( (mapi.MAPI_INIT_VERSION, 0) )</P>
<P>print "Hello from", win32api.GetComputerName()</P>
<P>mapi.MAPIUninitialize()</P>
<H4>Command Line used</H4>
<P>As it does not import pythoncom or pywintypes itself, they must be specified. As it uses the win32comext directory, -a must be used. If you have built the win32com extensions from sources, then the second -a is required.</P><DIR>
<DIR>
<CODE><P>\src\python-1.5.1\tools\freeze\freeze.py -a win32com=%PYTHONEX%\com\win32comext -a win32com.mapi=%PYTHONEX%\com\build\release testmapi.py -m pywintypes -m pythoncom</P></DIR>
</DIR>
</CODE><P>Resulting testmapi.exe: 352,768 bytes</P>
<H3>PipeTestService.py</H3>
<P>This is a standard Python demo in the Win32 extensions. It can be found in the "win32\demos\service" directory.</P>
<H4>Command Line used</H4>
<P>This will create a native NT Service EXE, dependent only on the main Python20.dll. All other modules are built-in to the final .EXE</P><DIR>
<DIR>
<CODE><P>\src\python-1.5.1\tools\freeze\freeze.py -s service %PYTHONEX%\win32\demos\service\pipeTestService.py</P></DIR>
</DIR>
<P>Resulting pipeTestService.exe: </CODE><FONT FACE="Courier New" SIZE=2>533,504 bytes.</P></FONT></BODY>
</HTML>

View file

@ -0,0 +1,148 @@
import sys, os
# Template used then the program is a GUI program
WINMAINTEMPLATE = """
#include <windows.h>
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // pointer to command line
int nCmdShow // show state of window
)
{
extern int Py_FrozenMain(int, char **);
PyImport_FrozenModules = _PyImport_FrozenModules;
return Py_FrozenMain(__argc, __argv);
}
"""
SERVICETEMPLATE = """
extern int PythonService_main(int, char **);
int main( int argc, char **argv)
{
PyImport_FrozenModules = _PyImport_FrozenModules;
return PythonService_main(argc, argv);
}
"""
subsystem_details = {
# -s flag : (C entry point template), (is it __main__?), (is it a DLL?)
'console' : (None, 1, 0),
'windows' : (WINMAINTEMPLATE, 1, 0),
'service' : (SERVICETEMPLATE, 0, 0),
'com_dll' : ("", 0, 1),
}
def get_custom_entry_point(subsystem):
try:
return subsystem_details[subsystem][:2]
except KeyError:
raise ValueError("The subsystem %s is not known" % subsystem)
def makemakefile(outfp, vars, files, target):
save = sys.stdout
try:
sys.stdout = outfp
realwork(vars, files, target)
finally:
sys.stdout = save
def realwork(vars, moddefns, target):
version_suffix = "%r%r" % sys.version_info[:2]
print("# Makefile for Microsoft Visual C++ generated by freeze.py script")
print()
print('target = %s' % target)
print('pythonhome = %s' % vars['prefix'])
print()
print('DEBUG=0 # Set to 1 to use the _d versions of Python.')
print('!IF $(DEBUG)')
print('debug_suffix=_d')
print('c_debug=/Zi /Od /DDEBUG /D_DEBUG')
print('l_debug=/DEBUG')
print('temp_dir=Build\\Debug')
print('!ELSE')
print('debug_suffix=')
print('c_debug=/Ox')
print('l_debug=')
print('temp_dir=Build\\Release')
print('!ENDIF')
print()
print('# The following line assumes you have built Python using the standard instructions')
print('# Otherwise fix the following line to point to the library.')
print('pythonlib = "$(pythonhome)/pcbuild/python%s$(debug_suffix).lib"' % version_suffix)
print()
# We only ever write one "entry point" symbol - either
# "main" or "WinMain". Therefore, there is no need to
# pass a subsystem switch to the linker as it works it
# out all by itself. However, the subsystem _does_ determine
# the file extension and additional linker flags.
target_link_flags = ""
target_ext = ".exe"
if subsystem_details[vars['subsystem']][2]:
target_link_flags = "-dll"
target_ext = ".dll"
print("# As the target uses Python%s.dll, we must use this compiler option!" % version_suffix)
print("cdl = /MD")
print()
print("all: $(target)$(debug_suffix)%s" % (target_ext))
print()
print('$(temp_dir):')
print(r' if not exist $(temp_dir)\. mkdir $(temp_dir)')
print()
objects = []
libs = ["shell32.lib", "comdlg32.lib", "wsock32.lib", "user32.lib", "oleaut32.lib"]
for moddefn in moddefns:
print("# Module", moddefn.name)
for file in moddefn.sourceFiles:
base = os.path.basename(file)
base, ext = os.path.splitext(base)
objects.append(base + ".obj")
print(r'$(temp_dir)\%s.obj: "%s"' % (base, file))
print("\t@$(CC) -c -nologo /Fo$* $(cdl) $(c_debug) /D BUILD_FREEZE", end=' ')
print('"-I$(pythonhome)/Include" "-I$(pythonhome)/PC" \\')
print("\t\t$(cflags) $(cdebug) $(cinclude) \\")
extra = moddefn.GetCompilerOptions()
if extra:
print("\t\t%s \\" % (' '.join(extra),))
print('\t\t"%s"' % file)
print()
# Add .lib files this module needs
for modlib in moddefn.GetLinkerLibs():
if modlib not in libs:
libs.append(modlib)
print("ADDN_LINK_FILES=", end=' ')
for addn in vars['addn_link']: print('"%s"' % (addn), end=' ')
print() ; print()
print("OBJS=", end=' ')
for obj in objects: print(r'"$(temp_dir)\%s"' % (obj), end=' ')
print() ; print()
print("LIBS=", end=' ')
for lib in libs: print('"%s"' % (lib), end=' ')
print() ; print()
print("$(target)$(debug_suffix)%s: $(temp_dir) $(OBJS)" % (target_ext))
print("\tlink -out:$(target)$(debug_suffix)%s %s" %
(target_ext, target_link_flags), "@<<")
print("\t$(OBJS)")
print("\t$(LIBS)")
print("\t$(ADDN_LINK_FILES)")
print("\t$(pythonlib) $(lcustom) $(l_debug)")
print("\t$(resources)")
print("<<")
print()
print("clean:")
print("\t-del /f *.obj")
print("\t-del /f $(target).exe")

1959
third_party/python/Tools/gdb/libpython.py vendored Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,150 @@
#!/usr/bin/env python3
"""
Convert the X11 locale.alias file into a mapping dictionary suitable
for locale.py.
Written by Marc-Andre Lemburg <mal@genix.com>, 2004-12-10.
"""
import locale
import sys
_locale = locale
# Location of the X11 alias file.
LOCALE_ALIAS = '/usr/share/X11/locale/locale.alias'
# Location of the glibc SUPPORTED locales file.
SUPPORTED = '/usr/share/i18n/SUPPORTED'
def parse(filename):
with open(filename, encoding='latin1') as f:
lines = list(f)
data = {}
for line in lines:
line = line.strip()
if not line:
continue
if line[:1] == '#':
continue
locale, alias = line.split()
# Fix non-standard locale names, e.g. ks_IN@devanagari.UTF-8
if '@' in alias:
alias_lang, _, alias_mod = alias.partition('@')
if '.' in alias_mod:
alias_mod, _, alias_enc = alias_mod.partition('.')
alias = alias_lang + '.' + alias_enc + '@' + alias_mod
# Strip ':'
if locale[-1] == ':':
locale = locale[:-1]
# Lower-case locale
locale = locale.lower()
# Ignore one letter locale mappings (except for 'c')
if len(locale) == 1 and locale != 'c':
continue
# Normalize encoding, if given
if '.' in locale:
lang, encoding = locale.split('.')[:2]
encoding = encoding.replace('-', '')
encoding = encoding.replace('_', '')
locale = lang + '.' + encoding
data[locale] = alias
return data
def parse_glibc_supported(filename):
with open(filename, encoding='latin1') as f:
lines = list(f)
data = {}
for line in lines:
line = line.strip()
if not line:
continue
if line[:1] == '#':
continue
line = line.replace('/', ' ').strip()
line = line.rstrip('\\').rstrip()
words = line.split()
if len(words) != 2:
continue
alias, alias_encoding = words
# Lower-case locale
locale = alias.lower()
# Normalize encoding, if given
if '.' in locale:
lang, encoding = locale.split('.')[:2]
encoding = encoding.replace('-', '')
encoding = encoding.replace('_', '')
locale = lang + '.' + encoding
# Add an encoding to alias
alias, _, modifier = alias.partition('@')
alias = _locale._replace_encoding(alias, alias_encoding)
if modifier and not (modifier == 'euro' and alias_encoding == 'ISO-8859-15'):
alias += '@' + modifier
data[locale] = alias
return data
def pprint(data):
items = sorted(data.items())
for k, v in items:
print(' %-40s%a,' % ('%a:' % k, v))
def print_differences(data, olddata):
items = sorted(olddata.items())
for k, v in items:
if k not in data:
print('# removed %a' % k)
elif olddata[k] != data[k]:
print('# updated %a -> %a to %a' % \
(k, olddata[k], data[k]))
# Additions are not mentioned
def optimize(data):
locale_alias = locale.locale_alias
locale.locale_alias = data.copy()
for k, v in data.items():
del locale.locale_alias[k]
if locale.normalize(k) != v:
locale.locale_alias[k] = v
newdata = locale.locale_alias
errors = check(data)
locale.locale_alias = locale_alias
if errors:
sys.exit(1)
return newdata
def check(data):
# Check that all alias definitions from the X11 file
# are actually mapped to the correct alias locales.
errors = 0
for k, v in data.items():
if locale.normalize(k) != v:
print('ERROR: %a -> %a != %a' % (k, locale.normalize(k), v),
file=sys.stderr)
errors += 1
return errors
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--locale-alias', default=LOCALE_ALIAS,
help='location of the X11 alias file '
'(default: %a)' % LOCALE_ALIAS)
parser.add_argument('--glibc-supported', default=SUPPORTED,
help='location of the glibc SUPPORTED locales file '
'(default: %a)' % SUPPORTED)
args = parser.parse_args()
data = locale.locale_alias.copy()
data.update(parse_glibc_supported(args.glibc_supported))
data.update(parse(args.locale_alias))
while True:
# Repeat optimization while the size is decreased.
n = len(data)
data = optimize(data)
if len(data) == n:
break
print_differences(data, locale.locale_alias)
print()
print('locale_alias = {')
pprint(data)
print('}')

238
third_party/python/Tools/i18n/msgfmt.py vendored Executable file
View file

@ -0,0 +1,238 @@
#! /usr/bin/env python3
# Written by Martin v. Löwis <loewis@informatik.hu-berlin.de>
"""Generate binary message catalog from textual translation description.
This program converts a textual Uniforum-style message catalog (.po file) into
a binary GNU catalog (.mo file). This is essentially the same function as the
GNU msgfmt program, however, it is a simpler implementation.
Usage: msgfmt.py [OPTIONS] filename.po
Options:
-o file
--output-file=file
Specify the output file to write to. If omitted, output will go to a
file named filename.mo (based off the input file name).
-h
--help
Print this message and exit.
-V
--version
Display version information and exit.
"""
import os
import sys
import ast
import getopt
import struct
import array
from email.parser import HeaderParser
__version__ = "1.1"
MESSAGES = {}
def usage(code, msg=''):
print(__doc__, file=sys.stderr)
if msg:
print(msg, file=sys.stderr)
sys.exit(code)
def add(id, str, fuzzy):
"Add a non-fuzzy translation to the dictionary."
global MESSAGES
if not fuzzy and str:
MESSAGES[id] = str
def generate():
"Return the generated output."
global MESSAGES
# the keys are sorted in the .mo file
keys = sorted(MESSAGES.keys())
offsets = []
ids = strs = b''
for id in keys:
# For each string, we need size and file offset. Each string is NUL
# terminated; the NUL does not count into the size.
offsets.append((len(ids), len(id), len(strs), len(MESSAGES[id])))
ids += id + b'\0'
strs += MESSAGES[id] + b'\0'
output = ''
# The header is 7 32-bit unsigned integers. We don't use hash tables, so
# the keys start right after the index tables.
# translated string.
keystart = 7*4+16*len(keys)
# and the values start after the keys
valuestart = keystart + len(ids)
koffsets = []
voffsets = []
# The string table first has the list of keys, then the list of values.
# Each entry has first the size of the string, then the file offset.
for o1, l1, o2, l2 in offsets:
koffsets += [l1, o1+keystart]
voffsets += [l2, o2+valuestart]
offsets = koffsets + voffsets
output = struct.pack("Iiiiiii",
0x950412de, # Magic
0, # Version
len(keys), # # of entries
7*4, # start of key index
7*4+len(keys)*8, # start of value index
0, 0) # size and offset of hash table
output += array.array("i", offsets).tobytes()
output += ids
output += strs
return output
def make(filename, outfile):
ID = 1
STR = 2
# Compute .mo name from .po name and arguments
if filename.endswith('.po'):
infile = filename
else:
infile = filename + '.po'
if outfile is None:
outfile = os.path.splitext(infile)[0] + '.mo'
try:
with open(infile, 'rb') as f:
lines = f.readlines()
except IOError as msg:
print(msg, file=sys.stderr)
sys.exit(1)
section = None
fuzzy = 0
# Start off assuming Latin-1, so everything decodes without failure,
# until we know the exact encoding
encoding = 'latin-1'
# Parse the catalog
lno = 0
for l in lines:
l = l.decode(encoding)
lno += 1
# If we get a comment line after a msgstr, this is a new entry
if l[0] == '#' and section == STR:
add(msgid, msgstr, fuzzy)
section = None
fuzzy = 0
# Record a fuzzy mark
if l[:2] == '#,' and 'fuzzy' in l:
fuzzy = 1
# Skip comments
if l[0] == '#':
continue
# Now we are in a msgid section, output previous section
if l.startswith('msgid') and not l.startswith('msgid_plural'):
if section == STR:
add(msgid, msgstr, fuzzy)
if not msgid:
# See whether there is an encoding declaration
p = HeaderParser()
charset = p.parsestr(msgstr.decode(encoding)).get_content_charset()
if charset:
encoding = charset
section = ID
l = l[5:]
msgid = msgstr = b''
is_plural = False
# This is a message with plural forms
elif l.startswith('msgid_plural'):
if section != ID:
print('msgid_plural not preceded by msgid on %s:%d' % (infile, lno),
file=sys.stderr)
sys.exit(1)
l = l[12:]
msgid += b'\0' # separator of singular and plural
is_plural = True
# Now we are in a msgstr section
elif l.startswith('msgstr'):
section = STR
if l.startswith('msgstr['):
if not is_plural:
print('plural without msgid_plural on %s:%d' % (infile, lno),
file=sys.stderr)
sys.exit(1)
l = l.split(']', 1)[1]
if msgstr:
msgstr += b'\0' # Separator of the various plural forms
else:
if is_plural:
print('indexed msgstr required for plural on %s:%d' % (infile, lno),
file=sys.stderr)
sys.exit(1)
l = l[6:]
# Skip empty lines
l = l.strip()
if not l:
continue
l = ast.literal_eval(l)
if section == ID:
msgid += l.encode(encoding)
elif section == STR:
msgstr += l.encode(encoding)
else:
print('Syntax error on %s:%d' % (infile, lno), \
'before:', file=sys.stderr)
print(l, file=sys.stderr)
sys.exit(1)
# Add last entry
if section == STR:
add(msgid, msgstr, fuzzy)
# Compute output
output = generate()
try:
with open(outfile,"wb") as f:
f.write(output)
except IOError as msg:
print(msg, file=sys.stderr)
def main():
try:
opts, args = getopt.getopt(sys.argv[1:], 'hVo:',
['help', 'version', 'output-file='])
except getopt.error as msg:
usage(1, msg)
outfile = None
# parse options
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-V', '--version'):
print("msgfmt.py", __version__)
sys.exit(0)
elif opt in ('-o', '--output-file'):
outfile = arg
# do it
if not args:
print('No input file given', file=sys.stderr)
print("Try `msgfmt --help' for more information.", file=sys.stderr)
return
for filename in args:
make(filename, outfile)
if __name__ == '__main__':
main()

631
third_party/python/Tools/i18n/pygettext.py vendored Executable file
View file

@ -0,0 +1,631 @@
#! /usr/bin/env python3
# -*- coding: iso-8859-1 -*-
# Originally written by Barry Warsaw <barry@python.org>
#
# Minimally patched to make it even more xgettext compatible
# by Peter Funk <pf@artcom-gmbh.de>
#
# 2002-11-22 Jürgen Hermann <jh@web.de>
# Added checks that _() only contains string literals, and
# command line args are resolved to module lists, i.e. you
# can now pass a filename, a module or package name, or a
# directory (including globbing chars, important for Win32).
# Made docstring fit in 80 chars wide displays using pydoc.
#
# for selftesting
try:
import fintl
_ = fintl.gettext
except ImportError:
_ = lambda s: s
__doc__ = _("""pygettext -- Python equivalent of xgettext(1)
Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the
internationalization of C programs. Most of these tools are independent of
the programming language and can be used from within Python programs.
Martin von Loewis' work[1] helps considerably in this regard.
There's one problem though; xgettext is the program that scans source code
looking for message strings, but it groks only C (or C++). Python
introduces a few wrinkles, such as dual quoting characters, triple quoted
strings, and raw strings. xgettext understands none of this.
Enter pygettext, which uses Python's standard tokenize module to scan
Python source code, generating .pot files identical to what GNU xgettext[2]
generates for C and C++ code. From there, the standard GNU tools can be
used.
A word about marking Python strings as candidates for translation. GNU
xgettext recognizes the following keywords: gettext, dgettext, dcgettext,
and gettext_noop. But those can be a lot of text to include all over your
code. C and C++ have a trick: they use the C preprocessor. Most
internationalized C source includes a #define for gettext() to _() so that
what has to be written in the source is much less. Thus these are both
translatable strings:
gettext("Translatable String")
_("Translatable String")
Python of course has no preprocessor so this doesn't work so well. Thus,
pygettext searches only for _() by default, but see the -k/--keyword flag
below for how to augment this.
[1] http://www.python.org/workshops/1997-10/proceedings/loewis.html
[2] http://www.gnu.org/software/gettext/gettext.html
NOTE: pygettext attempts to be option and feature compatible with GNU
xgettext where ever possible. However some options are still missing or are
not fully implemented. Also, xgettext's use of command line switches with
option arguments is broken, and in these cases, pygettext just defines
additional switches.
Usage: pygettext [options] inputfile ...
Options:
-a
--extract-all
Extract all strings.
-d name
--default-domain=name
Rename the default output file from messages.pot to name.pot.
-E
--escape
Replace non-ASCII characters with octal escape sequences.
-D
--docstrings
Extract module, class, method, and function docstrings. These do
not need to be wrapped in _() markers, and in fact cannot be for
Python to consider them docstrings. (See also the -X option).
-h
--help
Print this help message and exit.
-k word
--keyword=word
Keywords to look for in addition to the default set, which are:
%(DEFAULTKEYWORDS)s
You can have multiple -k flags on the command line.
-K
--no-default-keywords
Disable the default set of keywords (see above). Any keywords
explicitly added with the -k/--keyword option are still recognized.
--no-location
Do not write filename/lineno location comments.
-n
--add-location
Write filename/lineno location comments indicating where each
extracted string is found in the source. These lines appear before
each msgid. The style of comments is controlled by the -S/--style
option. This is the default.
-o filename
--output=filename
Rename the default output file from messages.pot to filename. If
filename is `-' then the output is sent to standard out.
-p dir
--output-dir=dir
Output files will be placed in directory dir.
-S stylename
--style stylename
Specify which style to use for location comments. Two styles are
supported:
Solaris # File: filename, line: line-number
GNU #: filename:line
The style name is case insensitive. GNU style is the default.
-v
--verbose
Print the names of the files being processed.
-V
--version
Print the version of pygettext and exit.
-w columns
--width=columns
Set width of output to columns.
-x filename
--exclude-file=filename
Specify a file that contains a list of strings that are not be
extracted from the input files. Each string to be excluded must
appear on a line by itself in the file.
-X filename
--no-docstrings=filename
Specify a file that contains a list of files (one per line) that
should not have their docstrings extracted. This is only useful in
conjunction with the -D option above.
If `inputfile' is -, standard input is read.
""")
import os
import importlib.machinery
import importlib.util
import sys
import glob
import time
import getopt
import token
import tokenize
__version__ = '1.5'
default_keywords = ['_']
DEFAULTKEYWORDS = ', '.join(default_keywords)
EMPTYSTRING = ''
# The normal pot-file header. msgmerge and Emacs's po-mode work better if it's
# there.
pot_header = _('''\
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\\n"
"POT-Creation-Date: %(time)s\\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
"Language-Team: LANGUAGE <LL@li.org>\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=%(charset)s\\n"
"Content-Transfer-Encoding: %(encoding)s\\n"
"Generated-By: pygettext.py %(version)s\\n"
''')
def usage(code, msg=''):
print(__doc__ % globals(), file=sys.stderr)
if msg:
print(msg, file=sys.stderr)
sys.exit(code)
def make_escapes(pass_nonascii):
global escapes, escape
if pass_nonascii:
# Allow non-ascii characters to pass through so that e.g. 'msgid
# "Höhe"' would result not result in 'msgid "H\366he"'. Otherwise we
# escape any character outside the 32..126 range.
mod = 128
escape = escape_ascii
else:
mod = 256
escape = escape_nonascii
escapes = [r"\%03o" % i for i in range(mod)]
for i in range(32, 127):
escapes[i] = chr(i)
escapes[ord('\\')] = r'\\'
escapes[ord('\t')] = r'\t'
escapes[ord('\r')] = r'\r'
escapes[ord('\n')] = r'\n'
escapes[ord('\"')] = r'\"'
def escape_ascii(s, encoding):
return ''.join(escapes[ord(c)] if ord(c) < 128 else c for c in s)
def escape_nonascii(s, encoding):
return ''.join(escapes[b] for b in s.encode(encoding))
def is_literal_string(s):
return s[0] in '\'"' or (s[0] in 'rRuU' and s[1] in '\'"')
def safe_eval(s):
# unwrap quotes, safely
return eval(s, {'__builtins__':{}}, {})
def normalize(s, encoding):
# This converts the various Python string types into a format that is
# appropriate for .po files, namely much closer to C style.
lines = s.split('\n')
if len(lines) == 1:
s = '"' + escape(s, encoding) + '"'
else:
if not lines[-1]:
del lines[-1]
lines[-1] = lines[-1] + '\n'
for i in range(len(lines)):
lines[i] = escape(lines[i], encoding)
lineterm = '\\n"\n"'
s = '""\n"' + lineterm.join(lines) + '"'
return s
def containsAny(str, set):
"""Check whether 'str' contains ANY of the chars in 'set'"""
return 1 in [c in str for c in set]
def getFilesForName(name):
"""Get a list of module files for a filename, a module or package name,
or a directory.
"""
if not os.path.exists(name):
# check for glob chars
if containsAny(name, "*?[]"):
files = glob.glob(name)
list = []
for file in files:
list.extend(getFilesForName(file))
return list
# try to find module or package
try:
spec = importlib.util.find_spec(name)
name = spec.origin
except ImportError:
name = None
if not name:
return []
if os.path.isdir(name):
# find all python files in directory
list = []
# get extension for python source files
_py_ext = importlib.machinery.SOURCE_SUFFIXES[0]
for root, dirs, files in os.walk(name):
# don't recurse into CVS directories
if 'CVS' in dirs:
dirs.remove('CVS')
# add all *.py files to list
list.extend(
[os.path.join(root, file) for file in files
if os.path.splitext(file)[1] == _py_ext]
)
return list
elif os.path.exists(name):
# a single file
return [name]
return []
class TokenEater:
def __init__(self, options):
self.__options = options
self.__messages = {}
self.__state = self.__waiting
self.__data = []
self.__lineno = -1
self.__freshmodule = 1
self.__curfile = None
self.__enclosurecount = 0
def __call__(self, ttype, tstring, stup, etup, line):
# dispatch
## import token
## print('ttype:', token.tok_name[ttype], 'tstring:', tstring,
## file=sys.stderr)
self.__state(ttype, tstring, stup[0])
def __waiting(self, ttype, tstring, lineno):
opts = self.__options
# Do docstring extractions, if enabled
if opts.docstrings and not opts.nodocstrings.get(self.__curfile):
# module docstring?
if self.__freshmodule:
if ttype == tokenize.STRING and is_literal_string(tstring):
self.__addentry(safe_eval(tstring), lineno, isdocstring=1)
self.__freshmodule = 0
elif ttype not in (tokenize.COMMENT, tokenize.NL):
self.__freshmodule = 0
return
# class or func/method docstring?
if ttype == tokenize.NAME and tstring in ('class', 'def'):
self.__state = self.__suiteseen
return
if ttype == tokenize.NAME and tstring in opts.keywords:
self.__state = self.__keywordseen
def __suiteseen(self, ttype, tstring, lineno):
# skip over any enclosure pairs until we see the colon
if ttype == tokenize.OP:
if tstring == ':' and self.__enclosurecount == 0:
# we see a colon and we're not in an enclosure: end of def
self.__state = self.__suitedocstring
elif tstring in '([{':
self.__enclosurecount += 1
elif tstring in ')]}':
self.__enclosurecount -= 1
def __suitedocstring(self, ttype, tstring, lineno):
# ignore any intervening noise
if ttype == tokenize.STRING and is_literal_string(tstring):
self.__addentry(safe_eval(tstring), lineno, isdocstring=1)
self.__state = self.__waiting
elif ttype not in (tokenize.NEWLINE, tokenize.INDENT,
tokenize.COMMENT):
# there was no class docstring
self.__state = self.__waiting
def __keywordseen(self, ttype, tstring, lineno):
if ttype == tokenize.OP and tstring == '(':
self.__data = []
self.__lineno = lineno
self.__state = self.__openseen
else:
self.__state = self.__waiting
def __openseen(self, ttype, tstring, lineno):
if ttype == tokenize.OP and tstring == ')':
# We've seen the last of the translatable strings. Record the
# line number of the first line of the strings and update the list
# of messages seen. Reset state for the next batch. If there
# were no strings inside _(), then just ignore this entry.
if self.__data:
self.__addentry(EMPTYSTRING.join(self.__data))
self.__state = self.__waiting
elif ttype == tokenize.STRING and is_literal_string(tstring):
self.__data.append(safe_eval(tstring))
elif ttype not in [tokenize.COMMENT, token.INDENT, token.DEDENT,
token.NEWLINE, tokenize.NL]:
# warn if we see anything else than STRING or whitespace
print(_(
'*** %(file)s:%(lineno)s: Seen unexpected token "%(token)s"'
) % {
'token': tstring,
'file': self.__curfile,
'lineno': self.__lineno
}, file=sys.stderr)
self.__state = self.__waiting
def __addentry(self, msg, lineno=None, isdocstring=0):
if lineno is None:
lineno = self.__lineno
if not msg in self.__options.toexclude:
entry = (self.__curfile, lineno)
self.__messages.setdefault(msg, {})[entry] = isdocstring
def set_filename(self, filename):
self.__curfile = filename
self.__freshmodule = 1
def write(self, fp):
options = self.__options
timestamp = time.strftime('%Y-%m-%d %H:%M%z')
encoding = fp.encoding if fp.encoding else 'UTF-8'
print(pot_header % {'time': timestamp, 'version': __version__,
'charset': encoding,
'encoding': '8bit'}, file=fp)
# Sort the entries. First sort each particular entry's keys, then
# sort all the entries by their first item.
reverse = {}
for k, v in self.__messages.items():
keys = sorted(v.keys())
reverse.setdefault(tuple(keys), []).append((k, v))
rkeys = sorted(reverse.keys())
for rkey in rkeys:
rentries = reverse[rkey]
rentries.sort()
for k, v in rentries:
# If the entry was gleaned out of a docstring, then add a
# comment stating so. This is to aid translators who may wish
# to skip translating some unimportant docstrings.
isdocstring = any(v.values())
# k is the message string, v is a dictionary-set of (filename,
# lineno) tuples. We want to sort the entries in v first by
# file name and then by line number.
v = sorted(v.keys())
if not options.writelocations:
pass
# location comments are different b/w Solaris and GNU:
elif options.locationstyle == options.SOLARIS:
for filename, lineno in v:
d = {'filename': filename, 'lineno': lineno}
print(_(
'# File: %(filename)s, line: %(lineno)d') % d, file=fp)
elif options.locationstyle == options.GNU:
# fit as many locations on one line, as long as the
# resulting line length doesn't exceed 'options.width'
locline = '#:'
for filename, lineno in v:
d = {'filename': filename, 'lineno': lineno}
s = _(' %(filename)s:%(lineno)d') % d
if len(locline) + len(s) <= options.width:
locline = locline + s
else:
print(locline, file=fp)
locline = "#:" + s
if len(locline) > 2:
print(locline, file=fp)
if isdocstring:
print('#, docstring', file=fp)
print('msgid', normalize(k, encoding), file=fp)
print('msgstr ""\n', file=fp)
def main():
global default_keywords
try:
opts, args = getopt.getopt(
sys.argv[1:],
'ad:DEhk:Kno:p:S:Vvw:x:X:',
['extract-all', 'default-domain=', 'escape', 'help',
'keyword=', 'no-default-keywords',
'add-location', 'no-location', 'output=', 'output-dir=',
'style=', 'verbose', 'version', 'width=', 'exclude-file=',
'docstrings', 'no-docstrings',
])
except getopt.error as msg:
usage(1, msg)
# for holding option values
class Options:
# constants
GNU = 1
SOLARIS = 2
# defaults
extractall = 0 # FIXME: currently this option has no effect at all.
escape = 0
keywords = []
outpath = ''
outfile = 'messages.pot'
writelocations = 1
locationstyle = GNU
verbose = 0
width = 78
excludefilename = ''
docstrings = 0
nodocstrings = {}
options = Options()
locations = {'gnu' : options.GNU,
'solaris' : options.SOLARIS,
}
# parse options
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-a', '--extract-all'):
options.extractall = 1
elif opt in ('-d', '--default-domain'):
options.outfile = arg + '.pot'
elif opt in ('-E', '--escape'):
options.escape = 1
elif opt in ('-D', '--docstrings'):
options.docstrings = 1
elif opt in ('-k', '--keyword'):
options.keywords.append(arg)
elif opt in ('-K', '--no-default-keywords'):
default_keywords = []
elif opt in ('-n', '--add-location'):
options.writelocations = 1
elif opt in ('--no-location',):
options.writelocations = 0
elif opt in ('-S', '--style'):
options.locationstyle = locations.get(arg.lower())
if options.locationstyle is None:
usage(1, _('Invalid value for --style: %s') % arg)
elif opt in ('-o', '--output'):
options.outfile = arg
elif opt in ('-p', '--output-dir'):
options.outpath = arg
elif opt in ('-v', '--verbose'):
options.verbose = 1
elif opt in ('-V', '--version'):
print(_('pygettext.py (xgettext for Python) %s') % __version__)
sys.exit(0)
elif opt in ('-w', '--width'):
try:
options.width = int(arg)
except ValueError:
usage(1, _('--width argument must be an integer: %s') % arg)
elif opt in ('-x', '--exclude-file'):
options.excludefilename = arg
elif opt in ('-X', '--no-docstrings'):
fp = open(arg)
try:
while 1:
line = fp.readline()
if not line:
break
options.nodocstrings[line[:-1]] = 1
finally:
fp.close()
# calculate escapes
make_escapes(not options.escape)
# calculate all keywords
options.keywords.extend(default_keywords)
# initialize list of strings to exclude
if options.excludefilename:
try:
fp = open(options.excludefilename)
options.toexclude = fp.readlines()
fp.close()
except IOError:
print(_(
"Can't read --exclude-file: %s") % options.excludefilename, file=sys.stderr)
sys.exit(1)
else:
options.toexclude = []
# resolve args to module lists
expanded = []
for arg in args:
if arg == '-':
expanded.append(arg)
else:
expanded.extend(getFilesForName(arg))
args = expanded
# slurp through all the files
eater = TokenEater(options)
for filename in args:
if filename == '-':
if options.verbose:
print(_('Reading standard input'))
fp = sys.stdin.buffer
closep = 0
else:
if options.verbose:
print(_('Working on %s') % filename)
fp = open(filename, 'rb')
closep = 1
try:
eater.set_filename(filename)
try:
tokens = tokenize.tokenize(fp.readline)
for _token in tokens:
eater(*_token)
except tokenize.TokenError as e:
print('%s: %s, line %d, column %d' % (
e.args[0], filename, e.args[1][0], e.args[1][1]),
file=sys.stderr)
finally:
if closep:
fp.close()
# write the output
if options.outfile == '-':
fp = sys.stdout
closep = 0
else:
if options.outpath:
options.outfile = os.path.join(options.outpath, options.outfile)
fp = open(options.outfile, 'w')
closep = 1
try:
eater.write(fp)
finally:
if closep:
fp.close()
if __name__ == '__main__':
main()
# some more test strings
# this one creates a warning
_('*** Seen unexpected token "%(token)s"') % {'token': 'test'}
_('more' 'than' 'one' 'string')

View file

@ -0,0 +1,6 @@
Importbench is a set of micro-benchmarks for various import scenarios.
It should not be used as an overall benchmark of import performance, but rather
an easy way to measure impact of possible code changes. For a real-world
benchmark of import, use the normal_startup benchmark from
https://github.com/python/performance

View file

@ -0,0 +1,244 @@
"""Benchmark some basic import use-cases.
The assumption is made that this benchmark is run in a fresh interpreter and
thus has no external changes made to import-related attributes in sys.
"""
from test.test_importlib import util
import decimal
import imp
import importlib
import importlib.machinery
import json
import os
import py_compile
import sys
import tabnanny
import timeit
def bench(name, cleanup=lambda: None, *, seconds=1, repeat=3):
"""Bench the given statement as many times as necessary until total
executions take one second."""
stmt = "__import__({!r})".format(name)
timer = timeit.Timer(stmt)
for x in range(repeat):
total_time = 0
count = 0
while total_time < seconds:
try:
total_time += timer.timeit(1)
finally:
cleanup()
count += 1
else:
# One execution too far
if total_time > seconds:
count -= 1
yield count // seconds
def from_cache(seconds, repeat):
"""sys.modules"""
name = '<benchmark import>'
module = imp.new_module(name)
module.__file__ = '<test>'
module.__package__ = ''
with util.uncache(name):
sys.modules[name] = module
yield from bench(name, repeat=repeat, seconds=seconds)
def builtin_mod(seconds, repeat):
"""Built-in module"""
name = 'errno'
if name in sys.modules:
del sys.modules[name]
# Relying on built-in importer being implicit.
yield from bench(name, lambda: sys.modules.pop(name), repeat=repeat,
seconds=seconds)
def source_wo_bytecode(seconds, repeat):
"""Source w/o bytecode: small"""
sys.dont_write_bytecode = True
try:
name = '__importlib_test_benchmark__'
# Clears out sys.modules and puts an entry at the front of sys.path.
with util.create_modules(name) as mapping:
assert not os.path.exists(imp.cache_from_source(mapping[name]))
sys.meta_path.append(importlib.machinery.PathFinder)
loader = (importlib.machinery.SourceFileLoader,
importlib.machinery.SOURCE_SUFFIXES)
sys.path_hooks.append(importlib.machinery.FileFinder.path_hook(loader))
yield from bench(name, lambda: sys.modules.pop(name), repeat=repeat,
seconds=seconds)
finally:
sys.dont_write_bytecode = False
def _wo_bytecode(module):
name = module.__name__
def benchmark_wo_bytecode(seconds, repeat):
"""Source w/o bytecode: {}"""
bytecode_path = imp.cache_from_source(module.__file__)
if os.path.exists(bytecode_path):
os.unlink(bytecode_path)
sys.dont_write_bytecode = True
try:
yield from bench(name, lambda: sys.modules.pop(name),
repeat=repeat, seconds=seconds)
finally:
sys.dont_write_bytecode = False
benchmark_wo_bytecode.__doc__ = benchmark_wo_bytecode.__doc__.format(name)
return benchmark_wo_bytecode
tabnanny_wo_bytecode = _wo_bytecode(tabnanny)
decimal_wo_bytecode = _wo_bytecode(decimal)
def source_writing_bytecode(seconds, repeat):
"""Source writing bytecode: small"""
assert not sys.dont_write_bytecode
name = '__importlib_test_benchmark__'
with util.create_modules(name) as mapping:
sys.meta_path.append(importlib.machinery.PathFinder)
loader = (importlib.machinery.SourceFileLoader,
importlib.machinery.SOURCE_SUFFIXES)
sys.path_hooks.append(importlib.machinery.FileFinder.path_hook(loader))
def cleanup():
sys.modules.pop(name)
os.unlink(imp.cache_from_source(mapping[name]))
for result in bench(name, cleanup, repeat=repeat, seconds=seconds):
assert not os.path.exists(imp.cache_from_source(mapping[name]))
yield result
def _writing_bytecode(module):
name = module.__name__
def writing_bytecode_benchmark(seconds, repeat):
"""Source writing bytecode: {}"""
assert not sys.dont_write_bytecode
def cleanup():
sys.modules.pop(name)
os.unlink(imp.cache_from_source(module.__file__))
yield from bench(name, cleanup, repeat=repeat, seconds=seconds)
writing_bytecode_benchmark.__doc__ = (
writing_bytecode_benchmark.__doc__.format(name))
return writing_bytecode_benchmark
tabnanny_writing_bytecode = _writing_bytecode(tabnanny)
decimal_writing_bytecode = _writing_bytecode(decimal)
def source_using_bytecode(seconds, repeat):
"""Source w/ bytecode: small"""
name = '__importlib_test_benchmark__'
with util.create_modules(name) as mapping:
sys.meta_path.append(importlib.machinery.PathFinder)
loader = (importlib.machinery.SourceFileLoader,
importlib.machinery.SOURCE_SUFFIXES)
sys.path_hooks.append(importlib.machinery.FileFinder.path_hook(loader))
py_compile.compile(mapping[name])
assert os.path.exists(imp.cache_from_source(mapping[name]))
yield from bench(name, lambda: sys.modules.pop(name), repeat=repeat,
seconds=seconds)
def _using_bytecode(module):
name = module.__name__
def using_bytecode_benchmark(seconds, repeat):
"""Source w/ bytecode: {}"""
py_compile.compile(module.__file__)
yield from bench(name, lambda: sys.modules.pop(name), repeat=repeat,
seconds=seconds)
using_bytecode_benchmark.__doc__ = (
using_bytecode_benchmark.__doc__.format(name))
return using_bytecode_benchmark
tabnanny_using_bytecode = _using_bytecode(tabnanny)
decimal_using_bytecode = _using_bytecode(decimal)
def main(import_, options):
if options.source_file:
with options.source_file:
prev_results = json.load(options.source_file)
else:
prev_results = {}
__builtins__.__import__ = import_
benchmarks = (from_cache, builtin_mod,
source_writing_bytecode,
source_wo_bytecode, source_using_bytecode,
tabnanny_writing_bytecode,
tabnanny_wo_bytecode, tabnanny_using_bytecode,
decimal_writing_bytecode,
decimal_wo_bytecode, decimal_using_bytecode,
)
if options.benchmark:
for b in benchmarks:
if b.__doc__ == options.benchmark:
benchmarks = [b]
break
else:
print('Unknown benchmark: {!r}'.format(options.benchmark,
file=sys.stderr))
sys.exit(1)
seconds = 1
seconds_plural = 's' if seconds > 1 else ''
repeat = 3
header = ('Measuring imports/second over {} second{}, best out of {}\n'
'Entire benchmark run should take about {} seconds\n'
'Using {!r} as __import__\n')
print(header.format(seconds, seconds_plural, repeat,
len(benchmarks) * seconds * repeat, __import__))
new_results = {}
for benchmark in benchmarks:
print(benchmark.__doc__, "[", end=' ')
sys.stdout.flush()
results = []
for result in benchmark(seconds=seconds, repeat=repeat):
results.append(result)
print(result, end=' ')
sys.stdout.flush()
assert not sys.dont_write_bytecode
print("]", "best is", format(max(results), ',d'))
new_results[benchmark.__doc__] = results
if prev_results:
print('\n\nComparing new vs. old\n')
for benchmark in benchmarks:
benchmark_name = benchmark.__doc__
old_result = max(prev_results[benchmark_name])
new_result = max(new_results[benchmark_name])
result = '{:,d} vs. {:,d} ({:%})'.format(new_result,
old_result,
new_result/old_result)
print(benchmark_name, ':', result)
if options.dest_file:
with options.dest_file:
json.dump(new_results, options.dest_file, indent=2)
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-b', '--builtin', dest='builtin', action='store_true',
default=False, help="use the built-in __import__")
parser.add_argument('-r', '--read', dest='source_file',
type=argparse.FileType('r'),
help='file to read benchmark data from to compare '
'against')
parser.add_argument('-w', '--write', dest='dest_file',
type=argparse.FileType('w'),
help='file to write benchmark data to')
parser.add_argument('--benchmark', dest='benchmark',
help='specific benchmark to run')
options = parser.parse_args()
import_ = __import__
if not options.builtin:
import_ = importlib.__import__
main(import_, options)

View file

@ -0,0 +1,556 @@
# -*- coding: utf-8 -*-
# This file should be kept compatible with both Python 2.6 and Python >= 3.0.
import itertools
import os
import platform
import re
import sys
import time
from optparse import OptionParser
out = sys.stdout
TEXT_ENCODING = 'utf8'
NEWLINES = 'lf'
# Compatibility
try:
xrange
except NameError:
xrange = range
def text_open(fn, mode, encoding=None):
try:
return open(fn, mode, encoding=encoding or TEXT_ENCODING)
except TypeError:
if 'r' in mode:
mode += 'U' # 'U' mode is needed only in Python 2.x
return open(fn, mode)
def get_file_sizes():
for s in ['20 KB', '400 KB', '10 MB']:
size, unit = s.split()
size = int(size) * {'KB': 1024, 'MB': 1024 ** 2}[unit]
yield s.replace(' ', ''), size
def get_binary_files():
return ((name + ".bin", size) for name, size in get_file_sizes())
def get_text_files():
return (("%s-%s-%s.txt" % (name, TEXT_ENCODING, NEWLINES), size)
for name, size in get_file_sizes())
def with_open_mode(mode):
def decorate(f):
f.file_open_mode = mode
return f
return decorate
def with_sizes(*sizes):
def decorate(f):
f.file_sizes = sizes
return f
return decorate
# Here begin the tests
@with_open_mode("r")
@with_sizes("medium")
def read_bytewise(f):
""" read one unit at a time """
f.seek(0)
while f.read(1):
pass
@with_open_mode("r")
@with_sizes("medium")
def read_small_chunks(f):
""" read 20 units at a time """
f.seek(0)
while f.read(20):
pass
@with_open_mode("r")
@with_sizes("medium")
def read_big_chunks(f):
""" read 4096 units at a time """
f.seek(0)
while f.read(4096):
pass
@with_open_mode("r")
@with_sizes("small", "medium", "large")
def read_whole_file(f):
""" read whole contents at once """
f.seek(0)
while f.read():
pass
@with_open_mode("rt")
@with_sizes("medium")
def read_lines(f):
""" read one line at a time """
f.seek(0)
for line in f:
pass
@with_open_mode("r")
@with_sizes("medium")
def seek_forward_bytewise(f):
""" seek forward one unit at a time """
f.seek(0, 2)
size = f.tell()
f.seek(0, 0)
for i in xrange(0, size - 1):
f.seek(i, 0)
@with_open_mode("r")
@with_sizes("medium")
def seek_forward_blockwise(f):
""" seek forward 1000 units at a time """
f.seek(0, 2)
size = f.tell()
f.seek(0, 0)
for i in xrange(0, size - 1, 1000):
f.seek(i, 0)
@with_open_mode("rb")
@with_sizes("medium")
def read_seek_bytewise(f):
""" alternate read & seek one unit """
f.seek(0)
while f.read(1):
f.seek(1, 1)
@with_open_mode("rb")
@with_sizes("medium")
def read_seek_blockwise(f):
""" alternate read & seek 1000 units """
f.seek(0)
while f.read(1000):
f.seek(1000, 1)
@with_open_mode("w")
@with_sizes("small")
def write_bytewise(f, source):
""" write one unit at a time """
for i in xrange(0, len(source)):
f.write(source[i:i+1])
@with_open_mode("w")
@with_sizes("medium")
def write_small_chunks(f, source):
""" write 20 units at a time """
for i in xrange(0, len(source), 20):
f.write(source[i:i+20])
@with_open_mode("w")
@with_sizes("medium")
def write_medium_chunks(f, source):
""" write 4096 units at a time """
for i in xrange(0, len(source), 4096):
f.write(source[i:i+4096])
@with_open_mode("w")
@with_sizes("large")
def write_large_chunks(f, source):
""" write 1e6 units at a time """
for i in xrange(0, len(source), 1000000):
f.write(source[i:i+1000000])
@with_open_mode("w+")
@with_sizes("small")
def modify_bytewise(f, source):
""" modify one unit at a time """
f.seek(0)
for i in xrange(0, len(source)):
f.write(source[i:i+1])
@with_open_mode("w+")
@with_sizes("medium")
def modify_small_chunks(f, source):
""" modify 20 units at a time """
f.seek(0)
for i in xrange(0, len(source), 20):
f.write(source[i:i+20])
@with_open_mode("w+")
@with_sizes("medium")
def modify_medium_chunks(f, source):
""" modify 4096 units at a time """
f.seek(0)
for i in xrange(0, len(source), 4096):
f.write(source[i:i+4096])
@with_open_mode("wb+")
@with_sizes("medium")
def modify_seek_forward_bytewise(f, source):
""" alternate write & seek one unit """
f.seek(0)
for i in xrange(0, len(source), 2):
f.write(source[i:i+1])
f.seek(i+2)
@with_open_mode("wb+")
@with_sizes("medium")
def modify_seek_forward_blockwise(f, source):
""" alternate write & seek 1000 units """
f.seek(0)
for i in xrange(0, len(source), 2000):
f.write(source[i:i+1000])
f.seek(i+2000)
# XXX the 2 following tests don't work with py3k's text IO
@with_open_mode("wb+")
@with_sizes("medium")
def read_modify_bytewise(f, source):
""" alternate read & write one unit """
f.seek(0)
for i in xrange(0, len(source), 2):
f.read(1)
f.write(source[i+1:i+2])
@with_open_mode("wb+")
@with_sizes("medium")
def read_modify_blockwise(f, source):
""" alternate read & write 1000 units """
f.seek(0)
for i in xrange(0, len(source), 2000):
f.read(1000)
f.write(source[i+1000:i+2000])
read_tests = [
read_bytewise, read_small_chunks, read_lines, read_big_chunks,
None, read_whole_file, None,
seek_forward_bytewise, seek_forward_blockwise,
read_seek_bytewise, read_seek_blockwise,
]
write_tests = [
write_bytewise, write_small_chunks, write_medium_chunks, write_large_chunks,
]
modify_tests = [
modify_bytewise, modify_small_chunks, modify_medium_chunks,
None,
modify_seek_forward_bytewise, modify_seek_forward_blockwise,
read_modify_bytewise, read_modify_blockwise,
]
def run_during(duration, func):
_t = time.time
n = 0
start = os.times()
start_timestamp = _t()
real_start = start[4] or start_timestamp
while True:
func()
n += 1
if _t() - start_timestamp > duration:
break
end = os.times()
real = (end[4] if start[4] else time.time()) - real_start
return n, real, sum(end[0:2]) - sum(start[0:2])
def warm_cache(filename):
with open(filename, "rb") as f:
f.read()
def run_all_tests(options):
def print_label(filename, func):
name = re.split(r'[-.]', filename)[0]
out.write(
("[%s] %s... "
% (name.center(7), func.__doc__.strip())
).ljust(52))
out.flush()
def print_results(size, n, real, cpu):
bw = n * float(size) / 1024 ** 2 / real
bw = ("%4d MB/s" if bw > 100 else "%.3g MB/s") % bw
out.write(bw.rjust(12) + "\n")
if cpu < 0.90 * real:
out.write(" warning: test above used only %d%% CPU, "
"result may be flawed!\n" % (100.0 * cpu / real))
def run_one_test(name, size, open_func, test_func, *args):
mode = test_func.file_open_mode
print_label(name, test_func)
if "w" not in mode or "+" in mode:
warm_cache(name)
with open_func(name) as f:
n, real, cpu = run_during(1.5, lambda: test_func(f, *args))
print_results(size, n, real, cpu)
def run_test_family(tests, mode_filter, files, open_func, *make_args):
for test_func in tests:
if test_func is None:
out.write("\n")
continue
if mode_filter in test_func.file_open_mode:
continue
for s in test_func.file_sizes:
name, size = files[size_names[s]]
#name += file_ext
args = tuple(f(name, size) for f in make_args)
run_one_test(name, size,
open_func, test_func, *args)
size_names = {
"small": 0,
"medium": 1,
"large": 2,
}
print("Python %s" % sys.version)
if sys.version_info < (3, 3):
if sys.maxunicode > 0xffff:
text = "UCS-4 (wide build)"
else:
text = "UTF-16 (narrow build)"
else:
text = "PEP 393"
print("Unicode: %s" % text)
print(platform.platform())
binary_files = list(get_binary_files())
text_files = list(get_text_files())
if "b" in options:
print("Binary unit = one byte")
if "t" in options:
print("Text unit = one character (%s-decoded)" % TEXT_ENCODING)
# Binary reads
if "b" in options and "r" in options:
print("\n** Binary input **\n")
run_test_family(read_tests, "t", binary_files, lambda fn: open(fn, "rb"))
# Text reads
if "t" in options and "r" in options:
print("\n** Text input **\n")
run_test_family(read_tests, "b", text_files, lambda fn: text_open(fn, "r"))
# Binary writes
if "b" in options and "w" in options:
print("\n** Binary append **\n")
def make_test_source(name, size):
with open(name, "rb") as f:
return f.read()
run_test_family(write_tests, "t", binary_files,
lambda fn: open(os.devnull, "wb"), make_test_source)
# Text writes
if "t" in options and "w" in options:
print("\n** Text append **\n")
def make_test_source(name, size):
with text_open(name, "r") as f:
return f.read()
run_test_family(write_tests, "b", text_files,
lambda fn: text_open(os.devnull, "w"), make_test_source)
# Binary overwrites
if "b" in options and "w" in options:
print("\n** Binary overwrite **\n")
def make_test_source(name, size):
with open(name, "rb") as f:
return f.read()
run_test_family(modify_tests, "t", binary_files,
lambda fn: open(fn, "r+b"), make_test_source)
# Text overwrites
if "t" in options and "w" in options:
print("\n** Text overwrite **\n")
def make_test_source(name, size):
with text_open(name, "r") as f:
return f.read()
run_test_family(modify_tests, "b", text_files,
lambda fn: text_open(fn, "r+"), make_test_source)
def prepare_files():
print("Preparing files...")
# Binary files
for name, size in get_binary_files():
if os.path.isfile(name) and os.path.getsize(name) == size:
continue
with open(name, "wb") as f:
f.write(os.urandom(size))
# Text files
chunk = []
with text_open(__file__, "r", encoding='utf8') as f:
for line in f:
if line.startswith("# <iobench text chunk marker>"):
break
else:
raise RuntimeError(
"Couldn't find chunk marker in %s !" % __file__)
if NEWLINES == "all":
it = itertools.cycle(["\n", "\r", "\r\n"])
else:
it = itertools.repeat(
{"cr": "\r", "lf": "\n", "crlf": "\r\n"}[NEWLINES])
chunk = "".join(line.replace("\n", next(it)) for line in f)
if isinstance(chunk, bytes):
chunk = chunk.decode('utf8')
chunk = chunk.encode(TEXT_ENCODING)
for name, size in get_text_files():
if os.path.isfile(name) and os.path.getsize(name) == size:
continue
head = chunk * (size // len(chunk))
tail = chunk[:size % len(chunk)]
# Adjust tail to end on a character boundary
while True:
try:
tail.decode(TEXT_ENCODING)
break
except UnicodeDecodeError:
tail = tail[:-1]
with open(name, "wb") as f:
f.write(head)
f.write(tail)
def main():
global TEXT_ENCODING, NEWLINES
usage = "usage: %prog [-h|--help] [options]"
parser = OptionParser(usage=usage)
parser.add_option("-b", "--binary",
action="store_true", dest="binary", default=False,
help="run binary I/O tests")
parser.add_option("-t", "--text",
action="store_true", dest="text", default=False,
help="run text I/O tests")
parser.add_option("-r", "--read",
action="store_true", dest="read", default=False,
help="run read tests")
parser.add_option("-w", "--write",
action="store_true", dest="write", default=False,
help="run write & modify tests")
parser.add_option("-E", "--encoding",
action="store", dest="encoding", default=None,
help="encoding for text tests (default: %s)" % TEXT_ENCODING)
parser.add_option("-N", "--newlines",
action="store", dest="newlines", default='lf',
help="line endings for text tests "
"(one of: {lf (default), cr, crlf, all})")
parser.add_option("-m", "--io-module",
action="store", dest="io_module", default=None,
help="io module to test (default: builtin open())")
options, args = parser.parse_args()
if args:
parser.error("unexpected arguments")
NEWLINES = options.newlines.lower()
if NEWLINES not in ('lf', 'cr', 'crlf', 'all'):
parser.error("invalid 'newlines' option: %r" % NEWLINES)
test_options = ""
if options.read:
test_options += "r"
if options.write:
test_options += "w"
elif not options.read:
test_options += "rw"
if options.text:
test_options += "t"
if options.binary:
test_options += "b"
elif not options.text:
test_options += "tb"
if options.encoding:
TEXT_ENCODING = options.encoding
if options.io_module:
globals()['open'] = __import__(options.io_module, {}, {}, ['open']).open
prepare_files()
run_all_tests(test_options)
if __name__ == "__main__":
main()
# -- This part to exercise text reading. Don't change anything! --
# <iobench text chunk marker>
"""
1.
Gáttir allar,
áðr gangi fram,
um skoðask skyli,
um skyggnast skyli,
því at óvíst er at vita,
hvar óvinir
sitja á fleti fyrir.
2.
Gefendr heilir!
Gestr er inn kominn,
hvar skal sitja sjá?
Mjök er bráðr,
er á bröndum skal
síns of freista frama.
3.
Elds er þörf,
þeims inn er kominn
ok á kné kalinn;
matar ok váða
er manni þörf,
þeim er hefr um fjall farit.
4.
Vatns er þörf,
þeim er til verðar kemr,
þerru ok þjóðlaðar,
góðs of æðis,
ef sér geta mætti,
orðs ok endrþögu.
5.
Vits er þörf,
þeim er víða ratar;
dælt er heima hvat;
at augabragði verðr,
er ekki kann
ok með snotrum sitr.
6.
At hyggjandi sinni
skyli-t maðr hræsinn vera,
heldr gætinn at geði;
þá er horskr ok þögull
kemr heimisgarða til,
sjaldan verðr víti vörum,
því at óbrigðra vin
fær maðr aldregi
en mannvit mikit.
7.
Inn vari gestr,
er til verðar kemr,
þunnu hljóði þegir,
eyrum hlýðir,
en augum skoðar;
svá nýsisk fróðra hverr fyrir.
8.
Hinn er sæll,
er sér of getr
lof ok líknstafi;
ódælla er við þat,
er maðr eiga skal
annars brjóstum í.
"""
"""
C'est revenir tard, je le sens, sur un sujet trop rebattu et déjà presque oublié. Mon état, qui ne me permet plus aucun travail suivi, mon aversion pour le genre polémique, ont causé ma lenteur à écrire et ma répugnance à publier. J'aurais même tout à fait supprimé ces Lettres, ou plutôt je lie les aurais point écrites, s'il n'eût été question que de moi : Mais ma patrie ne m'est pas tellement devenue étrangère que je puisse voir tranquillement opprimer ses citoyens, surtout lorsqu'ils n'ont compromis leurs droits qu'en défendant ma cause. Je serais le dernier des hommes si dans une telle occasion j'écoutais un sentiment qui n'est plus ni douceur ni patience, mais faiblesse et lâcheté, dans celui qu'il empêche de remplir son devoir.
Rien de moins important pour le public, j'en conviens, que la matière de ces lettres. La constitution d'une petite République, le sort d'un petit particulier, l'exposé de quelques injustices, la réfutation de quelques sophismes ; tout cela n'a rien en soi d'assez considérable pour mériter beaucoup de lecteurs : mais si mes sujets sont petits mes objets sont grands, et dignes de l'attention de tout honnête homme. Laissons Genève à sa place, et Rousseau dans sa dépression ; mais la religion, mais la liberté, la justice ! voilà, qui que vous soyez, ce qui n'est pas au-dessous de vous.
Qu'on ne cherche pas même ici dans le style le dédommagement de l'aridité de la matière. Ceux que quelques traits heureux de ma plume ont si fort irrités trouveront de quoi s'apaiser dans ces lettres, L'honneur de défendre un opprimé eût enflammé mon coeur si j'avais parlé pour un autre. Réduit au triste emploi de me défendre moi-même, j'ai me borner à raisonner ; m'échauffer eût été m'avilir. J'aurai donc trouvé grâce en ce point devant ceux qui s'imaginent qu'il est essentiel à la vérité d'être dite froidement ; opinion que pourtant j'ai peine à comprendre. Lorsqu'une vive persuasion nous anime, le moyen d'employer un langage glacé ? Quand Archimède tout transporté courait nu dans les rues de Syracuse, en avait-il moins trouvé la vérité parce qu'il se passionnait pour elle ? Tout au contraire, celui qui la sent ne peut s'abstenir de l'adorer ; celui qui demeure froid ne l'a pas vue.
Quoi qu'il en soit, je prie les lecteurs de vouloir bien mettre à part mon beau style, et d'examiner seulement si je raisonne bien ou mal ; car enfin, de cela seul qu'un auteur s'exprime en bons termes, je ne vois pas comment il peut s'ensuivre que cet auteur ne sait ce qu'il dit.
"""

543
third_party/python/Tools/msi/README.txt vendored Normal file
View file

@ -0,0 +1,543 @@
Quick Build Info
================
For testing, the installer should be built with the Tools/msi/build.bat
script:
build.bat [-x86] [-x64] [--doc]
For an official release, the installer should be built with the
Tools/msi/buildrelease.bat script and environment variables:
set PYTHON=<path to Python 2.7 or 3.4>
set SPHINXBUILD=<path to sphinx-build.exe>
set PATH=<path to Mercurial (hg.exe)>;
<path to HTML Help Compiler (hhc.exe)>;%PATH%
buildrelease.bat [-x86] [-x64] [-D] [-B]
[-o <output directory>] [-c <certificate name>]
See the Building the Installer section for more information.
Overview
========
Python is distributed on Windows as an installer that will configure the
user's system. This allows users to have a functioning copy of Python
without having to build it themselves.
The main tasks of the installer are:
* copy required files into the expected layout
* configure system settings so the installation can be located by
other programs
* add entry points for modifying, repairing and uninstalling Python
* make it easy to launch Python, its documentation, and IDLE
Each of these is discussed in a later section of this document.
Structure of the Installer
==========================
The installer is structured as a 'layout', which consists of a number of
CAB and MSI files and a single EXE.
The EXE is the main entry point into the installer. It contains the UI
and command-line logic, as well as the ability to locate and optionally
download other parts of the layout.
Each MSI contains the logic required to install a component or feature
of Python. These MSIs should not be launched directly by users. MSIs can
be embedded into the EXE or automatically downloaded as needed.
Each CAB contains the files making up a Python installation. CABs are
embedded into their associated MSI and are never seen by users.
MSIs are only required when the related feature or component is being
installed. When components are not selected for installation, the
associated MSI is not downloaded. This allows the installer to offer
options to install debugging symbols and binaries without increasing
the initial download size by separating them into their own MSIs.
Building the Installer
======================
Before building the installer, download extra build dependencies using
Tools\msi\get_externals.bat. (Note that this is in addition to the
similarly named file in PCBuild.)
One of the dependencies used in builds is WiX, a toolset that lets developers
create installers for Windows Installer, the Windows installation engine. WiX
has a dependency on the Microsoft .NET Framework Version 3.5 (which may not be
configured on recent versions of Windows, such as Windows 10). If you are
building on a recent Windows version, use the Control Panel (Programs | Programs
and Features | Turn Windows Features on or off) and ensure that the entry
".NET Framework 3.5 (includes .NET 2.0 and 3.0)" is enabled.
For testing, the installer should be built with the Tools/msi/build.bat
script:
build.bat [-x86] [-x64] [--doc] [--test-marker] [--pack]
This script will build the required configurations of Python and
generate an installer layout in PCBuild/(win32|amd64)/en-us.
Specify -x86 and/or -x64 to build for each platform. If neither is
specified, both platforms will be built. Currently, both the debug and
release versions of Python are required for the installer.
Specify --doc to build the documentation (.chm) file. If the file is not
available, it will simply be excluded from the installer. Ensure
%PYTHON% and %SPHINXBUILD% are set when passing this option. You may
also set %HTMLHELP% to the Html Help Compiler (hhc.exe), or put HHC on
your PATH or in externals/.
Specify --test-marker to build an installer that works side-by-side with
an official Python release. All registry keys and install locations will
include an extra marker to avoid overwriting files. This marker is
currently an 'x' prefix, but may change at any time.
Specify --pack to build an installer that does not require all MSIs to
be available alongside. This takes longer, but is easier to share.
For an official release, the installer should be built with the
Tools/msi/buildrelease.bat script:
set PYTHON=<path to Python 2.7 or 3.4>
set SPHINXBUILD=<path to sphinx-build.exe>
set PATH=<path to Mercurial (hg.exe)>;
<path to HTML Help Compiler (hhc.exe)>;%PATH%
buildrelease.bat [-x86] [-x64] [-D] [-B]
[-o <output directory>] [-c <certificate name>]
Specify -x86 and/or -x64 to build for each platform. If neither is
specified, both platforms will be built. Currently, both the debug and
release versions of Python are required for the installer.
Specify -D to skip rebuilding the documentation. The documentation is
required for a release and the build will fail if it is not available.
Specify -B to skip rebuilding Python. This is useful to only rebuild the
installer layout after a previous call to buildrelease.bat.
Specify -o to set an output directory. The installer layouts will be
copied to platform-specific subdirectories of this path.
Specify -c to choose a code-signing certificate to be used for all the
signable binaries in Python as well as each file making up the
installer. Official releases of Python must be signed.
Ensure %PYTHON% and %SPHINXBUILD% are set when passing this option. You
may also set %HTMLHELP% to the Html Help Compiler (hhc.exe), or put HHC
on your PATH or in externals/. You will also need Mercurial (hg.exe) on
your PATH.
If WiX is not found on your system, it will be automatically downloaded
and extracted to the externals/ directory.
To manually build layouts of the installer, build one of the projects in
the bundle folder.
msbuild bundle\snapshot.wixproj
msbuild bundle\releaseweb.wixproj
msbuild bundle\releaselocal.wixproj
msbuild bundle\full.wixproj
snapshot.wixproj produces a test installer versioned based on the date.
releaseweb.wixproj produces a release installer that does not embed any
of the layout.
releaselocal.wixproj produces a release installer that embeds the files
required for a default installation.
full.wixproj produces a test installer that embeds the entire layout.
The following properties may be passed when building these projects.
/p:BuildForRelease=(true|false)
When true, adds extra verification to ensure a complete installer is
produced. For example, binutils is required when building for a release
to generate MinGW-compatible libraries, and the build will be aborted if
this fails. Defaults to false.
/p:ReleaseUri=(any URI)
Used to generate unique IDs for the installers to allow side-by-side
installation. Forks of Python can use the same installer infrastructure
by providing a unique URI for this property. It does not need to be an
active internet address. Defaults to $(ComputerName).
Official releases use http://www.python.org/(architecture name)
/p:DownloadUrlBase=(any URI)
Specifies the base of a URL where missing parts of the installer layout
can be downloaded from. The build version and architecture will be
appended to create the full address. If omitted, missing components will
not be automatically downloaded.
/p:DownloadUrl=(any URI)
Specifies the full URL where missing parts of the installer layout can
be downloaded from. Should normally include '{2}', which will be
substituted for the filename. If omitted, missing components will not be
automatically downloaded. If specified, this value overrides
DownloadUrlBase.
/p:SigningCertificate=(certificate name)
Specifies the certificate to sign the installer layout with. If omitted,
the layout will not be signed.
/p:RebuildAll=(true|false)
When true, rebuilds all of the MSIs making up the layout. Defaults to
true.
Uploading the Installer
=======================
For official releases, the uploadrelease.bat script should be used.
You will require PuTTY so that plink.exe and pscp.exe can be used, and your
SSH key can be activated in pageant.exe. PuTTY should be either on your path
or in %ProgramFiles(x86)%\PuTTY.
To include signatures for each uploaded file, you will need gpg2.exe on your
path or have run get_externals.bat. You may also need to "gpg2.exe --import"
your key before running the upload script.
uploadrelease.bat --host <host> --user <username> [--dry-run] [--no-gpg]
The host is the URL to the server. This can be provided by the Release
Manager. You should be able to SSH to this address.
The username is your own username, which you have permission to SSH into
the server containing downloads.
Use --dry-run to display the generated upload commands without executing
them. Signatures for each file will be generated but not uploaded unless
--no-gpg is also passed.
Use --no-gpg to suppress signature generation and upload.
The default target directory (which appears in uploadrelease.proj) is
correct for official Python releases, but may be overridden with
--target <path> for other purposes. This path should generally not include
any version specifier, as that will be added automatically.
Modifying the Installer
=======================
The code for the installer is divided into three main groups: packages,
the bundle and the bootstrap application.
Packages
--------
Packages appear as subdirectories of Tools/msi (other than the bundle/
directory). The project file is a .wixproj and the build output is a
single MSI. Packages are built with the WiX Toolset. Some project files
share source files and use preprocessor directives to enable particular
features. These are typically used to keep the sources close when the
files are related, but produce multiple independent packages.
A package is the smallest element that may be independently installed or
uninstalled (as used in this installer). For example, the test suite has
its own package, as users can choose to add or remove it after the
initial installation.
All the files installed by a single package should be related, though
some packages may not install any files. For example, the pip package
executes the ensurepip package, but does not add or remove any of its
own files. (It is represented as a package because of its
installed/uninstalled nature, as opposed to the "precompile standard
library" option, for example.) Dependencies between packages are handled
by the bundle, but packages should detect when dependencies are missing
and raise an error.
Packages that include a lot of files may use an InstallFiles element in
the .wixproj file to generate sources. See lib/lib.wixproj for an
example, and msi.targets and csv_to_wxs.py for the implementation. This
element is also responsible for generating the code for cleaning up and
removing __pycache__ folders in any directory containing .py files.
All packages are built with the Tools/msi/common.wxs file, and so any
directory or property in this file may be referenced. Of particular
interest:
REGISTRYKEY (property)
The registry key for the current installation.
InstallDirectory (directory)
The root install directory for the current installation. Subdirectories
are also specified in this file (DLLs, Lib, etc.)
MenuDir (directory)
The Start Menu folder for the current installation.
UpgradeTable (property)
Every package should reference this property to include upgrade
information.
OptionalFeature (Component)
Packages that may be enabled or disabled should reference this component
and have an OPTIONAL_FEATURES entry in the bootstrap application to
properly handle Modify and Upgrade.
The .wxl_template file is specially handled by the build system for this
project to perform {{substitutions}} as defined in msi.targets. They
should be included in projects as <WxlTemplate> items, where .wxl files
are normally included as <EmbeddedResource> items.
Bundle
------
The bundle is compiled to the main EXE entry point that for most users
will represent the Python installer. It is built from Tools/msi/bundle
with packages references in Tools/msi/bundle/packagegroups.
Build logic for the bundle is in bundle.targets, but should be invoked
through one of the .wixproj files as described in Building the
Installer.
The UI is separated between Default.thm (UI layout), Default.wxl
(strings), bundle.wxs (properties) and the bootstrap application.
Bundle.wxs also contains the chain, which is the list of packages to
install and the order they should be installed in. These refer to named
package groups in bundle/packagegroups.
Each package group specifies one or more packages to install. Most
packages require two separate entries to support both per-user and
all-users installations. Because these reuse the same package, it does
not increase the overall size of the package.
Package groups refer to payload groups, which allow better control over
embedding and downloading files than the default settings. Whether files
are embedded and where they are downloaded from depends on settings
created by the project files.
Package references can include install conditions that determine when to
install the package. When a package is a dependency for others, the
condition should be crafted to ensure it is installed.
MSI packages are installed or uninstalled based on their current state
and the install condition. This makes them most suitable for features
that are clearly present or absent from the user's machine.
EXE packages are executed based on a customisable condition that can be
omitted. This makes them suitable for pre- or post-install tasks that
need to run regardless of whether features have been added or removed.
Bootstrap Application
---------------------
The bootstrap application is a C++ application that controls the UI and
installation. While it does not directly compile into the main EXE of
the installer, it forms the main active component. Most of the
installation functionality is provided by WiX, and so the bootstrap
application is predominantly responsible for the code behind the UI that
is defined in the Default.thm file. The bootstrap application code is in
bundle/bootstrap and is built automatically when building the bundle.
Installation Layout
===================
There are two installation layouts for Python on Windows, with the only
differences being supporting files. A layout is selected implicitly
based on whether the install is for all users of the machine or just for
the user performing the installation.
The default installation location when installing for all users is
"%ProgramFiles%\Python3X" for the 64-bit interpreter and
"%ProgramFiles(x86)%\Python3X-32" for the 32-bit interpreter. (Note that
the latter path is equivalent to "%ProgramFiles%\Python3X-32" when
running a 32-bit version of Windows.) This location requires
administrative privileges to install or later modify the installation.
The default installation location when installing for the current user
is "%LocalAppData%\Programs\Python\Python3X" for the 64-bit interpreter
and "%LocalAppData%\Programs\Python\Python3X-32" for the 32-bit
interpreter. Only the current user can access this location. This
provides a suitable level of protection against malicious modification
of Python's files.
(Default installation locations are set in Tools\msi\bundle\bundle.wxs.)
Within this install directory is the following approximate layout:
.\python[w].exe The core executable files
.\DLLs Stdlib extensions (*.pyd) and dependencies
.\Doc Documentation (*.chm)
.\include Development headers (*.h)
.\Lib Standard library
.\Lib\test Test suite
.\libs Development libraries (*.lib)
.\Scripts Launcher scripts (*.exe, *.py)
.\tcl Tcl dependencies (*.dll, *.tcl and others)
.\Tools Tool scripts (*.py)
When installed for all users, the following files are installed to
either "%SystemRoot%\System32" or "%SystemRoot%\SysWOW64" as
appropriate. For the current user, they are installed in the Python
install directory.
.\python3x.dll The core interpreter
.\python3.dll The stable ABI reference
When installed for all users, the following files are installed to
"%SystemRoot%" (typically "C:\Windows") to ensure they are always
available on PATH. (See Launching Python below.) For the current user,
they are installed in "%LocalAppData%\Programs\Python\PyLauncher".
.\py[w].exe PEP 397 launcher
System Settings
===============
On installation, registry keys are created so that other applications
can locate and identify installations of Python. The locations of these
keys vary based on the install type.
For 64-bit interpreters installed for all users, the root key is:
HKEY_LOCAL_MACHINE\Software\Python\PythonCore\3.X
For 32-bit interpreters installed for all users on a 64-bit operating
system, the root key is:
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Python\PythonCore\3.X-32
For 32-bit interpreters installed for all users on a 32-bit operating
system, the root key is:
HKEY_LOCAL_MACHINE\Software\Python\PythonCore\3.X-32
For 64-bit interpreters installed for the current user:
HKEY_CURRENT_USER\Software\Python\PythonCore\3.X
For 32-bit interpreters installed for the current user:
HKEY_CURRENT_USER\Software\Python\PythonCore\3.X-32
When the core Python executables are installed, a key "InstallPath" is
created within the root key with its default value set to the
executable's install directory. A value named "ExecutablePath" is added
with the full path to the main Python interpreter, and a key
"InstallGroup" is created with its default value set to the product
name "Python 3.X".
When the Python standard library is installed, a key "PythonPath" is
created within the root key with its default value set to the full path
to the Lib folder followed by the path to the DLLs folder, separated by
a semicolon.
When the documentation is installed, a key "Help" is created within the
root key, with a subkey "Main Python Documentation" with its default
value set to the full path to the installed CHM file.
The py.exe launcher is installed as part of a regular Python install,
but using a separate mechanism that allows it to more easily span
versions of Python. As a result, it has different root keys for its
registry entries:
When installed for all users on a 64-bit operating system, the
launcher's root key is:
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Python\Launcher
When installed for all users on a 32-bit operating system, the
launcher's root key is:
HKEY_LOCAL_MACHINE\Software\Python\Launcher
When installed for the current user:
HKEY_CURRENT_USER\Software\Python\Launcher
When the launcher is installed, a key "InstallPath" is created within
its root key with its default value set to the launcher's install
directory. File associations are also created for .py, .pyw, .pyc and
.pyo files.
Launching Python
================
When a feature offering user entry points in the Start Menu is
installed, a folder "Python 3.X" is created. Every shortcut should be
created within this folder, and each shortcut should include the version
and platform to allow users to identify the shortcut in a search results
page.
The core Python executables creates a shortcut "Python 3.X (32-bit)" or
"Python 3.X (64-bit)" depending on the interpreter.
The documentation creates a shortcut "Python 3.X 32-bit Manuals" or
"Python 3.X 64-bit Manuals". The documentation is identical for all
platforms, but the shortcuts need to be separate to avoid uninstallation
conflicts.
Installing IDLE creates a shortcut "IDLE (Python 3.X 32-bit)" or "IDLE
(Python 3.X 64-bit)" depending on the interpreter.
For users who often launch Python from a Command Prompt, an option is
provided to add the directory containing python.exe to the user or
system PATH variable. If the option is selected, the install directory
and the Scripts directory will be added at the start of the system PATH
for an all users install and the user PATH for a per-user install.
When the user only has one version of Python installed, this will behave
as expected. However, because Windows searches the system PATH before
the user PATH, users cannot override a system-wide installation of
Python on their PATH. Further, because the installer can only prepend to
the path, later installations of Python will take precedence over
earlier installations, regardless of interpreter version.
Because it is not possible to automatically create a sensible PATH
configuration, users are recommended to use the py.exe launcher and
manually modify their PATH variable to add Scripts directories in their
preferred order. System-wide installations of Python should consider not
modifying PATH, or using an alternative technology to modify their
users' PATH variables.
The py.exe launcher is recommended because it uses a consistent and
sensible search order for Python installations. User installations are
preferred over system-wide installs, and later versions are preferred
regardless of installation order (with the exception that py.exe
currently prefers 2.x versions over 3.x versions without the -3 command
line argument).
For both 32-bit and 64-bit interpreters, the 32-bit version of the
launcher is installed. This ensures that the search order is always
consistent (as the 64-bit launcher is subtly different from the 32-bit
launcher) and also avoids the need to install it multiple times. Future
versions of Python will upgrade the launcher in-place, using Windows
Installer's upgrade functionality to avoid conflicts with earlier
installed versions.
When installed, file associations are created for .py, .pyc and .pyo
files to launch with py.exe and .pyw files to launch with pyw.exe. This
makes Python files respect shebang lines by default and also avoids
conflicts between multiple Python installations.
Repair, Modify and Uninstall
============================
After installation, Python may be modified, repaired or uninstalled by
running the original EXE again or via the Programs and Features applet
(formerly known as Add or Remove Programs).
Modifications allow features to be added or removed. The install
directory and kind (all users/single user) cannot be modified. Because
Windows Installer caches installation packages, removing features will
not require internet access unless the package cache has been corrupted
or deleted. Adding features that were not previously installed and are
not embedded or otherwise available will require internet access.
Repairing will rerun the installation for all currently installed
features, restoring files and registry keys that have been modified or
removed. This operation generally will not redownload any files unless
the cached packages have been corrupted or deleted.
Removing Python will clean up all the files and registry keys that were
created by the installer, as well as __pycache__ folders that are
explicitly handled by the installer. Python packages installed later
using a tool like pip will not be removed. Some components may be
installed by other installers and these will not be removed if another
product has a dependency on them.

79
third_party/python/Tools/msi/build.bat vendored Normal file
View file

@ -0,0 +1,79 @@
@echo off
setlocal
set D=%~dp0
set PCBUILD=%D%..\..\PCBuild\
set BUILDX86=
set BUILDX64=
set BUILDDOC=
set BUILDTEST=--test-marker
set BUILDPACK=
set REBUILD=
:CheckOpts
if "%~1" EQU "-h" goto Help
if "%~1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts
if "%~1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts
if "%~1" EQU "--doc" (set BUILDDOC=1) && shift && goto CheckOpts
if "%~1" EQU "--no-test-marker" (set BUILDTEST=) && shift && goto CheckOpts
if "%~1" EQU "--pack" (set BUILDPACK=1) && shift && goto CheckOpts
if "%~1" EQU "-r" (set REBUILD=-r) && shift && goto CheckOpts
if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1)
call "%D%get_externals.bat"
call "%PCBUILD%find_msbuild.bat" %MSBUILD%
if ERRORLEVEL 1 (echo Cannot locate MSBuild.exe on PATH or as MSBUILD variable & exit /b 2)
if defined BUILDX86 (
call "%PCBUILD%build.bat" -d -e %REBUILD% %BUILDTEST%
if errorlevel 1 goto :eof
call "%PCBUILD%build.bat" -e %REBUILD% %BUILDTEST%
if errorlevel 1 goto :eof
)
if defined BUILDX64 (
call "%PCBUILD%build.bat" -p x64 -d -e %REBUILD% %BUILDTEST%
if errorlevel 1 goto :eof
call "%PCBUILD%build.bat" -p x64 -e %REBUILD% %BUILDTEST%
if errorlevel 1 goto :eof
)
if defined BUILDDOC (
call "%PCBUILD%..\Doc\make.bat" htmlhelp
if errorlevel 1 goto :eof
)
rem Build the launcher MSI separately
%MSBUILD% "%D%launcher\launcher.wixproj" /p:Platform=x86
set BUILD_CMD="%D%bundle\snapshot.wixproj"
if defined BUILDTEST (
set BUILD_CMD=%BUILD_CMD% /p:UseTestMarker=true
)
if defined BUILDPACK (
set BUILD_CMD=%BUILD_CMD% /p:Pack=true
)
if defined REBUILD (
set BUILD_CMD=%BUILD_CMD% /t:Rebuild
)
if defined BUILDX86 (
%MSBUILD% %BUILD_CMD%
if errorlevel 1 goto :eof
)
if defined BUILDX64 (
%MSBUILD% /p:Platform=x64 %BUILD_CMD%
if errorlevel 1 goto :eof
)
exit /B 0
:Help
echo build.bat [-x86] [-x64] [--doc] [-h] [--no-test-marker] [--pack] [-r]
echo.
echo -x86 Build x86 installers
echo -x64 Build x64 installers
echo --doc Build CHM documentation
echo --no-test-marker Build without test markers
echo --pack Embed core MSIs into installer
echo -r Rebuild rather than incremental build

View file

@ -0,0 +1,234 @@
@setlocal
@echo off
rem This script is intended for building official releases of Python.
rem To use it to build alternative releases, you should clone this file
rem and modify the following three URIs.
rem These two will ensure that your release can be installed
rem alongside an official Python release, by modifying the GUIDs used
rem for all components.
rem
rem The following substitutions will be applied to the release URI:
rem Variable Description Example
rem {arch} architecture amd64, win32
set RELEASE_URI=http://www.python.org/{arch}
rem This is the URL that will be used to download installation files.
rem The files available from the default URL *will* conflict with your
rem installer. Trust me, you don't want them, even if it seems like a
rem good idea.
rem
rem The following substitutions will be applied to the download URL:
rem Variable Description Example
rem {version} version number 3.5.0
rem {arch} architecture amd64, win32
rem {releasename} release name a1, b2, rc3 (or blank for final)
rem {msi} MSI filename core.msi
set DOWNLOAD_URL=https://www.python.org/ftp/python/{version}/{arch}{releasename}/{msi}
set D=%~dp0
set PCBUILD=%D%..\..\PCBuild\
if "%Py_OutDir%"=="" set Py_OutDir=%PCBUILD%
set EXTERNALS=%D%..\..\externals\windows-installer\
set BUILDX86=
set BUILDX64=
set TARGET=Rebuild
set TESTTARGETDIR=
set PGO=-m test -q --pgo
set BUILDNUGET=1
set BUILDZIP=1
:CheckOpts
if "%1" EQU "-h" goto Help
if "%1" EQU "-c" (set CERTNAME=%~2) && shift && shift && goto CheckOpts
if "%1" EQU "--certificate" (set CERTNAME=%~2) && shift && shift && goto CheckOpts
if "%1" EQU "-o" (set OUTDIR=%~2) && shift && shift && goto CheckOpts
if "%1" EQU "--out" (set OUTDIR=%~2) && shift && shift && goto CheckOpts
if "%1" EQU "-D" (set SKIPDOC=1) && shift && goto CheckOpts
if "%1" EQU "--skip-doc" (set SKIPDOC=1) && shift && goto CheckOpts
if "%1" EQU "-B" (set SKIPBUILD=1) && shift && goto CheckOpts
if "%1" EQU "--skip-build" (set SKIPBUILD=1) && shift && goto CheckOpts
if "%1" EQU "--download" (set DOWNLOAD_URL=%~2) && shift && shift && goto CheckOpts
if "%1" EQU "--test" (set TESTTARGETDIR=%~2) && shift && shift && goto CheckOpts
if "%1" EQU "-b" (set TARGET=Build) && shift && goto CheckOpts
if "%1" EQU "--build" (set TARGET=Build) && shift && goto CheckOpts
if "%1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts
if "%1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts
if "%1" EQU "--pgo" (set PGO=%~2) && shift && shift && goto CheckOpts
if "%1" EQU "--skip-pgo" (set PGO=) && shift && goto CheckOpts
if "%1" EQU "--skip-nuget" (set BUILDNUGET=) && shift && goto CheckOpts
if "%1" EQU "--skip-zip" (set BUILDZIP=) && shift && goto CheckOpts
if "%1" NEQ "" echo Invalid option: "%1" && exit /B 1
if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1)
if not exist "%GIT%" where git > "%TEMP%\git.loc" 2> nul && set /P GIT= < "%TEMP%\git.loc" & del "%TEMP%\git.loc"
if not exist "%GIT%" echo Cannot find Git on PATH && exit /B 1
call "%D%get_externals.bat"
call "%PCBUILD%find_msbuild.bat" %MSBUILD%
if ERRORLEVEL 1 (echo Cannot locate MSBuild.exe on PATH or as MSBUILD variable & exit /b 2)
:builddoc
if "%SKIPBUILD%" EQU "1" goto skipdoc
if "%SKIPDOC%" EQU "1" goto skipdoc
call "%D%..\..\doc\make.bat" htmlhelp
if errorlevel 1 goto :eof
:skipdoc
where dlltool /q && goto skipdlltoolsearch
set _DLLTOOL_PATH=
where /R "%EXTERNALS%\" dlltool > "%TEMP%\dlltool.loc" 2> nul && set /P _DLLTOOL_PATH= < "%TEMP%\dlltool.loc" & del "%TEMP%\dlltool.loc"
if not exist "%_DLLTOOL_PATH%" echo Cannot find binutils on PATH or in external && exit /B 1
for %%f in (%_DLLTOOL_PATH%) do set PATH=%PATH%;%%~dpf
set _DLLTOOL_PATH=
:skipdlltoolsearch
if defined BUILDX86 (
call :build x86
if errorlevel 1 exit /B
)
if defined BUILDX64 (
call :build x64 "%PGO%"
if errorlevel 1 exit /B
)
if defined TESTTARGETDIR (
call "%D%testrelease.bat" -t "%TESTTARGETDIR%"
)
exit /B 0
:build
@setlocal
@echo off
if "%1" EQU "x86" (
set PGO=
set BUILD=%Py_OutDir%win32\
set BUILD_PLAT=Win32
set OUTDIR_PLAT=win32
set OBJDIR_PLAT=x86
) else (
set BUILD=%Py_OutDir%amd64\
set PGO=%~2
set BUILD_PLAT=x64
set OUTDIR_PLAT=amd64
set OBJDIR_PLAT=x64
)
if exist "%BUILD%en-us" (
echo Deleting %BUILD%en-us
rmdir /q/s "%BUILD%en-us"
if errorlevel 1 exit /B
)
if exist "%D%obj\Debug_%OBJDIR_PLAT%" (
echo Deleting "%D%obj\Debug_%OBJDIR_PLAT%"
rmdir /q/s "%D%obj\Debug_%OBJDIR_PLAT%"
if errorlevel 1 exit /B
)
if exist "%D%obj\Release_%OBJDIR_PLAT%" (
echo Deleting "%D%obj\Release_%OBJDIR_PLAT%"
rmdir /q/s "%D%obj\Release_%OBJDIR_PLAT%"
if errorlevel 1 exit /B
)
if not "%CERTNAME%" EQU "" (
set CERTOPTS="/p:SigningCertificate=%CERTNAME%"
) else (
set CERTOPTS=
)
if not "%PGO%" EQU "" (
set PGOOPTS=--pgo-job "%PGO%"
) else (
set PGOOPTS=
)
if not "%SKIPBUILD%" EQU "1" (
@echo call "%PCBUILD%build.bat" -e -p %BUILD_PLAT% -t %TARGET% %PGOOPTS% %CERTOPTS%
@call "%PCBUILD%build.bat" -e -p %BUILD_PLAT% -t %TARGET% %PGOOPTS% %CERTOPTS%
@if errorlevel 1 exit /B
@rem build.bat turns echo back on, so we disable it again
@echo off
@echo call "%PCBUILD%build.bat" -d -e -p %BUILD_PLAT% -t %TARGET%
@call "%PCBUILD%build.bat" -d -e -p %BUILD_PLAT% -t %TARGET%
@if errorlevel 1 exit /B
@rem build.bat turns echo back on, so we disable it again
@echo off
)
if "%OUTDIR_PLAT%" EQU "win32" (
%MSBUILD% "%D%launcher\launcher.wixproj" /p:Platform=x86 %CERTOPTS% /p:ReleaseUri=%RELEASE_URI%
if errorlevel 1 exit /B
) else if not exist "%Py_OutDir%win32\en-us\launcher.msi" (
%MSBUILD% "%D%launcher\launcher.wixproj" /p:Platform=x86 %CERTOPTS% /p:ReleaseUri=%RELEASE_URI%
if errorlevel 1 exit /B
)
set BUILDOPTS=/p:Platform=%1 /p:BuildForRelease=true /p:DownloadUrl=%DOWNLOAD_URL% /p:DownloadUrlBase=%DOWNLOAD_URL_BASE% /p:ReleaseUri=%RELEASE_URI%
%MSBUILD% "%D%bundle\releaselocal.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=true
if errorlevel 1 exit /B
%MSBUILD% "%D%bundle\releaseweb.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=false
if errorlevel 1 exit /B
if defined BUILDZIP (
%MSBUILD% "%D%make_zip.proj" /t:Build %BUILDOPTS% %CERTOPTS% /p:OutputPath="%BUILD%en-us"
if errorlevel 1 exit /B
)
if defined BUILDNUGET (
%MSBUILD% "%D%..\nuget\make_pkg.proj" /t:Build /p:Configuration=Release /p:Platform=%1 /p:OutputPath="%BUILD%en-us"
if errorlevel 1 exit /B
)
if not "%OUTDIR%" EQU "" (
mkdir "%OUTDIR%\%OUTDIR_PLAT%"
mkdir "%OUTDIR%\%OUTDIR_PLAT%\binaries"
mkdir "%OUTDIR%\%OUTDIR_PLAT%\symbols"
robocopy "%BUILD%en-us" "%OUTDIR%\%OUTDIR_PLAT%" /XF "*.wixpdb"
robocopy "%BUILD%\" "%OUTDIR%\%OUTDIR_PLAT%\binaries" *.exe *.dll *.pyd /XF "_test*" /XF "*_d.*" /XF "_freeze*" /XF "tcl*" /XF "tk*" /XF "*_test.*"
robocopy "%BUILD%\" "%OUTDIR%\%OUTDIR_PLAT%\symbols" *.pdb /XF "_test*" /XF "*_d.*" /XF "_freeze*" /XF "tcl*" /XF "tk*" /XF "*_test.*"
)
exit /B 0
:Help
echo buildrelease.bat [--out DIR] [-x86] [-x64] [--certificate CERTNAME] [--build] [--pgo COMMAND]
echo [--skip-build] [--skip-doc] [--skip-nuget] [--skip-zip] [--skip-pgo]
echo [--download DOWNLOAD URL] [--test TARGETDIR]
echo [-h]
echo.
echo --out (-o) Specify an additional output directory for installers
echo -x86 Build x86 installers
echo -x64 Build x64 installers
echo --build (-b) Incrementally build Python rather than rebuilding
echo --skip-build (-B) Do not build Python (just do the installers)
echo --skip-doc (-D) Do not build documentation
echo --pgo Specify PGO command for x64 installers
echo --skip-pgo Build x64 installers without using PGO
echo --skip-nuget Do not build Nuget packages
echo --skip-zip Do not build embeddable package
echo --download Specify the full download URL for MSIs
echo --test Specify the test directory to run the installer tests
echo -h Display this help information
echo.
echo If no architecture is specified, all architectures will be built.
echo If --test is not specified, the installer tests are not run.
echo.
echo For the --pgo option, any Python command line can be used, or 'default' to
echo use the default task (-m test --pgo).
echo.
echo The following substitutions will be applied to the download URL:
echo Variable Description Example
echo {version} version number 3.5.0
echo {arch} architecture amd64, win32
echo {releasename} release name a1, b2, rc3 (or blank for final)
echo {msi} MSI filename core.msi

View file

@ -0,0 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<Theme xmlns="http://wixtoolset.org/schemas/thmutil/2010">
<Window Width="670" Height="412" HexStyle="100a0000" FontId="0">#(loc.Caption)</Window>
<Font Id="0" Height="-14" Weight="500" Foreground="000000" Background="ffffff">Segoe UI</Font>
<Font Id="1" Height="-26" Weight="500" Foreground="000000" Background="ffffff">Segoe UI</Font>
<Font Id="2" Height="-24" Weight="500" Foreground="808080" Background="ffffff">Segoe UI</Font>
<Font Id="3" Height="-14" Weight="500" Foreground="000000" Background="ffffff">Segoe UI</Font>
<Font Id="4" Height="-14" Weight="500" Foreground="ff0000" Background="ffffff" Underline="yes">Segoe UI</Font>
<Font Id="5" Height="-14" Weight="500" Foreground="808080" Background="ffffff">Segoe UI</Font>
<Page Name="Help">
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.HelpHeader)</Text>
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
<Hypertext X="185" Y="50" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Hypertext>
<Button Name="SuccessCancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CloseButton)</Button>
</Page>
<Page Name="Install">
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.InstallHeader)</Text>
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
<Text X="185" Y="50" Width="-11" Height="50" FontId="3" TabStop="yes">#(loc.InstallMessage)</Text>
<Button Name="InstallButton" X="185" Y="101" Width="-11" Height="109" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallButton)</Button>
<Button Name="InstallCustomButton" X="185" Y="221" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallCustomButton)</Button>
<Checkbox Name="InstallLauncherAllUsers" X="185" Y="-37" Width="-100" Height="24" TabStop="yes" FontId="3">#(loc.ShortInstallLauncherAllUsersLabel)</Checkbox>
<Checkbox Name="PrependPath" X="185" Y="-13" Width="-100" Height="24" TabStop="yes" FontId="3">#(loc.ShortPrependPathLabel)</Checkbox>
<Button Name="InstallCancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
</Page>
<Page Name="Upgrade">
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.InstallUpgradeHeader)</Text>
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
<Text X="185" Y="50" Width="-11" Height="50" FontId="3" TabStop="yes">#(loc.InstallUpgradeMessage)</Text>
<Button Name="InstallUpgradeButton" X="185" Y="101" Width="-11" Height="129" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallUpgradeButton)</Button>
<Button Name="InstallUpgradeCustomButton" X="185" Y="241" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallUpgradeCustomButton)</Button>
<Button Name="InstallCancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
</Page>
<Page Name="SimpleInstall">
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.InstallHeader)</Text>
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
<Button Name="InstallSimpleButton" X="185" Y="101" Width="-11" Height="129" TabStop="yes" FontId="3" HideWhenDisabled="yes" HexStyle="0xF">#(loc.InstallSimpleButton)</Button>
<Button Name="InstallCancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
</Page>
<Page Name="Custom1">
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.Custom1Header)</Text>
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
<Checkbox Name="Include_doc" X="185" Y="51" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.Include_docLabel)</Checkbox>
<Text X="205" Y="76" Width="-11" Height="24" TabStop="no" FontId="5">#(loc.Include_docHelpLabel)</Text>
<Checkbox Name="Include_pip" X="185" Y="101" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.Include_pipLabel)</Checkbox>
<Text X="205" Y="126" Width="-11" Height="24" TabStop="no" FontId="5">#(loc.Include_pipHelpLabel)</Text>
<Checkbox Name="Include_tcltk" X="185" Y="151" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.Include_tcltkLabel)</Checkbox>
<Text X="205" Y="176" Width="-11" Height="24" TabStop="no" FontId="5">#(loc.Include_tcltkHelpLabel)</Text>
<Checkbox Name="Include_test" X="185" Y="201" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.Include_testLabel)</Checkbox>
<Text X="205" Y="226" Width="-11" Height="24" TabStop="no" FontId="5">#(loc.Include_testHelpLabel)</Text>
<Checkbox Name="Include_launcher" X="185" Y="251" Width="100" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.Include_launcherLabel)</Checkbox>
<Checkbox Name="CustomInstallLauncherAllUsers" X="285" Y="251" Width="-11" Height="24" TabStop="yes" FontId="3">#(loc.InstallLauncherAllUsersLabel)</Checkbox>
<Text Name="Include_launcherHelp" X="205" Y="276" Width="-11" Height="24" TabStop="no" FontId="5"></Text>
<Button Name="Custom1BackButton" X="185" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CustomBackButton)</Button>
<Button Name="CustomNextButton" X="-101" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CustomNextButton)</Button>
<Button Name="Custom1CancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
</Page>
<Page Name="Custom2">
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.Custom2Header)</Text>
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
<Checkbox Name="InstallAllUsers" X="185" Y="51" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.InstallAllUsersLabel)</Checkbox>
<Checkbox Name="AssociateFiles" X="185" Y="76" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.AssociateFilesLabel)</Checkbox>
<Checkbox Name="Shortcuts" X="185" Y="101" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.ShortcutsLabel)</Checkbox>
<Checkbox Name="PrependPath" X="185" Y="126" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.PrependPathLabel)</Checkbox>
<Checkbox Name="CompileAll" X="185" Y="151" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.PrecompileLabel)</Checkbox>
<Checkbox Name="Include_symbols" X="185" Y="176" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.Include_symbolsLabel)</Checkbox>
<Checkbox Name="Include_debug" X="185" Y="201" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.Include_debugLabel)</Checkbox>
<Text X="185" Y="256" Width="-11" Height="17" FontId="3">#(loc.CustomLocationLabel)</Text>
<Editbox Name="TargetDir" X="185" Y="277" Width="-101" Height="27" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />
<Button Name="CustomBrowseButton" X="-11" Y="276" Width="85" Height="27" TabStop="yes" FontId="3">#(loc.CustomBrowseButton)</Button>
<Text Name="CustomBrowseButtonLabel" X="185" Y="306" Width="-91" Height="35" FontId="5" HideWhenDisabled="yes">#(loc.CustomLocationHelpLabel)</Text>
<Button Name="Custom2BackButton" X="185" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CustomBackButton)</Button>
<Button Name="CustomInstallButton" X="-101" Y="-11" Width="95" Height="27" TabStop="yes" FontId="0">#(loc.CustomInstallButton)</Button>
<Button Name="Custom2CancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
</Page>
<Page Name="Progress">
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.ProgressHeader)</Text>
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
<Text X="185" Y="111" Width="-11" Height="20" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Text>
<Text Name="OverallProgressPackageText" X="185" Y="146" Width="-11" Height="20" FontId="3" DisablePrefix="yes">#(loc.OverallProgressPackageText)</Text>
<Progressbar Name="OverallCalculatedProgressbar" X="185" Y="171" Width="-11" Height="24" />
<Button Name="ProgressCancelButton" X="-11" Y="-11" Width="95" Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
</Page>
<Page Name="Modify">
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.ModifyHeader)</Text>
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
<Button Name="ModifyButton" X="185" Y="101" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xF">#(loc.ModifyModifyButton)</Button>
<Button Name="RepairButton" X="185" Y="171" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.ModifyRepairButton)</Button>
<Button Name="UninstallButton" X="185" Y="241" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.ModifyUninstallButton)</Button>
<Button Name="ModifyCancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
</Page>
<Page Name="Success">
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.SuccessHeader)</Text>
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
<Hypertext Name="SuccessText" X="205" Y="71" Width="-71" Height="150" FontId="3" DisablePrefix="yes"></Hypertext>
<Button Name="SuccessMaxPathButton" X="185" Y="-70" Width="-11" Height="81" TabStop="yes" FontId="3" HexStyle="0xE" HideWhenDisabled="yes">#(loc.SuccessMaxPathButton)</Button>
<Text Name="SuccessRestartText" X="205" Y="-40" Width="-11" Height="34" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.SuccessRestartText)</Text>
<Button Name="SuccessRestartButton" X="-101" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessRestartButton)</Button>
<Button Name="SuccessCancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CloseButton)</Button>
</Page>
<Page Name="Failure">
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.FailureHeader)</Text>
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
<Hypertext Name="FailureLogFileLink" X="205" Y="71" Width="-11" Height="60" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
<Hypertext Name="FailureMessageText" X="205" Y="151" Width="-11" Height="120" FontId="3" TabStop="yes" HideWhenDisabled="yes"></Hypertext>
<Text Name="FailureRestartText" X="205" Y="-40" Width="-11" Height="34" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureRestartText)</Text>
<Button Name="FailureRestartButton" X="-101" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
<Button Name="FailureCancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CloseButton)</Button>
</Page>
</Theme>

View file

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" Language="1033" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="Caption">[WixBundleName] Setup</String>
<String Id="Title">[WixBundleName]</String>
<String Id="Installing">Installing</String>
<String Id="Installation">Setup</String>
<String Id="Modifying">Updating</String>
<String Id="Modification">Modify</String>
<String Id="Repairing">Repairing</String>
<String Id="Repair">Repair</String>
<String Id="Uninstalling">Removing</String>
<String Id="Uninstallation">Uninstall</String>
<String Id="ElevateForCRTInstall">You will be prompted for Administrator privileges to install a C Runtime Library update (KB2999226).
Continue?</String>
<String Id="CancelButton">&amp;Cancel</String>
<String Id="CloseButton">&amp;Close</String>
<String Id="InstallHeader">Install [WixBundleName]</String>
<String Id="InstallMessage">Select Install Now to install Python with default settings, or choose Customize to enable or disable features.</String>
<String Id="InstallVersion">Version [WixBundleVersion]</String>
<String Id="InstallUpgradeHeader">Upgrade to [WixBundleName]</String>
<String Id="InstallUpgradeMessage">Select Upgrade Now to keep your current settings, or choose Customize to enable or disable features.</String>
<String Id="ConfirmCancelMessage">Are you sure you want to cancel?</String>
<String Id="ExecuteUpgradeRelatedBundleMessage">Previous version</String>
<String Id="HelpHeader">Setup Help</String>
<String Id="HelpText">Visit &lt;a href="http://docs.python.org/[ShortVersion]/using/windows.html"&gt;docs.python.org/[ShortVersion]/using/windows.html&lt;/a&gt; for the full list of options, including the ability to enable and disable specific features.
"/passive" to display progress without requiring user interaction
"/quiet" to install/uninstall without displaying any UI
"/simple" to prevent user customization
"/uninstall" to remove Python (without confirmation)
"/layout [\[]directory[\]]" to pre-download all components
"/log [\[]filename[\]]" to specify log files location</String>
<String Id="InstallLicenseLinkText">[WixBundleName] &lt;a href="#"&gt;license terms&lt;/a&gt;.</String>
<String Id="InstallAcceptCheckbox">I &amp;agree to the license terms and conditions</String>
<String Id="InstallButton">&amp;Install Now</String>
<String Id="InstallButtonNote">[TargetDir]
Includes IDLE, pip and documentation
Creates shortcuts and file associations</String>
<String Id="InstallCustomButton">C&amp;ustomize installation</String>
<String Id="InstallCustomButtonNote">Choose location and features</String>
<String Id="InstallSimpleButton">&amp;Install</String>
<String Id="InstallSimpleButtonNote">Use settings preselected by your administrator
[SimpleInstallDescription]</String>
<String Id="InstallUpgradeButton">Up&amp;grade Now</String>
<String Id="InstallUpgradeButtonNote">[TargetDir]
Replaces your existing installation without changing settings.
Select Customize to review current options.</String>
<String Id="InstallUpgradeCustomButton">C&amp;ustomize installation</String>
<String Id="InstallUpgradeCustomButtonNote">Choose location and features</String>
<String Id="Custom1Header">Optional Features</String>
<String Id="Custom2Header">Advanced Options</String>
<String Id="CustomLocationLabel">Customize install location</String>
<String Id="CustomLocationHelpLabel">You will require write permissions for the selected location.</String>
<String Id="CustomInstallButton">&amp;Install</String>
<String Id="CustomNextButton">&amp;Next</String>
<String Id="CustomBackButton">&amp;Back</String>
<String Id="CustomBrowseButton">B&amp;rowse</String>
<String Id="Include_docLabel">&amp;Documentation</String>
<String Id="Include_docHelpLabel">Installs the Python documentation file.</String>
<String Id="Include_pipLabel">&amp;pip</String>
<String Id="Include_pipHelpLabel">Installs pip, which can download and install other Python packages.</String>
<String Id="Include_tcltkLabel">tcl/tk and &amp;IDLE</String>
<String Id="Include_tcltkHelpLabel">Installs tkinter and the IDLE development environment.</String>
<String Id="Include_testLabel">Python &amp;test suite</String>
<String Id="Include_testHelpLabel">Installs the standard library test suite.</String>
<String Id="Include_launcherLabel">py &amp;launcher</String>
<String Id="Include_launcherHelp">Installs the global 'py' launcher to make it easier to start Python.</String>
<String Id="Include_launcherRemove">Use Programs and Features to remove the 'py' launcher.</String>
<String Id="Include_launcherUpgrade">Upgrades the global 'py' launcher from the previous version.</String>
<String Id="AssociateFilesLabel">Associate &amp;files with Python (requires the py launcher)</String>
<String Id="ShortcutsLabel">Create shortcuts for installed applications</String>
<String Id="PrependPathLabel">Add Python to &amp;environment variables</String>
<String Id="ShortPrependPathLabel">Add &amp;Python [ShortVersion] to PATH</String>
<String Id="InstallAllUsersLabel">Install for &amp;all users</String>
<String Id="InstallLauncherAllUsersLabel">for &amp;all users (requires elevation)</String>
<String Id="ShortInstallLauncherAllUsersLabel">Install &amp;launcher for all users (recommended)</String>
<String Id="PrecompileLabel">&amp;Precompile standard library</String>
<String Id="Include_symbolsLabel">Download debugging &amp;symbols</String>
<String Id="Include_debugLabel">Download debu&amp;g binaries (requires VS 2015 or later)</String>
<String Id="ProgressHeader">[ActionLikeInstallation] Progress</String>
<String Id="ProgressLabel">[ActionLikeInstalling]:</String>
<String Id="OverallProgressPackageText">Initializing...</String>
<String Id="ModifyHeader">Modify Setup</String>
<String Id="ModifyModifyButton">&amp;Modify</String>
<String Id="ModifyButtonNote">Add or remove individual features.</String>
<String Id="ModifyRepairButton">&amp;Repair</String>
<String Id="RepairButtonNote">Ensure all current features are correctly installed.</String>
<String Id="ModifyUninstallButton">&amp;Uninstall</String>
<String Id="UninstallButtonNote">Remove the entire [WixBundleName] installation.</String>
<String Id="SuccessHeader">[ActionLikeInstallation] was successful</String>
<String Id="SuccessLaunchButton">&amp;Launch</String>
<String Id="SuccessRestartText">You may need to restart your computer to finish updating files.</String>
<String Id="SuccessRestartButton">&amp;Restart</String>
<String Id="SuccessInstallMessage">Special thanks to Mark Hammond, without whose years of freely shared Windows expertise, Python for Windows would still be Python for DOS.
New to Python? Start with the &lt;a href="https://docs.python.org/[ShortVersion]/tutorial/index.html"&gt;online tutorial&lt;/a&gt; and &lt;a href="https://docs.python.org/[ShortVersion]/index.html"&gt;documentation&lt;/a&gt;.
See &lt;a href="https://docs.python.org/[ShortVersion]/whatsnew/[ShortVersion].html"&gt;what's new&lt;/a&gt; in this release.</String>
<String Id="SuccessModifyMessage">Thank you for using [WixBundleName].</String>
<String Id="SuccessRepairMessage">Thank you for using [WixBundleName].
Feel free to email &lt;a href="mailto:python-list@python.org"&gt;python-list@python.org&lt;/a&gt; if you continue to encounter issues.</String>
<String Id="SuccessRemoveMessage">Thank you for using [WixBundleName].
Feel free to email &lt;a href="mailto:python-list@python.org"&gt;python-list@python.org&lt;/a&gt; if you encountered problems.</String>
<String Id="FailureHeader">Setup failed</String>
<String Id="FailureHyperlinkLogText">One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the &lt;a href="#"&gt;log file&lt;/a&gt;.</String>
<String Id="FailureRestartText">You must restart your computer to complete the rollback of the software.</String>
<String Id="FailureRestartButton">&amp;Restart</String>
<String Id="FailureExistingInstall">Unable to install [WixBundleName] due to an existing install. Use Programs and Features to modify, repair or remove [WixBundleName].</String>
<String Id="FailureWin7MissingSP1">Windows 7 Service Pack 1 and all applicable updates are required to install [WixBundleName].
Please &lt;a href="https://www.bing.com/search?q=how%20to%20install%20windows%207%20service%20pack%201"&gt;update your machine&lt;/a&gt; and then restart the installation.</String>
<String Id="FailureVistaMissingSP2">Windows Vista Service Pack 2 and all applicable updates are required to install [WixBundleName].
Please &lt;a href="https://www.bing.com/search?q=how%20to%20install%20windows%20vista%20service%20pack%202"&gt;update your machine&lt;/a&gt; and then restart the installation.</String>
<String Id="FailureXPOrEarlier">Windows Vista or later is required to install and use [WixBundleName].
Visit &lt;a href="https://www.python.org/"&gt;python.org&lt;/a&gt; to download Python 3.4.</String>
<String Id="FailureWS2K8R2MissingSP1">Windows Server 2008 R2 Service Pack 1 and all applicable updates are required to install [WixBundleName].
Please &lt;a href="https://www.bing.com/search?q=how%20to%20install%20windows%20server%202008%20r2%20service%20pack%201"&gt;update your machine&lt;/a&gt; and then restart the installation.</String>
<String Id="FailureWS2K8MissingSP2">Windows Server 2008 Service Pack 2 and all applicable updates are required to install [WixBundleName].
Please &lt;a href="https://www.bing.com/search?q=how%20to%20install%20windows%20server%202008%20service%20pack%202"&gt;update your machine&lt;/a&gt; and then restart the installation.</String>
<String Id="FailureWS2K3OrEarlier">Windows Server 2008 SP2 or later is required to install and use [WixBundleName].
Visit &lt;a href="https://www.python.org/"&gt;python.org&lt;/a&gt; to download Python 3.4.</String>
<String Id="SuccessMaxPathButton">Disable path length limit</String>
<String Id="SuccessMaxPathButtonNote">Changes your machine configuration to allow programs, including Python, to bypass the 260 character "MAX_PATH" limitation.</String>
</WixLocalization>

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View file

@ -0,0 +1,25 @@
This license applies to the bootstrapper application that is embedded within the installer. It has no impact on the licensing for the rest of the installer or Python itself, as no code covered by this license exists in any other part of the product.
---
Microsoft Reciprocal License (MS-RL)
This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.
1. Definitions
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.
A "contribution" is the original software, or any additions or changes to the software.
A "contributor" is any person that distributes its contribution under this license.
"Licensed patents" are a contributor's patent claims that read directly on its contribution.
2. Grant of Rights
(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
3. Conditions and Limitations
(A) Reciprocal Grants- For any file you distribute that contains code from the software (in source code or binary format), you must provide recipients the source code to that file along with a copy of this license, which license will govern that file. You may license other files that are entirely your own work and do not contain code from the software under any terms you choose.
(B) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
(C) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
(D) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
(E) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
(F) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
#include "pch.h"

View file

@ -0,0 +1,60 @@
//-------------------------------------------------------------------------------------------------
// <copyright file="precomp.h" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
//
// <summary>
// Precompiled header for standard bootstrapper application.
// </summary>
//-------------------------------------------------------------------------------------------------
#pragma once
#include <windows.h>
#include <gdiplus.h>
#include <Uxtheme.h>
#include <msiquery.h>
#include <objbase.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <stdlib.h>
#include <strsafe.h>
#include <stddef.h>
#include <versionhelpers.h>
#include "dutil.h"
#include "memutil.h"
#include "dictutil.h"
#include "dirutil.h"
#include "fileutil.h"
#include "locutil.h"
#include "logutil.h"
#include "pathutil.h"
#include "resrutil.h"
#include "shelutil.h"
#include "strutil.h"
#include "thmutil.h"
#include "uriutil.h"
#include "xmlutil.h"
#include "IBootstrapperEngine.h"
#include "IBootstrapperApplication.h"
#include "BalBaseBootstrapperApplication.h"
#include "balinfo.h"
#include "balcondition.h"
HRESULT CreateBootstrapperApplication(
__in HMODULE hModule,
__in BOOL fPrereq,
__in HRESULT hrHostInitialization,
__in IBootstrapperEngine* pEngine,
__in const BOOTSTRAPPER_COMMAND* pCommand,
__out IBootstrapperApplication** ppApplication
);
#include "IBootstrapperBAFunction.h"

View file

@ -0,0 +1,76 @@
//-------------------------------------------------------------------------------------------------
// <copyright file="wixstdba.cpp" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
//
// <summary>
// Setup chainer/bootstrapper standard UI for WiX toolset.
// </summary>
//-------------------------------------------------------------------------------------------------
#include "pch.h"
static HINSTANCE vhInstance = NULL;
extern "C" BOOL WINAPI DllMain(
IN HINSTANCE hInstance,
IN DWORD dwReason,
IN LPVOID /* pvReserved */
)
{
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
::DisableThreadLibraryCalls(hInstance);
vhInstance = hInstance;
break;
case DLL_PROCESS_DETACH:
vhInstance = NULL;
break;
}
return TRUE;
}
extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
__in IBootstrapperEngine* pEngine,
__in const BOOTSTRAPPER_COMMAND* pCommand,
__out IBootstrapperApplication** ppApplication
)
{
HRESULT hr = S_OK;
BalInitialize(pEngine);
hr = CreateBootstrapperApplication(vhInstance, FALSE, S_OK, pEngine, pCommand, ppApplication);
BalExitOnFailure(hr, "Failed to create bootstrapper application interface.");
LExit:
return hr;
}
extern "C" void WINAPI BootstrapperApplicationDestroy()
{
BalUninitialize();
}
extern "C" HRESULT WINAPI MbaPrereqBootstrapperApplicationCreate(
__in HRESULT hrHostInitialization,
__in IBootstrapperEngine* pEngine,
__in const BOOTSTRAPPER_COMMAND* pCommand,
__out IBootstrapperApplication** ppApplication
)
{
return E_NOTIMPL;
}
extern "C" void WINAPI MbaPrereqBootstrapperApplicationDestroy()
{ }

View file

@ -0,0 +1,18 @@
;-------------------------------------------------------------------------------------------------
; <copyright file="wixstdba.def" company="Outercurve Foundation">
; Copyright (c) 2004, Outercurve Foundation.
; This software is released under Microsoft Reciprocal License (MS-RL).
; The license and further copyright text can be found in the file
; LICENSE.TXT at the root directory of the distribution.
; </copyright>
;
; <summary>
; WiX Standard Bootstrapper Application DLL entry points.
; </summary>
;-------------------------------------------------------------------------------------------------
EXPORTS
BootstrapperApplicationCreate
BootstrapperApplicationDestroy
MbaPrereqBootstrapperApplicationCreate
MbaPrereqBootstrapperApplicationDestroy

View file

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30501.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pythonba", "pythonba.vcxproj", "{7A09B132-B3EE-499B-A700-A4B2157FEA3D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7A09B132-B3EE-499B-A700-A4B2157FEA3D}.Debug|Win32.ActiveCfg = Debug|Win32
{7A09B132-B3EE-499B-A700-A4B2157FEA3D}.Debug|Win32.Build.0 = Debug|Win32
{7A09B132-B3EE-499B-A700-A4B2157FEA3D}.Release|Win32.ActiveCfg = Release|Win32
{7A09B132-B3EE-499B-A700-A4B2157FEA3D}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<copyright file="wixstdba.vcxproj" company="Outercurve Foundation">
Copyright (c) 2004, Outercurve Foundation.
This software is released under Microsoft Reciprocal License (MS-RL).
The license and further copyright text can be found in the file
LICENSE.TXT at the root directory of the distribution.
</copyright>
-->
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<Configuration Condition="'$(Configuration)' == ''">Release</Configuration>
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
<PlatformToolset Condition="'$(PlatformToolset)' == '' and '$(VCTargetsPath14)' != ''">v140</PlatformToolset>
<PlatformToolset Condition="'$(PlatformToolset)' == '' and '$(VCTargetsPath12)' != ''">v120</PlatformToolset>
<ProjectGuid>{7A09B132-B3EE-499B-A700-A4B2157FEA3D}</ProjectGuid>
<TargetName>PythonBA</TargetName>
</PropertyGroup>
<Import Project="..\..\wix.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<Py_IntDir Condition="'$(Py_IntDir)' == ''">$(PySourcePath)PCbuild\obj\</Py_IntDir>
<IntDir>$(Py_IntDir)\$(MajorVersionNumber)$(MinorVersionNumber)$(ArchName)_$(Configuration)\msi_$(ProjectName)\</IntDir>
<IntDir>$(IntDir.Replace(`\\`, `\`))</IntDir>
<OutDir>$(IntDir)</OutDir>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>_CRT_STDIO_LEGACY_WIDE_SPECIFIERS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(WixInstallPath)sdk\inc</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<AdditionalDependencies>comctl32.lib;gdiplus.lib;msimg32.lib;shlwapi.lib;wininet.lib;dutil.lib;balutil.lib;version.lib;uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories Condition="'$(PlatformToolset)' == 'v140'">$(WixInstallPath)sdk\vs2015\lib\x86</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories Condition="'$(PlatformToolset)' == 'v120'">$(WixInstallPath)sdk\vs2013\lib\x86</AdditionalLibraryDirectories>
<ModuleDefinitionFile>pythonba.def</ModuleDefinitionFile>
<GenerateDebugInformation Condition="'$(Configuration)'=='Debug'">true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="PythonBootstrapperApplication.cpp" />
<ClCompile Include="pythonba.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<None Include="pythonba.def" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View file

@ -0,0 +1,25 @@
//-------------------------------------------------------------------------------------------------
// <copyright file="resource.h" company="Outercurve Foundation">
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file
// LICENSE.TXT at the root directory of the distribution.
// </copyright>
//-------------------------------------------------------------------------------------------------
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
//
#define IDC_STATIC -1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1003
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View file

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" TreatAsLocalProperty="DownloadUrl">
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<OutputType>Bundle</OutputType>
<BootstrapConfiguration Condition="'$(BootstrapConfiguration)' == ''">Release</BootstrapConfiguration>
<LinkerSuppressSpecificWarnings>1132;1135;1140</LinkerSuppressSpecificWarnings>
<OutputName Condition="$(BuildForRelease)">$(OutputName)-$(PythonVersion)</OutputName>
<OutputName Condition="!$(BuildForRelease)">$(OutputName)-$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber).$(RevisionNumber)</OutputName>
<OutputName Condition="$(Platform) == 'x64'">$(OutputName)-amd64</OutputName>
<OutputName Condition="'$(OutputSuffix)' != ''">$(OutputName)-$(OutputSuffix)</OutputName>
<OutputName Condition="'$(Configuration)' == 'Debug'">$(OutputName)-d</OutputName>
<TargetName>$(OutputName)</TargetName>
<OutputPath>$(OutputPath)en-us\</OutputPath>
<OutDir>$(OutputPath)</OutDir>
<!-- See Tools/msi/buildrelease.bat for help on configuring the download URL -->
<DownloadUrl Condition="'$(DownloadUrl)' == '' and '$(DownloadUrlBase)' != ''">$(DownloadUrlBase.TrimEnd(`/`))/{version}/{arch}{releasename}/{msi}</DownloadUrl>
<DefineConstants Condition="'$(DownloadUrl)' != ''">$(DefineConstants);DownloadUrl=$(DownloadUrl.Replace(`{version}`, `$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)`).Replace(`{arch}`, `$(ArchName)`).Replace(`{releasename}`, `$(ReleaseLevelName)`).Replace(`{msi}`, `{2}`))</DefineConstants>
<DefineConstants Condition="'$(DownloadUrl)' == ''">$(DefineConstants);DownloadUrl={2}</DefineConstants>
</PropertyGroup>
<ItemGroup>
<WixExtension Include="WixUtilExtension">
<HintPath>WixUtilExtension</HintPath>
<Name>WixUtilExtension</Name>
</WixExtension>
<WixExtension Include="WixDependencyExtension">
<HintPath>WixDependencyExtension</HintPath>
<Name>WixDependencyExtension</Name>
</WixExtension>
<WixExtension Include="WixBalExtension">
<HintPath>WixBalExtension</HintPath>
<Name>WixBalExtension</Name>
</WixExtension>
</ItemGroup>
<ItemGroup>
<Compile Include="bundle.wxs" />
<Compile Include="packagegroups\*.wxs" />
</ItemGroup>
<ItemGroup>
<Content Include="Default.thm" />
<Content Include="Default.wxl" />
<Content Include="SideBar.png" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="bundle.wxl" />
<WxlTemplate Include="*_en-US.wxl_template" />
</ItemGroup>
<ItemGroup>
<LinkerBindInputPaths Include="$(OutputPath)">
<BindName></BindName>
</LinkerBindInputPaths>
</ItemGroup>
<ItemDefinitionGroup>
<Package>
<Properties>BuildForRelease=$(BuildForRelease)</Properties>
</Package>
</ItemDefinitionGroup>
<ItemGroup>
<Package Include="..\core\core*.wixproj" />
<Package Include="..\dev\dev*.wixproj" />
<Package Include="..\doc\doc*.wixproj" />
<Package Include="..\exe\exe*.wixproj" />
<Package Include="..\lib\lib*.wixproj" />
<Package Include="..\path\path*.wixproj" />
<Package Include="..\pip\pip*.wixproj" />
<Package Include="..\tcltk\tcltk*.wixproj" />
<Package Include="..\test\test*.wixproj" />
<Package Include="..\tools\tools*.wixproj" />
</ItemGroup>
<PropertyGroup>
<BuildPackagesTargets>Build</BuildPackagesTargets>
</PropertyGroup>
<Target Name="_SetRebuildTarget" BeforeTargets="BeforeRebuild">
<PropertyGroup>
<BuildPackagesTargets>Rebuild</BuildPackagesTargets>
</PropertyGroup>
</Target>
<Target Name="BuildPackages" BeforeTargets="BeforeBuild" Condition="'$(RebuildAll)' != 'false'">
<MSBuild Projects="@(Package)" Targets="$(BuildPackagesTargets)" BuildInParallel="true" />
</Target>
<Target Name="BuildBootstrapApplication" BeforeTargets="BeforeBuild">
<Message Text="Building bootstrap app" Importance="high" />
<MSBuild Projects="bootstrap\pythonba.vcxproj"
Targets="Build;GetNativeTargetPath"
UseResultsCache="true"
Properties="Configuration=$(BootstrapConfiguration);Platform=Win32">
<Output TaskParameter="TargetOutputs" PropertyName="BootstrapAppPath" />
</MSBuild>
<PropertyGroup>
<DefineConstants>$(DefineConstants);BootstrapApp=$(BootstrapAppPath)</DefineConstants>
</PropertyGroup>
</Target>
<Import Project="..\msi.targets" />
</Project>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="CRTDescription">C Runtime Update (KB2999226)</String>
<String Id="CompileAllDescription">Precompiling standard library</String>
<String Id="CompileAllODescription">Precompiling standard library (-O)</String>
<String Id="CompileAllOODescription">Precompiling standard library (-OO)</String>
</WixLocalization>

View file

@ -0,0 +1,112 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension"
xmlns:dep="http://schemas.microsoft.com/wix/DependencyExtension">
<Bundle Name="!(loc.FullProductName)"
UpgradeCode="$(var.CoreUpgradeCode)"
Version="$(var.Version)"
IconSourceFile="..\..\..\PC\icons\setup.ico"
Manufacturer="!(loc.Manufacturer)"
AboutUrl="http://www.python.org/"
Compressed="no"
dep:ProviderKey="CPython-$(var.MajorVersionNumber).$(var.MinorVersionNumber)$(var.PyArchExt)$(var.PyTestExt)">
<BootstrapperApplication Id="PythonBA" SourceFile="$(var.BootstrapApp)">
<Payload Compressed='yes' SourceFile='Default.thm' />
<Payload Compressed='yes' SourceFile='Default.wxl' />
<Payload Compressed='yes' SourceFile='SideBar.png' />
</BootstrapperApplication>
<!-- May be set to "Removing" or "Repairing" -->
<Variable Name="ActionLikeInstalling" Value="Installing" />
<!-- May be set to "Uninstallation" or "Repair" -->
<Variable Name="ActionLikeInstallation" Value="Setup" />
<Variable Name="ShortVersion" Value="$(var.MajorVersionNumber).$(var.MinorVersionNumber)" />
<Variable Name="ShortVersionNoDot" Value="$(var.MajorVersionNumber)$(var.MinorVersionNumber)" />
<Variable Name="WinVer" Value="$(var.MajorVersionNumber).$(var.MinorVersionNumber)$(var.PyArchExt)$(var.PyTestExt)" />
<Variable Name="WinVerNoDot" Value="$(var.MajorVersionNumber)$(var.MinorVersionNumber)$(var.PyArchExt)$(var.PyTestExt)" />
<Variable Name="InstallAllUsers" Value="0" bal:Overridable="yes" />
<?if "$(var.PyTestExt)"="" ?>
<Variable Name="InstallLauncherAllUsers" Value="1" bal:Overridable="yes" />
<?else ?>
<Variable Name="InstallLauncherAllUsers" Value="0" />
<?endif ?>
<Variable Name="TargetDir" Value="" bal:Overridable="yes" />
<?if $(var.Platform)~="x64" ?>
<Variable Name="DefaultAllUsersTargetDir" Value="[ProgramFiles64Folder]Python[WinVerNoDot]" bal:Overridable="yes" />
<Variable Name="TargetPlatform" Value="x64" />
<?else ?>
<Variable Name="DefaultAllUsersTargetDir" Value="[ProgramFilesFolder]Python[WinVerNoDot]" bal:Overridable="yes" />
<Variable Name="TargetPlatform" Value="x86" />
<?endif ?>
<Variable Name="DefaultJustForMeTargetDir" Value="[LocalAppDataFolder]Programs\Python\Python[WinVerNoDot]" bal:Overridable="yes" />
<Variable Name="OptionalFeaturesRegistryKey" Value="Software\Python\PythonCore\[WinVer]\InstalledFeatures" />
<Variable Name="TargetDirRegistryKey" Value="Software\Python\PythonCore\[WinVer]\InstallPath" />
<!--
An empty string will use the other defaults based on InstallAllUsers
(and switch dynamically in the UI). To get the old default, pass
this property on the command line:
DefaultCustomTargetDir=[WindowsVolume]Python[ShortVersionNoDot]
-->
<Variable Name="DefaultCustomTargetDir" Value="" bal:Overridable="yes" />
<Variable Name="InstallAllUsersState" Value="enabled" bal:Overridable="yes" />
<?if "$(var.PyTestExt)"="" ?>
<Variable Name="InstallLauncherAllUsersState" Value="enabled" bal:Overridable="yes" />
<?else ?>
<Variable Name="InstallLauncherAllUsersState" Value="disable" bal:Overridable="yes" />
<?endif ?>
<Variable Name="CustomInstallLauncherAllUsersState" Value="[InstallLauncherAllUsersState]" />
<Variable Name="TargetDirState" Value="enabled" />
<Variable Name="CustomBrowseButtonState" Value="enabled" />
<Variable Name="Include_core" Value="1" />
<Variable Name="Include_exe" Value="1" bal:Overridable="yes" />
<Variable Name="Include_dev" Value="1" bal:Overridable="yes" />
<Variable Name="Include_lib" Value="1" bal:Overridable="yes" />
<Variable Name="Include_test" Value="1" bal:Overridable="yes" />
<Variable Name="Include_doc" Value="1" bal:Overridable="yes" />
<Variable Name="Include_tools" Value="1" bal:Overridable="yes" />
<Variable Name="Include_tcltk" Value="1" bal:Overridable="yes" />
<Variable Name="Include_pip" Value="1" bal:Overridable="yes" />
<?if "$(var.PyTestExt)"="" ?>
<Variable Name="Include_launcher" Value="1" bal:Overridable="yes" />
<Variable Name="Include_launcherState" Value="enabled" bal:Overridable="yes" />
<?else ?>
<Variable Name="Include_launcher" Value="0" />
<Variable Name="Include_launcherState" Value="disable" />
<?endif ?>
<Variable Name="Include_symbols" Value="0" bal:Overridable="yes" />
<Variable Name="Include_debug" Value="0" bal:Overridable="yes" />
<Variable Name="LauncherOnly" Value="0" bal:Overridable="yes" />
<Variable Name="DetectedLauncher" Value="0" />
<Variable Name="DetectedOldLauncher" Value="0" />
<Variable Name="AssociateFiles" Value="1" bal:Overridable="yes" />
<Variable Name="Shortcuts" Value="1" bal:Overridable="yes" />
<Variable Name="PrependPath" Value="0" bal:Overridable="yes" />
<Variable Name="CompileAll" Value="0" bal:Overridable="yes" />
<Variable Name="SimpleInstall" Value="0" bal:Overridable="yes" />
<Variable Name="SimpleInstallDescription" Value="" bal:Overridable="yes" />
<Chain ParallelCache="yes">
<PackageGroupRef Id="crt" />
<PackageGroupRef Id="core" />
<PackageGroupRef Id="dev" />
<PackageGroupRef Id="exe" />
<PackageGroupRef Id="lib" />
<PackageGroupRef Id="test" />
<PackageGroupRef Id="doc" />
<PackageGroupRef Id="tools" />
<PackageGroupRef Id="tcltk" />
<PackageGroupRef Id="launcher" />
<PackageGroupRef Id="pip" />
<PackageGroupRef Id="packageinstall" />
<PackageGroupRef Id="postinstall" />
</Chain>
</Bundle>
</Wix>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{3E204ADD-238D-4D10-852C-4F859325C839}</ProjectGuid>
<OutputName>python</OutputName>
<OutputSuffix>full</OutputSuffix>
</PropertyGroup>
<Import Project="..\msi.props" />
<PropertyGroup>
<DefineConstants>
$(DefineConstants);
CompressMSI=yes;
CompressPDB=yes;
CompressMSI_D=yes;
</DefineConstants>
</PropertyGroup>
<Import Project="bundle.targets" />
</Project>

View file

@ -0,0 +1,62 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PackageGroup Id="core">
<MsiPackage Id="core_AllUsers"
SourceFile="core.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="core_AllUsers_pdb"
SourceFile="core_pdb.msi"
Compressed="$(var.CompressPDB)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and Include_symbols and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="core_AllUsers_d"
SourceFile="core_d.msi"
Compressed="$(var.CompressMSI_D)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and Include_debug and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="core_JustForMe"
SourceFile="core.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="core_JustForMe_pdb"
SourceFile="core_pdb.msi"
Compressed="$(var.CompressPDB)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and Include_symbols and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="core_JustForMe_d"
SourceFile="core_d.msi"
Compressed="$(var.CompressMSI_D)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and Include_debug and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
</PackageGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,49 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PackageGroup Id="crt">
<PackageGroupRef Id="crt_14.0_v6.0" />
<PackageGroupRef Id="crt_14.0_v6.1" />
<PackageGroupRef Id="crt_14.0_v6.2" />
<PackageGroupRef Id="crt_14.0_v6.3" />
</PackageGroup>
</Fragment>
<?foreach ver in v6.0;v6.1;v6.2;v6.3 ?>
<?if "$(var.ver)" = "v6.0" ?>
<?define msuver=6.0 ?>
<?elseif "$(var.ver)" = "v6.1" ?>
<?define msuver=6.1 ?>
<?elseif "$(var.ver)" = "v6.2" ?>
<?define msuver=8-RT ?>
<?elseif "$(var.ver)" = "v6.3" ?>
<?define msuver=8.1 ?>
<?else ?>
<?error unknown version $(var.ver) ?>
<?endif ?>
<Fragment>
<PackageGroup Id="crt_14.0_$(var.ver)">
<MsuPackage Id="crt_14.0_$(var.ver)_x86"
KB="2999226"
SourceFile="!(bindpath.redist)\Windows$(var.msuver)-KB2999226-x86.msu"
DisplayName="!(loc.CRTDescription)"
Description="!(loc.CRTDescription)"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
InstallCondition="not CRTInstalled and VersionNT = $(var.ver) and not VersionNT64 and (Include_core or Include_exe or Include_launcher or Include_pip) and not LauncherOnly" />
<MsuPackage Id="crt_14.0_$(var.ver)_x64"
KB="2999226"
SourceFile="!(bindpath.redist)\Windows$(var.msuver)-KB2999226-x64.msu"
DisplayName="!(loc.CRTDescription)"
Description="!(loc.CRTDescription)"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
InstallCondition="not CRTInstalled and VersionNT64 = $(var.ver) and (Include_core or Include_exe or Include_launcher or Include_pip) and not LauncherOnly" />
</PackageGroup>
</Fragment>
<?undef msuver ?>
<?endforeach ?>
</Wix>

View file

@ -0,0 +1,44 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PackageGroup Id="dev">
<MsiPackage Id="dev_AllUsers"
SourceFile="dev.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and Include_dev and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="dev_AllUsers_d"
SourceFile="dev_d.msi"
Compressed="$(var.CompressMSI_D)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and Include_dev and Include_debug and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="dev_JustForMe"
SourceFile="dev.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and Include_dev and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="dev_JustForMe_d"
SourceFile="dev_d.msi"
Compressed="$(var.CompressMSI_D)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and Include_dev and Include_debug and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
</PackageGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,28 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PackageGroup Id="doc">
<MsiPackage Id="doc_AllUsers"
SourceFile="doc.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
EnableFeatureSelection="yes"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and Include_doc and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="doc_JustForMe"
SourceFile="doc.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
EnableFeatureSelection="yes"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and Include_doc and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
</PackageGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,64 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PackageGroup Id="exe">
<MsiPackage Id="exe_AllUsers"
SourceFile="exe.msi"
ForcePerMachine="yes"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
EnableFeatureSelection="yes"
InstallCondition="InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="exe_AllUsers_pdb"
SourceFile="exe_pdb.msi"
ForcePerMachine="yes"
Compressed="$(var.CompressPDB)"
DownloadUrl="$(var.DownloadUrl)"
InstallCondition="InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and Include_symbols and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="exe_AllUsers_d"
SourceFile="exe_d.msi"
ForcePerMachine="yes"
Compressed="$(var.CompressMSI_D)"
DownloadUrl="$(var.DownloadUrl)"
InstallCondition="InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and Include_debug and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="exe_JustForMe"
SourceFile="exe.msi"
ForcePerMachine="no"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
EnableFeatureSelection="yes"
InstallCondition="not InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="exe_JustForMe_pdb"
SourceFile="exe_pdb.msi"
ForcePerMachine="no"
Compressed="$(var.CompressPDB)"
DownloadUrl="$(var.DownloadUrl)"
InstallCondition="not InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and Include_symbols and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="exe_JustForMe_d"
SourceFile="exe_d.msi"
ForcePerMachine="no"
Compressed="$(var.CompressMSI_D)"
DownloadUrl="$(var.DownloadUrl)"
InstallCondition="not InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and Include_debug and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
</PackageGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,27 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PackageGroup Id="launcher">
<!-- The All Users launcher is always the 32-bit version -->
<MsiPackage Id="launcher_AllUsers"
SourceFile="!(bindpath.build32)en-us\launcher.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
EnableFeatureSelection="yes"
Permanent="yes"
Visible="yes"
InstallCondition="(InstallAllUsers or InstallLauncherAllUsers) and Include_launcher and not DetectedLauncher" />
<MsiPackage Id="launcher_JustForMe"
SourceFile="!(bindpath.build32)en-us\launcher.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
EnableFeatureSelection="yes"
Permanent="yes"
Visible="yes"
InstallCondition="not (InstallAllUsers or InstallLauncherAllUsers) and Include_launcher and not DetectedLauncher" />
</PackageGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,62 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PackageGroup Id="lib">
<MsiPackage Id="lib_AllUsers"
SourceFile="lib.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and Include_lib and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="lib_AllUsers_pdb"
SourceFile="lib_pdb.msi"
Compressed="$(var.CompressPDB)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and Include_lib and Include_symbols and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="lib_AllUsers_d"
SourceFile="lib_d.msi"
Compressed="$(var.CompressMSI_D)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and Include_lib and Include_debug and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="lib_JustForMe"
SourceFile="lib.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and Include_lib and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="lib_JustForMe_pdb"
SourceFile="lib_pdb.msi"
Compressed="$(var.CompressPDB)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and Include_lib and Include_symbols and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="lib_JustForMe_d"
SourceFile="lib_d.msi"
Compressed="$(var.CompressMSI_D)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and Include_lib and Include_debug and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
</PackageGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,26 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PackageGroup Id="packageinstall">
<!--
This is an example of installing a package using pip as part of main install.
For a network-only install, remove the Payload element and change the install
command to specify the package and (optionally) version specifier.
<ExePackage Id="requests"
SourceFile="py.exe"
Compressed="yes"
DisplayName="!(loc.CompileAllDescription)"
InstallCommand='-[WinVer] -m pip install requests-2.7.0-py2.py3-none-any.whl'
UninstallCommand='-[WinVer] -m pip uninstall -y requests'
Vital="no"
InstallCondition="Include_pip and not LauncherOnly">
<Payload SourceFile="requests-2.7.0-py2.py3-none-any.whl"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)" />
</ExePackage>
-->
</PackageGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,25 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PackageGroup Id="pip">
<MsiPackage Id="pip_AllUsers"
SourceFile="pip.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and Include_pip and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="pip_JustForMe"
SourceFile="pip.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and Include_pip and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
</PackageGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,88 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PackageGroup Id="postinstall">
<MsiPackage Id="path_AllUsers"
SourceFile="path.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and PrependPath and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="path_JustForMe"
SourceFile="path.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and PrependPath and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<?define CompileAllCommand=-E -s -Wi "[TargetDir]\Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py2_|lib2to3\\tests|venv\\scripts" "[TargetDir]\Lib"?>
<ExePackage Id="compileall_AllUsers"
SourceFile="py.exe"
Compressed="yes"
DisplayName="!(loc.CompileAllDescription)"
InstallCommand='-[WinVer] $(var.CompileAllCommand)'
RepairCommand='-[WinVer] $(var.CompileAllCommand)'
Permanent="yes"
PerMachine="yes"
Vital="no"
InstallCondition="InstallAllUsers and CompileAll and not LauncherOnly" />
<ExePackage Id="compileallO_AllUsers"
SourceFile="py.exe"
Compressed="yes"
DisplayName="!(loc.CompileAllODescription)"
InstallCommand='-[WinVer] -O $(var.CompileAllCommand)'
RepairCommand='-[WinVer] -O $(var.CompileAllCommand)'
Permanent="yes"
PerMachine="yes"
Vital="no"
InstallCondition="InstallAllUsers and CompileAll and not LauncherOnly" />
<ExePackage Id="compileallOO_AllUsers"
SourceFile="py.exe"
Compressed="yes"
DisplayName="!(loc.CompileAllOODescription)"
InstallCommand='-[WinVer] -OO $(var.CompileAllCommand)'
RepairCommand='-[WinVer] -OO $(var.CompileAllCommand)'
Permanent="yes"
PerMachine="yes"
Vital="no"
InstallCondition="InstallAllUsers and CompileAll and not LauncherOnly" />
<ExePackage Id="compileall_JustForMe"
SourceFile="py.exe"
Compressed="yes"
DisplayName="!(loc.CompileAllDescription)"
InstallCommand='-[WinVer] $(var.CompileAllCommand)'
RepairCommand='-[WinVer] $(var.CompileAllCommand)'
Permanent="yes"
PerMachine="no"
Vital="no"
InstallCondition="not InstallAllUsers and CompileAll and not LauncherOnly" />
<ExePackage Id="compileallO_JustForMe"
SourceFile="py.exe"
Compressed="yes"
DisplayName="!(loc.CompileAllODescription)"
InstallCommand='-[WinVer] -O $(var.CompileAllCommand)'
RepairCommand='-[WinVer] -O $(var.CompileAllCommand)'
Permanent="yes"
PerMachine="no"
Vital="no"
InstallCondition="not InstallAllUsers and CompileAll and not LauncherOnly" />
<ExePackage Id="compileallOO_JustForMe"
SourceFile="py.exe"
Compressed="yes"
DisplayName="!(loc.CompileAllOODescription)"
InstallCommand='-[WinVer] -OO $(var.CompileAllCommand)'
RepairCommand='-[WinVer] -OO $(var.CompileAllCommand)'
Permanent="yes"
PerMachine="no"
Vital="no"
InstallCondition="not InstallAllUsers and CompileAll and not LauncherOnly" />
</PackageGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,68 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PackageGroup Id="tcltk">
<MsiPackage Id="tcltk_AllUsers"
SourceFile="tcltk.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
EnableFeatureSelection="yes"
InstallCondition="InstallAllUsers and Include_tcltk and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="tcltk_AllUsers_pdb"
SourceFile="tcltk_pdb.msi"
Compressed="$(var.CompressPDB)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
EnableFeatureSelection="yes"
InstallCondition="InstallAllUsers and Include_tcltk and Include_symbols and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="tcltk_AllUsers_d"
SourceFile="tcltk_d.msi"
Compressed="$(var.CompressMSI_D)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
EnableFeatureSelection="yes"
InstallCondition="InstallAllUsers and Include_tcltk and Include_debug and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="tcltk_JustForMe"
SourceFile="tcltk.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
EnableFeatureSelection="yes"
InstallCondition="not InstallAllUsers and Include_tcltk and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="tcltk_JustForMe_pdb"
SourceFile="tcltk_pdb.msi"
Compressed="$(var.CompressPDB)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
EnableFeatureSelection="yes"
InstallCondition="not InstallAllUsers and Include_tcltk and Include_symbols and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="tcltk_JustForMe_d"
SourceFile="tcltk_d.msi"
Compressed="$(var.CompressMSI_D)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
EnableFeatureSelection="yes"
InstallCondition="not InstallAllUsers and Include_tcltk and Include_debug and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
</PackageGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,62 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PackageGroup Id="test">
<MsiPackage Id="test_AllUsers"
SourceFile="test.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and Include_test and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="test_AllUsers_pdb"
SourceFile="test_pdb.msi"
Compressed="$(var.CompressPDB)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and Include_test and Include_symbols and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="test_AllUsers_d"
SourceFile="test_d.msi"
Compressed="$(var.CompressMSI_D)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and Include_test and Include_debug and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="test_JustForMe"
SourceFile="test.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and Include_test and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="test_JustForMe_pdb"
SourceFile="test_pdb.msi"
Compressed="$(var.CompressPDB)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and Include_test and Include_symbols and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="test_JustForMe_d"
SourceFile="test_d.msi"
Compressed="$(var.CompressMSI_D)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and Include_test and Include_debug and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
</PackageGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,26 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PackageGroup Id="tools">
<MsiPackage Id="tools_AllUsers"
SourceFile="tools.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and Include_tools and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="tools_JustForMe"
SourceFile="tools.msi"
Compressed="$(var.CompressMSI)"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and Include_tools and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
</PackageGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{FCD43AC9-969F-49A1-8AC5-EDC27599D1EB}</ProjectGuid>
<OutputName>python</OutputName>
<OutputSuffix></OutputSuffix>
</PropertyGroup>
<Import Project="..\msi.props" />
<PropertyGroup>
<DefineConstants>
$(DefineConstants);
CompressMSI=yes;
CompressPDB=no;
CompressMSI_D=no
</DefineConstants>
</PropertyGroup>
<Import Project="bundle.targets" />
</Project>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{71CDE213-CB39-4BD9-B89D-BBB878689144}</ProjectGuid>
<OutputName>python</OutputName>
<OutputSuffix>webinstall</OutputSuffix>
</PropertyGroup>
<Import Project="..\msi.props" />
<PropertyGroup>
<DefineConstants>
$(DefineConstants);
CompressMSI=no;
CompressPDB=no;
CompressMSI_D=no
</DefineConstants>
</PropertyGroup>
<Import Project="bundle.targets" />
</Project>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{8A4A1162-4BF9-4FF6-9A98-315F01E44932}</ProjectGuid>
<OutputName>python</OutputName>
<OutputSuffix></OutputSuffix>
</PropertyGroup>
<Import Project="..\msi.props" />
<PropertyGroup>
<DefineConstants Condition="'$(Pack)' != 'true'">
$(DefineConstants);CompressMSI=no;
</DefineConstants>
<DefineConstants Condition="'$(Pack)' == 'true'">
$(DefineConstants);CompressMSI=yes;
</DefineConstants>
<DefineConstants>
$(DefineConstants);
CompressPDB=no;
CompressMSI_D=no;
</DefineConstants>
</PropertyGroup>
<Import Project="bundle.targets" />
</Project>

122
third_party/python/Tools/msi/common.wxs vendored Normal file
View file

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<Property Id="ROOTREGISTRYKEY" Value="Software\Python\PythonCore" />
</Fragment>
<Fragment>
<Property Id="REGISTRYKEY" Value="Software\Python\PythonCore\$(var.ShortVersion)$(var.PyArchExt)$(var.PyTestExt)" />
</Fragment>
<Fragment>
<Component Id="OptionalFeature" Guid="*" Directory="InstallDirectory">
<Condition>OPTIONALFEATURESREGISTRYKEY</Condition>
<RegistryKey Root="HKMU" Key="[OPTIONALFEATURESREGISTRYKEY]">
<RegistryValue Type="string" Name="$(var.OptionalFeatureName)" Value="$(var.Version)" KeyPath="yes" />
</RegistryKey>
</Component>
</Fragment>
<Fragment>
<Property Id="UpgradeTable" Value="1" />
<?ifndef SuppressUpgradeTable ?>
<Upgrade Id="$(var.UpgradeCode)">
<UpgradeVersion Property="DOWNGRADE" Minimum="$(var.Version)" IncludeMinimum="no" OnlyDetect="yes" />
<UpgradeVersion Property="UPGRADE" Minimum="$(var.UpgradeMinimumVersion)" IncludeMinimum="yes" Maximum="$(var.Version)" IncludeMaximum="no" />
</Upgrade>
<?endif ?>
<?ifdef CoreUpgradeCode ?>
<?if $(var.UpgradeCode)!=$(var.CoreUpgradeCode) ?>
<Upgrade Id="$(var.CoreUpgradeCode)">
<UpgradeVersion Property="MISSING_CORE" Minimum="$(var.Version)" IncludeMinimum="yes" Maximum="$(var.Version)" IncludeMaximum="yes" OnlyDetect="yes" />
</Upgrade>
<Condition Message="!(loc.IncorrectCore)">Installed OR NOT MISSING_CORE</Condition>
<?endif ?>
<?endif ?>
<Condition Message="!(loc.NoDowngrade)">Installed OR NOT DOWNGRADE</Condition>
<Condition Message="!(loc.NoTargetDir)">Installed OR TARGETDIR OR Suppress_TARGETDIR_Check</Condition>
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallInitialize" Overridable="yes">UPGRADE</RemoveExistingProducts>
</InstallExecuteSequence>
</Fragment>
<Fragment>
<!-- Include an icon for the Programs and Features dialog -->
<Icon Id="ARPIcon" SourceFile="!(bindpath.src)PC\icons\python.ico" />
<Property Id="ARPPRODUCTICON" Value="ARPIcon" />
<Property Id="ARPNOMODIFY" Value="1" />
<Property Id="DISABLEADVTSHORTCUTS" Value="1" />
</Fragment>
<Fragment>
<?ifdef InstallDirectoryGuidSeed ?>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="InstallDirectory" ComponentGuidGenerationSeed="$(var.InstallDirectoryGuidSeed)" />
</Directory>
<?endif ?>
</Fragment>
<!-- Top-level directories -->
<Fragment>
<DirectoryRef Id="InstallDirectory">
<Directory Id="DLLs" Name="DLLs">
<Directory Id="Catalogs" />
</Directory>
</DirectoryRef>
</Fragment>
<Fragment>
<DirectoryRef Id="InstallDirectory">
<Directory Id="Doc" Name="Doc" />
</DirectoryRef>
</Fragment>
<Fragment>
<DirectoryRef Id="InstallDirectory">
<Directory Id="include" Name="include" />
</DirectoryRef>
</Fragment>
<Fragment>
<DirectoryRef Id="InstallDirectory">
<Directory Id="Lib" Name="Lib" />
</DirectoryRef>
</Fragment>
<Fragment>
<DirectoryRef Id="InstallDirectory">
<Directory Id="libs" Name="libs" />
</DirectoryRef>
</Fragment>
<Fragment>
<DirectoryRef Id="InstallDirectory">
<Directory Id="Scripts" Name="Scripts" />
</DirectoryRef>
</Fragment>
<Fragment>
<DirectoryRef Id="InstallDirectory">
<Directory Id="tcl" Name="tcl" />
</DirectoryRef>
</Fragment>
<Fragment>
<DirectoryRef Id="InstallDirectory">
<Directory Id="Tools" Name="Tools" />
</DirectoryRef>
</Fragment>
<!-- Start Menu folder -->
<Fragment>
<DirectoryRef Id="TARGETDIR">
<Directory Id="ProgramMenuFolder">
<Directory Id="MenuDir" Name="!(loc.ProductName)" />
</Directory>
</DirectoryRef>
</Fragment>
</Wix>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="LCID">1033</String>
<String Id="Culture">en-us</String>
<String Id="ProductName">Python {{ShortVersion}}</String>
<String Id="FullProductName">Python {{LongVersion}} ({{Bitness}})</String>
<String Id="Title">Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}})</String>
<String Id="Description">Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}})</String>
<String Id="TitlePdb">Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}} symbols)</String>
<String Id="DescriptionPdb">Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}} symbols)</String>
<String Id="Title_d">Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}} debug)</String>
<String Id="Description_d">Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}} debug)</String>
<String Id="Manufacturer">Python Software Foundation</String>
<String Id="NoDowngrade">A newer version of !(loc.ProductName) is already installed.</String>
<String Id="IncorrectCore">An incorrect version of a prerequisite package is installed. Please uninstall any other versions of !(loc.ProductName) and try installing this again.</String>
<String Id="NoTargetDir">The TARGETDIR variable must be provided when invoking this installer.</String>
<String Id="ManufacturerSupportUrl">http://www.python.org/</String>
</WixLocalization>

View file

@ -0,0 +1,127 @@
'''
Processes a CSV file containing a list of files into a WXS file with
components for each listed file.
The CSV columns are:
source of file, target for file, group name
Usage::
py txt_to_wxs.py [path to file list .csv] [path to destination .wxs]
This is necessary to handle structures where some directories only
contain other directories. MSBuild is not able to generate the
Directory entries in the WXS file correctly, as it operates on files.
Python, however, can easily fill in the gap.
'''
__author__ = "Steve Dower <steve.dower@microsoft.com>"
import csv
import re
import sys
from collections import defaultdict
from itertools import chain, zip_longest
from pathlib import PureWindowsPath
from uuid import uuid1
ID_CHAR_SUBS = {
'-': '_',
'+': '_P',
}
def make_id(path):
return re.sub(
r'[^A-Za-z0-9_.]',
lambda m: ID_CHAR_SUBS.get(m.group(0), '_'),
str(path).rstrip('/\\'),
flags=re.I
)
DIRECTORIES = set()
def main(file_source, install_target):
with open(file_source, 'r', newline='') as f:
files = list(csv.reader(f))
assert len(files) == len(set(make_id(f[1]) for f in files)), "Duplicate file IDs exist"
directories = defaultdict(set)
cache_directories = defaultdict(set)
groups = defaultdict(list)
for source, target, group, disk_id, condition in files:
target = PureWindowsPath(target)
groups[group].append((source, target, disk_id, condition))
if target.suffix.lower() in {".py", ".pyw"}:
cache_directories[group].add(target.parent)
for dirname in target.parents:
parent = make_id(dirname.parent)
if parent and parent != '.':
directories[parent].add(dirname.name)
lines = [
'<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">',
' <Fragment>',
]
for dir_parent in sorted(directories):
lines.append(' <DirectoryRef Id="{}">'.format(dir_parent))
for dir_name in sorted(directories[dir_parent]):
lines.append(' <Directory Id="{}_{}" Name="{}" />'.format(dir_parent, make_id(dir_name), dir_name))
lines.append(' </DirectoryRef>')
for dir_parent in (make_id(d) for group in cache_directories.values() for d in group):
lines.append(' <DirectoryRef Id="{}">'.format(dir_parent))
lines.append(' <Directory Id="{}___pycache__" Name="__pycache__" />'.format(dir_parent))
lines.append(' </DirectoryRef>')
lines.append(' </Fragment>')
for group in sorted(groups):
lines.extend([
' <Fragment>',
' <ComponentGroup Id="{}">'.format(group),
])
for source, target, disk_id, condition in groups[group]:
lines.append(' <Component Id="{}" Directory="{}" Guid="*">'.format(make_id(target), make_id(target.parent)))
if condition:
lines.append(' <Condition>{}</Condition>'.format(condition))
if disk_id:
lines.append(' <File Id="{}" Name="{}" Source="{}" DiskId="{}" />'.format(make_id(target), target.name, source, disk_id))
else:
lines.append(' <File Id="{}" Name="{}" Source="{}" />'.format(make_id(target), target.name, source))
lines.append(' </Component>')
create_folders = {make_id(p) + "___pycache__" for p in cache_directories[group]}
remove_folders = {make_id(p2) for p1 in cache_directories[group] for p2 in chain((p1,), p1.parents)}
create_folders.discard(".")
remove_folders.discard(".")
if create_folders or remove_folders:
lines.append(' <Component Id="{}__pycache__folders" Directory="TARGETDIR" Guid="{}">'.format(group, uuid1()))
lines.extend(' <CreateFolder Directory="{}" />'.format(p) for p in create_folders)
lines.extend(' <RemoveFile Id="Remove_{0}_files" Name="*" On="uninstall" Directory="{0}" />'.format(p) for p in create_folders)
lines.extend(' <RemoveFolder Id="Remove_{0}_folder" On="uninstall" Directory="{0}" />'.format(p) for p in create_folders | remove_folders)
lines.append(' </Component>')
lines.extend([
' </ComponentGroup>',
' </Fragment>',
])
lines.append('</Wix>')
# Check if the file matches. If so, we don't want to touch it so
# that we can skip rebuilding.
try:
with open(install_target, 'r') as f:
if all(x.rstrip('\r\n') == y for x, y in zip_longest(f, lines)):
print('File is up to date')
return
except IOError:
pass
with open(install_target, 'w') as f:
f.writelines(line + '\n' for line in lines)
print('Wrote {} lines to {}'.format(len(lines), install_target))
if __name__ == '__main__':
main(sys.argv[1], sys.argv[2])

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{5F23F608-D74B-4259-A0CE-8DC65CC7FE53}</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName Condition="'$(OutputName)' == ''">dev</OutputName>
<OutputType>Package</OutputType>
</PropertyGroup>
<Import Project="..\msi.props" />
<PropertyGroup>
<DefineConstants Condition="$(BuildForRelease)">
$(DefineConstants);
IncludeMinGWLib=1;
</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="dev.wxs" />
<Compile Include="dev_files.wxs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="*.wxl" />
</ItemGroup>
<ItemGroup>
<InstallFiles Include="$(PySourcePath)include\*.h">
<SourceBase>$(PySourcePath)</SourceBase>
<Source>!(bindpath.src)</Source>
<TargetBase>$(PySourcePath)</TargetBase>
<Target_></Target_>
<Group>dev_include</Group>
</InstallFiles>
</ItemGroup>
<Target Name="BuildMinGWLib"
Inputs="$(BuildPath)$(PyDllName).dll"
Outputs="$(BuildPath)lib$(PyDllName).a"
AfterTargets="PrepareForBuild"
Condition="$(BuildForRelease)">
<!-- Build libpython##.a as part of this project. This requires gendef and dlltool on the path. -->
<PropertyGroup>
<_DllToolOpts>-m i386 --as-flags=--32</_DllToolOpts>
<_DllToolOpts Condition="$(Platform) == 'x64'">-m i386:x86-64</_DllToolOpts>
</PropertyGroup>
<Exec Command='gendef - "$(BuildPath)$(PyDllName).dll" &gt; "$(IntermediateOutputPath)mingwlib.def"' ContinueOnError="false" />
<Exec Command='dlltool --dllname $(PyDllName).dll --def "$(IntermediateOutputPath)mingwlib.def" --output-lib "$(BuildPath)lib$(PyDllName).a" $(_DllToolOpts)' />
</Target>
<Import Project="..\msi.targets" />
</Project>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Language="!(loc.LCID)" Name="!(loc.Title)" Version="$(var.Version)" Manufacturer="!(loc.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
<Package InstallerVersion="300" Compressed="yes" InstallScope="perUser" Platform="$(var.Platform)" />
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<PropertyRef Id="UpgradeTable" />
<Feature Id="DefaultFeature" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
<ComponentGroupRef Id="dev_include" />
<ComponentGroupRef Id="dev_pyconfig" />
<ComponentGroupRef Id="dev_libs" />
<?ifdef IncludeMinGWLib ?>
<ComponentGroupRef Id="dev_mingw" />
<?endif ?>
<ComponentRef Id="OptionalFeature" />
</Feature>
</Product>
</Wix>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{C11B4945-76BD-4137-B2E3-649460117A77}</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>dev_d</OutputName>
<OutputType>Package</OutputType>
</PropertyGroup>
<Import Project="..\msi.props" />
<ItemGroup>
<Compile Include="dev_d.wxs" />
<Compile Include="dev_files.wxs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="*.wxl" />
</ItemGroup>
<Import Project="..\msi.targets" />
</Project>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Language="!(loc.LCID)" Name="!(loc.Title_d)" Version="$(var.Version)" Manufacturer="!(loc.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
<Package InstallerVersion="300" Compressed="yes" InstallScope="perUser" Platform="$(var.Platform)" />
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<PropertyRef Id="UpgradeTable" />
<Feature Id="DebugBinaries" AllowAdvertise="no" Title="!(loc.Title_d)" Description="!(loc.Description_d)">
<ComponentGroupRef Id="dev_libs_d" />
</Feature>
</Product>
</Wix>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="Descriptor">Development Libraries</String>
<String Id="ShortDescriptor">dev</String>
</WixLocalization>

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<ComponentGroup Id="dev_pyconfig">
<Component Id="include_pyconfig.h" Directory="include" Guid="*">
<File Id="include_pyconfig.h" Name="pyconfig.h" Source="!(bindpath.src)PC\pyconfig.h" KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>
<Fragment>
<ComponentGroup Id="dev_libs">
<Component Id="libs_python3.lib" Directory="libs" Guid="*">
<File Id="libs_python_stable.lib" Name="python$(var.MajorVersionNumber).lib" KeyPath="yes" />
</Component>
<Component Id="libs_python.lib" Directory="libs" Guid="*">
<File Id="libs_python.lib" Name="python$(var.MajorVersionNumber)$(var.MinorVersionNumber).lib" KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>
<Fragment>
<ComponentGroup Id="dev_libs_d">
<Component Id="libs_python3_d.lib" Directory="libs" Guid="*">
<File Id="libs_python_stable_d.lib" Name="python$(var.MajorVersionNumber)_d.lib" />
</Component>
<Component Id="libs_python_d.lib" Directory="libs" Guid="*">
<File Id="libs_python_d.lib" Name="python$(var.MajorVersionNumber)$(var.MinorVersionNumber)_d.lib" />
</Component>
</ComponentGroup>
</Fragment>
<?ifdef IncludeMinGWLib ?>
<Fragment>
<ComponentGroup Id="dev_mingw">
<Component Id="libs_libpython.a" Directory="libs" Guid="*">
<File Id="libs_libpython.a" Name="libpython$(var.MajorVersionNumber)$(var.MinorVersionNumber).a" KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>
<?endif ?>
</Wix>

View file

@ -0,0 +1,23 @@
"""distutils.command.bdist_wininst
Suppresses the 'bdist_wininst' command, while still allowing
setuptools to import it without breaking."""
from distutils.core import Command
from distutils.errors import DistutilsPlatformError
class bdist_wininst(Command):
description = "create an executable installer for MS Windows"
# Marker for tests that we have the unsupported bdist_wininst
_unsupported = True
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
raise DistutilsPlatformError("bdist_wininst is not supported "
"in this Python distribution")

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{0D62A2BB-5F71-4447-8C8C-9708407B3674}</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>doc</OutputName>
<OutputType>Package</OutputType>
<!-- Shortcut validation is not necessary -->
<SuppressICEs>ICE43</SuppressICEs>
</PropertyGroup>
<Import Project="..\msi.props" />
<PropertyGroup>
<DocFilename>python$(MajorVersionNumber)$(MinorVersionNumber)$(MicroVersionNumber)$(ReleaseLevelName).chm</DocFilename>
<IncludeDocFile>false</IncludeDocFile>
<IncludeDocFile Condition="$(BuildForRelease) or Exists('$(PySourcePath)Doc\build\htmlhelp\$(DocFilename)')">true</IncludeDocFile>
</PropertyGroup>
<PropertyGroup Condition="$(IncludeDocFile)">
<DefineConstants>$(DefineConstants);DocFilename=$(DocFilename);</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="doc.wxs" />
<Compile Include="doc_files.wxs" Condition="$(IncludeDocFile)" />
<Compile Include="doc_no_files.wxs" Condition="!$(IncludeDocFile)" />
</ItemGroup>
<ItemGroup>
<WxlTemplate Include="*.wxl_template" />
</ItemGroup>
<Import Project="..\msi.targets" />
</Project>

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Language="!(loc.LCID)" Name="!(loc.Title)" Version="$(var.Version)" Manufacturer="!(loc.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
<Package InstallerVersion="300" Compressed="yes" InstallScope="perUser" Platform="$(var.Platform)" />
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<PropertyRef Id="UpgradeTable" />
<PropertyRef Id="REGISTRYKEY" />
<Property Id="HHExe" Value="C:\Windows\hh.exe" />
<CustomAction Id="SetHHExe" Property="HHCExe" Value='[WindowsFolder]\hh.exe' Execute="immediate" />
<InstallExecuteSequence>
<Custom Action="SetHHExe" Before="CostFinalize">1</Custom>
</InstallExecuteSequence>
<Feature Id="DefaultFeature" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
<ComponentGroupRef Id="doc" Primary="yes" />
<ComponentRef Id="OptionalFeature" />
</Feature>
<Feature Id="Shortcuts" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
<ComponentGroupRef Id="doc" />
<?ifdef DocFilename ?>
<Component Id="doc_shortcut" Directory="MenuDir" Guid="*">
<RegistryKey Root="HKMU" Key="[OPTIONALFEATURESREGISTRYKEY]">
<RegistryValue Name="$(var.OptionalFeatureName)_shortcut" Type="string" Value="$(var.Version)" KeyPath="yes" />
</RegistryKey>
<Shortcut Id="python.chm"
Target="[HHExe]"
Arguments="[#python.chm]"
Name="!(loc.ShortcutName)"
Description="!(loc.ShortcutDescription)"
WorkingDirectory="InstallDirectory"
Show="maximized" />
<RemoveFolder Id="Remove_MenuDir" On="uninstall" />
</Component>
<?endif ?>
</Feature>
</Product>
</Wix>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="ShortDescriptor">doc</String>
<String Id="Descriptor">Documentation</String>
<String Id="ShortcutName">Python {{ShortVersion}} Manuals ({{Bitness}})</String>
<String Id="ShortcutDescription">View the !(loc.ProductName) documentation.</String>
</WixLocalization>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PropertyRef Id="REGISTRYKEY" />
<ComponentGroup Id="doc">
<Component Id="python.chm" Directory="Doc" Guid="*">
<File Id="python.chm" Name="$(var.DocFilename)" KeyPath="yes" />
<RegistryKey Root="HKMU" Key="[REGISTRYKEY]">
<RegistryValue Key="Help\Main Python Documentation" Type="string" Value="[#python.chm]" />
</RegistryKey>
</Component>
</ComponentGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<ComponentGroup Id="doc">
<!--
This file is included when the CHM is not available.
This way, snapshot builds can succeed without having to
build the docs.
-->
<Component Id="EmptyDocFolder" Directory="Doc" Guid="{22FD42DB-EC66-4B1C-B1FC-44E0CF7B2462}">
<CreateFolder />
<RemoveFolder Id="Remove_EmptyDocFolder" On="uninstall" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>

View file

@ -0,0 +1,41 @@
Additional Conditions for this Windows binary build
---------------------------------------------------
This program is linked with and uses Microsoft Distributable Code,
copyrighted by Microsoft Corporation. The Microsoft Distributable Code
is embedded in each .exe, .dll and .pyd file as a result of running
the code through a linker.
If you further distribute programs that include the Microsoft
Distributable Code, you must comply with the restrictions on
distribution specified by Microsoft. In particular, you must require
distributors and external end users to agree to terms that protect the
Microsoft Distributable Code at least as much as Microsoft's own
requirements for the Distributable Code. See Microsoft's documentation
(included in its developer tools and on its website at microsoft.com)
for specific details.
Redistribution of the Windows binary build of the Python interpreter
complies with this agreement, provided that you do not:
- alter any copyright, trademark or patent notice in Microsoft's
Distributable Code;
- use Microsoft's trademarks in your programs' names or in a way that
suggests your programs come from or are endorsed by Microsoft;
- distribute Microsoft's Distributable Code to run on a platform other
than Microsoft operating systems, run-time technologies or application
platforms; or
- include Microsoft Distributable Code in malicious, deceptive or
unlawful programs.
These restrictions apply only to the Microsoft Distributable Code as
defined above, not to Python itself or any programs running on the
Python interpreter. The redistribution of the Python interpreter and
libraries is governed by the Python Software License included with this
file, or by other licenses as marked.

View file

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{6BD53305-B03E-49DC-85FB-5551B8CCC843}</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>exe</OutputName>
<OutputType>Package</OutputType>
</PropertyGroup>
<PropertyGroup>
<!-- Shortcut validation is not necessary -->
<SuppressICEs>ICE43</SuppressICEs>
</PropertyGroup>
<Import Project="..\msi.props" />
<ItemGroup>
<Compile Include="exe.wxs" />
<Compile Include="exe_files.wxs" />
<Compile Include="exe_reg.wxs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="*.wxl" />
<WxlTemplate Include="*.wxl_template" />
</ItemGroup>
<Target Name="_GenerateLicense" AfterTargets="PrepareForBuild">
<ItemGroup>
<LicenseFiles Include="$(PySourcePath)LICENSE;
crtlicense.txt;
$(bz2Dir)LICENSE;
$(opensslDir)LICENSE;
$(tclDir)license.terms;
$(tkDir)license.terms;
$(tixDir)license.terms" />
<_LicenseFiles Include="@(LicenseFiles)">
<Content>$([System.IO.File]::ReadAllText(%(FullPath)))</Content>
</_LicenseFiles>
</ItemGroup>
<WriteLinesToFile File="$(BuildPath)LICENSE"
Overwrite="true"
Lines="@(_LicenseFiles->'%(Content)')" />
</Target>
<Target Name="_CopyMiscNews" AfterTargets="PrepareForBuild" Condition="Exists('$(PySourcePath)Misc\NEWS')">
<Copy SourceFiles="$(PySourcePath)Misc\NEWS" DestinationFiles="$(BuildPath)NEWS.txt" />
</Target>
<Target Name="_MergeMiscNewsWithBlurb" AfterTargets="PrepareForBuild" Condition="$(Blurb) != '' and !Exists('$(PySourcePath)Misc\NEWS')">
<Exec Command="$(Blurb) merge -f &quot;$(BuildPath)NEWS.txt&quot;" WorkingDirectory="$(PCBuild)" />
</Target>
<Target Name="_MergeMiscNewsWithPython" AfterTargets="PrepareForBuild" Condition="$(Blurb) == '' and !Exists('$(PySourcePath)Misc\NEWS')">
<ItemGroup>
<HostPython Include="$(ExternalsDir)python*\tools\python.exe" />
<HostPython Include="@(HostPython)" Condition="Exists(%(FullPath))" />
<HostPython Include="py" Condition="@(HostPython) == ''" />
</ItemGroup>
<PropertyGroup>
<HostPython>@(HostPython)</HostPython>
<HostPython Condition="$(HostPython.Contains(';'))">$(HostPython.Remove($(HostPython.IndexOf(';'))))</HostPython>
</PropertyGroup>
<Exec Command="&quot;$(HostPython)&quot; -m pip install -U blurb" WorkingDirectory="$(PCBuild)" />
<Exec Command="&quot;$(HostPython)&quot; -m blurb merge -f &quot;$(BuildPath)NEWS.txt&quot;" WorkingDirectory="$(PCBuild)" />
</Target>
<Import Project="..\msi.targets" />
</Project>

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Language="!(loc.LCID)" Name="!(loc.Title)" Version="$(var.Version)" Manufacturer="!(loc.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
<Package InstallerVersion="300" Compressed="yes" InstallScope="perUser" Platform="$(var.Platform)" />
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<PropertyRef Id="UpgradeTable" />
<PropertyRef Id="REGISTRYKEY" />
<Feature Id="DefaultFeature" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
<ComponentGroupRef Id="exe_python" Primary="yes" />
<ComponentGroupRef Id="exe_reg" Primary="yes" />
<ComponentGroupRef Id="exe_txt" />
<ComponentGroupRef Id="exe_icons" />
<ComponentRef Id="OptionalFeature" />
</Feature>
<Feature Id="Shortcuts" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
<ComponentGroupRef Id="exe_python" />
<Component Id="exe_shortcut" Directory="MenuDir" Guid="*">
<Shortcut Id="python.exe"
Target="[#python.exe]"
Name="!(loc.ShortcutName)"
Description="!(loc.ShortcutDescription)"
WorkingDirectory="InstallDirectory" />
<RemoveFolder Id="Remove_MenuDir" Directory="MenuDir" On="uninstall" />
<RegistryKey Root="HKMU" Key="[REGISTRYKEY]">
<RegistryValue Key="InstalledFeatures" Name="Shortcuts" Type="string" Value="$(var.Version)" />
</RegistryKey>
</Component>
</Feature>
</Product>
</Wix>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{B1CA739C-8DB0-403B-9010-D79507507CE9}</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>exe_d</OutputName>
<OutputType>Package</OutputType>
</PropertyGroup>
<Import Project="..\msi.props" />
<ItemGroup>
<Compile Include="exe_d.wxs" />
<Compile Include="exe_files.wxs" />
<Compile Include="exe_reg.wxs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="*.wxl" />
<WxlTemplate Include="*.wxl_template" />
</ItemGroup>
<Import Project="..\msi.targets" />
</Project>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Language="!(loc.LCID)" Name="!(loc.Title_d)" Version="$(var.Version)" Manufacturer="!(loc.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
<Package InstallerVersion="300" Compressed="yes" InstallScope="perUser" Platform="$(var.Platform)" />
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<PropertyRef Id="UpgradeTable" />
<Feature Id="DebugBinaries" AllowAdvertise="no" Title="!(loc.Title_d)" Description="!(loc.Description_d)">
<ComponentGroupRef Id="exe_python_d" />
</Feature>
</Product>
</Wix>

Some files were not shown because too many files have changed in this diff Show more