From 2b314617a1d9a9e0a9c660f1d4734d5667763951 Mon Sep 17 00:00:00 2001 From: Yasser Tahiri Date: Tue, 22 Mar 2022 00:26:47 +0100 Subject: [PATCH] chore(ref): Improve Codebase and Refactor some functions --- deta/__init__.py | 6 ++--- deta/_async/client.py | 41 ++++++++-------------------- deta/base.py | 62 ++++++++++++++----------------------------- deta/drive.py | 12 +++------ deta/service.py | 15 +++-------- deta/utils.py | 2 +- tests/test_async.py | 32 +++++++++------------- tests/test_sync.py | 50 +++++++++++----------------------- 8 files changed, 72 insertions(+), 148 deletions(-) diff --git a/deta/__init__.py b/deta/__init__.py index 1eec891..7cfa9a3 100644 --- a/deta/__init__.py +++ b/deta/__init__.py @@ -23,7 +23,6 @@ __version__ = "1.1.0" - def Base(name: str): project_key, project_id = _get_project_key_id() return _Base(name, project_key, project_id) @@ -45,6 +44,7 @@ def Base(self, name: str, host: str = None): def AsyncBase(self, name: str, host: str = None): from ._async.client import _AsyncBase + return _AsyncBase(name, self.project_key, self.project_id, host) def Drive(self, name: str, host: str = None): @@ -80,6 +80,6 @@ def send_email(to, subject, message, charset="UTF-8"): try: resp = urllib.request.urlopen(req) if resp.getcode() != 200: - raise Exception(resp.read().decode("utf-8")) + raise ValueError(resp.read().decode("utf-8")) except urllib.error.URLError as e: - raise Exception(e.reason) + raise Exception(e.reason) from e diff --git a/deta/_async/client.py b/deta/_async/client.py index f183253..6815dcb 100644 --- a/deta/_async/client.py +++ b/deta/_async/client.py @@ -62,18 +62,12 @@ async def insert( expire_in: int = None, expire_at: typing.Union[int, float, datetime.datetime] = None, ): - if not isinstance(data, dict): - data = {"value": data} - else: - data = data.copy() - + data = data.copy() if isinstance(data, dict) else {"value": data} if key: data["key"] = key insert_ttl(data, self.__ttl_attribute, expire_in=expire_in, expire_at=expire_at) - async with self._session.post( - f"{self._base_url}/items", json={"item": data} - ) as resp: + async with self._session.post(f"{self._base_url}/items", json={"item": data}) as resp: return await resp.json() async def put( @@ -84,23 +78,16 @@ async def put( expire_in: int = None, expire_at: typing.Union[int, float, datetime.datetime] = None, ): - if not isinstance(data, dict): - data = {"value": data} - else: - data = data.copy() - + data = data.copy() if isinstance(data, dict) else {"value": data} if key: data["key"] = key insert_ttl(data, self.__ttl_attribute, expire_in=expire_in, expire_at=expire_at) - async with self._session.put( - f"{self._base_url}/items", json={"items": [data]} - ) as resp: - if resp.status == 207: - resp_json = await resp.json() - return resp_json["processed"]["items"][0] - else: + async with self._session.put(f"{self._base_url}/items", json={"items": [data]}) as resp: + if resp.status != 207: return None + resp_json = await resp.json() + return resp_json["processed"]["items"][0] async def put_many( self, @@ -116,14 +103,10 @@ async def put_many( data = i if not isinstance(i, dict): data = {"value": i} - insert_ttl( - data, self.__ttl_attribute, expire_in=expire_in, expire_at=expire_at - ) + insert_ttl(data, self.__ttl_attribute, expire_in=expire_in, expire_at=expire_at) _items.append(data) - async with self._session.put( - f"{self._base_url}/items", json={"items": _items} - ) as resp: + async with self._session.put(f"{self._base_url}/items", json={"items": _items}) as resp: return await resp.json() async def fetch( @@ -143,9 +126,7 @@ async def fetch( async with self._session.post(f"{self._base_url}/query", json=payload) as resp: resp_json = await resp.json() paging = resp_json.get("paging") - return FetchResponse( - paging.get("size"), paging.get("last"), resp_json.get("items") - ) + return FetchResponse(paging.get("size"), paging.get("last"), resp_json.get("items")) async def update( self, @@ -155,7 +136,7 @@ async def update( expire_in: int = None, expire_at: typing.Union[int, float, datetime.datetime] = None, ): - if key == "": + if not key: raise ValueError("Key is empty") payload = { diff --git a/deta/base.py b/deta/base.py index c15c127..91cf2b5 100644 --- a/deta/base.py +++ b/deta/base.py @@ -12,7 +12,9 @@ class FetchResponse: - def __init__(self, count=0, last=None, items=[]): + def __init__(self, count=0, last=None, items=None): + if items is None: + items = [] self._count = count self._last = last self._items = items @@ -30,11 +32,7 @@ def items(self): return self._items def __eq__(self, other): - return ( - self.count == other.count - and self.last == other.last - and self.items == other.items - ) + return self.count == other.count and self.last == other.last and self.items == other.items class Util: @@ -88,24 +86,24 @@ def __init__(self, name: str, project_key: str, project_id: str, host: str = Non self.util = Util() def get(self, key: str): - if key == "": + if not key: raise ValueError("Key is empty") # encode key key = quote(key, safe="") - _, res = self._request("/items/{}".format(key), "GET") + _, res = self._request(f"/items/{key}", "GET") return res or None def delete(self, key: str): """Delete an item from the database key: the key of item to be deleted """ - if key == "": + if not key: raise ValueError("Key is empty") # encode key key = quote(key, safe="") - self._request("/items/{}".format(key), "DELETE") + self._request(f"/items/{key}", "DELETE") return None def insert( @@ -116,22 +114,16 @@ def insert( expire_in: int = None, expire_at: typing.Union[int, float, datetime.datetime] = None, ): - if not isinstance(data, dict): - data = {"value": data} - else: - data = data.copy() - + data = data.copy() if isinstance(data, dict) else {"value": data} if key: data["key"] = key insert_ttl(data, self.__ttl_attribute, expire_in=expire_in, expire_at=expire_at) - code, res = self._request( - "/items", "POST", {"item": data}, content_type=JSON_MIME - ) + code, res = self._request("/items", "POST", {"item": data}, content_type=JSON_MIME) if code == 201: return res elif code == 409: - raise Exception("Item with key '{4}' already exists".format(key)) + raise ValueError("Item with key '{4}' already exists".format(key)) def put( self, @@ -146,18 +138,12 @@ def put( If `key` is not provided, the server will generate a random 12 chars key. """ - if not isinstance(data, dict): - data = {"value": data} - else: - data = data.copy() - + data = data.copy() if isinstance(data, dict) else {"value": data} if key: data["key"] = key insert_ttl(data, self.__ttl_attribute, expire_in=expire_in, expire_at=expire_at) - code, res = self._request( - "/items", "PUT", {"items": [data]}, content_type=JSON_MIME - ) + code, res = self._request("/items", "PUT", {"items": [data]}, content_type=JSON_MIME) return res["processed"]["items"][0] if res and code == 207 else None def put_many( @@ -173,14 +159,10 @@ def put_many( data = i if not isinstance(i, dict): data = {"value": i} - insert_ttl( - data, self.__ttl_attribute, expire_in=expire_in, expire_at=expire_at - ) + insert_ttl(data, self.__ttl_attribute, expire_in=expire_in, expire_at=expire_at) _items.append(data) - _, res = self._request( - "/items", "PUT", {"items": _items}, content_type=JSON_MIME - ) + _, res = self._request("/items", "PUT", {"items": _items}, content_type=JSON_MIME) return res def _fetch( @@ -190,10 +172,7 @@ def _fetch( last: str = None, ) -> typing.Optional[typing.Tuple[int, list]]: """This is where actual fetch happens.""" - payload = { - "limit": buffer, - "last": last if not isinstance(last, bool) else None, - } + payload = {"limit": buffer, "last": None if isinstance(last, bool) else last} if query: payload["query"] = query if isinstance(query, list) else [query] @@ -232,7 +211,7 @@ def update( `key` is the kye of the item to be updated """ - if key == "": + if not key: raise ValueError("Key is empty") payload = { @@ -263,13 +242,12 @@ def update( ) encoded_key = quote(key, safe="") - code, _ = self._request( - "/items/{}".format(encoded_key), "PATCH", payload, content_type=JSON_MIME - ) + code, _ = self._request(f"/items/{encoded_key}", "PATCH", payload, content_type=JSON_MIME) + if code == 200: return None elif code == 404: - raise Exception("Key '{}' not found".format(key)) + raise ValueError(f"Key '{key}' not found") def insert_ttl(item, ttl_attribute, expire_in=None, expire_at=None): diff --git a/deta/drive.py b/deta/drive.py index 2d4db38..5cf9318 100644 --- a/deta/drive.py +++ b/deta/drive.py @@ -29,7 +29,7 @@ def iter_chunks(self, chunk_size: int = 1024): if not chunk: break yield chunk - + def iter_lines(self, chunk_size: int = 1024): while True: chunk = self.__stream.readline(chunk_size) @@ -74,9 +74,7 @@ def get(self, name: str): Returns a DriveStreamingBody. """ assert name, "No name provided" - _, res = self._request( - f"/files/download?name={self._quote(name)}", "GET", stream=True - ) + _, res = self._request(f"/files/download?name={self._quote(name)}", "GET", stream=True) if res: return DriveStreamingBody(res) return None @@ -88,12 +86,10 @@ def delete_many(self, names: typing.List[str]): """ assert names, "Names is empty" assert len(names) <= 1000, "More than 1000 names to delete" - _, res = self._request( - "/files", "DELETE", {"names": names}, content_type=JSON_MIME - ) + _, res = self._request("/files", "DELETE", {"names": names}, content_type=JSON_MIME) return res - def delete(self, name: str): + def delete(self, name: str): # sourcery skip: raise-specific-error """Delete a file from drive. `name` is the name of the file. Returns the name of the file deleted. diff --git a/deta/service.py b/deta/service.py index e1f1cdf..0e1ff9e 100644 --- a/deta/service.py +++ b/deta/service.py @@ -24,9 +24,7 @@ def __init__( self.host = host self.timeout = timeout self.keep_alive = keep_alive - self.client = ( - http.client.HTTPSConnection(host, timeout=timeout) if keep_alive else None - ) + self.client = http.client.HTTPSConnection(host, timeout=timeout) if keep_alive else None def _is_socket_closed(self): if not self.client.sock: @@ -92,9 +90,7 @@ def _request( ## return json if application/json payload = ( - json.loads(res.read()) - if JSON_MIME in res.getheader("content-type") - else res.read() + json.loads(res.read()) if JSON_MIME in res.getheader("content-type") else res.read() ) if not self.keep_alive: @@ -113,9 +109,7 @@ def _send_request_with_retry( while retry > 0: try: if not self.keep_alive or reinitializeConnection: - self.client = http.client.HTTPSConnection( - host=self.host, timeout=self.timeout - ) + self.client = http.client.HTTPSConnection(host=self.host, timeout=self.timeout) self.client.request( method, @@ -123,8 +117,7 @@ def _send_request_with_retry( headers=headers, body=body, ) - res = self.client.getresponse() - return res + return self.client.getresponse() except http.client.RemoteDisconnected: reinitializeConnection = True retry -= 1 diff --git a/deta/utils.py b/deta/utils.py index f94c598..5bd127d 100644 --- a/deta/utils.py +++ b/deta/utils.py @@ -13,4 +13,4 @@ def _get_project_key_id(project_key: str = None, project_id: str = None): if project_id == project_key: raise AssertionError("Bad project key provided") - return project_key, project_id \ No newline at end of file + return project_key, project_id diff --git a/tests/test_async.py b/tests/test_async.py index 17fbf16..185d552 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -61,7 +61,7 @@ async def test_put(db): for input in ["Hello", 1, True, False, 3.14159265359]: resp = await db.put(input) - assert set(resp.keys()) == set(["key", "value"]) + assert set(resp.keys()) == {"key", "value"} async def test_put_fail(db): @@ -86,13 +86,13 @@ async def test_put_many_fail(db): async def test_put_many_fail_limit(db): with pytest.raises(Exception): - await db.put_many([i for i in range(26)]) + await db.put_many(list(range(26))) async def test_insert(db): item = {"msg": "hello"} resp = await db.insert(item) - assert set(resp.keys()) == set(["key", "msg"]) + assert set(resp.keys()) == {"key", "msg"} async def test_insert_fail(db, items): @@ -105,15 +105,15 @@ async def test_get(db, items): assert resp == items[0] resp = await db.get("key_does_not_exist") - assert resp == None + assert resp is None async def test_delete(db, items): resp = await db.delete(items[0]["key"]) - assert resp == None + assert resp is None resp = await db.delete("key_does_not_exist") - assert resp == None + assert resp is None async def test_fetch(db, items): @@ -149,9 +149,7 @@ async def test_fetch(db, items): ) assert res3 == expectedItem - res4 = await db.fetch( - [{"value?gt": 6}, {"value?lt": 50}], limit=2, last="existing2" - ) + res4 = await db.fetch([{"value?gt": 6}, {"value?lt": 50}], limit=2, last="existing2") expectedItem = FetchResponse( 1, None, @@ -186,7 +184,7 @@ async def test_fetch(db, items): async def test_update(db, items): resp = await db.update({"value.name": "spongebob"}, "existing4") - assert resp == None + assert resp is None resp = await db.get("existing4") expectedItem = {"key": "existing4", "value": {"name": "spongebob"}} @@ -194,7 +192,7 @@ async def test_update(db, items): resp = await db.update({"value.name": db.util.trim(), "value.age": 32}, "existing4") - assert resp == None + assert resp is None expectedItem = {"key": "existing4", "value": {"age": 32}} resp = await db.get("existing4") @@ -207,13 +205,13 @@ async def test_update(db, items): }, "%@#//#!#)#$_", ) - assert resp == None + assert resp is None resp = await db.update( {"list": db.util.prepend("x"), "value": db.util.increment(2)}, "%@#//#!#)#$_", ) - assert resp == None + assert resp is None expectedItem = {"key": "%@#//#!#)#$_", "list": ["x", "a", "b", "c"], "value": 3} resp = await db.get("%@#//#!#)#$_") assert resp == expectedItem @@ -323,9 +321,7 @@ async def test_ttl(db, items): # update # only if one of expire_in or expire_at if cexp_in or cexp_at: - await db.update( - None, item.get("key"), expire_in=cexp_in, expire_at=cexp_at - ) + await db.update(None, item.get("key"), expire_in=cexp_in, expire_at=cexp_at) got = await db.get(item.get("key")) assert abs(expected - got.get(BASE_TEST_TTL_ATTRIBUTE)) <= cdelta else: @@ -336,6 +332,4 @@ async def test_ttl(db, items): with pytest.raises(error): await db.insert(item, expire_in=cexp_in, expire_at=cexp_at) with pytest.raises(error): - await db.update( - None, item.get("key"), expire_in=cexp_in, expire_at=cexp_at - ) + await db.update(None, item.get("key"), expire_in=cexp_in, expire_at=cexp_at) diff --git a/tests/test_sync.py b/tests/test_sync.py index c4070b0..a29b62d 100644 --- a/tests/test_sync.py +++ b/tests/test_sync.py @@ -209,11 +209,11 @@ def test_put(self): self.assertEqual(self.db.put(item, "one"), resp) self.assertEqual(self.db.put(item, "one"), resp) self.assertEqual({"msg": "hello"}, item) - self.assertEqual(set(self.db.put("Hello").keys()), set(["key", "value"])) - self.assertEqual(set(self.db.put(1).keys()), set(["key", "value"])) - self.assertEqual(set(self.db.put(True).keys()), set(["key", "value"])) - self.assertEqual(set(self.db.put(False).keys()), set(["key", "value"])) - self.assertEqual(set(self.db.put(3.14159265359).keys()), set(["key", "value"])) + self.assertEqual(set(self.db.put("Hello").keys()), {"key", "value"}) + self.assertEqual(set(self.db.put(1).keys()), {"key", "value"}) + self.assertEqual(set(self.db.put(True).keys()), {"key", "value"}) + self.assertEqual(set(self.db.put(False).keys()), {"key", "value"}) + self.assertEqual(set(self.db.put(3.14159265359).keys()), {"key", "value"}) @unittest.expectedFailure def test_put_fail(self): @@ -231,11 +231,11 @@ def test_put_many_fail(self): @unittest.expectedFailure def test_put_many_fail_limit(self): - self.db.put_many([i for i in range(26)]) + self.db.put_many(list(range(26))) def test_insert(self): item = {"msg": "hello"} - self.assertEqual(set(self.db.insert(item).keys()), set(["key", "msg"])) + self.assertEqual(set(self.db.insert(item).keys()), {"key", "msg"}) self.assertEqual({"msg": "hello"}, item) @unittest.expectedFailure @@ -283,9 +283,7 @@ def test_fetch(self): ) self.assertEqual(res3, expectedItem) - res4 = self.db.fetch( - [{"value?gt": 6}, {"value?lt": 50}], limit=2, last="existing2" - ) + res4 = self.db.fetch([{"value?gt": 6}, {"value?lt": 50}], limit=2, last="existing2") expectedItem = FetchResponse( 1, None, @@ -323,9 +321,7 @@ def test_update(self): self.assertEqual(self.db.get("existing4"), expectedItem) self.assertIsNone( - self.db.update( - {"value.name": self.db.util.trim(), "value.age": 32}, "existing4" - ) + self.db.update({"value.name": self.db.util.trim(), "value.age": 32}, "existing4") ) expectedItem = {"key": "existing4", "value": {"age": 32}} self.assertEqual(self.db.get("existing4"), expectedItem) @@ -438,43 +434,29 @@ def test_ttl(self): # put self.db.put(item, expire_in=cexp_in, expire_at=cexp_at) got = self.db.get(item.get("key")) - self.assertAlmostEqual( - expected, got.get(self.ttl_attribute), delta=cdelta - ) + self.assertAlmostEqual(expected, got.get(self.ttl_attribute), delta=cdelta) # insert # need to udpate key as insert does not allow pre existing key item["key"] = "".join(random.choices(string.ascii_lowercase, k=6)) self.db.insert(item, expire_in=cexp_in, expire_at=cexp_at) got = self.db.get(item.get("key")) - self.assertAlmostEqual( - expected, got.get(self.ttl_attribute), delta=cdelta - ) + self.assertAlmostEqual(expected, got.get(self.ttl_attribute), delta=cdelta) # put many self.db.put_many([item], expire_in=cexp_in, expire_at=cexp_at) got = self.db.get(item.get("key")) - self.assertAlmostEqual( - expected, got.get(self.ttl_attribute), delta=cdelta - ) + self.assertAlmostEqual(expected, got.get(self.ttl_attribute), delta=cdelta) # update # only if one of expire_in or expire_at if cexp_in or cexp_at: - self.db.update( - None, item.get("key"), expire_in=cexp_in, expire_at=cexp_at - ) + self.db.update(None, item.get("key"), expire_in=cexp_in, expire_at=cexp_at) got = self.db.get(item.get("key")) - self.assertAlmostEqual( - expected, got.get(self.ttl_attribute), delta=cdelta - ) + self.assertAlmostEqual(expected, got.get(self.ttl_attribute), delta=cdelta) else: - self.assertRaises( - error, self.db.put, item, expire_in=cexp_in, expire_at=cexp_at - ) - self.assertRaises( - error, self.db.insert, item, expire_in=cexp_in, expire_at=cexp_at - ) + self.assertRaises(error, self.db.put, item, expire_in=cexp_in, expire_at=cexp_at) + self.assertRaises(error, self.db.insert, item, expire_in=cexp_in, expire_at=cexp_at) self.assertRaises( error, self.db.put_many,