1
0
Fork 0

Merging upstream version 2.4.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-03-12 11:11:12 +01:00
parent 5539cbc19b
commit 5f801f685c
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
7 changed files with 120 additions and 4 deletions

41
.github/workflows/codeql.yml vendored Normal file
View file

@ -0,0 +1,41 @@
name: "CodeQL"
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
schedule:
- cron: "36 4 * * 1"
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ python ]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{ matrix.language }}"

1
.gitignore vendored
View file

@ -11,3 +11,4 @@ __pycache__
/cli_helpers_dev
.idea/
.cache/
.vscode/

View file

@ -25,6 +25,7 @@ This project receives help from these awesome contributors:
- Mel Dafert
- Andrii Kohut
- Roland Walker
- Doug Harris
Thanks
------

View file

@ -1,5 +1,11 @@
# Changelog
## Version 2.4.0
(released on 2025-03-10)
- Added format_timestamps preprocessor for per-column date/time formatting.
## Version 2.3.1
- Don't escape newlines in `ascii` tables, and add `ascii_escaped` table format.

View file

@ -1 +1 @@
__version__ = "2.3.1"
__version__ = "2.4.0"

View file

@ -2,6 +2,7 @@
"""These preprocessor functions are used to process data prior to output."""
import string
from datetime import datetime
from cli_helpers import utils
from cli_helpers.compat import text_type, int_types, float_types, HAS_PYGMENTS, Token
@ -125,9 +126,11 @@ def escape_newlines(data, headers, **_):
return (
(
[
v.replace("\r", r"\r").replace("\n", r"\n")
if isinstance(v, text_type)
else v
(
v.replace("\r", r"\r").replace("\n", r"\n")
if isinstance(v, text_type)
else v
)
for v in row
]
for row in data
@ -351,3 +354,44 @@ def format_numbers(
[_format_number(v, column_types[i]) for i, v in enumerate(row)] for row in data
)
return data, headers
def format_timestamps(data, headers, column_date_formats=None, **_):
"""Format timestamps according to user preference.
This allows for per-column formatting for date, time, or datetime like data.
Add a `column_date_formats` section to your config file with separate lines for each column
that you'd like to specify a format using `name=format`. Use standard Python strftime
formatting strings
Example: `signup_date = "%Y-%m-%d"`
:param iterable data: An :term:`iterable` (e.g. list) of rows.
:param iterable headers: The column headers.
:param str column_date_format: The format strings to use for specific columns.
:return: The processed data and headers.
:rtype: tuple
"""
if column_date_formats is None:
return iter(data), headers
def _format_timestamp(value, name, column_date_formats):
if name not in column_date_formats:
return value
try:
dt = datetime.fromisoformat(value)
return dt.strftime(column_date_formats[name])
except (ValueError, TypeError):
# not a date
return value
data = (
[
_format_timestamp(v, headers[i], column_date_formats)
for i, v in enumerate(row)
]
for row in data
)
return data, headers

View file

@ -16,6 +16,7 @@ from cli_helpers.tabular_output.preprocessors import (
override_tab_value,
style_output,
format_numbers,
format_timestamps,
)
if HAS_PYGMENTS:
@ -348,3 +349,25 @@ def test_enforce_iterable():
assert False, "{} doesn't return iterable".format(name)
if isinstance(preprocessed[1], types.GeneratorType):
assert False, "{} returns headers as iterator".format(name)
def test_format_timestamps():
data = (
("name1", "2024-12-13T18:32:22", "2024-12-13T19:32:22", "2024-12-13T20:32:22"),
("name2", "2025-02-13T02:32:22", "2025-02-13T02:32:22", "2025-02-13T02:32:22"),
("name3", None, "not-actually-timestamp", "2025-02-13T02:32:22"),
)
headers = ["name", "date_col", "datetime_col", "unchanged_col"]
column_date_formats = {
"date_col": "%Y-%m-%d",
"datetime_col": "%I:%M:%S %m/%d/%y",
}
result_data, result_headers = format_timestamps(data, headers, column_date_formats)
expected = [
["name1", "2024-12-13", "07:32:22 12/13/24", "2024-12-13T20:32:22"],
["name2", "2025-02-13", "02:32:22 02/13/25", "2025-02-13T02:32:22"],
["name3", None, "not-actually-timestamp", "2025-02-13T02:32:22"],
]
assert expected == list(result_data)
assert headers == result_headers