PEP 615: Updates in response to Steering Council feedback (#1350)
* Rename nocache to no_cache This is more consistent with the snake_case naming convention in from_file and clear_cache. * Add section on clear_cache * Improve string representation section. In response to suggestions by Barry Warsaw: https://github.com/python/steering-council/issues/22#issuecomment-606169944 * Specify failure behavior for time zone data. From discussion with Barry Warsaw: https://github.com/python/steering-council/issues/22#issuecomment-606211514 * Add a footnote regarding the term "first-party" Per comments from Barry Warsaw: https://github.com/python/steering-council/issues/22#issuecomment-606211514
This commit is contained in:
parent
42e4ce4d65
commit
226d6efb95
92
pep-0615.rst
92
pep-0615.rst
|
@ -18,7 +18,7 @@ This proposes adding a module, ``zoneinfo``, to provide a concrete time zone
|
|||
implementation supporting the IANA time zone database. By default,
|
||||
``zoneinfo`` will use the system's time zone data if available; if no system
|
||||
time zone data is available, the library will fall back to using the
|
||||
first-party package ``tzdata``, deployed on PyPI.
|
||||
first-party package ``tzdata``, deployed on PyPI. [d]_
|
||||
|
||||
Motivation
|
||||
==========
|
||||
|
@ -97,6 +97,11 @@ read from the data source (usually a TZif file) upon construction, and may
|
|||
not change during the lifetime of the object (this restriction applies to all
|
||||
``ZoneInfo`` constructors).
|
||||
|
||||
In the event that no matching file is found on the search path (either because
|
||||
the system does not supply time zone data or because the key is invalid), the
|
||||
constructor will raise a ``zoneinfo.ZoneInfoNotFoundError``, which will be a
|
||||
subclass of ``KeyError``.
|
||||
|
||||
One somewhat unusual guarantee made by this constructor is that calls with
|
||||
identical arguments must return *identical* objects. Specifically, for all
|
||||
values of ``key``, the following assertion must always be valid [b]_::
|
||||
|
@ -132,7 +137,7 @@ behavior for end users.
|
|||
|
||||
.. code-block::
|
||||
|
||||
ZoneInfo.nocache(key: str)
|
||||
ZoneInfo.no_cache(key: str)
|
||||
|
||||
This is an alternate constructor that bypasses the constructor's cache. It is
|
||||
identical to the primary constructor, but returns a new object on each call.
|
||||
|
@ -145,7 +150,7 @@ should always be true:
|
|||
|
||||
.. code-block::
|
||||
|
||||
>>> a = ZoneInfo.nocache(key)
|
||||
>>> a = ZoneInfo.no_cache(key)
|
||||
>>> b = ZoneInfo(key)
|
||||
>>> a is not b
|
||||
|
||||
|
@ -164,7 +169,7 @@ stream objects have mutable state and so determining whether two inputs are
|
|||
identical is difficult or impossible, and it is likely that users constructing
|
||||
from a file specifically want to load from that file and not a cache.
|
||||
|
||||
As with ``ZoneInfo.nocache``, objects constructed by this method must not be
|
||||
As with ``ZoneInfo.no_cache``, objects constructed by this method must not be
|
||||
added to the cache.
|
||||
|
||||
Behavior during data updates
|
||||
|
@ -187,7 +192,7 @@ should come from the updated data source.
|
|||
This means that the point at which a ``ZoneInfo`` file is updated depends
|
||||
primarily on the semantics of the caching behavior. The only guaranteed way to
|
||||
get a ``ZoneInfo`` file from an updated data source is to induce a cache miss,
|
||||
either by bypassing the cache and using ``ZoneInfo.nocache`` or by clearing the
|
||||
either by bypassing the cache and using ``ZoneInfo.no_cache`` or by clearing the
|
||||
cache.
|
||||
|
||||
.. note::
|
||||
|
@ -197,15 +202,59 @@ cache.
|
|||
recommended) to eagerly pre-populate the cache with time zones that have
|
||||
never been constructed.
|
||||
|
||||
Deliberate cache invalidation
|
||||
#############################
|
||||
|
||||
In addition to ``ZoneInfo.no_cache``, which allows a user to *bypass* the
|
||||
cache, ``ZoneInfo`` also exposes a ``clear_cache`` method to deliberately
|
||||
invalidate either the entire cache or selective portions of the cache::
|
||||
|
||||
ZoneInfo.clear_cache(*, only_keys: Iterable[str]=None) -> None
|
||||
|
||||
If no arguments are passed, all caches are invalidated and the first call for
|
||||
each key to the primary ``ZoneInfo`` constructor after the cache has been
|
||||
cleared will return a new instance.
|
||||
|
||||
.. code-block::
|
||||
|
||||
>>> NYC0 = ZoneInfo("America/New_York")
|
||||
>>> NYC0 is ZoneInfo("America/New_York")
|
||||
True
|
||||
>>> ZoneInfo.clear_cache()
|
||||
>>> NYC1 = ZoneInfo("America/New_York")
|
||||
>>> NYC0 is NYC1
|
||||
False
|
||||
>>> NYC1 is ZoneInfo("America/New_York")
|
||||
True
|
||||
|
||||
An optional parameter, ``only_keys``, takes an iterable of keys to clear from
|
||||
the cache, otherwise leaving the cache intact.
|
||||
|
||||
.. code-block::
|
||||
|
||||
>>> NYC0 = ZoneInfo("America/New_York")
|
||||
>>> LA0 = ZoneInfo("America/Los_Angeles")
|
||||
>>> ZoneInfo.clear_cache(only_keys=["America/New_York"])
|
||||
>>> NYC1 = ZoneInfo("America/New_York")
|
||||
>>> LA0 = ZoneInfo("America/Los_Angeles")
|
||||
>>> NYC0 is NYC1
|
||||
False
|
||||
>>> LA0 is LA1
|
||||
True
|
||||
|
||||
Manipulation of the cache behavior is expected to be a niche use case; this
|
||||
function is primarily provided to facilitate testing, and to allow users with
|
||||
unusual requirements to tune the cache invalidation behavior to their needs.
|
||||
|
||||
.. _Representations:
|
||||
|
||||
String representation
|
||||
#####################
|
||||
|
||||
The ``ZoneInfo`` class's ``__str__`` representation will be drawn from the
|
||||
``key`` parameter. This is partially because the ``key`` represents a
|
||||
``key`` parameter. This is partially because the ``key`` represents a
|
||||
human-readable "name" of the string, but also because it is a useful parameter
|
||||
that users will want exposed. It is necessary to provide a mechanism to expose
|
||||
that users will want exposed. It is necessary to provide a mechanism to expose
|
||||
the key for serialization between languages and because it is also a primary
|
||||
key for localization projects like CLDR (the Unicode Common Locale Data
|
||||
Repository [#cldr]_).
|
||||
|
@ -218,6 +267,11 @@ An example:
|
|||
>>> str(zone)
|
||||
'Pacific/Kwajalein'
|
||||
|
||||
>>> dt = datetime(2020, 4, 1, 3, 15, tzinfo=zone)
|
||||
>>> f"{dt.isoformat()} [{dt.tzinfo}]"
|
||||
'2020-04-01T03:15:00+12:00 [Pacific/Kwajalein]'
|
||||
|
||||
|
||||
When a ``key`` is not specified, the ``str`` operation should not fail, but
|
||||
should return the file's ``__repr__``::
|
||||
|
||||
|
@ -227,7 +281,15 @@ should return the file's ``__repr__``::
|
|||
|
||||
The ``__repr__`` for a ``ZoneInfo`` is implementation-defined and not
|
||||
necessarily stable between versions, but it must not be a valid ``ZoneInfo``
|
||||
key.
|
||||
key, to avoid confusion between a key-derived ``ZoneInfo`` with a valid
|
||||
``__str__`` and a file-derived ``ZoneInfo`` which has fallen through to the
|
||||
``__repr__``.
|
||||
|
||||
Since the use of ``str()`` to access the key provides no easy way to check
|
||||
for the *presence* of a key (the only way is to try constructing a ``ZoneInfo``
|
||||
from it and detect whether it raises an exception), ``ZoneInfo`` objects will
|
||||
also expose a read-only ``key`` attribute, which will be ``None`` in the event
|
||||
that no key was supplied.
|
||||
|
||||
Pickle serialization
|
||||
####################
|
||||
|
@ -253,11 +315,11 @@ The behavior of a ``ZoneInfo`` file depends on how it was constructed:
|
|||
>>> a is b
|
||||
True
|
||||
|
||||
2. ``ZoneInfo.nocache(key)``: When constructed from the cache-bypassing
|
||||
2. ``ZoneInfo.no_cache(key)``: When constructed from the cache-bypassing
|
||||
constructor, the ``ZoneInfo`` object will still be serialized by key, but
|
||||
when deserialized, it will use the cache bypassing constructor. If
|
||||
``europe_berlin_pkl_nc`` is a string containing a pickle constructed from
|
||||
``ZoneInfo.nocache("Europe/Berlin")``, one would expect the following
|
||||
``ZoneInfo.no_cache("Europe/Berlin")``, one would expect the following
|
||||
behavior:
|
||||
|
||||
.. code-block::
|
||||
|
@ -295,7 +357,7 @@ to use system-deployed time zone data wherever possible. However, not all
|
|||
systems ship a publicly accessible time zone database — notably Windows uses a
|
||||
different system for managing time zones — and so if available ``zoneinfo``
|
||||
falls back to an installable first-party package, ``tzdata``, available on
|
||||
PyPI. If no system zoneinfo files are found but ``tzdata`` is installed, the
|
||||
PyPI. [d]_ If no system zoneinfo files are found but ``tzdata`` is installed, the
|
||||
primary ``ZoneInfo`` constructor will use ``tzdata`` as the time zone source.
|
||||
|
||||
System time zone information
|
||||
|
@ -352,7 +414,7 @@ The ``tzdata`` Python package
|
|||
In order to ensure easy access to time zone data for all end users, this PEP
|
||||
proposes to create a data-only package ``tzdata`` as a fallback for when system
|
||||
data is not available. The ``tzdata`` package would be distributed on PyPI as
|
||||
a "first party" package, maintained by the CPython development team.
|
||||
a "first party" package [d]_, maintained by the CPython development team.
|
||||
|
||||
The ``tzdata`` package contains only data and metadata, with no public-facing
|
||||
functions or classes. It will be designed to be compatible with both newer
|
||||
|
@ -792,6 +854,12 @@ Footnotes
|
|||
we do not need to worry about the possibly more serious issue that a given
|
||||
``datetime`` object's hash would change during its lifetime.
|
||||
|
||||
.. [d]
|
||||
The term "first party" here is distinguished from "third party" in that,
|
||||
although it is is distributed via PyPI and is not currently included in
|
||||
Python by default, it is to be considered an official sub-project of
|
||||
CPython rather than a "blessed" third-party package.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
|
|
Loading…
Reference in New Issue