cuid2 2.2.1__tar.gz → 2.3.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cuid2
3
- Version: 2.2.1
3
+ Version: 2.3.0
4
4
  Summary: Next generation GUIDs. Collision-resistant ids optimized for horizontal scaling and performance.
5
5
  Keywords: crypt,security,uuid,guid,cuid,cryptography
6
6
  Author: Will Gordon
@@ -11,7 +11,6 @@ Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: Operating System :: OS Independent
13
13
  Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
17
16
  Classifier: Programming Language :: Python :: 3.13
@@ -20,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.15
20
19
  Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable
21
20
  Classifier: Topic :: Security :: Cryptography
22
21
  Classifier: Typing :: Typed
23
- Requires-Python: >=3.10
22
+ Requires-Python: >=3.11
24
23
  Project-URL: repository, https://github.com/gordon-code/cuid2/
25
24
  Project-URL: Changelog, https://github.com/gordon-code/cuid2/blob/main/CHANGELOG.md
26
25
  Project-URL: Issues, https://github.com/gordon-code/cuid2/issues
@@ -28,7 +27,7 @@ Description-Content-Type: text/markdown
28
27
 
29
28
  # cuid2
30
29
 
31
- [![Python](https://img.shields.io/badge/python-3.10+-blue.svg)](https://pypi.org/project/cuid2/)
30
+ [![Python](https://img.shields.io/badge/python-3.11+-blue.svg)](https://pypi.org/project/cuid2/)
32
31
  [![PyPi](https://img.shields.io/pypi/v/cuid2.svg)](https://pypi.org/project/cuid2/)
33
32
  [![PyPi](https://img.shields.io/pypi/dm/cuid2.svg)](https://pypi.org/project/cuid2/)
34
33
  [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/gordon-code/cuid2/badge)](https://scorecard.dev/viewer/?uri=github.com/gordon-code/cuid2)
@@ -105,6 +104,8 @@ short_cuid: str = create_id(length=10)
105
104
  print(is_cuid(my_cuid)) # True
106
105
  ```
107
106
 
107
+ The CUID2 specification allows lengths 2..32; lengths `1` and `33`–`98` are still accepted in 2.x but emit a `FutureWarning` (shown as `cuid2: warning: ...` by the CLI), and 3.0.0 will reject them with `ValueError`.
108
+
108
109
  > **Tip for Django & ORM defaults:** Pass `default=create_id` directly on model fields (e.g., `models.CharField(max_length=24, default=create_id)`). Because `create_id` is a top-level function backed by a lazy singleton generator, Django `makemigrations` can serialize it directly and `Cuid()` initialization is deferred until the first ID is generated in each worker process.
109
110
 
110
111
  You can also generate and validate CUIDs directly in the terminal:
@@ -1,6 +1,6 @@
1
1
  # cuid2
2
2
 
3
- [![Python](https://img.shields.io/badge/python-3.10+-blue.svg)](https://pypi.org/project/cuid2/)
3
+ [![Python](https://img.shields.io/badge/python-3.11+-blue.svg)](https://pypi.org/project/cuid2/)
4
4
  [![PyPi](https://img.shields.io/pypi/v/cuid2.svg)](https://pypi.org/project/cuid2/)
5
5
  [![PyPi](https://img.shields.io/pypi/dm/cuid2.svg)](https://pypi.org/project/cuid2/)
6
6
  [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/gordon-code/cuid2/badge)](https://scorecard.dev/viewer/?uri=github.com/gordon-code/cuid2)
@@ -77,6 +77,8 @@ short_cuid: str = create_id(length=10)
77
77
  print(is_cuid(my_cuid)) # True
78
78
  ```
79
79
 
80
+ The CUID2 specification allows lengths 2..32; lengths `1` and `33`–`98` are still accepted in 2.x but emit a `FutureWarning` (shown as `cuid2: warning: ...` by the CLI), and 3.0.0 will reject them with `ValueError`.
81
+
80
82
  > **Tip for Django & ORM defaults:** Pass `default=create_id` directly on model fields (e.g., `models.CharField(max_length=24, default=create_id)`). Because `create_id` is a top-level function backed by a lazy singleton generator, Django `makemigrations` can serialize it directly and `Cuid()` initialization is deferred until the first ID is generated in each worker process.
81
83
 
82
84
  You can also generate and validate CUIDs directly in the terminal:
@@ -4,10 +4,10 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "cuid2"
7
- version = "2.2.1"
7
+ version = "2.3.0"
8
8
  description = "Next generation GUIDs. Collision-resistant ids optimized for horizontal scaling and performance."
9
9
  readme = "README.md"
10
- requires-python = ">=3.10"
10
+ requires-python = ">=3.11"
11
11
  license = "MIT"
12
12
  license-files = ["LICENSE"]
13
13
  classifiers = [
@@ -15,7 +15,6 @@ classifiers = [
15
15
  "Intended Audience :: Developers",
16
16
  "Operating System :: OS Independent",
17
17
  "Programming Language :: Python :: 3",
18
- "Programming Language :: Python :: 3.10",
19
18
  "Programming Language :: Python :: 3.11",
20
19
  "Programming Language :: Python :: 3.12",
21
20
  "Programming Language :: Python :: 3.13",
@@ -44,7 +43,7 @@ Changelog = "https://github.com/gordon-code/cuid2/blob/main/CHANGELOG.md"
44
43
  Issues = "https://github.com/gordon-code/cuid2/issues"
45
44
 
46
45
  [project.scripts]
47
- cuid2 = "cuid2.cli:main"
46
+ cuid2 = "cuid2.cli:_console_main"
48
47
 
49
48
  [tool.uv]
50
49
  default-groups = [
@@ -70,7 +69,7 @@ exclude = ["hack"]
70
69
  [tool.ruff]
71
70
  line-length = 120
72
71
  src = ["src"]
73
- target-version = "py310"
72
+ target-version = "py311"
74
73
  cache-dir = "local/.ruff_cache"
75
74
  extend-exclude = ["hack"]
76
75
  force-exclude = true
@@ -158,6 +157,7 @@ exclude = [
158
157
  "^dist/",
159
158
  "^hack/",
160
159
  ]
160
+ python_version = "3.11"
161
161
  strict = true
162
162
 
163
163
  [[tool.mypy.overrides]]
@@ -173,6 +173,7 @@ exclude = [
173
173
  "dist",
174
174
  "hack",
175
175
  ]
176
+ pythonVersion = "3.11"
176
177
  strict = ["src"]
177
178
 
178
179
  [dependency-groups]
@@ -182,12 +183,11 @@ lint = [
182
183
  "prek==0.5.7",
183
184
  "ruff==0.17.0",
184
185
  "rumdl==0.3.0",
185
- "zizmor==1.31.1; python_version >= '3.11'",
186
+ "zizmor==1.31.1",
186
187
  ]
187
188
  test = [
188
189
  "coverage[toml]==7.16.2",
189
- "hypothesis==6.168.5; python_version < '3.11'",
190
- "hypothesis==6.170.5; python_version >= '3.11'",
190
+ "hypothesis==6.170.5",
191
191
  "keepachangelog==2.0.0",
192
192
  "pytest==9.1.1",
193
193
  "pytest-cov==7.1.0",
@@ -4,13 +4,13 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "cuid2"
7
- version = "2.2.1"
7
+ version = "2.3.0"
8
8
  authors = [
9
9
  {name = "Will Gordon", email = "dev@gordoncode.dev"},
10
10
  ]
11
11
  description = "Next generation GUIDs. Collision-resistant ids optimized for horizontal scaling and performance."
12
12
  readme = "README.md"
13
- requires-python = ">=3.10"
13
+ requires-python = ">=3.11"
14
14
  license = "MIT"
15
15
  license-files = ["LICENSE"]
16
16
  classifiers = [
@@ -18,7 +18,6 @@ classifiers = [
18
18
  "Intended Audience :: Developers",
19
19
  "Operating System :: OS Independent",
20
20
  "Programming Language :: Python :: 3",
21
- "Programming Language :: Python :: 3.10",
22
21
  "Programming Language :: Python :: 3.11",
23
22
  "Programming Language :: Python :: 3.12",
24
23
  "Programming Language :: Python :: 3.13",
@@ -36,7 +35,7 @@ Changelog = "https://github.com/gordon-code/cuid2/blob/main/CHANGELOG.md"
36
35
  Issues = "https://github.com/gordon-code/cuid2/issues"
37
36
 
38
37
  [project.scripts]
39
- cuid2 = "cuid2.cli:main"
38
+ cuid2 = "cuid2.cli:_console_main"
40
39
 
41
40
  [tool.uv]
42
41
  default-groups = ["build", "lint", "test", "typing"]
@@ -50,12 +49,11 @@ lint = [
50
49
  "prek==0.5.7",
51
50
  "ruff==0.17.0",
52
51
  "rumdl==0.3.0",
53
- "zizmor==1.31.1; python_version >= '3.11'",
52
+ "zizmor==1.31.1",
54
53
  ]
55
54
  test = [
56
55
  "coverage[toml]==7.16.2",
57
- "hypothesis==6.168.5; python_version < '3.11'",
58
- "hypothesis==6.170.5; python_version >= '3.11'",
56
+ "hypothesis==6.170.5",
59
57
  "keepachangelog==2.0.0",
60
58
  "pytest==9.1.1",
61
59
  "pytest-cov==7.1.0",
@@ -82,7 +80,7 @@ exclude = ["hack"]
82
80
  [tool.ruff]
83
81
  line-length = 120
84
82
  src = ["src"]
85
- target-version = "py310"
83
+ target-version = "py311"
86
84
  cache-dir = "local/.ruff_cache"
87
85
  extend-exclude = ["hack"]
88
86
  force-exclude = true
@@ -152,6 +150,7 @@ exclude_also = [
152
150
  cache_dir = "local/.mypy_cache"
153
151
  files = ["."]
154
152
  exclude = ["^build/", "^dist/", "^hack/"]
153
+ python_version = "3.11"
155
154
  strict = true
156
155
 
157
156
  [[tool.mypy.overrides]]
@@ -160,4 +159,5 @@ ignore_missing_imports = true
160
159
 
161
160
  [tool.pyright]
162
161
  exclude = ["build", "dist", "hack"]
162
+ pythonVersion = "3.11"
163
163
  strict = ["src"]
@@ -2,6 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from cuid2.cli import main
5
+ from cuid2.cli import _console_main # pyright: ignore[reportPrivateUsage]
6
6
 
7
- main()
7
+ _console_main()
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import os
6
6
  import sys
7
+ import warnings
7
8
  from argparse import SUPPRESS, Action, ArgumentParser, ArgumentTypeError, RawDescriptionHelpFormatter
8
9
  from contextlib import suppress
9
10
  from functools import partial
@@ -18,6 +19,7 @@ if TYPE_CHECKING:
18
19
  from argparse import Namespace
19
20
  from collections.abc import Iterable, Iterator, Sequence
20
21
  from random import Random
22
+ from typing import TextIO
21
23
 
22
24
  _SLUG_LENGTH: int = 5
23
25
 
@@ -93,6 +95,23 @@ def _fixed_fingerprint(random_generator: Random, *, fingerprint: str) -> str:
93
95
  return fingerprint
94
96
 
95
97
 
98
+ def _show_cli_warning( # noqa: PLR0913, PLR0917
99
+ message: Warning | str,
100
+ category: type[Warning],
101
+ filename: str,
102
+ lineno: int,
103
+ file: TextIO | None = None,
104
+ line: str | None = None,
105
+ ) -> None:
106
+ # Prints warnings as one clean `cuid2: warning: <message>` stderr line, without the source path or code line.
107
+ del category, filename, lineno, line
108
+ stream = file if file is not None else sys.stderr
109
+ if stream is None: # No stderr (pythonw or fd 2 closed at startup): drop the warning like the stdlib does.
110
+ return
111
+ with suppress(OSError):
112
+ stream.write(f"cuid2: warning: {message}\n")
113
+
114
+
96
115
  def _build_parser() -> ArgumentParser:
97
116
  parser = ArgumentParser(
98
117
  prog="cuid2",
@@ -246,7 +265,16 @@ def main(args: Sequence[str] | None = None) -> None:
246
265
  ------
247
266
  SystemExit
248
267
  Raised with exit code ``0`` or ``1`` in ``--check``/``--validate`` or
249
- ``--version``/``--help`` modes, or exit code ``2`` on invalid arguments.
268
+ ``--version``/``--help`` modes, or exit code ``2`` on invalid arguments,
269
+ including a length warning that a warnings filter turned into an error.
270
+
271
+ Warns
272
+ -----
273
+ FutureWarning
274
+ When generating IDs (not in ``--check``/``--validate`` mode) with a length
275
+ outside the CUID2 specification range (``MIN_LENGTH``..``BIG_LENGTH``,
276
+ i.e., 2..32). The ``cuid2`` console script and ``python -m cuid2`` print it
277
+ as a ``cuid2: warning: ...`` line.
250
278
  """
251
279
  parser = _build_parser()
252
280
  cli_args = parser.parse_args(args)
@@ -259,12 +287,24 @@ def main(args: Sequence[str] | None = None) -> None:
259
287
 
260
288
  resolved_length = target_length if target_length is not None else DEFAULT_LENGTH
261
289
  count = cli_args.count if cli_args.count is not None else 1
262
- cuid_generator = (
263
- Cuid(length=resolved_length)
264
- if cli_args.fingerprint is None
265
- else Cuid(
266
- length=resolved_length,
267
- fingerprint=partial(_fixed_fingerprint, fingerprint=cli_args.fingerprint),
290
+ try:
291
+ cuid_generator = (
292
+ Cuid(length=resolved_length)
293
+ if cli_args.fingerprint is None
294
+ else Cuid(
295
+ length=resolved_length,
296
+ fingerprint=partial(_fixed_fingerprint, fingerprint=cli_args.fingerprint),
297
+ )
268
298
  )
269
- )
299
+ except FutureWarning as warning:
300
+ # A warnings filter such as -W error or PYTHONWARNINGS=error turned the length warning into an error.
301
+ parser.error(str(warning))
270
302
  _write_lines(f"{cuid_generator.generate()}\n" for _ in range(count))
303
+
304
+
305
+ def _console_main(args: Sequence[str] | None = None) -> None: # pyright: ignore[reportUnusedFunction]
306
+ # Entry point for the `cuid2` console script and `python -m cuid2`: prints warnings as `cuid2: warning:` lines.
307
+ # main() leaves warning delivery to its caller, so programmatic use never touches the global showwarning hook.
308
+ with warnings.catch_warnings():
309
+ warnings.showwarning = _show_cli_warning
310
+ main(args)
@@ -71,7 +71,7 @@ def _validate_length(length: int) -> None:
71
71
 
72
72
  Warns
73
73
  -----
74
- DeprecationWarning
74
+ FutureWarning
75
75
  If `length` is outside the CUID2 specification range (`MIN_LENGTH`..`BIG_LENGTH`, i.e., 2..32).
76
76
  """
77
77
  if isinstance(length, bool) or length < 1:
@@ -84,7 +84,7 @@ def _validate_length(length: int) -> None:
84
84
  warnings.warn(
85
85
  f"Length {length} outside the CUID2 specification range ({MIN_LENGTH}..{BIG_LENGTH}) "
86
86
  "is deprecated and will raise ValueError in v3.0.0.",
87
- DeprecationWarning,
87
+ FutureWarning,
88
88
  stacklevel=3,
89
89
  )
90
90
 
@@ -174,7 +174,7 @@ class Cuid:
174
174
  The length parameter is an integer that determines the maximum length of the generated string.
175
175
  It has a default value of DEFAULT_LENGTH (24).
176
176
  A length value less than 1 or greater than `MAXIMUM_LENGTH` (98 characters) will raise a ValueError.
177
- Lengths outside `MIN_LENGTH`..`BIG_LENGTH` (2..32) emit a DeprecationWarning.
177
+ Lengths outside `MIN_LENGTH`..`BIG_LENGTH` (2..32) emit a FutureWarning (a ValueError in 3.0.0).
178
178
  fingerprint : "FingerprintCallable", default=utils.create_fingerprint
179
179
  The "fingerprint" parameter is a callable function that generates a unique identifier. Called again in a
180
180
  forked child process; the default includes the child's `os.getpid()`.
@@ -186,7 +186,7 @@ class Cuid:
186
186
 
187
187
  Warns
188
188
  -----
189
- DeprecationWarning
189
+ FutureWarning
190
190
  If the length parameter is outside `MIN_LENGTH`..`BIG_LENGTH` (2..32 characters).
191
191
 
192
192
  Notes
@@ -272,7 +272,7 @@ class Cuid:
272
272
  The length parameter is an optional integer value that specifies the length of the generated string.
273
273
  If it is not provided, the default length value provided during class initialization is used.
274
274
  A length value less than 1 or greater than `MAXIMUM_LENGTH` (98 characters) will raise a ValueError.
275
- Lengths outside `MIN_LENGTH`..`BIG_LENGTH` (2..32) emit a DeprecationWarning.
275
+ Lengths outside `MIN_LENGTH`..`BIG_LENGTH` (2..32) emit a FutureWarning (a ValueError in 3.0.0).
276
276
 
277
277
  Returns
278
278
  -------
@@ -288,7 +288,7 @@ class Cuid:
288
288
 
289
289
  Warns
290
290
  -----
291
- DeprecationWarning
291
+ FutureWarning
292
292
  If the length parameter is outside `MIN_LENGTH`..`BIG_LENGTH` (2..32 characters).
293
293
  """
294
294
  if length is not None:
@@ -330,7 +330,7 @@ def create_id(length: int | None = None) -> str:
330
330
  length : int, optional
331
331
  The optional length of the generated CUID2 string. Defaults to `DEFAULT_LENGTH` (24) when omitted.
332
332
  A length value less than 1 or greater than `MAXIMUM_LENGTH` (98 characters) will raise a ValueError.
333
- Lengths outside `MIN_LENGTH`..`BIG_LENGTH` (2..32) emit a DeprecationWarning.
333
+ Lengths outside `MIN_LENGTH`..`BIG_LENGTH` (2..32) emit a FutureWarning (a ValueError in 3.0.0).
334
334
 
335
335
  Returns
336
336
  -------
@@ -344,7 +344,7 @@ def create_id(length: int | None = None) -> str:
344
344
 
345
345
  Warns
346
346
  -----
347
- DeprecationWarning
347
+ FutureWarning
348
348
  If the length parameter is outside `MIN_LENGTH`..`BIG_LENGTH` (2..32 characters).
349
349
  """
350
350
  global _default_generator # noqa: PLW0603
@@ -369,7 +369,7 @@ def cuid_wrapper(length: int = DEFAULT_LENGTH) -> Callable[[], str]:
369
369
  The length parameter is an integer that determines the maximum length of the generated string.
370
370
  It has a default value of DEFAULT_LENGTH (24).
371
371
  A length value less than 1 or greater than `MAXIMUM_LENGTH` (98 characters) will raise a ValueError.
372
- Lengths outside `MIN_LENGTH`..`BIG_LENGTH` (2..32) emit a DeprecationWarning.
372
+ Lengths outside `MIN_LENGTH`..`BIG_LENGTH` (2..32) emit a FutureWarning (a ValueError in 3.0.0).
373
373
 
374
374
  Returns
375
375
  -------
@@ -383,7 +383,7 @@ def cuid_wrapper(length: int = DEFAULT_LENGTH) -> Callable[[], str]:
383
383
 
384
384
  Warns
385
385
  -----
386
- DeprecationWarning
386
+ FutureWarning
387
387
  If the length parameter is outside `MIN_LENGTH`..`BIG_LENGTH` (2..32 characters).
388
388
  """
389
389
  _validate_length(length)
File without changes
File without changes
File without changes
File without changes