Skip to content

Commit 807fbd2

Browse files
committed
Merge branch 'main' of https://github.com/seung-lab/KVDbClient into main
2 parents 755670d + 2d5dd23 commit 807fbd2

File tree

13 files changed

+888
-15
lines changed

13 files changed

+888
-15
lines changed

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include requirements.txt

kvdbclient/__init__.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from collections import namedtuple
2+
3+
from .bigtable.client import Client as BigTableClient
4+
from .bigtable.attributes import Attribute
5+
from .serializers import Serializer
6+
from .serializers import UInt64String
7+
8+
9+
_backend_clientinfo_fields = ("TYPE", "CONFIG")
10+
_backend_clientinfo_defaults = (None, None)
11+
BackendClientInfo = namedtuple(
12+
"BackendClientInfo",
13+
_backend_clientinfo_fields,
14+
defaults=_backend_clientinfo_defaults,
15+
)
16+
17+
18+
def get_default_client_info():
19+
"""
20+
Load client from env variables.
21+
"""
22+
23+
# TODO make dynamic after multiple platform support is added
24+
from .bigtable import get_client_config as get_bigtable_client_config
25+
26+
return BackendClientInfo(
27+
CONFIG=get_bigtable_client_config(admin=True, read_only=False)
28+
)

kvdbclient/__version__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = "0.1.0"

kvdbclient/base.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
from abc import ABC
2+
from typing import Any
3+
from typing import Dict
4+
from typing import Tuple
5+
from typing import Callable
6+
from typing import Iterable
7+
from typing import Optional
8+
from datetime import datetime
9+
10+
from .serializers import Serializer
11+
from .serializers import UInt64String
12+
13+
14+
class SimpleClient(ABC):
15+
from abc import abstractmethod
16+
17+
"""
18+
Abstract class for interacting with backend data storage system.
19+
Eg., BigTableClient for using big table as storage.
20+
"""
21+
22+
@abstractmethod
23+
def create_table(self) -> None:
24+
"""Initialize the table and store associated meta."""
25+
26+
@abstractmethod
27+
def write_metadata(self, metadata):
28+
"""Update stored metadata."""
29+
30+
@abstractmethod
31+
def read_metadata(self):
32+
"""Read stored metadata."""
33+
34+
@abstractmethod
35+
def read_entries(
36+
self,
37+
entry_ids,
38+
properties=None,
39+
start_time=None,
40+
end_time=None,
41+
end_time_inclusive=False,
42+
):
43+
"""Read entries and their properties."""
44+
45+
@abstractmethod
46+
def read_entry(
47+
self,
48+
entry_id,
49+
properties=None,
50+
start_time=None,
51+
end_time=None,
52+
end_time_inclusive=False,
53+
):
54+
"""Read a single entry and it's properties."""
55+
56+
@abstractmethod
57+
def write_entries(self, entries):
58+
"""Writes/updates entries (IDs along with properties)."""
59+
60+
61+
class EntryKey:
62+
def __init__(self, key: Any, serializer: Optional[Serializer] = UInt64String()):
63+
self._key = key
64+
self._serializer = serializer.serialize
65+
66+
def serialize(self) -> Any:
67+
return self._serializer(self._key)
68+
69+
70+
class Entry:
71+
"""
72+
Represents a single entry/record/entity in the database.
73+
"""
74+
75+
def __init__(
76+
self,
77+
key: EntryKey,
78+
val_dict: Dict[Any, Any],
79+
timestamp: Optional[datetime] = None,
80+
):
81+
self._key = key
82+
self._val_dict = val_dict
83+
self._timestamp = timestamp
84+
85+
@property
86+
def key(self) -> Any:
87+
return self._key.serialize()
88+
89+
@property
90+
def values(self) -> Dict:
91+
return self._val_dict
92+
93+
@property
94+
def timestamp(self):
95+
return self._timestamp

kvdbclient/bigtable/__init__.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from collections import namedtuple
2+
from typing import Any
3+
from typing import Iterable
4+
from typing import Tuple
5+
6+
from .attributes import Attribute
7+
8+
DEFAULT_PROJECT = "neuromancer-seung-import"
9+
DEFAULT_INSTANCE = "pychunkedgraph"
10+
11+
_bigtableconfig_fields = (
12+
"PROJECT",
13+
"INSTANCE",
14+
"ADMIN",
15+
"READ_ONLY",
16+
"CREDENTIALS",
17+
)
18+
_bigtableconfig_defaults = (
19+
DEFAULT_PROJECT,
20+
DEFAULT_INSTANCE,
21+
True,
22+
False,
23+
None,
24+
)
25+
BigTableConfig = namedtuple(
26+
"BigTableConfig", _bigtableconfig_fields, defaults=_bigtableconfig_defaults
27+
)
28+
29+
30+
def get_client_config(
31+
project: str = None,
32+
instance: str = None,
33+
admin: bool = False,
34+
read_only: bool = True,
35+
):
36+
"""Helper function to load config from env."""
37+
from os import environ
38+
39+
_project = environ.get("BIGTABLE_PROJECT", DEFAULT_PROJECT)
40+
if project:
41+
_project = project
42+
43+
_instance = environ.get("BIGTABLE_INSTANCE", DEFAULT_INSTANCE)
44+
if instance:
45+
_instance = instance
46+
47+
kwargs = {
48+
"PROJECT": _project,
49+
"INSTANCE": _instance,
50+
"ADMIN": admin,
51+
"READ_ONLY": read_only,
52+
}
53+
return BigTableConfig(**kwargs)

kvdbclient/bigtable/attributes.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
from typing import NamedTuple
2+
3+
from .. import serializers
4+
5+
6+
class _AttributeType(NamedTuple):
7+
key: bytes
8+
family_id: str
9+
serializer: serializers.Serializer
10+
11+
12+
class Attribute(_AttributeType):
13+
__slots__ = ()
14+
_attributes = {}
15+
16+
def __init__(self, **kwargs):
17+
super().__init__()
18+
Attribute._attributes[(kwargs["family_id"], kwargs["key"])] = self
19+
20+
def serialize(self, obj):
21+
return self.serializer.serialize(obj)
22+
23+
def deserialize(self, stream):
24+
return self.serializer.deserialize(stream)
25+
26+
@property
27+
def basetype(self):
28+
return self.serializer.basetype
29+
30+
@property
31+
def index(self):
32+
return int(self.key.decode("utf-8").split("_")[-1])
33+
34+
35+
class AttributeArray:
36+
_attributearrays = {}
37+
38+
def __init__(self, pattern, family_id, serializer):
39+
self._pattern = pattern
40+
self._family_id = family_id
41+
self._serializer = serializer
42+
AttributeArray._attributearrays[(family_id, pattern)] = self
43+
44+
# TODO: Add missing check in `fromkey(family_id, key)` and remove this
45+
# loop (pre-creates `Attributes`, so that the inverse lookup works)
46+
for i in range(20):
47+
self[i] # pylint: disable=W0104
48+
49+
def __getitem__(self, item):
50+
return Attribute(
51+
key=self.pattern % item,
52+
family_id=self._family_id,
53+
serializer=self._serializer,
54+
)
55+
56+
@property
57+
def pattern(self):
58+
return self._pattern
59+
60+
@property
61+
def serialize(self):
62+
return self._serializer.serialize
63+
64+
@property
65+
def deserialize(self):
66+
return self._serializer.deserialize
67+
68+
@property
69+
def basetype(self):
70+
return self._serializer.basetype
71+
72+
73+
class TableMeta:
74+
key = b"meta"
75+
family_id = "0"
76+
data = Attribute(key=key, family_id=family_id, serializer=serializers.Pickle())

0 commit comments

Comments
 (0)