python-ulid 2.6.0__tar.gz → 2.7.0__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.
Files changed (27) hide show
  1. {python_ulid-2.6.0 → python_ulid-2.7.0}/CHANGELOG.rst +11 -3
  2. {python_ulid-2.6.0 → python_ulid-2.7.0}/PKG-INFO +1 -1
  3. {python_ulid-2.6.0 → python_ulid-2.7.0}/tests/test_base32.py +1 -0
  4. {python_ulid-2.6.0 → python_ulid-2.7.0}/tests/test_ulid.py +31 -0
  5. {python_ulid-2.6.0 → python_ulid-2.7.0}/ulid/__init__.py +2 -8
  6. {python_ulid-2.6.0 → python_ulid-2.7.0}/ulid/base32.py +3 -0
  7. {python_ulid-2.6.0 → python_ulid-2.7.0}/.github/workflows/lint-and-test.yml +0 -0
  8. {python_ulid-2.6.0 → python_ulid-2.7.0}/.github/workflows/publish.yml +0 -0
  9. {python_ulid-2.6.0 → python_ulid-2.7.0}/.gitignore +0 -0
  10. {python_ulid-2.6.0 → python_ulid-2.7.0}/.pre-commit-config.yaml +0 -0
  11. {python_ulid-2.6.0 → python_ulid-2.7.0}/.readthedocs.yml +0 -0
  12. {python_ulid-2.6.0 → python_ulid-2.7.0}/LICENSE +0 -0
  13. {python_ulid-2.6.0 → python_ulid-2.7.0}/README.rst +0 -0
  14. {python_ulid-2.6.0 → python_ulid-2.7.0}/docs/Makefile +0 -0
  15. {python_ulid-2.6.0 → python_ulid-2.7.0}/docs/requirements.txt +0 -0
  16. {python_ulid-2.6.0 → python_ulid-2.7.0}/docs/source/api.rst +0 -0
  17. {python_ulid-2.6.0 → python_ulid-2.7.0}/docs/source/changelog.rst +0 -0
  18. {python_ulid-2.6.0 → python_ulid-2.7.0}/docs/source/conf.py +0 -0
  19. {python_ulid-2.6.0 → python_ulid-2.7.0}/docs/source/index.rst +0 -0
  20. {python_ulid-2.6.0 → python_ulid-2.7.0}/hatch.toml +0 -0
  21. {python_ulid-2.6.0 → python_ulid-2.7.0}/logo.png +0 -0
  22. {python_ulid-2.6.0 → python_ulid-2.7.0}/pyproject.toml +0 -0
  23. {python_ulid-2.6.0 → python_ulid-2.7.0}/tests/__init__.py +0 -0
  24. {python_ulid-2.6.0 → python_ulid-2.7.0}/tests/test_cli.py +0 -0
  25. {python_ulid-2.6.0 → python_ulid-2.7.0}/ulid/__main__.py +0 -0
  26. {python_ulid-2.6.0 → python_ulid-2.7.0}/ulid/constants.py +0 -0
  27. {python_ulid-2.6.0 → python_ulid-2.7.0}/ulid/py.typed +0 -0
@@ -5,13 +5,20 @@ Changelog
5
5
 
6
6
  Versions follow `Semantic Versioning <http://www.semver.org>`_
7
7
 
8
+ `2.7.0`_ - 2024-06-17
9
+ ---------------------
10
+ Changed
11
+ ~~~~~~~
12
+ * Ensure that the validation of ULID's timestamp component aligns more closely with
13
+ the ULID specification.
14
+
8
15
  `2.6.0`_ - 2024-05-26
9
16
  ---------------------
10
17
  Changed
11
18
  ~~~~~~~
12
- * Provide more sophisticated validation when creating ``ULID``s from user input. When using
13
- ``ULID.from_str`` we will check if the characters match the base32 alphabet. In general, it is
14
- ensured that the timestamp part of the ULID is not out of range.
19
+ * Use stricter validation when a :class:`.ULID` value from user input. When using
20
+ :meth:`.ULID.from_str` we will check if the characters match the base32 alphabet. In general,
21
+ it is ensured that the timestamp part of the ULID is not out of range.
15
22
 
16
23
  `2.5.0`_ - 2024-04-26
17
24
  ---------------------
@@ -167,6 +174,7 @@ Changed
167
174
  * The package now has no external dependencies.
168
175
  * The test-coverage has been raised to 100%.
169
176
 
177
+ .. _2.7.0: https://github.com/mdomke/python-ulid/compare/2.6.0...2.7.0
170
178
  .. _2.6.0: https://github.com/mdomke/python-ulid/compare/2.5.0...2.6.0
171
179
  .. _2.5.0: https://github.com/mdomke/python-ulid/compare/2.4.0...2.5.0
172
180
  .. _2.4.0: https://github.com/mdomke/python-ulid/compare/2.3.0...2.4.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: python-ulid
3
- Version: 2.6.0
3
+ Version: 2.7.0
4
4
  Summary: Universally unique lexicographically sortable identifier
5
5
  Project-URL: Homepage, https://github.com/mdomke/python-ulid
6
6
  Project-URL: Documentation, https://python-ulid.readthedocs.io
@@ -21,6 +21,7 @@ from ulid import constants
21
21
  (base32.decode, "A" * (constants.REPR_LEN + 1)),
22
22
  (base32.decode_timestamp, "A" * (constants.TIMESTAMP_REPR_LEN - 1)),
23
23
  (base32.decode_timestamp, "A" * (constants.TIMESTAMP_REPR_LEN + 1)),
24
+ (base32.decode_timestamp, "Z" * constants.TIMESTAMP_REPR_LEN),
24
25
  (base32.decode_randomness, "A" * (constants.RANDOMNESS_REPR_LEN - 1)),
25
26
  (base32.decode_randomness, "A" * (constants.RANDOMNESS_REPR_LEN + 1)),
26
27
  ],
@@ -167,6 +167,37 @@ def test_ulid_invalid_input(constructor: Callable[[Params], ULID], value: Params
167
167
  constructor(value)
168
168
 
169
169
 
170
+ @pytest.mark.parametrize(
171
+ ("constructor", "value"),
172
+ [
173
+ (ULID, b"\x00" * 16),
174
+ (ULID.from_timestamp, 0),
175
+ (ULID.from_bytes, b"\x00" * 16),
176
+ (ULID.from_str, "0" * 26),
177
+ (ULID.from_hex, "0" * 32),
178
+ (ULID.from_uuid, uuid.UUID("0" * 32)),
179
+ ],
180
+ )
181
+ def test_ulid_min_input(constructor: Callable[[Params], ULID], value: Params) -> None:
182
+ constructor(value)
183
+
184
+
185
+ @pytest.mark.parametrize(
186
+ ("constructor", "value"),
187
+ [
188
+ (ULID, b"\xff" * 16),
189
+ (ULID.from_timestamp, 281474976710655),
190
+ (ULID.from_datetime, datetime.max.replace(tzinfo=timezone.utc)),
191
+ (ULID.from_bytes, b"\xff" * 16),
192
+ (ULID.from_str, "7" + "Z" * 25),
193
+ (ULID.from_hex, "f" * 32),
194
+ (ULID.from_uuid, uuid.UUID("f" * 32)),
195
+ ],
196
+ )
197
+ def test_ulid_max_input(constructor: Callable[[Params], ULID], value: Params) -> None:
198
+ constructor(value)
199
+
200
+
170
201
  def test_pydantic_protocol() -> None:
171
202
  ulid = ULID()
172
203
 
@@ -74,23 +74,17 @@ class ULID:
74
74
 
75
75
  Args:
76
76
  value (bytes, None): A sequence of 16 bytes representing an encoded ULID.
77
- validate (bool): If set to `True` validate if the timestamp part is valid.
78
77
 
79
78
  Raises:
80
79
  ValueError: If the provided value is not a valid encoded ULID.
81
80
  """
82
81
 
83
- def __init__(self, value: bytes | None = None, validate: bool = True) -> None:
82
+ def __init__(self, value: bytes | None = None) -> None:
84
83
  if value is not None and len(value) != constants.BYTES_LEN:
85
84
  raise ValueError("ULID has to be exactly 16 bytes long.")
86
85
  self.bytes: bytes = (
87
86
  value or ULID.from_timestamp(time.time_ns() // constants.NANOSECS_IN_MILLISECS).bytes
88
87
  )
89
- if value is not None and validate:
90
- try:
91
- self.datetime # noqa: B018
92
- except ValueError as err:
93
- raise ValueError("ULID timestamp is out of range.") from err
94
88
 
95
89
  @classmethod
96
90
  @validate_type(datetime)
@@ -137,7 +131,7 @@ class ULID:
137
131
  >>> ULID.from_uuid(uuid4())
138
132
  ULID(27Q506DP7E9YNRXA0XVD8Z5YSG)
139
133
  """
140
- return cls(value.bytes, validate=False)
134
+ return cls(value.bytes)
141
135
 
142
136
  @classmethod
143
137
  @validate_type(bytes)
@@ -210,6 +210,9 @@ def decode_timestamp(encoded: str) -> bytes:
210
210
  raise ValueError("ULID timestamp has to be exactly 10 characters long.")
211
211
  lut = DECODE
212
212
  values: bytes = bytes(encoded, "ascii")
213
+ # https://github.com/ulid/spec?tab=readme-ov-file#overflow-errors-when-parsing-base32-strings
214
+ if lut[values[0]] > 7:
215
+ raise ValueError(f"Timestamp value {encoded} is too large and will overflow 128-bits.")
213
216
  return bytes(
214
217
  [
215
218
  ((lut[values[0]] << 5) | lut[values[1]]) & 0xFF,
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes