bpo-38236: Dump path config at first import error (GH-16300)
Python now dumps path configuration if it fails to import the Python codecs of the filesystem and stdio encodings.
This commit is contained in:
parent
b4d0b39a9b
commit
fcdb027234
|
@ -425,6 +425,11 @@ PyConfig
|
||||||
|
|
||||||
:data:`sys.base_exec_prefix`.
|
:data:`sys.base_exec_prefix`.
|
||||||
|
|
||||||
|
.. c:member:: wchar_t* base_executable
|
||||||
|
|
||||||
|
:data:`sys._base_executable`: ``__PYVENV_LAUNCHER__`` environment
|
||||||
|
variable value, or copy of :c:member:`PyConfig.executable`.
|
||||||
|
|
||||||
.. c:member:: wchar_t* base_prefix
|
.. c:member:: wchar_t* base_prefix
|
||||||
|
|
||||||
:data:`sys.base_prefix`.
|
:data:`sys.base_prefix`.
|
||||||
|
@ -862,11 +867,13 @@ Path Configuration
|
||||||
* Path configuration input fields:
|
* Path configuration input fields:
|
||||||
|
|
||||||
* :c:member:`PyConfig.home`
|
* :c:member:`PyConfig.home`
|
||||||
* :c:member:`PyConfig.pythonpath_env`
|
|
||||||
* :c:member:`PyConfig.pathconfig_warnings`
|
* :c:member:`PyConfig.pathconfig_warnings`
|
||||||
|
* :c:member:`PyConfig.program_name`
|
||||||
|
* :c:member:`PyConfig.pythonpath_env`
|
||||||
|
|
||||||
* Path configuration output fields:
|
* Path configuration output fields:
|
||||||
|
|
||||||
|
* :c:member:`PyConfig.base_executable`
|
||||||
* :c:member:`PyConfig.exec_prefix`
|
* :c:member:`PyConfig.exec_prefix`
|
||||||
* :c:member:`PyConfig.executable`
|
* :c:member:`PyConfig.executable`
|
||||||
* :c:member:`PyConfig.prefix`
|
* :c:member:`PyConfig.prefix`
|
||||||
|
@ -918,6 +925,9 @@ The following configuration files are used by the path configuration:
|
||||||
* ``python._pth`` (Windows only)
|
* ``python._pth`` (Windows only)
|
||||||
* ``pybuilddir.txt`` (Unix only)
|
* ``pybuilddir.txt`` (Unix only)
|
||||||
|
|
||||||
|
The ``__PYVENV_LAUNCHER__`` environment variable is used to set
|
||||||
|
:c:member:`PyConfig.base_executable`
|
||||||
|
|
||||||
|
|
||||||
Py_RunMain()
|
Py_RunMain()
|
||||||
------------
|
------------
|
||||||
|
|
|
@ -60,6 +60,7 @@ extern wchar_t* _Py_GetDLLPath(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern PyStatus _PyPathConfig_Init(void);
|
extern PyStatus _PyPathConfig_Init(void);
|
||||||
|
extern void _Py_DumpPathConfig(PyThreadState *tstate);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Python now dumps path configuration if it fails to import the Python codecs
|
||||||
|
of the filesystem and stdio encodings.
|
|
@ -15804,13 +15804,13 @@ error:
|
||||||
|
|
||||||
|
|
||||||
static PyStatus
|
static PyStatus
|
||||||
init_stdio_encoding(PyInterpreterState *interp)
|
init_stdio_encoding(PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
/* Update the stdio encoding to the normalized Python codec name. */
|
/* Update the stdio encoding to the normalized Python codec name. */
|
||||||
PyConfig *config = &interp->config;
|
PyConfig *config = &tstate->interp->config;
|
||||||
if (config_get_codec_name(&config->stdio_encoding) < 0) {
|
if (config_get_codec_name(&config->stdio_encoding) < 0) {
|
||||||
return _PyStatus_ERR("failed to get the Python codec name "
|
return _PyStatus_ERR("failed to get the Python codec name "
|
||||||
"of the stdio encoding");
|
"of the stdio encoding");
|
||||||
}
|
}
|
||||||
return _PyStatus_OK();
|
return _PyStatus_OK();
|
||||||
}
|
}
|
||||||
|
@ -15864,15 +15864,18 @@ init_fs_codec(PyInterpreterState *interp)
|
||||||
|
|
||||||
|
|
||||||
static PyStatus
|
static PyStatus
|
||||||
init_fs_encoding(PyInterpreterState *interp)
|
init_fs_encoding(PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
|
PyInterpreterState *interp = tstate->interp;
|
||||||
|
|
||||||
/* Update the filesystem encoding to the normalized Python codec name.
|
/* Update the filesystem encoding to the normalized Python codec name.
|
||||||
For example, replace "ANSI_X3.4-1968" (locale encoding) with "ascii"
|
For example, replace "ANSI_X3.4-1968" (locale encoding) with "ascii"
|
||||||
(Python codec name). */
|
(Python codec name). */
|
||||||
PyConfig *config = &interp->config;
|
PyConfig *config = &interp->config;
|
||||||
if (config_get_codec_name(&config->filesystem_encoding) < 0) {
|
if (config_get_codec_name(&config->filesystem_encoding) < 0) {
|
||||||
|
_Py_DumpPathConfig(tstate);
|
||||||
return _PyStatus_ERR("failed to get the Python codec "
|
return _PyStatus_ERR("failed to get the Python codec "
|
||||||
"of the filesystem encoding");
|
"of the filesystem encoding");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init_fs_codec(interp) < 0) {
|
if (init_fs_codec(interp) < 0) {
|
||||||
|
@ -15885,14 +15888,12 @@ init_fs_encoding(PyInterpreterState *interp)
|
||||||
PyStatus
|
PyStatus
|
||||||
_PyUnicode_InitEncodings(PyThreadState *tstate)
|
_PyUnicode_InitEncodings(PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = tstate->interp;
|
PyStatus status = init_fs_encoding(tstate);
|
||||||
|
|
||||||
PyStatus status = init_fs_encoding(interp);
|
|
||||||
if (_PyStatus_EXCEPTION(status)) {
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
return init_stdio_encoding(interp);
|
return init_stdio_encoding(tstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -532,8 +532,7 @@ _Py_GetDLLPath(void)
|
||||||
|
|
||||||
|
|
||||||
static PyStatus
|
static PyStatus
|
||||||
get_program_full_path(const PyConfig *config,
|
get_program_full_path(_PyPathConfig *pathconfig)
|
||||||
PyCalculatePath *calculate, _PyPathConfig *pathconfig)
|
|
||||||
{
|
{
|
||||||
const wchar_t *pyvenv_launcher;
|
const wchar_t *pyvenv_launcher;
|
||||||
wchar_t program_full_path[MAXPATHLEN+1];
|
wchar_t program_full_path[MAXPATHLEN+1];
|
||||||
|
@ -977,7 +976,7 @@ calculate_path_impl(const PyConfig *config,
|
||||||
{
|
{
|
||||||
PyStatus status;
|
PyStatus status;
|
||||||
|
|
||||||
status = get_program_full_path(config, calculate, pathconfig);
|
status = get_program_full_path(pathconfig);
|
||||||
if (_PyStatus_EXCEPTION(status)) {
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "osdefs.h" /* DELIM */
|
#include "osdefs.h" /* DELIM */
|
||||||
#include "pycore_initconfig.h"
|
|
||||||
#include "pycore_fileutils.h"
|
#include "pycore_fileutils.h"
|
||||||
#include "pycore_getopt.h"
|
#include "pycore_getopt.h"
|
||||||
|
#include "pycore_initconfig.h"
|
||||||
|
#include "pycore_pathconfig.h"
|
||||||
|
#include "pycore_pyerrors.h"
|
||||||
#include "pycore_pylifecycle.h"
|
#include "pycore_pylifecycle.h"
|
||||||
#include "pycore_pymem.h"
|
#include "pycore_pymem.h"
|
||||||
#include "pycore_pystate.h" /* _PyRuntime */
|
#include "pycore_pystate.h" /* _PyRuntime */
|
||||||
#include "pycore_pathconfig.h"
|
|
||||||
#include <locale.h> /* setlocale() */
|
#include <locale.h> /* setlocale() */
|
||||||
#ifdef HAVE_LANGINFO_H
|
#ifdef HAVE_LANGINFO_H
|
||||||
# include <langinfo.h> /* nl_langinfo(CODESET) */
|
# include <langinfo.h> /* nl_langinfo(CODESET) */
|
||||||
|
@ -2539,3 +2540,97 @@ error:
|
||||||
Py_XDECREF(dict);
|
Py_XDECREF(dict);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_dump_ascii_wstr(const wchar_t *str)
|
||||||
|
{
|
||||||
|
if (str == NULL) {
|
||||||
|
PySys_WriteStderr("(not set)");
|
||||||
|
}
|
||||||
|
|
||||||
|
PySys_WriteStderr("'");
|
||||||
|
for (; *str != L'\0'; str++) {
|
||||||
|
wchar_t ch = *str;
|
||||||
|
if (ch == L'\'') {
|
||||||
|
PySys_WriteStderr("\\'");
|
||||||
|
} else if (0x20 <= ch && ch < 0x7f) {
|
||||||
|
PySys_WriteStderr("%lc", ch);
|
||||||
|
}
|
||||||
|
else if (ch <= 0xff) {
|
||||||
|
PySys_WriteStderr("\\x%02x", ch);
|
||||||
|
}
|
||||||
|
#if SIZEOF_WCHAR_T > 2
|
||||||
|
else if (ch > 0xffff) {
|
||||||
|
PySys_WriteStderr("\\U%08x", ch);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
PySys_WriteStderr("\\u%04x", ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PySys_WriteStderr("'");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Dump the Python path configuration into sys.stderr */
|
||||||
|
void
|
||||||
|
_Py_DumpPathConfig(PyThreadState *tstate)
|
||||||
|
{
|
||||||
|
PyObject *exc_type, *exc_value, *exc_tb;
|
||||||
|
_PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb);
|
||||||
|
|
||||||
|
PySys_WriteStderr("Python path configuration:\n");
|
||||||
|
|
||||||
|
#define DUMP_CONFIG(NAME, FIELD) \
|
||||||
|
do { \
|
||||||
|
PySys_WriteStderr(" " NAME " = "); \
|
||||||
|
init_dump_ascii_wstr(config->FIELD); \
|
||||||
|
PySys_WriteStderr("\n"); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
PyConfig *config = &tstate->interp->config;
|
||||||
|
DUMP_CONFIG("PYTHONHOME", home);
|
||||||
|
DUMP_CONFIG("PYTHONPATH", pythonpath_env);
|
||||||
|
DUMP_CONFIG("program name", program_name);
|
||||||
|
PySys_WriteStderr(" isolated = %i\n", config->isolated);
|
||||||
|
PySys_WriteStderr(" environment = %i\n", config->use_environment);
|
||||||
|
PySys_WriteStderr(" user site = %i\n", config->user_site_directory);
|
||||||
|
PySys_WriteStderr(" import site = %i\n", config->site_import);
|
||||||
|
#undef DUMP_CONFIG
|
||||||
|
|
||||||
|
#define DUMP_SYS(NAME) \
|
||||||
|
do { \
|
||||||
|
obj = PySys_GetObject(#NAME); \
|
||||||
|
PySys_FormatStderr(" sys.%s = ", #NAME); \
|
||||||
|
if (obj != NULL) { \
|
||||||
|
PySys_FormatStderr("%A", obj); \
|
||||||
|
} \
|
||||||
|
else { \
|
||||||
|
PySys_WriteStderr("(not set)"); \
|
||||||
|
} \
|
||||||
|
PySys_FormatStderr("\n"); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
PyObject *obj;
|
||||||
|
DUMP_SYS(_base_executable);
|
||||||
|
DUMP_SYS(base_prefix);
|
||||||
|
DUMP_SYS(base_exec_prefix);
|
||||||
|
DUMP_SYS(executable);
|
||||||
|
DUMP_SYS(prefix);
|
||||||
|
DUMP_SYS(exec_prefix);
|
||||||
|
#undef DUMP_SYS
|
||||||
|
|
||||||
|
PyObject *sys_path = PySys_GetObject("path"); /* borrowed reference */
|
||||||
|
if (sys_path != NULL && PyList_Check(sys_path)) {
|
||||||
|
PySys_WriteStderr(" sys.path = [\n");
|
||||||
|
Py_ssize_t len = PyList_GET_SIZE(sys_path);
|
||||||
|
for (Py_ssize_t i=0; i < len; i++) {
|
||||||
|
PyObject *path = PyList_GET_ITEM(sys_path, i);
|
||||||
|
PySys_FormatStderr(" %A,\n", path);
|
||||||
|
}
|
||||||
|
PySys_WriteStderr(" ]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
_PyErr_Restore(tstate, exc_type, exc_value, exc_tb);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue