pytest-resources 0.2.0__tar.gz → 0.2.2__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.
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/.gitignore +1 -1
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/CHANGELOG.md +28 -1
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/PKG-INFO +16 -4
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/README.md +15 -3
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/pyproject.toml +1 -1
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/integration/test_synth_library.py +27 -4
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/unit/test_formats.py +10 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/unit/test_nodes_synth.py +12 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/LICENSE +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/src/pytest_resources/__init__.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/src/pytest_resources/errors.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/src/pytest_resources/formats.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/src/pytest_resources/hooks.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/src/pytest_resources/index.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/src/pytest_resources/loaders.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/src/pytest_resources/nodes.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/src/pytest_resources/plugin.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/src/pytest_resources/py.typed +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/src/pytest_resources/synth.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/integration/test_library.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/resources/binary/blob.dat +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/resources/config/app.ini +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/resources/config/manifest.jsonc +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/resources/config/settings.toml +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/resources/data/movies.csv +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/resources/structured/nested/deep.json +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/resources/structured/sample.json +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/resources/structured/sample2.json +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/resources/unstructured/sample.md +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/resources/unstructured/sample2.md +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/unit/test_hook.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/unit/test_index.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/unit/test_init.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/unit/test_loaders.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/unit/test_plugin.py +0 -0
- {pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/unit/test_synth.py +0 -0
|
@@ -6,6 +6,31 @@ adheres to [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.2.2] - 2026-09-24
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Documentation: the synthesis surface (`make` / `batch` / `file`) is covered end to end,
|
|
14
|
+
with a new async-testing section (pure-CPU `make`/`batch`, `awalk` over adopted files,
|
|
15
|
+
off-loop `to_thread` for the network-backed `mp3`); the format matrix notes the document
|
|
16
|
+
and image kinds. The coverage floor is raised from 90% to 95% (current: 100%).
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Tests for `TypedDict` model synthesis, the `batch` default size, the extra synthetic file
|
|
21
|
+
suffixes, and the synthesis provider's memoization.
|
|
22
|
+
|
|
23
|
+
No behavioural change to the packaged wheel.
|
|
24
|
+
|
|
25
|
+
## [0.2.1] - 2026-09-24
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- The test suite is now cross-platform: file formats that `faker-file`/Pillow cannot
|
|
30
|
+
synthesize on Windows/macOS (missing system font, temporary-file locks) skip with a reason
|
|
31
|
+
instead of failing, and the synthetic-text assertion compares against the loader's raw
|
|
32
|
+
byte decode. No change to shipped behaviour.
|
|
33
|
+
|
|
9
34
|
## [0.2.0] - 2026-09-24
|
|
10
35
|
|
|
11
36
|
### Added
|
|
@@ -54,6 +79,8 @@ First release.
|
|
|
54
79
|
- A module-lifetime decode cache per tree, and typed misses (`EntryNotFoundError` /
|
|
55
80
|
`KeyError`) that carry a `difflib` "did you mean" hint.
|
|
56
81
|
|
|
57
|
-
[unreleased]: https://github.com/damvolkov/pytest-resources/compare/v0.2.
|
|
82
|
+
[unreleased]: https://github.com/damvolkov/pytest-resources/compare/v0.2.2...HEAD
|
|
83
|
+
[0.2.2]: https://github.com/damvolkov/pytest-resources/releases/tag/v0.2.2
|
|
84
|
+
[0.2.1]: https://github.com/damvolkov/pytest-resources/releases/tag/v0.2.1
|
|
58
85
|
[0.2.0]: https://github.com/damvolkov/pytest-resources/releases/tag/v0.2.0
|
|
59
86
|
[0.1.0]: https://github.com/damvolkov/pytest-resources/releases/tag/v0.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pytest-resources
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Lazy, typed, attribute-navigable fixtures for test resource files, with pluggable canonical loaders (e-serde by default).
|
|
5
5
|
Project-URL: Homepage, https://github.com/damvolkov/pytest-resources
|
|
6
6
|
Project-URL: Source, https://github.com/damvolkov/pytest-resources
|
|
@@ -39,12 +39,21 @@ extensible to **any** canonical `bytes -> object` loader, and anything else hand
|
|
|
39
39
|
raw `bytes`.
|
|
40
40
|
|
|
41
41
|
You point it at one or more directories of sample files; it recursively indexes the tree
|
|
42
|
-
without reading anything, and you reach, filter and
|
|
43
|
-
read:
|
|
42
|
+
without reading anything, and you reach, filter, randomise and synthesize parsed values
|
|
43
|
+
the way they read:
|
|
44
44
|
|
|
45
45
|
```python
|
|
46
|
+
from dataclasses import dataclass
|
|
47
|
+
|
|
46
48
|
import pytest_resources as pr
|
|
47
49
|
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class User:
|
|
53
|
+
name: str
|
|
54
|
+
age: int
|
|
55
|
+
|
|
56
|
+
|
|
48
57
|
def test_profile(resources: pr.Resources):
|
|
49
58
|
user = resources.structured.user # sample dir -> dict (decoded, cached)
|
|
50
59
|
body = resources.unstructured.intro # a .md -> str
|
|
@@ -69,7 +78,10 @@ uv add --group test "pytest-resources[random]" # both
|
|
|
69
78
|
```
|
|
70
79
|
|
|
71
80
|
The `resources` fixture auto-loads via the `pytest11` entry point — no imports in your
|
|
72
|
-
`conftest.py`.
|
|
81
|
+
`conftest.py`. Everything (index, navigation, synthesis) is async-test friendly:
|
|
82
|
+
`make`/`batch` are pure in-memory CPU and `abuild_resources`/`awalk` keep the loop free;
|
|
83
|
+
calling a synthesis method without its extra raises `ExtraNotInstalledError` with the
|
|
84
|
+
exact install command — the plugin never hard-depends on polyfactory or faker-file.
|
|
73
85
|
|
|
74
86
|
## What you get
|
|
75
87
|
|
|
@@ -6,12 +6,21 @@ extensible to **any** canonical `bytes -> object` loader, and anything else hand
|
|
|
6
6
|
raw `bytes`.
|
|
7
7
|
|
|
8
8
|
You point it at one or more directories of sample files; it recursively indexes the tree
|
|
9
|
-
without reading anything, and you reach, filter and
|
|
10
|
-
read:
|
|
9
|
+
without reading anything, and you reach, filter, randomise and synthesize parsed values
|
|
10
|
+
the way they read:
|
|
11
11
|
|
|
12
12
|
```python
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
|
|
13
15
|
import pytest_resources as pr
|
|
14
16
|
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class User:
|
|
20
|
+
name: str
|
|
21
|
+
age: int
|
|
22
|
+
|
|
23
|
+
|
|
15
24
|
def test_profile(resources: pr.Resources):
|
|
16
25
|
user = resources.structured.user # sample dir -> dict (decoded, cached)
|
|
17
26
|
body = resources.unstructured.intro # a .md -> str
|
|
@@ -36,7 +45,10 @@ uv add --group test "pytest-resources[random]" # both
|
|
|
36
45
|
```
|
|
37
46
|
|
|
38
47
|
The `resources` fixture auto-loads via the `pytest11` entry point — no imports in your
|
|
39
|
-
`conftest.py`.
|
|
48
|
+
`conftest.py`. Everything (index, navigation, synthesis) is async-test friendly:
|
|
49
|
+
`make`/`batch` are pure in-memory CPU and `abuild_resources`/`awalk` keep the loop free;
|
|
50
|
+
calling a synthesis method without its extra raises `ExtraNotInstalledError` with the
|
|
51
|
+
exact install command — the plugin never hard-depends on polyfactory or faker-file.
|
|
40
52
|
|
|
41
53
|
## What you get
|
|
42
54
|
|
|
@@ -8,7 +8,7 @@ same loader table as any authored resource.
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
from dataclasses import dataclass
|
|
11
|
-
from typing import TYPE_CHECKING, Any
|
|
11
|
+
from typing import TYPE_CHECKING, Any, TypedDict
|
|
12
12
|
|
|
13
13
|
import attrs
|
|
14
14
|
import msgspec
|
|
@@ -45,6 +45,11 @@ class Book:
|
|
|
45
45
|
pages: int
|
|
46
46
|
|
|
47
47
|
|
|
48
|
+
class Row(TypedDict):
|
|
49
|
+
k: str
|
|
50
|
+
v: int
|
|
51
|
+
|
|
52
|
+
|
|
48
53
|
@pytest.fixture
|
|
49
54
|
def tree(tmp_path: Path) -> Resources:
|
|
50
55
|
return pr.build_resources(tmp_path)
|
|
@@ -62,6 +67,18 @@ def test_make_autodetects_every_model_family(tree: Resources, model: type[Any])
|
|
|
62
67
|
assert isinstance(tree.make(model), model)
|
|
63
68
|
|
|
64
69
|
|
|
70
|
+
def test_make_builds_a_typeddict_model(tree: Resources) -> None:
|
|
71
|
+
row = tree.make(Row)
|
|
72
|
+
assert isinstance(row, dict)
|
|
73
|
+
assert set(row) == {"k", "v"}
|
|
74
|
+
assert isinstance(row["k"], str)
|
|
75
|
+
assert isinstance(row["v"], int)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_batch_defaults_to_ten(tree: Resources) -> None:
|
|
79
|
+
assert len(tree.batch(User)) == 10
|
|
80
|
+
|
|
81
|
+
|
|
65
82
|
def test_batch_returns_n_instances(tree: Resources) -> None:
|
|
66
83
|
squad = tree.batch(User, 4)
|
|
67
84
|
assert [type(item) for item in squad] == [User] * 4
|
|
@@ -120,7 +137,10 @@ def test_make_is_reproducible_under_a_seed(tree: Resources) -> None:
|
|
|
120
137
|
)
|
|
121
138
|
@pytest.mark.filterwarnings("ignore:imghdr was removed in Python 3.13:DeprecationWarning")
|
|
122
139
|
def test_file_writes_a_real_non_empty_file(tree: Resources, kind: FileType) -> None:
|
|
123
|
-
|
|
140
|
+
try:
|
|
141
|
+
path = tree.file(kind)
|
|
142
|
+
except OSError as exc:
|
|
143
|
+
pytest.skip(f"faker-file cannot synthesize {kind.value} here: {exc}") # needs a system font / no temp lock
|
|
124
144
|
assert path.exists()
|
|
125
145
|
assert path.stat().st_size > 0
|
|
126
146
|
assert pr.FileType.of_path(path) is kind
|
|
@@ -133,7 +153,7 @@ def test_file_resolves_a_suffix_from_a_filename(tree: Resources) -> None:
|
|
|
133
153
|
|
|
134
154
|
def test_named_file_is_adopted_and_decoded_like_an_authored_one(tree: Resources) -> None:
|
|
135
155
|
path = tree.file("txt", name="note")
|
|
136
|
-
assert tree.note == path.
|
|
156
|
+
assert tree.note == path.read_bytes().decode() # the node value is exactly the loader's decode
|
|
137
157
|
assert path in tree.paths("*.txt")
|
|
138
158
|
|
|
139
159
|
|
|
@@ -148,7 +168,10 @@ def test_csv_synthetic_stays_raw_bytes_until_a_loader_is_bound(tree: Resources)
|
|
|
148
168
|
|
|
149
169
|
|
|
150
170
|
def test_choice_and_walk_see_synthetic_files(tree: Resources) -> None:
|
|
151
|
-
|
|
171
|
+
try:
|
|
172
|
+
path = tree.file("png", name="logo")
|
|
173
|
+
except OSError as exc:
|
|
174
|
+
pytest.skip(f"faker-file cannot synthesize png here: {exc}") # needs a system font
|
|
152
175
|
assert tree.choice("*.png") == path.read_bytes()
|
|
153
176
|
assert path in list(tree.walk("*.png"))
|
|
154
177
|
|
|
@@ -16,6 +16,16 @@ from pytest_resources import FileType
|
|
|
16
16
|
(".cfg", FileType.INI),
|
|
17
17
|
(".jsonl", FileType.NDJSON),
|
|
18
18
|
(".md", FileType.MARKDOWN),
|
|
19
|
+
(".pdf", FileType.PDF),
|
|
20
|
+
(".docx", FileType.DOCX),
|
|
21
|
+
(".xlsx", FileType.XLSX),
|
|
22
|
+
(".jpg", FileType.JPEG),
|
|
23
|
+
(".jpeg", FileType.JPEG),
|
|
24
|
+
(".tif", FileType.TIFF),
|
|
25
|
+
(".tiff", FileType.TIFF),
|
|
26
|
+
(".webp", FileType.WEBP),
|
|
27
|
+
(".eml", FileType.EML),
|
|
28
|
+
(".zip", FileType.ZIP),
|
|
19
29
|
],
|
|
20
30
|
)
|
|
21
31
|
def test_filetype_of_known_suffix(suffix: str, expected: FileType) -> None:
|
|
@@ -9,6 +9,7 @@ from typing import TYPE_CHECKING
|
|
|
9
9
|
import pytest
|
|
10
10
|
|
|
11
11
|
from pytest_resources import build_resources
|
|
12
|
+
from pytest_resources.synth import SynthProvider
|
|
12
13
|
|
|
13
14
|
if TYPE_CHECKING:
|
|
14
15
|
from pytest_resources.nodes import Resources
|
|
@@ -50,6 +51,17 @@ def test_synth_module_stays_unloaded_until_first_use(tree: Resources) -> None:
|
|
|
50
51
|
assert tree._synth is None
|
|
51
52
|
|
|
52
53
|
|
|
54
|
+
def test_synth_is_built_once_and_memoized(tree: Resources) -> None:
|
|
55
|
+
tree.make(int)
|
|
56
|
+
assert isinstance(tree._synth, SynthProvider)
|
|
57
|
+
assert tree._common_synth() is tree._synth
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_assigned_synth_is_not_rebuilt(tree: Resources) -> None:
|
|
61
|
+
tree._synth = stub = _StubProvider()
|
|
62
|
+
assert tree._common_synth() is stub
|
|
63
|
+
|
|
64
|
+
|
|
53
65
|
def test_make_forwards_spec_seed_and_fields(tree: Resources) -> None:
|
|
54
66
|
tree._synth = stub = _StubProvider()
|
|
55
67
|
assert tree.make(User, seed=5, name="ada") == "OBJECT"
|
|
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
|
{pytest_resources-0.2.0 → pytest_resources-0.2.2}/tests/resources/structured/nested/deep.json
RENAMED
|
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
|