PEP 432: Reduce typing in proposed API
- consistently abbreviate Config - follow the Py*Object naming convention for Py*Config structs by dropping the underscore after the Py/_Py prefix
This commit is contained in:
parent
8d83264979
commit
62a5df58bd
97
pep-0432.txt
97
pep-0432.txt
|
@ -61,7 +61,8 @@ environments).
|
|||
To keep the implementation complexity under control, this PEP does *not*
|
||||
propose wholesale changes to the way the interpreter state is accessed at
|
||||
runtime, nor does it propose changes to the way subinterpreters are
|
||||
created after the main interpreter has already been initialized. Changing
|
||||
created after the main interpreter has already been initialized (beyond
|
||||
any changes needed to make sure they continue working as expected). Changing
|
||||
the order in which the existing initialization steps occur in order to make
|
||||
the startup sequence easier to maintain is already a substantial change, and
|
||||
attempting to make those other changes at the same time will make the
|
||||
|
@ -239,7 +240,9 @@ be able to control the following aspects of the final interpreter state:
|
|||
Note that this just covers settings that are currently configurable in some
|
||||
manner when using the main CPython executable. While this PEP aims to make
|
||||
adding additional configuration settings easier in the future, it
|
||||
deliberately avoids adding any new settings of its own.
|
||||
deliberately avoids adding any new settings of its own (except where such
|
||||
additional settings arise naturally in the course of migrating existing
|
||||
settings to the new structure).
|
||||
|
||||
|
||||
Design Details
|
||||
|
@ -280,7 +283,7 @@ Five distinct phases are proposed:
|
|||
* ``Py_IsInitialized()`` returns ``0``
|
||||
* The embedding application determines and applies the settings
|
||||
required to complete the initialization process by calling
|
||||
``Py_ReadConfiguration`` and ``Py_EndInitialization``.
|
||||
``Py_ReadConfig`` and ``Py_EndInitialization``.
|
||||
|
||||
* Initialized:
|
||||
|
||||
|
@ -318,8 +321,8 @@ grained API, which allows the embedding application greater control
|
|||
over the initialization process::
|
||||
|
||||
/* Phase 1: Pre-Initialization */
|
||||
Py_CoreConfig core_config = Py_CoreConfig_INIT;
|
||||
Py_Config config = Py_Config_INIT;
|
||||
PyCoreConfig core_config = PyCoreConfig_INIT;
|
||||
PyConfig config = PyConfig_INIT;
|
||||
/* Easily control the core configuration */
|
||||
core_config.ignore_environment = 1; /* Ignore environment variables */
|
||||
core_config.use_hash_seed = 0; /* Full hash randomisation */
|
||||
|
@ -327,13 +330,13 @@ over the initialization process::
|
|||
/* Phase 2: Initialization */
|
||||
/* Optionally preconfigure some settings here - they will then be
|
||||
* used to derive other settings */
|
||||
Py_ReadConfiguration(&config);
|
||||
Py_ReadConfig(&config);
|
||||
/* Can completely override derived settings here */
|
||||
Py_EndInitialization(&config);
|
||||
/* Phase 3: Initialized */
|
||||
/* If an embedding application has no real concept of a main module
|
||||
* it can leave the interpreter in this state indefinitely.
|
||||
* Otherwise, it can launch __main__ via the Py_Run*AsMain functions.
|
||||
* it can just stop the initialization process here.
|
||||
* Alternatively, it can launch __main__ via the PyRun_*Main functions.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -352,11 +355,13 @@ specific seed value for the randomised hashes, and if so, the specific value
|
|||
for the seed (a seed value of zero disables randomised hashing). In addition,
|
||||
due to the possible use of ``PYTHONHASHSEED`` in configuring the hash
|
||||
randomisation, the question of whether or not to consider environment
|
||||
variables must also be addressed early.
|
||||
variables must also be addressed early. Finally, to support the CPython
|
||||
build process, an option is offered to completely disable the import
|
||||
system.
|
||||
|
||||
The proposed API for this step in the startup sequence is::
|
||||
|
||||
void Py_BeginInitialization(const Py_CoreConfig *config);
|
||||
void Py_BeginInitialization(const PyCoreConfig *config);
|
||||
|
||||
Like Py_Initialize, this part of the new API treats initialization failures
|
||||
as fatal errors. While that's still not particularly embedding friendly,
|
||||
|
@ -364,27 +369,27 @@ the operations in this step *really* shouldn't be failing, and changing them
|
|||
to return error codes instead of aborting would be an even larger task than
|
||||
the one already being proposed.
|
||||
|
||||
The new ``Py_CoreConfig`` struct holds the settings required for preliminary
|
||||
The new ``PyCoreConfig`` struct holds the settings required for preliminary
|
||||
configuration::
|
||||
|
||||
/* Note: if changing anything in Py_CoreConfig, also update
|
||||
* Py_CoreConfig_INIT */
|
||||
/* Note: if changing anything in PyCoreConfig, also update
|
||||
* PyCoreConfig_INIT */
|
||||
typedef struct {
|
||||
int ignore_environment; /* -E switch */
|
||||
int use_hash_seed; /* PYTHONHASHSEED */
|
||||
unsigned long hash_seed; /* PYTHONHASHSEED */
|
||||
int _disable_importlib; /* Needed by freeze_importlib */
|
||||
} Py_CoreConfig;
|
||||
} PyCoreConfig;
|
||||
|
||||
#define Py_CoreConfig_INIT {0, -1, 0, 0}
|
||||
#define PyCoreConfig_INIT {0, -1, 0, 0}
|
||||
|
||||
The core configuration settings pointer may be ``NULL``, in which case the
|
||||
default values are ``ignore_environment = -1`` and ``use_hash_seed = -1``.
|
||||
|
||||
The ``Py_CoreConfig_INIT`` macro is designed to allow easy initialization
|
||||
The ``PyCoreConfig_INIT`` macro is designed to allow easy initialization
|
||||
of a struct instance with sensible defaults::
|
||||
|
||||
Py_CoreConfig core_config = Py_CoreConfig_INIT;
|
||||
PyCoreConfig core_config = PyCoreConfig_INIT;
|
||||
|
||||
``ignore_environment`` controls the processing of all Python related
|
||||
environment variables. If the flag is zero, then environment variables are
|
||||
|
@ -498,7 +503,7 @@ The next step in the initialization sequence is to determine the full
|
|||
settings needed to complete the process. No changes are made to the
|
||||
interpreter state at this point. The core API for this step is::
|
||||
|
||||
int Py_ReadConfiguration(PyConfig *config);
|
||||
int Py_ReadConfig(PyConfig *config);
|
||||
|
||||
The config argument should be a pointer to a config struct (which may be
|
||||
a temporary one stored on the C stack). For any already configured value
|
||||
|
@ -534,11 +539,11 @@ applied to the running interpreter until the ``Py_EndInitialization`` call
|
|||
Supported configuration settings
|
||||
--------------------------------
|
||||
|
||||
The new ``Py_Config`` struct holds the settings required to complete the
|
||||
The new ``PyConfig`` struct holds the settings required to complete the
|
||||
interpreter configuration. All fields are either pointers to Python
|
||||
data types (not set == ``NULL``) or numeric flags (not set == ``-1``)::
|
||||
|
||||
/* Note: if changing anything in Py_Config, also update Py_Config_INIT */
|
||||
/* Note: if changing anything in PyConfig, also update PyConfig_INIT */
|
||||
typedef struct {
|
||||
/* Argument processing */
|
||||
PyListObject *raw_argv;
|
||||
|
@ -611,30 +616,30 @@ data types (not set == ``NULL``) or numeric flags (not set == ``-1``)::
|
|||
int show_banner; /* -q switch (inverted) */
|
||||
int inspect_main; /* -i switch, PYTHONINSPECT */
|
||||
|
||||
} Py_Config;
|
||||
} PyConfig;
|
||||
|
||||
|
||||
/* Struct initialization is pretty ugly in C89. Avoiding this mess would
|
||||
* be the most attractive aspect of using a PyDictObject* instead... */
|
||||
#define _Py_ArgConfig_INIT NULL, NULL, NULL, NULL
|
||||
#define _Py_LocationConfig_INIT NULL, NULL, NULL, NULL, NULL, NULL
|
||||
#define _Py_SiteConfig_INIT -1, -1
|
||||
#define _Py_ImportConfig_INIT -1, -1, NULL
|
||||
#define _Py_StreamConfig_INIT -1, NULL, NULL, NULL, NULL, NULL, NULL
|
||||
#define _Py_FilesystemConfig_INIT NULL
|
||||
#define _Py_DebuggingConfig_INIT -1, -1, -1
|
||||
#define _Py_CodeGenConfig_INIT -1, -1
|
||||
#define _Py_SignalConfig_INIT -1
|
||||
#define _Py_ImplicitConfig_INIT NULL
|
||||
#define _Py_MainConfig_INIT -1, NULL, NULL, NULL, NULL, NULL, -1
|
||||
#define _Py_InteractiveConfig_INIT NULL, -1, -1
|
||||
#define _PyArgConfig_INIT NULL, NULL, NULL, NULL
|
||||
#define _PyLocationConfig_INIT NULL, NULL, NULL, NULL, NULL, NULL
|
||||
#define _PySiteConfig_INIT -1, -1
|
||||
#define _PyImportConfig_INIT -1, -1, NULL
|
||||
#define _PyStreamConfig_INIT -1, NULL, NULL, NULL, NULL, NULL, NULL
|
||||
#define _PyFilesystemConfig_INIT NULL
|
||||
#define _PyDebuggingConfig_INIT -1, -1, -1
|
||||
#define _PyCodeGenConfig_INIT -1, -1
|
||||
#define _PySignalConfig_INIT -1
|
||||
#define _PyImplicitConfig_INIT NULL
|
||||
#define _PyMainConfig_INIT -1, NULL, NULL, NULL, NULL, NULL, -1
|
||||
#define _PyInteractiveConfig_INIT NULL, -1, -1
|
||||
|
||||
#define Py_Config_INIT {_Py_ArgConfig_INIT, _Py_LocationConfig_INIT,
|
||||
_Py_SiteConfig_INIT, _Py_ImportConfig_INIT,
|
||||
_Py_StreamConfig_INIT, _Py_FilesystemConfig_INIT,
|
||||
_Py_DebuggingConfig_INIT, _Py_CodeGenConfig_INIT,
|
||||
_Py_SignalConfig_INIT, _Py_ImplicitConfig_INIT,
|
||||
_Py_MainConfig_INIT, _Py_InteractiveConfig_INIT}
|
||||
#define PyConfig_INIT {_PyArgConfig_INIT, _PyLocationConfig_INIT,
|
||||
_PySiteConfig_INIT, _PyImportConfig_INIT,
|
||||
_PyStreamConfig_INIT, _PyFilesystemConfig_INIT,
|
||||
_PyDebuggingConfig_INIT, _PyCodeGenConfig_INIT,
|
||||
_PySignalConfig_INIT, _PyImplicitConfig_INIT,
|
||||
_PyMainConfig_INIT, _PyInteractiveConfig_INIT}
|
||||
|
||||
<TBD: did I miss anything?>
|
||||
|
||||
|
@ -646,14 +651,14 @@ The final step in the initialization process is to actually put the
|
|||
configuration settings into effect and finish bootstrapping the interpreter
|
||||
up to full operation::
|
||||
|
||||
int Py_EndInitialization(const Py_Config *config);
|
||||
int Py_EndInitialization(const PyConfig *config);
|
||||
|
||||
Like Py_ReadConfiguration, this call will raise an exception and report an
|
||||
error return rather than exhibiting fatal errors if a problem is found with
|
||||
the config data.
|
||||
|
||||
All configuration settings are required - the configuration struct
|
||||
should always be passed through ``Py_ReadConfiguration()`` to ensure it
|
||||
should always be passed through ``Py_ReadConfig()`` to ensure it
|
||||
is fully populated.
|
||||
|
||||
After a successful call, ``Py_IsInitializing()`` will be false, while
|
||||
|
@ -792,7 +797,7 @@ Internal Storage of Configuration Data
|
|||
|
||||
The interpreter state will be updated to include details of the configuration
|
||||
settings supplied during initialization by extending the interpreter state
|
||||
object with an embedded copy of the ``Py_CoreConfig`` and ``Py_Config``
|
||||
object with an embedded copy of the ``PyCoreConfig`` and ``PyConfig``
|
||||
structs.
|
||||
|
||||
For debugging purposes, the configuration settings will be exposed as
|
||||
|
@ -834,7 +839,7 @@ Backwards Compatibility
|
|||
-----------------------
|
||||
|
||||
Backwards compatibility will be preserved primarily by ensuring that
|
||||
``Py_ReadConfiguration()`` interrogates all the previously defined
|
||||
``Py_ReadConfig()`` interrogates all the previously defined
|
||||
configuration settings stored in global variables and environment variables,
|
||||
and that ``Py_EndInitialization()`` writes affected settings back to the
|
||||
relevant locations.
|
||||
|
@ -911,14 +916,14 @@ Open Questions
|
|||
* Should there be ``Py_PreparingMain()`` and ``Py_RunningMain()`` query APIs?
|
||||
* Should the answer to ``Py_IsInitialized()`` be exposed via the ``sys``
|
||||
module?
|
||||
* Is initialisation of the ``Py_Config`` struct too unwieldy to be
|
||||
* Is initialisation of the ``PyConfig`` struct too unwieldy to be
|
||||
maintainable? Would a Python dictionary be a better choice, despite
|
||||
being harder to work with from C code?
|
||||
* Would it be better to manage the flag variables in ``Py_Config`` as
|
||||
* Would it be better to manage the flag variables in ``PyConfig`` as
|
||||
Python integers or as "negative means false, positive means true, zero
|
||||
means not set" so the struct can be initialized with a simple
|
||||
``memset(&config, 0, sizeof(*config))``, eliminating the need to update
|
||||
both Py_Config and Py_Config_INIT when adding new fields?
|
||||
both PyConfig and PyConfig_INIT when adding new fields?
|
||||
* The name of the new system Python executable is a bikeshed waiting to be
|
||||
painted. The 3 options considered so far are ``spython``, ``pysystem``
|
||||
and ``python-minimal``. The PEP text reflects my current preferred choice
|
||||
|
|
Loading…
Reference in New Issue