diff --git a/pep-0587.rst b/pep-0587.rst index 96f88b995..b37d35ffa 100644 --- a/pep-0587.rst +++ b/pep-0587.rst @@ -107,7 +107,7 @@ macros. New structures: * ``PyConfig`` -* ``PyInitError`` +* ``PyStatus`` * ``PyPreConfig`` * ``PyWideStringList`` @@ -121,19 +121,19 @@ New functions: * ``PyConfig_SetBytesArgv(config, argc, argv)`` * ``PyConfig_SetBytesString(config, config_str, str)`` * ``PyConfig_SetString(config, config_str, str)`` -* ``PyInitError_Error(err_msg)`` -* ``PyInitError_Exit(exitcode)`` -* ``PyInitError_Failed(err)`` -* ``PyInitError_IsError(err)`` -* ``PyInitError_IsExit(err)`` -* ``PyInitError_NoMemory()`` -* ``PyInitError_Ok()`` * ``PyPreConfig_InitIsolatedConfig(preconfig)`` * ``PyPreConfig_InitPythonConfig(preconfig)`` +* ``PyStatus_Error(err_msg)`` +* ``PyStatus_Exception(status)`` +* ``PyStatus_Exit(exitcode)`` +* ``PyStatus_IsError(status)`` +* ``PyStatus_IsExit(status)`` +* ``PyStatus_NoMemory()`` +* ``PyStatus_Ok()`` * ``PyWideStringList_Append(list, item)`` * ``PyWideStringList_Insert(list, index, item)`` * ``Py_BytesMain(argc, argv)`` -* ``Py_ExitInitError(err)`` +* ``Py_ExitStatusException(status)`` * ``Py_InitializeFromConfig(config)`` * ``Py_PreInitialize(preconfig)`` * ``Py_PreInitializeFromArgs(preconfig, argc, argv)`` @@ -159,45 +159,45 @@ PyWideStringList Methods: -* ``PyInitError PyWideStringList_Append(PyWideStringList *list, const wchar_t *item)``: +* ``PyStatus PyWideStringList_Append(PyWideStringList *list, const wchar_t *item)``: Append *item* to *list*. -* ``PyInitError PyWideStringList_Insert(PyWideStringList *list, Py_ssize_t index, const wchar_t *item)``: +* ``PyStatus PyWideStringList_Insert(PyWideStringList *list, Py_ssize_t index, const wchar_t *item)``: Insert *item* into *list* at *index*. If *index* is greater than *list* length, just append *item* to *list*. If *length* is non-zero, *items* must be non-NULL and all strings must be non-NULL. -PyInitError ------------ +PyStatus +-------- -``PyInitError`` is a structure to store an error message or an exit code -for the Python Initialization. For an error, it stores the C function -name which created the error. +``PyStatus`` is a structure to store the status of an initialization +function: success, error or exit. For an error, it can store the C +function name which created the error. Example:: - PyInitError alloc(void **ptr, size_t size) + PyStatus alloc(void **ptr, size_t size) { *ptr = PyMem_RawMalloc(size); if (*ptr == NULL) { - return PyInitError_NoMemory(); + return PyStatus_NoMemory(); } - return PyInitError_Ok(); + return PyStatus_Ok(); } int main(int argc, char **argv) { void *ptr; - PyInitError err = alloc(&ptr, 16); - if (PyInitError_Failed(err)) { - Py_ExitInitError(err); + PyStatus status = alloc(&ptr, 16); + if (PyStatus_Exception(status)) { + Py_ExitStatusException(status); } PyMem_Free(ptr); return 0; } -``PyInitError`` fields: +``PyStatus`` fields: * ``exitcode`` (``int``): Argument passed to ``exit()``. @@ -207,22 +207,29 @@ Example:: Name of the function which created an error, can be ``NULL``. * private ``_type`` field: for internal usage only. -Functions to create an error: +Functions to create a status: -* ``PyInitError_Ok()``: Success. -* ``PyInitError_Error(err_msg)``: Initialization error with a message. -* ``PyInitError_NoMemory()``: Memory allocation failure (out of memory). -* ``PyInitError_Exit(exitcode)``: Exit Python with the specified exit code. +* ``PyStatus_Ok()``: Success. +* ``PyStatus_Error(err_msg)``: Initialization error with a message. +* ``PyStatus_NoMemory()``: Memory allocation failure (out of memory). +* ``PyStatus_Exit(exitcode)``: Exit Python with the specified exit code. -Functions to handle an error: +Functions to handle a status: + +* ``PyStatus_Exception(status)``: Is the result an error or an exit? + If true, the exception must be handled; by calling + ``Py_ExitStatusException(status)`` for example. +* ``PyStatus_IsError(status)``: Is the result an error? +* ``PyStatus_IsExit(status)``: Is the result an exit? +* ``Py_ExitStatusException(status)``: Call ``exit(exitcode)`` if *status* + is an exit. Print the error messageand exit with a non-zero exit code + if *status* is an error. Must only be called if + ``PyStatus_Exception(status)`` is true. + +.. note:: + Internally, Python uses macros which set ``PyStatus.func``, + whereas functions to create a status set ``func`` to ``NULL``. -* ``PyInitError_Failed(err)``: Is the result an error or an exit? -* ``PyInitError_IsError(err)``: Is the result an error? -* ``PyInitError_IsExit(err)``: Is the result an exit? -* ``Py_ExitInitError(err)``: Call ``exit(exitcode)`` if *err* is an - exit, print the error and exit if *err* is an error. Must only be - called with an error and an exit: if ``PyInitError_Failed(err)`` is - true. Preinitialization with PyPreConfig ---------------------------------- @@ -240,9 +247,9 @@ Example using the preinitialization to enable the UTF-8 Mode:: preconfig.utf8_mode = 1; - PyInitError err = Py_PreInitialize(&preconfig); - if (PyInitError_Failed(err)) { - Py_ExitInitError(err); + PyStatus status = Py_PreInitialize(&preconfig); + if (PyStatus_Exception(status)) { + Py_ExitStatusException(status); } /* at this point, Python will speak UTF-8 */ @@ -258,12 +265,12 @@ Function to initialize a pre-configuration: Functions to preinitialization Python: -* ``PyInitError Py_PreInitialize(const PyPreConfig *preconfig)`` -* ``PyInitError Py_PreInitializeFromBytesArgs(const PyPreConfig *preconfig, int argc, char * const *argv)`` -* ``PyInitError Py_PreInitializeFromArgs(const PyPreConfig *preconfig, int argc, wchar_t * const * argv)`` +* ``PyStatus Py_PreInitialize(const PyPreConfig *preconfig)`` +* ``PyStatus Py_PreInitializeFromBytesArgs(const PyPreConfig *preconfig, int argc, char * const *argv)`` +* ``PyStatus Py_PreInitializeFromArgs(const PyPreConfig *preconfig, int argc, wchar_t * const * argv)`` -The caller is responsible to handle error or exit using -``PyInitError_Failed()`` and ``Py_ExitInitError()``. +The caller is responsible to handle exceptions (error or exit) using +``PyStatus_Exception()`` and ``Py_ExitStatusException()``. If Python is initialized with command line arguments, the command line arguments must also be passed to preinitialize Python, since they have @@ -279,11 +286,14 @@ an effect on the pre-configuration like encodings. For example, the * ``PYMEM_ALLOCATOR_NOT_SET`` (``0``): don't change memory allocators (use defaults) * ``PYMEM_ALLOCATOR_DEFAULT`` (``1``): default memory allocators - * ``PYMEM_ALLOCATOR_DEBUG`` (``2``): enable debug hooks + * ``PYMEM_ALLOCATOR_DEBUG`` (``2``): default memory allocators with + debug hooks * ``PYMEM_ALLOCATOR_MALLOC`` (``3``): force usage of ``malloc()`` - * ``PYMEM_ALLOCATOR_MALLOC_DEBUG`` (``4``): ``malloc()`` with debug hooks + * ``PYMEM_ALLOCATOR_MALLOC_DEBUG`` (``4``): force usage of + ``malloc()`` with debug hooks * ``PYMEM_ALLOCATOR_PYMALLOC`` (``5``): Python "pymalloc" allocator - * ``PYMEM_ALLOCATOR_PYMALLOC_DEBUG`` (``6``): pymalloc with debug hooks + * ``PYMEM_ALLOCATOR_PYMALLOC_DEBUG`` (``6``): Python "pymalloc" + allocator with debug hooks * Note: ``PYMEM_ALLOCATOR_PYMALLOC`` and ``PYMEM_ALLOCATOR_PYMALLOC_DEBUG`` are not supported if Python is configured using ``--without-pymalloc`` @@ -300,7 +310,7 @@ an effect on the pre-configuration like encodings. For example, the See ``PyConfig.dev_mode``. * ``isolated`` (``int``): See ``PyConfig.isolated``. -* ``legacy_windows_fs_encoding`` (``int``): +* ``legacy_windows_fs_encoding`` (``int``, Windows only): If non-zero, disable UTF-8 Mode, set the Python filesystem encoding to ``mbcs``, set the filesystem error handler to ``replace``. * ``parse_argv`` (``int``): @@ -313,11 +323,15 @@ an effect on the pre-configuration like encodings. For example, the * ``utf8_mode`` (``int``): If non-zero, enable the UTF-8 mode. -The ``legacy_windows_fs_encoding`` is only available on Windows. +The ``legacy_windows_fs_encoding`` field is only available on Windows. +``#ifdef MS_WINDOWS`` macro can be used for Windows specific code. -There is also a private field, for internal use only, -``_config_version`` (``int``): the configuration version, used -for ABI compatibility. +``PyPreConfig`` private fields, for internal use only: + +* ``_config_version`` (``int``): + Configuration version, used for ABI compatibility. +* ``_config_init`` (``int``): + Function used to initalize ``PyConfig``, used for preinitialization. ``PyMem_SetAllocator()`` can be called after ``Py_PreInitialize()`` and before ``Py_InitializeFromConfig()`` to install a custom memory @@ -339,23 +353,23 @@ Example setting the program name:: void init_python(void) { - PyInitError err; + PyStatus status; PyConfig config; - err = PyConfig_InitPythonConfig(&config); - if (PyInitError_Failed(err)) { + status = PyConfig_InitPythonConfig(&config); + if (PyStatus_Exception(status)) { goto fail; } /* Set the program name. Implicitly preinitialize Python. */ - err = PyConfig_SetString(&config, &config.program_name, + status = PyConfig_SetString(&config, &config.program_name, L"/path/to/my_program"); - if (PyInitError_Failed(err)) { + if (PyStatus_Exception(status)) { goto fail; } - err = Py_InitializeFromConfig(&config); - if (PyInitError_Failed(err)) { + status = Py_InitializeFromConfig(&config); + if (PyStatus_Exception(status)) { goto fail; } PyConfig_Clear(&config); @@ -363,29 +377,29 @@ Example setting the program name:: fail: PyConfig_Clear(&config); - Py_ExitInitError(err); + Py_ExitStatusException(status); } ``PyConfig`` methods: -* ``PyInitError PyConfig_InitPythonConfig(PyConfig *config)`` +* ``PyStatus PyConfig_InitPythonConfig(PyConfig *config)`` Initialize configuration with `Python Configuration`_. -* ``PyInitError PyConfig_InitIsolatedConfig(PyConfig *config)``: +* ``PyStatus PyConfig_InitIsolatedConfig(PyConfig *config)``: Initialize configuration with `Isolated Configuration`_. -* ``PyInitError PyConfig_SetString(PyConfig *config, wchar_t * const *config_str, const wchar_t *str)``: +* ``PyStatus PyConfig_SetString(PyConfig *config, wchar_t * const *config_str, const wchar_t *str)``: Copy the wide character string *str* into ``*config_str``. Preinitialize Python if needed. -* ``PyInitError PyConfig_SetBytesString(PyConfig *config, wchar_t * const *config_str, const char *str)``: +* ``PyStatus PyConfig_SetBytesString(PyConfig *config, wchar_t * const *config_str, const char *str)``: Decode *str* using ``Py_DecodeLocale()`` and set the result into ``*config_str``. Preinitialize Python if needed. -* ``PyInitError PyConfig_SetArgv(PyConfig *config, int argc, wchar_t * const *argv)``: +* ``PyStatus PyConfig_SetArgv(PyConfig *config, int argc, wchar_t * const *argv)``: Set command line arguments from wide character strings. Preinitialize Python if needed. -* ``PyInitError PyConfig_SetBytesArgv(PyConfig *config, int argc, char * const *argv)``: +* ``PyStatus PyConfig_SetBytesArgv(PyConfig *config, int argc, char * const *argv)``: Set command line arguments: decode bytes using ``Py_DecodeLocale()``. Preinitialize Python if needed. -* ``PyInitError PyConfig_Read(PyConfig *config)``: +* ``PyStatus PyConfig_Read(PyConfig *config)``: Read all Python configuration. Fields which are already initialized are left unchanged. Preinitialize Python if needed. @@ -409,11 +423,13 @@ preinitialization configuration depends on command line arguments (if Functions to initialize Python: -* ``PyInitError Py_InitializeFromConfig(const PyConfig *config)``: +* ``PyStatus Py_InitializeFromConfig(const PyConfig *config)``: Initialize Python from *config* configuration. -The caller of these methods and functions is responsible to handle error -or exit using ``PyInitError_Failed()`` and ``Py_ExitInitError()``. +The caller of these methods and functions is responsible to handle +exceptions (error or exit) using ``PyStatus_Exception()`` and +``Py_ExitStatusException()``. + ``PyConfig`` fields: @@ -465,6 +481,16 @@ or exit using ``PyInitError_Failed()`` and ``Py_ExitInitError()``. Install signal handlers? * ``interactive`` (``int``): Interactive mode. +* ``isolated`` (``int``): + If greater than 0, enable isolated mode: + + * ``sys.path`` contains neither the script's directory (computed from + ``argv[0]`` or the current directory) nor the user's site-packages + directory. + * Python REPL doesn't import ``readline`` nor enable default readline + configuration on interactive prompts. + * Set ``use_environment`` and ``user_site_directory`` are set to 0. + * ``legacy_windows_stdio`` (``int``, Windows only): If non-zero, use ``io.FileIO`` instead of ``WindowsConsoleIO`` for ``sys.stdin``, ``sys.stdout`` and ``sys.stderr``. @@ -531,6 +557,9 @@ or exit using ``PyInitError_Failed()`` and ``Py_ExitInitError()``. * ``xoptions`` (``PyWideStringList``): ``sys._xoptions``. +The ``legacy_windows_stdio`` field is only available on Windows. +``#ifdef MS_WINDOWS`` macro can be used for Windows specific code. + If ``parse_argv`` is non-zero, ``argv`` arguments are parsed the same way the regular Python parses command line arguments, and Python arguments are stripped from ``argv``: see `Command Line Arguments`_. @@ -553,13 +582,13 @@ Options`_. More complete example modifying the default configuration, read the configuration, and then override some parameters:: - PyInitError init_python(const char *program_name) + PyStatus init_python(const char *program_name) { - PyInitError err; + PyStatus status; PyConfig config; - err = PyConfig_InitPythonConfig(&config); - if (PyInitError_Failed(err)) { + status = PyConfig_InitPythonConfig(&config); + if (PyStatus_Exception(status)) { goto done; } @@ -567,44 +596,44 @@ configuration, and then override some parameters:: (decode byte string from the locale encoding). Implicitly preinitialize Python. */ - err = PyConfig_SetBytesString(&config, &config.program_name, + status = PyConfig_SetBytesString(&config, &config.program_name, program_name); - if (PyInitError_Failed(err)) { + if (PyStatus_Exception(status)) { goto done; } /* Read all configuration at once */ - err = PyConfig_Read(&config); - if (PyInitError_Failed(err)) { + status = PyConfig_Read(&config); + if (PyStatus_Exception(status)) { goto done; } /* Append our custom search path to sys.path */ - err = PyWideStringList_Append(&config.module_search_paths, + status = PyWideStringList_Append(&config.module_search_paths, L"/path/to/more/modules"); - if (PyInitError_Failed(err)) { + if (PyStatus_Exception(status)) { goto done; } /* Override executable computed by PyConfig_Read() */ - err = PyConfig_SetString(&config, &config.executable, + status = PyConfig_SetString(&config, &config.executable, L"/path/to/my_executable"); - if (PyInitError_Failed(err)) { + if (PyStatus_Exception(status)) { goto done; } - err = Py_InitializeFromConfig(&config); + status = Py_InitializeFromConfig(&config); done: PyConfig_Clear(&config); - return err; + return status; } .. note:: ``PyImport_FrozenModules``, ``PyImport_AppendInittab()`` and ``PyImport_ExtendInittab()`` functions are still relevant and - continue to work as previously. They should be set or called - before the Python initialization. + continue to work as previously. They should be set or called after + Python preinitialization and before the Python initialization. Isolated Configuration @@ -644,10 +673,10 @@ Example of customized Python always running in isolated mode:: int main(int argc, char **argv) { PyConfig config; - PyInitError err; + PyStatus status; - err = PyConfig_InitPythonConfig(&config); - if (PyInitError_Failed(err)) { + status = PyConfig_InitPythonConfig(&config); + if (PyStatus_Exception(status)) { goto fail; } @@ -655,13 +684,13 @@ Example of customized Python always running in isolated mode:: /* Decode command line arguments. Implicitly preinitialize Python (in isolated mode). */ - err = PyConfig_SetBytesArgv(&config, argc, argv); - if (PyInitError_Failed(err)) { + status = PyConfig_SetBytesArgv(&config, argc, argv); + if (PyStatus_Exception(status)) { goto fail; } - err = Py_InitializeFromConfig(&config); - if (PyInitError_Failed(err)) { + status = Py_InitializeFromConfig(&config); + if (PyStatus_Exception(status)) { goto fail; } PyConfig_Clear(&config); @@ -670,12 +699,12 @@ Example of customized Python always running in isolated mode:: fail: PyConfig_Clear(&config); - if (!PyInitError_IsExit(err)) { - /* Display the error message and exit the process with - non-zero exit code */ - Py_ExitInitError(err); + if (PyStatus_IsExit(status)) { + return status.exitcode; } - return err.exitcode; + /* Display the error message and exit the process with + non-zero exit code */ + Py_ExitStatusException(status); } This example is a basic implementation of the "System Python Executable" @@ -700,6 +729,11 @@ Path Configuration * ``prefix`` * ``module_search_paths_set``, ``module_search_paths`` +If at least one "output field" is not set, Python computes the path +configuration to fill unset fields. If ``module_search_paths_set`` is +equal to 0, ``module_search_paths`` is overriden and +``module_search_paths_set`` is set to 1. + It is possible to completely ignore the function computing the default path configuration by setting explicitly all path configuration output fields listed above. A string is considered as set even if it's an empty @@ -713,9 +747,22 @@ path configuration (Unix only, Windows does not log any warning). If ``base_prefix`` or ``base_exec_prefix`` fields are not set, they inherit their value from ``prefix`` and ``exec_prefix`` respectively. +``Py_RunMain()`` and ``Py_Main()`` modify ``sys.path``: + +* If ``run_filename`` is set and is a directory which contains a + ``__main__.py`` script, prepend ``run_filename`` to ``sys.path``. +* If ``isolated`` is zero: + + * If ``run_module`` is set, prepend the current directory to + ``sys.path``. Do nothing if the current directory cannot be read. + * If ``run_filename`` is set, prepends the directory of the filename + to ``sys.path``. + * Otherwise, prepends an empty string to ``sys.path``. + If ``site_import`` is non-zero, ``sys.path`` can be modified by the -``site`` module. For example, if ``user_site_directory`` is non-zero, -the user site directory is added to ``sys.path`` (if it exists). +``site`` module. If ``user_site_directory`` is non-zero the user's +site-package directory exists, the ``site`` module appends the user's +site-package directory to ``sys.path``. See also `Configuration Files`_ used by the path configuration. @@ -748,6 +795,94 @@ See `Python Configuration`_ for an example of customized Python always running in isolated mode using ``Py_RunMain()``. +Multi-Phase Initialization Private Provisional API +-------------------------------------------------- + +This section is a private provisional API introducing multi-phase +initialization, the core feature of the PEP 432: + +* "Core" initialization phase, "bare minimum Python": + + * Builtin types; + * Builtin exceptions; + * Builtin and frozen modules; + * The ``sys`` module is only partially initialized + (ex: ``sys.path`` doesn't exist yet); + +* "Main" initialization phase, Python is fully initialized: + + * Install and configure ``importlib``; + * Apply the `Path Configuration`_; + * Install signal handlers; + * Finish ``sys`` module initialization (ex: create ``sys.stdout`` and + ``sys.path``); + * Enable optional features like ``faulthandler`` and ``tracemalloc``; + * Import the ``site`` module; + * etc. + +Private provisional API: + +* ``PyConfig._init_main``: if set to 0, ``Py_InitializeFromConfig()`` + stops at the "Core" initialization phase. +* ``PyStatus _Py_InitializeMain(void)``: move to the "Main" + initialization phase, finish the Python initialization. + +No module is imported during the "Core" phase and the ``importlib`` +module is not configured: the `Path Configuration`_ is only applied +during the "Main" phase. It allows to customize Python in Python to +override or tune the `Path Configuration`_, maybe install a custom +sys.meta_path importer or an import hook, etc. + +It may become possible to compute the `Path Configuration`_ in Python, +after the Core phase and before the Main phase, which is one of the PEP +432 motivation. + +The "Core" phase is not properly defined: what should be and what should +not be available at this phase is not specified yet. The API is marked +as private and provisional: the API can be modified or even be removed +anytime until a proper public API is design. + +Example running Python code between "Core" and "Main" initialization +phases:: + + void init_python(void) + { + PyStatus status; + PyConfig config; + + status = PyConfig_InitPythonConfig(&config); + if (PyStatus_Exception(status)) { + PyConfig_Clear(&config); + Py_ExitStatusException(status); + } + + /* ... set 'config' configuration ... */ + + status = Py_InitializeFromConfig(&config); + PyConfig_Clear(&config); + if (PyStatus_Exception(status)) { + Py_ExitStatusException(status); + } + + /* Use sys.stderr because sys.stdout is only created + by _Py_InitializeMain() */ + int res = PyRun_SimpleString( + "import sys; " + "print('Run Python code before _Py_InitializeMain', " + "file=sys.stderr)"); + if (res < 0) { + exit(1); + } + + /* ... put more configuration code here ... */ + + status = _Py_InitializeMain(); + if (PyStatus_Exception(status)) { + Py_ExitStatusException(status); + } + } + + Backwards Compatibility ======================= @@ -776,9 +911,9 @@ PyPreConfig Python Isolated ``coerce_c_locale`` -1 0 ``configure_locale`` **1** 0 ``dev_mode`` -1 0 -``isolated`` -1 **1** +``isolated`` 0 **1** ``legacy_windows_fs_encoding`` -1 0 -``use_environment`` -1 0 +``use_environment`` 0 0 ``parse_argv`` **1** 0 ``utf8_mode`` -1 0 =============================== ======= ======== @@ -1025,9 +1160,9 @@ Default Python Configugration * ``coerce_c_locale`` = -1 * ``configure_locale`` = 1 * ``dev_mode`` = -1 -* ``isolated`` = -1 +* ``isolated`` = 0 * ``legacy_windows_fs_encoding`` = -1 -* ``use_environment`` = -1 +* ``use_environment`` = 1 * ``utf8_mode`` = -1 ``PyConfig_InitPythonConfig()``: @@ -1300,9 +1435,54 @@ Issues related to this PEP: standalone) to locate the module path according to the shared library" +Discussions +=========== + +* May 2019: + + * `[Python-Dev] PEP 587 "Python Initialization Configuration" version 4 + `_ + * `[Python-Dev] RFC: PEP 587 "Python Initialization Configuration": 3rd version + `_ + * `Study on applications embedding Python + `_ + * `[Python-Dev] RFC: PEP 587 "Python Initialization Configuration": + 2nd version + `_ + +* March 2019: + + * `[Python-Dev] PEP 587: Python Initialization Configuration + `_ + * `[Python-Dev] New Python Initialization API + `_ + +* February 2019: + + * `Adding char* based APIs for Unix + `_ + +* July-August 2018: + + * July: `[Python-Dev] New _Py_InitializeFromConfig() function (PEP 432) + `__ + * August: `[Python-Dev] New _Py_InitializeFromConfig() function (PEP 432) + `__ + Version History =============== +* Version 5: + + * Rename ``PyInitError`` to ``PyStatus`` + * Rename ``PyInitError_Failed()`` to ``PyStatus_Exception()`` + * Rename ``Py_ExitInitError()`` to ``Py_ExitStatusException()`` + * Add ``PyPreConfig._config_init`` private field. + * Fix Python Configuration default values: isolated=0 + and use_environment=1, instead of -1. + * Add "Multi-Phase Initialization Private Provisional API" + and "Discussions" sections + * Version 4: * Introduce "Python Configuration" and "Isolated Configuration" which