comparison planemo/lib/python3.7/site-packages/dateutil/zoneinfo/__init__.py @ 0:d30785e31577 draft

"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author guerler
date Fri, 31 Jul 2020 00:18:57 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:d30785e31577
1 # -*- coding: utf-8 -*-
2 import warnings
3 import json
4
5 from tarfile import TarFile
6 from pkgutil import get_data
7 from io import BytesIO
8
9 from dateutil.tz import tzfile as _tzfile
10
11 __all__ = ["get_zonefile_instance", "gettz", "gettz_db_metadata"]
12
13 ZONEFILENAME = "dateutil-zoneinfo.tar.gz"
14 METADATA_FN = 'METADATA'
15
16
17 class tzfile(_tzfile):
18 def __reduce__(self):
19 return (gettz, (self._filename,))
20
21
22 def getzoneinfofile_stream():
23 try:
24 return BytesIO(get_data(__name__, ZONEFILENAME))
25 except IOError as e: # TODO switch to FileNotFoundError?
26 warnings.warn("I/O error({0}): {1}".format(e.errno, e.strerror))
27 return None
28
29
30 class ZoneInfoFile(object):
31 def __init__(self, zonefile_stream=None):
32 if zonefile_stream is not None:
33 with TarFile.open(fileobj=zonefile_stream) as tf:
34 self.zones = {zf.name: tzfile(tf.extractfile(zf), filename=zf.name)
35 for zf in tf.getmembers()
36 if zf.isfile() and zf.name != METADATA_FN}
37 # deal with links: They'll point to their parent object. Less
38 # waste of memory
39 links = {zl.name: self.zones[zl.linkname]
40 for zl in tf.getmembers() if
41 zl.islnk() or zl.issym()}
42 self.zones.update(links)
43 try:
44 metadata_json = tf.extractfile(tf.getmember(METADATA_FN))
45 metadata_str = metadata_json.read().decode('UTF-8')
46 self.metadata = json.loads(metadata_str)
47 except KeyError:
48 # no metadata in tar file
49 self.metadata = None
50 else:
51 self.zones = {}
52 self.metadata = None
53
54 def get(self, name, default=None):
55 """
56 Wrapper for :func:`ZoneInfoFile.zones.get`. This is a convenience method
57 for retrieving zones from the zone dictionary.
58
59 :param name:
60 The name of the zone to retrieve. (Generally IANA zone names)
61
62 :param default:
63 The value to return in the event of a missing key.
64
65 .. versionadded:: 2.6.0
66
67 """
68 return self.zones.get(name, default)
69
70
71 # The current API has gettz as a module function, although in fact it taps into
72 # a stateful class. So as a workaround for now, without changing the API, we
73 # will create a new "global" class instance the first time a user requests a
74 # timezone. Ugly, but adheres to the api.
75 #
76 # TODO: Remove after deprecation period.
77 _CLASS_ZONE_INSTANCE = []
78
79
80 def get_zonefile_instance(new_instance=False):
81 """
82 This is a convenience function which provides a :class:`ZoneInfoFile`
83 instance using the data provided by the ``dateutil`` package. By default, it
84 caches a single instance of the ZoneInfoFile object and returns that.
85
86 :param new_instance:
87 If ``True``, a new instance of :class:`ZoneInfoFile` is instantiated and
88 used as the cached instance for the next call. Otherwise, new instances
89 are created only as necessary.
90
91 :return:
92 Returns a :class:`ZoneInfoFile` object.
93
94 .. versionadded:: 2.6
95 """
96 if new_instance:
97 zif = None
98 else:
99 zif = getattr(get_zonefile_instance, '_cached_instance', None)
100
101 if zif is None:
102 zif = ZoneInfoFile(getzoneinfofile_stream())
103
104 get_zonefile_instance._cached_instance = zif
105
106 return zif
107
108
109 def gettz(name):
110 """
111 This retrieves a time zone from the local zoneinfo tarball that is packaged
112 with dateutil.
113
114 :param name:
115 An IANA-style time zone name, as found in the zoneinfo file.
116
117 :return:
118 Returns a :class:`dateutil.tz.tzfile` time zone object.
119
120 .. warning::
121 It is generally inadvisable to use this function, and it is only
122 provided for API compatibility with earlier versions. This is *not*
123 equivalent to ``dateutil.tz.gettz()``, which selects an appropriate
124 time zone based on the inputs, favoring system zoneinfo. This is ONLY
125 for accessing the dateutil-specific zoneinfo (which may be out of
126 date compared to the system zoneinfo).
127
128 .. deprecated:: 2.6
129 If you need to use a specific zoneinfofile over the system zoneinfo,
130 instantiate a :class:`dateutil.zoneinfo.ZoneInfoFile` object and call
131 :func:`dateutil.zoneinfo.ZoneInfoFile.get(name)` instead.
132
133 Use :func:`get_zonefile_instance` to retrieve an instance of the
134 dateutil-provided zoneinfo.
135 """
136 warnings.warn("zoneinfo.gettz() will be removed in future versions, "
137 "to use the dateutil-provided zoneinfo files, instantiate a "
138 "ZoneInfoFile object and use ZoneInfoFile.zones.get() "
139 "instead. See the documentation for details.",
140 DeprecationWarning)
141
142 if len(_CLASS_ZONE_INSTANCE) == 0:
143 _CLASS_ZONE_INSTANCE.append(ZoneInfoFile(getzoneinfofile_stream()))
144 return _CLASS_ZONE_INSTANCE[0].zones.get(name)
145
146
147 def gettz_db_metadata():
148 """ Get the zonefile metadata
149
150 See `zonefile_metadata`_
151
152 :returns:
153 A dictionary with the database metadata
154
155 .. deprecated:: 2.6
156 See deprecation warning in :func:`zoneinfo.gettz`. To get metadata,
157 query the attribute ``zoneinfo.ZoneInfoFile.metadata``.
158 """
159 warnings.warn("zoneinfo.gettz_db_metadata() will be removed in future "
160 "versions, to use the dateutil-provided zoneinfo files, "
161 "ZoneInfoFile object and query the 'metadata' attribute "
162 "instead. See the documentation for details.",
163 DeprecationWarning)
164
165 if len(_CLASS_ZONE_INSTANCE) == 0:
166 _CLASS_ZONE_INSTANCE.append(ZoneInfoFile(getzoneinfofile_stream()))
167 return _CLASS_ZONE_INSTANCE[0].metadata