mcp-api-test 0.1.4__tar.gz → 0.2.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.
Files changed (29) hide show
  1. {mcp_api_test-0.1.4/src/mcp_api_test.egg-info → mcp_api_test-0.2.0}/PKG-INFO +5 -2
  2. {mcp_api_test-0.1.4 → mcp_api_test-0.2.0}/README.md +2 -0
  3. {mcp_api_test-0.1.4 → mcp_api_test-0.2.0}/pyproject.toml +18 -6
  4. mcp_api_test-0.2.0/src/mcp_api_test/__init__.py +3 -0
  5. {mcp_api_test-0.1.4/src → mcp_api_test-0.2.0/src/mcp_api_test}/__main__.py +1 -1
  6. {mcp_api_test-0.1.4/src → mcp_api_test-0.2.0/src/mcp_api_test}/flags.py +1 -1
  7. {mcp_api_test-0.1.4/src → mcp_api_test-0.2.0/src/mcp_api_test}/logger.py +4 -3
  8. mcp_api_test-0.2.0/src/mcp_api_test/py.typed +0 -0
  9. {mcp_api_test-0.1.4/src → mcp_api_test-0.2.0/src/mcp_api_test}/server.py +27 -19
  10. {mcp_api_test-0.1.4/src → mcp_api_test-0.2.0/src/mcp_api_test}/utils.py +1 -1
  11. {mcp_api_test-0.1.4 → mcp_api_test-0.2.0/src/mcp_api_test.egg-info}/PKG-INFO +5 -2
  12. {mcp_api_test-0.1.4 → mcp_api_test-0.2.0}/src/mcp_api_test.egg-info/SOURCES.txt +9 -6
  13. mcp_api_test-0.2.0/src/mcp_api_test.egg-info/entry_points.txt +2 -0
  14. {mcp_api_test-0.1.4 → mcp_api_test-0.2.0}/src/mcp_api_test.egg-info/requires.txt +2 -1
  15. mcp_api_test-0.2.0/src/mcp_api_test.egg-info/top_level.txt +1 -0
  16. {mcp_api_test-0.1.4 → mcp_api_test-0.2.0}/tests/test_mcp_api_tools.py +1 -1
  17. mcp_api_test-0.2.0/tests/test_mcp_server_compat.py +30 -0
  18. mcp_api_test-0.2.0/tests/test_packaging.py +49 -0
  19. {mcp_api_test-0.1.4 → mcp_api_test-0.2.0}/tests/test_parse_curl_command.py +1 -2
  20. {mcp_api_test-0.1.4 → mcp_api_test-0.2.0}/tests/test_parse_status_code.py +1 -1
  21. {mcp_api_test-0.1.4 → mcp_api_test-0.2.0}/tests/test_utils.py +1 -1
  22. mcp_api_test-0.1.4/src/mcp_api_test.egg-info/entry_points.txt +0 -2
  23. mcp_api_test-0.1.4/src/mcp_api_test.egg-info/top_level.txt +0 -6
  24. mcp_api_test-0.1.4/tests/test_packaging.py +0 -46
  25. {mcp_api_test-0.1.4 → mcp_api_test-0.2.0}/LICENSE +0 -0
  26. {mcp_api_test-0.1.4 → mcp_api_test-0.2.0}/MANIFEST.in +0 -0
  27. {mcp_api_test-0.1.4 → mcp_api_test-0.2.0}/setup.cfg +0 -0
  28. {mcp_api_test-0.1.4/src → mcp_api_test-0.2.0/src/mcp_api_test}/models.py +0 -0
  29. {mcp_api_test-0.1.4 → mcp_api_test-0.2.0}/src/mcp_api_test.egg-info/dependency_links.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-api-test
3
- Version: 0.1.4
3
+ Version: 0.2.0
4
4
  Summary: MCP server for testing REST API with built-in assertions
5
5
  Author: Ryan Febriansyah
6
6
  License-Expression: MIT
@@ -18,13 +18,14 @@ Classifier: Topic :: Software Development :: Testing
18
18
  Requires-Python: >=3.10
19
19
  Description-Content-Type: text/markdown
20
20
  License-File: LICENSE
21
- Requires-Dist: mcp<2.0.0,>=1.0.0
21
+ Requires-Dist: mcp<3.0.0,>=2.0.0
22
22
  Requires-Dist: httpx
23
23
  Requires-Dist: python-dotenv
24
24
  Provides-Extra: dev
25
25
  Requires-Dist: pytest; extra == "dev"
26
26
  Requires-Dist: pytest-asyncio; extra == "dev"
27
27
  Requires-Dist: respx; extra == "dev"
28
+ Requires-Dist: mypy; extra == "dev"
28
29
  Provides-Extra: docs
29
30
  Requires-Dist: mkdocs-material; extra == "docs"
30
31
  Dynamic: license-file
@@ -39,6 +40,8 @@ Unlike traditional testing frameworks, `mcp-api-test` exposes API testing as a *
39
40
 
40
41
  It complements (rather than replaces) tools like pytest, Postman, and Playwright.
41
42
 
43
+ > **Breaking changes in v0.2.0.** The server now runs on `mcp` 2.x, and the package layout moved from flat top-level modules to a proper `mcp_api_test` package. If you import internals directly, you may update to `from mcp_api_test.server import ...`. MCP client configuration (OpenCode, Claude Desktop, Claude Code) is unaffected. See the [changelog](docs/changelog.md) for details.
44
+
42
45
  ## Use cases
43
46
 
44
47
  - **QA & test engineering**: prompt an agent with natural language instead of crafting Postman requests
@@ -8,6 +8,8 @@ Unlike traditional testing frameworks, `mcp-api-test` exposes API testing as a *
8
8
 
9
9
  It complements (rather than replaces) tools like pytest, Postman, and Playwright.
10
10
 
11
+ > **Breaking changes in v0.2.0.** The server now runs on `mcp` 2.x, and the package layout moved from flat top-level modules to a proper `mcp_api_test` package. If you import internals directly, you may update to `from mcp_api_test.server import ...`. MCP client configuration (OpenCode, Claude Desktop, Claude Code) is unaffected. See the [changelog](docs/changelog.md) for details.
12
+
11
13
  ## Use cases
12
14
 
13
15
  - **QA & test engineering**: prompt an agent with natural language instead of crafting Postman requests
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mcp-api-test"
3
- version = "0.1.4"
3
+ version = "0.2.0"
4
4
  description = "MCP server for testing REST API with built-in assertions"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -10,7 +10,7 @@ authors = [
10
10
 
11
11
  requires-python = ">=3.10"
12
12
  dependencies = [
13
- "mcp>=1.0.0,<2.0.0",
13
+ "mcp>=2.0.0,<3.0.0",
14
14
  "httpx",
15
15
  "python-dotenv"
16
16
  ]
@@ -31,7 +31,7 @@ classifiers = [
31
31
  ]
32
32
 
33
33
  [project.scripts]
34
- mcp-api-test = "server:main"
34
+ mcp-api-test = "mcp_api_test.server:main"
35
35
 
36
36
  [build-system]
37
37
  requires = ["setuptools>=61"]
@@ -39,8 +39,20 @@ build-backend = "setuptools.build_meta"
39
39
 
40
40
  [tool.setuptools]
41
41
  package-dir = {"" = "src"}
42
- py-modules = ["server", "__main__", "logger", "models", "utils", "flags"]
42
+ packages = ["mcp_api_test"]
43
+
44
+ [tool.setuptools.package-data]
45
+ mcp_api_test = ["py.typed"]
43
46
 
44
47
  [project.optional-dependencies]
45
- dev = ["pytest", "pytest-asyncio", "respx"]
46
- docs = ["mkdocs-material"]
48
+ dev = ["pytest", "pytest-asyncio", "respx", "mypy"]
49
+ docs = ["mkdocs-material"]
50
+
51
+ [tool.mypy]
52
+ python_version = "3.10"
53
+ packages = ["mcp_api_test"]
54
+ check_untyped_defs = true
55
+ disallow_untyped_defs = true
56
+ no_implicit_optional = true
57
+ warn_redundant_casts = true
58
+ warn_unused_ignores = true
@@ -0,0 +1,3 @@
1
+ """Lightweight MCP for REST API testing for Claude Desktop and OpenCode"""
2
+
3
+ __version__ = "0.2.0"
@@ -1,6 +1,6 @@
1
1
  """Entry point for the initialize mcp-api-test package when run as a module"""
2
2
 
3
- from src.server import mcp
3
+ from .server import mcp
4
4
 
5
5
  if __name__ == "__main__":
6
6
  mcp.run()
@@ -28,7 +28,7 @@ CURL_VALUE_FLAGS: dict[str, str] = {
28
28
  }
29
29
 
30
30
  # standalone flags with no following value
31
- CURL_BOOLEAN_FLAGS: dict[str, str] = {
31
+ CURL_BOOLEAN_FLAGS: set[str] = {
32
32
  "-L",
33
33
  "--location", # follow redirects, very common in browser exports
34
34
  "-k",
@@ -1,5 +1,6 @@
1
1
  import logging
2
2
  import os
3
+ from typing import Any
3
4
 
4
5
 
5
6
  class Logger:
@@ -31,7 +32,7 @@ class Logger:
31
32
 
32
33
  self.logger.addHandler(file_handler)
33
34
 
34
- def info(self, message: str, *args, **kwargs) -> None:
35
+ def info(self, message: str, *args: Any, **kwargs: Any) -> None:
35
36
  """
36
37
  Log an info message with particular arguments
37
38
  """
@@ -39,7 +40,7 @@ class Logger:
39
40
  message = message % args
40
41
  self.logger.info(message, **kwargs)
41
42
 
42
- def warning(self, message: str, *args, **kwargs) -> None:
43
+ def warning(self, message: str, *args: Any, **kwargs: Any) -> None:
43
44
  """
44
45
  Log a warning message with particular arguments
45
46
  """
@@ -47,7 +48,7 @@ class Logger:
47
48
  message = message % args
48
49
  self.logger.warning(message, **kwargs)
49
50
 
50
- def error(self, message: str, *args, **kwargs) -> None:
51
+ def error(self, message: str, *args: Any, **kwargs: Any) -> None:
51
52
  """
52
53
  Log an error message with particular arguments
53
54
  """
File without changes
@@ -2,26 +2,26 @@ import json
2
2
  import shlex
3
3
  import time
4
4
  import httpx
5
- from logger import get_logger
6
5
  from dotenv import load_dotenv
7
6
  from urllib.parse import urlparse
8
7
  from typing import Optional, Dict, Any, List
9
- from mcp.server.fastmcp import FastMCP
10
- from models import APITestResult, AssertionResult
11
- from utils import (
8
+ from mcp.server.mcpserver import MCPServer
9
+ from .logger import get_logger
10
+ from .models import APITestResult, AssertionResult
11
+ from .utils import (
12
12
  render_console_template_result,
13
13
  render_error_result,
14
14
  build_fullpath_url,
15
15
  get_nested_fields,
16
16
  )
17
- from flags import CURL_BOOLEAN_FLAGS, CURL_VALUE_FLAGS, CURL_WARN_FLAGS
17
+ from .flags import CURL_BOOLEAN_FLAGS, CURL_VALUE_FLAGS, CURL_WARN_FLAGS
18
18
 
19
19
  load_dotenv()
20
20
 
21
21
  logger = get_logger(name="mcp-api-testing")
22
22
 
23
23
 
24
- mcp = FastMCP("mcp-api-test")
24
+ mcp = MCPServer("mcp-api-test")
25
25
 
26
26
 
27
27
  def parse_status_code_range(range_str: str) -> tuple[int, int]:
@@ -162,7 +162,7 @@ async def run_test_api(
162
162
  required_status_code_range: Optional[str] = None,
163
163
  required_response_fields: Optional[List[str]] = None,
164
164
  required_response_contains: Optional[str] = None,
165
- ):
165
+ ) -> str:
166
166
  """
167
167
  Test a given API services, it will supports either:
168
168
 
@@ -192,19 +192,27 @@ async def run_test_api(
192
192
  full_path_url = build_fullpath_url(base_url=base_url, endpoint=endpoint)
193
193
  method = method.upper()
194
194
 
195
+ content: Optional[str] = None
196
+ json_payload: Optional[Dict[str, Any]] = None
197
+ if payload is not None:
198
+ # cURL parser may produce a raw string for non-JSON -d payloads
199
+ # (example: form-encoded data). Use content= to send as-is rather
200
+ # than json= which would double-encode the string.
201
+ if isinstance(payload, str):
202
+ content = payload
203
+ else:
204
+ json_payload = payload
205
+
195
206
  start_time = time.perf_counter()
196
207
  try:
197
208
  async with httpx.AsyncClient(timeout=30) as client:
198
- kwargs = {"method": method, "url": full_path_url, "headers": headers}
199
- if payload is not None:
200
- # cURL parser may produce a raw string for non-JSON -d payloads
201
- # (example: form-encoded data). Use content= to send as-is rather
202
- # than json= which would double-encode the string.
203
- if isinstance(payload, str):
204
- kwargs["content"] = payload
205
- else:
206
- kwargs["json"] = payload
207
- response = await client.request(**kwargs)
209
+ response = await client.request(
210
+ method=method,
211
+ url=full_path_url,
212
+ headers=headers,
213
+ content=content,
214
+ json=json_payload,
215
+ )
208
216
  end_time = time.perf_counter()
209
217
  response_time_ms = (end_time - start_time) * 1000
210
218
  except Exception as e:
@@ -223,7 +231,7 @@ async def run_test_api(
223
231
  )
224
232
  resp_body = response.text
225
233
 
226
- assertions = []
234
+ assertions: List[Dict[str, Any]] = []
227
235
 
228
236
  if required_status_code is not None:
229
237
  passed = response.status_code == required_status_code
@@ -321,7 +329,7 @@ async def run_test_api(
321
329
 
322
330
 
323
331
  # expose this function so it can be called in toml files
324
- def main():
332
+ def main() -> None:
325
333
  mcp.run()
326
334
 
327
335
 
@@ -1,7 +1,7 @@
1
1
  """Utility functions for MCP API testing"""
2
2
 
3
3
  from typing import Any
4
- from models import APITestResult
4
+ from .models import APITestResult
5
5
 
6
6
 
7
7
  def render_console_template_result(result: APITestResult) -> str:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-api-test
3
- Version: 0.1.4
3
+ Version: 0.2.0
4
4
  Summary: MCP server for testing REST API with built-in assertions
5
5
  Author: Ryan Febriansyah
6
6
  License-Expression: MIT
@@ -18,13 +18,14 @@ Classifier: Topic :: Software Development :: Testing
18
18
  Requires-Python: >=3.10
19
19
  Description-Content-Type: text/markdown
20
20
  License-File: LICENSE
21
- Requires-Dist: mcp<2.0.0,>=1.0.0
21
+ Requires-Dist: mcp<3.0.0,>=2.0.0
22
22
  Requires-Dist: httpx
23
23
  Requires-Dist: python-dotenv
24
24
  Provides-Extra: dev
25
25
  Requires-Dist: pytest; extra == "dev"
26
26
  Requires-Dist: pytest-asyncio; extra == "dev"
27
27
  Requires-Dist: respx; extra == "dev"
28
+ Requires-Dist: mypy; extra == "dev"
28
29
  Provides-Extra: docs
29
30
  Requires-Dist: mkdocs-material; extra == "docs"
30
31
  Dynamic: license-file
@@ -39,6 +40,8 @@ Unlike traditional testing frameworks, `mcp-api-test` exposes API testing as a *
39
40
 
40
41
  It complements (rather than replaces) tools like pytest, Postman, and Playwright.
41
42
 
43
+ > **Breaking changes in v0.2.0.** The server now runs on `mcp` 2.x, and the package layout moved from flat top-level modules to a proper `mcp_api_test` package. If you import internals directly, you may update to `from mcp_api_test.server import ...`. MCP client configuration (OpenCode, Claude Desktop, Claude Code) is unaffected. See the [changelog](docs/changelog.md) for details.
44
+
42
45
  ## Use cases
43
46
 
44
47
  - **QA & test engineering**: prompt an agent with natural language instead of crafting Postman requests
@@ -2,12 +2,14 @@ LICENSE
2
2
  MANIFEST.in
3
3
  README.md
4
4
  pyproject.toml
5
- src/__main__.py
6
- src/flags.py
7
- src/logger.py
8
- src/models.py
9
- src/server.py
10
- src/utils.py
5
+ src/mcp_api_test/__init__.py
6
+ src/mcp_api_test/__main__.py
7
+ src/mcp_api_test/flags.py
8
+ src/mcp_api_test/logger.py
9
+ src/mcp_api_test/models.py
10
+ src/mcp_api_test/py.typed
11
+ src/mcp_api_test/server.py
12
+ src/mcp_api_test/utils.py
11
13
  src/mcp_api_test.egg-info/PKG-INFO
12
14
  src/mcp_api_test.egg-info/SOURCES.txt
13
15
  src/mcp_api_test.egg-info/dependency_links.txt
@@ -15,6 +17,7 @@ src/mcp_api_test.egg-info/entry_points.txt
15
17
  src/mcp_api_test.egg-info/requires.txt
16
18
  src/mcp_api_test.egg-info/top_level.txt
17
19
  tests/test_mcp_api_tools.py
20
+ tests/test_mcp_server_compat.py
18
21
  tests/test_packaging.py
19
22
  tests/test_parse_curl_command.py
20
23
  tests/test_parse_status_code.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ mcp-api-test = mcp_api_test.server:main
@@ -1,4 +1,4 @@
1
- mcp<2.0.0,>=1.0.0
1
+ mcp<3.0.0,>=2.0.0
2
2
  httpx
3
3
  python-dotenv
4
4
 
@@ -6,6 +6,7 @@ python-dotenv
6
6
  pytest
7
7
  pytest-asyncio
8
8
  respx
9
+ mypy
9
10
 
10
11
  [docs]
11
12
  mkdocs-material
@@ -0,0 +1 @@
1
+ mcp_api_test
@@ -3,7 +3,7 @@
3
3
  import pytest
4
4
  import respx
5
5
  import httpx
6
- from src.server import run_test_api
6
+ from mcp_api_test.server import run_test_api
7
7
 
8
8
 
9
9
  @pytest.mark.asyncio
@@ -0,0 +1,30 @@
1
+ """Regression tests for the mcp 2.x migration (FastMCP -> MCPServer)"""
2
+
3
+ import pytest
4
+ from mcp_api_test.server import mcp
5
+
6
+
7
+ def test_server_is_built_on_mcpserver():
8
+ # regression: mcp 2.x removed mcp.server.fastmcp.FastMCP in favor of
9
+ # mcp.server.mcpserver.MCPServer; importing the old path now raises
10
+ # ModuleNotFoundError instead of silently breaking at a later call site
11
+ from mcp.server.mcpserver import MCPServer
12
+
13
+ assert isinstance(mcp, MCPServer)
14
+
15
+
16
+ def test_old_fastmcp_import_path_is_gone():
17
+ # confirms we're actually running against the mcp 2.x line pinned in
18
+ # pyproject.toml, not an mcp 1.x install that would mask this migration
19
+ with pytest.raises(ModuleNotFoundError):
20
+ import mcp.server.fastmcp # noqa: F401
21
+
22
+
23
+ def test_run_test_api_is_registered_as_a_tool():
24
+ # @mcp.tool() kept the same decorator signature across the migration;
25
+ # this would fail if MCPServer's tool manager changed shape
26
+ import asyncio
27
+
28
+ tools = asyncio.run(mcp.list_tools())
29
+ tool_names = {tool.name for tool in tools}
30
+ assert "run_test_api" in tool_names
@@ -0,0 +1,49 @@
1
+ """Static checks that the source layout matches the wheel packaging config"""
2
+
3
+ import tomllib
4
+ from pathlib import Path
5
+
6
+ PROJECT_ROOT = Path(__file__).resolve().parents[1]
7
+ PACKAGE_DIR = PROJECT_ROOT / "src" / "mcp_api_test"
8
+
9
+
10
+ def _pyproject() -> dict:
11
+ with open(PROJECT_ROOT / "pyproject.toml", "rb") as f:
12
+ return tomllib.load(f)
13
+
14
+
15
+ def _project_version() -> str:
16
+ return _pyproject()["project"]["version"]
17
+
18
+
19
+ def test_declared_package_matches_src_directory():
20
+ packages = _pyproject()["tool"]["setuptools"]["packages"]
21
+ assert packages == ["mcp_api_test"]
22
+ assert PACKAGE_DIR.is_dir()
23
+
24
+
25
+ def test_all_modules_exist_in_package_dir():
26
+ # regression: flat py-modules layout drifting from the package dir
27
+ expected = {"server", "utils", "models", "logger", "flags", "__init__", "__main__"}
28
+ actual = {p.stem for p in PACKAGE_DIR.glob("*.py")}
29
+ assert expected <= actual
30
+
31
+
32
+ def test_py_typed_marker_exists_and_is_packaged():
33
+ # PEP 561: inline-typed packages must ship a py.typed marker
34
+ assert (PACKAGE_DIR / "py.typed").exists()
35
+
36
+ package_data = _pyproject()["tool"]["setuptools"]["package-data"]
37
+ assert "py.typed" in package_data.get("mcp_api_test", [])
38
+
39
+
40
+ def test_entry_point_targets_the_package():
41
+ scripts = _pyproject()["project"]["scripts"]
42
+ assert scripts["mcp-api-test"] == "mcp_api_test.server:main"
43
+
44
+
45
+ def test_version_matches_pyproject():
46
+ # regression: src/mcp_api_test/__init__.py __version__ drifted from pyproject.toml
47
+ import mcp_api_test
48
+
49
+ assert mcp_api_test.__version__ == _project_version()
@@ -1,9 +1,8 @@
1
1
  """Unit tests for the cURL command parser"""
2
2
 
3
3
  import logging
4
-
5
4
  import pytest
6
- from src.server import parse_curl_command
5
+ from mcp_api_test.server import parse_curl_command
7
6
 
8
7
 
9
8
  def test_basic_curl_command():
@@ -1,5 +1,5 @@
1
1
  import pytest
2
- from src.server import parse_status_code_range
2
+ from mcp_api_test.server import parse_status_code_range
3
3
 
4
4
 
5
5
  @pytest.mark.parametrize(
@@ -1,6 +1,6 @@
1
1
  """Unit tests for URL building helpers"""
2
2
 
3
- from src.utils import build_fullpath_url
3
+ from mcp_api_test.utils import build_fullpath_url
4
4
 
5
5
 
6
6
  def test_empty_endpoint_returns_base_with_slash():
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- mcp-api-test = server:main
@@ -1,6 +0,0 @@
1
- __main__
2
- flags
3
- logger
4
- models
5
- server
6
- utils
@@ -1,46 +0,0 @@
1
- """Static checks that the source layout matches the wheel packaging config"""
2
-
3
- import tomllib
4
- from pathlib import Path
5
-
6
- PROJECT_ROOT = Path(__file__).resolve().parents[1]
7
- SRC_DIR = PROJECT_ROOT / "src"
8
-
9
-
10
- def _packaged_modules() -> list[str]:
11
- with open(PROJECT_ROOT / "pyproject.toml", "rb") as f:
12
- config = tomllib.load(f)
13
- return config["tool"]["setuptools"]["py-modules"]
14
-
15
-
16
- def _project_version() -> str:
17
- with open(PROJECT_ROOT / "pyproject.toml", "rb") as f:
18
- config = tomllib.load(f)
19
- return config["project"]["version"]
20
-
21
-
22
- def test_all_src_modules_are_packaged():
23
- src_modules = {
24
- p.stem
25
- for p in SRC_DIR.glob("*.py")
26
- if p.name != "__init__.py" and not p.name.startswith("__")
27
- }
28
- missing = src_modules - set(_packaged_modules())
29
- assert not missing, (
30
- f"Modules in src/ that are missing from pyproject.toml "
31
- f"[tool.setuptools] py-modules: {sorted(missing)}"
32
- )
33
-
34
-
35
- def test_packaged_modules_exist_in_src():
36
- for module in _packaged_modules():
37
- assert (
38
- SRC_DIR / f"{module}.py"
39
- ).exists(), f"'{module}' is listed in py-modules but has no src/{module}.py"
40
-
41
-
42
- def test_version_matches_pyproject():
43
- # regression: src/__init__.py __version__ drifted from pyproject.toml
44
- import src
45
-
46
- assert src.__version__ == _project_version()
File without changes
File without changes
File without changes