pytest-graphql 0.1.0a1__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.
Files changed (101) hide show
  1. pytest_graphql-0.1.0a1/.gitignore +221 -0
  2. pytest_graphql-0.1.0a1/CHANGELOG.md +80 -0
  3. pytest_graphql-0.1.0a1/CONTRIBUTING.md +184 -0
  4. pytest_graphql-0.1.0a1/LICENSE +21 -0
  5. pytest_graphql-0.1.0a1/PKG-INFO +120 -0
  6. pytest_graphql-0.1.0a1/README.md +82 -0
  7. pytest_graphql-0.1.0a1/pyproject.toml +134 -0
  8. pytest_graphql-0.1.0a1/scripts/changelog_section.py +143 -0
  9. pytest_graphql-0.1.0a1/scripts/check_artifacts.py +319 -0
  10. pytest_graphql-0.1.0a1/scripts/check_core_purity.py +1792 -0
  11. pytest_graphql-0.1.0a1/scripts/check_no_pytest.py +168 -0
  12. pytest_graphql-0.1.0a1/scripts/check_publication_hygiene.py +489 -0
  13. pytest_graphql-0.1.0a1/scripts/git_hook_checks.py +3317 -0
  14. pytest_graphql-0.1.0a1/scripts/verify_release.py +700 -0
  15. pytest_graphql-0.1.0a1/src/pytest_graphql/__init__.py +62 -0
  16. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/__init__.py +7 -0
  17. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/auth.py +89 -0
  18. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/client.py +921 -0
  19. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/diagnostics.py +2352 -0
  20. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/errors.py +551 -0
  21. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/headers.py +40 -0
  22. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/lifecycle.py +1119 -0
  23. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/middleware.py +73 -0
  24. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/naming.py +107 -0
  25. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/operation.py +464 -0
  26. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/response/__init__.py +23 -0
  27. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/response/envelope.py +158 -0
  28. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/response/materialize.py +418 -0
  29. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/response/node.py +221 -0
  30. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/response/types.py +118 -0
  31. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/schema/__init__.py +3 -0
  32. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/schema/cache.py +32 -0
  33. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/schema/info.py +56 -0
  34. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/schema/source.py +112 -0
  35. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/selection/__init__.py +11 -0
  36. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/selection/builder.py +822 -0
  37. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/selection/model.py +202 -0
  38. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/selection/normalize.py +1423 -0
  39. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/selection/policy.py +261 -0
  40. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/transport/__init__.py +10 -0
  41. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/transport/base.py +79 -0
  42. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/transport/httpx_transport.py +1020 -0
  43. pytest_graphql-0.1.0a1/src/pytest_graphql/_core/validation.py +147 -0
  44. pytest_graphql-0.1.0a1/src/pytest_graphql/plugin/__init__.py +143 -0
  45. pytest_graphql-0.1.0a1/src/pytest_graphql/py.typed +0 -0
  46. pytest_graphql-0.1.0a1/tests/__init__.py +1 -0
  47. pytest_graphql-0.1.0a1/tests/schema/__init__.py +5 -0
  48. pytest_graphql-0.1.0a1/tests/schema/corpus/README.md +29 -0
  49. pytest_graphql-0.1.0a1/tests/schema/corpus/__init__.py +6 -0
  50. pytest_graphql-0.1.0a1/tests/schema/corpus/manifest.json +12 -0
  51. pytest_graphql-0.1.0a1/tests/schema/corpus/measure.py +546 -0
  52. pytest_graphql-0.1.0a1/tests/schema/corpus/sdl/catalog.graphql +141 -0
  53. pytest_graphql-0.1.0a1/tests/schema/corpus/sdl/feed.graphql +99 -0
  54. pytest_graphql-0.1.0a1/tests/schema/fake_transport.py +98 -0
  55. pytest_graphql-0.1.0a1/tests/schema/resolvers.py +438 -0
  56. pytest_graphql-0.1.0a1/tests/schema/sdl.graphql +453 -0
  57. pytest_graphql-0.1.0a1/tests/typing/derivable_transport.py +53 -0
  58. pytest_graphql-0.1.0a1/tests/typing/owned_acquisition.py +46 -0
  59. pytest_graphql-0.1.0a1/tests/typing/test_typing_fixtures.py +113 -0
  60. pytest_graphql-0.1.0a1/tests/unit/__init__.py +1 -0
  61. pytest_graphql-0.1.0a1/tests/unit/conftest.py +117 -0
  62. pytest_graphql-0.1.0a1/tests/unit/lifecycle_harness.py +625 -0
  63. pytest_graphql-0.1.0a1/tests/unit/lifecycle_products.py +241 -0
  64. pytest_graphql-0.1.0a1/tests/unit/local_http_server.py +120 -0
  65. pytest_graphql-0.1.0a1/tests/unit/plugin_probe.py +13 -0
  66. pytest_graphql-0.1.0a1/tests/unit/test_client.py +1368 -0
  67. pytest_graphql-0.1.0a1/tests/unit/test_client_over.py +163 -0
  68. pytest_graphql-0.1.0a1/tests/unit/test_cookie_isolation.py +279 -0
  69. pytest_graphql-0.1.0a1/tests/unit/test_core_purity.py +412 -0
  70. pytest_graphql-0.1.0a1/tests/unit/test_corpus_calibration.py +268 -0
  71. pytest_graphql-0.1.0a1/tests/unit/test_diagnostics.py +1804 -0
  72. pytest_graphql-0.1.0a1/tests/unit/test_errors.py +195 -0
  73. pytest_graphql-0.1.0a1/tests/unit/test_factory_lifecycle.py +784 -0
  74. pytest_graphql-0.1.0a1/tests/unit/test_hostile_schema.py +222 -0
  75. pytest_graphql-0.1.0a1/tests/unit/test_httpx_transport.py +1667 -0
  76. pytest_graphql-0.1.0a1/tests/unit/test_leak_suite.py +702 -0
  77. pytest_graphql-0.1.0a1/tests/unit/test_lifecycle_harness.py +219 -0
  78. pytest_graphql-0.1.0a1/tests/unit/test_lifecycle_interrupts.py +584 -0
  79. pytest_graphql-0.1.0a1/tests/unit/test_lifecycle_refusals.py +539 -0
  80. pytest_graphql-0.1.0a1/tests/unit/test_lifecycle_report.py +459 -0
  81. pytest_graphql-0.1.0a1/tests/unit/test_lifecycle_sites.py +661 -0
  82. pytest_graphql-0.1.0a1/tests/unit/test_naming.py +101 -0
  83. pytest_graphql-0.1.0a1/tests/unit/test_omission_records.py +663 -0
  84. pytest_graphql-0.1.0a1/tests/unit/test_operation.py +566 -0
  85. pytest_graphql-0.1.0a1/tests/unit/test_plugin_lifecycle.py +418 -0
  86. pytest_graphql-0.1.0a1/tests/unit/test_public_api.py +92 -0
  87. pytest_graphql-0.1.0a1/tests/unit/test_recorder.py +451 -0
  88. pytest_graphql-0.1.0a1/tests/unit/test_response.py +757 -0
  89. pytest_graphql-0.1.0a1/tests/unit/test_schema_cache.py +40 -0
  90. pytest_graphql-0.1.0a1/tests/unit/test_schema_info.py +64 -0
  91. pytest_graphql-0.1.0a1/tests/unit/test_schema_source.py +111 -0
  92. pytest_graphql-0.1.0a1/tests/unit/test_scripts.py +68 -0
  93. pytest_graphql-0.1.0a1/tests/unit/test_selection_builder.py +852 -0
  94. pytest_graphql-0.1.0a1/tests/unit/test_selection_model.py +119 -0
  95. pytest_graphql-0.1.0a1/tests/unit/test_selection_normalize.py +2854 -0
  96. pytest_graphql-0.1.0a1/tests/unit/test_selection_policy.py +304 -0
  97. pytest_graphql-0.1.0a1/tests/unit/test_selection_property.py +245 -0
  98. pytest_graphql-0.1.0a1/tests/unit/test_socket_guard.py +100 -0
  99. pytest_graphql-0.1.0a1/tests/unit/test_transport_base.py +106 -0
  100. pytest_graphql-0.1.0a1/tests/unit/test_validation.py +170 -0
  101. pytest_graphql-0.1.0a1/tests/unit/test_version.py +19 -0
@@ -0,0 +1,221 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ # Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ # poetry.lock
109
+ # poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ # pdm.lock
116
+ # pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ # pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # Redis
135
+ *.rdb
136
+ *.aof
137
+ *.pid
138
+
139
+ # RabbitMQ
140
+ mnesia/
141
+ rabbitmq/
142
+ rabbitmq-data/
143
+
144
+ # ActiveMQ
145
+ activemq-data/
146
+
147
+ # SageMath parsed files
148
+ *.sage.py
149
+
150
+ # Environments
151
+ .env
152
+ .envrc
153
+ .venv
154
+ env/
155
+ venv/
156
+ ENV/
157
+ env.bak/
158
+ venv.bak/
159
+
160
+ # Spyder project settings
161
+ .spyderproject
162
+ .spyproject
163
+
164
+ # Rope project settings
165
+ .ropeproject
166
+
167
+ # mkdocs documentation
168
+ /site
169
+
170
+ # mypy
171
+ .mypy_cache/
172
+ .dmypy.json
173
+ dmypy.json
174
+
175
+ # Pyre type checker
176
+ .pyre/
177
+
178
+ # pytype static type analyzer
179
+ .pytype/
180
+
181
+ # Cython debug symbols
182
+ cython_debug/
183
+
184
+ # PyCharm
185
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
186
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
187
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
188
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
189
+ # .idea/
190
+
191
+ # Abstra
192
+ # Abstra is an AI-powered process automation framework.
193
+ # Ignore directories containing user credentials, local state, and settings.
194
+ # Learn more at https://abstra.io/docs
195
+ .abstra/
196
+
197
+ # Visual Studio Code
198
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
199
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
200
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
201
+ # you could uncomment the following to ignore the entire vscode folder
202
+ # .vscode/
203
+ # Temporary file for partial code execution
204
+ tempCodeRunnerFile.py
205
+
206
+ # Ruff stuff:
207
+ .ruff_cache/
208
+
209
+ # PyPI configuration file
210
+ .pypirc
211
+
212
+ # Marimo
213
+ marimo/_static/
214
+ marimo/_lsp/
215
+ __marimo__/
216
+
217
+ # Streamlit
218
+ .streamlit/secrets.toml
219
+
220
+ # Local agent coordination state (review handoff logs), repository root only
221
+ /tmp/
@@ -0,0 +1,80 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
7
+ from `1.0.0` onward. While the version is `0.x`, the API may change between minor
8
+ versions. Every change is recorded here with a migration note, and no deprecation
9
+ cycle is promised.
10
+
11
+ ## [Unreleased]
12
+
13
+ ## [0.1.0a1] - 2026-10-03
14
+
15
+ First alpha. It contains a working client, transport, response model and one
16
+ pytest fixture.
17
+
18
+ It requires `graphql-core` 3.2. graphql-core 3.3 is not supported yet, and the
19
+ dependency is declared as `>=3.2,<3.3` so that an install never selects it.
20
+
21
+ ### Added
22
+
23
+ - `GraphQLClient`, `ClientConfig` and `build_client()`. `query()` and
24
+ `mutation()` call an operation by name and build its selection set from the
25
+ schema. `execute()` sends a raw document and returns the response. Names are
26
+ snake_case in Python and the schema's own spelling on the wire.
27
+ - Automatic selection with depth, field count and cycle limits, set through
28
+ `SelectionPolicy` and `CyclePolicy`. Explicit selections use `Selection`,
29
+ `Field` and `AUTO`. A field left out of an automatic selection is recorded,
30
+ not dropped silently.
31
+ - Local validation of each operation against the schema before it is sent, on
32
+ by default. `validate=False` turns it off. Variables are always checked
33
+ against their declared types.
34
+ - Schema loading through `IntrospectionSource` or `SDLFileSource`.
35
+ - `HttpxTransport`, behind the `Transport` protocol. Requests are always a JSON
36
+ `POST`. Timeouts, connect retries and the response size are bounded. Redirects
37
+ are not followed, and proxy and other environment settings are ignored unless
38
+ `trust_env=True`.
39
+ - Connection isolation with the default `HttpxTransport`. The test clients of
40
+ one pytest session share one connection pool, and a clone shares the pool of
41
+ the client it came from. Each `build_client()` call without `transport=`
42
+ creates its own pool. Every such client has its own cookie jar. Under the
43
+ default `cookie_scope="none"`, no cookie survives a call. A transport you
44
+ supply, through `build_client(transport=...)` or an overridden
45
+ `gql_transport` fixture, keeps its own connection and cookie behavior.
46
+ - `GraphQLResponse`, `Node` and `NodeList`. Data is converted using the schema,
47
+ and errors and partial data raise unless that is turned off.
48
+ - Diagnostics. `DiagnosticSnapshot` and `as_curl()` describe a call with
49
+ headers, variables and known credential values redacted. Recorded calls are
50
+ bounded, and truncation is always stated.
51
+ - `Auth`, `BearerAuth` and `HeaderAuth`, and the `Middleware` protocol with
52
+ `BaseMiddleware`. `with_headers()`, `with_auth()`, `as_()` and `anonymous()`
53
+ return a client with another identity.
54
+ - Ownership rules for closing resources. Closing a client closes what it owns,
55
+ exactly once. A failure while building a client closes everything built so
56
+ far.
57
+ - The pytest fixtures `gql_url`, `gql_transport` and `gql`, and the
58
+ `--gql-url` flag. The schema loads once per session. Each test gets its own
59
+ client, which is closed after the test, whether it passed or failed.
60
+ - Packaging skeleton: `pyproject.toml` with a hatchling backend, PEP 621
61
+ metadata and a `src/` layout, the `pytest_graphql` package with `__version__`
62
+ and `py.typed`, and the `pytest11` entry point.
63
+ - Tooling configuration: ruff lint and format, `mypy --strict` on `src/`, and
64
+ pytest defaults.
65
+ - `scripts/check_core_purity.py`, which fails when any module outside the
66
+ pytest plugin package imports pytest.
67
+ - The `test` workflow, running the representative CI matrix on Linux, the test
68
+ suite on macOS and Windows at the newest supported Python, the core purity
69
+ check and the no-pytest install job.
70
+ - The `release` workflow, which builds one artifact set, records a digest for
71
+ every file, runs the artifact checks, and verifies the release back from
72
+ TestPyPI before any upload to PyPI. It publishes nothing until the first
73
+ release gate.
74
+ - `CONTRIBUTING.md` with the development setup and the release checklist.
75
+ - `requirements/build.in` and a pinned `requirements/build.txt` covering the
76
+ build backend and its dependencies, used both as build constraints for the
77
+ release build and as the environment for the sdist install-back.
78
+
79
+ [Unreleased]: https://github.com/skhomenko/pytest-graphql/compare/v0.1.0a1...HEAD
80
+ [0.1.0a1]: https://github.com/skhomenko/pytest-graphql/releases/tag/v0.1.0a1
@@ -0,0 +1,184 @@
1
+ # Contributing
2
+
3
+ ## Development setup
4
+
5
+ ```bash
6
+ git clone git@github.com:skhomenko/pytest-graphql.git
7
+ cd pytest-graphql
8
+ uv sync --all-extras
9
+ git config core.hooksPath .githooks
10
+ ```
11
+
12
+ The hooks are tracked in `.githooks/` and do nothing until that last command
13
+ runs. A linked worktree needs the same setting of its own.
14
+
15
+ ## Checks
16
+
17
+ Run all of these before you open a pull request. CI runs the same set.
18
+
19
+ ```bash
20
+ uv run ruff check .
21
+ uv run ruff format --check .
22
+ uv run mypy --strict src/
23
+ uv run pytest -q
24
+ python3 scripts/check_core_purity.py
25
+ ```
26
+
27
+ `scripts/` holds contributor tooling that runs on the standard library alone, so
28
+ those scripts work before the project environment exists. Each one has a
29
+ `--self-test` mode, and the test suite runs it.
30
+
31
+ Text intended for publication is scanned separately:
32
+
33
+ ```bash
34
+ python3 scripts/check_publication_hygiene.py README.md CHANGELOG.md
35
+ ```
36
+
37
+ ## Layout rules
38
+
39
+ - Library code lives in `src/pytest_graphql/`.
40
+ - The pytest layer is confined to `src/pytest_graphql/plugin/`. No module
41
+ outside that package may import pytest. `scripts/check_core_purity.py`
42
+ enforces this, and CI fails when it reports a finding.
43
+ - Tests live in `tests/`. A unit test never opens a non-loopback socket.
44
+
45
+ ## Branches and commits
46
+
47
+ Branch names use a type prefix and a short hyphenated description: `feat/`,
48
+ `fix/`, `docs/`, `chore/`, `refactor/`, `test/` or `security/`.
49
+
50
+ Commit subjects use conventional-commits prefixes and stay at or under 72
51
+ characters. Body lines wrap at 72. The commit-message hook enforces both, and
52
+ `docs/reference/COMMIT_MESSAGE_RULES.md` states exactly how a line is measured.
53
+ Never bypass a hook.
54
+
55
+ ## Supported versions
56
+
57
+ The supported set is Python 3.10 through 3.14 with pytest 7.4 or newer. That
58
+ range is the compatibility promise and it is what the dependency metadata
59
+ declares.
60
+
61
+ CI does not run the whole cross product. It runs one job per row of the
62
+ representative matrix in the compatibility section of
63
+ `docs/reference/DESIGN_DECISIONS.md`. Those rows are a sample of the supported
64
+ range, never a narrower supported set. Adding or removing a row is one change
65
+ that edits that table and `.github/workflows/test.yml` together.
66
+
67
+ Linux, macOS and Windows are supported. The matrix rows run on Linux. Two more
68
+ jobs run the test suite on macOS and on Windows at the newest supported Python.
69
+ The same section states that rule.
70
+
71
+ `requires-python` declares both ends of the range, `>=3.10,<3.15`. Raising the
72
+ ceiling means editing that section, `pyproject.toml` and the matrix together,
73
+ then running `uv lock`.
74
+
75
+ ## Pinned build tooling
76
+
77
+ Two programs run during a release build, and both are pinned so the reviewed
78
+ tree selects them.
79
+
80
+ - The uv version lives in the `UV_VERSION` variable at the top of each workflow.
81
+ Dependabot moves action SHAs but not this value, so bump it by commit.
82
+ - `requirements/build.txt` pins the build backend and its own dependencies.
83
+ `requirements/build.in` holds the direct requirement. Regenerate the pinned
84
+ file with:
85
+
86
+ ```
87
+ uv pip compile --universal --python-version 3.10 requirements/build.in \
88
+ -o requirements/build.txt
89
+ ```
90
+
91
+ The release build passes that file to `uv build --build-constraints`, and the
92
+ sdist install-back job installs it before building with isolation disabled.
93
+
94
+ ## Release checklist
95
+
96
+ Publication happens at three gates. The release machinery exists from the first
97
+ milestone and publishes nothing before the alpha gate.
98
+
99
+ | Gate | Version | Requires |
100
+ |---|---|---|
101
+ | Alpha | `0.1.0a1` | Working client, transport, response model and one fixture |
102
+ | Beta | `0.1.0b1` | Complete pytest plugin |
103
+ | Stable | `0.1.0` | Complete documentation and release acceptance |
104
+
105
+ Every gate runs the same steps. Steps 1 to 6 are the contributor's. Steps 7 and
106
+ 8 are the maintainer's, and no agent performs them.
107
+
108
+ 1. Confirm the branch is green.
109
+
110
+ ```bash
111
+ uv run ruff check . && uv run ruff format --check . \
112
+ && uv run mypy --strict src/ && uv run pytest -q
113
+ ```
114
+
115
+ 2. Set the version in one place and check it.
116
+
117
+ ```bash
118
+ $EDITOR src/pytest_graphql/__init__.py
119
+ uv run python -c "import pytest_graphql; print(pytest_graphql.__version__)"
120
+ ```
121
+
122
+ 3. Move the `Unreleased` entries into a dated section for that version in
123
+ `CHANGELOG.md`, and scan the text that will be published.
124
+
125
+ ```bash
126
+ python3 scripts/check_publication_hygiene.py README.md CHANGELOG.md
127
+ ```
128
+
129
+ 4. Merge the release branch, then tag the merge commit. The tag is `v` followed
130
+ by the exact version. The release workflow refuses a tag that disagrees with
131
+ `__version__`.
132
+
133
+ ```bash
134
+ git tag "v$(uv run python -c 'import pytest_graphql; print(pytest_graphql.__version__)')"
135
+ git push origin --tags
136
+ ```
137
+
138
+ 5. Watch the `release` workflow. It builds one artifact set, records a digest
139
+ for every file, and runs the artifact checks: `twine check`, PEP 621
140
+ metadata completeness, long-description rendering, wheel and sdist contents,
141
+ and `__version__` agreeing with the tag.
142
+
143
+ 6. Before the first gate the workflow stops there, leaving the artifact set
144
+ built, checked and retained. The upload jobs are gated on the repository
145
+ variable `RELEASE_PUBLISH`, which is unset until the maintainer opens the
146
+ alpha gate. From that point the run continues into the upload jobs, which
147
+ wait for review in the protected `pypi` environment.
148
+
149
+ 7. Approve the TestPyPI upload. The workflow then enumerates that release
150
+ through the TestPyPI index, compares the complete remote file set with the
151
+ build manifest in both directions, fetches each file by its index URL,
152
+ rechecks every digest, and installs and tests the wheel and the sdist in
153
+ separate clean environments.
154
+
155
+ 8. Approve the PyPI upload. It uploads the same files that TestPyPI verified.
156
+ Nothing is rebuilt between the two indexes, because a rebuild is a different
157
+ artifact.
158
+
159
+ Two properties of the indexes shape this checklist. A version can be uploaded
160
+ once per index and cannot be replaced, only yanked, so a failed check burns that
161
+ version number and the next attempt increments it. Before `0.1.0` exists, no
162
+ stable version satisfies `pytest-graphql`, so an ordinary unpinned install can
163
+ select `0.1.0a1`. Publishing the alpha to PyPI therefore exposes it to ordinary
164
+ installs, and the maintainer accepts that exposure at the gate. The alternative
165
+ is to keep the alpha on TestPyPI until a stable version exists.
166
+
167
+ Trusted publishing is configured as a pending publisher on PyPI and on TestPyPI,
168
+ so no upload token is stored. The token exchange is first exercised at the alpha
169
+ gate, because a pending publisher cannot be tested without a real upload.
170
+
171
+ ### Repository configuration
172
+
173
+ These settings live in GitHub and on the two indexes, not in the repository, so
174
+ the maintainer applies them once. The release workflow assumes all of them.
175
+
176
+ | Where | Setting |
177
+ |---|---|
178
+ | PyPI | A pending publisher for `pytest-graphql`, owner `skhomenko`, repository `pytest-graphql`, workflow `release.yml`, environment `pypi` |
179
+ | TestPyPI | The same pending publisher, with the same values |
180
+ | GitHub environment `pypi` | Protected, with a required reviewer. Both upload jobs run in it |
181
+ | GitHub variable `RELEASE_PUBLISH` | Unset until the alpha gate. Set it to `true` to let the upload jobs run |
182
+
183
+ No upload token is stored anywhere. The install-back job runs outside the
184
+ environment and holds no publishing credential of any kind.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sergii Khomenko
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,120 @@
1
+ Metadata-Version: 2.5
2
+ Name: pytest-graphql
3
+ Version: 0.1.0a1
4
+ Summary: Schema-aware GraphQL API testing for pytest: a GraphQL client, an httpx transport and a pytest fixture.
5
+ Project-URL: Documentation, https://skhomenko.github.io/pytest-graphql/
6
+ Project-URL: Source, https://github.com/skhomenko/pytest-graphql
7
+ Project-URL: Changelog, https://github.com/skhomenko/pytest-graphql/blob/main/CHANGELOG.md
8
+ Project-URL: Issues, https://github.com/skhomenko/pytest-graphql/issues
9
+ Author: Sergii Khomenko
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: api,graphql,integration,pytest,testing
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Framework :: Pytest
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Topic :: Software Development :: Testing
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: <3.15,>=3.10
26
+ Requires-Dist: certifi
27
+ Requires-Dist: graphql-core<3.3,>=3.2
28
+ Requires-Dist: httpx<1,>=0.27
29
+ Provides-Extra: dev
30
+ Requires-Dist: coverage[toml]>=7.4; extra == 'dev'
31
+ Requires-Dist: hypothesis>=6.100; extra == 'dev'
32
+ Requires-Dist: mypy>=1.11; extra == 'dev'
33
+ Requires-Dist: pytest>=7.4; extra == 'dev'
34
+ Requires-Dist: ruff>=0.6; extra == 'dev'
35
+ Provides-Extra: pytest
36
+ Requires-Dist: pytest>=7.4; extra == 'pytest'
37
+ Description-Content-Type: text/markdown
38
+
39
+ # pytest-graphql
40
+
41
+ Schema-aware GraphQL API testing for pytest.
42
+
43
+ ## Status
44
+
45
+ Alpha. This release contains a working client, an `httpx` transport, a response
46
+ model and one pytest fixture. The API may still change before `0.1.0`.
47
+
48
+ What `0.1.0a1` contains:
49
+
50
+ - `GraphQLClient` and `build_client()`. The client reads your schema and builds
51
+ the selection set for an operation. By default it checks the operation
52
+ against the schema before it sends anything, and `validate=False` turns that
53
+ check off. Arguments and fields are snake_case in Python and use the schema's
54
+ own names on the wire.
55
+ - An `httpx` transport with explicit timeout, retry and response size limits.
56
+ With this transport, tests share one connection pool and each client keeps
57
+ its own cookie jar. A transport you supply manages its own connections and
58
+ cookies.
59
+ - A response model. Failures carry a redacted summary of the request.
60
+ `RequestInfo.as_curl()`, available to middleware, renders a `curl` command
61
+ that reproduces a request, with credentials replaced by placeholders.
62
+ - Bearer and header auth, and request middleware.
63
+ - The pytest fixtures `gql`, `gql_url` and `gql_transport`, and the
64
+ `--gql-url` flag. The schema loads once per session, and each test gets its
65
+ own client.
66
+
67
+ Not in this release yet: ini options, environment variables and hooks, response
68
+ matching, fake data, error assertions and polling.
69
+
70
+ The changelog records what each release contains:
71
+ https://github.com/skhomenko/pytest-graphql/blob/main/CHANGELOG.md
72
+
73
+ ## Usage
74
+
75
+ With pytest, pass the endpoint on the command line:
76
+
77
+ ```
78
+ pytest --gql-url=http://localhost:8000/graphql
79
+ ```
80
+
81
+ ```python
82
+ def test_user_has_a_name(gql):
83
+ user = gql.query("user", id="123")
84
+ assert user.name
85
+ ```
86
+
87
+ For a URL known only at run time, override the `gql_url` fixture in your
88
+ `conftest.py`. The `--gql-url` flag still wins when both are given.
89
+
90
+ Without pytest, use `build_client()`, and close the client when you are done:
91
+
92
+ ```python
93
+ from pytest_graphql import build_client
94
+
95
+ with build_client(url="http://localhost:8000/graphql") as gql:
96
+ user = gql.query("user", id="123")
97
+ ```
98
+
99
+ ## Install
100
+
101
+ ```
102
+ pip install pytest-graphql
103
+ ```
104
+
105
+ The required dependencies are `graphql-core`, `httpx`, and `certifi`. `pytest`
106
+ is optional, so the client can be used outside a test suite:
107
+
108
+ ```
109
+ pip install "pytest-graphql[pytest]"
110
+ ```
111
+
112
+ ## Supported versions
113
+
114
+ Python 3.10 through 3.14, with pytest 7.4 or newer when the pytest extra is
115
+ installed. CI tests a representative sample of that range rather than the whole
116
+ cross product.
117
+
118
+ ## License
119
+
120
+ MIT. See https://github.com/skhomenko/pytest-graphql/blob/main/LICENSE