Skip to content

Commit fc386be

Browse files
authored
Use pathlib.Path to read unix tz (#742)
1 parent 9826867 commit fc386be

File tree

1 file changed

+35
-64
lines changed

1 file changed

+35
-64
lines changed

src/pendulum/tz/local_timezone.py

+35-64
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import warnings
88

99
from contextlib import contextmanager
10+
from pathlib import Path
1011
from typing import TYPE_CHECKING
11-
from typing import cast
1212

1313
from pendulum.tz.exceptions import InvalidTimezone
1414
from pendulum.tz.timezone import UTC
@@ -165,86 +165,57 @@ def _get_unix_timezone(_root: str = "/") -> Timezone:
165165

166166
# Now look for distribution specific configuration files
167167
# that contain the timezone name.
168-
tzpath = os.path.join(_root, "etc/timezone")
169-
if os.path.isfile(tzpath):
170-
with open(tzpath, "rb") as tzfile:
171-
tzfile_data = tzfile.read()
172-
173-
# Issue #3 was that /etc/timezone was a zoneinfo file.
174-
# That's a misconfiguration, but we need to handle it gracefully:
175-
if tzfile_data[:5] != b"TZif2":
176-
etctz = tzfile_data.strip().decode()
177-
# Get rid of host definitions and comments:
178-
if " " in etctz:
179-
etctz, dummy = etctz.split(" ", 1)
180-
if "#" in etctz:
181-
etctz, dummy = etctz.split("#", 1)
182-
183-
return Timezone(etctz.replace(" ", "_"))
168+
tzpath = Path(_root) / "etc" / "timezone"
169+
if tzpath.is_file():
170+
tzfile_data = tzpath.read_bytes()
171+
# Issue #3 was that /etc/timezone was a zoneinfo file.
172+
# That's a misconfiguration, but we need to handle it gracefully:
173+
if not tzfile_data.startswith(b"TZif2"):
174+
etctz = tzfile_data.strip().decode()
175+
# Get rid of host definitions and comments:
176+
etctz, _, _ = etctz.partition(" ")
177+
etctz, _, _ = etctz.partition("#")
178+
return Timezone(etctz.replace(" ", "_"))
184179

185180
# CentOS has a ZONE setting in /etc/sysconfig/clock,
186181
# OpenSUSE has a TIMEZONE setting in /etc/sysconfig/clock and
187182
# Gentoo has a TIMEZONE setting in /etc/conf.d/clock
188183
# We look through these files for a timezone:
189-
zone_re = re.compile(r'\s*ZONE\s*=\s*"')
190-
timezone_re = re.compile(r'\s*TIMEZONE\s*=\s*"')
191-
end_re = re.compile('"')
184+
zone_re = re.compile(r'\s*(TIME)?ZONE\s*=\s*"([^"]+)?"')
192185

193186
for filename in ("etc/sysconfig/clock", "etc/conf.d/clock"):
194-
tzpath = os.path.join(_root, filename)
195-
if not os.path.isfile(tzpath):
196-
continue
197-
198-
with open(tzpath) as tzfile:
199-
data = tzfile.readlines()
200-
201-
for line in data:
202-
# Look for the ZONE= setting.
203-
match = zone_re.match(line)
204-
if match is None:
205-
# No ZONE= setting. Look for the TIMEZONE= setting.
206-
match = timezone_re.match(line)
207-
208-
if match is not None:
209-
# Some setting existed
210-
line = line[match.end() :]
211-
etctz = line[
212-
: cast(
213-
"re.Match[str]",
214-
end_re.search(line),
215-
).start()
216-
]
217-
218-
parts = list(reversed(etctz.replace(" ", "_").split(os.path.sep)))
219-
tzpath_parts: list[str] = []
220-
while parts:
221-
tzpath_parts.insert(0, parts.pop(0))
222-
223-
with contextlib.suppress(InvalidTimezone):
224-
return Timezone(os.path.join(*tzpath_parts))
187+
tzpath = Path(_root) / filename
188+
if tzpath.is_file():
189+
data = tzpath.read_text().splitlines()
190+
for line in data:
191+
# Look for the ZONE= or TIMEZONE= setting.
192+
match = zone_re.match(line)
193+
if match:
194+
etctz = match.group(2)
195+
parts = list(reversed(etctz.replace(" ", "_").split(os.path.sep)))
196+
tzpath_parts: list[str] = []
197+
while parts:
198+
tzpath_parts.insert(0, parts.pop(0))
199+
with contextlib.suppress(InvalidTimezone):
200+
return Timezone(os.path.sep.join(tzpath_parts))
225201

226202
# systemd distributions use symlinks that include the zone name,
227203
# see manpage of localtime(5) and timedatectl(1)
228-
tzpath = os.path.join(_root, "etc", "localtime")
229-
if os.path.isfile(tzpath) and os.path.islink(tzpath):
230-
parts = list(
231-
reversed(os.path.realpath(tzpath).replace(" ", "_").split(os.path.sep))
232-
)
204+
tzpath = Path(_root) / "etc" / "localtime"
205+
if tzpath.is_file() and tzpath.is_symlink():
206+
parts = [p.replace(" ", "_") for p in reversed(tzpath.resolve().parts)]
233207
tzpath_parts: list[str] = [] # type: ignore[no-redef]
234208
while parts:
235209
tzpath_parts.insert(0, parts.pop(0))
236210
with contextlib.suppress(InvalidTimezone):
237-
return Timezone(os.path.join(*tzpath_parts))
211+
return Timezone(os.path.sep.join(tzpath_parts))
238212

239213
# No explicit setting existed. Use localtime
240214
for filename in ("etc/localtime", "usr/local/etc/localtime"):
241-
tzpath = os.path.join(_root, filename)
242-
243-
if not os.path.isfile(tzpath):
244-
continue
245-
246-
with open(tzpath, "rb") as f:
247-
return Timezone.from_file(f)
215+
tzpath = Path(_root) / filename
216+
if tzpath.is_file():
217+
with tzpath.open("rb") as f:
218+
return Timezone.from_file(f)
248219

249220
warnings.warn(
250221
"Unable not find any timezone configuration, defaulting to UTC.", stacklevel=1

0 commit comments

Comments
 (0)