Merge tag 'v3.8.0a3'
Python 3.8.0a3
diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
index ae0c9fb..6342ee3 100644
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -211,19 +211,18 @@
@classmethod
def f(cls, arg1, arg2, ...): ...
- The ``@classmethod`` form is a function :term:`decorator` -- see the description
- of function definitions in :ref:`function` for details.
+ The ``@classmethod`` form is a function :term:`decorator` -- see
+ :ref:`function` for details.
- It can be called either on the class (such as ``C.f()``) or on an instance (such
+ A class method can be called either on the class (such as ``C.f()``) or on an instance (such
as ``C().f()``). The instance is ignored except for its class. If a class
method is called for a derived class, the derived class object is passed as the
implied first argument.
Class methods are different than C++ or Java static methods. If you want those,
- see :func:`staticmethod` in this section.
+ see :func:`staticmethod`.
- For more information on class methods, consult the documentation on the standard
- type hierarchy in :ref:`types`.
+ For more information on class methods, see :ref:`types`.
.. function:: compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
@@ -1452,11 +1451,11 @@
@staticmethod
def f(arg1, arg2, ...): ...
- The ``@staticmethod`` form is a function :term:`decorator` -- see the
- description of function definitions in :ref:`function` for details.
+ The ``@staticmethod`` form is a function :term:`decorator` -- see
+ :ref:`function` for details.
- It can be called either on the class (such as ``C.f()``) or on an instance (such
- as ``C().f()``). The instance is ignored except for its class.
+ A static method can be called either on the class (such as ``C.f()``) or on an instance (such
+ as ``C().f()``).
Static methods in Python are similar to those found in Java or C++. Also see
:func:`classmethod` for a variant that is useful for creating alternate class
@@ -1471,8 +1470,7 @@
class C:
builtin_open = staticmethod(open)
- For more information on static methods, consult the documentation on the
- standard type hierarchy in :ref:`types`.
+ For more information on static methods, see :ref:`types`.
.. index::
diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst
index 8ef9e2e..11e137b 100644
--- a/Doc/library/idle.rst
+++ b/Doc/library/idle.rst
@@ -356,8 +356,8 @@
Go to file/line
Same as in Debug menu.
-The Shell window also has an output squeezing facility explained in the
-the *Python Shell window* subsection below.
+The Shell window also has an output squeezing facility explained in the *Python
+Shell window* subsection below.
Squeeze
If the cursor is over an output line, squeeze all the output between
@@ -716,17 +716,15 @@
A Windows console, for instance, keeps a user-settable 1 to 9999 lines,
with 300 the default.
-A Tk Text widget, and hence IDLE's Shell, displays characters (codepoints)
-in the the BMP (Basic Multilingual Plane) subset of Unicode.
-Which characters are displayed with a proper glyph and which with a
-replacement box depends on the operating system and installed fonts.
-Tab characters cause the following text to begin after
-the next tab stop. (They occur every 8 'characters').
-Newline characters cause following text to appear on a new line.
-Other control characters are ignored or displayed as a space, box, or
-something else, depending on the operating system and font.
-(Moving the text cursor through such output with arrow keys may exhibit
-some surprising spacing behavior.)
+A Tk Text widget, and hence IDLE's Shell, displays characters (codepoints) in
+the BMP (Basic Multilingual Plane) subset of Unicode. Which characters are
+displayed with a proper glyph and which with a replacement box depends on the
+operating system and installed fonts. Tab characters cause the following text
+to begin after the next tab stop. (They occur every 8 'characters'). Newline
+characters cause following text to appear on a new line. Other control
+characters are ignored or displayed as a space, box, or something else,
+depending on the operating system and font. (Moving the text cursor through
+such output with arrow keys may exhibit some surprising spacing behavior.)
.. code-block:: none
diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst
index 5adde29..08555c3 100644
--- a/Doc/library/logging.rst
+++ b/Doc/library/logging.rst
@@ -1215,6 +1215,10 @@
closing all handlers. This should be called at application exit and no
further use of the logging system should be made after this call.
+ When the logging module is imported, it registers this function as an exit
+ handler (see :mod:`atexit`), so normally there's no need to do that
+ manually.
+
.. function:: setLoggerClass(klass)
diff --git a/Doc/library/queue.rst b/Doc/library/queue.rst
index f99f6ff..2eeab5e 100644
--- a/Doc/library/queue.rst
+++ b/Doc/library/queue.rst
@@ -150,6 +150,11 @@
Otherwise (*block* is false), return an item if one is immediately available,
else raise the :exc:`Empty` exception (*timeout* is ignored in that case).
+ Prior to 3.0 on POSIX systems, and for all versions on Windows, if
+ *block* is true and *timeout* is ``None``, this operation goes into
+ an uninterruptible wait on an underlying lock. This means that no exceptions
+ can occur, and in particular a SIGINT will not trigger a :exc:`KeyboardInterrupt`.
+
.. method:: Queue.get_nowait()
diff --git a/Doc/library/wsgiref.rst b/Doc/library/wsgiref.rst
index ffca1fc..b85ec53 100644
--- a/Doc/library/wsgiref.rst
+++ b/Doc/library/wsgiref.rst
@@ -781,3 +781,35 @@
# Serve until process is killed
httpd.serve_forever()
+
+
+Example of a small wsgiref-based web server::
+
+ # Takes a path to serve from and an optional port number (defaults to 8000),
+ # then tries to serve files. Mime types are guessed from the file names, 404
+ # errors are raised if the file is not found.
+ import sys
+ import os
+ import mimetypes
+ from wsgiref import simple_server, util
+
+ def app(environ, respond):
+ fn = os.path.join(path, environ['PATH_INFO'][1:])
+ if '.' not in fn.split(os.path.sep)[-1]:
+ fn = os.path.join(fn, 'index.html')
+ type = mimetypes.guess_type(fn)[0]
+
+ if os.path.exists(fn):
+ respond('200 OK', [('Content-Type', type)])
+ return util.FileWrapper(open(fn, "rb"))
+ else:
+ respond('404 Not Found', [('Content-Type', 'text/plain')])
+ return [b'not found']
+
+ path = sys.argv[1]
+ port = int(sys.argv[2]) if len(sys.argv) > 2 else 8000
+ with simple_server.make_server('', port, app) as httpd:
+ print("Serving {} on port {}, control-C to stop".format(path, port))
+
+ # Serve until process is killed
+ httpd.serve_forever()
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index 3855d36..6ab7991 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -174,6 +174,20 @@
Added :func:`~gettext.pgettext` and its variants.
(Contributed by Franz Glasner, Éric Araujo, and Cheryl Sabella in :issue:`2504`.)
+inspect
+-------
+
+The :func:`inspect.getdoc` function can now find docstrings for ``__slots__``
+if that attribute is a :class:`dict` where the values are docstrings.
+This provides documentation options similar to what we already have
+for :func:`property`, :func:`classmethod`, and :func:`staticmethod`::
+
+ class AudioClip:
+ __slots__ = {'bit_rate': 'expressed in kilohertz to one decimal place',
+ 'duration': 'in seconds, rounded up to an integer'}
+ def __init__(self, bit_rate, duration):
+ self.bit_rate = round(bit_rate / 1000.0, 1)
+ self.duration = ceil(duration)
gc
--
diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h
index bb086cb..827a19a 100644
--- a/Include/cpython/coreconfig.h
+++ b/Include/cpython/coreconfig.h
@@ -123,7 +123,9 @@
/* --- _PyCoreConfig ---------------------------------------------- */
typedef struct {
- _PyPreConfig preconfig;
+ int isolated;
+ int use_environment;
+ int dev_mode;
/* Install signal handlers? Yes by default. */
int install_signal_handlers;
@@ -375,7 +377,9 @@
#define _PyCoreConfig_INIT \
(_PyCoreConfig){ \
_PyCoreConfig_WINDOWS_INIT \
- .preconfig = _PyPreConfig_INIT, \
+ .isolated = -1, \
+ .use_environment = -1, \
+ .dev_mode = -1, \
.install_signal_handlers = 1, \
.use_hash_seed = -1, \
.faulthandler = -1, \
@@ -400,8 +404,7 @@
/* --- Function used for testing ---------------------------------- */
-PyAPI_FUNC(PyObject *) _Py_GetGlobalVariablesAsDict(void);
-PyAPI_FUNC(PyObject *) _PyCoreConfig_AsDict(const _PyCoreConfig *config);
+PyAPI_FUNC(PyObject*) _Py_GetConfigsAsDict(void);
#ifdef __cplusplus
}
diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h
index a226de8..e32e54c 100644
--- a/Include/cpython/pylifecycle.h
+++ b/Include/cpython/pylifecycle.h
@@ -16,7 +16,7 @@
PyAPI_FUNC(_PyInitError) _Py_PreInitialize(void);
PyAPI_FUNC(_PyInitError) _Py_PreInitializeFromPreConfig(
- _PyPreConfig *preconfig);
+ const _PyPreConfig *preconfig);
PyAPI_FUNC(_PyInitError) _Py_PreInitializeFromConfig(
const _PyCoreConfig *coreconfig);
@@ -33,9 +33,6 @@
PyAPI_FUNC(int) _PyMainInterpreterConfig_Copy(
_PyMainInterpreterConfig *config,
const _PyMainInterpreterConfig *config2);
-/* Used by _testcapi.get_main_config() */
-PyAPI_FUNC(PyObject*) _PyMainInterpreterConfig_AsDict(
- const _PyMainInterpreterConfig *config);
PyAPI_FUNC(_PyInitError) _Py_InitializeMainInterpreter(
PyInterpreterState *interp,
diff --git a/Include/internal/pycore_coreconfig.h b/Include/internal/pycore_coreconfig.h
index d44172e..d79f590 100644
--- a/Include/internal/pycore_coreconfig.h
+++ b/Include/internal/pycore_coreconfig.h
@@ -16,12 +16,14 @@
_PyWstrList xoptions; /* "-X value" option */
int use_environment; /* -E option */
int isolated; /* -I option */
+ int dev_mode; /* -X dev and PYTHONDEVMODE */
} _PyPreCmdline;
#define _PyPreCmdline_INIT \
(_PyPreCmdline){ \
.use_environment = -1, \
- .isolated = -1}
+ .isolated = -1, \
+ .dev_mode = -1}
/* Note: _PyPreCmdline_INIT sets other fields to 0/NULL */
PyAPI_FUNC(void) _PyPreCmdline_Clear(_PyPreCmdline *cmdline);
@@ -76,22 +78,23 @@
PyAPI_FUNC(const wchar_t*) _Py_get_xoption(
const _PyWstrList *xoptions,
const wchar_t *name);
+PyAPI_FUNC(const char*) _Py_GetEnv(
+ int use_environment,
+ const char *name);
PyAPI_FUNC(void) _PyPreConfig_Clear(_PyPreConfig *config);
PyAPI_FUNC(int) _PyPreConfig_Copy(_PyPreConfig *config,
const _PyPreConfig *config2);
PyAPI_FUNC(void) _PyPreConfig_GetGlobalConfig(_PyPreConfig *config);
PyAPI_FUNC(void) _PyPreConfig_SetGlobalConfig(const _PyPreConfig *config);
-PyAPI_FUNC(const char*) _PyPreConfig_GetEnv(const _PyPreConfig *config,
- const char *name);
-PyAPI_FUNC(void) _Py_get_env_flag(_PyPreConfig *config,
+PyAPI_FUNC(void) _Py_get_env_flag(
+ int use_environment,
int *flag,
const char *name);
PyAPI_FUNC(_PyInitError) _PyPreConfig_Read(_PyPreConfig *config,
const _PyArgv *args,
const _PyCoreConfig *coreconfig);
-PyAPI_FUNC(int) _PyPreConfig_AsDict(const _PyPreConfig *config,
- PyObject *dict);
+PyAPI_FUNC(PyObject*) _PyPreConfig_AsDict(const _PyPreConfig *config);
PyAPI_FUNC(_PyInitError) _PyPreConfig_ReadFromArgv(_PyPreConfig *config,
const _PyArgv *args);
PyAPI_FUNC(_PyInitError) _PyPreConfig_Write(_PyPreConfig *config);
@@ -108,18 +111,15 @@
const _PyCoreConfig *config);
PyAPI_FUNC(void) _PyCoreConfig_GetGlobalConfig(_PyCoreConfig *config);
PyAPI_FUNC(void) _PyCoreConfig_SetGlobalConfig(const _PyCoreConfig *config);
-PyAPI_FUNC(const char*) _PyCoreConfig_GetEnv(
- const _PyCoreConfig *config,
- const char *name);
-PyAPI_FUNC(int) _PyCoreConfig_GetEnvDup(
- const _PyCoreConfig *config,
- wchar_t **dest,
- wchar_t *wname,
- char *name);
PyAPI_FUNC(_PyInitError) _PyCoreConfig_Read(_PyCoreConfig *config);
PyAPI_FUNC(_PyInitError) _PyCoreConfig_ReadFromArgv(_PyCoreConfig *config,
const _PyArgv *args);
-PyAPI_FUNC(_PyInitError) _PyCoreConfig_Write(const _PyCoreConfig *config);
+PyAPI_FUNC(void) _PyCoreConfig_Write(const _PyCoreConfig *config);
+
+/* --- _PyMainInterpreterConfig ----------------------------------- */
+
+PyAPI_FUNC(PyObject*) _PyMainInterpreterConfig_AsDict(
+ const _PyMainInterpreterConfig *config);
#ifdef __cplusplus
}
diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h
index 9514b1c..3214d6b 100644
--- a/Include/internal/pycore_pylifecycle.h
+++ b/Include/internal/pycore_pylifecycle.h
@@ -77,6 +77,9 @@
PyAPI_FUNC(void) _PyGC_DumpShutdownStats(void);
+PyAPI_FUNC(_PyInitError) _Py_PreInitializeInPlace(
+ _PyPreConfig *config);
+
#ifdef __cplusplus
}
#endif
diff --git a/Lib/inspect.py b/Lib/inspect.py
index b8a1422..8c398bd 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -582,9 +582,12 @@
cls = obj.__objclass__
if getattr(cls, name) is not obj:
return None
+ if ismemberdescriptor(obj):
+ slots = getattr(cls, '__slots__', None)
+ if isinstance(slots, dict) and name in slots:
+ return slots[name]
else:
return None
-
for base in cls.__mro__:
try:
doc = getattr(base, name).__doc__
diff --git a/Lib/keyword.py b/Lib/keyword.py
old mode 100755
new mode 100644
index 150c2bc..ddcbb25
--- a/Lib/keyword.py
+++ b/Lib/keyword.py
@@ -1,98 +1,55 @@
-#! /usr/bin/env python3
-
-"""Keywords (from "graminit.c")
+"""Keywords (from "Grammar/Grammar")
This file is automatically generated; please don't muck it up!
To update the symbols in this file, 'cd' to the top directory of
-the python source tree after building the interpreter and run:
+the python source tree and run:
- ./python Lib/keyword.py
+ python3 -m Parser.pgen.keywordgen Grammar/Grammar \
+ Grammar/Tokens \
+ Lib/keyword.py
+
+Alternatively, you can run 'make regen-keyword'.
"""
__all__ = ["iskeyword", "kwlist"]
kwlist = [
-#--start keywords--
- 'False',
- 'None',
- 'True',
- 'and',
- 'as',
- 'assert',
- 'break',
- 'class',
- 'continue',
- 'def',
- 'del',
- 'elif',
- 'else',
- 'except',
- 'finally',
- 'for',
- 'from',
- 'global',
- 'if',
- 'import',
- 'in',
- 'is',
- 'lambda',
- 'nonlocal',
- 'not',
- 'or',
- 'pass',
- 'raise',
- 'return',
- 'try',
- 'while',
- 'with',
- 'yield',
-#--end keywords--
- ]
-
-kwlist.append('async')
-kwlist.append('await')
-kwlist.sort()
+ 'False',
+ 'None',
+ 'True',
+ 'and',
+ 'as',
+ 'assert',
+ 'async',
+ 'await',
+ 'break',
+ 'class',
+ 'continue',
+ 'def',
+ 'del',
+ 'elif',
+ 'else',
+ 'except',
+ 'finally',
+ 'for',
+ 'from',
+ 'global',
+ 'if',
+ 'import',
+ 'in',
+ 'is',
+ 'lambda',
+ 'nonlocal',
+ 'not',
+ 'or',
+ 'pass',
+ 'raise',
+ 'return',
+ 'try',
+ 'while',
+ 'with',
+ 'yield'
+]
iskeyword = frozenset(kwlist).__contains__
-
-def main():
- import sys, re
-
- args = sys.argv[1:]
- iptfile = args and args[0] or "Python/graminit.c"
- if len(args) > 1: optfile = args[1]
- else: optfile = "Lib/keyword.py"
-
- # load the output skeleton from the target, taking care to preserve its
- # newline convention.
- with open(optfile, newline='') as fp:
- format = fp.readlines()
- nl = format[0][len(format[0].strip()):] if format else '\n'
-
- # scan the source file for keywords
- with open(iptfile) as fp:
- strprog = re.compile('"([^"]+)"')
- lines = []
- for line in fp:
- if '{1, "' in line:
- match = strprog.search(line)
- if match:
- lines.append(" '" + match.group(1) + "'," + nl)
- lines.sort()
-
- # insert the lines of keywords into the skeleton
- try:
- start = format.index("#--start keywords--" + nl) + 1
- end = format.index("#--end keywords--" + nl)
- format[start:end] = lines
- except ValueError:
- sys.stderr.write("target does not contain format markers\n")
- sys.exit(1)
-
- # write the output file
- with open(optfile, 'w', newline='') as fp:
- fp.writelines(format)
-
-if __name__ == "__main__":
- main()
diff --git a/Lib/statistics.py b/Lib/statistics.py
index e5a6246..bd8a6f9 100644
--- a/Lib/statistics.py
+++ b/Lib/statistics.py
@@ -709,7 +709,8 @@
# https://en.wikipedia.org/wiki/Normal_distribution
# https://en.wikipedia.org/wiki/Variance#Properties
- __slots__ = ('mu', 'sigma')
+ __slots__ = {'mu': 'Arithmetic mean of a normal distribution',
+ 'sigma': 'Standard deviation of a normal distribution'}
def __init__(self, mu=0.0, sigma=1.0):
'NormalDist where mu is the mean and sigma is the standard deviation.'
diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py
index 07f3cb3..79f7e82 100644
--- a/Lib/test/pythoninfo.py
+++ b/Lib/test/pythoninfo.py
@@ -598,18 +598,15 @@
# Dump global configuration variables, _PyCoreConfig
# and _PyMainInterpreterConfig
try:
- from _testcapi import get_global_config, get_core_config, get_main_config
+ from _testcapi import get_configs
except ImportError:
return
- for prefix, get_config_func in (
- ('global_config', get_global_config),
- ('core_config', get_core_config),
- ('main_config', get_main_config),
- ):
- config = get_config_func()
+ all_configs = get_configs()
+ for config_type in sorted(all_configs):
+ config = all_configs[config_type]
for key in sorted(config):
- info_add('%s[%s]' % (prefix, key), repr(config[key]))
+ info_add('%s[%s]' % (config_type, key), repr(config[key]))
def collect_subprocess(info_add):
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index 374346e..ff3cfb1 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -268,13 +268,26 @@
)
# Mark config which should be get by get_default_config()
GET_DEFAULT_CONFIG = object()
+ DEFAULT_PRE_CONFIG = {
+ 'allocator': None,
+ 'coerce_c_locale': 0,
+ 'coerce_c_locale_warn': 0,
+ 'utf8_mode': 0,
+ }
+ COPY_PRE_CONFIG = [
+ 'dev_mode',
+ 'isolated',
+ 'use_environment',
+ ]
+
DEFAULT_CORE_CONFIG = {
- 'install_signal_handlers': 1,
+ 'isolated': 0,
'use_environment': 1,
+ 'dev_mode': 0,
+
+ 'install_signal_handlers': 1,
'use_hash_seed': 0,
'hash_seed': 0,
- 'allocator': None,
- 'dev_mode': 0,
'faulthandler': 0,
'tracemalloc': 0,
'import_time': 0,
@@ -286,10 +299,6 @@
'filesystem_encoding': GET_DEFAULT_CONFIG,
'filesystem_errors': GET_DEFAULT_CONFIG,
- 'utf8_mode': 0,
- 'coerce_c_locale': 0,
- 'coerce_c_locale_warn': 0,
-
'pycache_prefix': None,
'program_name': './_testembed',
'argv': [""],
@@ -306,7 +315,6 @@
'exec_prefix': GET_DEFAULT_CONFIG,
'base_exec_prefix': GET_DEFAULT_CONFIG,
- 'isolated': 0,
'site_import': 1,
'bytes_warning': 0,
'inspect': 0,
@@ -332,8 +340,10 @@
'_frozen': 0,
}
if MS_WINDOWS:
- DEFAULT_CORE_CONFIG.update({
+ DEFAULT_PRE_CONFIG.update({
'legacy_windows_fs_encoding': 0,
+ })
+ DEFAULT_CORE_CONFIG.update({
'legacy_windows_stdio': 0,
})
@@ -359,6 +369,9 @@
'Py_HashRandomizationFlag': 1,
'_Py_HasFileSystemDefaultEncodeErrors': 0,
}
+ COPY_GLOBAL_PRE_CONFIG = [
+ ('Py_UTF8Mode', 'utf8_mode'),
+ ]
COPY_GLOBAL_CONFIG = [
# Copy core config to global config for expected values
# True means that the core config value is inverted (0 => 1 and 1 => 0)
@@ -376,13 +389,14 @@
('Py_NoUserSiteDirectory', 'user_site_directory', True),
('Py_OptimizeFlag', 'optimization_level'),
('Py_QuietFlag', 'quiet'),
- ('Py_UTF8Mode', 'utf8_mode'),
('Py_UnbufferedStdioFlag', 'buffered_stdio', True),
('Py_VerboseFlag', 'verbose'),
]
if MS_WINDOWS:
- COPY_GLOBAL_CONFIG.extend((
+ COPY_GLOBAL_PRE_CONFIG.extend((
('Py_LegacyWindowsFSEncodingFlag', 'legacy_windows_fs_encoding'),
+ ))
+ COPY_GLOBAL_CONFIG.extend((
('Py_LegacyWindowsStdioFlag', 'legacy_windows_stdio'),
))
@@ -453,6 +467,11 @@
expected[key] = config[key]
return expected
+ def check_pre_config(self, config, expected):
+ pre_config = dict(config['pre_config'])
+ core_config = dict(config['core_config'])
+ self.assertEqual(pre_config, expected)
+
def check_core_config(self, config, expected):
core_config = dict(config['core_config'])
for key in self.UNTESTED_CORE_CONFIG:
@@ -460,6 +479,7 @@
self.assertEqual(core_config, expected)
def check_global_config(self, config):
+ pre_config = config['pre_config']
core_config = config['core_config']
expected = dict(self.DEFAULT_GLOBAL_CONFIG)
@@ -470,10 +490,17 @@
else:
global_key, core_key = item
expected[global_key] = core_config[core_key]
+ for item in self.COPY_GLOBAL_PRE_CONFIG:
+ if len(item) == 3:
+ global_key, core_key, opposite = item
+ expected[global_key] = 0 if pre_config[core_key] else 1
+ else:
+ global_key, core_key = item
+ expected[global_key] = pre_config[core_key]
self.assertEqual(config['global_config'], expected)
- def check_config(self, testname, expected):
+ def check_config(self, testname, expected_config, expected_preconfig):
env = dict(os.environ)
# Remove PYTHON* environment variables to get deterministic environment
for key in list(env):
@@ -488,15 +515,24 @@
# Ignore err
config = json.loads(out)
- expected = self.get_expected_config(expected, env)
- self.check_core_config(config, expected)
+ expected_preconfig = dict(self.DEFAULT_PRE_CONFIG, **expected_preconfig)
+ expected_config = self.get_expected_config(expected_config, env)
+ for key in self.COPY_PRE_CONFIG:
+ if key not in expected_preconfig:
+ expected_preconfig[key] = expected_config[key]
+
+ self.check_core_config(config, expected_config)
+ self.check_pre_config(config, expected_preconfig)
self.check_main_config(config)
self.check_global_config(config)
def test_init_default_config(self):
- self.check_config("init_default_config", {})
+ self.check_config("init_default_config", {}, {})
def test_init_global_config(self):
+ preconfig = {
+ 'utf8_mode': 1,
+ }
config = {
'program_name': './globalvar',
'site_import': 0,
@@ -509,7 +545,6 @@
'quiet': 1,
'buffered_stdio': 0,
- 'utf8_mode': 1,
'stdio_encoding': 'utf-8',
'stdio_errors': 'surrogateescape',
'filesystem_encoding': 'utf-8',
@@ -517,21 +552,23 @@
'user_site_directory': 0,
'_frozen': 1,
}
- self.check_config("init_global_config", config)
+ self.check_config("init_global_config", config, preconfig)
def test_init_from_config(self):
+ preconfig = {
+ 'allocator': 'malloc',
+ 'utf8_mode': 1,
+ }
config = {
'install_signal_handlers': 0,
'use_hash_seed': 1,
'hash_seed': 123,
- 'allocator': 'malloc',
'tracemalloc': 2,
'import_time': 1,
'show_ref_count': 1,
'show_alloc_count': 1,
'malloc_stats': 1,
- 'utf8_mode': 1,
'stdio_encoding': 'iso8859-1',
'stdio_errors': 'replace',
'filesystem_encoding': 'utf-8',
@@ -559,16 +596,18 @@
'_check_hash_pycs_mode': 'always',
'_frozen': 1,
}
- self.check_config("init_from_config", config)
+ self.check_config("init_from_config", config, preconfig)
+ INIT_ENV_PRECONFIG = {
+ 'allocator': 'malloc',
+ 'utf8_mode': 1,
+ }
INIT_ENV_CONFIG = {
'use_hash_seed': 1,
'hash_seed': 42,
- 'allocator': 'malloc',
'tracemalloc': 2,
'import_time': 1,
'malloc_stats': 1,
- 'utf8_mode': 1,
'filesystem_encoding': 'utf-8',
'filesystem_errors': UTF8_MODE_ERRORS,
'inspect': 1,
@@ -584,35 +623,43 @@
}
def test_init_env(self):
- self.check_config("init_env", self.INIT_ENV_CONFIG)
+ self.check_config("init_env", self.INIT_ENV_CONFIG, self.INIT_ENV_PRECONFIG)
def test_init_env_dev_mode(self):
+ preconfig = dict(self.INIT_ENV_PRECONFIG,
+ allocator='debug')
config = dict(self.INIT_ENV_CONFIG,
- allocator='debug',
dev_mode=1)
- self.check_config("init_env_dev_mode", config)
+ self.check_config("init_env_dev_mode", config, preconfig)
- def test_init_env_dev_mode(self):
+ def test_init_env_dev_mode_alloc(self):
+ preconfig = dict(self.INIT_ENV_PRECONFIG,
+ allocator='malloc')
config = dict(self.INIT_ENV_CONFIG,
- allocator='malloc',
dev_mode=1)
- self.check_config("init_env_dev_mode_alloc", config)
+ self.check_config("init_env_dev_mode_alloc", config, preconfig)
def test_init_dev_mode(self):
- config = {
- 'dev_mode': 1,
- 'faulthandler': 1,
+ preconfig = {
'allocator': 'debug',
}
- self.check_config("init_dev_mode", config)
+ config = {
+ 'faulthandler': 1,
+ 'dev_mode': 1,
+ }
+ self.check_config("init_dev_mode", config, preconfig)
def test_init_isolated(self):
+ preconfig = {
+ 'isolated': 0,
+ 'use_environment': 1,
+ }
config = {
'isolated': 1,
'use_environment': 0,
'user_site_directory': 0,
}
- self.check_config("init_isolated", config)
+ self.check_config("init_isolated", config, preconfig)
if __name__ == "__main__":
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index b9072e0..bc675aa 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -375,6 +375,11 @@
self.assertEqual(inspect.getsource(obj),
self.sourcerange(top, bottom))
+class SlotUser:
+ 'Docstrings for __slots__'
+ __slots__ = {'power': 'measured in kilowatts',
+ 'distance': 'measured in kilometers'}
+
class TestRetrievingSourceCode(GetSourceBase):
fodderModule = mod
@@ -429,6 +434,10 @@
'A longer,\n\nindented\n\ndocstring.')
self.assertEqual(inspect.getdoc(git.abuse),
'Another\n\ndocstring\n\ncontaining\n\ntabs')
+ self.assertEqual(inspect.getdoc(SlotUser.power),
+ 'measured in kilowatts')
+ self.assertEqual(inspect.getdoc(SlotUser.distance),
+ 'measured in kilometers')
@unittest.skipIf(sys.flags.optimize >= 2,
"Docstrings are omitted with -O2 and above")
diff --git a/Lib/test/test_keyword.py b/Lib/test/test_keyword.py
index af99f52..3e2a8b3 100644
--- a/Lib/test/test_keyword.py
+++ b/Lib/test/test_keyword.py
@@ -1,20 +1,5 @@
import keyword
import unittest
-from test import support
-import filecmp
-import os
-import sys
-import subprocess
-import shutil
-import textwrap
-
-KEYWORD_FILE = support.findfile('keyword.py')
-GRAMMAR_FILE = os.path.join(os.path.split(__file__)[0],
- '..', '..', 'Python', 'graminit.c')
-TEST_PY_FILE = 'keyword_test.py'
-GRAMMAR_TEST_FILE = 'graminit_test.c'
-PY_FILE_WITHOUT_KEYWORDS = 'minimal_keyword.py'
-NONEXISTENT_FILE = 'not_here.txt'
class Test_iskeyword(unittest.TestCase):
@@ -35,103 +20,17 @@
keyword.kwlist = ['its', 'all', 'eggs', 'beans', 'and', 'a', 'slice']
self.assertFalse(keyword.iskeyword('eggs'))
+ def test_all_keywords_fail_to_be_used_as_names(self):
+ for key in keyword.kwlist:
+ with self.assertRaises(SyntaxError):
+ exec(f"{key} = 42")
-class TestKeywordGeneration(unittest.TestCase):
+ def test_async_and_await_are_keywords(self):
+ self.assertIn("async", keyword.kwlist)
+ self.assertIn("await", keyword.kwlist)
- def _copy_file_without_generated_keywords(self, source_file, dest_file):
- with open(source_file, 'rb') as fp:
- lines = fp.readlines()
- nl = lines[0][len(lines[0].strip()):]
- with open(dest_file, 'wb') as fp:
- fp.writelines(lines[:lines.index(b"#--start keywords--" + nl) + 1])
- fp.writelines(lines[lines.index(b"#--end keywords--" + nl):])
-
- def _generate_keywords(self, grammar_file, target_keyword_py_file):
- proc = subprocess.Popen([sys.executable,
- KEYWORD_FILE,
- grammar_file,
- target_keyword_py_file], stderr=subprocess.PIPE)
- stderr = proc.communicate()[1]
- return proc.returncode, stderr
-
- @unittest.skipIf(not os.path.exists(GRAMMAR_FILE),
- 'test only works from source build directory')
- def test_real_grammar_and_keyword_file(self):
- self._copy_file_without_generated_keywords(KEYWORD_FILE, TEST_PY_FILE)
- self.addCleanup(support.unlink, TEST_PY_FILE)
- self.assertFalse(filecmp.cmp(KEYWORD_FILE, TEST_PY_FILE))
- self.assertEqual((0, b''), self._generate_keywords(GRAMMAR_FILE,
- TEST_PY_FILE))
- self.assertTrue(filecmp.cmp(KEYWORD_FILE, TEST_PY_FILE))
-
- def test_grammar(self):
- self._copy_file_without_generated_keywords(KEYWORD_FILE, TEST_PY_FILE)
- self.addCleanup(support.unlink, TEST_PY_FILE)
- with open(GRAMMAR_TEST_FILE, 'w') as fp:
- # Some of these are probably implementation accidents.
- fp.writelines(textwrap.dedent("""\
- {2, 1},
- {11, "encoding_decl", 0, 2, states_79,
- "\000\000\040\000\000\000\000\000\000\000\000\000"
- "\000\000\000\000\000\000\000\000\000"},
- {1, "jello"},
- {326, 0},
- {1, "turnip"},
- \t{1, "This one is tab indented"
- {278, 0},
- {1, "crazy but legal"
- "also legal" {1, "
- {1, "continue"},
- {1, "lemon"},
- {1, "tomato"},
- {1, "wigii"},
- {1, 'no good'}
- {283, 0},
- {1, "too many spaces"}"""))
- self.addCleanup(support.unlink, GRAMMAR_TEST_FILE)
- self._generate_keywords(GRAMMAR_TEST_FILE, TEST_PY_FILE)
- expected = [
- " 'This one is tab indented',",
- " 'also legal',",
- " 'continue',",
- " 'crazy but legal',",
- " 'jello',",
- " 'lemon',",
- " 'tomato',",
- " 'turnip',",
- " 'wigii',",
- ]
- with open(TEST_PY_FILE) as fp:
- lines = fp.read().splitlines()
- start = lines.index("#--start keywords--") + 1
- end = lines.index("#--end keywords--")
- actual = lines[start:end]
- self.assertEqual(actual, expected)
-
- def test_empty_grammar_results_in_no_keywords(self):
- self._copy_file_without_generated_keywords(KEYWORD_FILE,
- PY_FILE_WITHOUT_KEYWORDS)
- self.addCleanup(support.unlink, PY_FILE_WITHOUT_KEYWORDS)
- shutil.copyfile(KEYWORD_FILE, TEST_PY_FILE)
- self.addCleanup(support.unlink, TEST_PY_FILE)
- self.assertEqual((0, b''), self._generate_keywords(os.devnull,
- TEST_PY_FILE))
- self.assertTrue(filecmp.cmp(TEST_PY_FILE, PY_FILE_WITHOUT_KEYWORDS))
-
- def test_keywords_py_without_markers_produces_error(self):
- rc, stderr = self._generate_keywords(os.devnull, os.devnull)
- self.assertNotEqual(rc, 0)
- self.assertRegex(stderr, b'does not contain format markers')
-
- def test_missing_grammar_file_produces_error(self):
- rc, stderr = self._generate_keywords(NONEXISTENT_FILE, KEYWORD_FILE)
- self.assertNotEqual(rc, 0)
- self.assertRegex(stderr, b'(?ms)' + NONEXISTENT_FILE.encode())
-
- def test_missing_keywords_py_file_produces_error(self):
- rc, stderr = self._generate_keywords(os.devnull, NONEXISTENT_FILE)
- self.assertNotEqual(rc, 0)
- self.assertRegex(stderr, b'(?ms)' + NONEXISTENT_FILE.encode())
+ def test_keywords_are_sorted(self):
+ self.assertListEqual(sorted(keyword.kwlist), keyword.kwlist)
if __name__ == "__main__":
diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py
index 485ffe2..7f7839d 100644
--- a/Lib/test/test_statistics.py
+++ b/Lib/test/test_statistics.py
@@ -2051,7 +2051,7 @@
nd = statistics.NormalDist(300, 23)
with self.assertRaises(TypeError):
vars(nd)
- self.assertEqual(nd.__slots__, ('mu', 'sigma'))
+ self.assertEqual(tuple(nd.__slots__), ('mu', 'sigma'))
def test_instantiation_and_attributes(self):
nd = statistics.NormalDist(500, 17)
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 8042e8e..174b12c 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -724,7 +724,7 @@
# Regenerate all generated files
regen-all: regen-opcode regen-opcode-targets regen-typeslots regen-grammar \
- regen-token regen-symbol regen-ast regen-importlib clinic
+ regen-token regen-keyword regen-symbol regen-ast regen-importlib clinic
############################################################################
# Special rules for object files
@@ -843,6 +843,15 @@
$(srcdir)/Grammar/Tokens \
$(srcdir)/Lib/token.py
+.PHONY: regen-keyword
+regen-keyword:
+ # Regenerate Lib/keyword.py from Grammar/Grammar and Grammar/Tokens
+ # using Parser/pgen
+ $(PYTHON_FOR_REGEN) -m Parser.pgen.keywordgen $(srcdir)/Grammar/Grammar \
+ $(srcdir)/Grammar/Tokens \
+ $(srcdir)/Lib/keyword.py.new
+ $(UPDATE_FILE) $(srcdir)/Lib/keyword.py $(srcdir)/Lib/keyword.py.new
+
.PHONY: regen-symbol
regen-symbol: $(srcdir)/Include/graminit.h
# Regenerate Lib/symbol.py from Include/graminit.h
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-03-20-00-37-24.bpo-12456.fnKoKo.rst b/Misc/NEWS.d/next/Core and Builtins/2019-03-20-00-37-24.bpo-12456.fnKoKo.rst
new file mode 100644
index 0000000..10d6c49
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-03-20-00-37-24.bpo-12456.fnKoKo.rst
@@ -0,0 +1,2 @@
+Regenerate :mod:`keyword` from the Grammar and Tokens file using pgen. Patch
+by Pablo Galindo.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-03-25-23-37-26.bpo-36430.sd9xxQ.rst b/Misc/NEWS.d/next/Core and Builtins/2019-03-25-23-37-26.bpo-36430.sd9xxQ.rst
new file mode 100644
index 0000000..a65ee09
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-03-25-23-37-26.bpo-36430.sd9xxQ.rst
@@ -0,0 +1 @@
+Fix a possible reference leak in :func:`itertools.count`.
diff --git a/Misc/NEWS.d/next/Documentation/2019-03-23-09-25-12.bpo-36345.L704Zv.rst b/Misc/NEWS.d/next/Documentation/2019-03-23-09-25-12.bpo-36345.L704Zv.rst
new file mode 100644
index 0000000..c6206a7
--- /dev/null
+++ b/Misc/NEWS.d/next/Documentation/2019-03-23-09-25-12.bpo-36345.L704Zv.rst
@@ -0,0 +1,2 @@
+Using the code of the ``Tools/scripts/serve.py`` script as an example in the
+:mod:`wsgiref` documentation. Contributed by Stéphane Wirtel.
diff --git a/Misc/NEWS.d/next/Library/2019-03-22-13-47-52.bpo-36326.WCnEI5.rst b/Misc/NEWS.d/next/Library/2019-03-22-13-47-52.bpo-36326.WCnEI5.rst
new file mode 100644
index 0000000..e458a70
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-03-22-13-47-52.bpo-36326.WCnEI5.rst
@@ -0,0 +1,2 @@
+inspect.getdoc() can now find docstrings for member objects when __slots__
+is a dictionary.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 350ef77..c82ba0c 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -4675,27 +4675,9 @@
static PyObject *
-get_global_config(PyObject *self, PyObject *Py_UNUSED(args))
+get_configs(PyObject *self, PyObject *Py_UNUSED(args))
{
- return _Py_GetGlobalVariablesAsDict();
-}
-
-
-static PyObject *
-get_core_config(PyObject *self, PyObject *Py_UNUSED(args))
-{
- PyInterpreterState *interp = _PyInterpreterState_Get();
- const _PyCoreConfig *config = _PyInterpreterState_GetCoreConfig(interp);
- return _PyCoreConfig_AsDict(config);
-}
-
-
-static PyObject *
-get_main_config(PyObject *self, PyObject *Py_UNUSED(args))
-{
- PyInterpreterState *interp = _PyInterpreterState_Get();
- const _PyMainInterpreterConfig *config = _PyInterpreterState_GetMainConfig(interp);
- return _PyMainInterpreterConfig_AsDict(config);
+ return _Py_GetConfigsAsDict();
}
@@ -4942,9 +4924,7 @@
{"bad_get", (PyCFunction)(void(*)(void))bad_get, METH_FASTCALL},
{"EncodeLocaleEx", encode_locale_ex, METH_VARARGS},
{"DecodeLocaleEx", decode_locale_ex, METH_VARARGS},
- {"get_global_config", get_global_config, METH_NOARGS},
- {"get_core_config", get_core_config, METH_NOARGS},
- {"get_main_config", get_main_config, METH_NOARGS},
+ {"get_configs", get_configs, METH_NOARGS},
#ifdef Py_REF_DEBUG
{"negative_refcount", negative_refcount, METH_NOARGS},
#endif
diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c
index 536f7fa..103029d 100644
--- a/Modules/itertoolsmodule.c
+++ b/Modules/itertoolsmodule.c
@@ -4089,6 +4089,7 @@
lz = (countobject *)type->tp_alloc(type, 0);
if (lz == NULL) {
Py_XDECREF(long_cnt);
+ Py_DECREF(long_step);
return NULL;
}
lz->cnt = cnt;
diff --git a/Modules/main.c b/Modules/main.c
index 197c9b3..9fcc76e 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -294,7 +294,7 @@
goto done;
}
- err = _Py_PreInitializeFromPreConfig(&config);
+ err = _Py_PreInitializeInPlace(&config);
done:
_PyPreConfig_Clear(&config);
@@ -311,11 +311,6 @@
return err;
}
- err = _PyCoreConfig_Write(config);
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
-
return _Py_InitializeCore(interp_p, config);
}
@@ -483,7 +478,7 @@
static void
pymain_import_readline(const _PyCoreConfig *config)
{
- if (config->preconfig.isolated) {
+ if (config->isolated) {
return;
}
if (!config->inspect && RUN_CODE(config)) {
@@ -655,7 +650,7 @@
static void
pymain_run_startup(_PyCoreConfig *config, PyCompilerFlags *cf)
{
- const char *startup = _PyCoreConfig_GetEnv(config, "PYTHONSTARTUP");
+ const char *startup = _Py_GetEnv(config->use_environment, "PYTHONSTARTUP");
if (startup == NULL) {
return;
}
@@ -735,7 +730,7 @@
{
/* Check this environment variable at the end, to give programs the
opportunity to set it from Python. */
- if (!Py_InspectFlag && _PyCoreConfig_GetEnv(config, "PYTHONINSPECT")) {
+ if (!Py_InspectFlag && _Py_GetEnv(config->use_environment, "PYTHONINSPECT")) {
Py_InspectFlag = 1;
config->inspect = 1;
}
@@ -775,7 +770,7 @@
goto done;
}
}
- else if (!config->preconfig.isolated) {
+ else if (!config->isolated) {
PyObject *path0 = NULL;
if (_PyPathConfig_ComputeSysPath0(&config->argv, &path0)) {
if (path0 == NULL) {
diff --git a/Parser/pgen/keywordgen.py b/Parser/pgen/keywordgen.py
new file mode 100644
index 0000000..eeb3ef7
--- /dev/null
+++ b/Parser/pgen/keywordgen.py
@@ -0,0 +1,60 @@
+"""Generate Lib/keyword.py from the Grammar and Tokens files using pgen"""
+
+import argparse
+
+from .pgen import ParserGenerator
+
+TEMPLATE = r'''
+"""Keywords (from "Grammar/Grammar")
+
+This file is automatically generated; please don't muck it up!
+
+To update the symbols in this file, 'cd' to the top directory of
+the python source tree and run:
+
+ python3 -m Parser.pgen.keywordgen Grammar/Grammar \
+ Grammar/Tokens \
+ Lib/keyword.py
+
+Alternatively, you can run 'make regen-keyword'.
+"""
+
+__all__ = ["iskeyword", "kwlist"]
+
+kwlist = [
+ {keywords}
+]
+
+iskeyword = frozenset(kwlist).__contains__
+'''.lstrip()
+
+EXTRA_KEYWORDS = ["async", "await"]
+
+
+def main():
+ parser = argparse.ArgumentParser(description="Generate the Lib/keywords.py "
+ "file from the grammar.")
+ parser.add_argument(
+ "grammar", type=str, help="The file with the grammar definition in EBNF format"
+ )
+ parser.add_argument(
+ "tokens", type=str, help="The file with the token definitions"
+ )
+ parser.add_argument(
+ "keyword_file",
+ type=argparse.FileType('w'),
+ help="The path to write the keyword definitions",
+ )
+ args = parser.parse_args()
+ p = ParserGenerator(args.grammar, args.tokens)
+ grammar = p.make_grammar()
+
+ with args.keyword_file as thefile:
+ all_keywords = sorted(list(grammar.keywords) + EXTRA_KEYWORDS)
+
+ keywords = ",\n ".join(map(repr, all_keywords))
+ thefile.write(TEMPLATE.format(keywords=keywords))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/Programs/_freeze_importlib.c b/Programs/_freeze_importlib.c
index e6c51a4..0818012 100644
--- a/Programs/_freeze_importlib.c
+++ b/Programs/_freeze_importlib.c
@@ -77,7 +77,7 @@
text[text_size] = '\0';
_PyCoreConfig config = _PyCoreConfig_INIT;
- config.preconfig.use_environment = 0;
+ config.use_environment = 0;
config.user_site_directory = 0;
config.site_import = 0;
config.program_name = L"./_freeze_importlib";
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 7c143f1..70ef45f 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -301,64 +301,29 @@
static int
dump_config_impl(void)
{
- PyObject *config = NULL;
- PyObject *dict = NULL;
-
- config = PyDict_New();
+ PyObject *config = _Py_GetConfigsAsDict();
if (config == NULL) {
- goto error;
+ return -1;
}
- /* global config */
- dict = _Py_GetGlobalVariablesAsDict();
- if (dict == NULL) {
- goto error;
- }
- if (PyDict_SetItemString(config, "global_config", dict) < 0) {
- goto error;
- }
- Py_CLEAR(dict);
-
- /* core config */
- PyInterpreterState *interp = _PyInterpreterState_Get();
- const _PyCoreConfig *core_config = _PyInterpreterState_GetCoreConfig(interp);
- dict = _PyCoreConfig_AsDict(core_config);
- if (dict == NULL) {
- goto error;
- }
- if (PyDict_SetItemString(config, "core_config", dict) < 0) {
- goto error;
- }
- Py_CLEAR(dict);
-
- /* main config */
- const _PyMainInterpreterConfig *main_config = _PyInterpreterState_GetMainConfig(interp);
- dict = _PyMainInterpreterConfig_AsDict(main_config);
- if (dict == NULL) {
- goto error;
- }
- if (PyDict_SetItemString(config, "main_config", dict) < 0) {
- goto error;
- }
- Py_CLEAR(dict);
-
+ PyObject *res;
PyObject *json = PyImport_ImportModule("json");
- PyObject *res = PyObject_CallMethod(json, "dumps", "O", config);
- Py_DECREF(json);
+ if (json) {
+ res = PyObject_CallMethod(json, "dumps", "O", config);
+ Py_DECREF(json);
+ }
+ else {
+ res = NULL;
+ }
Py_CLEAR(config);
if (res == NULL) {
- goto error;
+ return -1;
}
PySys_FormatStdout("%S\n", res);
Py_DECREF(res);
return 0;
-
-error:
- Py_XDECREF(config);
- Py_XDECREF(dict);
- return -1;
}
@@ -432,6 +397,22 @@
static int test_init_from_config(void)
{
+ _PyInitError err;
+
+ _PyPreConfig preconfig = _PyPreConfig_INIT;
+
+ putenv("PYTHONMALLOC=malloc_debug");
+ preconfig.allocator = "malloc";
+
+ putenv("PYTHONUTF8=0");
+ Py_UTF8Mode = 0;
+ preconfig.utf8_mode = 1;
+
+ err = _Py_PreInitializeFromPreConfig(&preconfig);
+ if (_Py_INIT_FAILED(err)) {
+ _Py_ExitInitError(err);
+ }
+
/* Test _Py_InitializeFromConfig() */
_PyCoreConfig config = _PyCoreConfig_INIT;
config.install_signal_handlers = 0;
@@ -442,9 +423,6 @@
config.use_hash_seed = 1;
config.hash_seed = 123;
- putenv("PYTHONMALLOC=malloc_debug");
- config.preconfig.allocator = "malloc";
-
/* dev_mode=1 is tested in test_init_dev_mode() */
putenv("PYTHONFAULTHANDLER=");
@@ -465,10 +443,6 @@
/* FIXME: test coerce_c_locale and coerce_c_locale_warn */
- putenv("PYTHONUTF8=0");
- Py_UTF8Mode = 0;
- config.preconfig.utf8_mode = 1;
-
putenv("PYTHONPYCACHEPREFIX=env_pycache_prefix");
config.pycache_prefix = L"conf_pycache_prefix";
@@ -556,7 +530,7 @@
Py_FrozenFlag = 0;
config._frozen = 1;
- _PyInitError err = _Py_InitializeFromConfig(&config);
+ err = _Py_InitializeFromConfig(&config);
/* Don't call _PyCoreConfig_Clear() since all strings are static */
if (_Py_INIT_FAILED(err)) {
_Py_ExitInitError(err);
@@ -642,20 +616,30 @@
static int test_init_isolated(void)
{
+ _PyInitError err;
+
+ _PyPreConfig preconfig = _PyPreConfig_INIT;
+
+ /* Set coerce_c_locale and utf8_mode to not depend on the locale */
+ preconfig.coerce_c_locale = 0;
+ preconfig.utf8_mode = 0;
+
+ err = _Py_PreInitializeFromPreConfig(&preconfig);
+ if (_Py_INIT_FAILED(err)) {
+ _Py_ExitInitError(err);
+ }
+
/* Test _PyCoreConfig.isolated=1 */
_PyCoreConfig config = _PyCoreConfig_INIT;
Py_IsolatedFlag = 0;
- config.preconfig.isolated = 1;
+ config.isolated = 1;
- /* Set coerce_c_locale and utf8_mode to not depend on the locale */
- config.preconfig.coerce_c_locale = 0;
- config.preconfig.utf8_mode = 0;
/* Use path starting with "./" avoids a search along the PATH */
config.program_name = L"./_testembed";
test_init_env_dev_mode_putenvs();
- _PyInitError err = _Py_InitializeFromConfig(&config);
+ err = _Py_InitializeFromConfig(&config);
if (_Py_INIT_FAILED(err)) {
_Py_ExitInitError(err);
}
@@ -670,7 +654,7 @@
_PyCoreConfig config = _PyCoreConfig_INIT;
putenv("PYTHONFAULTHANDLER=");
putenv("PYTHONMALLOC=");
- config.preconfig.dev_mode = 1;
+ config.dev_mode = 1;
config.program_name = L"./_testembed";
_PyInitError err = _Py_InitializeFromConfig(&config);
if (_Py_INIT_FAILED(err)) {
diff --git a/Python/ceval.c b/Python/ceval.c
index 40320bf..28e9232 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -4948,7 +4948,7 @@
}
x = PyImport_GetModule(fullmodname);
Py_DECREF(fullmodname);
- if (x == NULL) {
+ if (x == NULL && !PyErr_Occurred()) {
goto error;
}
Py_DECREF(pkgname);
@@ -4971,7 +4971,7 @@
"cannot import name %R from %R (unknown location)",
name, pkgname_or_unknown
);
- /* NULL check for errmsg done by PyErr_SetImportError. */
+ /* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */
PyErr_SetImportError(errmsg, pkgname, NULL);
}
else {
@@ -4979,7 +4979,7 @@
"cannot import name %R from %R (%S)",
name, pkgname_or_unknown, pkgpath
);
- /* NULL check for errmsg done by PyErr_SetImportError. */
+ /* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */
PyErr_SetImportError(errmsg, pkgname, pkgpath);
}
diff --git a/Python/coreconfig.c b/Python/coreconfig.c
index ba5abb6..2e6eb40 100644
--- a/Python/coreconfig.c
+++ b/Python/coreconfig.c
@@ -131,7 +131,7 @@
#endif
-PyObject *
+static PyObject *
_Py_GetGlobalVariablesAsDict(void)
{
PyObject *dict, *obj;
@@ -469,8 +469,6 @@
void
_PyCoreConfig_Clear(_PyCoreConfig *config)
{
- _PyPreConfig_Clear(&config->preconfig);
-
#define CLEAR(ATTR) \
do { \
PyMem_RawFree(ATTR); \
@@ -514,10 +512,6 @@
{
_PyCoreConfig_Clear(config);
- if (_PyPreConfig_Copy(&config->preconfig, &config2->preconfig) < 0) {
- return -1;
- }
-
#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
#define COPY_STR_ATTR(ATTR) \
do { \
@@ -544,6 +538,9 @@
} \
} while (0)
+ COPY_ATTR(isolated);
+ COPY_ATTR(use_environment);
+ COPY_ATTR(dev_mode);
COPY_ATTR(install_signal_handlers);
COPY_ATTR(use_hash_seed);
COPY_ATTR(hash_seed);
@@ -610,21 +607,21 @@
}
-const char*
+static const char*
_PyCoreConfig_GetEnv(const _PyCoreConfig *config, const char *name)
{
- return _PyPreConfig_GetEnv(&config->preconfig, name);
+ return _Py_GetEnv(config->use_environment, name);
}
-int
+static int
_PyCoreConfig_GetEnvDup(const _PyCoreConfig *config,
wchar_t **dest,
wchar_t *wname, char *name)
{
- assert(config->preconfig.use_environment >= 0);
+ assert(config->use_environment >= 0);
- if (!config->preconfig.use_environment) {
+ if (!config->use_environment) {
*dest = NULL;
return 0;
}
@@ -668,8 +665,6 @@
void
_PyCoreConfig_GetGlobalConfig(_PyCoreConfig *config)
{
- _PyPreConfig_GetGlobalConfig(&config->preconfig);
-
#define COPY_FLAG(ATTR, VALUE) \
if (config->ATTR == -1) { \
config->ATTR = VALUE; \
@@ -679,6 +674,8 @@
config->ATTR = !(VALUE); \
}
+ COPY_FLAG(isolated, Py_IsolatedFlag);
+ COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
COPY_FLAG(bytes_warning, Py_BytesWarningFlag);
COPY_FLAG(inspect, Py_InspectFlag);
COPY_FLAG(interactive, Py_InteractiveFlag);
@@ -714,6 +711,8 @@
VAR = !config->ATTR; \
}
+ COPY_FLAG(isolated, Py_IsolatedFlag);
+ COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag);
COPY_FLAG(bytes_warning, Py_BytesWarningFlag);
COPY_FLAG(inspect, Py_InspectFlag);
COPY_FLAG(interactive, Py_InteractiveFlag);
@@ -924,34 +923,34 @@
static _PyInitError
config_read_env_vars(_PyCoreConfig *config)
{
- _PyPreConfig *preconfig = &config->preconfig;
+ int use_env = config->use_environment;
/* Get environment variables */
- _Py_get_env_flag(preconfig, &config->parser_debug, "PYTHONDEBUG");
- _Py_get_env_flag(preconfig, &config->verbose, "PYTHONVERBOSE");
- _Py_get_env_flag(preconfig, &config->optimization_level, "PYTHONOPTIMIZE");
- _Py_get_env_flag(preconfig, &config->inspect, "PYTHONINSPECT");
+ _Py_get_env_flag(use_env, &config->parser_debug, "PYTHONDEBUG");
+ _Py_get_env_flag(use_env, &config->verbose, "PYTHONVERBOSE");
+ _Py_get_env_flag(use_env, &config->optimization_level, "PYTHONOPTIMIZE");
+ _Py_get_env_flag(use_env, &config->inspect, "PYTHONINSPECT");
int dont_write_bytecode = 0;
- _Py_get_env_flag(preconfig, &dont_write_bytecode, "PYTHONDONTWRITEBYTECODE");
+ _Py_get_env_flag(use_env, &dont_write_bytecode, "PYTHONDONTWRITEBYTECODE");
if (dont_write_bytecode) {
config->write_bytecode = 0;
}
int no_user_site_directory = 0;
- _Py_get_env_flag(preconfig, &no_user_site_directory, "PYTHONNOUSERSITE");
+ _Py_get_env_flag(use_env, &no_user_site_directory, "PYTHONNOUSERSITE");
if (no_user_site_directory) {
config->user_site_directory = 0;
}
int unbuffered_stdio = 0;
- _Py_get_env_flag(preconfig, &unbuffered_stdio, "PYTHONUNBUFFERED");
+ _Py_get_env_flag(use_env, &unbuffered_stdio, "PYTHONUNBUFFERED");
if (unbuffered_stdio) {
config->buffered_stdio = 0;
}
#ifdef MS_WINDOWS
- _Py_get_env_flag(preconfig, &config->legacy_windows_stdio,
+ _Py_get_env_flag(use_env, &config->legacy_windows_stdio,
"PYTHONLEGACYWINDOWSSTDIO");
#endif
@@ -1149,7 +1148,8 @@
static _PyInitError
-config_init_stdio_encoding(_PyCoreConfig *config)
+config_init_stdio_encoding(_PyCoreConfig *config,
+ const _PyPreConfig *preconfig)
{
/* If Py_SetStandardStreamEncoding() have been called, use these
parameters. */
@@ -1219,7 +1219,7 @@
}
/* UTF-8 Mode uses UTF-8/surrogateescape */
- if (config->preconfig.utf8_mode) {
+ if (preconfig->utf8_mode) {
if (config->stdio_encoding == NULL) {
config->stdio_encoding = _PyMem_RawStrdup("utf-8");
if (config->stdio_encoding == NULL) {
@@ -1254,10 +1254,10 @@
static _PyInitError
-config_init_fs_encoding(_PyCoreConfig *config)
+config_init_fs_encoding(_PyCoreConfig *config, const _PyPreConfig *preconfig)
{
#ifdef MS_WINDOWS
- if (config->preconfig.legacy_windows_fs_encoding) {
+ if (preconfig->legacy_windows_fs_encoding) {
/* Legacy Windows filesystem encoding: mbcs/replace */
if (config->filesystem_encoding == NULL) {
config->filesystem_encoding = _PyMem_RawStrdup("mbcs");
@@ -1292,7 +1292,7 @@
}
#else
if (config->filesystem_encoding == NULL) {
- if (config->preconfig.utf8_mode) {
+ if (preconfig->utf8_mode) {
/* UTF-8 Mode use: utf-8/surrogateescape */
config->filesystem_encoding = _PyMem_RawStrdup("utf-8");
/* errors defaults to surrogateescape above */
@@ -1341,12 +1341,8 @@
{
_PyInitError err;
- err = _Py_PreInitializeFromConfig(config);
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
-
- _PyPreCmdline_GetPreConfig(cmdline, &_PyRuntime.preconfig);
+ const _PyPreConfig *preconfig = &_PyRuntime.preconfig;
+ _PyPreCmdline_GetPreConfig(cmdline, preconfig);
_PyPreCmdline_GetCoreConfig(cmdline, config);
err = _PyPreCmdline_Read(cmdline);
@@ -1360,19 +1356,16 @@
return _Py_INIT_NO_MEMORY();
}
- if (_PyPreConfig_Copy(&config->preconfig, &_PyRuntime.preconfig) < 0) {
- return _Py_INIT_NO_MEMORY();
- }
-
_PyCoreConfig_GetGlobalConfig(config);
- assert(config->preconfig.use_environment >= 0);
+ assert(config->use_environment >= 0);
- if (config->preconfig.isolated > 0) {
+ if (config->isolated > 0) {
+ config->use_environment = 0;
config->user_site_directory = 0;
}
- if (config->preconfig.use_environment) {
+ if (config->use_environment) {
err = config_read_env_vars(config);
if (_Py_INIT_FAILED(err)) {
return err;
@@ -1421,7 +1414,7 @@
}
/* default values */
- if (config->preconfig.dev_mode) {
+ if (config->dev_mode) {
if (config->faulthandler < 0) {
config->faulthandler = 1;
}
@@ -1438,13 +1431,13 @@
}
if (config->filesystem_encoding == NULL || config->filesystem_errors == NULL) {
- err = config_init_fs_encoding(config);
+ err = config_init_fs_encoding(config, preconfig);
if (_Py_INIT_FAILED(err)) {
return err;
}
}
- err = config_init_stdio_encoding(config);
+ err = config_init_stdio_encoding(config, preconfig);
if (_Py_INIT_FAILED(err)) {
return err;
}
@@ -1456,7 +1449,7 @@
}
}
- assert(config->preconfig.use_environment >= 0);
+ assert(config->use_environment >= 0);
assert(config->filesystem_encoding != NULL);
assert(config->filesystem_errors != NULL);
assert(config->stdio_encoding != NULL);
@@ -1544,26 +1537,15 @@
- set Py_xxx global configuration variables
- initialize C standard streams (stdin, stdout, stderr) */
-_PyInitError
+void
_PyCoreConfig_Write(const _PyCoreConfig *config)
{
_PyCoreConfig_SetGlobalConfig(config);
config_init_stdio(config);
-
- /* Write the new pre-configuration into _PyRuntime */
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
- int res = _PyPreConfig_Copy(&_PyRuntime.preconfig, &config->preconfig);
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
- if (res < 0) {
- return _Py_INIT_NO_MEMORY();
- }
-
- return _Py_INIT_OK();
}
-PyObject *
+static PyObject *
_PyCoreConfig_AsDict(const _PyCoreConfig *config)
{
PyObject *dict;
@@ -1573,11 +1555,6 @@
return NULL;
}
- if (_PyPreConfig_AsDict(&config->preconfig, dict) < 0) {
- Py_DECREF(dict);
- return NULL;
- }
-
#define SET_ITEM(KEY, EXPR) \
do { \
PyObject *obj = (EXPR); \
@@ -1609,6 +1586,9 @@
#define SET_ITEM_WSTRLIST(LIST) \
SET_ITEM(#LIST, _PyWstrList_AsList(&config->LIST))
+ SET_ITEM_INT(isolated);
+ SET_ITEM_INT(use_environment);
+ SET_ITEM_INT(dev_mode);
SET_ITEM_INT(install_signal_handlers);
SET_ITEM_INT(use_hash_seed);
SET_ITEM_UINT(hash_seed);
@@ -1950,7 +1930,7 @@
* the lowest precedence entries first so that later entries override them.
*/
- if (config->preconfig.dev_mode) {
+ if (config->dev_mode) {
if (_PyWstrList_Append(&config->warnoptions, L"default")) {
return _Py_INIT_NO_MEMORY();
}
@@ -2106,7 +2086,7 @@
return err;
}
- if (config->preconfig.use_environment) {
+ if (config->use_environment) {
err = cmdline_init_env_warnoptions(cmdline, config);
if (_Py_INIT_FAILED(err)) {
return err;
@@ -2158,3 +2138,67 @@
cmdline_clear(&cmdline);
return err;
}
+
+
+PyObject*
+_Py_GetConfigsAsDict(void)
+{
+ PyObject *config = NULL;
+ PyObject *dict = NULL;
+
+ config = PyDict_New();
+ if (config == NULL) {
+ goto error;
+ }
+
+ /* global config */
+ dict = _Py_GetGlobalVariablesAsDict();
+ if (dict == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(config, "global_config", dict) < 0) {
+ goto error;
+ }
+ Py_CLEAR(dict);
+
+ /* pre config */
+ PyInterpreterState *interp = _PyInterpreterState_Get();
+ const _PyPreConfig *pre_config = &_PyRuntime.preconfig;
+ dict = _PyPreConfig_AsDict(pre_config);
+ if (dict == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(config, "pre_config", dict) < 0) {
+ goto error;
+ }
+ Py_CLEAR(dict);
+
+ /* core config */
+ const _PyCoreConfig *core_config = _PyInterpreterState_GetCoreConfig(interp);
+ dict = _PyCoreConfig_AsDict(core_config);
+ if (dict == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(config, "core_config", dict) < 0) {
+ goto error;
+ }
+ Py_CLEAR(dict);
+
+ /* main config */
+ const _PyMainInterpreterConfig *main_config = _PyInterpreterState_GetMainConfig(interp);
+ dict = _PyMainInterpreterConfig_AsDict(main_config);
+ if (dict == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(config, "main_config", dict) < 0) {
+ goto error;
+ }
+ Py_CLEAR(dict);
+
+ return config;
+
+error:
+ Py_XDECREF(config);
+ Py_XDECREF(dict);
+ return NULL;
+}
diff --git a/Python/import.c b/Python/import.c
index bf3a994..c00c3aa 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -966,11 +966,10 @@
Py_DECREF(v);
m = PyImport_GetModule(name);
- if (m == NULL) {
+ if (m == NULL && !PyErr_Occurred()) {
PyErr_Format(PyExc_ImportError,
"Loaded module %R not found in sys.modules",
name);
- return NULL;
}
return m;
@@ -1735,6 +1734,10 @@
}
mod = PyImport_GetModule(abs_name);
+ if (mod == NULL && PyErr_Occurred()) {
+ goto error;
+ }
+
if (mod != NULL && mod != Py_None) {
_Py_IDENTIFIER(__spec__);
_Py_IDENTIFIER(_lock_unlock_module);
@@ -1810,9 +1813,11 @@
final_mod = PyImport_GetModule(to_return);
Py_DECREF(to_return);
if (final_mod == NULL) {
- PyErr_Format(PyExc_KeyError,
- "%R not in sys.modules as expected",
- to_return);
+ if (!PyErr_Occurred()) {
+ PyErr_Format(PyExc_KeyError,
+ "%R not in sys.modules as expected",
+ to_return);
+ }
goto error;
}
}
@@ -1875,6 +1880,10 @@
PyObject *reloaded_module = NULL;
PyObject *imp = _PyImport_GetModuleId(&PyId_imp);
if (imp == NULL) {
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+
imp = PyImport_ImportModule("imp");
if (imp == NULL) {
return NULL;
diff --git a/Python/pathconfig.c b/Python/pathconfig.c
index f0b13fd..7fea7c3 100644
--- a/Python/pathconfig.c
+++ b/Python/pathconfig.c
@@ -331,7 +331,7 @@
#endif
if (path_config.isolated != -1) {
- config->preconfig.isolated = path_config.isolated;
+ config->isolated = path_config.isolated;
}
if (path_config.site_import != -1) {
config->site_import = path_config.site_import;
diff --git a/Python/preconfig.c b/Python/preconfig.c
index ac87a7a..d336352 100644
--- a/Python/preconfig.c
+++ b/Python/preconfig.c
@@ -143,6 +143,23 @@
COPY_ATTR(use_environment);
COPY_ATTR(isolated);
+ COPY_ATTR(dev_mode);
+
+#undef COPY_ATTR
+}
+
+
+void
+_PyPreCmdline_SetPreConfig(const _PyPreCmdline *cmdline, _PyPreConfig *config)
+{
+#define COPY_ATTR(ATTR) \
+ if (cmdline->ATTR != -1) { \
+ config->ATTR = cmdline->ATTR; \
+ }
+
+ COPY_ATTR(use_environment);
+ COPY_ATTR(isolated);
+ COPY_ATTR(dev_mode);
#undef COPY_ATTR
}
@@ -152,12 +169,13 @@
_PyPreCmdline_GetCoreConfig(_PyPreCmdline *cmdline, const _PyCoreConfig *config)
{
#define COPY_ATTR(ATTR) \
- if (config->preconfig.ATTR != -1) { \
- cmdline->ATTR = config->preconfig.ATTR; \
+ if (config->ATTR != -1) { \
+ cmdline->ATTR = config->ATTR; \
}
COPY_ATTR(use_environment);
COPY_ATTR(isolated);
+ COPY_ATTR(dev_mode);
#undef COPY_ATTR
}
@@ -167,12 +185,13 @@
_PyPreCmdline_SetCoreConfig(const _PyPreCmdline *cmdline, _PyCoreConfig *config)
{
#define COPY_ATTR(ATTR) \
- if (config->preconfig.ATTR == -1 && cmdline->ATTR != -1) { \
- config->preconfig.ATTR = cmdline->ATTR; \
+ if (config->ATTR == -1 && cmdline->ATTR != -1) { \
+ config->ATTR = cmdline->ATTR; \
}
COPY_ATTR(use_environment);
COPY_ATTR(isolated);
+ COPY_ATTR(dev_mode);
#undef COPY_ATTR
}
@@ -206,13 +225,13 @@
COPY_ATTR(isolated);
COPY_ATTR(use_environment);
+ COPY_ATTR(dev_mode);
COPY_ATTR(coerce_c_locale);
COPY_ATTR(coerce_c_locale_warn);
#ifdef MS_WINDOWS
COPY_ATTR(legacy_windows_fs_encoding);
#endif
COPY_ATTR(utf8_mode);
- COPY_ATTR(dev_mode);
COPY_STR_ATTR(allocator);
#undef COPY_ATTR
@@ -270,11 +289,11 @@
const char*
-_PyPreConfig_GetEnv(const _PyPreConfig *config, const char *name)
+_Py_GetEnv(int use_environment, const char *name)
{
- assert(config->use_environment >= 0);
+ assert(use_environment >= 0);
- if (!config->use_environment) {
+ if (!use_environment) {
return NULL;
}
@@ -288,6 +307,13 @@
}
+static const char*
+_PyPreConfig_GetEnv(const _PyPreConfig *config, const char *name)
+{
+ return _Py_GetEnv(config->use_environment, name);
+}
+
+
int
_Py_str_to_int(const char *str, int *result)
{
@@ -307,9 +333,9 @@
void
-_Py_get_env_flag(_PyPreConfig *config, int *flag, const char *name)
+_Py_get_env_flag(int use_environment, int *flag, const char *name)
{
- const char *var = _PyPreConfig_GetEnv(config, name);
+ const char *var = _Py_GetEnv(use_environment, name);
if (!var) {
return;
}
@@ -434,8 +460,9 @@
/* legacy_windows_fs_encoding, utf8_mode, coerce_c_locale */
if (config->use_environment) {
#ifdef MS_WINDOWS
- _Py_get_env_flag(config, &config->legacy_windows_fs_encoding,
- "PYTHONLEGACYWINDOWSFSENCODING");
+ _Py_get_env_flag(config->use_environment,
+ &config->legacy_windows_fs_encoding,
+ "PYTHONLEGACYWINDOWSFSENCODING");
#endif
const char *env = _PyPreConfig_GetEnv(config, "PYTHONCOERCECLOCALE");
@@ -559,24 +586,16 @@
}
-void
-_PyPreCmdline_SetPreConfig(const _PyPreCmdline *cmdline, _PyPreConfig *config)
+PyObject*
+_PyPreConfig_AsDict(const _PyPreConfig *config)
{
-#define COPY_ATTR(ATTR) \
- if (cmdline->ATTR != -1) { \
- config->ATTR = cmdline->ATTR; \
+ PyObject *dict;
+
+ dict = PyDict_New();
+ if (dict == NULL) {
+ return NULL;
}
- COPY_ATTR(use_environment);
- COPY_ATTR(isolated);
-
-#undef COPY_ATTR
-}
-
-
-int
-_PyPreConfig_AsDict(const _PyPreConfig *config, PyObject *dict)
-{
#define SET_ITEM(KEY, EXPR) \
do { \
PyObject *obj = (EXPR); \
@@ -608,10 +627,11 @@
#endif
SET_ITEM_INT(dev_mode);
SET_ITEM_STR(allocator);
- return 0;
+ return dict;
fail:
- return -1;
+ Py_DECREF(dict);
+ return NULL;
#undef FROM_STRING
#undef SET_ITEM
@@ -696,7 +716,7 @@
if (coreconfig) {
_PyPreCmdline_GetCoreConfig(&cmdline, coreconfig);
if (config->dev_mode == -1) {
- config->dev_mode = coreconfig->preconfig.dev_mode;
+ config->dev_mode = coreconfig->dev_mode;
}
}
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 66cadc9..b12fa82 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -286,9 +286,10 @@
"locales is recommended.\n";
static void
-_emit_stderr_warning_for_legacy_locale(const _PyCoreConfig *core_config)
+_emit_stderr_warning_for_legacy_locale(void)
{
- if (core_config->preconfig.coerce_c_locale_warn && _Py_LegacyLocaleDetected()) {
+ const _PyPreConfig *preconfig = &_PyRuntime.preconfig;
+ if (preconfig->coerce_c_locale_warn && _Py_LegacyLocaleDetected()) {
PySys_FormatStderr("%s", _C_LOCALE_WARNING);
}
}
@@ -675,6 +676,8 @@
{
PyInterpreterState *interp;
+ _PyCoreConfig_Write(core_config);
+
_PyInitError err = pycore_init_runtime(core_config);
if (_Py_INIT_FAILED(err)) {
return err;
@@ -720,54 +723,64 @@
const _PyCoreConfig *coreconfig)
{
_PyInitError err;
+ _PyPreConfig local_config = _PyPreConfig_INIT;
+ if (!config) {
+ config = &local_config;
+ }
err = _PyRuntime_Initialize();
if (_Py_INIT_FAILED(err)) {
- return err;
+ goto done;
}
if (_PyRuntime.pre_initialized) {
/* If it's already configured: ignored the new configuration */
- return _Py_INIT_OK();
- }
-
- if (!src_config && coreconfig) {
- src_config = &coreconfig->preconfig;
+ err = _Py_INIT_OK();
+ goto done;
}
if (src_config) {
if (_PyPreConfig_Copy(config, src_config) < 0) {
- return _Py_INIT_ERR("failed to copy pre config");
+ err = _Py_INIT_ERR("failed to copy pre config");
+ goto done;
}
}
err = _PyPreConfig_Read(config, NULL, coreconfig);
if (_Py_INIT_FAILED(err)) {
- return err;
+ goto done;
}
err = _PyPreConfig_Write(config);
if (_Py_INIT_FAILED(err)) {
- return err;
+ goto done;
}
_PyRuntime.pre_initialized = 1;
- return _Py_INIT_OK();
+ err = _Py_INIT_OK();
+
+done:
+ _PyPreConfig_Clear(&local_config);
+ return err;
}
_PyInitError
_Py_PreInitialize(void)
{
- _PyPreConfig config = _PyPreConfig_INIT;
- _PyInitError err = pyinit_preinit(&config, NULL, NULL);
- _PyPreConfig_Clear(&config);
- return err;
+ return pyinit_preinit(NULL, NULL, NULL);
}
_PyInitError
-_Py_PreInitializeFromPreConfig(_PyPreConfig *config)
+_Py_PreInitializeFromPreConfig(const _PyPreConfig *src_config)
+{
+ return pyinit_preinit(NULL, src_config, NULL);
+}
+
+
+_PyInitError
+_Py_PreInitializeInPlace(_PyPreConfig *config)
{
return pyinit_preinit(config, NULL, NULL);
}
@@ -776,10 +789,7 @@
_PyInitError
_Py_PreInitializeFromConfig(const _PyCoreConfig *coreconfig)
{
- _PyPreConfig config = _PyPreConfig_INIT;
- _PyInitError err = pyinit_preinit(&config, NULL, coreconfig);
- _PyPreConfig_Clear(&config);
- return err;
+ return pyinit_preinit(NULL, NULL, coreconfig);
}
@@ -964,7 +974,7 @@
}
#ifndef MS_WINDOWS
- _emit_stderr_warning_for_legacy_locale(core_config);
+ _emit_stderr_warning_for_legacy_locale();
#endif
return _Py_INIT_OK();
@@ -2157,8 +2167,10 @@
PyObject *result;
PyObject *threading = _PyImport_GetModuleId(&PyId_threading);
if (threading == NULL) {
- /* threading not imported */
- PyErr_Clear();
+ if (PyErr_Occurred()) {
+ PyErr_WriteUnraisable(NULL);
+ }
+ /* else: threading not imported */
return;
}
result = _PyObject_CallMethodId(threading, &PyId__shutdown, NULL);
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 4351a7f..12ec7d5 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -283,7 +283,9 @@
builtins = _PyImport_GetModuleId(&PyId_builtins);
if (builtins == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "lost builtins module");
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_RuntimeError, "lost builtins module");
+ }
return NULL;
}
Py_DECREF(builtins);
@@ -2156,6 +2158,7 @@
{
int pos = 0;
PyObject *seq;
+ const _PyPreConfig *preconfig = &_PyRuntime.preconfig;
const _PyCoreConfig *config = &_PyInterpreterState_GET_UNSAFE()->core_config;
seq = PyStructSequence_New(&FlagsType);
@@ -2172,16 +2175,16 @@
SetFlag(!config->write_bytecode);
SetFlag(!config->user_site_directory);
SetFlag(!config->site_import);
- SetFlag(!config->preconfig.use_environment);
+ SetFlag(!config->use_environment);
SetFlag(config->verbose);
/* SetFlag(saw_unbuffered_flag); */
/* SetFlag(skipfirstline); */
SetFlag(config->bytes_warning);
SetFlag(config->quiet);
SetFlag(config->use_hash_seed == 0 || config->hash_seed != 0);
- SetFlag(config->preconfig.isolated);
- PyStructSequence_SET_ITEM(seq, pos++, PyBool_FromLong(config->preconfig.dev_mode));
- SetFlag(config->preconfig.utf8_mode);
+ SetFlag(config->isolated);
+ PyStructSequence_SET_ITEM(seq, pos++, PyBool_FromLong(config->dev_mode));
+ SetFlag(preconfig->utf8_mode);
#undef SetFlag
if (PyErr_Occurred()) {