Skip to content
This repository was archived by the owner on Jan 24, 2025. It is now read-only.

Commit 38c84aa

Browse files
authored
kvstore change empty to nil (#55)
* update keybase clients types to client at 5.4.0 release * update for new kvstore empty as null * in simplest kvstore example, explicitly use self-team * handful of cleanuppy things
1 parent 3aae385 commit 38c84aa

File tree

12 files changed

+2162
-997
lines changed

12 files changed

+2162
-997
lines changed

examples/3_simple_storage.py

+19-11
Original file line numberDiff line numberDiff line change
@@ -47,61 +47,69 @@ def noop_handler(*args, **kwargs):
4747

4848
namespace = "current-favorites"
4949
key = "Sam"
50+
teamName = f"{bot.username},{bot.username}"
5051

5152
# using the default team, which is yourself (your implicit self-team
5253
# "yourusername,yourusername")
5354

55+
# get a non-existent entry
56+
res = await bot.kvstore.get(namespace, key, team=teamName)
57+
print("GET NON-EXISTENT: ", res)
58+
assert res.entry_value is None
59+
5460
# put with default revision
55-
# note: if revision=None, the server does a get (to get
61+
# note: if revision=None, the service does a get (to get
5662
# the latest revision number) then a put (with revision
5763
# number + 1); this operation is not atomic.
5864
value = "The Left Hand of Darkness"
59-
res = await bot.kvstore.put(namespace, key, value, revision=None)
65+
res = await bot.kvstore.put(namespace, key, value, revision=None, team=teamName)
6066
print("PUT: ", res)
6167
rev = res.revision
6268

6369
# fail put
6470
try:
65-
res = await bot.kvstore.put(namespace, key, "Fahrenheit 451", revision=rev)
71+
res = await bot.kvstore.put(
72+
namespace, key, "Fahrenheit 451", revision=rev, team=teamName
73+
)
6674
except RevisionError as e:
6775
print("EXPECTING PUT FAIL: ", e)
6876

6977
# list namespaces
70-
res = await bot.kvstore.list_namespaces()
78+
res = await bot.kvstore.list_namespaces(team=teamName)
7179
print("LIST NAMESPACES: ", res)
7280
assert len(res.namespaces) > 0
7381

7482
# list entryKeys
75-
res = await bot.kvstore.list_entrykeys(namespace)
83+
res = await bot.kvstore.list_entrykeys(namespace, team=teamName)
7684
print("LIST ENTRYKEYS: ", res)
7785
assert len(res.entry_keys) > 0
7886

7987
# get
80-
res = await bot.kvstore.get(namespace, key)
88+
res = await bot.kvstore.get(namespace, key, team=teamName)
8189
print("GET: ", res)
8290
assert res.entry_value == value
8391

8492
# fail delete
8593
try:
86-
res = await bot.kvstore.delete(namespace, key, revision=rev + 2)
94+
res = await bot.kvstore.delete(namespace, key, revision=rev + 2, team=teamName)
8795
except RevisionError as e:
8896
print("EXPECTING DELETE FAIL: ", e)
8997

9098
# delete
91-
res = await bot.kvstore.delete(namespace, key, revision=rev + 1)
99+
res = await bot.kvstore.delete(namespace, key, revision=rev + 1, team=teamName)
92100
print("DELETE: ", res)
93101
assert res.revision == rev + 1
94102

95103
# fail delete
96104
try:
97-
res = await bot.kvstore.delete(namespace, key, revision=rev + 2)
105+
res = await bot.kvstore.delete(namespace, key, revision=rev + 2, team=teamName)
98106
except DeleteNonExistentError as e:
99107
print("EXPECTING DELETE FAIL: ", e)
100108

101109
# get
102-
res = await bot.kvstore.get(namespace, key)
110+
res = await bot.kvstore.get(namespace, key, team=teamName)
103111
print("GET: ", res)
104-
assert res.entry_value == ""
112+
assert res.entry_value is None
105113

106114

107115
async def main():

examples/4_totp_storage.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def to_json(self, secret):
8787

8888
async def add(self, bot, team, issuer, secret):
8989
val = json.dumps(self.to_json(secret))
90-
await bot.kvstore.put(self.NAMESPACE, issuer, val, team)
90+
await bot.kvstore.put(self.NAMESPACE, issuer, val, team=team)
9191

9292
async def remove(self, bot, team, issuer):
9393
# throws exception if nothing to delete

examples/5_secret_storage.py

+38-27
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#
1919
# Here we've stored the HMAC secret and other entries in the team's kvstore;
2020
# you could also store the entries in the bot's own kvstore (the default team).
21+
#
22+
# TODO: this is currently not working exactly right. sorry.
2123
# ###################################
2224

2325
import asyncio
@@ -69,15 +71,15 @@ def __init__(self, client):
6971

7072
async def put(
7173
self,
72-
team: str,
7374
namespace: str,
7475
entry_key: str,
7576
entry_value: Dict[str, str],
77+
team: str,
7678
revision: Union[int, None] = None,
7779
) -> Union[keybase1.KVPutResult, keybase1.KVGetResult]:
7880
try:
7981
res: keybase1.KVPutResult = await self.kvstore.put(
80-
team, namespace, entry_key, entry_value, revision
82+
namespace, entry_key, entry_value, team=team, revision=revision
8183
)
8284
return res # successful put. return KVPutResult
8385
except RevisionError:
@@ -86,14 +88,14 @@ async def put(
8688

8789
async def delete(
8890
self,
89-
team: str,
9091
namespace: str,
9192
entry_key: str,
93+
team: str,
9294
revision: Union[int, None] = None,
9395
) -> Union[keybase1.KVDeleteEntryResult, keybase1.KVGetResult]:
9496
try:
9597
res: keybase1.KVDeleteEntryResult = await self.kvstore.delete(
96-
team, namespace, entry_key, revision
98+
namespace=namespace, entry_key=entry_key, revision=revision, team=team
9799
)
98100
return res # successful delete. return KVDeleteEntryResult
99101
except (RevisionError, DeleteNonExistentError):
@@ -102,15 +104,15 @@ async def delete(
102104
return res
103105

104106
async def get(
105-
self, team: str, namespace: str, entry_key: str
107+
self, namespace: str, entry_key: str, team: str
106108
) -> keybase1.KVGetResult:
107-
res = await self.kvstore.get(team, namespace, entry_key)
109+
res = await self.kvstore.get(namespace, entry_key, team)
108110
return res
109111

110112
async def list_entrykeys(
111-
self, team: str, namespace: str
113+
self, namespace: str, team: str
112114
) -> keybase1.KVListEntryResult:
113-
res = await self.kvstore.list_entrykeys(team, namespace)
115+
res = await self.kvstore.list_entrykeys(namespace, team)
114116
return res
115117

116118

@@ -155,11 +157,15 @@ async def load_secret(self, team, namespace) -> bytes:
155157
try:
156158
# we don't expect self.SECRET_KEY's revision > 0
157159
await self.kvstore.put(
158-
namespace, self.SECRET_KEY, bytes_to_str(secret), 1, team
160+
namespace,
161+
self.SECRET_KEY,
162+
bytes_to_str(secret),
163+
revision=1,
164+
team=team,
159165
)
160166
except RevisionError:
161167
res: keybase1.KVGetResult = await self.kvstore.get(
162-
team, namespace, self.SECRET_KEY
168+
namespace, self.SECRET_KEY, team=team
163169
)
164170
secret = str_to_bytes(res.entry_value)
165171
if team not in self.secrets:
@@ -182,7 +188,7 @@ async def put(
182188
entry_value[SecretKeyKVStoreClient.KEY_KEY] = entry_key
183189
h = await self.hmac_key(team, namespace, entry_key)
184190
res = await self.kvstore.put(
185-
namespace, h, json.dumps(entry_value), revision, team
191+
namespace, h, json.dumps(entry_value), revision=revision, team=team
186192
)
187193
res.entry_key = entry_key
188194
return res
@@ -195,28 +201,28 @@ async def delete(
195201
revision: Union[int, None] = None,
196202
) -> keybase1.KVDeleteEntryResult:
197203
h = await self.hmac_key(team, namespace, entry_key)
198-
res = await self.kvstore.delete(namespace, h, revision, team)
204+
res = await self.kvstore.delete(namespace, h, revision=revision, team=team)
199205
res.entry_key = entry_key
200206
return res
201207

202208
async def get(
203209
self, team: str, namespace: str, entry_key: str
204210
) -> keybase1.KVGetResult:
205211
h = await self.hmac_key(team, namespace, entry_key)
206-
res = await self.kvstore.get(namespace, h, team)
212+
res = await self.kvstore.get(namespace, h, team=team)
207213
res.entry_key = entry_key
208214
return res
209215

210216
async def list_entrykeys(
211217
self, team: str, namespace: str
212218
) -> keybase1.KVListEntryResult:
213-
res = await self.kvstore.list_entrykeys(namespace, team)
219+
res = await self.kvstore.list_entrykeys(namespace, team=team)
214220
if res.entry_keys:
215221
res.entry_keys = [
216222
e for e in res.entry_keys if not e.entry_key.startswith("_")
217223
]
218224
for e in res.entry_keys:
219-
get_res = await self.kvstore.get(namespace, e.entry_key, team)
225+
get_res = await self.kvstore.get(namespace, e.entry_key, team=team)
220226
e.entry_key = json.loads(get_res.entry_value)[self.KEY_KEY]
221227
return res
222228

@@ -242,7 +248,7 @@ async def add(self, team, tool) -> Tuple[bool, Union[keybase1.KVGetResult, None]
242248
most recent get result if applicable)
243249
"""
244250
res = await self.lookup(team, tool)
245-
if res.entry_value != "":
251+
if res.entry_value is not None:
246252
return (True, res) # if tool already exists, return get
247253
expected_revision = res.revision + 1
248254
res = await self.kvstore.put(team, self.NAMESPACE, tool, {}, expected_revision)
@@ -260,10 +266,15 @@ async def remove(
260266
most recent get result if applicable)
261267
"""
262268
res = await self.lookup(team, tool)
263-
if res.entry_value == "":
269+
if res.entry_value is None:
264270
return (True, res) # if tool already doesn't exist, return get
265271
expected_revision = res.revision + 1
266-
res = await self.kvstore.delete(team, self.NAMESPACE, tool, expected_revision)
272+
res = await self.kvstore.delete(
273+
namespace=self.NAMESPACE,
274+
entry_key=tool,
275+
revision=expected_revision,
276+
team=team,
277+
)
267278
if type(res) == keybase1.KVGetResult:
268279
return (False, res)
269280
else:
@@ -281,14 +292,14 @@ async def reserve(
281292
most recent get result if applicable)
282293
"""
283294
res = await self.lookup(team, tool)
284-
info = json.loads(res.entry_value) if res.entry_value != "" else {}
295+
info = json.loads(res.entry_value) if res.entry_value is not None else {}
285296
if day in info:
286297
return (False, res) # failed to put because day is already reserved.
287298
else:
288299
info[day] = user
289300
expected_revision = res.revision + 1
290301
res = await self.kvstore.put(
291-
team, self.NAMESPACE, tool, info, expected_revision
302+
self.NAMESPACE, tool, info, revision=expected_revision, team=team
292303
)
293304
if type(res) == keybase1.KVGetResult:
294305
return (False, res)
@@ -308,7 +319,7 @@ async def unreserve(
308319
most recent get result if applicable)
309320
"""
310321
res = await self.lookup(team, tool)
311-
info = json.loads(res.entry_value) if res.entry_value != "" else {}
322+
info = json.loads(res.entry_value) if res.entry_value is not None else {}
312323
if day not in info:
313324
# a noop because currently not reserved
314325
return (True, res)
@@ -319,20 +330,20 @@ async def unreserve(
319330
info.pop(day)
320331
expected_revision = res.revision + 1
321332
res = await self.kvstore.put(
322-
team, self.NAMESPACE, tool, info, expected_revision
333+
self.NAMESPACE, tool, info, revision=expected_revision, team=team
323334
)
324335
if type(res) == keybase1.KVGetResult:
325336
return (False, res)
326337
else:
327338
return (True, None)
328339

329340
async def list_tools(self, team) -> List[str]:
330-
res = await self.kvstore.list_entrykeys(team, self.NAMESPACE)
341+
res = await self.kvstore.list_entrykeys(self.NAMESPACE, team=team)
331342
keys = [e.entry_key for e in res.entry_keys] if res.entry_keys else []
332343
return keys
333344

334345

335-
async def basic_rental_users(bot, rental, team):
346+
async def basic_rental_users(rental, team):
336347
user1 = "Jo"
337348
user2 = "Charlie"
338349
date1 = "2044-03-12"
@@ -397,7 +408,7 @@ async def basic_rental_users(bot, rental, team):
397408
assert SecretKeyKVStoreClient.KEY_KEY in info
398409

399410

400-
async def concurrent_rental_users(bot, rental, team):
411+
async def concurrent_rental_users(rental, team):
401412
tool = "time travel machine"
402413

403414
async def concurrent_rental_user(user_id: int):
@@ -451,10 +462,10 @@ def noop_handler(*args, **kwargs):
451462
rental = RentalBotClient(bot)
452463

453464
print("...basic rental actions...")
454-
await basic_rental_users(bot, rental, team)
465+
await basic_rental_users(rental, team)
455466

456467
print("...multiple users try to reserve...")
457-
await concurrent_rental_users(bot, rental, team)
468+
await concurrent_rental_users(rental, team)
458469

459470
print("...5_secret_storage example is complete.")
460471

pykeybasebot/kvstore_client.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,12 @@ async def list_entrykeys(
9898
return keybase1.KVListEntryResult.from_dict(res)
9999

100100
def is_deleted(self, res: keybase1.KVGetResult) -> bool:
101-
return res.revision > 0 and res.entry_value == ""
101+
return res.revision > 0 and (res.entry_value is None or res.entry_value == "")
102102

103103
def is_present(self, res: keybase1.KVGetResult) -> bool:
104-
return res.revision > 0 and res.entry_value != ""
104+
return (
105+
res.revision > 0 and res.entry_value is not None and res.entry_value != ""
106+
)
105107

106108
async def execute(self, command):
107109
resp = await self.bot.submit("kvstore api", json.dumps(command).encode("utf-8"))

0 commit comments

Comments
 (0)