PEP 615: Changes to TZPATH and str, plus minor tweaks (#1323)
* Change fallback behavior for __str__ Per Petr's suggestion in the discourse thread. Turns out this was basically what the reference implementation does anyway. * Rename `set_tzpath` to `reset_tzpath` * Adjust TZPATH strategy Partially in response to Petr's comment on the discourse thread, and partially from further reflection. * Fix typo in RFC 8536 reference * Add path traversal to security implications. Seems like a minor concern, but possibly worth noting.
This commit is contained in:
parent
6b5dd00bf1
commit
37a7083660
107
pep-0615.rst
107
pep-0615.rst
|
@ -210,13 +210,15 @@ An example:
|
|||
'Pacific/Kwajalein'
|
||||
|
||||
When a ``key`` is not specified, the ``str`` operation should not fail, but
|
||||
should return the empty string::
|
||||
|
||||
>>> with open("/dev/null", "w") as f:
|
||||
... zone = ZoneInfo.from_file(f)
|
||||
should return the file's ``__repr__``::
|
||||
|
||||
>>> zone = ZoneInfo.from_file(f)
|
||||
>>> str(zone)
|
||||
''
|
||||
'ZoneInfo.from_file(<_io.BytesIO object at ...>)'
|
||||
|
||||
The ``__repr__`` for a ``ZoneInfo`` is implementation-defined and not
|
||||
necessarily stable between versions, but it must not be a valid ``ZoneInfo``
|
||||
key.
|
||||
|
||||
Pickle serialization
|
||||
####################
|
||||
|
@ -363,7 +365,7 @@ customize it. This PEP provides for three such avenues for customization:
|
|||
|
||||
1. Global configuration via a compile-time option
|
||||
2. Per-run configuration via environment variables
|
||||
3. Runtime configuration change via a ``set_tzpath`` function
|
||||
3. Runtime configuration change via a ``reset_tzpath`` function
|
||||
|
||||
Compile-time options
|
||||
####################
|
||||
|
@ -379,16 +381,13 @@ listing possible locations for the time zone data to be deployed (e.g.
|
|||
Environment variables
|
||||
#####################
|
||||
|
||||
When initializing ``TZPATH`` (and whenever ``set_tzpath`` is called with no
|
||||
arguments), the ``zoneinfo`` module will use two environment variables,
|
||||
``PYTHONTZPATH`` and ``PYTHONTZPATH_APPEND``, if they exist, to set the search
|
||||
path.
|
||||
When initializing ``TZPATH`` (and whenever ``reset_tzpath`` is called with no
|
||||
arguments), the ``zoneinfo`` module will use the environment variable
|
||||
``PYTHONTZPATH``, if it exists, to set the search path.
|
||||
|
||||
Both are ``os.pathsep`` delimited strings. ``PYTHONTZPATH`` *replaces* the
|
||||
default time zone path, whereas ``PYTHONTZPATH_APPEND`` appends to the end of
|
||||
the time zone path.
|
||||
|
||||
Some examples of the proposed semantics::
|
||||
``PYTHONTZPATH`` is an ``os.pathsep``-delimited string which *replaces* (rather
|
||||
than augments) the default time zone path. Some examples of the proposed
|
||||
semantics::
|
||||
|
||||
$ python print_tzpath.py
|
||||
("/usr/share/zoneinfo",
|
||||
|
@ -403,23 +402,24 @@ Some examples of the proposed semantics::
|
|||
$ PYTHONTZPATH="" python print_tzpath.py
|
||||
()
|
||||
|
||||
$ PYTHONTZPATH_APPEND="/my/directory" python print_tzpath.py
|
||||
("/usr/share/zoneinfo",
|
||||
"/usr/lib/zoneinfo",
|
||||
"/usr/share/lib/zoneinfo",
|
||||
"/etc/zoneinfo",
|
||||
"/my/directory")
|
||||
This provides no built-in mechanism for prepending or appending to the default
|
||||
search path, as these use cases are likely to be somewhat more niche. It should
|
||||
be possible to populate an environment variable with the default search path
|
||||
fairly easily::
|
||||
|
||||
``set_tzpath`` function
|
||||
#######################
|
||||
$ export DEFAULT_TZPATH=$(python -c \
|
||||
"import os, zoneinfo; print(os.pathsep.join(zoneinfo.TZPATH))")
|
||||
|
||||
``zoneinfo`` provides a ``set_tzpath`` function that allows for changing the
|
||||
``reset_tzpath`` function
|
||||
#########################
|
||||
|
||||
``zoneinfo`` provides a ``reset_tzpath`` function that allows for changing the
|
||||
search path at runtime.
|
||||
|
||||
.. code-block::
|
||||
|
||||
def set_tzpath(
|
||||
tzpaths: Optional[Sequence[Union[str, os.PathLike]]] = None
|
||||
def reset_tzpath(
|
||||
to: Optional[Sequence[Union[str, os.PathLike]]] = None
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
@ -430,7 +430,7 @@ configuration.
|
|||
|
||||
This is likely to be primarily useful for (permanently or temporarily)
|
||||
disabling the use of system time zone paths and forcing the module to use the
|
||||
``tzdata`` package. It is not likely that ``set_tzpath`` will be a common
|
||||
``tzdata`` package. It is not likely that ``reset_tzpath`` will be a common
|
||||
operation, save perhaps in test functions sensitive to time zone configuration,
|
||||
but it seems preferable to provide an official mechanism for changing this
|
||||
rather than allowing a proliferation of hacks around the immutability of
|
||||
|
@ -451,9 +451,9 @@ cache is implementation-defined. This means that the behavior of the
|
|||
when used with the same ``key`` under different values of ``TZPATH``. For
|
||||
example::
|
||||
|
||||
>>> set_tzpath(["/my/custom/tzdb"])
|
||||
>>> reset_tzpath(to=["/my/custom/tzdb"])
|
||||
>>> a = ZoneInfo("My/Custom/Zone")
|
||||
>>> set_tzpath()
|
||||
>>> reset_tzpath()
|
||||
>>> b = ZoneInfo("My/Custom/Zone")
|
||||
>>> del a
|
||||
>>> del b
|
||||
|
@ -488,6 +488,11 @@ but potentially from user-supplied data. Errors in the implementation
|
|||
(particularly the C code) could cause potential security issues, but there is
|
||||
no special risk relative to parsing other file types.
|
||||
|
||||
Because the time zone data keys are essentially paths relative to some time
|
||||
zone root, implementations should take care to avoid path traversal attacks.
|
||||
Requesting keys such as ``../../../path/to/something`` should not reveal
|
||||
anything about the state of the file system outside of the time zone path.
|
||||
|
||||
Reference Implementation
|
||||
========================
|
||||
|
||||
|
@ -691,25 +696,32 @@ so great that it overwhelms the practical implementation concerns, but this
|
|||
still requires some discussion.
|
||||
|
||||
|
||||
Structure of the ``PYTHON_TZPATH`` environment variables
|
||||
========================================================
|
||||
Structure of the ``PYTHON_TZPATH`` environment variable
|
||||
=======================================================
|
||||
|
||||
This PEP proposes two variables to set the time zone path: ``PYTHONTZPATH`` and
|
||||
``PYTHONTZPATH_APPEND``. This is based on the assumption that the majority of
|
||||
This PEP proposes to use a single environment variable: ``PYTHONTZPATH``.
|
||||
This is based on the assumption that the majority of
|
||||
users who would want to manipulate the time zone path would want to fully
|
||||
replace it (e.g. "I know exactly where my time zone data is"), and a smaller
|
||||
fraction would want to use the standard time zone paths wherever possible, but
|
||||
add additional locations (possibly containing custom time zones).
|
||||
replace it (e.g. "I know exactly where my time zone data is"), and other
|
||||
use cases like prepending to the existing search path would be less common.
|
||||
|
||||
There are several other schemes that were considered and weakly rejected:
|
||||
|
||||
1. Separate these into a ``DEFAULT_PYTHONTZPATH`` and ``PYTHONTZPATH``
|
||||
variable, where ``PYTHONTZPATH`` would contain values to append (or prepend)
|
||||
to the default time zone path, and ``DEFAULT_PYTHONTZPATH`` would *replace*
|
||||
the default time zone path. This was rejected because it would likely lead
|
||||
to user confusion if the primary use case is to replace rather than augment.
|
||||
1. Separate ``PYTHON_TZPATH`` into two environment variables:
|
||||
``DEFAULT_PYTHONTZPATH`` and ``PYTHONTZPATH``, where ``PYTHONTZPATH`` would
|
||||
contain values to append (or prepend) to the default time zone path, and
|
||||
``DEFAULT_PYTHONTZPATH`` would *replace* the default time zone path. This
|
||||
was rejected because it would likely lead to user confusion if the primary
|
||||
use case is to replace rather than augment.
|
||||
|
||||
2. Use *only* the ``PYTHONTZPATH`` variable, but provide a custom special value
|
||||
2. Adding either ``PYTHONTZPATH_PREPEND``, ``PYTHONTZPATH_APPEND`` or both, so
|
||||
that users can augment the search path on either end without attempting to
|
||||
determine what the default time zone path is. This was rejected as likely to
|
||||
be unnecessary, and because it could easily be added in a
|
||||
backwards-compatible manner in future updates if there is much demand for
|
||||
such a feature.
|
||||
|
||||
3. Use only the ``PYTHONTZPATH`` variable, but provide a custom special value
|
||||
that represents the default time zone path, e.g. ``<<DEFAULT_TZPATH>>``, so
|
||||
users could append to the time zone path with, e.g.
|
||||
``PYTHONTZPATH=<<DEFAULT_TZPATH>>:/my/path`` could be used to append
|
||||
|
@ -719,6 +731,11 @@ There are several other schemes that were considered and weakly rejected:
|
|||
usually found in ``PATH``-like variables, and it would be hard to discover
|
||||
mistakes in your implementation.
|
||||
|
||||
One advantage to this scheme would be that it would add a natural extension
|
||||
point for specifying non-file-based elements on the search path, such as
|
||||
changing the priority of ``tzdata`` if it exists, or if native support for
|
||||
TZDIST [#rfc7808]_ were to be added to the library in the future.
|
||||
|
||||
Windows support via Microsoft's ICU API
|
||||
=======================================
|
||||
|
||||
|
@ -780,8 +797,12 @@ References
|
|||
RFC 6557: Procedures for Maintaining the Time Zone Database
|
||||
https://tools.ietf.org/html/rfc6557
|
||||
|
||||
.. [#rfc7808]
|
||||
RFC 7808: Time Zone Data Distribution Service
|
||||
https://tools.ietf.org/html/rfc7808
|
||||
|
||||
.. [#rfc8536]
|
||||
RFC 8636: The Time Zone Information Format (TZif)
|
||||
RFC 8536: The Time Zone Information Format (TZif)
|
||||
https://tools.ietf.org/html/rfc8536
|
||||
|
||||
.. [#nontransitive_comp]
|
||||
|
|
Loading…
Reference in New Issue