edq-utils 0.0.1__py3-none-any.whl → 0.0.3__py3-none-any.whl
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.
Potentially problematic release.
This version of edq-utils might be problematic. Click here for more details.
- edq/__init__.py +5 -1
- edq/py.typed +0 -0
- edq/testing/__init__.py +3 -0
- edq/testing/run.py +112 -0
- edq/testing/unittest.py +54 -0
- edq/util/__init__.py +3 -0
- edq/util/dirent.py +228 -44
- edq/util/dirent_test.py +823 -25
- edq/util/json.py +163 -0
- edq/util/json_test.py +228 -0
- edq/util/pyimport.py +73 -0
- edq/util/pyimport_test.py +83 -0
- edq/util/reflection.py +32 -0
- edq/util/testdata/dirent-operations/symlink_file_empty +0 -0
- edq/util/time.py +75 -0
- edq/util/time_test.py +107 -0
- {edq_utils-0.0.1.dist-info → edq_utils-0.0.3.dist-info}/METADATA +3 -1
- edq_utils-0.0.3.dist-info/RECORD +28 -0
- edq_utils-0.0.1.dist-info/RECORD +0 -16
- /edq/util/testdata/dirent-operations/{symlinklink_a.txt → symlink_a.txt} +0 -0
- /edq/util/testdata/dirent-operations/{symlinklink_dir_1 → symlink_dir_1}/b.txt +0 -0
- /edq/util/testdata/dirent-operations/{symlinklink_dir_1 → symlink_dir_1}/dir_2/c.txt +0 -0
- {edq_utils-0.0.1.dist-info → edq_utils-0.0.3.dist-info}/WHEEL +0 -0
- {edq_utils-0.0.1.dist-info → edq_utils-0.0.3.dist-info}/licenses/LICENSE +0 -0
- {edq_utils-0.0.1.dist-info → edq_utils-0.0.3.dist-info}/top_level.txt +0 -0
edq/util/time_test.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import datetime
|
|
3
|
+
|
|
4
|
+
import edq.testing.unittest
|
|
5
|
+
import edq.util.time
|
|
6
|
+
|
|
7
|
+
TIMEZONE_UTC: datetime.timezone = datetime.timezone.utc
|
|
8
|
+
TIMEZONE_PST: datetime.timezone = datetime.timezone(datetime.timedelta(hours = -7), name = 'PST')
|
|
9
|
+
TIMEZONE_CEST: datetime.timezone = datetime.timezone(datetime.timedelta(hours = 2), name = 'CEST')
|
|
10
|
+
|
|
11
|
+
class TestTime(edq.testing.unittest.BaseTest):
|
|
12
|
+
""" Test time-based operations. """
|
|
13
|
+
|
|
14
|
+
def test_timestamp_now(self):
|
|
15
|
+
""" Test getting a timestamp for the current moment. """
|
|
16
|
+
|
|
17
|
+
start = edq.util.time.Timestamp.now()
|
|
18
|
+
time.sleep(0.01)
|
|
19
|
+
middle = edq.util.time.Timestamp.now()
|
|
20
|
+
time.sleep(0.01)
|
|
21
|
+
end = edq.util.time.Timestamp.now()
|
|
22
|
+
|
|
23
|
+
self.assertLessEqual(start, middle)
|
|
24
|
+
self.assertLessEqual(middle, end)
|
|
25
|
+
|
|
26
|
+
def test_timestamp_pytime_conversion(self):
|
|
27
|
+
""" Test converting between timestamps and Python datetimes. """
|
|
28
|
+
|
|
29
|
+
# [(timestamp, python time), ...]
|
|
30
|
+
test_cases = [
|
|
31
|
+
(edq.util.time.Timestamp(0), datetime.datetime(1970, 1, 1, 0, 0, 0, 0, TIMEZONE_UTC)),
|
|
32
|
+
|
|
33
|
+
(edq.util.time.Timestamp(1755139534019), datetime.datetime(2025, 8, 14, 2, 45, 34, 19000, TIMEZONE_UTC)),
|
|
34
|
+
(edq.util.time.Timestamp(1755139534019), datetime.datetime(2025, 8, 13, 19, 45, 34, 19000, TIMEZONE_PST)),
|
|
35
|
+
(edq.util.time.Timestamp(1755139534019), datetime.datetime(2025, 8, 14, 4, 45, 34, 19000, TIMEZONE_CEST)),
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
for (i, test_case) in enumerate(test_cases):
|
|
39
|
+
(timestamp, pytime) = test_case
|
|
40
|
+
|
|
41
|
+
with self.subTest(msg = f"Case {i} ('{timestamp}' == '{pytime}'):"):
|
|
42
|
+
convert_pytime = timestamp.to_pytime(pytime.tzinfo)
|
|
43
|
+
self.assertEqual(pytime, convert_pytime, 'pytime')
|
|
44
|
+
|
|
45
|
+
convert_timestamp = edq.util.time.Timestamp.from_pytime(pytime)
|
|
46
|
+
self.assertEqual(timestamp, convert_timestamp, 'timestamp')
|
|
47
|
+
|
|
48
|
+
# Check other time zones.
|
|
49
|
+
# Use string comparisons to ensure the timezone is compared (and not just the UTC time).
|
|
50
|
+
timezones = [
|
|
51
|
+
TIMEZONE_UTC,
|
|
52
|
+
TIMEZONE_PST,
|
|
53
|
+
TIMEZONE_CEST,
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
for timezone in timezones:
|
|
57
|
+
pytime_pst = pytime.astimezone(timezone).isoformat(timespec = 'milliseconds')
|
|
58
|
+
convert_pytime_pst = timestamp.to_pytime(timezone).isoformat(timespec = 'milliseconds')
|
|
59
|
+
self.assertEqual(pytime_pst, convert_pytime_pst, f"pytime {timezone}")
|
|
60
|
+
|
|
61
|
+
def test_timestamp_pretty(self):
|
|
62
|
+
""" Test the "pretty" representations of timestamps. """
|
|
63
|
+
|
|
64
|
+
# [(timestamp, timezone, pretty short, pretty long), ...]
|
|
65
|
+
test_cases = [
|
|
66
|
+
(edq.util.time.Timestamp(0), TIMEZONE_UTC, "1970-01-01 00:00", "1970-01-01T00:00:00.000+00:00"),
|
|
67
|
+
|
|
68
|
+
(edq.util.time.Timestamp(1755139534019), TIMEZONE_UTC, "2025-08-14 02:45", "2025-08-14T02:45:34.019+00:00"),
|
|
69
|
+
(edq.util.time.Timestamp(1755139534019), TIMEZONE_PST, "2025-08-13 19:45", "2025-08-13T19:45:34.019-07:00"),
|
|
70
|
+
(edq.util.time.Timestamp(1755139534019), TIMEZONE_CEST, "2025-08-14 04:45", "2025-08-14T04:45:34.019+02:00"),
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
for (i, test_case) in enumerate(test_cases):
|
|
74
|
+
(timestamp, timezone, expected_pretty_short, expected_pretty_long) = test_case
|
|
75
|
+
|
|
76
|
+
with self.subTest(msg = f"Case {i} ('{timestamp}'):"):
|
|
77
|
+
actual_pretty_short = timestamp.pretty(short = True, timezone = timezone)
|
|
78
|
+
actual_pretty_long = timestamp.pretty(short = False, timezone = timezone)
|
|
79
|
+
|
|
80
|
+
self.assertEqual(expected_pretty_short, actual_pretty_short, 'short')
|
|
81
|
+
self.assertEqual(expected_pretty_long, actual_pretty_long, 'long')
|
|
82
|
+
|
|
83
|
+
def test_timestamp_sub(self):
|
|
84
|
+
""" Test subtracting timestamps. """
|
|
85
|
+
|
|
86
|
+
# [(a, b, expected), ...]
|
|
87
|
+
# All values in this structure will be in ints and converted later.
|
|
88
|
+
test_cases = [
|
|
89
|
+
(0, 0, 0),
|
|
90
|
+
(0, 1, -1),
|
|
91
|
+
(1, 0, 1),
|
|
92
|
+
|
|
93
|
+
(100, 100, 0),
|
|
94
|
+
(100, 101, -1),
|
|
95
|
+
(101, 100, 1),
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
for (i, test_case) in enumerate(test_cases):
|
|
99
|
+
(raw_a, raw_b, raw_expected) = test_case
|
|
100
|
+
|
|
101
|
+
with self.subTest(msg = f"Case {i} ({raw_a} - {raw_b}):"):
|
|
102
|
+
a = edq.util.time.Timestamp(raw_a)
|
|
103
|
+
b = edq.util.time.Timestamp(raw_b)
|
|
104
|
+
expected = edq.util.time.Duration(raw_expected)
|
|
105
|
+
|
|
106
|
+
actual = a - b
|
|
107
|
+
self.assertEqual(expected, actual)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: edq-utils
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
4
4
|
Summary: Common utilities used by EduLinq Python projects.
|
|
5
5
|
Author-email: Eriq Augustine <eriq@edulinq.org>
|
|
6
6
|
License: MIT License
|
|
@@ -34,8 +34,10 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
34
34
|
Requires-Python: >=3.8
|
|
35
35
|
Description-Content-Type: text/markdown
|
|
36
36
|
License-File: LICENSE
|
|
37
|
+
Requires-Dist: json5>=0.9.14
|
|
37
38
|
Provides-Extra: dev
|
|
38
39
|
Requires-Dist: mypy>=1.14.1; extra == "dev"
|
|
40
|
+
Requires-Dist: pdoc>=14.7.0; extra == "dev"
|
|
39
41
|
Requires-Dist: pylint; extra == "dev"
|
|
40
42
|
Requires-Dist: twine; extra == "dev"
|
|
41
43
|
Requires-Dist: vermin; extra == "dev"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
edq/__init__.py,sha256=SgI3o5Z-z1KSX-sg-2ZL2vhNQ-KiMte0ewCvjQv8wWA,86
|
|
2
|
+
edq/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
edq/testing/__init__.py,sha256=IKd3fPU_8d_jP19HxG-zKwxFwn7nqFGGtXOY5slY41c,32
|
|
4
|
+
edq/testing/run.py,sha256=qnqGCEwZP-hY87X99EJw2xoMaTF8QeOf7Lx8JI7oM_4,3843
|
|
5
|
+
edq/testing/unittest.py,sha256=J_sUYGIdP8HDQioQtUPF_H4n2aKf0_XHLdhzs59fvck,1665
|
|
6
|
+
edq/util/__init__.py,sha256=9EFKQE77S-B6OJJKFaMg8k3WkMMUQYlGjlTv6tQmWVo,29
|
|
7
|
+
edq/util/dirent.py,sha256=C-ZTVbOVBlEc71g4l8rMO5EJHv4Lcl9-FH0Kp1B3oc8,10314
|
|
8
|
+
edq/util/dirent_test.py,sha256=oXpAaEhOkEr0zw0fdAPypx7QH1aFbY2Hpox-9OpZjhs,33380
|
|
9
|
+
edq/util/json.py,sha256=p74F5OCxbRv4mvMSkRdy-fYVqAETx5_65IEhesTH8SM,5228
|
|
10
|
+
edq/util/json_test.py,sha256=utUVRbw3z42ke4fpRVI294RrFHcMKms8khVYRkISNk4,8009
|
|
11
|
+
edq/util/pyimport.py,sha256=M1j58vg4b6gTg92Cz5-bns3eQCCIMKDApBclP-iR620,2198
|
|
12
|
+
edq/util/pyimport_test.py,sha256=wuTR5pzVZanWDA2FuVc-Pxyo_GwkGGfFf_qyK6LNQRs,2851
|
|
13
|
+
edq/util/reflection.py,sha256=jPcW6h0fwSDYh04O5rUxlgoF7HK6fVQ2mq7DD9qPrEg,972
|
|
14
|
+
edq/util/time.py,sha256=anoNM_KniARLombv2BnsoHuCzDqMKiDdIzV7RUe2ZOk,2648
|
|
15
|
+
edq/util/time_test.py,sha256=iQZwzVTVQQ4TdXrLb9MUMCYlKrIe8qyF-hiC9YLTaMo,4610
|
|
16
|
+
edq/util/testdata/dirent-operations/a.txt,sha256=h0KPxSKAPTEGXnvOPPA_5HUJZjHl4Hu9eg_eYMTPJcc,2
|
|
17
|
+
edq/util/testdata/dirent-operations/file_empty,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
+
edq/util/testdata/dirent-operations/symlink_a.txt,sha256=h0KPxSKAPTEGXnvOPPA_5HUJZjHl4Hu9eg_eYMTPJcc,2
|
|
19
|
+
edq/util/testdata/dirent-operations/symlink_file_empty,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
edq/util/testdata/dirent-operations/dir_1/b.txt,sha256=AmOCmYm2_ZVPcrqvL8ZLwuLwHWktTecphuqAj26ZgT8,2
|
|
21
|
+
edq/util/testdata/dirent-operations/dir_1/dir_2/c.txt,sha256=o6XnFfDMV0pzw_m-u2vCTzL_1bZ7OHJEwskJ2neaFHg,2
|
|
22
|
+
edq/util/testdata/dirent-operations/symlink_dir_1/b.txt,sha256=AmOCmYm2_ZVPcrqvL8ZLwuLwHWktTecphuqAj26ZgT8,2
|
|
23
|
+
edq/util/testdata/dirent-operations/symlink_dir_1/dir_2/c.txt,sha256=o6XnFfDMV0pzw_m-u2vCTzL_1bZ7OHJEwskJ2neaFHg,2
|
|
24
|
+
edq_utils-0.0.3.dist-info/licenses/LICENSE,sha256=MS4iYEl4rOxMoprZuc86iYVoyk4YgaVoMt7WmGvVF8w,1064
|
|
25
|
+
edq_utils-0.0.3.dist-info/METADATA,sha256=YoOLw86gdPLaSAy_z9UfftRk83wxjjM-nD7r8H2FsEg,2471
|
|
26
|
+
edq_utils-0.0.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
27
|
+
edq_utils-0.0.3.dist-info/top_level.txt,sha256=znBHSj6tgXtcMKrUVtovLli5fIEJCb7d-BMxTLRK4zk,4
|
|
28
|
+
edq_utils-0.0.3.dist-info/RECORD,,
|
edq_utils-0.0.1.dist-info/RECORD
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
edq/__init__.py,sha256=DsAHdxLC16H2VjdFOU5tBx2xT9VnNQ-XbTS24fRCa_w,22
|
|
2
|
-
edq/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
edq/util/dirent.py,sha256=Dr4OtB9TvJmiGLrjdiSmsh5Fk8G49jfklh4wdOx13ro,4436
|
|
4
|
-
edq/util/dirent_test.py,sha256=FBMHEmcrfR7VILBzgy1cMWrFEp9wNQ5RNbL5vOdezT4,5998
|
|
5
|
-
edq/util/testdata/dirent-operations/a.txt,sha256=h0KPxSKAPTEGXnvOPPA_5HUJZjHl4Hu9eg_eYMTPJcc,2
|
|
6
|
-
edq/util/testdata/dirent-operations/file_empty,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
-
edq/util/testdata/dirent-operations/symlinklink_a.txt,sha256=h0KPxSKAPTEGXnvOPPA_5HUJZjHl4Hu9eg_eYMTPJcc,2
|
|
8
|
-
edq/util/testdata/dirent-operations/dir_1/b.txt,sha256=AmOCmYm2_ZVPcrqvL8ZLwuLwHWktTecphuqAj26ZgT8,2
|
|
9
|
-
edq/util/testdata/dirent-operations/dir_1/dir_2/c.txt,sha256=o6XnFfDMV0pzw_m-u2vCTzL_1bZ7OHJEwskJ2neaFHg,2
|
|
10
|
-
edq/util/testdata/dirent-operations/symlinklink_dir_1/b.txt,sha256=AmOCmYm2_ZVPcrqvL8ZLwuLwHWktTecphuqAj26ZgT8,2
|
|
11
|
-
edq/util/testdata/dirent-operations/symlinklink_dir_1/dir_2/c.txt,sha256=o6XnFfDMV0pzw_m-u2vCTzL_1bZ7OHJEwskJ2neaFHg,2
|
|
12
|
-
edq_utils-0.0.1.dist-info/licenses/LICENSE,sha256=MS4iYEl4rOxMoprZuc86iYVoyk4YgaVoMt7WmGvVF8w,1064
|
|
13
|
-
edq_utils-0.0.1.dist-info/METADATA,sha256=Q99RoHQkHjWZEkP-gEdtEaEPE1xoauWVtUXWsE3OlmM,2398
|
|
14
|
-
edq_utils-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
15
|
-
edq_utils-0.0.1.dist-info/top_level.txt,sha256=znBHSj6tgXtcMKrUVtovLli5fIEJCb7d-BMxTLRK4zk,4
|
|
16
|
-
edq_utils-0.0.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|