vastdb 0.1.1__py3-none-any.whl → 0.1.2__py3-none-any.whl
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.
- vastdb/__init__.py +6 -2
- vastdb/bench/test_perf.py +3 -3
- vastdb/bucket.py +10 -6
- vastdb/errors.py +12 -6
- vastdb/internal_commands.py +146 -152
- vastdb/schema.py +10 -5
- vastdb/table.py +49 -52
- vastdb/tests/test_duckdb.py +61 -0
- vastdb/tests/test_projections.py +1 -0
- vastdb/tests/test_sanity.py +2 -2
- vastdb/tests/test_schemas.py +2 -1
- vastdb/tests/test_tables.py +36 -51
- vastdb/tests/util.py +1 -4
- vastdb/transaction.py +16 -6
- vastdb/util.py +4 -3
- {vastdb-0.1.1.dist-info → vastdb-0.1.2.dist-info}/METADATA +1 -4
- {vastdb-0.1.1.dist-info → vastdb-0.1.2.dist-info}/RECORD +20 -19
- {vastdb-0.1.1.dist-info → vastdb-0.1.2.dist-info}/WHEEL +1 -1
- {vastdb-0.1.1.dist-info → vastdb-0.1.2.dist-info}/LICENSE +0 -0
- {vastdb-0.1.1.dist-info → vastdb-0.1.2.dist-info}/top_level.txt +0 -0
vastdb/__init__.py
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"""VAST Database Python SDK."""
|
|
2
2
|
|
|
3
|
+
import functools
|
|
4
|
+
|
|
3
5
|
from . import session
|
|
4
6
|
|
|
7
|
+
|
|
5
8
|
# A helper function, useful as a short-hand for Session c-tor: `session = vastdb.connect(...)`
|
|
6
|
-
|
|
7
|
-
connect
|
|
9
|
+
@functools.wraps(session.Session)
|
|
10
|
+
def connect(*args, **kwargs): # noqa: D103
|
|
11
|
+
return session.Session(*args, **kwargs)
|
vastdb/bench/test_perf.py
CHANGED
|
@@ -12,7 +12,7 @@ log = logging.getLogger(__name__)
|
|
|
12
12
|
|
|
13
13
|
@pytest.mark.benchmark
|
|
14
14
|
def test_bench(session, clean_bucket_name, parquets_path, crater_path):
|
|
15
|
-
files = [str(parquets_path/f) for f in (parquets_path.glob('**/*.pq'))]
|
|
15
|
+
files = [str(parquets_path / f) for f in (parquets_path.glob('**/*.pq'))]
|
|
16
16
|
|
|
17
17
|
with session.transaction() as tx:
|
|
18
18
|
b = tx.bucket(clean_bucket_name)
|
|
@@ -22,8 +22,8 @@ def test_bench(session, clean_bucket_name, parquets_path, crater_path):
|
|
|
22
22
|
s = time.time()
|
|
23
23
|
pa_table = pa.Table.from_batches(t.select(columns=['sid'], predicate=t['sid'] == 10033007, config=config))
|
|
24
24
|
e = time.time()
|
|
25
|
-
log.info("'SELECT sid from TABLE WHERE sid = 10033007' returned in %s seconds.", e-s)
|
|
25
|
+
log.info("'SELECT sid from TABLE WHERE sid = 10033007' returned in %s seconds.", e - s)
|
|
26
26
|
if crater_path:
|
|
27
27
|
with open(f'{crater_path}/bench_results', 'a') as f:
|
|
28
|
-
f.write(f"'SELECT sid FROM TABLE WHERE sid = 10033007' returned in {e-s} seconds")
|
|
28
|
+
f.write(f"'SELECT sid FROM TABLE WHERE sid = 10033007' returned in {e - s} seconds")
|
|
29
29
|
assert pa_table.num_rows == 255_075
|
vastdb/bucket.py
CHANGED
|
@@ -6,9 +6,13 @@ It is possible to list and access VAST snapshots generated over a bucket.
|
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
8
|
from dataclasses import dataclass
|
|
9
|
+
from typing import TYPE_CHECKING, List, Optional
|
|
9
10
|
|
|
10
11
|
from . import errors, schema, transaction
|
|
11
12
|
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from .schema import Schema
|
|
15
|
+
|
|
12
16
|
log = logging.getLogger(__name__)
|
|
13
17
|
|
|
14
18
|
|
|
@@ -27,7 +31,7 @@ class Bucket:
|
|
|
27
31
|
name: str
|
|
28
32
|
tx: "transaction.Transaction"
|
|
29
33
|
|
|
30
|
-
def create_schema(self, path: str, fail_if_exists=True) -> "
|
|
34
|
+
def create_schema(self, path: str, fail_if_exists=True) -> "Schema":
|
|
31
35
|
"""Create a new schema (a container of tables) under this bucket."""
|
|
32
36
|
if current := self.schema(path, fail_if_missing=False):
|
|
33
37
|
if fail_if_exists:
|
|
@@ -36,9 +40,9 @@ class Bucket:
|
|
|
36
40
|
return current
|
|
37
41
|
self.tx._rpc.api.create_schema(self.name, path, txid=self.tx.txid)
|
|
38
42
|
log.info("Created schema: %s", path)
|
|
39
|
-
return self.schema(path)
|
|
43
|
+
return self.schema(path) # type: ignore[return-value]
|
|
40
44
|
|
|
41
|
-
def schema(self, path: str, fail_if_missing=True) -> "
|
|
45
|
+
def schema(self, path: str, fail_if_missing=True) -> Optional["Schema"]:
|
|
42
46
|
"""Get a specific schema (a container of tables) under this bucket."""
|
|
43
47
|
s = self.schemas(path)
|
|
44
48
|
log.debug("schema: %s", s)
|
|
@@ -51,14 +55,14 @@ class Bucket:
|
|
|
51
55
|
log.debug("Found schema: %s", s[0].name)
|
|
52
56
|
return s[0]
|
|
53
57
|
|
|
54
|
-
def schemas(self, name: str = None) -> ["
|
|
58
|
+
def schemas(self, name: Optional[str] = None) -> List["Schema"]:
|
|
55
59
|
"""List bucket's schemas."""
|
|
56
60
|
schemas = []
|
|
57
61
|
next_key = 0
|
|
58
62
|
exact_match = bool(name)
|
|
59
63
|
log.debug("list schemas param: schema=%s, exact_match=%s", name, exact_match)
|
|
60
64
|
while True:
|
|
61
|
-
|
|
65
|
+
_bucket_name, curr_schemas, next_key, is_truncated, _ = \
|
|
62
66
|
self.tx._rpc.api.list_schemas(bucket=self.name, next_key=next_key, txid=self.tx.txid,
|
|
63
67
|
name_prefix=name, exact_match=exact_match)
|
|
64
68
|
if not curr_schemas:
|
|
@@ -69,7 +73,7 @@ class Bucket:
|
|
|
69
73
|
|
|
70
74
|
return [schema.Schema(name=name, bucket=self) for name, *_ in schemas]
|
|
71
75
|
|
|
72
|
-
def snapshots(self) -> [Snapshot]:
|
|
76
|
+
def snapshots(self) -> List[Snapshot]:
|
|
73
77
|
"""List bucket's snapshots."""
|
|
74
78
|
snapshots = []
|
|
75
79
|
next_key = 0
|
vastdb/errors.py
CHANGED
|
@@ -26,6 +26,7 @@ log = logging.getLogger(__name__)
|
|
|
26
26
|
class HttpError(Exception):
|
|
27
27
|
code: str
|
|
28
28
|
message: str
|
|
29
|
+
method: str
|
|
29
30
|
url: str
|
|
30
31
|
status: int # HTTP status
|
|
31
32
|
headers: requests.structures.CaseInsensitiveDict # HTTP response headers
|
|
@@ -88,6 +89,10 @@ class Missing(Exception):
|
|
|
88
89
|
pass
|
|
89
90
|
|
|
90
91
|
|
|
92
|
+
class MissingTransaction(Missing):
|
|
93
|
+
pass
|
|
94
|
+
|
|
95
|
+
|
|
91
96
|
@dataclass
|
|
92
97
|
class MissingBucket(Missing):
|
|
93
98
|
bucket: str
|
|
@@ -150,21 +155,22 @@ def from_response(res: requests.Response):
|
|
|
150
155
|
|
|
151
156
|
log.debug("response: url='%s', code=%s, headers=%s, body='%s'", res.request.url, res.status_code, res.headers, res.text)
|
|
152
157
|
# try to parse S3 XML response for the error details:
|
|
153
|
-
|
|
154
|
-
|
|
158
|
+
code_str = None
|
|
159
|
+
message_str = None
|
|
155
160
|
if res.text:
|
|
156
161
|
try:
|
|
157
162
|
root = xml.etree.ElementTree.fromstring(res.text)
|
|
158
163
|
code = root.find('Code')
|
|
159
|
-
|
|
164
|
+
code_str = code.text if code is not None else None
|
|
160
165
|
message = root.find('Message')
|
|
161
|
-
|
|
166
|
+
message_str = message.text if message is not None else None
|
|
162
167
|
except xml.etree.ElementTree.ParseError:
|
|
163
168
|
log.debug("invalid XML: %r", res.text)
|
|
164
169
|
|
|
165
170
|
kwargs = dict(
|
|
166
|
-
code=
|
|
167
|
-
message=
|
|
171
|
+
code=code_str,
|
|
172
|
+
message=message_str,
|
|
173
|
+
method=res.request.method,
|
|
168
174
|
url=res.request.url,
|
|
169
175
|
status=res.status_code,
|
|
170
176
|
headers=res.headers,
|