Skip to content

Commit 494a4f4

Browse files
author
luckyPipewrench
committed
feat: add logo + social preview + fix nanosecond RFC 3339 parsing on Python 3.9/3.10
Repo pimpery pass: - Added centered Pipelock logo to the top of README. - Added social-preview.png for sharing on link previews. Must be uploaded via GitHub repo Settings → Social preview (no REST API support for that field). Correctness fix: - Python 3.9/3.10 `datetime.fromisoformat` only accepts microsecond precision. Go emits nanosecond precision (time.RFC3339Nano). `_is_valid_rfc3339` now truncates fractional seconds to 6 digits before calling fromisoformat, so Go-emitted timestamps with 7-9 fractional digits verify correctly on every supported Python version. Regex shape-check still covers 1-9 digits, semantic check still catches bad dates. Fixes `test_valid_rfc3339_timestamps_accepted[2026-04-09T12:00:00.123456789Z]`.
1 parent f045c9c commit 494a4f4

4 files changed

Lines changed: 89 additions & 4 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
<p align="center">
2+
<img src="assets/pipelock-logo.svg" alt="Pipelock" width="200">
3+
</p>
4+
15
# pipelock-verify
26

37
[![PyPI](https://img.shields.io/pypi/v/pipelock-verify.svg?label=PyPI&logo=pypi&logoColor=white)](https://pypi.org/project/pipelock-verify/)

assets/pipelock-logo.svg

Lines changed: 64 additions & 0 deletions
Loading

assets/social-preview.png

300 KB
Loading

pipelock_verify/_verify.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,34 @@
6464
def _is_valid_rfc3339(value: Any) -> bool:
6565
"""Return True if value parses as an RFC 3339 timestamp Go would accept.
6666
67-
Python's datetime.fromisoformat accepts the ``Z`` suffix natively only
68-
on 3.11+, so we substitute it with ``+00:00`` before parsing to support
69-
3.9 and 3.10 as well.
67+
Go's ``time.RFC3339Nano`` allows up to 9 fractional digits (nanoseconds).
68+
Python's ``datetime.fromisoformat`` tops out at microsecond precision
69+
(6 fractional digits) and the ``Z`` suffix only parses natively on 3.11+.
70+
We handle both differences here so valid Go timestamps verify on 3.9-3.13.
7071
"""
7172
if not isinstance(value, str):
7273
return False
7374
if not _RFC3339_RE.match(value):
7475
return False
7576
candidate = value[:-1] + "+00:00" if value.endswith("Z") else value
77+
# Truncate fractional seconds to 6 digits so fromisoformat accepts
78+
# Go's nanosecond timestamps on Python 3.9/3.10. The regex above has
79+
# already validated the overall shape, so we know there is at most one
80+
# ``.`` before the timezone offset.
81+
match = re.match(
82+
r"^(?P<prefix>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})"
83+
r"(?:\.(?P<frac>\d{1,9}))?"
84+
r"(?P<offset>[+-]\d{2}:\d{2})$",
85+
candidate,
86+
)
87+
if match is None:
88+
return False
89+
prefix = match.group("prefix")
90+
frac = match.group("frac") or ""
91+
offset = match.group("offset")
92+
truncated = f"{prefix}.{frac[:6]}{offset}" if frac else f"{prefix}{offset}"
7693
try:
77-
datetime.fromisoformat(candidate)
94+
datetime.fromisoformat(truncated)
7895
except ValueError:
7996
return False
8097
return True

0 commit comments

Comments
 (0)