unstd 1.0.2__tar.gz → 1.0.4__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.
- {unstd-1.0.2 → unstd-1.0.4}/.github/workflows/ci.yml +30 -0
- {unstd-1.0.2 → unstd-1.0.4}/CHANGELOG.md +32 -0
- {unstd-1.0.2 → unstd-1.0.4}/PKG-INFO +19 -19
- {unstd-1.0.2 → unstd-1.0.4}/pyproject.toml +29 -19
- {unstd-1.0.2 → unstd-1.0.4}/tests/test_package.py +27 -0
- {unstd-1.0.2 → unstd-1.0.4}/uv.lock +19 -19
- {unstd-1.0.2 → unstd-1.0.4}/.github/workflows/release.yml +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/.gitignore +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/LICENSE +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/NOTICE +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/bench/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/bench/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/bench/__main__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/bench/baseline.json +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/bench/cases.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/bench/report.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/bench/timing.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/audio/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/audio/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/audio/wavx.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/clone/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/clone/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/clone/structural.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/containers/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/containers/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/containers/guard.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/containers/persistent.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/containers/sorted.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/crypto/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/crypto/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/crypto/digest.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/crypto/tls.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/crypto/token.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/fs/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/fs/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/ids/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/ids/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/ids/hash.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/ids/uid.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/iters/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/iters/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/iters/distinct.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/iters/reshape.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/iters/runs.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/iters/select.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/model/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/model/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/model/base.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/model/settings.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/pack/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/pack/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/pack/binpack.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/proc/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/proc/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/py.typed +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/rand/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/rand/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/rand/crypto.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/rand/draw.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/rex/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/rex/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/serde/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/serde/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/serde/b64.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/serde/jsonx.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/serde/ndjson.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/serde/structs.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/text/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/text/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/text/fuzz.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/time/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/time/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/time/dateutil.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/time/timeutil.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/toml/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/src/unstd/toml/__init__.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/audio/test_audio.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/clone/test_clone.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/conftest.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/containers/test_containers.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/crypto/blake3_reference_vectors.json +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/crypto/test_adverse.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/crypto/test_vectors.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/fs/test_fs.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/ids/test_uid.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/iters/test_iters.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/model/test_model.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/pack/test_pack.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/proc/test_proc.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/properties/README.md +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/properties/test_clone_invariants.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/properties/test_pack_invariants.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/properties/test_serde_parity.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/properties/test_toml_invariants.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/properties/test_uuid7.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/properties/test_wav_quant.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/rand/test_rand.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/rex/test_rex.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/serde/test_b64.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/serde/test_jsonx.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/serde/test_ndjson.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/serde/test_structs.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/test_bench.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/text/test_text.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/time/test_dateutil.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/time/test_timeutil.py +0 -0
- {unstd-1.0.2 → unstd-1.0.4}/tests/toml/test_toml.py +0 -0
|
@@ -59,6 +59,36 @@ jobs:
|
|
|
59
59
|
- run: uv sync --all-extras --group dev --python ${{ matrix.python-version }}
|
|
60
60
|
- run: uv run --python ${{ matrix.python-version }} pytest -q
|
|
61
61
|
|
|
62
|
+
floors:
|
|
63
|
+
# Every extra declares a floor, and a floor is a promise: install this old a
|
|
64
|
+
# backend and the library still works. Nothing else in this matrix tests it —
|
|
65
|
+
# `test` resolves the newest of everything, so the floors could be fiction
|
|
66
|
+
# for years and only a consumer with an older pin would ever find out, as a
|
|
67
|
+
# resolver error blamed on their own manifest.
|
|
68
|
+
#
|
|
69
|
+
# `lowest-direct` takes the oldest version each DIRECT floor admits while
|
|
70
|
+
# leaving transitives modern, which is the environment a downstream
|
|
71
|
+
# application actually produces. A failure here means the floor is wrong, not
|
|
72
|
+
# the code: raise it to the version that works and say so in the changelog.
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
steps:
|
|
75
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
76
|
+
with:
|
|
77
|
+
persist-credentials: false
|
|
78
|
+
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
|
79
|
+
with:
|
|
80
|
+
enable-cache: false
|
|
81
|
+
python-version: "3.13"
|
|
82
|
+
- run: uv sync --all-extras --group dev --python 3.13 --resolution lowest-direct
|
|
83
|
+
# Which versions the floors admitted — the first thing anyone reading a
|
|
84
|
+
# failure here needs, and not recoverable from the traceback.
|
|
85
|
+
- run: uv pip list
|
|
86
|
+
# `--no-sync` is what makes this job mean anything. A bare `uv run`
|
|
87
|
+
# re-resolves in the default `highest` mode and quietly reinstalls the
|
|
88
|
+
# newest of everything first, so the suite would run against the same
|
|
89
|
+
# environment `test` already covers and pass no matter what the floors say.
|
|
90
|
+
- run: uv run --no-sync --python 3.13 pytest -q
|
|
91
|
+
|
|
62
92
|
test-fallback:
|
|
63
93
|
# A base install (no optional extras) is a load-bearing, documented contract
|
|
64
94
|
# on nearly every module: each accelerated backend degrades to a
|
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- towncrier release notes start -->
|
|
4
4
|
|
|
5
|
+
## [1.0.4] - 2026-08-31
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- The extra floors sit at the minor series rather than the patch we happened to
|
|
10
|
+
develop against, and CI now proves them. 1.0.3 relaxed `==` to `>=` but left
|
|
11
|
+
each floor on an exact patch, so `unstd[model]` still rejected an application
|
|
12
|
+
one pydantic bugfix behind - a resolver error that reads as the application's
|
|
13
|
+
fault. The API a backend offers changes at the minor, which is where a floor
|
|
14
|
+
belongs.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- A `floors` CI job resolves `--resolution lowest-direct` and runs the whole
|
|
19
|
+
suite against the oldest version every floor admits. A floor is a promise that
|
|
20
|
+
the library works that far back, and nothing was testing it: the rest of the
|
|
21
|
+
matrix resolves the newest of everything, so the floors could have been fiction
|
|
22
|
+
indefinitely and only a downstream with an older pin would have found out.
|
|
23
|
+
|
|
24
|
+
## [1.0.3] - 2026-08-31
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Every extra declares a floor rather than an exact `==` pin. The pins were
|
|
29
|
+
inherited from the monorepo this package was extracted from, where an exact
|
|
30
|
+
pin is correct because a monorepo is the application. Published, they meant an
|
|
31
|
+
application already on `pydantic==2.13.4` could not install `unstd[model]` at
|
|
32
|
+
all - the resolver reports the conflict against the application, not against
|
|
33
|
+
us - and two libraries pinning patches are simply not co-installable. The
|
|
34
|
+
floors are the versions each extra is tested against; a consumer that wants an
|
|
35
|
+
exact version has its own manifest and lockfile to say so in.
|
|
36
|
+
|
|
5
37
|
## [1.0.2] - 2026-08-31
|
|
6
38
|
|
|
7
39
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: unstd
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: stdlib-faithful accelerated replacements behind optional extras
|
|
5
5
|
Project-URL: Homepage, https://github.com/The-Billy-Company/unstd
|
|
6
6
|
Project-URL: Repository, https://github.com/The-Billy-Company/unstd
|
|
@@ -21,39 +21,39 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
21
21
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
22
|
Requires-Python: >=3.12
|
|
23
23
|
Provides-Extra: audio
|
|
24
|
-
Requires-Dist: numpy
|
|
25
|
-
Requires-Dist: soundfile
|
|
24
|
+
Requires-Dist: numpy>=2.5; extra == 'audio'
|
|
25
|
+
Requires-Dist: soundfile>=0.14; extra == 'audio'
|
|
26
26
|
Provides-Extra: clone
|
|
27
|
-
Requires-Dist: msgspec
|
|
27
|
+
Requires-Dist: msgspec>=0.21; extra == 'clone'
|
|
28
28
|
Provides-Extra: containers
|
|
29
|
-
Requires-Dist: immutables
|
|
30
|
-
Requires-Dist: sortedcontainers
|
|
29
|
+
Requires-Dist: immutables>=0.21; extra == 'containers'
|
|
30
|
+
Requires-Dist: sortedcontainers>=2.4; extra == 'containers'
|
|
31
31
|
Provides-Extra: crypto
|
|
32
|
-
Requires-Dist: blake3
|
|
32
|
+
Requires-Dist: blake3>=1.0; extra == 'crypto'
|
|
33
33
|
Provides-Extra: ids
|
|
34
|
-
Requires-Dist: blake3
|
|
35
|
-
Requires-Dist: uuid-utils
|
|
34
|
+
Requires-Dist: blake3>=1.0; extra == 'ids'
|
|
35
|
+
Requires-Dist: uuid-utils>=0.17; extra == 'ids'
|
|
36
36
|
Provides-Extra: model
|
|
37
|
-
Requires-Dist: pydantic-settings
|
|
38
|
-
Requires-Dist: pydantic
|
|
37
|
+
Requires-Dist: pydantic-settings>=2.15; extra == 'model'
|
|
38
|
+
Requires-Dist: pydantic>=2.13; extra == 'model'
|
|
39
39
|
Provides-Extra: pack
|
|
40
|
-
Requires-Dist: numpy
|
|
40
|
+
Requires-Dist: numpy>=2.5; extra == 'pack'
|
|
41
41
|
Provides-Extra: proto
|
|
42
|
-
Requires-Dist: protobuf
|
|
42
|
+
Requires-Dist: protobuf>=7.36; extra == 'proto'
|
|
43
43
|
Provides-Extra: rand
|
|
44
|
-
Requires-Dist: numpy
|
|
44
|
+
Requires-Dist: numpy>=2.5; extra == 'rand'
|
|
45
45
|
Provides-Extra: rex
|
|
46
46
|
Requires-Dist: irregex>=2.3.0; extra == 'rex'
|
|
47
47
|
Provides-Extra: serde
|
|
48
|
-
Requires-Dist: msgspec
|
|
49
|
-
Requires-Dist: orjson
|
|
50
|
-
Requires-Dist: pybase64
|
|
48
|
+
Requires-Dist: msgspec>=0.21; extra == 'serde'
|
|
49
|
+
Requires-Dist: orjson>=3.12; extra == 'serde'
|
|
50
|
+
Requires-Dist: pybase64>=1.5; extra == 'serde'
|
|
51
51
|
Provides-Extra: text
|
|
52
52
|
Requires-Dist: rapidfuzz>=3.12.0; extra == 'text'
|
|
53
53
|
Provides-Extra: time
|
|
54
|
-
Requires-Dist: whenever
|
|
54
|
+
Requires-Dist: whenever>=0.10; extra == 'time'
|
|
55
55
|
Provides-Extra: toml
|
|
56
|
-
Requires-Dist: tomlkit
|
|
56
|
+
Requires-Dist: tomlkit>=0.15; extra == 'toml'
|
|
57
57
|
Description-Content-Type: text/markdown
|
|
58
58
|
|
|
59
59
|
# unstd
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "unstd"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.4"
|
|
8
8
|
description = "stdlib-faithful accelerated replacements behind optional extras"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -32,57 +32,67 @@ classifiers = [
|
|
|
32
32
|
]
|
|
33
33
|
dependencies = []
|
|
34
34
|
|
|
35
|
+
# Every entry below is a FLOOR, never an `==` pin. A library that pins a patch
|
|
36
|
+
# decides its consumers' resolutions for them, and two libraries doing that are
|
|
37
|
+
# simply not co-installable. Applications are where an exact pin belongs, and a
|
|
38
|
+
# consumer that wants one still has its own manifest and lockfile to say so in.
|
|
39
|
+
#
|
|
40
|
+
# The floor sits at the MINOR series, because that is where the API a backend
|
|
41
|
+
# offers actually changes — pinning the patch we happened to develop against
|
|
42
|
+
# rejects a consumer one bugfix behind for no reason we could state. CI's
|
|
43
|
+
# `floors` job resolves `--resolution lowest-direct` and runs the whole suite
|
|
44
|
+
# there, so each of these is a claim under test rather than a guess.
|
|
35
45
|
[project.optional-dependencies]
|
|
36
46
|
serde = [
|
|
37
|
-
"orjson
|
|
38
|
-
"msgspec
|
|
39
|
-
"pybase64
|
|
47
|
+
"orjson>=3.12",
|
|
48
|
+
"msgspec>=0.21",
|
|
49
|
+
"pybase64>=1.5",
|
|
40
50
|
]
|
|
41
51
|
ids = [
|
|
42
|
-
"blake3
|
|
43
|
-
"uuid-utils
|
|
52
|
+
"blake3>=1.0",
|
|
53
|
+
"uuid-utils>=0.17",
|
|
44
54
|
]
|
|
45
55
|
crypto = [
|
|
46
|
-
"blake3
|
|
56
|
+
"blake3>=1.0",
|
|
47
57
|
]
|
|
48
58
|
time = [
|
|
49
|
-
"whenever
|
|
59
|
+
"whenever>=0.10",
|
|
50
60
|
]
|
|
51
61
|
# `timeutil`'s protobuf Timestamp bridge only. Kept out of `time` so a
|
|
52
62
|
# `whenever` consumer does not inherit protobuf, and out of the base install so
|
|
53
63
|
# the rest of `timeutil` stays pure stdlib.
|
|
54
64
|
proto = [
|
|
55
|
-
"protobuf
|
|
65
|
+
"protobuf>=7.36",
|
|
56
66
|
]
|
|
57
67
|
model = [
|
|
58
|
-
"pydantic
|
|
59
|
-
"pydantic-settings
|
|
68
|
+
"pydantic>=2.13",
|
|
69
|
+
"pydantic-settings>=2.15",
|
|
60
70
|
]
|
|
61
71
|
rex = [
|
|
62
72
|
"irregex>=2.3.0",
|
|
63
73
|
]
|
|
64
74
|
containers = [
|
|
65
|
-
"sortedcontainers
|
|
66
|
-
"immutables
|
|
75
|
+
"sortedcontainers>=2.4",
|
|
76
|
+
"immutables>=0.21",
|
|
67
77
|
]
|
|
68
78
|
rand = [
|
|
69
|
-
"numpy
|
|
79
|
+
"numpy>=2.5",
|
|
70
80
|
]
|
|
71
81
|
pack = [
|
|
72
|
-
"numpy
|
|
82
|
+
"numpy>=2.5",
|
|
73
83
|
]
|
|
74
84
|
clone = [
|
|
75
|
-
"msgspec
|
|
85
|
+
"msgspec>=0.21",
|
|
76
86
|
]
|
|
77
87
|
text = [
|
|
78
88
|
"rapidfuzz>=3.12.0",
|
|
79
89
|
]
|
|
80
90
|
audio = [
|
|
81
|
-
"soundfile
|
|
82
|
-
"numpy
|
|
91
|
+
"soundfile>=0.14",
|
|
92
|
+
"numpy>=2.5",
|
|
83
93
|
]
|
|
84
94
|
toml = [
|
|
85
|
-
"tomlkit
|
|
95
|
+
"tomlkit>=0.15",
|
|
86
96
|
]
|
|
87
97
|
|
|
88
98
|
[project.urls]
|
|
@@ -110,6 +110,33 @@ def test_the_base_install_has_no_third_party_closure() -> None:
|
|
|
110
110
|
)
|
|
111
111
|
|
|
112
112
|
|
|
113
|
+
def test_no_extra_pins_an_exact_version() -> None:
|
|
114
|
+
"""A library that pins a patch resolves for its consumers, and breaks them.
|
|
115
|
+
|
|
116
|
+
Every extra here shipped with ``==`` in 1.0.2, inherited from the monorepo
|
|
117
|
+
this package was extracted from — where an exact pin is right, because a
|
|
118
|
+
monorepo *is* the application. Published, the same pin means an application
|
|
119
|
+
already on ``pydantic==2.13.4`` cannot install ``unstd[model]`` at all, and
|
|
120
|
+
the resolver blames the application. Two such libraries in one environment
|
|
121
|
+
are simply not co-installable.
|
|
122
|
+
|
|
123
|
+
So the invariant is the shape of the specifier, not any particular version:
|
|
124
|
+
floors only. A consumer wanting an exact version still has its own manifest
|
|
125
|
+
and lockfile to say so in.
|
|
126
|
+
"""
|
|
127
|
+
project = _pyproject()["project"]
|
|
128
|
+
assert isinstance(project, dict)
|
|
129
|
+
extras = project.get("optional-dependencies", {})
|
|
130
|
+
assert isinstance(extras, dict)
|
|
131
|
+
pinned = {
|
|
132
|
+
f"{extra}: {req}"
|
|
133
|
+
for extra, reqs in extras.items()
|
|
134
|
+
for req in reqs
|
|
135
|
+
if "==" in req
|
|
136
|
+
}
|
|
137
|
+
assert not pinned, f"extras must declare floors, not exact pins: {sorted(pinned)}"
|
|
138
|
+
|
|
139
|
+
|
|
113
140
|
def test_the_typing_marker_ships() -> None:
|
|
114
141
|
"""Without ``py.typed`` every annotation in this library is invisible.
|
|
115
142
|
|
|
@@ -1263,7 +1263,7 @@ wheels = [
|
|
|
1263
1263
|
|
|
1264
1264
|
[[package]]
|
|
1265
1265
|
name = "unstd"
|
|
1266
|
-
version = "1.0.
|
|
1266
|
+
version = "1.0.4"
|
|
1267
1267
|
source = { editable = "." }
|
|
1268
1268
|
|
|
1269
1269
|
[package.optional-dependencies]
|
|
@@ -1327,26 +1327,26 @@ dev = [
|
|
|
1327
1327
|
|
|
1328
1328
|
[package.metadata]
|
|
1329
1329
|
requires-dist = [
|
|
1330
|
-
{ name = "blake3", marker = "extra == 'crypto'", specifier = "
|
|
1331
|
-
{ name = "blake3", marker = "extra == 'ids'", specifier = "
|
|
1332
|
-
{ name = "immutables", marker = "extra == 'containers'", specifier = "
|
|
1330
|
+
{ name = "blake3", marker = "extra == 'crypto'", specifier = ">=1.0" },
|
|
1331
|
+
{ name = "blake3", marker = "extra == 'ids'", specifier = ">=1.0" },
|
|
1332
|
+
{ name = "immutables", marker = "extra == 'containers'", specifier = ">=0.21" },
|
|
1333
1333
|
{ name = "irregex", marker = "extra == 'rex'", specifier = ">=2.3.0" },
|
|
1334
|
-
{ name = "msgspec", marker = "extra == 'clone'", specifier = "
|
|
1335
|
-
{ name = "msgspec", marker = "extra == 'serde'", specifier = "
|
|
1336
|
-
{ name = "numpy", marker = "extra == 'audio'", specifier = "
|
|
1337
|
-
{ name = "numpy", marker = "extra == 'pack'", specifier = "
|
|
1338
|
-
{ name = "numpy", marker = "extra == 'rand'", specifier = "
|
|
1339
|
-
{ name = "orjson", marker = "extra == 'serde'", specifier = "
|
|
1340
|
-
{ name = "protobuf", marker = "extra == 'proto'", specifier = "
|
|
1341
|
-
{ name = "pybase64", marker = "extra == 'serde'", specifier = "
|
|
1342
|
-
{ name = "pydantic", marker = "extra == 'model'", specifier = "
|
|
1343
|
-
{ name = "pydantic-settings", marker = "extra == 'model'", specifier = "
|
|
1334
|
+
{ name = "msgspec", marker = "extra == 'clone'", specifier = ">=0.21" },
|
|
1335
|
+
{ name = "msgspec", marker = "extra == 'serde'", specifier = ">=0.21" },
|
|
1336
|
+
{ name = "numpy", marker = "extra == 'audio'", specifier = ">=2.5" },
|
|
1337
|
+
{ name = "numpy", marker = "extra == 'pack'", specifier = ">=2.5" },
|
|
1338
|
+
{ name = "numpy", marker = "extra == 'rand'", specifier = ">=2.5" },
|
|
1339
|
+
{ name = "orjson", marker = "extra == 'serde'", specifier = ">=3.12" },
|
|
1340
|
+
{ name = "protobuf", marker = "extra == 'proto'", specifier = ">=7.36" },
|
|
1341
|
+
{ name = "pybase64", marker = "extra == 'serde'", specifier = ">=1.5" },
|
|
1342
|
+
{ name = "pydantic", marker = "extra == 'model'", specifier = ">=2.13" },
|
|
1343
|
+
{ name = "pydantic-settings", marker = "extra == 'model'", specifier = ">=2.15" },
|
|
1344
1344
|
{ name = "rapidfuzz", marker = "extra == 'text'", specifier = ">=3.12.0" },
|
|
1345
|
-
{ name = "sortedcontainers", marker = "extra == 'containers'", specifier = "
|
|
1346
|
-
{ name = "soundfile", marker = "extra == 'audio'", specifier = "
|
|
1347
|
-
{ name = "tomlkit", marker = "extra == 'toml'", specifier = "
|
|
1348
|
-
{ name = "uuid-utils", marker = "extra == 'ids'", specifier = "
|
|
1349
|
-
{ name = "whenever", marker = "extra == 'time'", specifier = "
|
|
1345
|
+
{ name = "sortedcontainers", marker = "extra == 'containers'", specifier = ">=2.4" },
|
|
1346
|
+
{ name = "soundfile", marker = "extra == 'audio'", specifier = ">=0.14" },
|
|
1347
|
+
{ name = "tomlkit", marker = "extra == 'toml'", specifier = ">=0.15" },
|
|
1348
|
+
{ name = "uuid-utils", marker = "extra == 'ids'", specifier = ">=0.17" },
|
|
1349
|
+
{ name = "whenever", marker = "extra == 'time'", specifier = ">=0.10" },
|
|
1350
1350
|
]
|
|
1351
1351
|
provides-extras = ["serde", "ids", "crypto", "time", "proto", "model", "rex", "containers", "rand", "pack", "clone", "text", "audio", "toml"]
|
|
1352
1352
|
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|