vbase-api 0.1.3__tar.gz → 0.1.4__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,17 @@
1
+ # Changelog
2
+
3
+ All notable changes are documented here, following
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
+ Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ Earlier releases were not tracked in this file; see the
8
+ [commit history](https://github.com/validityBase/vbase-api-py/commits/main/)
9
+ for prior changes.
10
+
11
+ ## [Unreleased]
12
+
13
+ ## [0.1.4] - 2026-10-26
14
+
15
+ ### Added
16
+
17
+ - Compatibility test matrix for Python 3.8, 3.11, and 3.12.
@@ -1 +1,2 @@
1
1
  include requirements.in
2
+ include CHANGELOG.md
@@ -1,13 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vbase-api
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: vBase REST API Python Client
5
5
  Author-email: vBase <tech@vbase.com>
6
- License-Expression: Apache-2.0
6
+ License: Apache-2.0
7
7
  Project-URL: Homepage, https://github.com/validityBase/vbase-api-py
8
8
  Project-URL: Documentation, https://docs.vbase.com/
9
9
  Keywords: vbase,stamping,web3,blockchain,validation
10
10
  Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
11
14
  Classifier: Operating System :: OS Independent
12
15
  Requires-Python: >=3.8
13
16
  Description-Content-Type: text/markdown
@@ -20,6 +23,8 @@ Dynamic: license-file
20
23
 
21
24
  vBase REST API Python Client
22
25
 
26
+ Requires Python 3.11 or newer.
27
+
23
28
  See [documentation](https://docs.vbase.com/) and the [Swagger UI](https://app.vbase.com/swagger/) for more details.
24
29
 
25
30
  ---
@@ -2,6 +2,8 @@
2
2
 
3
3
  vBase REST API Python Client
4
4
 
5
+ Requires Python 3.11 or newer.
6
+
5
7
  See [documentation](https://docs.vbase.com/) and the [Swagger UI](https://app.vbase.com/swagger/) for more details.
6
8
 
7
9
  ---
@@ -1,5 +1,5 @@
1
1
  [build-system]
2
- requires = ["setuptools >= 77.0.3"]
2
+ requires = ["setuptools >= 62.6"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
@@ -8,7 +8,7 @@ dynamic = ["version", "dependencies"]
8
8
  description = "vBase REST API Python Client"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
11
- license = "Apache-2.0"
11
+ license = {text = "Apache-2.0"}
12
12
  authors = [
13
13
  { name = "vBase", email = "tech@vbase.com" }
14
14
  ]
@@ -16,6 +16,9 @@ authors = [
16
16
  keywords = ["vbase", "stamping", "web3", "blockchain", "validation"]
17
17
  classifiers = [
18
18
  "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3 :: Only",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
19
22
  "Operating System :: OS Independent",
20
23
  ]
21
24
 
@@ -0,0 +1 @@
1
+ __version__ = "0.1.4"
@@ -1,13 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vbase-api
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: vBase REST API Python Client
5
5
  Author-email: vBase <tech@vbase.com>
6
- License-Expression: Apache-2.0
6
+ License: Apache-2.0
7
7
  Project-URL: Homepage, https://github.com/validityBase/vbase-api-py
8
8
  Project-URL: Documentation, https://docs.vbase.com/
9
9
  Keywords: vbase,stamping,web3,blockchain,validation
10
10
  Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
11
14
  Classifier: Operating System :: OS Independent
12
15
  Requires-Python: >=3.8
13
16
  Description-Content-Type: text/markdown
@@ -20,6 +23,8 @@ Dynamic: license-file
20
23
 
21
24
  vBase REST API Python Client
22
25
 
26
+ Requires Python 3.11 or newer.
27
+
23
28
  See [documentation](https://docs.vbase.com/) and the [Swagger UI](https://app.vbase.com/swagger/) for more details.
24
29
 
25
30
  ---
@@ -1,3 +1,4 @@
1
+ CHANGELOG.md
1
2
  LICENSE.txt
2
3
  MANIFEST.in
3
4
  NOTICE.txt
@@ -13,4 +14,5 @@ src/vbase_api.egg-info/SOURCES.txt
13
14
  src/vbase_api.egg-info/dependency_links.txt
14
15
  src/vbase_api.egg-info/requires.txt
15
16
  src/vbase_api.egg-info/top_level.txt
17
+ tests/test_api_client.py
16
18
  tests/test_file_integrity_e2e.py
@@ -0,0 +1,107 @@
1
+ """Client request/response contracts that run without live services."""
2
+
3
+ import json
4
+ import tempfile
5
+ import unittest
6
+ from pathlib import Path
7
+ from unittest.mock import patch
8
+
9
+ import requests
10
+
11
+ import vbase_api
12
+
13
+
14
+ class APIClientTests(unittest.TestCase):
15
+ def setUp(self):
16
+ self.client = vbase_api.VBaseAPIClient(
17
+ api_key="test-only-key", base_url="https://example.invalid", timeout=7
18
+ )
19
+ self.addCleanup(self.client.close)
20
+ self.receipt = {
21
+ "transaction_hash": "0xtransaction",
22
+ "user_address": "0xuser",
23
+ "set_cid": "0xset",
24
+ "object_cid": "0xobject",
25
+ "timestamp": "2026-10-26T00:00:00Z",
26
+ "chain_id": 1,
27
+ }
28
+
29
+ @staticmethod
30
+ def response(status, payload):
31
+ response = requests.Response()
32
+ response.status_code = status
33
+ response._content = json.dumps(payload).encode("utf-8")
34
+ return response
35
+
36
+ def test_collection_request_and_response(self):
37
+ payload = {
38
+ "id": 1,
39
+ "name": "Example",
40
+ "cid": "0xset",
41
+ "is_pinned": True,
42
+ "is_public": False,
43
+ "created_at": "2026-10-26T00:00:00Z",
44
+ "description": "Example collection",
45
+ }
46
+ with patch.object(
47
+ self.client.session, "post", return_value=self.response(201, payload)
48
+ ) as post:
49
+ collection = self.client.create_collection("Example", "Example collection")
50
+ self.assertEqual(collection.cid, "0xset")
51
+ self.assertEqual(collection.name, "Example")
52
+ post.assert_called_once_with(
53
+ "https://example.invalid/api/v1/collections",
54
+ json={
55
+ "name": "Example",
56
+ "cid": None,
57
+ "description": "Example collection",
58
+ "is_pinned": True,
59
+ },
60
+ timeout=7,
61
+ )
62
+
63
+ def test_stamp_response_types(self):
64
+ for status, expected in [
65
+ (200, vbase_api.IdempotentStampResponse),
66
+ (201, vbase_api.StampCreatedResponse),
67
+ ]:
68
+ with self.subTest(status=status):
69
+ with patch.object(
70
+ self.client.session,
71
+ "post",
72
+ return_value=self.response(
73
+ status, {"commitment_receipt": self.receipt}
74
+ ),
75
+ ):
76
+ stamp = self.client.create_stamp(data_cid="0xobject")
77
+ self.assertIsInstance(stamp, expected)
78
+ self.assertEqual(stamp.commitment_receipt.object_cid, "0xobject")
79
+
80
+ def test_upload_closes_file_after_request(self):
81
+ with tempfile.TemporaryDirectory() as directory:
82
+ path = Path(directory) / "example.bin"
83
+ path.write_bytes(b"example")
84
+ with patch.object(
85
+ self.client.session,
86
+ "post",
87
+ return_value=self.response(201, {"commitment_receipt": self.receipt}),
88
+ ) as post:
89
+ result = self.client.upload_stamped_file("Example", path)
90
+ uploaded = post.call_args.kwargs["files"]["file"][1]
91
+ self.assertTrue(uploaded.closed)
92
+ self.assertEqual(result.commitment_receipt.object_cid, "0xobject")
93
+
94
+ def test_api_error_preserves_status_and_message(self):
95
+ with patch.object(
96
+ self.client.session,
97
+ "get",
98
+ return_value=self.response(403, {"error": "Access denied"}),
99
+ ):
100
+ with self.assertRaises(vbase_api.VBaseAPIError) as raised:
101
+ self.client.get_collections()
102
+ self.assertEqual(raised.exception.status_code, 403)
103
+ self.assertEqual(str(raised.exception), "[403] Access denied")
104
+
105
+
106
+ if __name__ == "__main__":
107
+ unittest.main()
@@ -9,6 +9,7 @@ environment variables.
9
9
  from __future__ import annotations
10
10
 
11
11
  import hashlib
12
+ import importlib.metadata as metadata
12
13
  import os
13
14
  import tempfile
14
15
  import time
@@ -26,6 +27,7 @@ except ImportError as exc: # pragma: no cover
26
27
  "Install requirements/e2e.txt to run live file-integrity E2E tests."
27
28
  ) from exc
28
29
 
30
+ import vbase_api
29
31
  from vbase_api import VBaseAPIClient, VBaseAPIError
30
32
 
31
33
 
@@ -54,6 +56,48 @@ def _int_env(name: str, default: int) -> int:
54
56
  ) from None
55
57
 
56
58
 
59
+ def _log_and_assert_package_source() -> None:
60
+ install_source = _first_env("VBASE_API_PACKAGE_SOURCE")
61
+ if not install_source:
62
+ return
63
+
64
+ package_path = Path(vbase_api.__file__).resolve()
65
+ package_version = getattr(vbase_api, "__version__", "unknown")
66
+ try:
67
+ distribution_version = metadata.version("vbase-api")
68
+ except metadata.PackageNotFoundError:
69
+ distribution_version = "not installed"
70
+ print(
71
+ "vbase-api "
72
+ f"package_version={package_version} "
73
+ f"distribution_version={distribution_version} "
74
+ f"imported from {package_path}"
75
+ )
76
+
77
+ repo_root_raw = _first_env("GITHUB_WORKSPACE")
78
+ if not repo_root_raw:
79
+ return
80
+
81
+ repo_root = Path(repo_root_raw).resolve()
82
+ try:
83
+ package_path.relative_to(repo_root)
84
+ package_in_repo = True
85
+ except ValueError:
86
+ package_in_repo = False
87
+
88
+ if install_source == "source":
89
+ if not package_in_repo:
90
+ raise AssertionError(
91
+ "Source-install E2E run imported vbase_api outside the checkout: "
92
+ f"{package_path}"
93
+ )
94
+ elif install_source == "pypi" and package_in_repo:
95
+ raise AssertionError(
96
+ "PyPI-install E2E run imported vbase_api from the checkout instead of "
97
+ f"site-packages: {package_path}"
98
+ )
99
+
100
+
57
101
  @dataclass(frozen=True)
58
102
  class LiveE2EConfig:
59
103
  """Configuration needed for live app/API file-integrity tests."""
@@ -119,6 +163,7 @@ class VBaseAPIClientFileIntegrityE2ETests(unittest.TestCase):
119
163
 
120
164
  @classmethod
121
165
  def setUpClass(cls) -> None:
166
+ _log_and_assert_package_source()
122
167
  cls.config = LiveE2EConfig.from_env()
123
168
  cls.client = VBaseAPIClient(
124
169
  api_key=cls.config.api_key,
@@ -1 +0,0 @@
1
- __version__ = "0.1.3"
File without changes
File without changes
File without changes
File without changes