mm-std 0.7.0__tar.gz → 0.7.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mm_std-0.7.0 → mm_std-0.7.1}/.claude/settings.local.json +2 -1
- {mm_std-0.7.0 → mm_std-0.7.1}/PKG-INFO +1 -1
- {mm_std-0.7.0 → mm_std-0.7.1}/README.md +4 -4
- {mm_std-0.7.0 → mm_std-0.7.1}/pyproject.toml +7 -2
- {mm_std-0.7.0 → mm_std-0.7.1}/src/mm_std/__init__.py +1 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/src/mm_std/date_utils.py +11 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/src/mm_std/dict_utils.py +1 -1
- {mm_std-0.7.0 → mm_std-0.7.1}/tests/mm_std/test_date_utils.py +53 -1
- {mm_std-0.7.0 → mm_std-0.7.1}/uv.lock +22 -22
- {mm_std-0.7.0 → mm_std-0.7.1}/.gitignore +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/.pre-commit-config.yaml +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/CLAUDE.md +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/justfile +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/src/mm_std/json_utils.py +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/src/mm_std/py.typed +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/src/mm_std/random_utils.py +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/src/mm_std/str_utils.py +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/src/mm_std/subprocess_utils.py +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/tests/__init__.py +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/tests/mm_std/__init__.py +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/tests/mm_std/test_dict_utils.py +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/tests/mm_std/test_json_utils.py +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/tests/mm_std/test_random_utils.py +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/tests/mm_std/test_str_utils.py +0 -0
- {mm_std-0.7.0 → mm_std-0.7.1}/tests/mm_std/test_subprocess_utils.py +0 -0
|
@@ -183,14 +183,14 @@ cleaned = compact_dict(
|
|
|
183
183
|
UTC-focused datetime operations:
|
|
184
184
|
|
|
185
185
|
```python
|
|
186
|
-
from mm_std import
|
|
186
|
+
from mm_std import utc, parse_datetime
|
|
187
187
|
|
|
188
188
|
# Current UTC time
|
|
189
|
-
now =
|
|
189
|
+
now = utc()
|
|
190
190
|
|
|
191
191
|
# Time calculations
|
|
192
|
-
past =
|
|
193
|
-
future =
|
|
192
|
+
past = utc(hours=-2, minutes=-30)
|
|
193
|
+
future = utc(days=7)
|
|
194
194
|
|
|
195
195
|
# Flexible date parsing
|
|
196
196
|
dates = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mm-std"
|
|
3
|
-
version = "0.7.
|
|
3
|
+
version = "0.7.1"
|
|
4
4
|
description = ""
|
|
5
5
|
requires-python = ">=3.14"
|
|
6
6
|
dependencies = []
|
|
@@ -18,7 +18,7 @@ dev = [
|
|
|
18
18
|
"pytest~=9.0.2",
|
|
19
19
|
"pytest-xdist~=3.8.0",
|
|
20
20
|
"ruff~=0.14.14",
|
|
21
|
-
"ty~=0.0.
|
|
21
|
+
"ty~=0.0.14",
|
|
22
22
|
]
|
|
23
23
|
|
|
24
24
|
[tool.mypy]
|
|
@@ -68,3 +68,8 @@ indent-style = "space"
|
|
|
68
68
|
[tool.bandit]
|
|
69
69
|
exclude_dirs = ["tests"]
|
|
70
70
|
skips = ["B311"]
|
|
71
|
+
|
|
72
|
+
[[tool.ty.overrides]]
|
|
73
|
+
include = ["src/mm_std/__init__.py", "tests/**"]
|
|
74
|
+
[tool.ty.overrides.rules]
|
|
75
|
+
deprecated = "ignore"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""mm-std: Python utilities for common data manipulation tasks."""
|
|
2
2
|
|
|
3
3
|
from .date_utils import parse_datetime as parse_datetime
|
|
4
|
+
from .date_utils import utc as utc
|
|
4
5
|
from .date_utils import utc_from_timestamp as utc_from_timestamp
|
|
5
6
|
from .date_utils import utc_now as utc_now
|
|
6
7
|
from .date_utils import utc_now_offset as utc_now_offset
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
"""UTC-focused datetime operations and flexible date parsing."""
|
|
2
2
|
|
|
3
3
|
from datetime import UTC, datetime, timedelta
|
|
4
|
+
from warnings import deprecated
|
|
4
5
|
|
|
5
6
|
|
|
7
|
+
def utc(*, days: int = 0, hours: int = 0, minutes: int = 0, seconds: int = 0) -> datetime:
|
|
8
|
+
"""Get current UTC time, optionally shifted by the specified delta.
|
|
9
|
+
|
|
10
|
+
Use negative values to get time in the past.
|
|
11
|
+
"""
|
|
12
|
+
return datetime.now(UTC) + timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@deprecated("Use utc() instead")
|
|
6
16
|
def utc_now() -> datetime:
|
|
7
17
|
"""Get current UTC time."""
|
|
8
18
|
return datetime.now(UTC)
|
|
9
19
|
|
|
10
20
|
|
|
21
|
+
@deprecated("Use utc() instead")
|
|
11
22
|
def utc_now_offset(
|
|
12
23
|
*, days: int | None = None, hours: int | None = None, minutes: int | None = None, seconds: int | None = None
|
|
13
24
|
) -> datetime:
|
|
@@ -68,7 +68,7 @@ def compact_dict(
|
|
|
68
68
|
defaults = {}
|
|
69
69
|
|
|
70
70
|
if isinstance(mapping, defaultdict):
|
|
71
|
-
result: MutableMapping[K, V] = defaultdict(mapping.default_factory)
|
|
71
|
+
result: MutableMapping[K, V] = defaultdict(mapping.default_factory) # ty: ignore[invalid-assignment]
|
|
72
72
|
else:
|
|
73
73
|
result = mapping.__class__()
|
|
74
74
|
|
|
@@ -4,7 +4,59 @@ from datetime import UTC, datetime, timedelta
|
|
|
4
4
|
|
|
5
5
|
import pytest
|
|
6
6
|
|
|
7
|
-
from mm_std import parse_datetime, utc_from_timestamp, utc_now, utc_now_offset
|
|
7
|
+
from mm_std import parse_datetime, utc, utc_from_timestamp, utc_now, utc_now_offset
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestUtc:
|
|
11
|
+
"""Tests for utc function."""
|
|
12
|
+
|
|
13
|
+
def test_returns_datetime_with_utc_timezone(self) -> None:
|
|
14
|
+
"""Result has UTC timezone info."""
|
|
15
|
+
result = utc()
|
|
16
|
+
assert result.tzinfo == UTC
|
|
17
|
+
|
|
18
|
+
def test_returns_current_time(self) -> None:
|
|
19
|
+
"""Result is close to actual current time."""
|
|
20
|
+
before = datetime.now(UTC)
|
|
21
|
+
result = utc()
|
|
22
|
+
after = datetime.now(UTC)
|
|
23
|
+
assert before <= result <= after
|
|
24
|
+
|
|
25
|
+
def test_positive_days_returns_future(self) -> None:
|
|
26
|
+
"""Positive days parameter shifts time forward."""
|
|
27
|
+
now = datetime.now(UTC)
|
|
28
|
+
result = utc(days=1)
|
|
29
|
+
assert result > now
|
|
30
|
+
assert result - now >= timedelta(days=1) - timedelta(seconds=1)
|
|
31
|
+
|
|
32
|
+
def test_negative_hours_returns_past(self) -> None:
|
|
33
|
+
"""Negative hours parameter shifts time backward."""
|
|
34
|
+
now = datetime.now(UTC)
|
|
35
|
+
result = utc(hours=-2)
|
|
36
|
+
assert result < now
|
|
37
|
+
assert now - result >= timedelta(hours=2) - timedelta(seconds=1)
|
|
38
|
+
|
|
39
|
+
def test_single_param_minutes(self) -> None:
|
|
40
|
+
"""Works with only minutes parameter."""
|
|
41
|
+
now = datetime.now(UTC)
|
|
42
|
+
result = utc(minutes=30)
|
|
43
|
+
diff = result - now
|
|
44
|
+
assert timedelta(minutes=29, seconds=59) <= diff <= timedelta(minutes=30, seconds=1)
|
|
45
|
+
|
|
46
|
+
def test_single_param_seconds(self) -> None:
|
|
47
|
+
"""Works with only seconds parameter."""
|
|
48
|
+
now = datetime.now(UTC)
|
|
49
|
+
result = utc(seconds=120)
|
|
50
|
+
diff = result - now
|
|
51
|
+
assert timedelta(seconds=119) <= diff <= timedelta(seconds=121)
|
|
52
|
+
|
|
53
|
+
def test_combined_params(self) -> None:
|
|
54
|
+
"""Works with multiple parameters combined."""
|
|
55
|
+
now = datetime.now(UTC)
|
|
56
|
+
result = utc(days=1, hours=2, minutes=30, seconds=15)
|
|
57
|
+
expected_delta = timedelta(days=1, hours=2, minutes=30, seconds=15)
|
|
58
|
+
diff = result - now
|
|
59
|
+
assert expected_delta - timedelta(seconds=1) <= diff <= expected_delta + timedelta(seconds=1)
|
|
8
60
|
|
|
9
61
|
|
|
10
62
|
class TestUtcNow:
|
|
@@ -142,7 +142,7 @@ wheels = [
|
|
|
142
142
|
|
|
143
143
|
[[package]]
|
|
144
144
|
name = "mm-std"
|
|
145
|
-
version = "0.7.
|
|
145
|
+
version = "0.7.1"
|
|
146
146
|
source = { editable = "." }
|
|
147
147
|
|
|
148
148
|
[package.dev-dependencies]
|
|
@@ -168,7 +168,7 @@ dev = [
|
|
|
168
168
|
{ name = "pytest", specifier = "~=9.0.2" },
|
|
169
169
|
{ name = "pytest-xdist", specifier = "~=3.8.0" },
|
|
170
170
|
{ name = "ruff", specifier = "~=0.14.14" },
|
|
171
|
-
{ name = "ty", specifier = "~=0.0.
|
|
171
|
+
{ name = "ty", specifier = "~=0.0.14" },
|
|
172
172
|
]
|
|
173
173
|
|
|
174
174
|
[[package]]
|
|
@@ -430,26 +430,26 @@ wheels = [
|
|
|
430
430
|
|
|
431
431
|
[[package]]
|
|
432
432
|
name = "ty"
|
|
433
|
-
version = "0.0.
|
|
434
|
-
source = { registry = "https://pypi.org/simple" }
|
|
435
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
436
|
-
wheels = [
|
|
437
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
438
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
439
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
440
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
441
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
442
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
443
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
444
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
445
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
446
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
447
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
448
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
449
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
450
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
451
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
452
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
433
|
+
version = "0.0.14"
|
|
434
|
+
source = { registry = "https://pypi.org/simple" }
|
|
435
|
+
sdist = { url = "https://files.pythonhosted.org/packages/af/57/22c3d6bf95c2229120c49ffc2f0da8d9e8823755a1c3194da56e51f1cc31/ty-0.0.14.tar.gz", hash = "sha256:a691010565f59dd7f15cf324cdcd1d9065e010c77a04f887e1ea070ba34a7de2", size = 5036573, upload-time = "2026-01-27T00:57:31.427Z" }
|
|
436
|
+
wheels = [
|
|
437
|
+
{ url = "https://files.pythonhosted.org/packages/99/cb/cc6d1d8de59beb17a41f9a614585f884ec2d95450306c173b3b7cc090d2e/ty-0.0.14-py3-none-linux_armv6l.whl", hash = "sha256:32cf2a7596e693094621d3ae568d7ee16707dce28c34d1762947874060fdddaa", size = 10034228, upload-time = "2026-01-27T00:57:53.133Z" },
|
|
438
|
+
{ url = "https://files.pythonhosted.org/packages/f3/96/dd42816a2075a8f31542296ae687483a8d047f86a6538dfba573223eaf9a/ty-0.0.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f971bf9805f49ce8c0968ad53e29624d80b970b9eb597b7cbaba25d8a18ce9a2", size = 9939162, upload-time = "2026-01-27T00:57:43.857Z" },
|
|
439
|
+
{ url = "https://files.pythonhosted.org/packages/ff/b4/73c4859004e0f0a9eead9ecb67021438b2e8e5fdd8d03e7f5aca77623992/ty-0.0.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:45448b9e4806423523268bc15e9208c4f3f2ead7c344f615549d2e2354d6e924", size = 9418661, upload-time = "2026-01-27T00:58:03.411Z" },
|
|
440
|
+
{ url = "https://files.pythonhosted.org/packages/58/35/839c4551b94613db4afa20ee555dd4f33bfa7352d5da74c5fa416ffa0fd2/ty-0.0.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee94a9b747ff40114085206bdb3205a631ef19a4d3fb89e302a88754cbbae54c", size = 9837872, upload-time = "2026-01-27T00:57:23.718Z" },
|
|
441
|
+
{ url = "https://files.pythonhosted.org/packages/41/2b/bbecf7e2faa20c04bebd35fc478668953ca50ee5847ce23e08acf20ea119/ty-0.0.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6756715a3c33182e9ab8ffca2bb314d3c99b9c410b171736e145773ee0ae41c3", size = 9848819, upload-time = "2026-01-27T00:57:58.501Z" },
|
|
442
|
+
{ url = "https://files.pythonhosted.org/packages/be/60/3c0ba0f19c0f647ad9d2b5b5ac68c0f0b4dc899001bd53b3a7537fb247a2/ty-0.0.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89d0038a2f698ba8b6fec5cf216a4e44e2f95e4a5095a8c0f57fe549f87087c2", size = 10324371, upload-time = "2026-01-27T00:57:29.291Z" },
|
|
443
|
+
{ url = "https://files.pythonhosted.org/packages/24/32/99d0a0b37d0397b0a989ffc2682493286aa3bc252b24004a6714368c2c3d/ty-0.0.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c64a83a2d669b77f50a4957039ca1450626fb474619f18f6f8a3eb885bf7544", size = 10865898, upload-time = "2026-01-27T00:57:33.542Z" },
|
|
444
|
+
{ url = "https://files.pythonhosted.org/packages/1a/88/30b583a9e0311bb474269cfa91db53350557ebec09002bfc3fb3fc364e8c/ty-0.0.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:242488bfb547ef080199f6fd81369ab9cb638a778bb161511d091ffd49c12129", size = 10555777, upload-time = "2026-01-27T00:58:05.853Z" },
|
|
445
|
+
{ url = "https://files.pythonhosted.org/packages/cd/a2/cb53fb6325dcf3d40f2b1d0457a25d55bfbae633c8e337bde8ec01a190eb/ty-0.0.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4790c3866f6c83a4f424fc7d09ebdb225c1f1131647ba8bdc6fcdc28f09ed0ff", size = 10412913, upload-time = "2026-01-27T00:57:38.834Z" },
|
|
446
|
+
{ url = "https://files.pythonhosted.org/packages/42/8f/f2f5202d725ed1e6a4e5ffaa32b190a1fe70c0b1a2503d38515da4130b4c/ty-0.0.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:950f320437f96d4ea9a2332bbfb5b68f1c1acd269ebfa4c09b6970cc1565bd9d", size = 9837608, upload-time = "2026-01-27T00:57:55.898Z" },
|
|
447
|
+
{ url = "https://files.pythonhosted.org/packages/f7/ba/59a2a0521640c489dafa2c546ae1f8465f92956fede18660653cce73b4c5/ty-0.0.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4a0ec3ee70d83887f86925bbc1c56f4628bd58a0f47f6f32ddfe04e1f05466df", size = 9884324, upload-time = "2026-01-27T00:57:46.786Z" },
|
|
448
|
+
{ url = "https://files.pythonhosted.org/packages/03/95/8d2a49880f47b638743212f011088552ecc454dd7a665ddcbdabea25772a/ty-0.0.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a1a4e6b6da0c58b34415955279eff754d6206b35af56a18bb70eb519d8d139ef", size = 10033537, upload-time = "2026-01-27T00:58:01.149Z" },
|
|
449
|
+
{ url = "https://files.pythonhosted.org/packages/e9/40/4523b36f2ce69f92ccf783855a9e0ebbbd0f0bb5cdce6211ee1737159ed3/ty-0.0.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:dc04384e874c5de4c5d743369c277c8aa73d1edea3c7fc646b2064b637db4db3", size = 10495910, upload-time = "2026-01-27T00:57:26.691Z" },
|
|
450
|
+
{ url = "https://files.pythonhosted.org/packages/08/d5/655beb51224d1bfd4f9ddc0bb209659bfe71ff141bcf05c418ab670698f0/ty-0.0.14-py3-none-win32.whl", hash = "sha256:b20e22cf54c66b3e37e87377635da412d9a552c9bf4ad9fc449fed8b2e19dad2", size = 9507626, upload-time = "2026-01-27T00:57:41.43Z" },
|
|
451
|
+
{ url = "https://files.pythonhosted.org/packages/b6/d9/c569c9961760e20e0a4bc008eeb1415754564304fd53997a371b7cf3f864/ty-0.0.14-py3-none-win_amd64.whl", hash = "sha256:e312ff9475522d1a33186657fe74d1ec98e4a13e016d66f5758a452c90ff6409", size = 10437980, upload-time = "2026-01-27T00:57:36.422Z" },
|
|
452
|
+
{ url = "https://files.pythonhosted.org/packages/ad/0c/186829654f5bfd9a028f6648e9caeb11271960a61de97484627d24443f91/ty-0.0.14-py3-none-win_arm64.whl", hash = "sha256:b6facdbe9b740cb2c15293a1d178e22ffc600653646452632541d01c36d5e378", size = 9885831, upload-time = "2026-01-27T00:57:49.747Z" },
|
|
453
453
|
]
|
|
454
454
|
|
|
455
455
|
[[package]]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|