Skip to content
This repository was archived by the owner on Oct 22, 2024. It is now read-only.

Commit ddfb382

Browse files
authored
Merge branch 'master' into general-clean-up
2 parents 5e4eabb + 961a0b2 commit ddfb382

12 files changed

Lines changed: 89 additions & 31 deletions

File tree

.github/workflows/pull_request.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ jobs:
1212
# tests can't run in parallel as they write and read data with same keys
1313
max-parallel: 1
1414
matrix:
15-
python-version: ["3.7", "3.8", "3.9"]
15+
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
1616
steps:
1717
# Get the code into the container
1818
- name: Checkout
19-
uses: actions/checkout@v2
19+
uses: actions/checkout@v3
2020
# Setup Python
2121
- name: Setup Python
22-
uses: actions/setup-python@v2
22+
uses: actions/setup-python@v4
2323
with:
2424
python-version: ${{ matrix.python-version }}
2525
# Test the code

.github/workflows/tag_release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ jobs:
1111
steps:
1212
# Get the code into our container
1313
- name: Checkout
14-
uses: actions/checkout@v2
14+
uses: actions/checkout@v3
1515
# Setup Python
1616
- name: Setup Python
17-
uses: actions/setup-python@v2
17+
uses: actions/setup-python@v4
1818
with:
1919
python-version: ^3.5
2020
# Install dependencies

.github/workflows/test_release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ jobs:
99
steps:
1010
# Get the code into our container
1111
- name: Checkout
12-
uses: actions/checkout@v2
12+
uses: actions/checkout@v3
1313
# Setup Python
1414
- name: Setup Python
15-
uses: actions/setup-python@v2
15+
uses: actions/setup-python@v4
1616
with:
1717
python-version: ^3.5
1818
# Install dependencies

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Deta Python Library (SDK)
22

3-
Supports Python 3.5+ only. [Read the docs.](https://deta.space/docs/en/reference/base/sdk)
3+
Please use a [supported version of Python](https://devguide.python.org/versions/). This package requires a minimum of Python 3.6. [Read the docs.](https://deta.space/docs/en/build/reference/sdk)
44

55
Install from PyPi
66

deta/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
except ImportError:
2222
pass
2323

24-
__version__ = "1.1.0"
25-
24+
__version__ = "1.2.0"
2625

2726
def Base(name: str):
2827
project_key, project_id = _get_project_key_id()
@@ -45,6 +44,7 @@ def Base(self, name: str, host: Union[str, None] = None):
4544

4645
def AsyncBase(self, name: str, host: Union[str, None] = None):
4746
from ._async.client import _AsyncBase
47+
4848
return _AsyncBase(name, self.project_key, self.project_id, host)
4949

5050
def Drive(self, name: str, host: Union[str, None] = None):

deta/_async/client.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,17 @@ async def put(
9393
if key:
9494
data["key"] = key
9595

96+
9697
insert_ttl(data, self.__ttl_attribute,
9798
expire_in=expire_in, expire_at=expire_at)
9899
async with self._session.put(
99100
f"{self._base_url}/items", json={"items": [data]}
100101
) as resp:
101102
if resp.status == 207:
102103
resp_json = await resp.json()
103-
return resp_json["processed"]["items"][0]
104-
else:
105-
return None
104+
if "processed" in resp_json:
105+
return resp_json["processed"]["items"][0]
106+
return None
106107

107108
async def put_many(
108109
self,
@@ -134,6 +135,7 @@ async def fetch(
134135
*,
135136
limit: int = 1000,
136137
last: Union[str, None] = None,
138+
desc: bool = False,
137139
):
138140
payload = {}
139141
if query:
@@ -142,6 +144,9 @@ async def fetch(
142144
payload["limit"] = limit
143145
if last:
144146
payload["last"] = last
147+
if desc:
148+
payload["sort"] = "desc"
149+
145150
async with self._session.post(f"{self._base_url}/query", json=payload) as resp:
146151
resp_json = await resp.json()
147152
paging = resp_json.get("paging")

deta/base.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,11 @@ def put(
160160
"/items", "PUT", {"items": [data]}, content_type=JSON_MIME
161161
)
162162

163-
if res and code == 207:
164-
return res["processed"]["items"][0] # pyright: ignore
163+
164+
if code == 207 and "processed" in res:
165+
return res["processed"]["items"][0]
166+
else:
167+
return None
165168

166169
def put_many(
167170
self,
@@ -191,11 +194,13 @@ def _fetch(
191194
query: Union[dict, list, None] = None,
192195
buffer: Union[int, None] = None,
193196
last: Union[str, None] = None,
194-
):
197+
desc: bool = False,
198+
) -> typing.Optional[typing.Tuple[int, list]]:
195199
"""This is where actual fetch happens."""
196200
payload = {
197201
"limit": buffer,
198202
"last": last if not isinstance(last, bool) else None,
203+
"sort": "desc" if desc else "",
199204
}
200205

201206
if query:
@@ -214,12 +219,16 @@ def fetch(
214219
*,
215220
limit: int = 1000,
216221
last: Union[str, None] = None,
222+
desc: bool = False,
223+
217224
):
218225
"""
219226
fetch items from the database.
220227
`query` is an optional filter or list of filters. Without filter, it will return the whole db.
221228
"""
222-
res = self._fetch(query, limit, last)
229+
230+
_, res = self._fetch(query, limit, last, desc)
231+
223232

224233
paging = res.get("paging") # pyright: ignore
225234

@@ -238,7 +247,7 @@ def update(
238247
"""
239248
update an item in the database
240249
`updates` specifies the attribute names and values to update,add or remove
241-
`key` is the kye of the item to be updated
250+
`key` is the key of the item to be updated
242251
"""
243252

244253
if key == "":

deta/service.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,19 @@
55
import struct
66
from typing import Union
77
import urllib.error
8+
from pathlib import Path
89

910
JSON_MIME = "application/json"
1011

1112

13+
class CustomJSONEncoder(json.JSONEncoder):
14+
15+
def default(self, o: typing.Any) -> typing.Any:
16+
if isinstance(o, Path):
17+
return o.resolve().as_posix()
18+
return super().default(o)
19+
20+
1221
class _Service:
1322
def __init__(
1423
self,
@@ -75,7 +84,9 @@ def _request(
7584
pass
7685

7786
# send request
78-
body = json.dumps(data) if content_type == JSON_MIME else data
87+
body = json.dumps(
88+
data, cls=CustomJSONEncoder
89+
) if content_type == JSON_MIME else data
7990

8091
# response
8192
res = self._send_request_with_retry(method, url, headers, body)
@@ -92,8 +103,9 @@ def _request(
92103
# return None if not found
93104
if status == 404:
94105
return status, None
95-
raise urllib.error.HTTPError(
96-
url, status, res.reason, res.headers, res.fp)
106+
fp = res.fp if res.fp is not None else '' # FIXME: workaround to fix traceback printing for HTTPError
107+
raise urllib.error.HTTPError(url, status, res.reason, res.headers, fp)
108+
97109

98110
# if stream return the response and client without reading and closing the client
99111
if stream:

pytest.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[pytest]
2+
addopts = --color=yes
3+
asyncio_mode = auto

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
setup(
44
name="deta",
5-
version="1.1.0",
5+
version="1.2.0",
66
description="Python SDK for Deta Base & Deta Drive.",
77
url="http://github.com/deta/deta-python",
88
author="Deta",

0 commit comments

Comments
 (0)