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'
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]