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:
Paul Ganssle 2020-03-01 09:23:37 -05:00 committed by GitHub
parent 6b5dd00bf1
commit 37a7083660
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 64 additions and 43 deletions

View File

@ -210,13 +210,15 @@ An example:
'Pacific/Kwajalein' 'Pacific/Kwajalein'
When a ``key`` is not specified, the ``str`` operation should not fail, but When a ``key`` is not specified, the ``str`` operation should not fail, but
should return the empty string:: should return the file's ``__repr__``::
>>> with open("/dev/null", "w") as f:
... zone = ZoneInfo.from_file(f)
>>> zone = ZoneInfo.from_file(f)
>>> str(zone) >>> 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 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 1. Global configuration via a compile-time option
2. Per-run configuration via environment variables 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 Compile-time options
#################### ####################
@ -379,16 +381,13 @@ listing possible locations for the time zone data to be deployed (e.g.
Environment variables Environment variables
##################### #####################
When initializing ``TZPATH`` (and whenever ``set_tzpath`` is called with no When initializing ``TZPATH`` (and whenever ``reset_tzpath`` is called with no
arguments), the ``zoneinfo`` module will use two environment variables, arguments), the ``zoneinfo`` module will use the environment variable
``PYTHONTZPATH`` and ``PYTHONTZPATH_APPEND``, if they exist, to set the search ``PYTHONTZPATH``, if it exists, to set the search path.
path.
Both are ``os.pathsep`` delimited strings. ``PYTHONTZPATH`` *replaces* the ``PYTHONTZPATH`` is an ``os.pathsep``-delimited string which *replaces* (rather
default time zone path, whereas ``PYTHONTZPATH_APPEND`` appends to the end of than augments) the default time zone path. Some examples of the proposed
the time zone path. semantics::
Some examples of the proposed semantics::
$ python print_tzpath.py $ python print_tzpath.py
("/usr/share/zoneinfo", ("/usr/share/zoneinfo",
@ -403,23 +402,24 @@ Some examples of the proposed semantics::
$ PYTHONTZPATH="" python print_tzpath.py $ PYTHONTZPATH="" python print_tzpath.py
() ()
$ PYTHONTZPATH_APPEND="/my/directory" python print_tzpath.py This provides no built-in mechanism for prepending or appending to the default
("/usr/share/zoneinfo", search path, as these use cases are likely to be somewhat more niche. It should
"/usr/lib/zoneinfo", be possible to populate an environment variable with the default search path
"/usr/share/lib/zoneinfo", fairly easily::
"/etc/zoneinfo",
"/my/directory")
``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. search path at runtime.
.. code-block:: .. code-block::
def set_tzpath( def reset_tzpath(
tzpaths: Optional[Sequence[Union[str, os.PathLike]]] = None to: Optional[Sequence[Union[str, os.PathLike]]] = None
) -> None: ) -> None:
... ...
@ -430,7 +430,7 @@ configuration.
This is likely to be primarily useful for (permanently or temporarily) 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 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, operation, save perhaps in test functions sensitive to time zone configuration,
but it seems preferable to provide an official mechanism for changing this but it seems preferable to provide an official mechanism for changing this
rather than allowing a proliferation of hacks around the immutability of 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 when used with the same ``key`` under different values of ``TZPATH``. For
example:: example::
>>> set_tzpath(["/my/custom/tzdb"]) >>> reset_tzpath(to=["/my/custom/tzdb"])
>>> a = ZoneInfo("My/Custom/Zone") >>> a = ZoneInfo("My/Custom/Zone")
>>> set_tzpath() >>> reset_tzpath()
>>> b = ZoneInfo("My/Custom/Zone") >>> b = ZoneInfo("My/Custom/Zone")
>>> del a >>> del a
>>> del b >>> 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 (particularly the C code) could cause potential security issues, but there is
no special risk relative to parsing other file types. 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 Reference Implementation
======================== ========================
@ -691,25 +696,32 @@ so great that it overwhelms the practical implementation concerns, but this
still requires some discussion. 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 This PEP proposes to use a single environment variable: ``PYTHONTZPATH``.
``PYTHONTZPATH_APPEND``. This is based on the assumption that the majority of This is based on the assumption that the majority of
users who would want to manipulate the time zone path would want to fully 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 replace it (e.g. "I know exactly where my time zone data is"), and other
fraction would want to use the standard time zone paths wherever possible, but use cases like prepending to the existing search path would be less common.
add additional locations (possibly containing custom time zones).
There are several other schemes that were considered and weakly rejected: There are several other schemes that were considered and weakly rejected:
1. Separate these into a ``DEFAULT_PYTHONTZPATH`` and ``PYTHONTZPATH`` 1. Separate ``PYTHON_TZPATH`` into two environment variables:
variable, where ``PYTHONTZPATH`` would contain values to append (or prepend) ``DEFAULT_PYTHONTZPATH`` and ``PYTHONTZPATH``, where ``PYTHONTZPATH`` would
to the default time zone path, and ``DEFAULT_PYTHONTZPATH`` would *replace* contain values to append (or prepend) to the default time zone path, and
the default time zone path. This was rejected because it would likely lead ``DEFAULT_PYTHONTZPATH`` would *replace* the default time zone path. This
to user confusion if the primary use case is to replace rather than augment. 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 that represents the default time zone path, e.g. ``<<DEFAULT_TZPATH>>``, so
users could append to the time zone path with, e.g. users could append to the time zone path with, e.g.
``PYTHONTZPATH=<<DEFAULT_TZPATH>>:/my/path`` could be used to append ``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 usually found in ``PATH``-like variables, and it would be hard to discover
mistakes in your implementation. 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 Windows support via Microsoft's ICU API
======================================= =======================================
@ -780,8 +797,12 @@ References
RFC 6557: Procedures for Maintaining the Time Zone Database RFC 6557: Procedures for Maintaining the Time Zone Database
https://tools.ietf.org/html/rfc6557 https://tools.ietf.org/html/rfc6557
.. [#rfc7808]
RFC 7808: Time Zone Data Distribution Service
https://tools.ietf.org/html/rfc7808
.. [#rfc8536] .. [#rfc8536]
RFC 8636: The Time Zone Information Format (TZif) RFC 8536: The Time Zone Information Format (TZif)
https://tools.ietf.org/html/rfc8536 https://tools.ietf.org/html/rfc8536
.. [#nontransitive_comp] .. [#nontransitive_comp]