pytest-resources 0.2.2__tar.gz → 0.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.
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/CHANGELOG.md +26 -1
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/PKG-INFO +27 -12
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/README.md +26 -11
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/src/pytest_resources/__init__.py +2 -1
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/src/pytest_resources/loaders.py +33 -18
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/src/pytest_resources/synth.py +1 -2
- pytest_resources-0.3.0/tests/unit/test_loaders.py +68 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/unit/test_plugin.py +1 -1
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/unit/test_synth.py +1 -1
- pytest_resources-0.2.2/tests/unit/test_loaders.py +0 -59
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/.gitignore +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/LICENSE +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/pyproject.toml +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/src/pytest_resources/errors.py +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/src/pytest_resources/formats.py +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/src/pytest_resources/hooks.py +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/src/pytest_resources/index.py +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/src/pytest_resources/nodes.py +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/src/pytest_resources/plugin.py +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/src/pytest_resources/py.typed +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/integration/test_library.py +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/integration/test_synth_library.py +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/resources/binary/blob.dat +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/resources/config/app.ini +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/resources/config/manifest.jsonc +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/resources/config/settings.toml +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/resources/data/movies.csv +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/resources/structured/nested/deep.json +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/resources/structured/sample.json +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/resources/structured/sample2.json +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/resources/unstructured/sample.md +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/resources/unstructured/sample2.md +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/unit/test_formats.py +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/unit/test_hook.py +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/unit/test_index.py +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/unit/test_init.py +0 -0
- {pytest_resources-0.2.2 → pytest_resources-0.3.0}/tests/unit/test_nodes_synth.py +0 -0
|
@@ -6,6 +6,29 @@ adheres to [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.3.0] - 2026-09-25
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **The default loader is now the Python standard library** (`json` + `tomllib`): the core
|
|
14
|
+
ships with zero third-party dependencies. e-serde is no longer auto-selected when present,
|
|
15
|
+
so `JSONC` / `YAML` / `INI` decode to raw `bytes` unless you opt in.
|
|
16
|
+
- The `[serde]` extra is now an explicit opt-in on equal footing with `[objects]` /
|
|
17
|
+
`[files]`, documented as the recommended fast, multi-format official loader.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- `eserde_loaders()` (exported): the e-serde codec table. Register it from `conftest.py`
|
|
22
|
+
via `pytest_resource_loaders` to make e-serde the project's loader; it raises
|
|
23
|
+
`ExtraNotInstalledError` (naming the `[serde]` extra) when the extra is absent.
|
|
24
|
+
|
|
25
|
+
## [0.2.3] - 2026-09-25
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- `ExtraNotInstalledError` now emits a single **uv-only** install hint (dropped the
|
|
30
|
+
redundant `pip` line), matching the project's toolchain and the docs.
|
|
31
|
+
|
|
9
32
|
## [0.2.2] - 2026-09-24
|
|
10
33
|
|
|
11
34
|
### Changed
|
|
@@ -79,7 +102,9 @@ First release.
|
|
|
79
102
|
- A module-lifetime decode cache per tree, and typed misses (`EntryNotFoundError` /
|
|
80
103
|
`KeyError`) that carry a `difflib` "did you mean" hint.
|
|
81
104
|
|
|
82
|
-
[unreleased]: https://github.com/damvolkov/pytest-resources/compare/v0.
|
|
105
|
+
[unreleased]: https://github.com/damvolkov/pytest-resources/compare/v0.3.0...HEAD
|
|
106
|
+
[0.3.0]: https://github.com/damvolkov/pytest-resources/releases/tag/v0.3.0
|
|
107
|
+
[0.2.3]: https://github.com/damvolkov/pytest-resources/releases/tag/v0.2.3
|
|
83
108
|
[0.2.2]: https://github.com/damvolkov/pytest-resources/releases/tag/v0.2.2
|
|
84
109
|
[0.2.1]: https://github.com/damvolkov/pytest-resources/releases/tag/v0.2.1
|
|
85
110
|
[0.2.0]: https://github.com/damvolkov/pytest-resources/releases/tag/v0.2.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pytest-resources
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
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
|
|
@@ -33,10 +33,11 @@ Description-Content-Type: text/markdown
|
|
|
33
33
|
|
|
34
34
|
# pytest-resources
|
|
35
35
|
|
|
36
|
-
Lazy, typed, attribute-navigable fixtures for test resource files —
|
|
37
|
-
|
|
38
|
-
extensible to **any** canonical `bytes -> object` loader
|
|
39
|
-
|
|
36
|
+
Lazy, typed, attribute-navigable fixtures for test resource files — decoded through the
|
|
37
|
+
**Python standard library** by default (`json` + `tomllib`, zero extra dependencies),
|
|
38
|
+
extensible to **any** canonical `bytes -> object` loader. The optional
|
|
39
|
+
[`e-serde`](https://pypi.org/project/e-serde/) extra is **recommended** as the fast,
|
|
40
|
+
multi-format official loader; anything without a parser is handed back as raw `bytes`.
|
|
40
41
|
|
|
41
42
|
You point it at one or more directories of sample files; it recursively indexes the tree
|
|
42
43
|
without reading anything, and you reach, filter, randomise and synthesize parsed values
|
|
@@ -70,18 +71,18 @@ def test_profile(resources: pr.Resources):
|
|
|
70
71
|
## Install
|
|
71
72
|
|
|
72
73
|
```bash
|
|
73
|
-
uv add --group test
|
|
74
|
-
uv add --group test pytest-resources
|
|
74
|
+
uv add --group test pytest-resources # default: stdlib (json + tomllib), zero extra deps
|
|
75
|
+
uv add --group test "pytest-resources[serde]" # e-serde — fast, multi-format loader (recommended)
|
|
75
76
|
uv add --group test "pytest-resources[objects]" # resources.make()/batch(): random model objects
|
|
76
77
|
uv add --group test "pytest-resources[files]" # resources.file(): synthetic files, 25 formats
|
|
77
|
-
uv add --group test "pytest-resources[random]" # both
|
|
78
|
+
uv add --group test "pytest-resources[random]" # both synthesis backends
|
|
78
79
|
```
|
|
79
80
|
|
|
80
81
|
The `resources` fixture auto-loads via the `pytest11` entry point — no imports in your
|
|
81
82
|
`conftest.py`. Everything (index, navigation, synthesis) is async-test friendly:
|
|
82
83
|
`make`/`batch` are pure in-memory CPU and `abuild_resources`/`awalk` keep the loop free;
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
a missing extra raises `ExtraNotInstalledError` with the exact install command — the plugin
|
|
85
|
+
never hard-depends on e-serde, polyfactory or faker-file.
|
|
85
86
|
|
|
86
87
|
## What you get
|
|
87
88
|
|
|
@@ -97,7 +98,7 @@ exact install command — the plugin never hard-depends on polyfactory or faker-
|
|
|
97
98
|
| **Open-ended fallback** | `CSV`/`TSV`/`PDF`/… and any unknown kind stay raw `bytes` |
|
|
98
99
|
| **Many roots, one tree** | CLI / ini / `pytest_resources_roots` hook, merged (later wins), auto-created |
|
|
99
100
|
| **Pluggable codecs** | override or add any kind through the `pytest_resource_loaders` hook |
|
|
100
|
-
| **e-serde
|
|
101
|
+
| **Stdlib default, e-serde opt-in** | `json`/`tomllib` by default; register `eserde_loaders()` for the fast multi-format backend |
|
|
101
102
|
| **Friendly misses** | `EntryNotFoundError` / `KeyError` carry a "did you mean" hint |
|
|
102
103
|
|
|
103
104
|
## Configuring the roots
|
|
@@ -139,6 +140,19 @@ def pytest_resource_loaders(register):
|
|
|
139
140
|
`register` merges into the session's table, so you can override a default kind as easily
|
|
140
141
|
as add an unknown one. Kinds left unbound hand back **raw bytes**.
|
|
141
142
|
|
|
143
|
+
### The recommended official loader: e-serde
|
|
144
|
+
|
|
145
|
+
The default is the standard library. Install the `[serde]` extra and register one call to
|
|
146
|
+
make [`e-serde`](https://pypi.org/project/e-serde/) your official loader — ultrarapid,
|
|
147
|
+
native Rust/C, and it decodes JSONC/YAML/INI too:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from pytest_resources import eserde_loaders
|
|
151
|
+
|
|
152
|
+
def pytest_resource_loaders(register):
|
|
153
|
+
register(eserde_loaders())
|
|
154
|
+
```
|
|
155
|
+
|
|
142
156
|
## Programmatic use
|
|
143
157
|
|
|
144
158
|
Outside pytest, build a tree yourself:
|
|
@@ -150,7 +164,8 @@ import pytest_resources as pr
|
|
|
150
164
|
tree = pr.build_resources(Path("fixtures")) # sync, one root
|
|
151
165
|
tree = pr.build_resources([Path("a"), Path("b")]) # merged roots, later wins
|
|
152
166
|
tree = await pr.abuild_resources(Path("fixtures")) # off the event loop
|
|
153
|
-
table = pr.default_loaders() #
|
|
167
|
+
table = pr.default_loaders() # stdlib codecs (json + tomllib)
|
|
168
|
+
tree = pr.build_resources(Path("fixtures"), pr.eserde_loaders()) # opt into e-serde instead
|
|
154
169
|
```
|
|
155
170
|
|
|
156
171
|
## Development
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# pytest-resources
|
|
2
2
|
|
|
3
|
-
Lazy, typed, attribute-navigable fixtures for test resource files —
|
|
4
|
-
|
|
5
|
-
extensible to **any** canonical `bytes -> object` loader
|
|
6
|
-
|
|
3
|
+
Lazy, typed, attribute-navigable fixtures for test resource files — decoded through the
|
|
4
|
+
**Python standard library** by default (`json` + `tomllib`, zero extra dependencies),
|
|
5
|
+
extensible to **any** canonical `bytes -> object` loader. The optional
|
|
6
|
+
[`e-serde`](https://pypi.org/project/e-serde/) extra is **recommended** as the fast,
|
|
7
|
+
multi-format official loader; anything without a parser is handed back as raw `bytes`.
|
|
7
8
|
|
|
8
9
|
You point it at one or more directories of sample files; it recursively indexes the tree
|
|
9
10
|
without reading anything, and you reach, filter, randomise and synthesize parsed values
|
|
@@ -37,18 +38,18 @@ def test_profile(resources: pr.Resources):
|
|
|
37
38
|
## Install
|
|
38
39
|
|
|
39
40
|
```bash
|
|
40
|
-
uv add --group test
|
|
41
|
-
uv add --group test pytest-resources
|
|
41
|
+
uv add --group test pytest-resources # default: stdlib (json + tomllib), zero extra deps
|
|
42
|
+
uv add --group test "pytest-resources[serde]" # e-serde — fast, multi-format loader (recommended)
|
|
42
43
|
uv add --group test "pytest-resources[objects]" # resources.make()/batch(): random model objects
|
|
43
44
|
uv add --group test "pytest-resources[files]" # resources.file(): synthetic files, 25 formats
|
|
44
|
-
uv add --group test "pytest-resources[random]" # both
|
|
45
|
+
uv add --group test "pytest-resources[random]" # both synthesis backends
|
|
45
46
|
```
|
|
46
47
|
|
|
47
48
|
The `resources` fixture auto-loads via the `pytest11` entry point — no imports in your
|
|
48
49
|
`conftest.py`. Everything (index, navigation, synthesis) is async-test friendly:
|
|
49
50
|
`make`/`batch` are pure in-memory CPU and `abuild_resources`/`awalk` keep the loop free;
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
a missing extra raises `ExtraNotInstalledError` with the exact install command — the plugin
|
|
52
|
+
never hard-depends on e-serde, polyfactory or faker-file.
|
|
52
53
|
|
|
53
54
|
## What you get
|
|
54
55
|
|
|
@@ -64,7 +65,7 @@ exact install command — the plugin never hard-depends on polyfactory or faker-
|
|
|
64
65
|
| **Open-ended fallback** | `CSV`/`TSV`/`PDF`/… and any unknown kind stay raw `bytes` |
|
|
65
66
|
| **Many roots, one tree** | CLI / ini / `pytest_resources_roots` hook, merged (later wins), auto-created |
|
|
66
67
|
| **Pluggable codecs** | override or add any kind through the `pytest_resource_loaders` hook |
|
|
67
|
-
| **e-serde
|
|
68
|
+
| **Stdlib default, e-serde opt-in** | `json`/`tomllib` by default; register `eserde_loaders()` for the fast multi-format backend |
|
|
68
69
|
| **Friendly misses** | `EntryNotFoundError` / `KeyError` carry a "did you mean" hint |
|
|
69
70
|
|
|
70
71
|
## Configuring the roots
|
|
@@ -106,6 +107,19 @@ def pytest_resource_loaders(register):
|
|
|
106
107
|
`register` merges into the session's table, so you can override a default kind as easily
|
|
107
108
|
as add an unknown one. Kinds left unbound hand back **raw bytes**.
|
|
108
109
|
|
|
110
|
+
### The recommended official loader: e-serde
|
|
111
|
+
|
|
112
|
+
The default is the standard library. Install the `[serde]` extra and register one call to
|
|
113
|
+
make [`e-serde`](https://pypi.org/project/e-serde/) your official loader — ultrarapid,
|
|
114
|
+
native Rust/C, and it decodes JSONC/YAML/INI too:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from pytest_resources import eserde_loaders
|
|
118
|
+
|
|
119
|
+
def pytest_resource_loaders(register):
|
|
120
|
+
register(eserde_loaders())
|
|
121
|
+
```
|
|
122
|
+
|
|
109
123
|
## Programmatic use
|
|
110
124
|
|
|
111
125
|
Outside pytest, build a tree yourself:
|
|
@@ -117,7 +131,8 @@ import pytest_resources as pr
|
|
|
117
131
|
tree = pr.build_resources(Path("fixtures")) # sync, one root
|
|
118
132
|
tree = pr.build_resources([Path("a"), Path("b")]) # merged roots, later wins
|
|
119
133
|
tree = await pr.abuild_resources(Path("fixtures")) # off the event loop
|
|
120
|
-
table = pr.default_loaders() #
|
|
134
|
+
table = pr.default_loaders() # stdlib codecs (json + tomllib)
|
|
135
|
+
tree = pr.build_resources(Path("fixtures"), pr.eserde_loaders()) # opt into e-serde instead
|
|
121
136
|
```
|
|
122
137
|
|
|
123
138
|
## Development
|
|
@@ -14,7 +14,7 @@ from importlib.metadata import PackageNotFoundError, version
|
|
|
14
14
|
from pytest_resources.errors import EntryNotFoundError, ExtraNotInstalledError, ResourceError
|
|
15
15
|
from pytest_resources.formats import FileType
|
|
16
16
|
from pytest_resources.index import abuild_resources, build_resources
|
|
17
|
-
from pytest_resources.loaders import Loader, default_loaders
|
|
17
|
+
from pytest_resources.loaders import Loader, default_loaders, eserde_loaders
|
|
18
18
|
from pytest_resources.nodes import ResourceNode, Resources
|
|
19
19
|
|
|
20
20
|
try:
|
|
@@ -34,4 +34,5 @@ __all__ = [
|
|
|
34
34
|
"abuild_resources",
|
|
35
35
|
"build_resources",
|
|
36
36
|
"default_loaders",
|
|
37
|
+
"eserde_loaders",
|
|
37
38
|
]
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
"""pytest_resources.loaders: pluggable decoders, e-serde
|
|
1
|
+
"""pytest_resources.loaders: pluggable decoders, stdlib by default, e-serde opt-in.
|
|
2
2
|
|
|
3
|
-
The system accepts any canonical ``bytes -> object`` loader. ``default_loaders``
|
|
4
|
-
returns the
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
The system accepts any canonical ``bytes -> object`` loader. ``default_loaders()``
|
|
4
|
+
returns the standard-library table (``json`` + ``tomllib``) — the light, dependency-free
|
|
5
|
+
default. [`e-serde`](https://pypi.org/project/e-serde/) is an optional ``[serde]`` extra:
|
|
6
|
+
call :func:`eserde_loaders` and register it to swap in the fast, multi-format backend.
|
|
7
|
+
Kinds with no parser hand back raw bytes for the caller to decode.
|
|
7
8
|
"""
|
|
8
9
|
|
|
9
10
|
from __future__ import annotations
|
|
@@ -14,6 +15,7 @@ from functools import partial
|
|
|
14
15
|
from tomllib import loads as _toml_loads
|
|
15
16
|
from typing import Any
|
|
16
17
|
|
|
18
|
+
from pytest_resources.errors import ExtraNotInstalledError
|
|
17
19
|
from pytest_resources.formats import FileType
|
|
18
20
|
|
|
19
21
|
Loader = Callable[[bytes], Any]
|
|
@@ -39,10 +41,33 @@ def _lines(loader: Loader, data: bytes) -> list[Any]:
|
|
|
39
41
|
return [loader(line) for line in data.splitlines() if line.strip()]
|
|
40
42
|
|
|
41
43
|
|
|
42
|
-
def
|
|
43
|
-
"""
|
|
44
|
-
|
|
44
|
+
def default_loaders() -> dict[FileType, Loader]:
|
|
45
|
+
"""The default codec table — the standard library only; kinds without one stay bytes."""
|
|
46
|
+
table: dict[FileType, Loader] = dict.fromkeys(FileType, _raw)
|
|
47
|
+
table |= _stdlib_loaders()
|
|
48
|
+
return table
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def eserde_loaders() -> dict[FileType, Loader]:
|
|
52
|
+
"""The recommended fast table backed by e-serde — needs the optional `[serde]` extra.
|
|
53
|
+
|
|
54
|
+
Register it from a ``conftest.py`` to make e-serde the project's official loader::
|
|
55
|
+
|
|
56
|
+
from pytest_resources import eserde_loaders
|
|
57
|
+
|
|
45
58
|
|
|
59
|
+
def pytest_resource_loaders(register):
|
|
60
|
+
register(eserde_loaders())
|
|
61
|
+
"""
|
|
62
|
+
try:
|
|
63
|
+
from eserde import Format, loads # noqa: PLC0415 -- optional fast path, not a core dep
|
|
64
|
+
except ImportError as exc:
|
|
65
|
+
msg = (
|
|
66
|
+
"`eserde_loaders()` requires the 'serde' extra.\n"
|
|
67
|
+
'Install it with: uv add --group test "pytest-resources[serde]"\n'
|
|
68
|
+
"Underlying import failed: eserde"
|
|
69
|
+
)
|
|
70
|
+
raise ExtraNotInstalledError(msg) from exc
|
|
46
71
|
json_row = partial(loads, format=Format.JSON)
|
|
47
72
|
return {
|
|
48
73
|
FileType.JSON: json_row,
|
|
@@ -65,13 +90,3 @@ def _stdlib_loaders() -> dict[FileType, Loader]:
|
|
|
65
90
|
FileType.MARKDOWN: _text,
|
|
66
91
|
FileType.TEXT: _text,
|
|
67
92
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def default_loaders() -> dict[FileType, Loader]:
|
|
71
|
-
"""A fresh codec table: e-serde when importable, else the stdlib; other kinds stay bytes."""
|
|
72
|
-
table: dict[FileType, Loader] = dict.fromkeys(FileType, _raw)
|
|
73
|
-
try:
|
|
74
|
-
table |= _eserde_loaders()
|
|
75
|
-
except ImportError:
|
|
76
|
-
table |= _stdlib_loaders()
|
|
77
|
-
return table
|
|
@@ -116,8 +116,7 @@ class SynthProvider:
|
|
|
116
116
|
return
|
|
117
117
|
msg = (
|
|
118
118
|
f"`Resources.{method}()` requires the '{extra}' extra.\n"
|
|
119
|
-
f'Install it with: uv add --group test "pytest-resources[{extra}]"
|
|
120
|
-
f'(pip: pip install "pytest-resources[{extra}]")\n'
|
|
119
|
+
f'Install it with: uv add --group test "pytest-resources[{extra}]"\n'
|
|
121
120
|
f"Underlying import failed: {module}"
|
|
122
121
|
)
|
|
123
122
|
raise ExtraNotInstalledError(msg)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""tests/unit: the loader tables — the stdlib default and the opt-in e-serde table."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from pytest_resources import FileType
|
|
9
|
+
from pytest_resources.errors import ExtraNotInstalledError
|
|
10
|
+
from pytest_resources.loaders import _lines, _raw, _text, default_loaders, eserde_loaders
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_default_loaders_covers_every_kind() -> None:
|
|
14
|
+
assert set(default_loaders()) == set(FileType)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_default_loaders_is_stdlib() -> None:
|
|
18
|
+
table = default_loaders()
|
|
19
|
+
assert table[FileType.JSON](b'{"a": 1, "b": [1, 2]}') == {"a": 1, "b": [1, 2]}
|
|
20
|
+
assert table[FileType.TOML](b"a = 1\n") == {"a": 1}
|
|
21
|
+
assert table[FileType.NDJSON](b'{"i": 1}\n\n{"i": 2}') == [{"i": 1}, {"i": 2}]
|
|
22
|
+
assert table[FileType.MARKDOWN](b"# t\n") == "# t\n"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@pytest.mark.parametrize("fmt", [FileType.CSV, FileType.YAML, FileType.INI, FileType.JSONC, FileType.HTML])
|
|
26
|
+
def test_default_loaders_leaves_the_rest_as_bytes(fmt: FileType) -> None:
|
|
27
|
+
assert default_loaders()[fmt](b"raw") == b"raw" # no stdlib codec -> honest bytes
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_default_loaders_does_not_pick_eserde() -> None:
|
|
31
|
+
pytest.importorskip("eserde") # e-serde is optional: the default must ignore it, even when installed
|
|
32
|
+
assert default_loaders()[FileType.JSONC](b'{"a": 1}') == b'{"a": 1}'
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.mark.parametrize(
|
|
36
|
+
("fmt", "blob", "want"),
|
|
37
|
+
[
|
|
38
|
+
(FileType.JSON, b'{"a": 1}', {"a": 1}),
|
|
39
|
+
(FileType.JSONC, b'{"a": 1 /* c */}', {"a": 1}),
|
|
40
|
+
(FileType.INI, b"[s]\nk = v\n", {"s": {"k": "v"}}),
|
|
41
|
+
(FileType.TOML, b"a = 1\n", {"a": 1}),
|
|
42
|
+
(FileType.YAML, b"a: 1\n", {"a": 1}),
|
|
43
|
+
],
|
|
44
|
+
)
|
|
45
|
+
def test_eserde_loaders_decodes_config_kinds(fmt: FileType, blob: bytes, want: dict) -> None:
|
|
46
|
+
pytest.importorskip("eserde")
|
|
47
|
+
assert eserde_loaders()[fmt](blob) == want
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_eserde_loaders_requires_the_extra(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
51
|
+
monkeypatch.setitem(sys.modules, "eserde", None) # forces the ImportError path
|
|
52
|
+
with pytest.raises(ExtraNotInstalledError) as exc:
|
|
53
|
+
eserde_loaders()
|
|
54
|
+
assert "pytest-resources[serde]" in str(exc.value)
|
|
55
|
+
assert "uv add" in str(exc.value)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_eserde_loaders_is_importable_without_calling_it() -> None:
|
|
59
|
+
assert callable(eserde_loaders) # importing loaders must not import e-serde eagerly
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_lines_splits_and_decodes_per_line() -> None:
|
|
63
|
+
assert _lines(json.loads, b'{"i": 1}\n\n{"i": 2}\n') == [{"i": 1}, {"i": 2}]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_text_and_raw_helpers() -> None:
|
|
67
|
+
assert _text("café".encode()) == "café"
|
|
68
|
+
assert _raw(b"x") == b"x"
|
|
@@ -35,7 +35,7 @@ def test_resources_fixture_is_indexed_tree(resources: Resources) -> None:
|
|
|
35
35
|
assert isinstance(resources, pr.Resources)
|
|
36
36
|
assert resources.structured.sample["id"] == "sample1"
|
|
37
37
|
assert resources.config.settings["owner"]["name"] == "damien"
|
|
38
|
-
assert resources.config.manifest
|
|
38
|
+
assert isinstance(resources.config.manifest, bytes) # JSONC has no stdlib codec -> bytes by default
|
|
39
39
|
assert isinstance(resources.unstructured.sample, str)
|
|
40
40
|
|
|
41
41
|
|
|
@@ -39,7 +39,7 @@ def test_synth_file_without_files_explains_the_extra(monkeypatch: pytest.MonkeyP
|
|
|
39
39
|
provider.file(FileType.PDF)
|
|
40
40
|
msg = str(excinfo.value)
|
|
41
41
|
assert "pytest-resources[files]" in msg
|
|
42
|
-
assert "
|
|
42
|
+
assert "uv add" in msg
|
|
43
43
|
assert "faker-file" in msg
|
|
44
44
|
assert "file" in msg
|
|
45
45
|
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
"""tests/unit: the pluggable loader table and its e-serde / stdlib backends."""
|
|
2
|
-
|
|
3
|
-
import json
|
|
4
|
-
import sys
|
|
5
|
-
|
|
6
|
-
import pytest
|
|
7
|
-
|
|
8
|
-
from pytest_resources import FileType
|
|
9
|
-
from pytest_resources.loaders import _lines, _raw, _text, default_loaders
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def test_default_loaders_covers_every_kind() -> None:
|
|
13
|
-
assert set(default_loaders()) == set(FileType)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def test_json_kind_decodes_to_native_dict() -> None:
|
|
17
|
-
assert default_loaders()[FileType.JSON](b'{"a": 1, "b": [1, 2]}') == {"a": 1, "b": [1, 2]}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def test_text_and_markdown_decode_to_str() -> None:
|
|
21
|
-
table = default_loaders()
|
|
22
|
-
assert table[FileType.TEXT](b"hi") == "hi"
|
|
23
|
-
assert isinstance(table[FileType.MARKDOWN](b"# t\n"), str)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def test_unbound_kind_hands_back_raw_bytes() -> None:
|
|
27
|
-
assert default_loaders()[FileType.CSV](b"a,b") == b"a,b"
|
|
28
|
-
assert _raw(b"x") == b"x"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def test_lines_splits_and_decodes_per_line() -> None:
|
|
32
|
-
assert _lines(json.loads, b'{"i": 1}\n\n{"i": 2}\n') == [{"i": 1}, {"i": 2}]
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def test_text_helper_decodes_utf8() -> None:
|
|
36
|
-
assert _text("café".encode()) == "café"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def test_stdlib_fallback_when_eserde_absent(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
40
|
-
monkeypatch.setitem(sys.modules, "eserde", None) # forces ImportError inside default_loaders
|
|
41
|
-
table = default_loaders()
|
|
42
|
-
assert table[FileType.JSON](b'{"a": 1}') == {"a": 1}
|
|
43
|
-
assert table[FileType.TOML](b"a = 1\n") == {"a": 1}
|
|
44
|
-
assert table[FileType.NDJSON](b'{"i": 1}\n{"i": 2}') == [{"i": 1}, {"i": 2}]
|
|
45
|
-
assert table[FileType.INI](b"[s]\nk=v") == b"[s]\nk=v" # not a stdlib codec -> bytes
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@pytest.mark.parametrize(
|
|
49
|
-
("fmt", "blob", "want"),
|
|
50
|
-
[
|
|
51
|
-
(FileType.JSONC, b'{"a": 1 /* c */}', {"a": 1}),
|
|
52
|
-
(FileType.INI, b"[s]\nk = v\n", {"s": {"k": "v"}}),
|
|
53
|
-
(FileType.TOML, b"a = 1\n", {"a": 1}),
|
|
54
|
-
(FileType.YAML, b"a: 1\n", {"a": 1}),
|
|
55
|
-
],
|
|
56
|
-
)
|
|
57
|
-
def test_eserde_native_config_kinds(fmt: FileType, blob: bytes, want: dict) -> None:
|
|
58
|
-
pytest.importorskip("eserde")
|
|
59
|
-
assert default_loaders()[fmt](blob) == want
|
|
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.2 → pytest_resources-0.3.0}/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
|