summaryrefslogtreecommitdiff
path: root/Tools
diff options
context:
space:
mode:
authorSteve Dower <steve.dower@microsoft.com>2017-02-06 14:12:19 -0800
committerSteve Dower <steve.dower@microsoft.com>2017-02-06 14:12:19 -0800
commit5b4df5813c20fe96f117d0201965b52e86a1a66d (patch)
treed991f61bc824ca1b1b92bf7fb16fe3dacd4b1335 /Tools
parent3e0bdff8a0793d305b972f4a653e4698d440b3ae (diff)
parent95b272b4e0d5438a12702e51e05d03f5a5a8e505 (diff)
downloadcpython-5b4df5813c20fe96f117d0201965b52e86a1a66d.tar.gz
Includes ensurepip and venv packages in nuget package.
Diffstat (limited to 'Tools')
-rw-r--r--Tools/buildbot/build-amd64.bat5
-rw-r--r--Tools/buildbot/clean-amd64.bat5
-rw-r--r--Tools/buildbot/clean.bat1
-rw-r--r--Tools/buildbot/external-amd64.bat3
-rw-r--r--Tools/buildbot/external.bat3
-rw-r--r--Tools/buildbot/test-amd64.bat6
-rw-r--r--Tools/buildbot/test.bat4
-rwxr-xr-xTools/clinic/clinic.py128
-rwxr-xr-xTools/demo/ss1.py2
-rwxr-xr-xTools/freeze/freeze.py6
-rw-r--r--Tools/freeze/winmakemakefile.py6
-rwxr-xr-xTools/gdb/libpython.py81
-rw-r--r--Tools/hg/hgtouch.py1
-rwxr-xr-xTools/i18n/pygettext.py51
-rw-r--r--Tools/msi/buildrelease.bat87
-rw-r--r--Tools/msi/bundle/Default.thm7
-rw-r--r--Tools/msi/bundle/Default.wxl3
-rw-r--r--Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp155
-rw-r--r--Tools/msi/bundle/bundle.icobin19790 -> 0 bytes
-rw-r--r--Tools/msi/bundle/bundle.wxs2
-rw-r--r--Tools/msi/common.wxs12
-rw-r--r--Tools/msi/common_en-US.wxl_template1
-rw-r--r--Tools/msi/exe/exe.wixproj1
-rw-r--r--Tools/msi/exe/exe.wxs2
-rw-r--r--Tools/msi/exe/exe_d.wixproj1
-rw-r--r--Tools/msi/exe/exe_en-US.wxl_template1
-rw-r--r--Tools/msi/exe/exe_files.wxs10
-rw-r--r--Tools/msi/exe/exe_pdb.wixproj1
-rw-r--r--Tools/msi/exe/exe_reg.wxs25
-rw-r--r--Tools/msi/launcher/launcher.wixproj2
-rw-r--r--Tools/msi/launcher/launcher.wxs16
-rw-r--r--Tools/msi/launcher/launcher_en-US.wxl1
-rw-r--r--Tools/msi/launcher/launcher_reg.wxs8
-rw-r--r--Tools/msi/lib/lib.wixproj1
-rw-r--r--Tools/msi/lib/lib.wxs1
-rw-r--r--Tools/msi/lib/lib_files.wxs15
-rw-r--r--Tools/msi/make_zip.proj2
-rw-r--r--Tools/msi/make_zip.py54
-rw-r--r--Tools/msi/msi.props11
-rw-r--r--Tools/msi/msi.targets33
-rw-r--r--Tools/msi/test/test_files.wxs77
-rw-r--r--Tools/msi/tools/tools.wixproj1
-rw-r--r--Tools/msi/tools/tools.wxs1
-rw-r--r--Tools/msi/tools/tools_files.wxs7
-rw-r--r--Tools/nuget/make_pkg.proj2
-rw-r--r--Tools/parser/unparse.py86
-rw-r--r--Tools/pybench/CommandLine.py4
-rw-r--r--Tools/pybench/With.py1
-rw-r--r--Tools/pynche/ColorDB.py6
-rwxr-xr-xTools/scripts/combinerefs.py4
-rwxr-xr-xTools/scripts/diff.py2
-rwxr-xr-xTools/scripts/fixdiv.py4
-rw-r--r--Tools/scripts/generate_opcode_h.py2
-rwxr-xr-xTools/scripts/h2py.py8
-rwxr-xr-xTools/scripts/highlight.py16
-rwxr-xr-xTools/scripts/idle32
-rwxr-xr-xTools/scripts/mailerdaemon.py2
-rwxr-xr-xTools/scripts/nm2def.py4
-rwxr-xr-xTools/scripts/parseentities.py4
-rwxr-xr-xTools/scripts/pathfix.py2
-rwxr-xr-xTools/scripts/ptags.py2
-rwxr-xr-xTools/scripts/pyvenv6
-rwxr-xr-xTools/scripts/svneol.py2
-rwxr-xr-xTools/scripts/texi2html.py10
-rw-r--r--Tools/ssl/test_multiple_versions.py6
-rw-r--r--Tools/tz/zdump.py81
-rw-r--r--Tools/unicode/gencodec.py10
-rw-r--r--Tools/unicode/makeunicodedata.py11
68 files changed, 676 insertions, 441 deletions
diff --git a/Tools/buildbot/build-amd64.bat b/Tools/buildbot/build-amd64.bat
deleted file mode 100644
index f77407bcf7..0000000000
--- a/Tools/buildbot/build-amd64.bat
+++ /dev/null
@@ -1,5 +0,0 @@
-@rem Formerly used by the buildbot "compile" step.
-@echo This script is no longer used and may be removed in the future.
-@echo To get the same effect as this script, use
-@echo PCbuild\build.bat -d -e -k -p x64
-call "%~dp0build.bat" -p x64 %*
diff --git a/Tools/buildbot/clean-amd64.bat b/Tools/buildbot/clean-amd64.bat
deleted file mode 100644
index b53c7c1038..0000000000
--- a/Tools/buildbot/clean-amd64.bat
+++ /dev/null
@@ -1,5 +0,0 @@
-@rem Formerly used by the buildbot "clean" step.
-@echo This script is no longer used and may be removed in the future.
-@echo To get the same effect as this script, use `clean.bat` from this
-@echo directory and pass `-p x64` as two arguments.
-call "%~dp0clean.bat" -p x64 %*
diff --git a/Tools/buildbot/clean.bat b/Tools/buildbot/clean.bat
index 0fc68fd727..13e667991b 100644
--- a/Tools/buildbot/clean.bat
+++ b/Tools/buildbot/clean.bat
@@ -14,3 +14,4 @@ del /s "%root%\Lib\*.pyc" "%root%\Lib\*.pyo"
echo Deleting test leftovers ...
rmdir /s /q "%root%\build"
+del /s "%pcbuild%\python*.zip"
diff --git a/Tools/buildbot/external-amd64.bat b/Tools/buildbot/external-amd64.bat
deleted file mode 100644
index bfaef055f5..0000000000
--- a/Tools/buildbot/external-amd64.bat
+++ /dev/null
@@ -1,3 +0,0 @@
-@echo This script is no longer used and may be removed in the future.
-@echo Please use PCbuild\get_externals.bat instead.
-@"%~dp0..\..\PCbuild\get_externals.bat" %*
diff --git a/Tools/buildbot/external.bat b/Tools/buildbot/external.bat
deleted file mode 100644
index bfaef055f5..0000000000
--- a/Tools/buildbot/external.bat
+++ /dev/null
@@ -1,3 +0,0 @@
-@echo This script is no longer used and may be removed in the future.
-@echo Please use PCbuild\get_externals.bat instead.
-@"%~dp0..\..\PCbuild\get_externals.bat" %*
diff --git a/Tools/buildbot/test-amd64.bat b/Tools/buildbot/test-amd64.bat
deleted file mode 100644
index e48329c0b3..0000000000
--- a/Tools/buildbot/test-amd64.bat
+++ /dev/null
@@ -1,6 +0,0 @@
-@rem Formerly used by the buildbot "test" step.
-@echo This script is no longer used and may be removed in the future.
-@echo To get the same effect as this script, use
-@echo PCbuild\rt.bat -q -d -x64 -uall -rwW
-@echo or use `test.bat` in this directory and pass `-x64` as an argument.
-call "%~dp0test.bat" -x64 %*
diff --git a/Tools/buildbot/test.bat b/Tools/buildbot/test.bat
index ff7d167e6a..a32d38b5ec 100644
--- a/Tools/buildbot/test.bat
+++ b/Tools/buildbot/test.bat
@@ -4,7 +4,7 @@ setlocal
set here=%~dp0
set rt_opts=-q -d
-set regrtest_args=
+set regrtest_args=-j1
:CheckOpts
if "%1"=="-x64" (set rt_opts=%rt_opts% %1) & shift & goto CheckOpts
@@ -16,4 +16,4 @@ 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 --timeout=3600 %regrtest_args%
+call "%here%..\..\PCbuild\rt.bat" %rt_opts% -uall -rwW --slowest --timeout=1200 %regrtest_args%
diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index f615ed9a44..75ac673737 100755
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -644,7 +644,7 @@ class CLanguage(Language):
default_return_converter = (not f.return_converter or
f.return_converter.type == 'PyObject *')
- positional = parameters and (parameters[-1].kind == inspect.Parameter.POSITIONAL_ONLY)
+ positional = parameters and parameters[-1].is_positional_only()
all_boring_objects = False # yes, this will be false if there are 0 parameters, it's fine
first_optional = len(parameters)
for i, p in enumerate(parameters):
@@ -661,7 +661,7 @@ class CLanguage(Language):
new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
meth_o = (len(parameters) == 1 and
- parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and
+ parameters[0].is_positional_only() and
not converters[0].is_optional() and
not new_or_init)
@@ -705,6 +705,11 @@ class CLanguage(Language):
{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
""")
+ parser_prototype_fastcall = normalize_snippet("""
+ static PyObject *
+ {c_basename}({self_type}{self_name}, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
+ """)
+
parser_prototype_varargs = normalize_snippet("""
static PyObject *
{c_basename}({self_type}{self_name}, PyObject *args)
@@ -743,7 +748,10 @@ class CLanguage(Language):
return output()
def insert_keywords(s):
- return linear_format(s, declarations="static char *_keywords[] = {{{keywords}, NULL}};\n{declarations}")
+ return linear_format(s, declarations=
+ 'static const char * const _keywords[] = {{{keywords}, NULL}};\n'
+ 'static _PyArg_Parser _parser = {{"{format_units}:{name}", _keywords, 0}};\n'
+ '{declarations}')
if not parameters:
# no parameters, METH_NOARGS
@@ -797,8 +805,9 @@ class CLanguage(Language):
""" % argname)
parser_definition = parser_body(parser_prototype, normalize_snippet("""
- if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments}))
+ if (!PyArg_Parse(%s, "{format_units}:{name}", {parse_arguments})) {{
goto exit;
+ }}
""" % argname, indent=4))
elif has_option_groups:
@@ -822,8 +831,9 @@ class CLanguage(Language):
parser_definition = parser_body(parser_prototype, normalize_snippet("""
if (!PyArg_UnpackTuple(args, "{name}",
{unpack_min}, {unpack_max},
- {parse_arguments}))
+ {parse_arguments})) {{
goto exit;
+ }}
""", indent=4))
elif positional:
@@ -835,10 +845,24 @@ class CLanguage(Language):
parser_definition = parser_body(parser_prototype, normalize_snippet("""
if (!PyArg_ParseTuple(args, "{format_units}:{name}",
- {parse_arguments}))
+ {parse_arguments})) {{
goto exit;
+ }}
""", indent=4))
+ elif not new_or_init:
+ flags = "METH_FASTCALL"
+
+ parser_prototype = parser_prototype_fastcall
+
+ body = normalize_snippet("""
+ if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
+ {parse_arguments})) {{
+ goto exit;
+ }}
+ """, indent=4)
+ parser_definition = parser_body(parser_prototype, body)
+ parser_definition = insert_keywords(parser_definition)
else:
# positional-or-keyword arguments
flags = "METH_VARARGS|METH_KEYWORDS"
@@ -846,15 +870,12 @@ class CLanguage(Language):
parser_prototype = parser_prototype_keyword
body = normalize_snippet("""
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "{format_units}:{name}", _keywords,
- {parse_arguments}))
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
+ {parse_arguments})) {{
goto exit;
- """, indent=4)
- parser_definition = parser_body(parser_prototype, normalize_snippet("""
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "{format_units}:{name}", _keywords,
- {parse_arguments}))
- goto exit;
- """, indent=4))
+ }}
+ """, indent=4)
+ parser_definition = parser_body(parser_prototype, body)
parser_definition = insert_keywords(parser_definition)
@@ -878,13 +899,15 @@ class CLanguage(Language):
if not parses_keywords:
fields.insert(0, normalize_snippet("""
- if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs))
+ if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) {{
goto exit;
+ }}
""", indent=4))
if not parses_positional:
fields.insert(0, normalize_snippet("""
- if ({self_type_check}!_PyArg_NoPositional("{name}", args))
+ if ({self_type_check}!_PyArg_NoPositional("{name}", args)) {{
goto exit;
+ }}
""", indent=4))
parser_definition = parser_body(parser_prototype, *fields)
@@ -1032,8 +1055,9 @@ class CLanguage(Language):
s = """
case {count}:
- if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments}))
+ if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) {{
goto exit;
+ }}
{group_booleans}
break;
"""[1:]
@@ -1067,7 +1091,7 @@ class CLanguage(Language):
last_group = 0
first_optional = len(selfless)
- positional = selfless and selfless[-1].kind == inspect.Parameter.POSITIONAL_ONLY
+ positional = selfless and selfless[-1].is_positional_only()
new_or_init = f.kind in (METHOD_NEW, METHOD_INIT)
default_return_converter = (not f.return_converter or
f.return_converter.type == 'PyObject *')
@@ -1216,7 +1240,7 @@ def OverrideStdioWith(stdout):
def create_regex(before, after, word=True, whole_line=True):
"""Create an re object for matching marker lines."""
- group_re = "\w+" if word else ".+"
+ group_re = r"\w+" if word else ".+"
pattern = r'{}({}){}'
if whole_line:
pattern = '^' + pattern + '$'
@@ -2359,7 +2383,10 @@ class CConverter(metaclass=CConverterAutoRegister):
data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip())
# keywords
- data.keywords.append(parameter.name)
+ if parameter.is_positional_only():
+ data.keywords.append('')
+ else:
+ data.keywords.append(parameter.name)
# format_units
if self.is_optional() and '|' not in data.format_units:
@@ -2572,21 +2599,21 @@ class unsigned_long_converter(CConverter):
if not bitwise:
fail("Unsigned longs must be bitwise (for now).")
-class PY_LONG_LONG_converter(CConverter):
- type = 'PY_LONG_LONG'
+class long_long_converter(CConverter):
+ type = 'long long'
default_type = int
format_unit = 'L'
c_ignored_default = "0"
-class unsigned_PY_LONG_LONG_converter(CConverter):
- type = 'unsigned PY_LONG_LONG'
+class unsigned_long_long_converter(CConverter):
+ type = 'unsigned long long'
default_type = int
format_unit = 'K'
c_ignored_default = "0"
def converter_init(self, *, bitwise=False):
if not bitwise:
- fail("Unsigned PY_LONG_LONGs must be bitwise (for now).")
+ fail("Unsigned long long must be bitwise (for now).")
class Py_ssize_t_converter(CConverter):
type = 'Py_ssize_t'
@@ -2676,7 +2703,7 @@ class str_converter(CConverter):
def cleanup(self):
if self.encoding:
name = ensure_legal_c_identifier(self.name)
- return "".join(["if (", name, ")\n PyMem_FREE(", name, ");\n"])
+ return "".join(["if (", name, ") {\n PyMem_FREE(", name, ");\n}\n"])
#
# This is the fourth or fifth rewrite of registering all the
@@ -2786,7 +2813,7 @@ class Py_buffer_converter(CConverter):
def cleanup(self):
name = ensure_legal_c_identifier(self.name)
- return "".join(["if (", name, ".obj)\n PyBuffer_Release(&", name, ");\n"])
+ return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"])
def correct_name_for_self(f):
@@ -2959,10 +2986,10 @@ class CReturnConverter(metaclass=CReturnConverterAutoRegister):
data.return_value = name
def err_occurred_if(self, expr, data):
- data.return_conversion.append('if (({}) && PyErr_Occurred())\n goto exit;\n'.format(expr))
+ data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr))
def err_occurred_if_null_pointer(self, variable, data):
- data.return_conversion.append('if ({} == NULL)\n goto exit;\n'.format(variable))
+ data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable))
def render(self, function, data):
"""
@@ -2977,8 +3004,9 @@ class NoneType_return_converter(CReturnConverter):
def render(self, function, data):
self.declare(data)
data.return_conversion.append('''
-if (_return_value != Py_None)
+if (_return_value != Py_None) {
goto exit;
+}
return_value = Py_None;
Py_INCREF(Py_None);
'''.strip())
@@ -3183,6 +3211,7 @@ class DSLParser:
self.state = self.state_dsl_start
self.parameter_indent = None
self.keyword_only = False
+ self.positional_only = False
self.group = 0
self.parameter_state = self.ps_start
self.seen_positional_with_default = False
@@ -3561,8 +3590,8 @@ class DSLParser:
# "parameter_state". (Previously the code was a miasma of ifs and
# separate boolean state variables.) The states are:
#
- # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] / <- line
- # 01 2 3 4 5 6 7 <- state transitions
+ # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line
+ # 01 2 3 4 5 6 <- state transitions
#
# 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
# 1: ps_left_square_before. left square brackets before required parameters.
@@ -3573,9 +3602,8 @@ class DSLParser:
# now must have default values.
# 5: ps_group_after. in a group, after required parameters.
# 6: ps_right_square_after. right square brackets after required parameters.
- # 7: ps_seen_slash. seen slash.
ps_start, ps_left_square_before, ps_group_before, ps_required, \
- ps_optional, ps_group_after, ps_right_square_after, ps_seen_slash = range(8)
+ ps_optional, ps_group_after, ps_right_square_after = range(7)
def state_parameters_start(self, line):
if self.ignore_line(line):
@@ -3854,9 +3882,6 @@ class DSLParser:
return name, False, kwargs
def parse_special_symbol(self, symbol):
- if self.parameter_state == self.ps_seen_slash:
- fail("Function " + self.function.name + " specifies " + symbol + " after /, which is unsupported.")
-
if symbol == '*':
if self.keyword_only:
fail("Function " + self.function.name + " uses '*' more than once.")
@@ -3883,13 +3908,15 @@ class DSLParser:
else:
fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)")
elif symbol == '/':
+ if self.positional_only:
+ fail("Function " + self.function.name + " uses '/' more than once.")
+ self.positional_only = True
# ps_required and ps_optional are allowed here, that allows positional-only without option groups
# to work (and have default values!)
if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group:
fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)")
if self.keyword_only:
fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
- self.parameter_state = self.ps_seen_slash
# fixup preceding parameters
for p in self.function.parameters.values():
if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)):
@@ -3977,23 +4004,20 @@ class DSLParser:
# populate "right_bracket_count" field for every parameter
assert parameters, "We should always have a self parameter. " + repr(f)
assert isinstance(parameters[0].converter, self_converter)
+ # self is always positional-only.
+ assert parameters[0].is_positional_only()
parameters[0].right_bracket_count = 0
- parameters_after_self = parameters[1:]
- if parameters_after_self:
- # for now, the only way Clinic supports positional-only parameters
- # is if all of them are positional-only...
- #
- # ... except for self! self is always positional-only.
-
- positional_only_parameters = [p.kind == inspect.Parameter.POSITIONAL_ONLY for p in parameters_after_self]
- if parameters_after_self[0].kind == inspect.Parameter.POSITIONAL_ONLY:
- assert all(positional_only_parameters)
- for p in parameters:
- p.right_bracket_count = abs(p.group)
+ positional_only = True
+ for p in parameters[1:]:
+ if not p.is_positional_only():
+ positional_only = False
+ else:
+ assert positional_only
+ if positional_only:
+ p.right_bracket_count = abs(p.group)
else:
# don't put any right brackets around non-positional-only parameters, ever.
- for p in parameters_after_self:
- p.right_bracket_count = 0
+ p.right_bracket_count = 0
right_bracket_count = 0
diff --git a/Tools/demo/ss1.py b/Tools/demo/ss1.py
index c51f041933..bf88820dca 100755
--- a/Tools/demo/ss1.py
+++ b/Tools/demo/ss1.py
@@ -413,7 +413,7 @@ class FormulaCell(BaseCell):
def renumber(self, x1, y1, x2, y2, dx, dy):
out = []
- for part in re.split('(\w+)', self.formula):
+ 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()
diff --git a/Tools/freeze/freeze.py b/Tools/freeze/freeze.py
index 44edd57b4f..d602f58539 100755
--- a/Tools/freeze/freeze.py
+++ b/Tools/freeze/freeze.py
@@ -124,9 +124,7 @@ def main():
# default the exclude list for each platform
if win: exclude = exclude + [
- 'dos', 'dospath', 'mac', 'macpath', 'macfs', 'MACFS', 'posix',
- 'ce',
- ]
+ 'dos', 'dospath', 'mac', 'macpath', 'macfs', 'MACFS', 'posix', ]
fail_import = exclude[:]
@@ -218,7 +216,7 @@ def main():
ishome = os.path.exists(os.path.join(prefix, 'Python', 'ceval.c'))
# locations derived from options
- version = sys.version[:3]
+ version = '%d.%d' % sys.version_info[:2]
flagged_version = version + sys.abiflags
if win:
extensions_c = 'frozen_extensions.c'
diff --git a/Tools/freeze/winmakemakefile.py b/Tools/freeze/winmakemakefile.py
index 390d8ac144..9bb3e6e173 100644
--- a/Tools/freeze/winmakemakefile.py
+++ b/Tools/freeze/winmakemakefile.py
@@ -95,7 +95,7 @@ def realwork(vars, moddefns, target):
print()
print('$(temp_dir):')
- print(' if not exist $(temp_dir)\. mkdir $(temp_dir)')
+ print(r' if not exist $(temp_dir)\. mkdir $(temp_dir)')
print()
objects = []
@@ -106,7 +106,7 @@ def realwork(vars, moddefns, target):
base = os.path.basename(file)
base, ext = os.path.splitext(base)
objects.append(base + ".obj")
- print('$(temp_dir)\%s.obj: "%s"' % (base, file))
+ 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) \\")
@@ -126,7 +126,7 @@ def realwork(vars, moddefns, target):
print() ; print()
print("OBJS=", end=' ')
- for obj in objects: print('"$(temp_dir)\%s"' % (obj), end=' ')
+ for obj in objects: print(r'"$(temp_dir)\%s"' % (obj), end=' ')
print() ; print()
print("LIBS=", end=' ')
diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py
index ed515c0017..cc1afbe16d 100755
--- a/Tools/gdb/libpython.py
+++ b/Tools/gdb/libpython.py
@@ -44,7 +44,7 @@ The module also extends gdb with some python-specific commands.
# NOTE: some gdbs are linked with Python 3, so this file should be dual-syntax
# compatible (2.6+ and 3.0+). See #19308.
-from __future__ import print_function, with_statement
+from __future__ import print_function
import gdb
import os
import locale
@@ -666,8 +666,9 @@ class PyDictObjectPtr(PyObjectPtr):
'''
keys = self.field('ma_keys')
values = self.field('ma_values')
- for i in safe_range(keys['dk_size']):
- ep = keys['dk_entries'].address + i
+ entries, nentries = self._get_entries(keys)
+ for i in safe_range(nentries):
+ ep = entries[i]
if long(values):
pyop_value = PyObjectPtr.from_pyobject_ptr(values[i])
else:
@@ -707,6 +708,33 @@ class PyDictObjectPtr(PyObjectPtr):
pyop_value.write_repr(out, visited)
out.write('}')
+ def _get_entries(self, keys):
+ dk_nentries = int(keys['dk_nentries'])
+ dk_size = int(keys['dk_size'])
+ try:
+ # <= Python 3.5
+ return keys['dk_entries'], dk_size
+ except gdb.error:
+ # >= Python 3.6
+ pass
+
+ if dk_size <= 0xFF:
+ offset = dk_size
+ elif dk_size <= 0xFFFF:
+ offset = 2 * dk_size
+ elif dk_size <= 0xFFFFFFFF:
+ offset = 4 * dk_size
+ else:
+ offset = 8 * dk_size
+
+ ent_addr = keys['dk_indices']['as_1'].address
+ ent_addr = ent_addr.cast(_type_unsigned_char_ptr()) + offset
+ ent_ptr_t = gdb.lookup_type('PyDictKeyEntry').pointer()
+ ent_addr = ent_addr.cast(ent_ptr_t)
+
+ return ent_addr, dk_nentries
+
+
class PyListObjectPtr(PyObjectPtr):
_typename = 'PyListObject'
@@ -1464,23 +1492,38 @@ class Frame(object):
'''
if self.is_waiting_for_gil():
return 'Waiting for the GIL'
- elif self.is_gc_collect():
+
+ if self.is_gc_collect():
return 'Garbage-collecting'
- else:
- # Detect invocations of PyCFunction instances:
- older = self.older()
- if older and older._gdbframe.name() == 'PyCFunction_Call':
- # Within that frame:
- # "func" is the local containing the PyObject* of the
- # PyCFunctionObject instance
- # "f" is the same value, but cast to (PyCFunctionObject*)
- # "self" is the (PyObject*) of the 'self'
- try:
- # Use the prettyprinter for the func:
- func = older._gdbframe.read_var('func')
- return str(func)
- except RuntimeError:
- return 'PyCFunction invocation (unable to read "func")'
+
+ # Detect invocations of PyCFunction instances:
+ older = self.older()
+ if not older:
+ return False
+
+ caller = older._gdbframe.name()
+ if not caller:
+ return False
+
+ if caller == 'PyCFunction_Call':
+ # Within that frame:
+ # "func" is the local containing the PyObject* of the
+ # PyCFunctionObject instance
+ # "f" is the same value, but cast to (PyCFunctionObject*)
+ # "self" is the (PyObject*) of the 'self'
+ try:
+ # Use the prettyprinter for the func:
+ func = older._gdbframe.read_var('func')
+ return str(func)
+ except RuntimeError:
+ return 'PyCFunction invocation (unable to read "func")'
+
+ elif caller == '_PyCFunction_FastCallDict':
+ try:
+ func = older._gdbframe.read_var('func_obj')
+ return str(func)
+ except RuntimeError:
+ return 'PyCFunction invocation (unable to read "func_obj")'
# This frame isn't worth reporting:
return False
diff --git a/Tools/hg/hgtouch.py b/Tools/hg/hgtouch.py
index 119d812148..fbca469ba9 100644
--- a/Tools/hg/hgtouch.py
+++ b/Tools/hg/hgtouch.py
@@ -7,7 +7,6 @@ syntax of make rules.
In addition to the dependency syntax, #-comments are supported.
"""
-from __future__ import with_statement
import errno
import os
import time
diff --git a/Tools/i18n/pygettext.py b/Tools/i18n/pygettext.py
index da4243887d..8ef5ff8a3e 100755
--- a/Tools/i18n/pygettext.py
+++ b/Tools/i18n/pygettext.py
@@ -156,7 +156,8 @@ If `inputfile' is -, standard input is read.
""")
import os
-import imp
+import importlib.machinery
+import importlib.util
import sys
import glob
import time
@@ -263,8 +264,7 @@ def _visit_pyfiles(list, dirname, names):
# get extension for python source files
if '_py_ext' not in globals():
global _py_ext
- _py_ext = [triple[0] for triple in imp.get_suffixes()
- if triple[2] == imp.PY_SOURCE][0]
+ _py_ext = importlib.machinery.SOURCE_SUFFIXES[0]
# don't recurse into CVS directories
if 'CVS' in names:
@@ -277,45 +277,6 @@ def _visit_pyfiles(list, dirname, names):
)
-def _get_modpkg_path(dotted_name, pathlist=None):
- """Get the filesystem path for a module or a package.
-
- Return the file system path to a file for a module, and to a directory for
- a package. Return None if the name is not found, or is a builtin or
- extension module.
- """
- # split off top-most name
- parts = dotted_name.split('.', 1)
-
- if len(parts) > 1:
- # we have a dotted path, import top-level package
- try:
- file, pathname, description = imp.find_module(parts[0], pathlist)
- if file: file.close()
- except ImportError:
- return None
-
- # check if it's indeed a package
- if description[2] == imp.PKG_DIRECTORY:
- # recursively handle the remaining name parts
- pathname = _get_modpkg_path(parts[1], [pathname])
- else:
- pathname = None
- else:
- # plain name
- try:
- file, pathname, description = imp.find_module(
- dotted_name, pathlist)
- if file:
- file.close()
- if description[2] not in [imp.PY_SOURCE, imp.PKG_DIRECTORY]:
- pathname = None
- except ImportError:
- pathname = None
-
- return pathname
-
-
def getFilesForName(name):
"""Get a list of module files for a filename, a module or package name,
or a directory.
@@ -330,7 +291,11 @@ def getFilesForName(name):
return list
# try to find module or package
- name = _get_modpkg_path(name)
+ try:
+ spec = importlib.util.find_spec(name)
+ name = spec.origin
+ except ImportError:
+ name = None
if not name:
return []
diff --git a/Tools/msi/buildrelease.bat b/Tools/msi/buildrelease.bat
index f296e613ac..4659a32b83 100644
--- a/Tools/msi/buildrelease.bat
+++ b/Tools/msi/buildrelease.bat
@@ -35,7 +35,7 @@ set BUILDX86=
set BUILDX64=
set TARGET=Rebuild
set TESTTARGETDIR=
-set PGO=
+set PGO=-m test -q --pgo
set BUILDNUGET=1
set BUILDZIP=1
@@ -57,6 +57,7 @@ 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
@@ -109,21 +110,14 @@ exit /B 0
@echo off
if "%1" EQU "x86" (
- call "%PCBUILD%env.bat" x86
+ set PGO=
set BUILD=%PCBUILD%win32\
set BUILD_PLAT=Win32
set OUTDIR_PLAT=win32
set OBJDIR_PLAT=x86
-) else if "%~2" NEQ "" (
- call "%PCBUILD%env.bat" amd64
- set PGO=%~2
- set BUILD=%PCBUILD%amd64-pgo\
- set BUILD_PLAT=x64
- set OUTDIR_PLAT=amd64
- set OBJDIR_PLAT=x64
) else (
- call "%PCBUILD%env.bat" amd64
set BUILD=%PCBUILD%amd64\
+ set PGO=%~2
set BUILD_PLAT=x64
set OUTDIR_PLAT=amd64
set OBJDIR_PLAT=x64
@@ -135,6 +129,12 @@ if exist "%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%"
@@ -146,45 +146,38 @@ if not "%CERTNAME%" EQU "" (
) else (
set CERTOPTS=
)
-
+if not "%PGO%" EQU "" (
+ set PGOOPTS=--pgo-job "%PGO%"
+) else (
+ set PGOOPTS=
+)
if not "%SKIPBUILD%" EQU "1" (
- @call "%PCBUILD%build.bat" -e -p %BUILD_PLAT% -d -t %TARGET% %CERTOPTS%
+ @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
-
- if "%PGO%" EQU "" (
- @call "%PCBUILD%build.bat" -e -p %BUILD_PLAT% -t %TARGET% %CERTOPTS%
- ) else (
- @call "%PCBUILD%build.bat" -e -p %BUILD_PLAT% -c PGInstrument -t %TARGET% %CERTOPTS%
- @if errorlevel 1 exit /B
-
- @del "%BUILD%*.pgc"
- if "%PGO%" EQU "default" (
- "%BUILD%python.exe" -m test -q --pgo
- ) else if "%PGO%" EQU "default2" (
- "%BUILD%python.exe" -m test -r -q --pgo
- "%BUILD%python.exe" -m test -r -q --pgo
- ) else if "%PGO%" EQU "default10" (
- for /L %%i in (0, 1, 9) do "%BUILD%python.exe" -m test -q -r --pgo
- ) else if "%PGO%" EQU "pybench" (
- "%BUILD%python.exe" "%PCBUILD%..\Tools\pybench\pybench.py"
- ) else (
- "%BUILD%python.exe" %PGO%
- )
-
- @call "%PCBUILD%build.bat" -e -p %BUILD_PLAT% -c PGUpdate -t Build %CERTOPTS%
- )
+
+ @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
)
-set BUILDOPTS=/p:BuildForRelease=true /p:DownloadUrl=%DOWNLOAD_URL% /p:DownloadUrlBase=%DOWNLOAD_URL_BASE% /p:ReleaseUri=%RELEASE_URI%
-if "%PGO%" NEQ "" set BUILDOPTS=%BUILDOPTS% /p:PGOBuildPath=%BUILD%
-msbuild "%D%launcher\launcher.wixproj" /p:Platform=x86 %CERTOPTS% /p:ReleaseUri=%RELEASE_URI%
-msbuild "%D%bundle\releaselocal.wixproj" /t:Rebuild /p:Platform=%1 %BUILDOPTS% %CERTOPTS% /p:RebuildAll=true
+call "%PCBUILD%env.bat"
+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 "%PCBUILD%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 /p:Platform=%1 %BUILDOPTS% %CERTOPTS% /p:RebuildAll=false
+msbuild "%D%bundle\releaseweb.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=false
if errorlevel 1 exit /B
if defined BUILDZIP (
@@ -210,7 +203,7 @@ 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]
+echo [--skip-build] [--skip-doc] [--skip-nuget] [--skip-zip] [--skip-pgo]
echo [--download DOWNLOAD URL] [--test TARGETDIR]
echo [-h]
echo.
@@ -220,9 +213,10 @@ 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 --pgo Build x64 installers using PGO
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
@@ -230,13 +224,8 @@ 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 as well as the
-echo following shortcuts:
-echo Shortcut Description
-echo default Test suite with --pgo
-echo default2 2x test suite with --pgo and randomized test order
-echo default10 10x test suite with --pgo and randomized test order
-echo pybench pybench script
+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
diff --git a/Tools/msi/bundle/Default.thm b/Tools/msi/bundle/Default.thm
index 4d9c97a194..1c0bd08eec 100644
--- a/Tools/msi/bundle/Default.thm
+++ b/Tools/msi/bundle/Default.thm
@@ -116,10 +116,11 @@
<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="-31" Height="100" FontId="3" DisablePrefix="yes"></Hypertext>
+ <Hypertext Name="SuccessText" X="205" Y="71" Width="-71" Height="150" FontId="3" DisablePrefix="yes"></Hypertext>
- <Text Name="SuccessRestartText" X="205" Y="-100" Width="-11" Height="34" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.SuccessRestartText)</Text>
- <Button Name="LaunchButton" X="185" Y="-50" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xF" HideWhenDisabled="yes">#(loc.SuccessLaunchButton)</Button>
+ <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>
diff --git a/Tools/msi/bundle/Default.wxl b/Tools/msi/bundle/Default.wxl
index ed792460e6..43506d6100 100644
--- a/Tools/msi/bundle/Default.wxl
+++ b/Tools/msi/bundle/Default.wxl
@@ -142,4 +142,7 @@ Please &lt;a href="https://www.bing.com/search?q=how%20to%20install%20windows%20
<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>
diff --git a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp
index 6a67ee211c..e88981fc3a 100644
--- a/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp
+++ b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp
@@ -11,10 +11,6 @@
#include "pch.h"
static const LPCWSTR PYBA_WINDOW_CLASS = L"PythonBA";
-static const LPCWSTR PYBA_VARIABLE_LAUNCH_TARGET_PATH = L"LaunchTarget";
-static const LPCWSTR PYBA_VARIABLE_LAUNCH_TARGET_ELEVATED_ID = L"LaunchTargetElevatedId";
-static const LPCWSTR PYBA_VARIABLE_LAUNCH_ARGUMENTS = L"LaunchArguments";
-static const LPCWSTR PYBA_VARIABLE_LAUNCH_HIDDEN = L"LaunchHidden";
static const DWORD PYBA_ACQUIRE_PERCENTAGE = 30;
static const LPCWSTR PYBA_VARIABLE_BUNDLE_FILE_VERSION = L"WixBundleFileVersion";
@@ -129,11 +125,11 @@ enum CONTROL_ID {
ID_PROGRESS_CANCEL_BUTTON,
// Success page
- ID_LAUNCH_BUTTON,
ID_SUCCESS_TEXT,
ID_SUCCESS_RESTART_TEXT,
ID_SUCCESS_RESTART_BUTTON,
ID_SUCCESS_CANCEL_BUTTON,
+ ID_SUCCESS_MAX_PATH_BUTTON,
// Failure page
ID_FAILURE_LOGFILE_LINK,
@@ -188,11 +184,11 @@ static THEME_ASSIGN_CONTROL_ID CONTROL_ID_NAMES[] = {
{ ID_OVERALL_PROGRESS_TEXT, L"OverallProgressText" },
{ ID_PROGRESS_CANCEL_BUTTON, L"ProgressCancelButton" },
- { ID_LAUNCH_BUTTON, L"LaunchButton" },
{ ID_SUCCESS_TEXT, L"SuccessText" },
{ ID_SUCCESS_RESTART_TEXT, L"SuccessRestartText" },
{ ID_SUCCESS_RESTART_BUTTON, L"SuccessRestartButton" },
{ ID_SUCCESS_CANCEL_BUTTON, L"SuccessCancelButton" },
+ { ID_SUCCESS_MAX_PATH_BUTTON, L"SuccessMaxPathButton" },
{ ID_FAILURE_LOGFILE_LINK, L"FailureLogFileLink" },
{ ID_FAILURE_MESSAGE_TEXT, L"FailureMessageText" },
@@ -436,6 +432,11 @@ class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
case ID_UNINSTALL_BUTTON:
OnPlan(BOOTSTRAPPER_ACTION_UNINSTALL);
break;
+
+ case ID_SUCCESS_MAX_PATH_BUTTON:
+ EnableMaxPathSupport();
+ ThemeControlEnable(_theme, ID_SUCCESS_MAX_PATH_BUTTON, FALSE);
+ break;
}
LExit:
@@ -533,9 +534,8 @@ class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
}
void SuccessPage_Show() {
- // on the "Success" page, check if the restart or launch button should be enabled.
+ // on the "Success" page, check if the restart button should be enabled.
BOOL showRestartButton = FALSE;
- BOOL launchTargetExists = FALSE;
LOC_STRING *successText = nullptr;
HRESULT hr = S_OK;
@@ -543,8 +543,6 @@ class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
if (BOOTSTRAPPER_RESTART_PROMPT == _command.restart) {
showRestartButton = TRUE;
}
- } else if (ThemeControlExists(_theme, ID_LAUNCH_BUTTON)) {
- launchTargetExists = BalStringVariableExists(PYBA_VARIABLE_LAUNCH_TARGET_PATH);
}
switch (_plannedAction) {
@@ -571,9 +569,41 @@ class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
}
}
- ThemeControlEnable(_theme, ID_LAUNCH_BUTTON, launchTargetExists && BOOTSTRAPPER_ACTION_UNINSTALL < _plannedAction);
ThemeControlEnable(_theme, ID_SUCCESS_RESTART_TEXT, showRestartButton);
ThemeControlEnable(_theme, ID_SUCCESS_RESTART_BUTTON, showRestartButton);
+
+ if (_command.action != BOOTSTRAPPER_ACTION_INSTALL ||
+ !IsWindowsVersionOrGreater(10, 0, 0)) {
+ ThemeControlEnable(_theme, ID_SUCCESS_MAX_PATH_BUTTON, FALSE);
+ } else {
+ DWORD dataType = 0, buffer = 0, bufferLen = sizeof(buffer);
+ HKEY hKey;
+ LRESULT res = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE,
+ L"SYSTEM\\CurrentControlSet\\Control\\FileSystem",
+ 0,
+ KEY_READ,
+ &hKey
+ );
+ if (res == ERROR_SUCCESS) {
+ res = RegQueryValueExW(hKey, L"LongPathsEnabled", nullptr, &dataType,
+ (LPBYTE)&buffer, &bufferLen);
+ RegCloseKey(hKey);
+ }
+ else {
+ BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Failed to open SYSTEM\\CurrentControlSet\\Control\\FileSystem: error code %d", res);
+ }
+ if (res == ERROR_SUCCESS && dataType == REG_DWORD && buffer == 0) {
+ ThemeControlElevates(_theme, ID_SUCCESS_MAX_PATH_BUTTON, TRUE);
+ }
+ else {
+ if (res == ERROR_SUCCESS)
+ BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Failed to read LongPathsEnabled value: error code %d", res);
+ else
+ BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Hiding MAX_PATH button because it is already enabled");
+ ThemeControlEnable(_theme, ID_SUCCESS_MAX_PATH_BUTTON, FALSE);
+ }
+ }
}
void FailurePage_Show() {
@@ -626,6 +656,34 @@ class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
ThemeControlEnable(_theme, ID_FAILURE_RESTART_BUTTON, showRestartButton);
}
+ static void EnableMaxPathSupport() {
+ LPWSTR targetDir = nullptr, defaultDir = nullptr;
+ HRESULT hr = BalGetStringVariable(L"TargetDir", &targetDir);
+ if (FAILED(hr) || !targetDir || !targetDir[0]) {
+ BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to get TargetDir");
+ return;
+ }
+
+ LPWSTR pythonw = nullptr;
+ StrAllocFormatted(&pythonw, L"%ls\\pythonw.exe", targetDir);
+ if (!pythonw || !pythonw[0]) {
+ BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to construct pythonw.exe path");
+ return;
+ }
+
+ LPCWSTR arguments = L"-c \"import winreg; "
+ "winreg.SetValueEx("
+ "winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, "
+ "r'SYSTEM\\CurrentControlSet\\Control\\FileSystem'), "
+ "'LongPathsEnabled', "
+ "None, "
+ "winreg.REG_DWORD, "
+ "1"
+ ")\"";
+ BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Executing %ls %ls", pythonw, arguments);
+ HINSTANCE res = ShellExecuteW(0, L"runas", pythonw, arguments, NULL, SW_HIDE);
+ BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "return code 0x%08x", res);
+ }
public: // IBootstrapperApplication
virtual STDMETHODIMP OnStartup() {
@@ -1216,12 +1274,6 @@ public: // IBootstrapperApplication
}
virtual STDMETHODIMP_(void) OnLaunchApprovedExeComplete(__in HRESULT hrStatus, __in DWORD /*processId*/) {
- if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hrStatus) {
- //try with ShelExec next time
- OnClickLaunchButton();
- } else {
- ::PostMessageW(_hWnd, WM_CLOSE, 0, 0);
- }
}
@@ -1867,10 +1919,6 @@ private:
switch (LOWORD(wParam)) {
// Customize commands
// Success/failure commands
- case ID_LAUNCH_BUTTON:
- pBA->OnClickLaunchButton();
- return 0;
-
case ID_SUCCESS_RESTART_BUTTON: __fallthrough;
case ID_FAILURE_RESTART_BUTTON:
pBA->OnClickRestartButton();
@@ -2372,69 +2420,6 @@ private:
}
- //
- // OnClickLaunchButton - launch the app from the success page.
- //
- void OnClickLaunchButton() {
- HRESULT hr = S_OK;
- LPWSTR sczUnformattedLaunchTarget = nullptr;
- LPWSTR sczLaunchTarget = nullptr;
- LPWSTR sczLaunchTargetElevatedId = nullptr;
- LPWSTR sczUnformattedArguments = nullptr;
- LPWSTR sczArguments = nullptr;
- int nCmdShow = SW_SHOWNORMAL;
-
- hr = BalGetStringVariable(PYBA_VARIABLE_LAUNCH_TARGET_PATH, &sczUnformattedLaunchTarget);
- BalExitOnFailure1(hr, "Failed to get launch target variable '%ls'.", PYBA_VARIABLE_LAUNCH_TARGET_PATH);
-
- hr = BalFormatString(sczUnformattedLaunchTarget, &sczLaunchTarget);
- BalExitOnFailure1(hr, "Failed to format launch target variable: %ls", sczUnformattedLaunchTarget);
-
- if (BalStringVariableExists(PYBA_VARIABLE_LAUNCH_TARGET_ELEVATED_ID)) {
- hr = BalGetStringVariable(PYBA_VARIABLE_LAUNCH_TARGET_ELEVATED_ID, &sczLaunchTargetElevatedId);
- BalExitOnFailure1(hr, "Failed to get launch target elevated id '%ls'.", PYBA_VARIABLE_LAUNCH_TARGET_ELEVATED_ID);
- }
-
- if (BalStringVariableExists(PYBA_VARIABLE_LAUNCH_ARGUMENTS)) {
- hr = BalGetStringVariable(PYBA_VARIABLE_LAUNCH_ARGUMENTS, &sczUnformattedArguments);
- BalExitOnFailure1(hr, "Failed to get launch arguments '%ls'.", PYBA_VARIABLE_LAUNCH_ARGUMENTS);
- }
-
- if (BalStringVariableExists(PYBA_VARIABLE_LAUNCH_HIDDEN)) {
- nCmdShow = SW_HIDE;
- }
-
- if (sczLaunchTargetElevatedId && !_triedToLaunchElevated) {
- _triedToLaunchElevated = TRUE;
- hr = _engine->LaunchApprovedExe(_hWnd, sczLaunchTargetElevatedId, sczUnformattedArguments, 0);
- if (FAILED(hr)) {
- BalLogError(hr, "Failed to launch elevated target: %ls", sczLaunchTargetElevatedId);
-
- //try with ShelExec next time
- OnClickLaunchButton();
- }
- } else {
- if (sczUnformattedArguments) {
- hr = BalFormatString(sczUnformattedArguments, &sczArguments);
- BalExitOnFailure1(hr, "Failed to format launch arguments variable: %ls", sczUnformattedArguments);
- }
-
- hr = ShelExec(sczLaunchTarget, sczArguments, L"open", nullptr, nCmdShow, _hWnd, nullptr);
- BalExitOnFailure1(hr, "Failed to launch target: %ls", sczLaunchTarget);
-
- ::PostMessageW(_hWnd, WM_CLOSE, 0, 0);
- }
-
- LExit:
- StrSecureZeroFreeString(sczArguments);
- ReleaseStr(sczUnformattedArguments);
- ReleaseStr(sczLaunchTargetElevatedId);
- StrSecureZeroFreeString(sczLaunchTarget);
- ReleaseStr(sczUnformattedLaunchTarget);
-
- return;
- }
-
//
// OnClickRestartButton - allows the restart and closes the app.
@@ -3157,7 +3142,6 @@ public:
_taskbarButtonCreatedMessage = UINT_MAX;
_taskbarButtonOK = FALSE;
_showingInternalUIThisPackage = FALSE;
- _triedToLaunchElevated = FALSE;
_suppressPaint = FALSE;
@@ -3242,7 +3226,6 @@ private:
UINT _taskbarButtonCreatedMessage;
BOOL _taskbarButtonOK;
BOOL _showingInternalUIThisPackage;
- BOOL _triedToLaunchElevated;
BOOL _suppressPaint;
diff --git a/Tools/msi/bundle/bundle.ico b/Tools/msi/bundle/bundle.ico
deleted file mode 100644
index 1ab629eff2..0000000000
--- a/Tools/msi/bundle/bundle.ico
+++ /dev/null
Binary files differ
diff --git a/Tools/msi/bundle/bundle.wxs b/Tools/msi/bundle/bundle.wxs
index eda088404f..02a456b3fd 100644
--- a/Tools/msi/bundle/bundle.wxs
+++ b/Tools/msi/bundle/bundle.wxs
@@ -5,7 +5,7 @@
<Bundle Name="!(loc.FullProductName)"
UpgradeCode="$(var.CoreUpgradeCode)"
Version="$(var.Version)"
- IconSourceFile="bundle.ico"
+ IconSourceFile="..\..\..\PC\icons\setup.ico"
Manufacturer="!(loc.Manufacturer)"
AboutUrl="http://www.python.org/"
DisableModify="button"
diff --git a/Tools/msi/common.wxs b/Tools/msi/common.wxs
index 4efad6562a..398d94a24d 100644
--- a/Tools/msi/common.wxs
+++ b/Tools/msi/common.wxs
@@ -1,6 +1,10 @@
<?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>
@@ -16,10 +20,12 @@
<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) ?>
@@ -40,7 +46,7 @@
<Fragment>
<!-- Include an icon for the Programs and Features dialog -->
- <Icon Id="ARPIcon" SourceFile="!(bindpath.src)PC\pycon.ico" />
+ <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" />
@@ -57,7 +63,9 @@
<!-- Top-level directories -->
<Fragment>
<DirectoryRef Id="InstallDirectory">
- <Directory Id="DLLs" Name="DLLs" />
+ <Directory Id="DLLs" Name="DLLs">
+ <Directory Id="Catalogs" />
+ </Directory>
</DirectoryRef>
</Fragment>
diff --git a/Tools/msi/common_en-US.wxl_template b/Tools/msi/common_en-US.wxl_template
index 8d03526882..c95c271c27 100644
--- a/Tools/msi/common_en-US.wxl_template
+++ b/Tools/msi/common_en-US.wxl_template
@@ -14,4 +14,5 @@
<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>
diff --git a/Tools/msi/exe/exe.wixproj b/Tools/msi/exe/exe.wixproj
index d26a603268..24df0f5f7a 100644
--- a/Tools/msi/exe/exe.wixproj
+++ b/Tools/msi/exe/exe.wixproj
@@ -14,6 +14,7 @@
<ItemGroup>
<Compile Include="exe.wxs" />
<Compile Include="exe_files.wxs" />
+ <Compile Include="exe_reg.wxs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="*.wxl" />
diff --git a/Tools/msi/exe/exe.wxs b/Tools/msi/exe/exe.wxs
index 154cee5c47..03d43c6032 100644
--- a/Tools/msi/exe/exe.wxs
+++ b/Tools/msi/exe/exe.wxs
@@ -9,6 +9,7 @@
<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" />
@@ -24,7 +25,6 @@
WorkingDirectory="InstallDirectory" />
<RemoveFolder Id="Remove_MenuDir" Directory="MenuDir" On="uninstall" />
<RegistryKey Root="HKMU" Key="[REGISTRYKEY]">
- <RegistryValue Key="InstallPath\InstallGroup" Type="string" Value="!(loc.ProductName)" KeyPath="yes" />
<RegistryValue Key="InstalledFeatures" Name="Shortcuts" Type="string" Value="$(var.Version)" />
</RegistryKey>
</Component>
diff --git a/Tools/msi/exe/exe_d.wixproj b/Tools/msi/exe/exe_d.wixproj
index 27545caf7d..cf085bed4d 100644
--- a/Tools/msi/exe/exe_d.wixproj
+++ b/Tools/msi/exe/exe_d.wixproj
@@ -10,6 +10,7 @@
<ItemGroup>
<Compile Include="exe_d.wxs" />
<Compile Include="exe_files.wxs" />
+ <Compile Include="exe_reg.wxs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="*.wxl" />
diff --git a/Tools/msi/exe/exe_en-US.wxl_template b/Tools/msi/exe/exe_en-US.wxl_template
index 577fbe51a5..1f9e290394 100644
--- a/Tools/msi/exe/exe_en-US.wxl_template
+++ b/Tools/msi/exe/exe_en-US.wxl_template
@@ -4,4 +4,5 @@
<String Id="ShortDescriptor">executable</String>
<String Id="ShortcutName">Python {{ShortVersion}} ({{Bitness}})</String>
<String Id="ShortcutDescription">Launches the !(loc.ProductName) interpreter.</String>
+ <String Id="SupportUrl">http://www.python.org/</String>
</WixLocalization>
diff --git a/Tools/msi/exe/exe_files.wxs b/Tools/msi/exe/exe_files.wxs
index 9e47b5d980..01385874fa 100644
--- a/Tools/msi/exe/exe_files.wxs
+++ b/Tools/msi/exe/exe_files.wxs
@@ -28,6 +28,9 @@
</Component>
<Component Id="pythonw.exe" Directory="InstallDirectory" Guid="$(var.PythonwExeComponentGuid)">
<File Name="pythonw.exe" KeyPath="yes" />
+ <RegistryKey Root="HKMU" Key="[REGISTRYKEY]">
+ <RegistryValue Key="InstallPath" Name="WindowedExecutablePath" Type="string" Value="[#pythonw.exe]" KeyPath="no" />
+ </RegistryKey>
</Component>
<Component Id="vcruntime140.dll" Directory="InstallDirectory" Guid="*">
<File Name="vcruntime140.dll" Source="!(bindpath.redist)vcruntime140.dll" KeyPath="yes" />
@@ -66,10 +69,13 @@
<Fragment>
<ComponentGroup Id="exe_icons">
<Component Id="py.ico" Directory="DLLs" Guid="*">
- <File Name="py.ico" Source="!(bindpath.src)PC\py.ico" KeyPath="yes" />
+ <File Name="py.ico" Source="!(bindpath.src)PC\icons\py.ico" KeyPath="yes" />
</Component>
<Component Id="pyc.ico" Directory="DLLs" Guid="*">
- <File Name="pyc.ico" Source="!(bindpath.src)PC\pyc.ico" KeyPath="yes" />
+ <File Name="pyc.ico" Source="!(bindpath.src)PC\icons\pyc.ico" KeyPath="yes" />
+ </Component>
+ <Component Id="pyd.ico" Directory="DLLs" Guid="*">
+ <File Name="pyd.ico" Source="!(bindpath.src)PC\icons\pyd.ico" KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>
diff --git a/Tools/msi/exe/exe_pdb.wixproj b/Tools/msi/exe/exe_pdb.wixproj
index 4f4c869926..bf1213e9d4 100644
--- a/Tools/msi/exe/exe_pdb.wixproj
+++ b/Tools/msi/exe/exe_pdb.wixproj
@@ -10,6 +10,7 @@
<ItemGroup>
<Compile Include="exe_pdb.wxs" />
<Compile Include="exe_files.wxs" />
+ <Compile Include="exe_reg.wxs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="*.wxl" />
diff --git a/Tools/msi/exe/exe_reg.wxs b/Tools/msi/exe/exe_reg.wxs
new file mode 100644
index 0000000000..4443c21554
--- /dev/null
+++ b/Tools/msi/exe/exe_reg.wxs
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+ <Fragment>
+ <PropertyRef Id="ROOTREGISTRYKEY" />
+ <PropertyRef Id="REGISTRYKEY" />
+
+ <ComponentGroup Id="exe_reg">
+ <Component Id="CommonPythonRegistration" Directory="InstallDirectory" Guid="$(var.CommonPythonRegComponentGuid)">
+ <RegistryKey Root="HKMU" Key="[ROOTREGISTRYKEY]">
+ <RegistryValue Name="DisplayName" Type="string" Value="!(loc.Manufacturer)" KeyPath="yes" />
+ <RegistryValue Name="SupportUrl" Type="string" Value="!(loc.ManufacturerSupportUrl)" KeyPath="no" />
+ </RegistryKey>
+ </Component>
+ <Component Id="PythonRegistration" Directory="InstallDirectory" Guid="$(var.PythonRegComponentGuid)">
+ <RegistryKey Root="HKMU" Key="[REGISTRYKEY]">
+ <RegistryValue Name="DisplayName" Type="string" Value="!(loc.ShortcutName)" KeyPath="yes" />
+ <RegistryValue Name="SupportUrl" Type="string" Value="!(loc.SupportUrl)" KeyPath="no" />
+ <RegistryValue Name="Version" Type="string" Value="$(var.LongVersion)" KeyPath="no" />
+ <RegistryValue Name="SysVersion" Type="string" Value="$(var.ShortVersion)" KeyPath="no" />
+ <RegistryValue Name="SysArchitecture" Type="string" Value="$(var.PlatformArchitecture)" KeyPath="no" />
+ </RegistryKey>
+ </Component>
+ </ComponentGroup>
+ </Fragment>
+</Wix>
diff --git a/Tools/msi/launcher/launcher.wixproj b/Tools/msi/launcher/launcher.wixproj
index 01a9dcb29e..8935ce88a7 100644
--- a/Tools/msi/launcher/launcher.wixproj
+++ b/Tools/msi/launcher/launcher.wixproj
@@ -5,7 +5,7 @@
<SchemaVersion>2.0</SchemaVersion>
<OutputName>launcher</OutputName>
<OutputType>Package</OutputType>
- <DefineConstants>UpgradeCode=1B68A0EC-4DD3-5134-840E-73854B0863F1;$(DefineConstants)</DefineConstants>
+ <DefineConstants>UpgradeCode=1B68A0EC-4DD3-5134-840E-73854B0863F1;SuppressUpgradeTable=1;$(DefineConstants)</DefineConstants>
<IgnoreCommonWxlTemplates>true</IgnoreCommonWxlTemplates>
<SuppressICEs>ICE80</SuppressICEs>
</PropertyGroup>
diff --git a/Tools/msi/launcher/launcher.wxs b/Tools/msi/launcher/launcher.wxs
index ebd875cd9a..7de131a3ed 100644
--- a/Tools/msi/launcher/launcher.wxs
+++ b/Tools/msi/launcher/launcher.wxs
@@ -5,7 +5,10 @@
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<Property Id="Suppress_TARGETDIR_Check" Value="1" />
- <PropertyRef Id="ARPPRODUCTICON" />
+ <Icon Id="ARPIcon" SourceFile="!(bindpath.src)PC\icons\launcher.ico" />
+ <Property Id="ARPPRODUCTICON" Value="ARPIcon" />
+ <Property Id="ARPNOMODIFY" Value="1" />
+ <Property Id="DISABLEADVTSHORTCUTS" Value="1" />
<Feature Id="DefaultFeature" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
<ComponentGroupRef Id="launcher_exe" Primary="yes" />
@@ -26,18 +29,21 @@
<Custom Before="SetLauncherInstallDirectoryLM" Action="SetLauncherInstallDirectoryCU">NOT Installed AND NOT ALLUSERS=1</Custom>
<Custom Before="CostFinalize" Action="SetLauncherInstallDirectoryLM">NOT Installed AND ALLUSERS=1</Custom>
- <RemoveExistingProducts After="InstallValidate">UPGRADE or REMOVE_350_LAUNCHER</RemoveExistingProducts>
+ <RemoveExistingProducts After="InstallValidate">UPGRADE or REMOVE_350_LAUNCHER or REMOVE_360A1_LAUNCHER</RemoveExistingProducts>
</InstallExecuteSequence>
+ <!-- Upgrade all versions of the launcher -->
+ <Upgrade Id="$(var.UpgradeCode)">
+ <UpgradeVersion Property="DOWNGRADE" Minimum="$(var.Version)" IncludeMinimum="no" OnlyDetect="yes" />
+ <UpgradeVersion Property="UPGRADE" Minimum="0.0.0.0" IncludeMinimum="yes" Maximum="$(var.Version)" IncludeMaximum="no" />
+ </Upgrade>
<!-- Python 3.5.0 shipped with a different UpgradeCode -->
<Upgrade Id="A71530B9-E89D-53DB-9C2D-C6D7551876D8">
<UpgradeVersion Minimum="0.0.0.0" Property="REMOVE_350_LAUNCHER" />
</Upgrade>
<!-- Python 3.6.0a1 shipped with a different UpgradeCode -->
<Upgrade Id="394750C0-7880-5A8F-999F-933965FBCFB4">
- <UpgradeVersion Maximum="$(var.Version)" Property="REMOVE_360A1_LAUNCHER" />
- <UpgradeVersion Minimum="$(var.Version)" Property="BLOCK_360A1_LAUNCHER" />
+ <UpgradeVersion Minimum="0.0.0.0" Property="REMOVE_360A1_LAUNCHER" />
</Upgrade>
- <Condition Message="!(loc.NoDowngrade)">Installed OR NOT BLOCK_360A1_LAUNCHER</Condition>
</Product>
</Wix>
diff --git a/Tools/msi/launcher/launcher_en-US.wxl b/Tools/msi/launcher/launcher_en-US.wxl
index e4c1aaa9fa..a7e3827c52 100644
--- a/Tools/msi/launcher/launcher_en-US.wxl
+++ b/Tools/msi/launcher/launcher_en-US.wxl
@@ -11,6 +11,7 @@
<String Id="PythonFileDescription">Python File</String>
<String Id="PythonNoConFileDescription">Python File (no console)</String>
<String Id="PythonCompiledFileDescription">Compiled Python File</String>
+ <String Id="PythonExtensionDescription">Python Extension Module</String>
<String Id="PythonArchiveFileDescription">Python Zip Application File</String>
<String Id="PythonNoConArchiveFileDescription">Python Zip Application File (no console)</String>
</WixLocalization>
diff --git a/Tools/msi/launcher/launcher_reg.wxs b/Tools/msi/launcher/launcher_reg.wxs
index 981961ab0d..dace97ee58 100644
--- a/Tools/msi/launcher/launcher_reg.wxs
+++ b/Tools/msi/launcher/launcher_reg.wxs
@@ -27,14 +27,18 @@
</ProgId>
<RegistryValue Root="HKCR" Key="Python.CompiledFile\shellex\DropHandler" Value="{BEA218D2-6950-497B-9434-61683EC065FE}" Type="string" />
- <ProgId Id="Python.ArchiveFile" Description="!(loc.PythonArchiveFileDescription)" Advertise="no" Icon="py.exe" IconIndex="1">
+ <ProgId Id="Python.Extension" Description="!(loc.PythonExtensionDescription)" Advertise="no" Icon="py.exe" IconIndex="3">
+ <Extension Id="pyd" />
+ </ProgId>
+
+ <ProgId Id="Python.ArchiveFile" Description="!(loc.PythonArchiveFileDescription)" Advertise="no" Icon="py.exe" IconIndex="5">
<Extension Id="pyz" ContentType="application/x-zip-compressed">
<Verb Id="open" TargetFile="py.exe" Argument="&quot;%L&quot; %*" />
</Extension>
</ProgId>
<RegistryValue Root="HKCR" Key="Python.ArchiveFile\shellex\DropHandler" Value="{BEA218D2-6950-497B-9434-61683EC065FE}" Type="string" />
- <ProgId Id="Python.NoConArchiveFile" Description="!(loc.PythonNoConArchiveFileDescription)" Advertise="no" Icon="py.exe" IconIndex="1">
+ <ProgId Id="Python.NoConArchiveFile" Description="!(loc.PythonNoConArchiveFileDescription)" Advertise="no" Icon="py.exe" IconIndex="5">
<Extension Id="pyzw" ContentType="application/x-zip-compressed">
<Verb Id="open" TargetFile="pyw.exe" Argument="&quot;%L&quot; %*" />
</Extension>
diff --git a/Tools/msi/lib/lib.wixproj b/Tools/msi/lib/lib.wixproj
index 64e58787b8..26311ea327 100644
--- a/Tools/msi/lib/lib.wixproj
+++ b/Tools/msi/lib/lib.wixproj
@@ -27,6 +27,7 @@
<TargetBase>$(PySourcePath)Lib</TargetBase>
<Target_>Lib\</Target_>
<Group>lib_py</Group>
+ <IncludeInCat>true</IncludeInCat>
</InstallFiles>
</ItemGroup>
diff --git a/Tools/msi/lib/lib.wxs b/Tools/msi/lib/lib.wxs
index 2b04bcb304..2a3b9ecfee 100644
--- a/Tools/msi/lib/lib.wxs
+++ b/Tools/msi/lib/lib.wxs
@@ -11,6 +11,7 @@
<ComponentGroupRef Id="lib_py" />
<ComponentGroupRef Id="lib_files" />
<ComponentGroupRef Id="lib_extensions" />
+ <ComponentGroupRef Id="lib_cat" />
<ComponentRef Id="OptionalFeature" />
</Feature>
</Product>
diff --git a/Tools/msi/lib/lib_files.wxs b/Tools/msi/lib/lib_files.wxs
index a992784939..a83f544db6 100644
--- a/Tools/msi/lib/lib_files.wxs
+++ b/Tools/msi/lib/lib_files.wxs
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
- <?define exts=pyexpat;select;unicodedata;winsound;_bz2;_elementtree;_socket;_ssl;_msi;_ctypes;_hashlib;_multiprocessing;_lzma;_decimal;_overlapped;_sqlite3 ?>
+ <?define exts=pyexpat;select;unicodedata;winsound;_bz2;_elementtree;_socket;_ssl;_msi;_ctypes;_hashlib;_multiprocessing;_lzma;_decimal;_overlapped;_sqlite3;_asyncio ?>
<Fragment>
<ComponentGroup Id="lib_extensions">
<?foreach ext in $(var.exts)?>
@@ -63,16 +63,17 @@
<RegistryValue Key="PythonPath" Type="string" Value="[Lib];[DLLs]" />
</RegistryKey>
</Component>
- <Component Id="Lib_site_packages_README" Directory="Lib_site_packages" Guid="*">
- <File Id="Lib_site_packages_README" Name="README.txt" Source="!(bindpath.src)Lib\site-packages\README" KeyPath="yes" />
- </Component>
<Component Id="Lib2to3_pickle_remove" Directory="Lib_lib2to3" Guid="$(var.RemoveLib2to3PickleComponentGuid)">
<RemoveFile Id="Lib2to3_pickle_remove_files" Name="*.pickle" On="uninstall" />
<RemoveFolder Id="Lib2to3_pickle_remove_folder" On="uninstall" />
</Component>
</ComponentGroup>
- <DirectoryRef Id="Lib">
- <Directory Id="Lib_site_packages" Name="site-packages" />
- </DirectoryRef>
+ </Fragment>
+ <Fragment>
+ <ComponentGroup Id="lib_cat">
+ <Component Id="lib_cat" Directory="Catalogs" Guid="*">
+ <File Name="python_lib.cat" KeyPath="yes" />
+ </Component>
+ </ComponentGroup>
</Fragment>
</Wix>
diff --git a/Tools/msi/make_zip.proj b/Tools/msi/make_zip.proj
index 1af6dd2868..f78e6ffa28 100644
--- a/Tools/msi/make_zip.proj
+++ b/Tools/msi/make_zip.proj
@@ -16,7 +16,7 @@
<TargetPath>$(OutputPath)\$(TargetName)$(TargetExt)</TargetPath>
<CleanCommand>rmdir /q/s "$(IntermediateOutputPath)\zip_$(ArchName)"</CleanCommand>
<Arguments>"$(PythonExe)" "$(MSBuildThisFileDirectory)\make_zip.py"</Arguments>
- <Arguments>$(Arguments) -e -o "$(TargetPath)" -t "$(IntermediateOutputPath)\zip_$(ArchName)" -b "$(BuildPath.TrimEnd('\'))"</Arguments>
+ <Arguments>$(Arguments) -e -o "$(TargetPath)" -t "$(IntermediateOutputPath)\zip_$(ArchName)" -a $(ArchName)</Arguments>
<Environment>set DOC_FILENAME=python$(PythonVersion).chm
set VCREDIST_PATH=$(VS140COMNTOOLS)\..\..\VC\redist\$(Platform)\Microsoft.VC140.CRT</Environment>
</PropertyGroup>
diff --git a/Tools/msi/make_zip.py b/Tools/msi/make_zip.py
index 6a03cbef0d..710e4a5c23 100644
--- a/Tools/msi/make_zip.py
+++ b/Tools/msi/make_zip.py
@@ -20,6 +20,7 @@ DEBUG_FILES = {
'_ctypes_test',
'_testbuffer',
'_testcapi',
+ '_testconsole',
'_testimportmultiple',
'_testmultiphase',
'xxlimited',
@@ -45,11 +46,16 @@ EXCLUDE_FILE_FROM_LIBRARY = {
}
EXCLUDE_FILE_FROM_LIBS = {
+ 'liblzma',
'ssleay',
'libeay',
'python3stub',
}
+EXCLUDED_FILES = {
+ 'pyshellext',
+}
+
def is_not_debug(p):
if DEBUG_RE.search(p.name):
return False
@@ -57,7 +63,7 @@ def is_not_debug(p):
if TKTCL_RE.search(p.name):
return False
- return p.stem.lower() not in DEBUG_FILES
+ return p.stem.lower() not in DEBUG_FILES and p.stem.lower() not in EXCLUDED_FILES
def is_not_debug_or_python(p):
return is_not_debug(p) and not PYTHON_DLL_RE.search(p.name)
@@ -67,8 +73,6 @@ def include_in_lib(p):
if p.is_dir():
if name in EXCLUDE_FROM_LIBRARY:
return False
- if name.startswith('plat-'):
- return False
if name == 'test' and p.parts[-2].lower() == 'lib':
return False
if name in {'test', 'tests'} and p.parts[-3].lower() == 'lib':
@@ -99,25 +103,27 @@ def include_in_tools(p):
return p.suffix.lower() in {'.py', '.pyw', '.txt'}
+BASE_NAME = 'python{0.major}{0.minor}'.format(sys.version_info)
+
FULL_LAYOUT = [
- ('/', '$build', 'python.exe', is_not_debug),
- ('/', '$build', 'pythonw.exe', is_not_debug),
- ('/', '$build', 'python{0.major}.dll'.format(sys.version_info), is_not_debug),
- ('/', '$build', 'python{0.major}{0.minor}.dll'.format(sys.version_info), is_not_debug),
- ('DLLs/', '$build', '*.pyd', is_not_debug),
- ('DLLs/', '$build', '*.dll', is_not_debug_or_python),
+ ('/', 'PCBuild/$arch', 'python.exe', is_not_debug),
+ ('/', 'PCBuild/$arch', 'pythonw.exe', is_not_debug),
+ ('/', 'PCBuild/$arch', 'python{}.dll'.format(sys.version_info.major), is_not_debug),
+ ('/', 'PCBuild/$arch', '{}.dll'.format(BASE_NAME), is_not_debug),
+ ('DLLs/', 'PCBuild/$arch', '*.pyd', is_not_debug),
+ ('DLLs/', 'PCBuild/$arch', '*.dll', is_not_debug_or_python),
('include/', 'include', '*.h', None),
('include/', 'PC', 'pyconfig.h', None),
('Lib/', 'Lib', '**/*', include_in_lib),
- ('libs/', '$build', '*.lib', include_in_libs),
+ ('libs/', 'PCBuild/$arch', '*.lib', include_in_libs),
('Tools/', 'Tools', '**/*', include_in_tools),
]
EMBED_LAYOUT = [
- ('/', '$build', 'python*.exe', is_not_debug),
- ('/', '$build', '*.pyd', is_not_debug),
- ('/', '$build', '*.dll', is_not_debug),
- ('python{0.major}{0.minor}.zip'.format(sys.version_info), 'Lib', '**/*', include_in_embeddable_lib),
+ ('/', 'PCBuild/$arch', 'python*.exe', is_not_debug),
+ ('/', 'PCBuild/$arch', '*.pyd', is_not_debug),
+ ('/', 'PCBuild/$arch', '*.dll', is_not_debug),
+ ('{}.zip'.format(BASE_NAME), 'Lib', '**/*', include_in_embeddable_lib),
]
if os.getenv('DOC_FILENAME'):
@@ -181,15 +187,15 @@ def main():
parser.add_argument('-o', '--out', metavar='file', help='The name of the output archive', type=Path, default=None)
parser.add_argument('-t', '--temp', metavar='dir', help='A directory to temporarily extract files into', type=Path, default=None)
parser.add_argument('-e', '--embed', help='Create an embedding layout', action='store_true', default=False)
- parser.add_argument('-b', '--build', help='Specify the build directory', type=Path)
+ parser.add_argument('-a', '--arch', help='Specify the architecture to use (win32/amd64)', type=str, default="win32")
ns = parser.parse_args()
source = ns.source or (Path(__file__).resolve().parent.parent.parent)
out = ns.out
- build = ns.build
+ arch = ns.arch
assert isinstance(source, Path)
assert not out or isinstance(out, Path)
- assert isinstance(build, Path)
+ assert isinstance(arch, str)
if ns.temp:
temp = ns.temp
@@ -212,10 +218,7 @@ def main():
try:
for t, s, p, c in layout:
- if s == '$build':
- fs = build
- else:
- fs = source / s
+ fs = source / s.replace("$arch", arch)
files = rglob(fs, p, c)
extra_files = []
if s == 'Lib' and p == '**/*':
@@ -226,8 +229,13 @@ def main():
copied = copy_to_layout(temp / t.rstrip('/'), chain(files, extra_files))
print('Copied {} files'.format(copied))
- with open(str(temp / 'pyvenv.cfg'), 'w') as f:
- print('applocal = true', file=f)
+ if ns.embed:
+ with open(str(temp / (BASE_NAME + '._pth')), 'w') as f:
+ print(BASE_NAME + '.zip', file=f)
+ print('.', file=f)
+ print('', file=f)
+ print('# Uncomment to run site.main() automatically', file=f)
+ print('#import site', file=f)
if out:
total = copy_to_layout(out, rglob(temp, '**/*', None))
diff --git a/Tools/msi/msi.props b/Tools/msi/msi.props
index 0cf7c7779f..60abba1f7b 100644
--- a/Tools/msi/msi.props
+++ b/Tools/msi/msi.props
@@ -11,6 +11,7 @@
<Configuration Condition="'$(Configuration)' == ''">Release</Configuration>
<Platform Condition="'$(Platform)' == ''">x86</Platform>
<InstallScope Condition="'$(InstallScope)' != 'perMachine'">perUser</InstallScope>
+ <_MakeCatCommand Condition="'$(_MakeCatCommand)' == ''">makecat</_MakeCatCommand>
</PropertyGroup>
<Import Project="wix.props" />
@@ -69,6 +70,8 @@
<PropertyGroup>
<Bitness>32-bit</Bitness>
<Bitness Condition="$(Platform) == 'x64'">64-bit</Bitness>
+ <PlatformArchitecture>32bit</PlatformArchitecture>
+ <PlatformArchitecture Condition="$(Platform) == 'x64'">64bit</PlatformArchitecture>
<DefineConstants>
$(DefineConstants);
Version=$(InstallerVersion);
@@ -79,6 +82,7 @@
UpgradeMinimumVersion=$(MajorVersionNumber).$(MinorVersionNumber).0.0;
NextMajorVersionNumber=$(MajorVersionNumber).$([msbuild]::Add($(MinorVersionNumber), 1)).0.0;
Bitness=$(Bitness);
+ PlatformArchitecture=$(PlatformArchitecture);
PyDebugExt=$(PyDebugExt);
PyArchExt=$(PyArchExt);
PyTestExt=$(PyTestExt);
@@ -100,6 +104,7 @@
<Group>generated_filelist</Group>
<Condition></Condition>
<DiskId></DiskId>
+ <IncludeInCat>false</IncludeInCat>
</InstallFiles>
<LinkerBindInputPaths>
<Visible>false</Visible>
@@ -155,6 +160,12 @@
<_Uuid Include="RemoveLib2to3PickleComponentGuid">
<Uri>lib2to3/pickles</Uri>
</_Uuid>
+ <_Uuid Include="CommonPythonRegComponentGuid">
+ <Uri>registry</Uri>
+ </_Uuid>
+ <_Uuid Include="PythonRegComponentGuid">
+ <Uri>registry/$(OutputName)</Uri>
+ </_Uuid>
</ItemGroup>
<Target Name="_GenerateGuids" AfterTargets="PrepareForBuild" Condition="$(TargetName) != 'launcher'">
<PropertyGroup>
diff --git a/Tools/msi/msi.targets b/Tools/msi/msi.targets
index 86be35badb..9283a1ed6c 100644
--- a/Tools/msi/msi.targets
+++ b/Tools/msi/msi.targets
@@ -12,8 +12,10 @@
<_Source>%(Source)$([msbuild]::MakeRelative(%(SourceBase), %(FullPath)))</_Source>
<_Target>%(Target_)$([msbuild]::MakeRelative(%(TargetBase), %(FullPath)))</_Target>
</InstallFiles>
+
+ <_CatalogFiles Include="@(InstallFiles)" Condition="%(InstallFiles.IncludeInCat) and ''!=$([System.IO.File]::ReadAllText(%(InstallFiles.FullPath)))" />
</ItemGroup>
-
+
<WriteLinesToFile File="$(_FileListTarget)" Lines="@(InstallFiles->'&quot;%(_Source)&quot;,&quot;%(_Target)&quot;,&quot;%(Group)&quot;,&quot;%(DiskId)&quot;,&quot;%(Condition)&quot;')" Overwrite="true" />
<Exec Command='"$(PythonExe)" csv_to_wxs.py "$(_FileListTarget)" "$(_InstallFilesTarget)"'
WorkingDirectory="$(MSBuildThisFileDirectory)" />
@@ -24,6 +26,35 @@
</ItemGroup>
</Target>
+ <Target Name="GenerateCatalog" AfterTargets="ProcessInstallFiles" Condition="'@(_CatalogFiles)' != ''">
+ <PropertyGroup>
+ <_CatFileSourceTarget>$(IntermediateOutputPath)$(MSBuildProjectName).cdf</_CatFileSourceTarget>
+ <_CatFileTarget>$(IntermediateOutputPath)python_$(MSBuildProjectName).cat</_CatFileTarget>
+ <_CatFile>[CatalogHeader]
+Name=$([System.IO.Path]::GetFileName($(_CatFileTarget)))
+ResultDir=$([System.IO.Path]::GetDirectoryName($(_CatFileTarget)))
+PublicVersion=1
+CatalogVersion=2
+HashAlgorithms=SHA256
+PageHashes=false
+EncodingType=
+
+[CatalogFiles]
+@(_CatalogFiles->'&lt;HASH&gt;%(Filename)%(Extension)=%(FullPath)','
+')
+</_CatFile>
+ </PropertyGroup>
+
+ <WriteLinesToFile File="$(_CatFileSourceTarget)" Lines="$(_CatFile)" Overwrite="true" />
+ <Exec Command='$(_MakeCatCommand) "$(_CatFileSourceTarget)"' WorkingDirectory="$(MSBuildThisFileDirectory)" />
+ <Exec Command='$(_SignCommand) "$(_CatFileTarget)"' WorkingDirectory="$(MSBuildThisFileDirectory)"
+ Condition="Exists($(_CatFileTarget)) and '$(_SignCommand)' != ''" />
+
+ <ItemGroup>
+ <FileWrites Include="$(_CatFileSourceTarget);$(_CatFileTarget)" />
+ </ItemGroup>
+ </Target>
+
<Target Name="_TransformWxlTemplates" AfterTargets="PrepareForBuild" Inputs="@(WxlTemplate);$(PySourcePath)include\patchlevel.h" Outputs="$(IntermediateOutputPath)%(Filename).wxl">
<PropertyGroup Condition="'@(WxlTemplate)' != ''">
<_Content>$([System.IO.File]::ReadAllText(%(WxlTemplate.FullPath)).Replace(`{{ShortVersion}}`, `$(MajorVersionNumber).$(MinorVersionNumber)$(PyTestExt)`).Replace(`{{LongVersion}}`, `$(PythonVersion)$(PyTestExt)`).Replace(`{{Bitness}}`, `$(Bitness)`))</_Content>
diff --git a/Tools/msi/test/test_files.wxs b/Tools/msi/test/test_files.wxs
index e803aa0f55..82a9115f75 100644
--- a/Tools/msi/test/test_files.wxs
+++ b/Tools/msi/test/test_files.wxs
@@ -1,77 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+ <?define exts=_testcapi;_ctypes_test;_testbuffer;_testimportmultiple;_testmultiphase;_testconsole ?>
<Fragment>
<ComponentGroup Id="test_extensions">
- <Component Id="_testcapi.pyd" Directory="DLLs" Guid="*">
- <File Id="_testcapi.pyd" Name="_testcapi.pyd" KeyPath="yes" />
- </Component>
- <Component Id="_ctypes_test.pyd" Directory="DLLs" Guid="*">
- <File Id="_ctypes_test.pyd" Name="_ctypes_test.pyd" KeyPath="yes" />
- </Component>
- <Component Id="_testbuffer.pyd" Directory="DLLs" Guid="*">
- <File Id="_testbuffer.pyd" Name="_testbuffer.pyd" KeyPath="yes" />
- </Component>
- <Component Id="_testimportmultiple.pyd" Directory="DLLs" Guid="*">
- <File Id="_testimportmultiple.pyd" Name="_testimportmultiple.pyd" KeyPath="yes" />
- </Component>
- <Component Id="_testmultiphase.pyd" Directory="DLLs" Guid="*">
- <File Id="_testmultiphase.pyd" Name="_testmultiphase.pyd" KeyPath="yes" />
+ <?foreach ext in $(var.exts)?>
+
+ <Component Id="$(var.ext).pyd" Directory="DLLs" Guid="*">
+ <File Name="$(var.ext).pyd" KeyPath="yes" />
</Component>
+
+ <?endforeach ?>
</ComponentGroup>
</Fragment>
<Fragment>
<ComponentGroup Id="test_extensions_symbols">
- <Component Id="_testcapi.pdb" Directory="DLLs" Guid="*">
- <File Id="_testcapi.pdb" Name="_testcapi.pdb" />
- </Component>
- <Component Id="_ctypes_test.pdb" Directory="DLLs" Guid="*">
- <File Id="_ctypes_test.pdb" Name="_ctypes_test.pdb" />
- </Component>
- <Component Id="_testbuffer.pdb" Directory="DLLs" Guid="*">
- <File Id="_testbuffer.pdb" Name="_testbuffer.pdb" />
- </Component>
- <Component Id="_testimportmultiple.pdb" Directory="DLLs" Guid="*">
- <File Id="_testimportmultiple.pdb" Name="_testimportmultiple.pdb" />
- </Component>
- <Component Id="_testmultiphase.pdb" Directory="DLLs" Guid="*">
- <File Id="_testmultiphase.pdb" Name="_testmultiphase.pdb" />
+ <?foreach ext in $(var.exts)?>
+
+ <Component Id="$(var.ext).pdb" Directory="DLLs" Guid="*">
+ <File Name="$(var.ext).pdb" />
</Component>
+
+ <?endforeach ?>
</ComponentGroup>
</Fragment>
<Fragment>
<ComponentGroup Id="test_extensions_d">
- <Component Id="_testcapi_d.pyd" Directory="DLLs" Guid="*">
- <File Id="_testcapi_d.pyd" Name="_testcapi_d.pyd" />
- </Component>
- <Component Id="_ctypes_test_d.pyd" Directory="DLLs" Guid="*">
- <File Id="_ctypes_test_d.pyd" Name="_ctypes_test_d.pyd" />
- </Component>
- <Component Id="_testbuffer_d.pyd" Directory="DLLs" Guid="*">
- <File Id="_testbuffer_d.pyd" Name="_testbuffer_d.pyd" />
- </Component>
- <Component Id="_testimportmultiple_d.pyd" Directory="DLLs" Guid="*">
- <File Id="_testimportmultiple_d.pyd" Name="_testimportmultiple_d.pyd" />
- </Component>
- <Component Id="_testmultiphase_d.pyd" Directory="DLLs" Guid="*">
- <File Id="_testmultiphase_d.pyd" Name="_testmultiphase_d.pyd" />
- </Component>
- <Component Id="_testcapi_d.pdb" Directory="DLLs" Guid="*">
- <File Id="_testcapi_d.pdb" Name="_testcapi_d.pdb" />
- </Component>
- <Component Id="_ctypes_test_d.pdb" Directory="DLLs" Guid="*">
- <File Id="_ctypes_test_d.pdb" Name="_ctypes_test_d.pdb" />
- </Component>
- <Component Id="_testbuffer_d.pdb" Directory="DLLs" Guid="*">
- <File Id="_testbuffer_d.pdb" Name="_testbuffer_d.pdb" />
- </Component>
- <Component Id="_testimportmultiple_d.pdb" Directory="DLLs" Guid="*">
- <File Id="_testimportmultiple_d.pdb" Name="_testimportmultiple_d.pdb" />
+ <?foreach ext in $(var.exts)?>
+
+ <Component Id="$(var.ext)_d.pyd" Directory="DLLs" Guid="*">
+ <File Name="$(var.ext)_d.pyd" />
</Component>
- <Component Id="_testmultiphase_d.pdb" Directory="DLLs" Guid="*">
- <File Id="_testmultiphase_d.pdb" Name="_testmultiphase_d.pdb" />
+ <Component Id="$(var.ext)_d.pdb" Directory="DLLs" Guid="*">
+ <File Name="$(var.ext)_d.pdb" />
</Component>
+
+ <?endforeach ?>
</ComponentGroup>
</Fragment>
</Wix>
diff --git a/Tools/msi/tools/tools.wixproj b/Tools/msi/tools/tools.wixproj
index f43cf3309e..b7fc41ee92 100644
--- a/Tools/msi/tools/tools.wixproj
+++ b/Tools/msi/tools/tools.wixproj
@@ -36,6 +36,7 @@
<TargetBase>$(PySourcePath)</TargetBase>
<Target_></Target_>
<Group>tools_py</Group>
+ <IncludeInCat>true</IncludeInCat>
</InstallFiles>
</ItemGroup>
diff --git a/Tools/msi/tools/tools.wxs b/Tools/msi/tools/tools.wxs
index 8f8418a46c..7a805d0612 100644
--- a/Tools/msi/tools/tools.wxs
+++ b/Tools/msi/tools/tools.wxs
@@ -9,6 +9,7 @@
<Feature Id="DefaultFeature" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
<ComponentGroupRef Id="tools_py" />
<ComponentGroupRef Id="tools_scripts" />
+ <ComponentGroupRef Id="tools_cat" />
<ComponentRef Id="OptionalFeature" />
</Feature>
</Product>
diff --git a/Tools/msi/tools/tools_files.wxs b/Tools/msi/tools/tools_files.wxs
index 3ae0db2e1f..9c76b1b444 100644
--- a/Tools/msi/tools/tools_files.wxs
+++ b/Tools/msi/tools/tools_files.wxs
@@ -13,4 +13,11 @@
</Component>
</ComponentGroup>
</Fragment>
+ <Fragment>
+ <ComponentGroup Id="tools_cat">
+ <Component Id="tools_cat" Directory="Catalogs" Guid="*">
+ <File Name="python_tools.cat" KeyPath="yes" />
+ </Component>
+ </ComponentGroup>
+ </Fragment>
</Wix>
diff --git a/Tools/nuget/make_pkg.proj b/Tools/nuget/make_pkg.proj
index 81b84f9884..d7e932cee5 100644
--- a/Tools/nuget/make_pkg.proj
+++ b/Tools/nuget/make_pkg.proj
@@ -23,7 +23,7 @@
<CleanCommand>rmdir /q/s "$(IntermediateOutputPath)"</CleanCommand>
<PythonArguments>"$(PythonExe)" "$(MSBuildThisFileDirectory)\..\msi\make_zip.py"</PythonArguments>
- <PythonArguments>$(PythonArguments) -t "$(IntermediateOutputPath)" -b "$(BuildPath.TrimEnd('\'))"</PythonArguments>
+ <PythonArguments>$(PythonArguments) -t "$(IntermediateOutputPath)" -a $(ArchName)</PythonArguments>
<PipArguments>"$(IntermediateOutputPath)\python.exe" -B -c "import sys; sys.path.append(r'$(PySourcePath)\Lib'); import ensurepip; ensurepip._main()"</PipArguments>
<PackageArguments Condition="$(Packages) != ''">"$(IntermediateOutputPath)\python.exe" -B -m pip install -U $(Packages)</PackageArguments>
diff --git a/Tools/parser/unparse.py b/Tools/parser/unparse.py
index 285030e792..7e1cc4ea5d 100644
--- a/Tools/parser/unparse.py
+++ b/Tools/parser/unparse.py
@@ -104,6 +104,19 @@ class Unparser:
self.write(" "+self.binop[t.op.__class__.__name__]+"= ")
self.dispatch(t.value)
+ def _AnnAssign(self, t):
+ self.fill()
+ if not t.simple and isinstance(t.target, ast.Name):
+ self.write('(')
+ self.dispatch(t.target)
+ if not t.simple and isinstance(t.target, ast.Name):
+ self.write(')')
+ self.write(": ")
+ self.dispatch(t.annotation)
+ if t.value:
+ self.write(" = ")
+ self.dispatch(t.value)
+
def _Return(self, t):
self.fill("return")
if t.value:
@@ -322,9 +335,72 @@ class Unparser:
def _Str(self, tree):
self.write(repr(tree.s))
+ def _JoinedStr(self, t):
+ self.write("f")
+ string = io.StringIO()
+ self._fstring_JoinedStr(t, string.write)
+ self.write(repr(string.getvalue()))
+
+ def _FormattedValue(self, t):
+ self.write("f")
+ string = io.StringIO()
+ self._fstring_FormattedValue(t, string.write)
+ self.write(repr(string.getvalue()))
+
+ def _fstring_JoinedStr(self, t, write):
+ for value in t.values:
+ meth = getattr(self, "_fstring_" + type(value).__name__)
+ meth(value, write)
+
+ def _fstring_Str(self, t, write):
+ value = t.s.replace("{", "{{").replace("}", "}}")
+ write(value)
+
+ def _fstring_Constant(self, t, write):
+ assert isinstance(t.value, str)
+ value = t.value.replace("{", "{{").replace("}", "}}")
+ write(value)
+
+ def _fstring_FormattedValue(self, t, write):
+ write("{")
+ expr = io.StringIO()
+ Unparser(t.value, expr)
+ expr = expr.getvalue().rstrip("\n")
+ if expr.startswith("{"):
+ write(" ") # Separate pair of opening brackets as "{ {"
+ write(expr)
+ if t.conversion != -1:
+ conversion = chr(t.conversion)
+ assert conversion in "sra"
+ write(f"!{conversion}")
+ if t.format_spec:
+ write(":")
+ meth = getattr(self, "_fstring_" + type(t.format_spec).__name__)
+ meth(t.format_spec, write)
+ write("}")
+
def _Name(self, t):
self.write(t.id)
+ def _write_constant(self, value):
+ if isinstance(value, (float, complex)):
+ self.write(repr(value).replace("inf", INFSTR))
+ else:
+ self.write(repr(value))
+
+ def _Constant(self, t):
+ value = t.value
+ if isinstance(value, tuple):
+ self.write("(")
+ if len(value) == 1:
+ self._write_constant(value[0])
+ self.write(",")
+ else:
+ interleave(lambda: self.write(", "), self._write_constant, value)
+ self.write(")")
+ else:
+ self._write_constant(t.value)
+
def _NameConstant(self, t):
self.write(repr(t.value))
@@ -368,7 +444,10 @@ class Unparser:
self.write("}")
def _comprehension(self, t):
- self.write(" for ")
+ if t.is_async:
+ self.write(" async for ")
+ else:
+ self.write(" for ")
self.dispatch(t.target)
self.write(" in ")
self.dispatch(t.iter)
@@ -413,7 +492,7 @@ class Unparser:
def _Tuple(self, t):
self.write("(")
if len(t.elts) == 1:
- (elt,) = t.elts
+ elt = t.elts[0]
self.dispatch(elt)
self.write(",")
else:
@@ -460,7 +539,8 @@ class Unparser:
# Special case: 3.__abs__() is a syntax error, so if t.value
# is an integer literal then we need to either parenthesize
# it or add an extra space to get 3 .__abs__().
- if isinstance(t.value, ast.Num) and isinstance(t.value.n, int):
+ if ((isinstance(t.value, ast.Num) and isinstance(t.value.n, int))
+ or (isinstance(t.value, ast.Constant) and isinstance(t.value.value, int))):
self.write(" ")
self.write(".")
self.write(t.attr)
diff --git a/Tools/pybench/CommandLine.py b/Tools/pybench/CommandLine.py
index 073cca0507..54a8ba7326 100644
--- a/Tools/pybench/CommandLine.py
+++ b/Tools/pybench/CommandLine.py
@@ -99,8 +99,8 @@ def option_dict(options):
# Alias
getpasswd = invisible_input
-_integerRE = re.compile('\s*(-?\d+)\s*$')
-_integerRangeRE = re.compile('\s*(-?\d+)\s*-\s*(-?\d+)\s*$')
+_integerRE = re.compile(r'\s*(-?\d+)\s*$')
+_integerRangeRE = re.compile(r'\s*(-?\d+)\s*-\s*(-?\d+)\s*$')
def srange(s,
diff --git a/Tools/pybench/With.py b/Tools/pybench/With.py
index 5f59e8c05b..30cd3c2c8a 100644
--- a/Tools/pybench/With.py
+++ b/Tools/pybench/With.py
@@ -1,4 +1,3 @@
-from __future__ import with_statement
from pybench import Test
class WithFinally(Test):
diff --git a/Tools/pynche/ColorDB.py b/Tools/pynche/ColorDB.py
index 5ced0e71b5..0348148a61 100644
--- a/Tools/pynche/ColorDB.py
+++ b/Tools/pynche/ColorDB.py
@@ -134,17 +134,17 @@ class ColorDB:
class RGBColorDB(ColorDB):
_re = re.compile(
- '\s*(?P<red>\d+)\s+(?P<green>\d+)\s+(?P<blue>\d+)\s+(?P<name>.*)')
+ r'\s*(?P<red>\d+)\s+(?P<green>\d+)\s+(?P<blue>\d+)\s+(?P<name>.*)')
class HTML40DB(ColorDB):
- _re = re.compile('(?P<name>\S+)\s+(?P<hexrgb>#[0-9a-fA-F]{6})')
+ _re = re.compile(r'(?P<name>\S+)\s+(?P<hexrgb>#[0-9a-fA-F]{6})')
def _extractrgb(self, mo):
return rrggbb_to_triplet(mo.group('hexrgb'))
class LightlinkDB(HTML40DB):
- _re = re.compile('(?P<name>(.+))\s+(?P<hexrgb>#[0-9a-fA-F]{6})')
+ _re = re.compile(r'(?P<name>(.+))\s+(?P<hexrgb>#[0-9a-fA-F]{6})')
def _extractname(self, mo):
return mo.group('name').strip()
diff --git a/Tools/scripts/combinerefs.py b/Tools/scripts/combinerefs.py
index e10e49ad7c..7ca95267c9 100755
--- a/Tools/scripts/combinerefs.py
+++ b/Tools/scripts/combinerefs.py
@@ -6,7 +6,7 @@ combinerefs path
A helper for analyzing PYTHONDUMPREFS output.
When the PYTHONDUMPREFS envar is set in a debug build, at Python shutdown
-time Py_Finalize() prints the list of all live objects twice: first it
+time Py_FinalizeEx() prints the list of all live objects twice: first it
prints the repr() of each object while the interpreter is still fully intact.
After cleaning up everything it can, it prints all remaining live objects
again, but the second time just prints their addresses, refcounts, and type
@@ -41,7 +41,7 @@ CAUTION: If object is a container type, it may not actually contain all the
objects shown in the repr: the repr was captured from the first output block,
and some of the containees may have been released since then. For example,
it's common for the line showing the dict of interned strings to display
-strings that no longer exist at the end of Py_Finalize; this can be recognized
+strings that no longer exist at the end of Py_FinalizeEx; this can be recognized
(albeit painfully) because such containees don't have a line of their own.
The objects are listed in allocation order, with most-recently allocated
diff --git a/Tools/scripts/diff.py b/Tools/scripts/diff.py
index 9720a43155..96199b8511 100755
--- a/Tools/scripts/diff.py
+++ b/Tools/scripts/diff.py
@@ -8,7 +8,7 @@
"""
-import sys, os, time, difflib, argparse
+import sys, os, difflib, argparse
from datetime import datetime, timezone
def file_mtime(path):
diff --git a/Tools/scripts/fixdiv.py b/Tools/scripts/fixdiv.py
index 20f33865e2..1213a4e397 100755
--- a/Tools/scripts/fixdiv.py
+++ b/Tools/scripts/fixdiv.py
@@ -174,8 +174,8 @@ def usage(msg):
sys.stderr.write("Usage: %s [-m] warnings\n" % sys.argv[0])
sys.stderr.write("Try `%s -h' for more information.\n" % sys.argv[0])
-PATTERN = ("^(.+?):(\d+): DeprecationWarning: "
- "classic (int|long|float|complex) division$")
+PATTERN = (r"^(.+?):(\d+): DeprecationWarning: "
+ r"classic (int|long|float|complex) division$")
def readwarnings(warningsfile):
prog = re.compile(PATTERN)
diff --git a/Tools/scripts/generate_opcode_h.py b/Tools/scripts/generate_opcode_h.py
index c62f9a5b23..948b56f900 100644
--- a/Tools/scripts/generate_opcode_h.py
+++ b/Tools/scripts/generate_opcode_h.py
@@ -1,7 +1,5 @@
# This script generates the opcode.h header file.
-from __future__ import with_statement
-
import sys
header = """/* Auto-generated by Tools/scripts/generate_opcode_h.py */
#ifndef Py_OPCODE_H
diff --git a/Tools/scripts/h2py.py b/Tools/scripts/h2py.py
index 0967fc29d6..4363c0cf73 100755
--- a/Tools/scripts/h2py.py
+++ b/Tools/scripts/h2py.py
@@ -23,13 +23,13 @@
import sys, re, getopt, os
-p_define = re.compile('^[\t ]*#[\t ]*define[\t ]+([a-zA-Z0-9_]+)[\t ]+')
+p_define = re.compile(r'^[\t ]*#[\t ]*define[\t ]+([a-zA-Z0-9_]+)[\t ]+')
p_macro = re.compile(
- '^[\t ]*#[\t ]*define[\t ]+'
- '([a-zA-Z0-9_]+)\(([_a-zA-Z][_a-zA-Z0-9]*)\)[\t ]+')
+ r'^[\t ]*#[\t ]*define[\t ]+'
+ r'([a-zA-Z0-9_]+)\(([_a-zA-Z][_a-zA-Z0-9]*)\)[\t ]+')
-p_include = re.compile('^[\t ]*#[\t ]*include[\t ]+<([^>\n]+)>')
+p_include = re.compile(r'^[\t ]*#[\t ]*include[\t ]+<([^>\n]+)>')
p_comment = re.compile(r'/\*([^*]+|\*+[^/])*(\*+/)?')
p_cpp_comment = re.compile('//.*')
diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py
index 66ad868ec3..9272fee4ee 100755
--- a/Tools/scripts/highlight.py
+++ b/Tools/scripts/highlight.py
@@ -147,14 +147,14 @@ def build_html_page(classified_text, title='python',
#### LaTeX Output ##########################################
default_latex_commands = {
- 'comment': '{\color{red}#1}',
- 'string': '{\color{ForestGreen}#1}',
- 'docstring': '{\emph{\color{ForestGreen}#1}}',
- 'keyword': '{\color{orange}#1}',
- 'builtin': '{\color{purple}#1}',
- 'definition': '{\color{orange}#1}',
- 'defname': '{\color{blue}#1}',
- 'operator': '{\color{brown}#1}',
+ 'comment': r'{\color{red}#1}',
+ 'string': r'{\color{ForestGreen}#1}',
+ 'docstring': r'{\emph{\color{ForestGreen}#1}}',
+ 'keyword': r'{\color{orange}#1}',
+ 'builtin': r'{\color{purple}#1}',
+ 'definition': r'{\color{orange}#1}',
+ 'defname': r'{\color{blue}#1}',
+ 'operator': r'{\color{brown}#1}',
}
default_latex_document = r'''
diff --git a/Tools/scripts/idle3 b/Tools/scripts/idle3
index 8ee92c2afe..d7332bca48 100755
--- a/Tools/scripts/idle3
+++ b/Tools/scripts/idle3
@@ -1,5 +1,5 @@
#! /usr/bin/env python3
-from idlelib.PyShell import main
+from idlelib.pyshell import main
if __name__ == '__main__':
main()
diff --git a/Tools/scripts/mailerdaemon.py b/Tools/scripts/mailerdaemon.py
index aeb451e942..635e5482e6 100755
--- a/Tools/scripts/mailerdaemon.py
+++ b/Tools/scripts/mailerdaemon.py
@@ -88,7 +88,7 @@ del i
# no more expressions are searched for. So, order is important.
emparse_list_reason = [
r'^5\d{2} <>\.\.\. (?P<reason>.*)',
- '<>\.\.\. (?P<reason>.*)',
+ r'<>\.\.\. (?P<reason>.*)',
re.compile(r'^<<< 5\d{2} (?P<reason>.*)', re.MULTILINE),
re.compile('===== stderr was =====\nrmail: (?P<reason>.*)'),
re.compile('^Diagnostic-Code: (?P<reason>.*)', re.MULTILINE),
diff --git a/Tools/scripts/nm2def.py b/Tools/scripts/nm2def.py
index 8f07559e21..83bbcd749f 100755
--- a/Tools/scripts/nm2def.py
+++ b/Tools/scripts/nm2def.py
@@ -36,8 +36,8 @@ option to produce this format (since it is the original v7 Unix format).
"""
import os, sys
-PYTHONLIB = 'libpython'+sys.version[:3]+'.a'
-PC_PYTHONLIB = 'Python'+sys.version[0]+sys.version[2]+'.dll'
+PYTHONLIB = 'libpython%d.%d.a' % sys.version_info[:2]
+PC_PYTHONLIB = 'Python%d%d.dll' % sys.version_info[:2]
NM = 'nm -p -g %s' # For Linux, use "nm -g %s"
def symbols(lib=PYTHONLIB,types=('T','C','D')):
diff --git a/Tools/scripts/parseentities.py b/Tools/scripts/parseentities.py
index a042d1c24c..c686b0241a 100755
--- a/Tools/scripts/parseentities.py
+++ b/Tools/scripts/parseentities.py
@@ -14,7 +14,7 @@
"""
import re,sys
-entityRE = re.compile('<!ENTITY +(\w+) +CDATA +"([^"]+)" +-- +((?:.|\n)+?) *-->')
+entityRE = re.compile(r'<!ENTITY +(\w+) +CDATA +"([^"]+)" +-- +((?:.|\n)+?) *-->')
def parse(text,pos=0,endpos=None):
@@ -39,7 +39,7 @@ def writefile(f,defs):
if charcode[:2] == '&#':
code = int(charcode[2:-1])
if code < 256:
- charcode = "'\%o'" % code
+ charcode = r"'\%o'" % code
else:
charcode = repr(charcode)
else:
diff --git a/Tools/scripts/pathfix.py b/Tools/scripts/pathfix.py
index 22432d1639..562bbc7378 100755
--- a/Tools/scripts/pathfix.py
+++ b/Tools/scripts/pathfix.py
@@ -64,7 +64,7 @@ def main():
if fix(arg): bad = 1
sys.exit(bad)
-ispythonprog = re.compile('^[a-zA-Z0-9_]+\.py$')
+ispythonprog = re.compile(r'^[a-zA-Z0-9_]+\.py$')
def ispython(name):
return bool(ispythonprog.match(name))
diff --git a/Tools/scripts/ptags.py b/Tools/scripts/ptags.py
index ca643b3494..396cbd07ea 100755
--- a/Tools/scripts/ptags.py
+++ b/Tools/scripts/ptags.py
@@ -24,7 +24,7 @@ def main():
for s in tags: fp.write(s)
-expr = '^[ \t]*(def|class)[ \t]+([a-zA-Z0-9_]+)[ \t]*[:\(]'
+expr = r'^[ \t]*(def|class)[ \t]+([a-zA-Z0-9_]+)[ \t]*[:\(]'
matcher = re.compile(expr)
def treat_file(filename):
diff --git a/Tools/scripts/pyvenv b/Tools/scripts/pyvenv
index 978d691d1e..1fb42c6391 100755
--- a/Tools/scripts/pyvenv
+++ b/Tools/scripts/pyvenv
@@ -1,6 +1,12 @@
#!/usr/bin/env python3
if __name__ == '__main__':
import sys
+ import pathlib
+
+ executable = pathlib.Path(sys.executable or 'python3').name
+ print('WARNING: the pyenv script is deprecated in favour of '
+ f'`{executable} -m venv`', file=sys.stderr)
+
rc = 1
try:
import venv
diff --git a/Tools/scripts/svneol.py b/Tools/scripts/svneol.py
index 8abdd01529..6c70da9692 100755
--- a/Tools/scripts/svneol.py
+++ b/Tools/scripts/svneol.py
@@ -1,6 +1,6 @@
#! /usr/bin/env python3
-"""
+r"""
SVN helper script.
Try to set the svn:eol-style property to "native" on every .py, .txt, .c and
diff --git a/Tools/scripts/texi2html.py b/Tools/scripts/texi2html.py
index 99835280fe..9c1e9fe8d8 100755
--- a/Tools/scripts/texi2html.py
+++ b/Tools/scripts/texi2html.py
@@ -78,11 +78,11 @@ spprog = re.compile('[\n@{}&<>]') # Special characters in
# running text
#
# menu item (Yuck!)
-miprog = re.compile('^\* ([^:]*):(:|[ \t]*([^\t,\n.]+)([^ \t\n]*))[ \t\n]*')
-# 0 1 1 2 3 34 42 0
-# ----- ---------- ---------
-# -|-----------------------------
-# -----------------------------------------------------
+miprog = re.compile(r'^\* ([^:]*):(:|[ \t]*([^\t,\n.]+)([^ \t\n]*))[ \t\n]*')
+# 0 1 1 2 3 34 42 0
+# ----- ---------- ---------
+# -|-----------------------------
+# -----------------------------------------------------
diff --git a/Tools/ssl/test_multiple_versions.py b/Tools/ssl/test_multiple_versions.py
index dd57dcf18b..30d5fcf2e0 100644
--- a/Tools/ssl/test_multiple_versions.py
+++ b/Tools/ssl/test_multiple_versions.py
@@ -105,11 +105,11 @@ class BuildSSL:
def _subprocess_call(self, cmd, stdout=subprocess.DEVNULL, env=None,
**kwargs):
- log.debug("Call '{}'".format(" ".join(cmd)))
+ log.debug("Call '%s'", " ".join(cmd))
return subprocess.check_call(cmd, stdout=stdout, env=env, **kwargs)
def _subprocess_output(self, cmd, env=None, **kwargs):
- log.debug("Call '{}'".format(" ".join(cmd)))
+ log.debug("Call '%s'", " ".join(cmd))
out = subprocess.check_output(cmd, env=env)
return out.strip().decode("utf-8")
@@ -168,7 +168,7 @@ class BuildSSL:
if not self.has_src:
self._download_openssl()
else:
- log.debug("Already has src {}".format(self.src_file))
+ log.debug("Already has src %s", self.src_file)
self._unpack_openssl()
self._build_openssl()
self._install_openssl()
diff --git a/Tools/tz/zdump.py b/Tools/tz/zdump.py
new file mode 100644
index 0000000000..f94b483101
--- /dev/null
+++ b/Tools/tz/zdump.py
@@ -0,0 +1,81 @@
+import sys
+import os
+import struct
+from array import array
+from collections import namedtuple
+from datetime import datetime, timedelta
+
+ttinfo = namedtuple('ttinfo', ['tt_gmtoff', 'tt_isdst', 'tt_abbrind'])
+
+class TZInfo:
+ def __init__(self, transitions, type_indices, ttis, abbrs):
+ self.transitions = transitions
+ self.type_indices = type_indices
+ self.ttis = ttis
+ self.abbrs = abbrs
+
+ @classmethod
+ def fromfile(cls, fileobj):
+ if fileobj.read(4).decode() != "TZif":
+ raise ValueError("not a zoneinfo file")
+ fileobj.seek(20)
+ header = fileobj.read(24)
+ tzh = (tzh_ttisgmtcnt, tzh_ttisstdcnt, tzh_leapcnt,
+ tzh_timecnt, tzh_typecnt, tzh_charcnt) = struct.unpack(">6l", header)
+ transitions = array('i')
+ transitions.fromfile(fileobj, tzh_timecnt)
+ if sys.byteorder != 'big':
+ transitions.byteswap()
+
+ type_indices = array('B')
+ type_indices.fromfile(fileobj, tzh_timecnt)
+
+ ttis = []
+ for i in range(tzh_typecnt):
+ ttis.append(ttinfo._make(struct.unpack(">lbb", fileobj.read(6))))
+
+ abbrs = fileobj.read(tzh_charcnt)
+
+ self = cls(transitions, type_indices, ttis, abbrs)
+ self.tzh = tzh
+
+ return self
+
+ def dump(self, stream, start=None, end=None):
+ for j, (trans, i) in enumerate(zip(self.transitions, self.type_indices)):
+ utc = datetime.utcfromtimestamp(trans)
+ tti = self.ttis[i]
+ lmt = datetime.utcfromtimestamp(trans + tti.tt_gmtoff)
+ abbrind = tti.tt_abbrind
+ abbr = self.abbrs[abbrind:self.abbrs.find(0, abbrind)].decode()
+ if j > 0:
+ prev_tti = self.ttis[self.type_indices[j - 1]]
+ shift = " %+g" % ((tti.tt_gmtoff - prev_tti.tt_gmtoff) / 3600)
+ else:
+ shift = ''
+ print("%s UTC = %s %-5s isdst=%d" % (utc, lmt, abbr, tti[1]) + shift, file=stream)
+
+ @classmethod
+ def zonelist(cls, zonedir='/usr/share/zoneinfo'):
+ zones = []
+ for root, _, files in os.walk(zonedir):
+ for f in files:
+ p = os.path.join(root, f)
+ with open(p, 'rb') as o:
+ magic = o.read(4)
+ if magic == b'TZif':
+ zones.append(p[len(zonedir) + 1:])
+ return zones
+
+if __name__ == '__main__':
+ if len(sys.argv) < 2:
+ zones = TZInfo.zonelist()
+ for z in zones:
+ print(z)
+ sys.exit()
+ filepath = sys.argv[1]
+ if not filepath.startswith('/'):
+ filepath = os.path.join('/usr/share/zoneinfo', filepath)
+ with open(filepath, 'rb') as fileobj:
+ tzi = TZInfo.fromfile(fileobj)
+ tzi.dump(sys.stdout)
diff --git a/Tools/unicode/gencodec.py b/Tools/unicode/gencodec.py
index 4c214690d3..31f0112150 100644
--- a/Tools/unicode/gencodec.py
+++ b/Tools/unicode/gencodec.py
@@ -37,11 +37,11 @@ UNI_UNDEFINED = chr(0xFFFE)
# Placeholder for a missing code point
MISSING_CODE = -1
-mapRE = re.compile('((?:0x[0-9a-fA-F]+\+?)+)'
- '\s+'
- '((?:(?:0x[0-9a-fA-Z]+|<[A-Za-z]+>)\+?)*)'
- '\s*'
- '(#.+)?')
+mapRE = re.compile(r'((?:0x[0-9a-fA-F]+\+?)+)'
+ r'\s+'
+ r'((?:(?:0x[0-9a-fA-Z]+|<[A-Za-z]+>)\+?)*)'
+ r'\s*'
+ r'(#.+)?')
def parsecodes(codes, len=len, range=range):
diff --git a/Tools/unicode/makeunicodedata.py b/Tools/unicode/makeunicodedata.py
index 713e175c50..5d8014a5da 100644
--- a/Tools/unicode/makeunicodedata.py
+++ b/Tools/unicode/makeunicodedata.py
@@ -42,7 +42,7 @@ VERSION = "3.2"
# * Doc/library/stdtypes.rst, and
# * Doc/library/unicodedata.rst
# * Doc/reference/lexical_analysis.rst (two occurrences)
-UNIDATA_VERSION = "8.0.0"
+UNIDATA_VERSION = "9.0.0"
UNICODE_DATA = "UnicodeData%s.txt"
COMPOSITION_EXCLUSIONS = "CompositionExclusions%s.txt"
EASTASIAN_WIDTH = "EastAsianWidth%s.txt"
@@ -796,6 +796,7 @@ def merge_old_version(version, new, old):
category_changes = [0xFF]*0x110000
decimal_changes = [0xFF]*0x110000
mirrored_changes = [0xFF]*0x110000
+ east_asian_width_changes = [0xFF]*0x110000
# In numeric data, 0 means "no change",
# -1 means "did not have a numeric value
numeric_changes = [0] * 0x110000
@@ -862,6 +863,9 @@ def merge_old_version(version, new, old):
elif k == 14:
# change to simple titlecase mapping; ignore
pass
+ elif k == 15:
+ # change to east asian width
+ east_asian_width_changes[i] = EASTASIANWIDTH_NAMES.index(value)
elif k == 16:
# derived property changes; not yet
pass
@@ -873,8 +877,9 @@ def merge_old_version(version, new, old):
class Difference(Exception):pass
raise Difference(hex(i), k, old.table[i], new.table[i])
new.changed.append((version, list(zip(bidir_changes, category_changes,
- decimal_changes, mirrored_changes,
- numeric_changes)),
+ decimal_changes, mirrored_changes,
+ east_asian_width_changes,
+ numeric_changes)),
normalization_changes))
def open_data(template, version):