Skip to content

Commit 9c5343f

Browse files
committed
Replace arrow with humanize
This is good enough for our use case and is much lighter weight. Signed-off-by: Stephen Finucane <stephen@that.guru>
1 parent c1faf35 commit 9c5343f

7 files changed

Lines changed: 39 additions & 8 deletions

File tree

‎.pre-commit-config.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ repos:
99
- id: end-of-file-fixer
1010
- id: trailing-whitespace
1111
- repo: https://github.com/astral-sh/ruff-pre-commit
12-
rev: v0.15.10
12+
rev: v0.17.1
1313
hooks:
1414
- id: ruff-check
1515
args: ['--fix', '--unsafe-fixes']

‎README.rst‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,14 @@ dependencies. On Fedora, run:
4747
.. code-block:: bash
4848
4949
$ sudo dnf install python3-requests python3-click python3-pbr \
50-
python3-arrow python3-tabulate python3-yaml
50+
python3-humanize python3-tabulate python3-yaml
5151
5252
On Ubuntu, run:
5353

5454
.. code-block:: bash
5555
5656
$ sudo apt-get install python3-requests python3-click python3-pbr \
57-
python3-arrow python3-tabulate python3-yaml
57+
python3-humanize python3-tabulate python3-yaml
5858
5959
Once dependencies are installed, clone this repo and install with ``pip``:
6060

‎git_pw/patch.py‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import sys
99
from typing import Any
1010

11-
import arrow
1211
import click
1312

1413
from git_pw import api
@@ -442,7 +441,7 @@ def list_cmd(
442441
for patch in patches:
443442
item = [
444443
patch.get('id'),
445-
arrow.get(patch['date']).humanize(),
444+
utils.humanize_date(patch['date']),
446445
utils.trim(patch.get('name') or ''),
447446
'{} ({})'.format(
448447
(patch.get('submitter') or {}).get('name'),

‎git_pw/series.py‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import sys
99
from typing import Any
1010

11-
import arrow
1211
import click
1312

1413
from git_pw import api
@@ -257,7 +256,7 @@ def list_cmd(
257256
for series_ in series:
258257
item = [
259258
series_.get('id'),
260-
arrow.get(series_['date']).humanize(),
259+
utils.humanize_date(series_['date']),
261260
utils.trim(series_.get('name') or ''),
262261
series_.get('version'),
263262
'{} ({})'.format(

‎git_pw/utils.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from collections.abc import Callable, Sequence
66
import csv
7+
import datetime
78
import io
89
import logging
910
import os
@@ -12,6 +13,7 @@
1213
from typing import Any, TypeVar, overload
1314

1415
import click
16+
import humanize
1517
from tabulate import tabulate
1618
import yaml
1719

@@ -35,6 +37,14 @@ def trim(string: str, length: int = 70) -> str:
3537
return (string[: length - 1] + '...') if len(string) > length else string
3638

3739

40+
def humanize_date(value: str) -> str:
41+
"""Format an API timestamp as a relative date, assuming UTC if naive."""
42+
date = datetime.datetime.fromisoformat(value)
43+
if date.tzinfo is None:
44+
date = date.replace(tzinfo=datetime.UTC)
45+
return humanize.naturaltime(datetime.datetime.now(datetime.UTC) - date)
46+
47+
3848
def git_config(value: str) -> str:
3949
"""Parse config from ``git-config`` cache.
4050

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ readme = {file = "README.rst", content-type = "text/x-rst"}
1212
license = "MIT"
1313
dynamic = ["version"]
1414
dependencies = [
15-
"arrow>=0.10",
1615
"click>=8.0",
16+
"humanize>=4.0",
1717
"PyYAML>=5.1",
1818
"requests>=2.0",
1919
"tabulate>=0.8",

‎tests/test_utils.py‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,38 @@
11
"""Unit tests for ``git_pw/utils.py``."""
22

3+
import datetime
34
import subprocess
45
import textwrap
56
import os
67

8+
import pytest
79
import yaml
810
from unittest import mock
911

1012
from git_pw import utils
1113

1214

15+
@pytest.mark.parametrize(
16+
'value',
17+
[
18+
'2026-01-02 10:00:00',
19+
'2026-01-02T10:00:00Z',
20+
'2026-01-02T12:00:00+02:00',
21+
],
22+
)
23+
@mock.patch.object(utils.humanize, 'naturaltime')
24+
def test_humanize_date(mock_naturaltime, value):
25+
now = datetime.datetime(2026, 1, 2, 12, tzinfo=datetime.UTC)
26+
with mock.patch.object(utils, 'datetime', wraps=datetime) as mock_datetime:
27+
mock_datetime.UTC = datetime.UTC
28+
mock_datetime.datetime.now.return_value = now
29+
30+
assert utils.humanize_date(value) == mock_naturaltime.return_value
31+
mock_datetime.datetime.now.assert_called_once_with(datetime.UTC)
32+
33+
mock_naturaltime.assert_called_once_with(datetime.timedelta(hours=2))
34+
35+
1336
@mock.patch.object(utils.subprocess, 'check_output', return_value=b' bar ')
1437
def test_git_config(mock_subprocess):
1538
value = utils.git_config('foo')

0 commit comments

Comments
 (0)