Skip to content

Commit 7fa60ec

Browse files
committed
BB: Pipeline.get_time() regression in 5.0.1: datetime.fromisoformat() fails on Python <3.11 for non-3/6-digit fractional seconds
atlassian-api#1651
1 parent 901c019 commit 7fa60ec

2 files changed

Lines changed: 33 additions & 3 deletions

File tree

atlassian/bitbucket/base.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# coding=utf-8
22

33
import copy
4+
import re
45
from datetime import datetime
56
from pprint import PrettyPrinter
67

@@ -158,8 +159,14 @@ def get_time(self, id):
158159
if isinstance(value_str, str):
159160
# Bitbucket Cloud returns ISO 8601 timestamps with optional
160161
# fractional seconds and either an offset or a trailing ``Z``.
161-
# Do not trim or otherwise alter the timestamp: doing so turns
162-
# ``+00:00`` into the invalid ``+00:00Z`` form.
162+
# Python 3.10 and older only accept 0, 3, or 6 fractional digits,
163+
# while Bitbucket may return another precision. Clamp the fraction
164+
# to microsecond precision without touching the UTC offset.
165+
value_str = re.sub(
166+
r"\.(\d+)(?=(?:Z|[+-]\d{2}:?\d{2})?$)",
167+
lambda match: "." + match.group(1)[:6].ljust(6, "0"),
168+
value_str,
169+
)
163170
value = datetime.fromisoformat(value_str.replace("Z", "+00:00"))
164171
else:
165172
value = value_str

tests/test_bitbucket_cloud_oo.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# coding: utf8
22
import sys
3-
from datetime import datetime, timezone
3+
from datetime import datetime, timedelta, timezone
44

55
import pytest
66

@@ -9,6 +9,7 @@
99
from atlassian.bitbucket.cloud.common.users import User
1010
from atlassian.bitbucket.cloud.repositories import WorkspaceRepositories
1111
from atlassian.bitbucket.cloud.repositories.commits import Commit as RepositoryCommit
12+
from atlassian.bitbucket.cloud.repositories.pipelines import Pipeline
1213
from atlassian.bitbucket.cloud.repositories.pullRequests import (
1314
Build,
1415
Comment,
@@ -52,6 +53,28 @@ def test_commit_date_parses_iso8601_timestamps(self, timestamp, expected):
5253

5354
assert commit.date == expected
5455

56+
@pytest.mark.parametrize(
57+
"timestamp, expected",
58+
[
59+
(
60+
"2026-08-15T23:19:42.71295178+00:00",
61+
datetime(2026, 8, 15, 23, 19, 42, 712951, tzinfo=timezone.utc),
62+
),
63+
(
64+
"2026-08-15T23:19:42.7+05:30",
65+
datetime(2026, 8, 15, 23, 19, 42, 700000, tzinfo=timezone(timedelta(hours=5, minutes=30))),
66+
),
67+
],
68+
)
69+
def test_pipeline_time_normalizes_variable_fractional_seconds(self, timestamp, expected):
70+
pipeline = Pipeline(
71+
"https://api.bitbucket.org/2.0/repositories/workspace/repository/pipelines/{pipeline}",
72+
{"type": "pipeline", "completed_on": timestamp},
73+
**CLOUD._new_session_args,
74+
)
75+
76+
assert pipeline.completed_on == expected
77+
5578
def test_each_workspace_uses_user_workspaces_endpoint(self, monkeypatch):
5679
workspaces = CLOUD.workspaces
5780
workspace = object()

0 commit comments

Comments
 (0)