======================
WSGIInterpreterOptions
======================
:Description: Container for per-interpreter configuration directives.
:Syntax: `` ... ``
:Context: server config
Section directive that scopes a set of per-interpreter configuration
directives to interpreters matching the supplied selector keys. The
container exists so that properties of an individual Python sub
interpreter (or set of sub interpreters) can be configured
independently of the process-wide defaults.
Example::
WSGIPerInterpreterGIL On
WSGISwitchInterval 0.002
WSGIPythonPath /opt/app1/lib
For the GIL-mode side of this container's behaviour, including
worked examples mixing modes across processes, see
:doc:`../user-guides/gil-modes-and-free-threading`.
Selectors
---------
Both ``process-group=`` and ``application-group=`` are optional.
Omitting a key means the container matches any value for that
dimension. The empty container ```` matches
every interpreter.
The ``process-group=`` value matches against the name of a
``WSGIDaemonProcess`` group, or against the empty string for embedded
mode interpreters created in Apache child processes.
The ``application-group=`` value matches against the resolved
application group name at interpreter-creation time. So
``application-group=app1`` matches when a ``WSGIApplicationGroup app1``
directive (or equivalent ``application-group=`` parameter on
``WSGIScriptAlias``, ``WSGIImportScript`` or ``WSGIHandlerScript``)
selects ``app1``.
The literal value ``%{GLOBAL}`` is accepted as a synonym for the
empty string on **both** selectors. On ``application-group=`` it
matches the main Python interpreter. On ``process-group=`` it matches
embedded mode (Apache child processes that have not been routed to a
daemon group).
Variable-expanded application group names of the form ``%{ENV:VAR}``
are resolved at request time, after the configuration has been loaded,
and the container match is evaluated then.
Permitted child directives
--------------------------
Only the following directives are valid inside the container:
* :doc:`WSGIPerInterpreterGIL`
* :doc:`WSGIFreeThreading`
* :doc:`WSGISwitchInterval`
* :doc:`WSGIPythonPath`
* :doc:`WSGIRestrictStdin`
* :doc:`WSGIRestrictStdout`
* :doc:`WSGIRestrictSignal`
Any other directive placed inside the container is a configuration
error.
When a directive listed above appears at server config scope without
being inside a container, it continues to behave as documented on its
own page. Containers are purely additive; existing configurations
continue to work unchanged.
Inheritance and merge rules
---------------------------
When an interpreter is created, mod_wsgi walks every container
defined at server config scope and selects those whose selectors match
the interpreter's resolved process group and application group names.
Each matching container has a specificity score equal to the count of
non-wildcard selector keys: 0 for ````, 1 for
a single-key container, 2 for one with both keys set. Top-level
directives outside any container are treated as the lowest layer.
For the scalar directives (``WSGIPerInterpreterGIL``,
``WSGISwitchInterval``, ``WSGIRestrictStdin``, ``WSGIRestrictStdout``,
``WSGIRestrictSignal``) the most-specific matching layer wins. If two
matching containers share the same specificity, the one written later
in the configuration wins. If no container matches, the top-level
value applies.
For ``WSGIPythonPath`` every matching layer contributes. See
`WSGIPythonPath layering`_ below.
``WSGIFreeThreading`` is resolved separately from the per-interpreter
directives because free-threading is a process-wide setting fixed at
``Py_InitializeFromConfig`` time. The resolver walks containers
matching the current process's ``process-group=`` selector only;
containers with ``application-group=`` set are skipped (and warned
at config load). The resolved value drives ``PyConfig.enable_gil``
and is then read back by sub interpreter creation and switch
interval sites to suppress configuration that has no effect when
the GIL is disabled. See :doc:`WSGIFreeThreading` for the full
rules.
WSGIPythonPath layering
-----------------------
``WSGIPythonPath`` is additive across matching layers rather than
last-write-wins. Each layer's directory list is processed in turn,
least-specific first, most-specific last. For each directory in a
layer mod_wsgi calls ``site.addsitedir()`` so that any ``.pth`` files
in that directory are processed normally, then hoists the entries
that ``site.addsitedir()`` added to the front of ``sys.path``.
Because layers are applied least-specific to most-specific and each
hoist places entries at the front, the most-specific layer's
directories end up at the very front of ``sys.path`` once all layers
have been applied.
The base layer for ``WSGIPythonPath`` depends on which interpreter is
being created:
* For embedded mode interpreters the base layer is the top-level
``WSGIPythonPath`` directive, if set.
* For daemon mode interpreters the base layer is the ``python-path=``
parameter on the matching ``WSGIDaemonProcess`` directive, if set.
The container's ``WSGIPythonPath`` is purely additive on top of the
applicable base layer. It never replaces the base layer. To use a
different base in daemon mode, set ``python-path=`` on the
``WSGIDaemonProcess`` directive.
The empty container::
WSGIPythonPath /opt/lib
adds ``/opt/lib`` to both embedded and daemon interpreters, which is
something there is no way to express with a single top-level directive.
Switch interval validation
--------------------------
A ``WSGIPerInterpreterGIL`` setting only changes the GIL configuration
of sub interpreters. Under the shared GIL the Python interpreter's
switch interval is a process-global value: every interpreter in the
process sees the same switch interval, regardless of which one
``sys.setswitchinterval()`` is called from.
Setting ``WSGISwitchInterval`` inside a container that selects on
``application-group=`` therefore requires that the matching interpreter
also resolves to per-interpreter GIL after the merge. Otherwise the
directive would appear to be application-group-scoped while silently
mutating the process-global value.
For statically-named ``application-group=`` containers the check runs
at configuration load. For ``application-group=%{ENV:VAR}`` containers
the check runs at sub-interpreter creation time; if the check fails
the switch interval setting is skipped for that interpreter and a
warning is logged. The request itself still proceeds.
Containers selecting only on ``process-group=`` (or with no selectors
at all) are always safe with ``WSGISwitchInterval``, because every
interpreter in the matched scope shares whatever GIL configuration is
in force.
Examples
--------
Process-wide opt-in to per-interpreter GIL::
WSGIPerInterpreterGIL On
Per-interpreter GIL only for a single application group, leaving the
rest of the process on the shared GIL::
WSGIPerInterpreterGIL On
Per-interpreter GIL for every interpreter in a named daemon process
group::
WSGIPerInterpreterGIL On
Tuning the GIL switch interval for one application that has its own
GIL, while leaving the rest of the process untouched::
WSGIPerInterpreterGIL On
WSGISwitchInterval 0.001
Adding a directory to ``sys.path`` for one application without
disturbing the daemon-wide path::
WSGIDaemonProcess daemon-1 python-path=/opt/daemon-1
WSGIPythonPath /opt/app1/src:/opt/app1/lib
Restricting ``sys.stdout`` for a single application group while
leaving the process default unchanged::
WSGIRestrictStdout On