Compare commits

..

2 Commits

Author SHA1 Message Date
Clemens Schwaighofer
0e6331fa6a v0.33.0: datetime parsing update 2025-11-06 13:26:07 +09:00
Clemens Schwaighofer
c98c5df63c Update datetime parse helper
Allow non T in isotime format, add non T normal datetime parsing
2025-11-06 13:24:27 +09:00
6 changed files with 62 additions and 10 deletions

View File

@@ -52,7 +52,7 @@ Have the following setup in `project.toml`
```toml ```toml
[[tool.uv.index]] [[tool.uv.index]]
name = "egra-gitea" name = "opj-pypi"
url = "https://git.egplusww.jp/api/packages/PyPI/pypi/simple/" url = "https://git.egplusww.jp/api/packages/PyPI/pypi/simple/"
publish-url = "https://git.egplusww.jp/api/packages/PyPI/pypi" publish-url = "https://git.egplusww.jp/api/packages/PyPI/pypi"
explicit = true explicit = true
@@ -60,15 +60,15 @@ explicit = true
```sh ```sh
uv build uv build
uv publish --index egra-gitea --token <gitea token> uv publish --index opj-pypi --token <gitea token>
``` ```
## Test package ## Use package
We must set the full index URL here because we run with "--no-project" We must set the full index URL here because we run with "--no-project"
```sh ```sh
uv run --with corelibs --index egra-gitea=https://git.egplusww.jp/api/packages/PyPI/pypi/simple/ --no-project -- python -c "import corelibs" uv run --with corelibs --index opj-pypi=https://git.egplusww.jp/api/packages/PyPI/pypi/simple/ --no-project -- python -c "import corelibs"
``` ```
### Python tests ### Python tests
@@ -101,7 +101,7 @@ uv run test-run/<script>
This will also add the index entry This will also add the index entry
```sh ```sh
uv add corelibs --index egra-gitea=https://git.egplusww.jp/api/packages/PyPI/pypi/simple/ uv add corelibs --index opj-pypi=https://git.egplusww.jp/api/packages/PyPI/pypi/simple/
``` ```
## Python venv setup ## Python venv setup

View File

@@ -1,7 +1,7 @@
# MARK: Project info # MARK: Project info
[project] [project]
name = "corelibs" name = "corelibs"
version = "0.32.0" version = "0.33.0"
description = "Collection of utils for Python scripts" description = "Collection of utils for Python scripts"
readme = "README.md" readme = "README.md"
requires-python = ">=3.13" requires-python = ">=3.13"
@@ -17,7 +17,7 @@ dependencies = [
# MARK: build target # MARK: build target
[[tool.uv.index]] [[tool.uv.index]]
name = "egra-gitea" name = "opj-pypi"
url = "https://git.egplusww.jp/api/packages/PyPI/pypi/simple/" url = "https://git.egplusww.jp/api/packages/PyPI/pypi/simple/"
publish-url = "https://git.egplusww.jp/api/packages/PyPI/pypi" publish-url = "https://git.egplusww.jp/api/packages/PyPI/pypi"
explicit = true explicit = true
@@ -63,12 +63,13 @@ ignore = [
[tool.pylint.MASTER] [tool.pylint.MASTER]
# this is for the tests/etc folders # this is for the tests/etc folders
init-hook='import sys; sys.path.append("src/")' init-hook='import sys; sys.path.append("src/")'
# MARK: Testing
[tool.pytest.ini_options] [tool.pytest.ini_options]
testpaths = [ testpaths = [
"tests", "tests",
] ]
[tool.coverage.run] [tool.coverage.run]
omit = [ omit = [
"*/tests/*", "*/tests/*",

View File

@@ -159,10 +159,14 @@ def parse_flexible_date(
# Try different parsing methods # Try different parsing methods
parsers: list[Callable[[str], datetime]] = [ parsers: list[Callable[[str], datetime]] = [
# ISO 8601 format # ISO 8601 format, also with missing "T"
lambda x: datetime.fromisoformat(x), # pylint: disable=W0108 lambda x: datetime.fromisoformat(x), # pylint: disable=W0108
lambda x: datetime.fromisoformat(x.replace(' ', 'T')), # pylint: disable=W0108
# Simple date format # Simple date format
lambda x: datetime.strptime(x, "%Y-%m-%d"), lambda x: datetime.strptime(x, "%Y-%m-%d"),
# datetime without T
lambda x: datetime.strptime(x, "%Y-%m-%d %H:%M:%S"),
lambda x: datetime.strptime(x, "%Y-%m-%d %H:%M:%S.%f"),
# Alternative ISO formats (fallback) # Alternative ISO formats (fallback)
lambda x: datetime.strptime(x, "%Y-%m-%dT%H:%M:%S"), lambda x: datetime.strptime(x, "%Y-%m-%dT%H:%M:%S"),
lambda x: datetime.strptime(x, "%Y-%m-%dT%H:%M:%S.%f"), lambda x: datetime.strptime(x, "%Y-%m-%dT%H:%M:%S.%f"),

View File

View File

@@ -275,6 +275,53 @@ class TestParseFlexibleDate:
assert isinstance(result, datetime) assert isinstance(result, datetime)
assert result.tzinfo is not None assert result.tzinfo is not None
def test_parse_flexible_date_missing_t_with_timezone_shift(self):
"""Test parse_flexible_date with timezone shift"""
result = parse_flexible_date('2023-12-25 15:30:45+00:00', timezone_tz='Asia/Tokyo', shift_time_zone=True)
assert isinstance(result, datetime)
assert result.tzinfo is not None
def test_parse_flexible_date_space_separated_datetime(self):
"""Test parse_flexible_date with space-separated datetime format"""
result = parse_flexible_date('2023-12-25 15:30:45')
assert isinstance(result, datetime)
assert result.year == 2023
assert result.month == 12
assert result.day == 25
assert result.hour == 15
assert result.minute == 30
assert result.second == 45
def test_parse_flexible_date_space_separated_with_microseconds(self):
"""Test parse_flexible_date with space-separated datetime and microseconds"""
result = parse_flexible_date('2023-12-25 15:30:45.123456')
assert isinstance(result, datetime)
assert result.year == 2023
assert result.month == 12
assert result.day == 25
assert result.hour == 15
assert result.minute == 30
assert result.second == 45
assert result.microsecond == 123456
def test_parse_flexible_date_t_separated_datetime(self):
"""Test parse_flexible_date with T-separated datetime (alternative ISO format)"""
result = parse_flexible_date('2023-12-25T15:30:45')
assert isinstance(result, datetime)
assert result.year == 2023
assert result.month == 12
assert result.day == 25
assert result.hour == 15
assert result.minute == 30
assert result.second == 45
def test_parse_flexible_date_t_separated_with_microseconds(self):
"""Test parse_flexible_date with T-separated datetime and microseconds"""
result = parse_flexible_date('2023-12-25T15:30:45.123456')
assert isinstance(result, datetime)
assert result.year == 2023
assert result.microsecond == 123456
def test_parse_flexible_date_invalid_format(self): def test_parse_flexible_date_invalid_format(self):
"""Test parse_flexible_date with invalid format returns None""" """Test parse_flexible_date with invalid format returns None"""
result = parse_flexible_date('invalid-date') result = parse_flexible_date('invalid-date')

2
uv.lock generated
View File

@@ -108,7 +108,7 @@ wheels = [
[[package]] [[package]]
name = "corelibs" name = "corelibs"
version = "0.32.0" version = "0.33.0"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "cryptography" }, { name = "cryptography" },