Skip to content

Commit 7e943b3

Browse files
committed
Add time conversion
1 parent bf9b613 commit 7e943b3

6 files changed

Lines changed: 144 additions & 20 deletions

File tree

reportportal_client/aio/client.py

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ async def __get_launch_url(self, launch_uuid_future: Union[Optional[str], Task[O
353353
async def start_launch(
354354
self,
355355
name: str,
356-
start_time: Union[str, datetime],
356+
start_time: str,
357357
*,
358358
description: Optional[str] = None,
359359
attributes: Optional[Union[list, dict]] = None,
@@ -406,7 +406,7 @@ async def start_test_item(
406406
self,
407407
launch_uuid: Union[str, Task[str]],
408408
name: str,
409-
start_time: Union[str, datetime],
409+
start_time: str,
410410
item_type: str,
411411
*,
412412
parent_item_id: Optional[Union[str, Task[str]]] = None,
@@ -482,7 +482,7 @@ async def finish_test_item(
482482
self,
483483
launch_uuid: Union[str, Task[str]],
484484
item_id: Union[str, Task[str]],
485-
end_time: Union[str, datetime],
485+
end_time: str,
486486
*,
487487
status: Optional[str] = None,
488488
description: Optional[str] = None,
@@ -539,7 +539,7 @@ async def finish_test_item(
539539
async def finish_launch(
540540
self,
541541
launch_uuid: Union[str, Task[str]],
542-
end_time: Union[str, datetime],
542+
end_time: str,
543543
*,
544544
status: Optional[str] = None,
545545
attributes: Optional[Union[list, dict]] = None,
@@ -947,7 +947,13 @@ async def start_launch(
947947
if not self.use_own_launch:
948948
return self.launch_uuid
949949
launch_uuid = await self.__client.start_launch(
950-
name, start_time, description=description, attributes=attributes, rerun=rerun, rerun_of=rerun_of, **kwargs
950+
name,
951+
await self._convert_time(start_time),
952+
description=description,
953+
attributes=attributes,
954+
rerun=rerun,
955+
rerun_of=rerun_of,
956+
**kwargs,
951957
)
952958
self.__launch_uuid = launch_uuid
953959
return self.launch_uuid
@@ -993,7 +999,7 @@ async def start_test_item(
993999
item_id = await self.__client.start_test_item(
9941000
self.__launch_uuid,
9951001
name,
996-
start_time,
1002+
await self._convert_time(start_time),
9971003
item_type,
9981004
description=description,
9991005
attributes=attributes,
@@ -1045,7 +1051,7 @@ async def finish_test_item(
10451051
result = await self.__client.finish_test_item(
10461052
self.__launch_uuid,
10471053
item_id,
1048-
end_time,
1054+
await self._convert_time(end_time),
10491055
status=status,
10501056
issue=issue,
10511057
attributes=attributes,
@@ -1075,7 +1081,7 @@ async def finish_launch(
10751081
"""
10761082
if self.use_own_launch:
10771083
result = await self.__client.finish_launch(
1078-
self.__launch_uuid, end_time, status=status, attributes=attributes, **kwargs
1084+
self.__launch_uuid, await self._convert_time(end_time), status=status, attributes=attributes, **kwargs
10791085
)
10801086
else:
10811087
result = ""
@@ -1173,6 +1179,13 @@ async def use_microseconds(self) -> Optional[bool]:
11731179
self._use_microseconds = False
11741180
return self._use_microseconds
11751181

1182+
async def _convert_time(self, time_value: Union[str, datetime]) -> str:
1183+
if isinstance(time_value, str):
1184+
return time_value
1185+
if await self.use_microseconds():
1186+
return time_value.strftime("%Y-%m-%dT%H:%M:%S.%f%z")
1187+
return str(int(time_value.timestamp() * 1000))
1188+
11761189
async def log(
11771190
self,
11781191
time: Union[str, datetime],
@@ -1200,7 +1213,7 @@ async def log(
12001213
truncate_fields_enabled=None,
12011214
replace_binary_characters=None,
12021215
launch_uuid=self.__launch_uuid,
1203-
time=time,
1216+
time=await self._convert_time(time),
12041217
file=rp_file,
12051218
item_uuid=item_id,
12061219
level=rp_level,
@@ -1475,7 +1488,13 @@ def start_launch(
14751488
if not self.own_launch:
14761489
return self.launch_uuid
14771490
launch_uuid_coro = self.__client.start_launch(
1478-
name, start_time, description=description, attributes=attributes, rerun=rerun, rerun_of=rerun_of, **kwargs
1491+
name,
1492+
self._convert_time(start_time),
1493+
description=description,
1494+
attributes=attributes,
1495+
rerun=rerun,
1496+
rerun_of=rerun_of,
1497+
**kwargs,
14791498
)
14801499
self.__launch_uuid = self.create_task(launch_uuid_coro)
14811500
return self.launch_uuid
@@ -1521,7 +1540,7 @@ def start_test_item(
15211540
item_id_coro = self.__client.start_test_item(
15221541
self.launch_uuid,
15231542
name,
1524-
start_time,
1543+
self._convert_time(start_time),
15251544
item_type,
15261545
description=description,
15271546
attributes=attributes,
@@ -1571,7 +1590,7 @@ def finish_test_item(
15711590
result_coro = self.__client.finish_test_item(
15721591
self.launch_uuid,
15731592
item_id,
1574-
end_time,
1593+
self._convert_time(end_time),
15751594
status=status,
15761595
issue=issue,
15771596
attributes=attributes,
@@ -1603,7 +1622,7 @@ def finish_launch(
16031622
self.create_task(self.__client.log_batch(self._log_batcher.flush()))
16041623
if self.own_launch:
16051624
result_coro = self.__client.finish_launch(
1606-
self.launch_uuid, end_time, status=status, attributes=attributes, **kwargs
1625+
self.launch_uuid, self._convert_time(end_time), status=status, attributes=attributes, **kwargs
16071626
)
16081627
else:
16091628
result_coro = self.__empty_str()
@@ -1697,6 +1716,13 @@ def use_microseconds(self) -> Task[bool]:
16971716
return self.create_task(self._return_value(self._use_microseconds))
16981717
return self.create_task(self.__resolve_use_microseconds())
16991718

1719+
def _convert_time(self, time_value: Union[str, datetime]) -> str:
1720+
if isinstance(time_value, str):
1721+
return time_value
1722+
if self.use_microseconds().blocking_result():
1723+
return time_value.strftime("%Y-%m-%dT%H:%M:%S.%f%z")
1724+
return str(int(time_value.timestamp() * 1000))
1725+
17001726
async def _log_batch(self, log_rq: Optional[list[AsyncRPRequestLog]]) -> Optional[tuple[str, ...]]:
17011727
return await self.__client.log_batch(log_rq)
17021728

@@ -1730,7 +1756,7 @@ def log(
17301756
truncate_fields_enabled=None,
17311757
replace_binary_characters=None,
17321758
launch_uuid=self.launch_uuid,
1733-
time=time,
1759+
time=self._convert_time(time),
17341760
file=rp_file,
17351761
item_uuid=item_id,
17361762
level=rp_level,

reportportal_client/client.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ def use_microseconds(self) -> Optional[bool]:
161161
"""
162162
raise NotImplementedError('"use_microseconds" method is not implemented!')
163163

164+
@abstractmethod
165+
def _convert_time(self, time: Union[str, datetime]) -> str:
166+
"""Convert time to the format expected by ReportPortal."""
167+
raise NotImplementedError('"convert_time" method is not implemented!')
168+
164169
@abstractmethod
165170
def start_launch(
166171
self,
@@ -714,7 +719,7 @@ def start_launch(
714719
url = uri_join(self.base_url_v2, "launch")
715720
request_payload = LaunchStartRequest(
716721
name=name,
717-
start_time=start_time,
722+
start_time=self._convert_time(start_time),
718723
attributes=attributes,
719724
truncate_attributes_enabled=self.truncate_attributes,
720725
truncate_fields_enabled=self.truncate_fields,
@@ -788,7 +793,7 @@ def start_test_item(
788793
url = uri_join(self.base_url_v2, "item")
789794
request_payload = ItemStartRequest(
790795
name=name,
791-
start_time=start_time,
796+
start_time=self._convert_time(start_time),
792797
type_=item_type,
793798
launch_uuid=self.__launch_uuid,
794799
attributes=attributes,
@@ -857,7 +862,7 @@ def finish_test_item(
857862
return None
858863
url = uri_join(self.base_url_v2, "item", item_id)
859864
request_payload = ItemFinishRequest(
860-
end_time=end_time,
865+
end_time=self._convert_time(end_time),
861866
launch_uuid=self.__launch_uuid,
862867
status=status,
863868
attributes=attributes,
@@ -906,7 +911,7 @@ def finish_launch(
906911
return None
907912
url = uri_join(self.base_url_v2, "launch", self.__launch_uuid, "finish")
908913
request_payload = LaunchFinishRequest(
909-
end_time=end_time,
914+
end_time=self._convert_time(end_time),
910915
status=status,
911916
attributes=attributes,
912917
truncate_attributes_enabled=self.truncate_attributes,
@@ -1014,7 +1019,7 @@ def log(
10141019
truncate_fields_enabled=None,
10151020
replace_binary_characters=None,
10161021
launch_uuid=self.__launch_uuid,
1017-
time=time,
1022+
time=self._convert_time(time),
10181023
file=rp_file,
10191024
item_uuid=item_id,
10201025
level=str(level),
@@ -1084,7 +1089,7 @@ def get_launch_ui_url(self) -> Optional[str]:
10841089
if not mode:
10851090
mode = self.mode
10861091

1087-
launch_type = "launches" if mode.upper() == "DEFAULT" else "userdebug"
1092+
launch_type = "launches" if str(mode).upper() == "DEFAULT" else "userdebug"
10881093

10891094
path = "ui/#{project_name}/{launch_type}/all/{launch_id}".format(
10901095
project_name=self.__project.lower(), launch_type=launch_type, launch_id=ui_id
@@ -1144,6 +1149,14 @@ def use_microseconds(self) -> Optional[bool]:
11441149
self._use_microseconds = False
11451150
return self._use_microseconds
11461151

1152+
def _convert_time(self, time: Union[str, datetime]) -> str:
1153+
"""Convert time to the format expected by ReportPortal."""
1154+
if isinstance(time, str):
1155+
return time
1156+
if self.use_microseconds():
1157+
return time.strftime("%Y-%m-%dT%H:%M:%S.%f%z")
1158+
return str(int(time.timestamp() * 1000))
1159+
11471160
def _add_current_item(self, item: str) -> None:
11481161
"""Add the last item from the self._items queue."""
11491162
self._item_stack.put(item)

tests/aio/test_async_client.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# limitations under the License
1313

1414
import pickle
15+
from datetime import datetime, timezone
1516
from unittest import mock
1617

1718
# noinspection PyPackageRequirements
@@ -220,3 +221,22 @@ async def test_use_microseconds_cached(async_client: AsyncRPClient):
220221
assert await async_client.use_microseconds() is True
221222
assert await async_client.use_microseconds() is True
222223
client.get_api_info.assert_not_called()
224+
225+
226+
@pytest.mark.parametrize(
227+
"time_value, microseconds_enabled, expected_result",
228+
[
229+
("1712700812345", True, "1712700812345"),
230+
(datetime(2024, 1, 2, 3, 4, 5, 678901, tzinfo=timezone.utc), True, "2024-01-02T03:04:05.678901+0000"),
231+
(
232+
datetime(2024, 1, 2, 3, 4, 5, 678901, tzinfo=timezone.utc),
233+
False,
234+
str(int(datetime(2024, 1, 2, 3, 4, 5, 678901, tzinfo=timezone.utc).timestamp() * 1000)),
235+
),
236+
],
237+
)
238+
@pytest.mark.asyncio
239+
async def test_convert_time(async_client: AsyncRPClient, time_value, microseconds_enabled, expected_result):
240+
async_client.use_microseconds = mock.AsyncMock(return_value=microseconds_enabled)
241+
242+
assert await async_client._convert_time(time_value) == expected_result

tests/aio/test_batched_client.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# limitations under the License
1313

1414
import pickle
15+
from datetime import datetime, timezone
1516
from unittest import mock
1617

1718
# noinspection PyPackageRequirements
@@ -189,3 +190,25 @@ def test_use_microseconds_cached():
189190
assert client.use_microseconds().blocking_result() is True
190191
assert client.use_microseconds().blocking_result() is True
191192
aio_client.get_api_info.assert_called_once_with()
193+
194+
195+
@pytest.mark.parametrize(
196+
"time_value, microseconds_enabled, expected_result",
197+
[
198+
("1712700812345", True, "1712700812345"),
199+
(datetime(2024, 1, 2, 3, 4, 5, 678901, tzinfo=timezone.utc), True, "2024-01-02T03:04:05.678901+0000"),
200+
(
201+
datetime(2024, 1, 2, 3, 4, 5, 678901, tzinfo=timezone.utc),
202+
False,
203+
str(int(datetime(2024, 1, 2, 3, 4, 5, 678901, tzinfo=timezone.utc).timestamp() * 1000)),
204+
),
205+
],
206+
)
207+
def test_convert_time(time_value, microseconds_enabled, expected_result):
208+
aio_client = mock.AsyncMock()
209+
client = BatchedRPClient("http://endpoint", "project", api_key="api_key", client=aio_client)
210+
microseconds_task = mock.Mock()
211+
microseconds_task.blocking_result.return_value = microseconds_enabled
212+
client.use_microseconds = mock.Mock(return_value=microseconds_task)
213+
214+
assert client._convert_time(time_value) == expected_result

tests/aio/test_threaded_client.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import pickle
1515
import time
16+
from datetime import datetime, timezone
1617
from unittest import mock
1718

1819
# noinspection PyPackageRequirements
@@ -187,3 +188,25 @@ def test_use_microseconds_cached():
187188
assert client.use_microseconds().blocking_result() is True
188189
assert client.use_microseconds().blocking_result() is True
189190
aio_client.get_api_info.assert_called_once_with()
191+
192+
193+
@pytest.mark.parametrize(
194+
"time_value, microseconds_enabled, expected_result",
195+
[
196+
("1712700812345", True, "1712700812345"),
197+
(datetime(2024, 1, 2, 3, 4, 5, 678901, tzinfo=timezone.utc), True, "2024-01-02T03:04:05.678901+0000"),
198+
(
199+
datetime(2024, 1, 2, 3, 4, 5, 678901, tzinfo=timezone.utc),
200+
False,
201+
str(int(datetime(2024, 1, 2, 3, 4, 5, 678901, tzinfo=timezone.utc).timestamp() * 1000)),
202+
),
203+
],
204+
)
205+
def test_convert_time(time_value, microseconds_enabled, expected_result):
206+
aio_client = mock.AsyncMock()
207+
client = ThreadedRPClient("http://endpoint", "project", api_key="api_key", client=aio_client)
208+
microseconds_task = mock.Mock()
209+
microseconds_task.blocking_result.return_value = microseconds_enabled
210+
client.use_microseconds = mock.Mock(return_value=microseconds_task)
211+
212+
assert client._convert_time(time_value) == expected_result

tests/test_client.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# limitations under the License
1313

1414
import pickle
15+
from datetime import datetime, timezone
1516
from io import StringIO
1617
from unittest import mock
1718

@@ -379,6 +380,24 @@ def test_use_microseconds_default_false(rp_client: RPClient):
379380
rp_client.get_api_info.assert_called_once_with()
380381

381382

383+
@pytest.mark.parametrize(
384+
"time_value, microseconds_enabled, expected_result",
385+
[
386+
("1712700812345", True, "1712700812345"),
387+
(datetime(2024, 1, 2, 3, 4, 5, 678901, tzinfo=timezone.utc), True, "2024-01-02T03:04:05.678901+0000"),
388+
(
389+
datetime(2024, 1, 2, 3, 4, 5, 678901, tzinfo=timezone.utc),
390+
False,
391+
str(int(datetime(2024, 1, 2, 3, 4, 5, 678901, tzinfo=timezone.utc).timestamp() * 1000)),
392+
),
393+
],
394+
)
395+
def test_convert_time(rp_client: RPClient, time_value, microseconds_enabled, expected_result):
396+
rp_client.use_microseconds = mock.Mock(return_value=microseconds_enabled)
397+
398+
assert rp_client._convert_time(time_value) == expected_result
399+
400+
382401
def test_oauth_authentication_parameters():
383402
"""Test that OAuth 2.0 authentication parameters work correctly."""
384403
client = RPClient(

0 commit comments

Comments
 (0)