pytest-rowsmith 0.1.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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 meiorz
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,175 @@
1
+ Metadata-Version: 2.4
2
+ Name: pytest-rowsmith
3
+ Version: 0.1.0
4
+ Summary: pytest fixture for reproducible fake test data (CSV, JSON, SQL) from the free Rowsmith API, cached for offline runs.
5
+ Author: meiorz
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/meiorz/rowsmith-mcp/tree/main/pytest-rowsmith
8
+ Project-URL: Source, https://github.com/meiorz/rowsmith-mcp
9
+ Project-URL: Issues, https://github.com/meiorz/rowsmith-mcp/issues
10
+ Keywords: pytest,fixtures,test data,fake data,csv,sql
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Framework :: Pytest
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.9
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: Topic :: Software Development :: Testing
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: pytest>=7
27
+ Dynamic: license-file
28
+
29
+ # pytest-rowsmith
30
+
31
+ A pytest plugin with one fixture, `rowsmith`, that gives your tests reproducible fake test data (CSV, JSON or
32
+ SQL INSERTs) generated from a table schema by the Rowsmith API.
33
+
34
+ **Network use.** The plugin calls the Rowsmith API over the network (POST
35
+ https://testdata-api.re-jam620.workers.dev/v1/generate) only when a test calls `rowsmith.generate()` or
36
+ `rowsmith.fetch()` and that request is not in the cache yet: the first time a schema (with its rows, seed,
37
+ format, table and version) is used, or every schema once per run with `--rowsmith-refresh`. Importing the package,
38
+ loading the plugin and creating the fixture make no network call. Calls go to the free Rowsmith API under its terms
39
+ of use (https://testdata-api.re-jam620.workers.dev/terms) and count against your daily limit.
40
+
41
+ - Free, rate-limited, no account, no API key.
42
+ - The same schema and seed give byte-identical output for the same generator version. The plugin pins the
43
+ version in every request (`"version": "1"` by default), so cached answers stay valid.
44
+ - Send schemas only. Never send real data.
45
+ - Identifiers come only from reserved or invalid ranges: emails use example.com, example.net, example.org and
46
+ mail.test; phones, card numbers and SSN- and IBAN-shaped values come from reserved or invalid ranges too.
47
+ - No runtime dependency besides pytest; HTTP goes through the standard library's urllib.
48
+
49
+ ## Install
50
+ ```sh
51
+ pip install pytest-rowsmith
52
+ ```
53
+ Or from the public repository at the plugin's release tag pytest-rowsmith-v0.1.0:
54
+ ```sh
55
+ pip install "git+https://github.com/meiorz/rowsmith-mcp@pytest-rowsmith-v0.1.0#subdirectory=pytest-rowsmith"
56
+ ```
57
+ The install from the repository needs git and network access to PyPI for the build tool (setuptools); nothing is
58
+ compiled. pytest loads the plugin automatically. Python 3.9 or later.
59
+
60
+ ## Example
61
+ ```python
62
+ ORDERS = [
63
+ {"name": "order_id", "type": "sequence", "prefix": "ord_", "pad": 4},
64
+ {"name": "email", "type": "email"},
65
+ {"name": "total_usd", "type": "decimal", "min": 1, "max": 500},
66
+ ]
67
+
68
+ def test_orders(rowsmith):
69
+ orders = rowsmith.generate(ORDERS, rows=20, seed=42)
70
+ assert len(orders) == 20 and orders[0]["order_id"] == "ord_0001"
71
+ assert all(o["email"].rsplit("@", 1)[1] in ("example.com", "example.net", "example.org", "mail.test") for o in orders)
72
+ ```
73
+ The column types and their options are listed at https://testdata-api.re-jam620.workers.dev/v1/types; the full
74
+ API is described at https://testdata-api.re-jam620.workers.dev/openapi.json.
75
+
76
+ ### From your own schema
77
+ Instead of `columns`, pass `schema=`: a JSON Schema dict (type object with properties), such as a Pydantic
78
+ model's `model_json_schema()` or a Zod export, or an OpenAPI component as
79
+ `{"openapi": <document dict>, "component": "Order"}`. The service maps it to columns; properties it cannot map
80
+ (arrays, patterns and other unsupported forms) are left out, never guessed, and listed in
81
+ `fetch(...).schema_unmapped`. Before sending, the plugin removes `example`, `examples`, `default`, `const` and `x-*`
82
+ keys from the schema, so their values do not leave your machine; the service ignores them too.
83
+ For an OpenAPI component, only the named component and the schemas it references are sent.
84
+ ```python
85
+ from myapp.models import User # a Pydantic model
86
+
87
+ def test_users(rowsmith):
88
+ users = rowsmith.generate(schema=User.model_json_schema(), rows=20, seed=42)
89
+ assert len(users) == 20
90
+ ```
91
+
92
+ ## The fixture
93
+ `rowsmith` is session-scoped. Its methods take the same arguments:
94
+
95
+ | Argument | Default | Meaning |
96
+ |---|---|---|
97
+ | `columns` | | list of column definitions, as in the API; pass `columns` or `schema` |
98
+ | `schema` | | a JSON Schema dict, or `{"openapi": ..., "component": ...}`; pass `columns` or `schema` |
99
+ | `rows` | `10` | 1 to 500 |
100
+ | `seed` | `1` | always sent, so every call is reproducible |
101
+ | `format` | `"json"` | `"csv"`, `"json"` or `"sql"` |
102
+ | `table` | not sent | table name (used in SQL output) |
103
+ | `version` | `"1"` | generator version, always sent |
104
+
105
+ - `rowsmith.generate(columns, ...)` (or `generate(schema=..., ...)`) returns a list of dicts for `json` (values typed as in the JSON) and `csv`
106
+ (values are strings), and the SQL text for `sql`.
107
+ - `rowsmith.fetch(columns, ...)` returns a `RowsmithResult` with `body` (the exact bytes), `text`, `sha256`,
108
+ `headers`, `generator_version`, `seed`, `reproduce`, `schema_unmapped`, `schema_version`, `output_sha256`,
109
+ `request_sha256`, `from_cache` and `parsed()`. `reproduce` is the service's
110
+ X-Reproduce line (sent with CSV and SQL answers, and kept in the cache); JSON answers carry none, so for them it
111
+ is the request that was sent, in the same form.
112
+ - On anything other than a successful answer the call raises `pytest_rowsmith.RowsmithError`. Its message names
113
+ the HTTP status, the service's error and `next` text, and the reproduce line. A 4xx answer is not retried; a 5xx
114
+ answer or a network error is retried exactly once, 1 second later. There is no fallback to random or local data.
115
+ - Each request times out after 30 s.
116
+
117
+ `pytest_rowsmith.Rowsmith` is the same client outside pytest (`Rowsmith(base_url=..., cache=None)`).
118
+
119
+ ## Golden manifests
120
+ Pin a dataset for an eval and detect drift. The service sends `X-Output-SHA256` (the sha256 of the body bytes) and
121
+ `X-Request-SHA256` (the sha256 of the canonical request, the same for a schema and the columns it maps to) with
122
+ every answer; the result exposes them as `output_sha256` and `request_sha256`, and the cache keeps them.
123
+ `request_sha256` is the X-Request-SHA256 header; without it, the sha256 of the body in a body-b64url X-Reproduce
124
+ line; otherwise None, and a run with `--rowsmith-refresh` fetches the answer again with its headers.
125
+ `output_sha256` without its header is computed from the body bytes.
126
+ ```python
127
+ ORDERS = [{"name": "order_id", "type": "sequence", "prefix": "ord_", "pad": 4}, {"name": "email", "type": "email"}]
128
+
129
+ def test_orders_are_golden(rowsmith):
130
+ result = rowsmith.fetch(ORDERS, rows=20, seed=42, format="csv")
131
+ entry = rowsmith.manifest_entry(result, "orders-v1") # save it once, e.g. into tests/golden.json
132
+ rowsmith.assert_golden(result, entry["output_sha256"]) # later: compare against the saved entry or its hash
133
+ ```
134
+ - `rowsmith.manifest_entry(result, name)` returns `{"name", "request_sha256", "output_sha256", "output_version",
135
+ "schema_version", "reproduce"}`, one entry of `{"rowsmith_manifest": 1, "entries": [...]}` (the format is in the
136
+ service's llms.txt). `reproduce` regenerates the bytes by itself: the service's X-Reproduce line when it carries
137
+ the body, otherwise the request the plugin sent.
138
+ - `rowsmith.assert_golden(result, expected)` takes a sha256 hex string or a manifest entry (then the request hash
139
+ must match too) and fails with both hashes, the versions, whether the answer came from the cache, and the
140
+ reproduce line. Both are also importable from `pytest_rowsmith`.
141
+ - The plugin pins the version in every request. A pinned version is served as long as the service runs; a retired version answers 409. A version's output is not changed in place: a golden test checks its bytes on every build.
142
+
143
+ ## Caching and offline runs
144
+ Answers are stored in pytest's own cache (`.pytest_cache/v/rowsmith/v1/` in your project), one entry per request,
145
+ keyed by the sha256 of the exact request-body bytes. An entry holds the response bytes and the headers
146
+ content-type, x-generator-version, x-seed, x-reproduce, x-request-sha256 and x-output-sha256, plus
147
+ x-schema-version and x-schema-unmapped for a schema request. A suite therefore calls the API once per distinct
148
+ request and then runs offline, as long as `.pytest_cache` is kept. A damaged entry is fetched again.
149
+
150
+ - `pytest --rowsmith-refresh` ignores the cache: each distinct request is sent once in that run and its entry is
151
+ replaced.
152
+ - `pytest --cache-clear` removes the cache, Rowsmith entries included.
153
+ - With pytest's cache disabled (`-p no:cacheprovider`), answers are kept in memory for the run only.
154
+ - The cache key does not include the base URL.
155
+
156
+ ## Configuration
157
+ | Setting | Where | Default |
158
+ |---|---|---|
159
+ | API base URL | `ROWSMITH_URL` environment variable, or `rowsmith_url` in your pytest ini file; the variable wins | `https://testdata-api.re-jam620.workers.dev` |
160
+ | Bypass the cache | `--rowsmith-refresh` | off |
161
+
162
+ Every request sends `User-Agent: pytest-rowsmith/<version>` and `x-rowsmith-tool: pytest`. The service counts these calls under tool pytest in its aggregate usage totals (counts only; nothing per caller).
163
+
164
+ ## Limits and terms
165
+ Up to 500 rows and 50 columns per call, with daily limits per caller; over a limit the call fails with the
166
+ service's 429 message. Use of the Rowsmith service is under its terms of use:
167
+ https://testdata-api.re-jam620.workers.dev/terms. Data notice: https://testdata-api.re-jam620.workers.dev/privacy.
168
+
169
+ The MIT licence covers this plugin's code only.
170
+
171
+ ## Development
172
+ ```sh
173
+ PYTHONPATH=src python -m pytest # offline: a local stub server stands in for the API
174
+ ROWSMITH_LIVE=1 PYTHONPATH=src python -m pytest # adds the live golden test (one real API call)
175
+ ```
@@ -0,0 +1,147 @@
1
+ # pytest-rowsmith
2
+
3
+ A pytest plugin with one fixture, `rowsmith`, that gives your tests reproducible fake test data (CSV, JSON or
4
+ SQL INSERTs) generated from a table schema by the Rowsmith API.
5
+
6
+ **Network use.** The plugin calls the Rowsmith API over the network (POST
7
+ https://testdata-api.re-jam620.workers.dev/v1/generate) only when a test calls `rowsmith.generate()` or
8
+ `rowsmith.fetch()` and that request is not in the cache yet: the first time a schema (with its rows, seed,
9
+ format, table and version) is used, or every schema once per run with `--rowsmith-refresh`. Importing the package,
10
+ loading the plugin and creating the fixture make no network call. Calls go to the free Rowsmith API under its terms
11
+ of use (https://testdata-api.re-jam620.workers.dev/terms) and count against your daily limit.
12
+
13
+ - Free, rate-limited, no account, no API key.
14
+ - The same schema and seed give byte-identical output for the same generator version. The plugin pins the
15
+ version in every request (`"version": "1"` by default), so cached answers stay valid.
16
+ - Send schemas only. Never send real data.
17
+ - Identifiers come only from reserved or invalid ranges: emails use example.com, example.net, example.org and
18
+ mail.test; phones, card numbers and SSN- and IBAN-shaped values come from reserved or invalid ranges too.
19
+ - No runtime dependency besides pytest; HTTP goes through the standard library's urllib.
20
+
21
+ ## Install
22
+ ```sh
23
+ pip install pytest-rowsmith
24
+ ```
25
+ Or from the public repository at the plugin's release tag pytest-rowsmith-v0.1.0:
26
+ ```sh
27
+ pip install "git+https://github.com/meiorz/rowsmith-mcp@pytest-rowsmith-v0.1.0#subdirectory=pytest-rowsmith"
28
+ ```
29
+ The install from the repository needs git and network access to PyPI for the build tool (setuptools); nothing is
30
+ compiled. pytest loads the plugin automatically. Python 3.9 or later.
31
+
32
+ ## Example
33
+ ```python
34
+ ORDERS = [
35
+ {"name": "order_id", "type": "sequence", "prefix": "ord_", "pad": 4},
36
+ {"name": "email", "type": "email"},
37
+ {"name": "total_usd", "type": "decimal", "min": 1, "max": 500},
38
+ ]
39
+
40
+ def test_orders(rowsmith):
41
+ orders = rowsmith.generate(ORDERS, rows=20, seed=42)
42
+ assert len(orders) == 20 and orders[0]["order_id"] == "ord_0001"
43
+ assert all(o["email"].rsplit("@", 1)[1] in ("example.com", "example.net", "example.org", "mail.test") for o in orders)
44
+ ```
45
+ The column types and their options are listed at https://testdata-api.re-jam620.workers.dev/v1/types; the full
46
+ API is described at https://testdata-api.re-jam620.workers.dev/openapi.json.
47
+
48
+ ### From your own schema
49
+ Instead of `columns`, pass `schema=`: a JSON Schema dict (type object with properties), such as a Pydantic
50
+ model's `model_json_schema()` or a Zod export, or an OpenAPI component as
51
+ `{"openapi": <document dict>, "component": "Order"}`. The service maps it to columns; properties it cannot map
52
+ (arrays, patterns and other unsupported forms) are left out, never guessed, and listed in
53
+ `fetch(...).schema_unmapped`. Before sending, the plugin removes `example`, `examples`, `default`, `const` and `x-*`
54
+ keys from the schema, so their values do not leave your machine; the service ignores them too.
55
+ For an OpenAPI component, only the named component and the schemas it references are sent.
56
+ ```python
57
+ from myapp.models import User # a Pydantic model
58
+
59
+ def test_users(rowsmith):
60
+ users = rowsmith.generate(schema=User.model_json_schema(), rows=20, seed=42)
61
+ assert len(users) == 20
62
+ ```
63
+
64
+ ## The fixture
65
+ `rowsmith` is session-scoped. Its methods take the same arguments:
66
+
67
+ | Argument | Default | Meaning |
68
+ |---|---|---|
69
+ | `columns` | | list of column definitions, as in the API; pass `columns` or `schema` |
70
+ | `schema` | | a JSON Schema dict, or `{"openapi": ..., "component": ...}`; pass `columns` or `schema` |
71
+ | `rows` | `10` | 1 to 500 |
72
+ | `seed` | `1` | always sent, so every call is reproducible |
73
+ | `format` | `"json"` | `"csv"`, `"json"` or `"sql"` |
74
+ | `table` | not sent | table name (used in SQL output) |
75
+ | `version` | `"1"` | generator version, always sent |
76
+
77
+ - `rowsmith.generate(columns, ...)` (or `generate(schema=..., ...)`) returns a list of dicts for `json` (values typed as in the JSON) and `csv`
78
+ (values are strings), and the SQL text for `sql`.
79
+ - `rowsmith.fetch(columns, ...)` returns a `RowsmithResult` with `body` (the exact bytes), `text`, `sha256`,
80
+ `headers`, `generator_version`, `seed`, `reproduce`, `schema_unmapped`, `schema_version`, `output_sha256`,
81
+ `request_sha256`, `from_cache` and `parsed()`. `reproduce` is the service's
82
+ X-Reproduce line (sent with CSV and SQL answers, and kept in the cache); JSON answers carry none, so for them it
83
+ is the request that was sent, in the same form.
84
+ - On anything other than a successful answer the call raises `pytest_rowsmith.RowsmithError`. Its message names
85
+ the HTTP status, the service's error and `next` text, and the reproduce line. A 4xx answer is not retried; a 5xx
86
+ answer or a network error is retried exactly once, 1 second later. There is no fallback to random or local data.
87
+ - Each request times out after 30 s.
88
+
89
+ `pytest_rowsmith.Rowsmith` is the same client outside pytest (`Rowsmith(base_url=..., cache=None)`).
90
+
91
+ ## Golden manifests
92
+ Pin a dataset for an eval and detect drift. The service sends `X-Output-SHA256` (the sha256 of the body bytes) and
93
+ `X-Request-SHA256` (the sha256 of the canonical request, the same for a schema and the columns it maps to) with
94
+ every answer; the result exposes them as `output_sha256` and `request_sha256`, and the cache keeps them.
95
+ `request_sha256` is the X-Request-SHA256 header; without it, the sha256 of the body in a body-b64url X-Reproduce
96
+ line; otherwise None, and a run with `--rowsmith-refresh` fetches the answer again with its headers.
97
+ `output_sha256` without its header is computed from the body bytes.
98
+ ```python
99
+ ORDERS = [{"name": "order_id", "type": "sequence", "prefix": "ord_", "pad": 4}, {"name": "email", "type": "email"}]
100
+
101
+ def test_orders_are_golden(rowsmith):
102
+ result = rowsmith.fetch(ORDERS, rows=20, seed=42, format="csv")
103
+ entry = rowsmith.manifest_entry(result, "orders-v1") # save it once, e.g. into tests/golden.json
104
+ rowsmith.assert_golden(result, entry["output_sha256"]) # later: compare against the saved entry or its hash
105
+ ```
106
+ - `rowsmith.manifest_entry(result, name)` returns `{"name", "request_sha256", "output_sha256", "output_version",
107
+ "schema_version", "reproduce"}`, one entry of `{"rowsmith_manifest": 1, "entries": [...]}` (the format is in the
108
+ service's llms.txt). `reproduce` regenerates the bytes by itself: the service's X-Reproduce line when it carries
109
+ the body, otherwise the request the plugin sent.
110
+ - `rowsmith.assert_golden(result, expected)` takes a sha256 hex string or a manifest entry (then the request hash
111
+ must match too) and fails with both hashes, the versions, whether the answer came from the cache, and the
112
+ reproduce line. Both are also importable from `pytest_rowsmith`.
113
+ - The plugin pins the version in every request. A pinned version is served as long as the service runs; a retired version answers 409. A version's output is not changed in place: a golden test checks its bytes on every build.
114
+
115
+ ## Caching and offline runs
116
+ Answers are stored in pytest's own cache (`.pytest_cache/v/rowsmith/v1/` in your project), one entry per request,
117
+ keyed by the sha256 of the exact request-body bytes. An entry holds the response bytes and the headers
118
+ content-type, x-generator-version, x-seed, x-reproduce, x-request-sha256 and x-output-sha256, plus
119
+ x-schema-version and x-schema-unmapped for a schema request. A suite therefore calls the API once per distinct
120
+ request and then runs offline, as long as `.pytest_cache` is kept. A damaged entry is fetched again.
121
+
122
+ - `pytest --rowsmith-refresh` ignores the cache: each distinct request is sent once in that run and its entry is
123
+ replaced.
124
+ - `pytest --cache-clear` removes the cache, Rowsmith entries included.
125
+ - With pytest's cache disabled (`-p no:cacheprovider`), answers are kept in memory for the run only.
126
+ - The cache key does not include the base URL.
127
+
128
+ ## Configuration
129
+ | Setting | Where | Default |
130
+ |---|---|---|
131
+ | API base URL | `ROWSMITH_URL` environment variable, or `rowsmith_url` in your pytest ini file; the variable wins | `https://testdata-api.re-jam620.workers.dev` |
132
+ | Bypass the cache | `--rowsmith-refresh` | off |
133
+
134
+ Every request sends `User-Agent: pytest-rowsmith/<version>` and `x-rowsmith-tool: pytest`. The service counts these calls under tool pytest in its aggregate usage totals (counts only; nothing per caller).
135
+
136
+ ## Limits and terms
137
+ Up to 500 rows and 50 columns per call, with daily limits per caller; over a limit the call fails with the
138
+ service's 429 message. Use of the Rowsmith service is under its terms of use:
139
+ https://testdata-api.re-jam620.workers.dev/terms. Data notice: https://testdata-api.re-jam620.workers.dev/privacy.
140
+
141
+ The MIT licence covers this plugin's code only.
142
+
143
+ ## Development
144
+ ```sh
145
+ PYTHONPATH=src python -m pytest # offline: a local stub server stands in for the API
146
+ ROWSMITH_LIVE=1 PYTHONPATH=src python -m pytest # adds the live golden test (one real API call)
147
+ ```
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pytest-rowsmith"
7
+ dynamic = ["version"]
8
+ description = "pytest fixture for reproducible fake test data (CSV, JSON, SQL) from the free Rowsmith API, cached for offline runs."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ authors = [{ name = "meiorz" }]
13
+ requires-python = ">=3.9"
14
+ dependencies = ["pytest>=7"]
15
+ keywords = ["pytest", "fixtures", "test data", "fake data", "csv", "sql"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Framework :: Pytest",
19
+ "Intended Audience :: Developers",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3 :: Only",
23
+ "Programming Language :: Python :: 3.9",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Topic :: Software Development :: Testing",
29
+ ]
30
+
31
+ [project.urls]
32
+ Homepage = "https://github.com/meiorz/rowsmith-mcp/tree/main/pytest-rowsmith"
33
+ Source = "https://github.com/meiorz/rowsmith-mcp"
34
+ Issues = "https://github.com/meiorz/rowsmith-mcp/issues"
35
+
36
+ [project.entry-points.pytest11]
37
+ rowsmith = "pytest_rowsmith.plugin"
38
+
39
+ [tool.setuptools.dynamic]
40
+ version = { attr = "pytest_rowsmith.__version__" }
41
+
42
+ [tool.setuptools.packages.find]
43
+ where = ["src"]
44
+
45
+ [tool.pytest.ini_options]
46
+ testpaths = ["tests"]
47
+ markers = ["live: calls the real Rowsmith API; runs only with ROWSMITH_LIVE=1"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+