Skip to content

Commit a45f064

Browse files
committed
Use pathlib.Path to read unix tz
1 parent d1a874d commit a45f064

File tree

1 file changed

+36
-63
lines changed

1 file changed

+36
-63
lines changed

pendulum/tz/local_timezone.py

+36-63
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 Iterator
11-
from typing import cast
1212

1313
from pendulum.tz.exceptions import InvalidTimezone
1414
from pendulum.tz.timezone import UTC
@@ -161,85 +161,58 @@ def _get_unix_timezone(_root: str = "/") -> Timezone:
161161

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

181176
# CentOS has a ZONE setting in /etc/sysconfig/clock,
182177
# OpenSUSE has a TIMEZONE setting in /etc/sysconfig/clock and
183178
# Gentoo has a TIMEZONE setting in /etc/conf.d/clock
184179
# We look through these files for a timezone:
185-
zone_re = re.compile(r'\s*ZONE\s*=\s*"')
186-
timezone_re = re.compile(r'\s*TIMEZONE\s*=\s*"')
187-
end_re = re.compile('"')
180+
zone_re = re.compile(r'\s*(TIME)?ZONE\s*=\s*"([^"]+)?"')
188181

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

221199
# systemd distributions use symlinks that include the zone name,
222200
# see manpage of localtime(5) and timedatectl(1)
223-
tzpath = os.path.join(_root, "etc", "localtime")
224-
if os.path.isfile(tzpath) and os.path.islink(tzpath):
225-
parts = list(
226-
reversed(os.path.realpath(tzpath).replace(" ", "_").split(os.path.sep))
227-
)
201+
tzpath = Path(_root) / "etc" / "localtime"
202+
if tzpath.is_file() and tzpath.is_symlink():
203+
parts = [p.replace(" ", "_") for p in reversed(tzpath.resolve().parts)]
228204
tzpath_parts: list[str] = [] # type: ignore[no-redef]
229205
while parts:
230206
tzpath_parts.insert(0, parts.pop(0))
231207
with contextlib.suppress(InvalidTimezone):
232-
return Timezone(os.path.join(*tzpath_parts))
208+
return Timezone("/".join(tzpath_parts))
233209

234210
# No explicit setting existed. Use localtime
235211
for filename in ("etc/localtime", "usr/local/etc/localtime"):
236-
tzpath = os.path.join(_root, filename)
237-
238-
if not os.path.isfile(tzpath):
239-
continue
240-
241-
with open(tzpath, "rb") as f:
242-
return Timezone.from_file(f)
212+
tzpath = Path(_root) / filename
213+
if tzpath.is_file():
214+
with tzpath.open("rb") as f:
215+
return Timezone.from_file(f)
243216

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

0 commit comments

Comments
 (0)