summaryrefslogtreecommitdiff
path: root/Tools
diff options
context:
space:
mode:
Diffstat (limited to 'Tools')
-rw-r--r--Tools/buildbot/test.bat4
-rwxr-xr-xTools/clinic/clinic.py98
-rwxr-xr-xTools/freeze/freeze.py2
-rwxr-xr-xTools/i18n/pygettext.py51
-rw-r--r--Tools/msi/bundle/bundle.icobin19790 -> 0 bytes
-rw-r--r--Tools/msi/bundle/bundle.wxs2
-rw-r--r--Tools/msi/common.wxs6
-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_en-US.wxl1
-rw-r--r--Tools/msi/launcher/launcher_reg.wxs8
-rw-r--r--Tools/msi/lib/lib_files.wxs6
-rw-r--r--Tools/msi/msi.props9
-rw-r--r--Tools/parser/unparse.py68
-rwxr-xr-xTools/scripts/combinerefs.py4
-rwxr-xr-xTools/scripts/diff.py2
-rwxr-xr-xTools/scripts/idle32
-rwxr-xr-xTools/scripts/nm2def.py4
-rwxr-xr-xTools/scripts/pyvenv6
-rw-r--r--Tools/ssl/test_multiple_versions.py6
-rw-r--r--Tools/tz/zdump.py81
27 files changed, 286 insertions, 116 deletions
diff --git a/Tools/buildbot/test.bat b/Tools/buildbot/test.bat
index ff7d167e6a..7bc4de502f 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=900 %regrtest_args%
diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index f615ed9a44..282b1a01ab 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)
@@ -743,7 +743,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 +800,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 +826,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,8 +840,9 @@ 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))
else:
@@ -846,15 +852,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 +881,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 +1037,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 +1073,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 *')
@@ -2359,7 +2365,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:
@@ -2676,7 +2685,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 +2795,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 +2968,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 +2986,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 +3193,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 +3572,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 +3584,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 +3864,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 +3890,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 +3986,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/freeze/freeze.py b/Tools/freeze/freeze.py
index 44edd57b4f..ba756c3f20 100755
--- a/Tools/freeze/freeze.py
+++ b/Tools/freeze/freeze.py
@@ -218,7 +218,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/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/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 38307e063c..c89e6ee4c7 100644
--- a/Tools/msi/bundle/bundle.wxs
+++ b/Tools/msi/bundle/bundle.wxs
@@ -4,7 +4,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..a97ee92f9f 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>
@@ -40,7 +44,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\setup.ico" />
<Property Id="ARPPRODUCTICON" Value="ARPIcon" />
<Property Id="ARPNOMODIFY" Value="1" />
<Property Id="DISABLEADVTSHORTCUTS" Value="1" />
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_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_files.wxs b/Tools/msi/lib/lib_files.wxs
index fa79a8d692..804ab0146d 100644
--- a/Tools/msi/lib/lib_files.wxs
+++ b/Tools/msi/lib/lib_files.wxs
@@ -64,16 +64,10 @@
<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>
</Wix>
diff --git a/Tools/msi/msi.props b/Tools/msi/msi.props
index 0cf7c7779f..745fc54117 100644
--- a/Tools/msi/msi.props
+++ b/Tools/msi/msi.props
@@ -69,6 +69,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 +81,7 @@
UpgradeMinimumVersion=$(MajorVersionNumber).$(MinorVersionNumber).0.0;
NextMajorVersionNumber=$(MajorVersionNumber).$([msbuild]::Add($(MinorVersionNumber), 1)).0.0;
Bitness=$(Bitness);
+ PlatformArchitecture=$(PlatformArchitecture);
PyDebugExt=$(PyDebugExt);
PyArchExt=$(PyArchExt);
PyTestExt=$(PyTestExt);
@@ -155,6 +158,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/parser/unparse.py b/Tools/parser/unparse.py
index 285030e792..72030576d0 100644
--- a/Tools/parser/unparse.py
+++ b/Tools/parser/unparse.py
@@ -322,9 +322,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))
@@ -413,7 +476,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 +523,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/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/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/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/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/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)