doeff-hy-pytest 0.5.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.
@@ -0,0 +1,142 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ # macOS debug symbols for the compiled extension above: build output that
7
+ # embeds the builder's absolute paths, so it must not be distributed either.
8
+ *.dSYM/
9
+ .Python
10
+ env/
11
+ venv/
12
+ .venv/
13
+ ENV/
14
+ env.bak/
15
+ venv.bak/
16
+ .env
17
+ .env.*
18
+
19
+ # Distribution / packaging
20
+ .Python
21
+ build/
22
+ develop-eggs/
23
+ dist/
24
+ downloads/
25
+ eggs/
26
+ .eggs/
27
+ lib/
28
+ lib64/
29
+ parts/
30
+ sdist/
31
+ var/
32
+ wheels/
33
+ *.egg-info/
34
+ .installed.cfg
35
+ *.egg
36
+ MANIFEST
37
+
38
+ # Testing
39
+ .pytest_cache/
40
+ .coverage
41
+ .coverage.*
42
+ coverage.xml
43
+ *.cover
44
+ .hypothesis/
45
+ htmlcov/
46
+ .tox/
47
+
48
+ # IDE
49
+ # Generated by Eclipse buildship and machine-specific: embeds the local Java home
50
+ # and toolchain paths. The gradle build does not read it.
51
+ ide-plugins/pycharm/.settings/org.eclipse.buildship.core.prefs
52
+ .idea/
53
+ .vscode/
54
+ *.swp
55
+ *.swo
56
+ *~
57
+ .DS_Store
58
+
59
+ # UV
60
+ !uv.lock
61
+ .venv/
62
+
63
+ # Ruff
64
+ .ruff_cache/
65
+
66
+ # MyPy
67
+ .mypy_cache/
68
+ .dmypy.json
69
+ dmypy.json
70
+
71
+ # Generated logs, traces, and local databases
72
+ .doeff-lint.jsonl
73
+ .doeff-flow/
74
+ *.jsonl
75
+ # 旧い版の coordinator の置き場の log(版上げの下見の検 test_deployed_state_upgrade.hy が読む fixture — 生成された log ではない)
76
+ !packages/doeff-cluster/tests/fixtures/coordinator_state_*/wal/wal.jsonl
77
+ # codex の app-server の実物の行を録った物(行の分類の検 packages/doeff-codex/tests/test_lines.hy が読む fixture — 生成された log ではない)
78
+ !packages/doeff-codex/tests/recorded/codex-*/*.jsonl
79
+ *.db
80
+ *.db-journal
81
+ *.db-shm
82
+ *.db-wal
83
+ *.sqlite
84
+ *.sqlite-journal
85
+ *.sqlite-shm
86
+ *.sqlite-wal
87
+ *.sqlite3
88
+ *.sqlite3-journal
89
+ *.sqlite3-shm
90
+ *.sqlite3-wal
91
+ None
92
+ Untitled
93
+
94
+ # Local agent and browser automation state
95
+ .agent-home/
96
+ .playwright-mcp/
97
+ .claude/settings.local.json
98
+ .claude/skills/install-vscode-plugin/
99
+ .agents/skills/install-vscode-plugin/
100
+
101
+ # Accidental desktop helper bundle captured at repository root
102
+ /server.js
103
+
104
+ # Rust build artifacts
105
+ rust/**/target/
106
+ packages/**/target/
107
+
108
+ # Local deploy keys
109
+ proboscis_doeff_deploy
110
+ proboscis_doeff_deploy.pub
111
+
112
+ # Worktrees and orchestration
113
+ .git-worktrees/
114
+ .orch/
115
+ .sisyphus/
116
+ VAULT
117
+
118
+ # Override global gitignore for examples
119
+ !examples/
120
+ ORCH_PROMPT.md
121
+ .worktrees/
122
+
123
+ # Local workspace artifacts
124
+ # Repo-root scratch directory only. A `python/` directory inside a package
125
+ # (e.g. packages/doeff-indexer/python/) is NOT covered by this rule.
126
+ /python/
127
+
128
+
129
+ # 設計記録は repo に入れる — global の除外(`artifacts` の dir・`*.html`・`*.svg`)を打ち消す
130
+ # (打ち消しは dir を先に戻さないと中身に効かない)
131
+ !docs/design/*/artifacts/
132
+ !docs/design/**
133
+ # 書き込みロックだけは入れない(道具が作る一時 file — 打ち消しの後に置く)
134
+ docs/design/*/.records.lock
135
+
136
+ # Repository-owned Zenn article visuals (override global image ignores)
137
+ !/images/zenn-use-cases-v0/*.png
138
+ # 記事が参照する採用画像は generated/ の下に在る(上の行は直下だけに効き、2026-09-16 の 47 枚は入らなかった)
139
+ !/images/zenn-use-cases-v0/generated/
140
+ !/images/zenn-use-cases-v0/generated/*.png
141
+ # 手で書いた図の正本(global の `*.svg` の除外を打ち消す)
142
+ !/publications/zenn-use-cases-v0/visuals/*.svg
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 proboscis contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,163 @@
1
+ Metadata-Version: 2.5
2
+ Name: doeff-hy-pytest
3
+ Version: 0.5.0
4
+ Summary: pytest plugin for doeff-hy tests: a Python 3.14 fix for Hy and optional per-test time limits
5
+ Project-URL: Homepage, https://github.com/proboscis/doeff/tree/main/packages/doeff-hy-pytest
6
+ Project-URL: Repository, https://github.com/proboscis/doeff
7
+ Project-URL: Issues, https://github.com/proboscis/doeff/issues
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Requires-Python: >=3.11
11
+ Description-Content-Type: text/markdown
12
+
13
+ # doeff-hy-pytest
14
+
15
+ The pytest plugin for tests written with
16
+ [doeff-hy](https://github.com/proboscis/doeff/tree/main/packages/doeff-hy).
17
+
18
+ **This README is for** developers who run pytest on Hy code that uses doeff. After
19
+ reading it you know what the plugin does without any setting, and how to turn on its
20
+ optional time limits for tests.
21
+
22
+ ## What it does
23
+
24
+ pytest loads the plugin by itself (entry point `pytest11`, name `doeff_hy`). It does
25
+ two things:
26
+
27
+ | Job | When it acts | Setting needed |
28
+ | --- | --- | --- |
29
+ | Fixes a Hy problem on Python 3.14 | At pytest start-up, before any conftest imports Hy | None |
30
+ | Time limits for Hy tests | During each test in a `.hy` file | Yes; off by default |
31
+
32
+ **The Python 3.14 fix.** Hy replaces `ast.unparse`. On Python 3.14, when pytest reads
33
+ fixture annotations as strings, that replacement recurses without end. The plugin
34
+ installs a corrected replacement (`doeff_hy.ast_unparse.install()`) as soon as pytest
35
+ starts, so it is in place even if a conftest or another plugin imports Hy first.
36
+
37
+ **Why this is a separate package.** pytest marks every module of a distribution that
38
+ declares a `pytest11` entry point for assertion rewriting. If doeff-hy itself declared
39
+ the entry point, pytest would try to rewrite doeff-hy's `.hy` files as Python and the
40
+ import would fail with a `SyntaxError`. This package contains no `.hy` files, so the
41
+ mark is harmless here.
42
+
43
+ The plugin does **not** collect `.hy` test files. The doeff-hy README shows the
44
+ `conftest.py` hook that collects them:
45
+ [Testing with deftest](https://github.com/proboscis/doeff/tree/main/packages/doeff-hy#testing-with-deftest).
46
+
47
+ ## Installation
48
+
49
+ doeff-hy depends on this package, so it is already installed when doeff or doeff-hy
50
+ is:
51
+
52
+ ```bash
53
+ pip install doeff # installs doeff-hy and doeff-hy-pytest
54
+ ```
55
+
56
+ You do not list it yourself. The exception: if you install doeff-hy from a git
57
+ revision with uv, add a `[tool.uv.sources]` entry for doeff-hy-pytest from the same
58
+ revision.
59
+
60
+ To check that pytest loaded it, look for `doeff-hy-pytest` in the `plugins:` line of
61
+ `pytest` output, or in the plugins that `pytest -VV` lists:
62
+
63
+ ```bash run
64
+ pytest -VV # doeff-hy-pytest
65
+ ```
66
+
67
+ ## Time limits for Hy tests
68
+
69
+ Tests that run programs against in-memory or scripted handlers should be fast. The
70
+ limits tell you when one of them becomes slow. They apply only to tests defined in
71
+ `.hy` files (`deftest` and plain test functions in the same file); Python test files
72
+ are not measured. With none of the three limits set, the plugin measures nothing.
73
+
74
+ ### The three limits
75
+
76
+ | Setting | What it limits | Unit | How it is measured |
77
+ | --- | --- | --- | --- |
78
+ | `doeff_test_call_budget_steps` | Running one test (pytest's `call` phase; fixture setup and teardown are not included) | doeff-vm steps (a positive integer, or `default` = 100,000) | Steps the VM executed. The count does not depend on machine load; CPU seconds are reported but not judged |
79
+ | `doeff_test_call_budget_by_marker` | Running one test that carries a given pytest mark | Wall-clock seconds, one line per mark: `mark=seconds` | For tests that do real I/O (child processes, sockets), whose cost does not show up as VM steps. A test that matches a line is judged by seconds even when a step limit is set; if several lines match, the longest limit applies |
80
+ | `doeff_test_collect_budget_seconds` | Importing one `.hy` test file | CPU seconds | Only when the file is imported through the `pytest_doeff_import_hy_module` hook, which the collector of [doeff-adr](https://github.com/proboscis/doeff/tree/main/packages/doeff-adr) calls. With the plain `conftest.py` collector from the doeff-hy README, nothing is measured |
81
+
82
+ A test that matches no `by_marker` line is judged by steps if a step limit is set, and
83
+ is not measured otherwise. A test that executes 0 steps (it only reads data and never
84
+ runs the VM) is within the limit.
85
+
86
+ Measured time excludes work that is not the test's own cost: compiling source to
87
+ bytecode when no cache exists, the first import of another module (a one-time cost of
88
+ a shared dependency), and garbage collection. Each is subtracted on the same clock
89
+ that is being judged.
90
+
91
+ ### What happens when a test goes over
92
+
93
+ | Setting | Values |
94
+ | --- | --- |
95
+ | `doeff_test_budget_mode` | `report` (default): warn and list the slow tests at the end. `fail`: the slow test fails |
96
+ | `doeff_test_budget_registry` | Directories (relative to the pytest rootdir, one per line) that list tests allowed to go over. One file per test: `<first 12 hex chars of sha256(key)>.txt`; line 1 is the key (the pytest node id, or the file path relative to rootdir for the collection limit), the following lines give the reason. When a test goes over, the message names the file to add in the first directory |
97
+
98
+ In `fail` mode, a listed test that finishes in at most half of its limit also fails,
99
+ as a stale entry, and the message names the file to delete. Between half the limit and
100
+ the limit, the summary only reports that the entry can be removed.
101
+
102
+ ### Example
103
+
104
+ ```toml
105
+ [tool.pytest.ini_options]
106
+ doeff_test_call_budget_steps = "default"
107
+ doeff_test_call_budget_by_marker = ["real_world=10"]
108
+ doeff_test_collect_budget_seconds = 1.0
109
+ doeff_test_budget_mode = "fail"
110
+ doeff_test_budget_registry = ["tests/over-budget"]
111
+ ```
112
+
113
+ With this configuration, each Hy test may run 100,000 VM steps; a test marked
114
+ `real_world` may take 10 seconds of wall-clock time instead; a test over its limit
115
+ fails unless `tests/over-budget` lists it.
116
+
117
+ ### More settings
118
+
119
+ | Setting or API | What it does |
120
+ | --- | --- |
121
+ | `step_budget_multiplier` | While a step-limited test runs, the scheduler stops it once it reaches *limit × multiplier* steps (default 20), so a test that never finishes fails instead of hanging |
122
+ | `doeff_test_call_steps_counted` | `call` (default): count all steps of the test. `world-running`: for tests that run a simulated world recorded in `doeff_core_effects.world_phases`, count only the steps of the world's running phase |
123
+ | `doeff_hy_pytest.budget.declare_step_budget(test, steps, reason)` | Gives one test its own step limit with a one-line reason, next to the test's definition. Over the declared value fails; at most half of it fails as stale |
124
+ | `--doeff-python-calls` | Command-line flag. Counts Python calls (`sys.monitoring` CALL events) during tests that declared a step limit, and prints one summary line. Reports only; never fails a test |
125
+
126
+ The step limits need a doeff-vm build that exposes step counts
127
+ (`doeff_vm.doeff_vm.vm_work_counts`). If it is missing, pytest stops at start-up with
128
+ a `UsageError` instead of silently falling back to seconds.
129
+
130
+ ### Output
131
+
132
+ With `-v`, the summary prints one line per measured test: steps, handler calls, and
133
+ CPU seconds. Use these numbers to pick a step limit.
134
+
135
+ The report and failure messages are currently written in Japanese.
136
+
137
+ ## How it fits with the other doeff packages
138
+
139
+ doeff is published as five core packages. `pip install doeff` installs all of them.
140
+
141
+ | Package | Role |
142
+ | --- | --- |
143
+ | [doeff](https://github.com/proboscis/doeff) | The Python API: `@do`, handler installers, `run`, the `doeff` CLI |
144
+ | [doeff-vm](https://github.com/proboscis/doeff/tree/main/packages/doeff-vm) | The Rust VM that executes programs |
145
+ | [doeff-core-effects](https://github.com/proboscis/doeff/tree/main/packages/doeff-core-effects) | The standard effects and their handlers |
146
+ | [doeff-hy](https://github.com/proboscis/doeff/tree/main/packages/doeff-hy) | Macros for writing doeff code in Hy, a Lisp that compiles to Python |
147
+ | **doeff-hy-pytest** | This package: the pytest plugin for tests written with doeff-hy |
148
+
149
+ Arrows point from a package to a package it depends on:
150
+
151
+ ```text
152
+ doeff ──► doeff-vm
153
+ │
154
+ └─────► doeff-core-effects ──► doeff-hy ──► doeff-hy-pytest
155
+ ```
156
+
157
+ doeff-hy also depends on doeff and doeff-core-effects, so the five packages are
158
+ released together with matching versions. doeff-hy-pytest declares no dependencies of
159
+ its own; it imports doeff-hy, which is always installed alongside it.
160
+
161
+ ## License
162
+
163
+ MIT. See [LICENSE](https://github.com/proboscis/doeff/blob/main/LICENSE).
@@ -0,0 +1,151 @@
1
+ # doeff-hy-pytest
2
+
3
+ The pytest plugin for tests written with
4
+ [doeff-hy](https://github.com/proboscis/doeff/tree/main/packages/doeff-hy).
5
+
6
+ **This README is for** developers who run pytest on Hy code that uses doeff. After
7
+ reading it you know what the plugin does without any setting, and how to turn on its
8
+ optional time limits for tests.
9
+
10
+ ## What it does
11
+
12
+ pytest loads the plugin by itself (entry point `pytest11`, name `doeff_hy`). It does
13
+ two things:
14
+
15
+ | Job | When it acts | Setting needed |
16
+ | --- | --- | --- |
17
+ | Fixes a Hy problem on Python 3.14 | At pytest start-up, before any conftest imports Hy | None |
18
+ | Time limits for Hy tests | During each test in a `.hy` file | Yes; off by default |
19
+
20
+ **The Python 3.14 fix.** Hy replaces `ast.unparse`. On Python 3.14, when pytest reads
21
+ fixture annotations as strings, that replacement recurses without end. The plugin
22
+ installs a corrected replacement (`doeff_hy.ast_unparse.install()`) as soon as pytest
23
+ starts, so it is in place even if a conftest or another plugin imports Hy first.
24
+
25
+ **Why this is a separate package.** pytest marks every module of a distribution that
26
+ declares a `pytest11` entry point for assertion rewriting. If doeff-hy itself declared
27
+ the entry point, pytest would try to rewrite doeff-hy's `.hy` files as Python and the
28
+ import would fail with a `SyntaxError`. This package contains no `.hy` files, so the
29
+ mark is harmless here.
30
+
31
+ The plugin does **not** collect `.hy` test files. The doeff-hy README shows the
32
+ `conftest.py` hook that collects them:
33
+ [Testing with deftest](https://github.com/proboscis/doeff/tree/main/packages/doeff-hy#testing-with-deftest).
34
+
35
+ ## Installation
36
+
37
+ doeff-hy depends on this package, so it is already installed when doeff or doeff-hy
38
+ is:
39
+
40
+ ```bash
41
+ pip install doeff # installs doeff-hy and doeff-hy-pytest
42
+ ```
43
+
44
+ You do not list it yourself. The exception: if you install doeff-hy from a git
45
+ revision with uv, add a `[tool.uv.sources]` entry for doeff-hy-pytest from the same
46
+ revision.
47
+
48
+ To check that pytest loaded it, look for `doeff-hy-pytest` in the `plugins:` line of
49
+ `pytest` output, or in the plugins that `pytest -VV` lists:
50
+
51
+ ```bash run
52
+ pytest -VV # doeff-hy-pytest
53
+ ```
54
+
55
+ ## Time limits for Hy tests
56
+
57
+ Tests that run programs against in-memory or scripted handlers should be fast. The
58
+ limits tell you when one of them becomes slow. They apply only to tests defined in
59
+ `.hy` files (`deftest` and plain test functions in the same file); Python test files
60
+ are not measured. With none of the three limits set, the plugin measures nothing.
61
+
62
+ ### The three limits
63
+
64
+ | Setting | What it limits | Unit | How it is measured |
65
+ | --- | --- | --- | --- |
66
+ | `doeff_test_call_budget_steps` | Running one test (pytest's `call` phase; fixture setup and teardown are not included) | doeff-vm steps (a positive integer, or `default` = 100,000) | Steps the VM executed. The count does not depend on machine load; CPU seconds are reported but not judged |
67
+ | `doeff_test_call_budget_by_marker` | Running one test that carries a given pytest mark | Wall-clock seconds, one line per mark: `mark=seconds` | For tests that do real I/O (child processes, sockets), whose cost does not show up as VM steps. A test that matches a line is judged by seconds even when a step limit is set; if several lines match, the longest limit applies |
68
+ | `doeff_test_collect_budget_seconds` | Importing one `.hy` test file | CPU seconds | Only when the file is imported through the `pytest_doeff_import_hy_module` hook, which the collector of [doeff-adr](https://github.com/proboscis/doeff/tree/main/packages/doeff-adr) calls. With the plain `conftest.py` collector from the doeff-hy README, nothing is measured |
69
+
70
+ A test that matches no `by_marker` line is judged by steps if a step limit is set, and
71
+ is not measured otherwise. A test that executes 0 steps (it only reads data and never
72
+ runs the VM) is within the limit.
73
+
74
+ Measured time excludes work that is not the test's own cost: compiling source to
75
+ bytecode when no cache exists, the first import of another module (a one-time cost of
76
+ a shared dependency), and garbage collection. Each is subtracted on the same clock
77
+ that is being judged.
78
+
79
+ ### What happens when a test goes over
80
+
81
+ | Setting | Values |
82
+ | --- | --- |
83
+ | `doeff_test_budget_mode` | `report` (default): warn and list the slow tests at the end. `fail`: the slow test fails |
84
+ | `doeff_test_budget_registry` | Directories (relative to the pytest rootdir, one per line) that list tests allowed to go over. One file per test: `<first 12 hex chars of sha256(key)>.txt`; line 1 is the key (the pytest node id, or the file path relative to rootdir for the collection limit), the following lines give the reason. When a test goes over, the message names the file to add in the first directory |
85
+
86
+ In `fail` mode, a listed test that finishes in at most half of its limit also fails,
87
+ as a stale entry, and the message names the file to delete. Between half the limit and
88
+ the limit, the summary only reports that the entry can be removed.
89
+
90
+ ### Example
91
+
92
+ ```toml
93
+ [tool.pytest.ini_options]
94
+ doeff_test_call_budget_steps = "default"
95
+ doeff_test_call_budget_by_marker = ["real_world=10"]
96
+ doeff_test_collect_budget_seconds = 1.0
97
+ doeff_test_budget_mode = "fail"
98
+ doeff_test_budget_registry = ["tests/over-budget"]
99
+ ```
100
+
101
+ With this configuration, each Hy test may run 100,000 VM steps; a test marked
102
+ `real_world` may take 10 seconds of wall-clock time instead; a test over its limit
103
+ fails unless `tests/over-budget` lists it.
104
+
105
+ ### More settings
106
+
107
+ | Setting or API | What it does |
108
+ | --- | --- |
109
+ | `step_budget_multiplier` | While a step-limited test runs, the scheduler stops it once it reaches *limit × multiplier* steps (default 20), so a test that never finishes fails instead of hanging |
110
+ | `doeff_test_call_steps_counted` | `call` (default): count all steps of the test. `world-running`: for tests that run a simulated world recorded in `doeff_core_effects.world_phases`, count only the steps of the world's running phase |
111
+ | `doeff_hy_pytest.budget.declare_step_budget(test, steps, reason)` | Gives one test its own step limit with a one-line reason, next to the test's definition. Over the declared value fails; at most half of it fails as stale |
112
+ | `--doeff-python-calls` | Command-line flag. Counts Python calls (`sys.monitoring` CALL events) during tests that declared a step limit, and prints one summary line. Reports only; never fails a test |
113
+
114
+ The step limits need a doeff-vm build that exposes step counts
115
+ (`doeff_vm.doeff_vm.vm_work_counts`). If it is missing, pytest stops at start-up with
116
+ a `UsageError` instead of silently falling back to seconds.
117
+
118
+ ### Output
119
+
120
+ With `-v`, the summary prints one line per measured test: steps, handler calls, and
121
+ CPU seconds. Use these numbers to pick a step limit.
122
+
123
+ The report and failure messages are currently written in Japanese.
124
+
125
+ ## How it fits with the other doeff packages
126
+
127
+ doeff is published as five core packages. `pip install doeff` installs all of them.
128
+
129
+ | Package | Role |
130
+ | --- | --- |
131
+ | [doeff](https://github.com/proboscis/doeff) | The Python API: `@do`, handler installers, `run`, the `doeff` CLI |
132
+ | [doeff-vm](https://github.com/proboscis/doeff/tree/main/packages/doeff-vm) | The Rust VM that executes programs |
133
+ | [doeff-core-effects](https://github.com/proboscis/doeff/tree/main/packages/doeff-core-effects) | The standard effects and their handlers |
134
+ | [doeff-hy](https://github.com/proboscis/doeff/tree/main/packages/doeff-hy) | Macros for writing doeff code in Hy, a Lisp that compiles to Python |
135
+ | **doeff-hy-pytest** | This package: the pytest plugin for tests written with doeff-hy |
136
+
137
+ Arrows point from a package to a package it depends on:
138
+
139
+ ```text
140
+ doeff ──► doeff-vm
141
+ │
142
+ └─────► doeff-core-effects ──► doeff-hy ──► doeff-hy-pytest
143
+ ```
144
+
145
+ doeff-hy also depends on doeff and doeff-core-effects, so the five packages are
146
+ released together with matching versions. doeff-hy-pytest declares no dependencies of
147
+ its own; it imports doeff-hy, which is always installed alongside it.
148
+
149
+ ## License
150
+
151
+ MIT. See [LICENSE](https://github.com/proboscis/doeff/blob/main/LICENSE).
@@ -0,0 +1,30 @@
1
+ [build-system]
2
+ # license の SPDX の式と license-files(PEP 639)を既定で core metadata に書くのは hatchling 1.27 から(既定の版 2.4)。
3
+ requires = ["hatchling>=1.27"]
4
+ build-backend = "hatchling.build"
5
+
6
+ [project]
7
+ name = "doeff-hy-pytest"
8
+ version = "0.5.0"
9
+ description = "pytest plugin for doeff-hy tests: a Python 3.14 fix for Hy and optional per-test time limits"
10
+ readme = "README.md"
11
+ requires-python = ">=3.11"
12
+ license = "MIT"
13
+ license-files = ["LICENSE"]
14
+ # 依存を宣言しない: この plugin は doeff-hy に引かれて入る(doeff-hy → doeff-hy-pytest の向きだけ)。
15
+ # 当て物の本体は doeff_hy.ast_unparse にあり、plugin はそれを import して当てるだけ。
16
+ dependencies = []
17
+
18
+ [project.urls]
19
+ Homepage = "https://github.com/proboscis/doeff/tree/main/packages/doeff-hy-pytest"
20
+ Repository = "https://github.com/proboscis/doeff"
21
+ Issues = "https://github.com/proboscis/doeff/issues"
22
+
23
+ # pytest は pytest11 の entry point を持つ配布物の**全 module** に assert の書き換えの印を付ける。doeff-hy 自身がこの
24
+ # entry point を持つと doeff_hy の .hy(macros.hy など)まで Python として書き換えようとして import が落ちる(wheel で
25
+ # 入れた repo だけ — editable の install では印が付かない)。だから plugin は .hy を持たないこの配布物に置く。
26
+ [project.entry-points.pytest11]
27
+ doeff_hy = "doeff_hy_pytest"
28
+
29
+ [tool.hatch.build.targets.wheel]
30
+ packages = ["src/doeff_hy_pytest"]
@@ -0,0 +1,25 @@
1
+ """doeff-hy の pytest plugin(entry point `pytest11` の名 `doeff_hy`)。
2
+
3
+ pytest は起動時に plugin と conftest を読み、fixture の注記を Python 3.14 では
4
+ `annotation_format=Format.STRING` で読む。Hy がそれより前に(他の plugin や conftest から)
5
+ import されていると、Hy の `ast.unparse` の差し替えがそこで止まらない再帰になる
6
+ (doeff_hy/ast_unparse.py)。`import doeff_hy` を待たず、pytest の起動の時点で置き換えるための plugin。
7
+
8
+ もう 1 つの役目は Hy の検の時間の上限(doeff_hy_pytest/budget.py — 設定が無ければ何もしない)。hook は
9
+ この module から輸出して、entry point の 1 つ(`doeff_hy`)のまま載せる。
10
+
11
+ この module が doeff-hy とは別の配布物にある理由は pyproject.toml の註(pytest の assert の書き換えの印が
12
+ 配布物の全 module に付き、doeff_hy の .hy を壊す)。
13
+ """
14
+
15
+ from doeff_hy.ast_unparse import install
16
+
17
+ from doeff_hy_pytest.budget import pytest_addoption as pytest_addoption
18
+ from doeff_hy_pytest.budget import pytest_configure as pytest_configure
19
+ from doeff_hy_pytest.budget import pytest_doeff_import_hy_module as pytest_doeff_import_hy_module
20
+ from doeff_hy_pytest.budget import pytest_runtest_call as pytest_runtest_call
21
+ from doeff_hy_pytest.budget import pytest_runtest_makereport as pytest_runtest_makereport
22
+ from doeff_hy_pytest.budget import pytest_terminal_summary as pytest_terminal_summary
23
+ from doeff_hy_pytest.budget import pytest_unconfigure as pytest_unconfigure
24
+
25
+ install()