Skip to content

Commit e3efb65

Browse files
authored
release 1.1.0
1 parent a43eb16 commit e3efb65

File tree

5 files changed

+57
-30
lines changed

5 files changed

+57
-30
lines changed

README.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ A Python client for [jsonstore.io](https://www.jsonstore.io/)
55
```bash
66
pip install json-store-client
77
```
8+
#### An optional installation of [ujson](https://pypi.org/project/ujson/) is recommended for faster json processing.
9+
##### Also installing [cchardet](https://pypi.org/project/cchardet/) and [aiodns](https://pypi.org/project/aiodns/) are recommended by aiohttp for faster performance.
810

911
## Usage
1012

11-
#### Demo of storing a Python object with json-store-client in async on [repl.it](https://repl.it/@leon332157/json-store-client-demo).
13+
#### Demo of storing a Python json-friendly object with json-store-client in async on [repl.it](https://repl.it/@leon332157/json-store-client-demo).
1214

1315
```python
1416
from json_store_client import *
@@ -73,7 +75,7 @@ Both return the client to use for data operations.
7375
Storing data in jsonstore with a key.
7476

7577
###### key (str): The key to be stored on jsonstore
76-
###### data (any): The data to be stored under the key. It can be any Python objects. Will be processed with [jsonpickle](https://github.com/jsonpickle/jsonpickle)
78+
###### data (any): The data to be stored under the key. It can be any Python objects.
7779
###### timeout (int): The timeout for the http request. Default 5 seconds
7880

7981

@@ -82,7 +84,7 @@ Storing data in jsonstore with a key.
8284

8385
Storing data in jsonstore with a dictionary mapping.
8486

85-
###### data (dict): A dict of {key(s):value(s)} to be updated. Value(s) can be any python object, will be dumped with [jsonpickle](https://github.com/jsonpickle/jsonpickle)
87+
###### data (dict): A dict of {key(s):value(s)} to be updated.
8688
###### timeout (int): The timeout for the http request. Default 5 seconds
8789

8890
> **Note:** If there is already some data stored under the key, it will be overwritten.

json_store_client/__init__.py

+25-18
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,19 @@
4444
4545
await client.delete('test_key')
4646
"""
47-
import json
47+
try:
48+
import ujson as json
49+
except ImportError:
50+
import json
51+
from asyncio import get_event_loop
4852
from warnings import warn
4953

5054
import aiohttp
51-
import jsonpickle
52-
import pkg_resources
5355
import requests
5456

5557
DEFAULT_TIMEOUT_SECONDS = 5
56-
VERSION = '1.0.2'
58+
VERSION = '1.1.0'
59+
__all__ = ['JsonstoreError', 'Client', 'AsyncClient', 'EmptyResponseWarning']
5760

5861

5962
class JsonstoreError(Exception):
@@ -98,7 +101,7 @@ def retrieve(self, key: str, timeout: int = DEFAULT_TIMEOUT_SECONDS):
98101
if not json_resp or not json_resp['result']:
99102
warn('Jsonstore returned null, please make sure something is saved under this key.', EmptyResponseWarning)
100103
return None
101-
return jsonpickle.decode(json_resp['result'])
104+
return json_resp['result']
102105
except (ValueError, KeyError) as e:
103106
raise JsonstoreError(str(e))
104107

@@ -108,13 +111,13 @@ def store(self, key: str, data, timeout: int = DEFAULT_TIMEOUT_SECONDS):
108111
"""Save data in jsonstore under a key.
109112
110113
:param key:str Name of key to a resource
111-
:param data:any Data to be updated/saved, will be processed with jsonpickle.
114+
:param data Data to be updated/saved..
112115
:param timeout:int Timeout of the request in seconds
113116
"""
114117
if not isinstance(key, str):
115118
raise TypeError("Key must be str, not {}".format(key.__class__.__name__))
116119
url = self.__finalize_url(key)
117-
json_data = json.dumps(jsonpickle.encode(data))
120+
json_data = json.dumps(data)
118121
resp = self.session.post(url, data=json_data, timeout=timeout)
119122
self.__check_response(resp)
120123
return json_data
@@ -173,17 +176,20 @@ def __finalize_url(self, key):
173176
class AsyncClient:
174177
def __init__(self, token: str):
175178
self.version = VERSION
176-
self.session = aiohttp.ClientSession(headers={
177-
'Accept': 'application/json',
178-
'Content-type': 'application/json',
179-
'User-Agent': f'Mozilla/5.0 Python/json-store-client/{self.version}'
180-
})
179+
self.session = get_event_loop().run_until_complete(self.__create_session())
181180
if not isinstance(token, str):
182181
raise TypeError("Token must be str, not {}".format(token.__class__.__name__))
183182
if token.startswith('https://'):
184183
token = token.split('/')[-1]
185184
self.__base_url = f'https://www.jsonstore.io/{token}'
186185

186+
async def __create_session(self):
187+
return aiohttp.ClientSession(headers={
188+
'Accept': 'application/json',
189+
'Content-type': 'application/json',
190+
'User-Agent': f'Mozilla/5.0 Python/json-store-client/{self.version}'
191+
})
192+
187193
async def retrieve(self, key: str, timeout: int = DEFAULT_TIMEOUT_SECONDS):
188194
"""Get gets value from jsonstore.
189195
@@ -196,11 +202,12 @@ async def retrieve(self, key: str, timeout: int = DEFAULT_TIMEOUT_SECONDS):
196202
url = await self.__finalize_url(key)
197203
try:
198204
async with self.session.get(url, timeout=timeout) as s:
199-
json_resp = await s.json()
205+
json_resp = json.loads(await s.text())
200206
if not json_resp or not json_resp['result']:
201-
warn('JSONSTORE WARNING: Jsonstore returned null, please make sure something is saved under this key.')
207+
warn('JSONSTORE WARNING: Jsonstore returned null, please make sure something is saved under this key.',
208+
EmptyResponseWarning)
202209
return None
203-
return jsonpickle.decode(json_resp['result'])
210+
return json_resp['result']
204211
except (ValueError, KeyError) as e:
205212
raise JsonstoreError(str(e))
206213

@@ -210,13 +217,13 @@ async def store(self, key: str, data, timeout: int = DEFAULT_TIMEOUT_SECONDS):
210217
"""Save data in jsonstore under a key.
211218
212219
:param key:str Name of key to a resource
213-
:param data:any Data to be updated/saved, will be processed with jsonpickle.
220+
:param data Data to be updated/saved.
214221
:param timeout:int Timeout of the request in seconds
215222
"""
216223
if not isinstance(key, str):
217224
raise TypeError("Key must be str, not {}".format(key.__class__.__name__))
218225
url = await self.__finalize_url(key)
219-
json_data = json.dumps(jsonpickle.encode(data))
226+
json_data = json.dumps(data)
220227
async with self.session.post(url, data=json_data, timeout=timeout) as s:
221228
s.raise_for_status()
222229
return json_data
@@ -226,7 +233,7 @@ async def store(self, key: str, data, timeout: int = DEFAULT_TIMEOUT_SECONDS):
226233
async def store_multiple(self, data: dict, timeout: int = DEFAULT_TIMEOUT_SECONDS):
227234
"""Save data in jsonstore with a dict mapping.
228235
229-
:param data:dict A dict of {key(s):value(s)} to be updated. Value(s) can be any python object, will be processed with jsonpickle.
236+
:param data:dict A dict of {key(s):value(s)} to be updated.
230237
:param timeout:int Timeout of the request in seconds
231238
"""
232239
if not isinstance(data, dict):

requirements.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
requests>=2.22.0
22
aiohttp>=3.5.4
3-
jsonpickle==1.1
3+
jsonpickle==1.1
4+
ujson==1.35

setup.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
with open("README.md", "r") as fh:
44
long_description = fh.read()
55
requires = [
6-
'requests', 'jsonpickle', 'aiohttp'
6+
'requests', 'aiohttp'
77
]
88
setuptools.setup(
99
name="json-store-client",
10-
version="1.0.2",
10+
version="1.1.0",
1111
author="leon332157",
1212
author_email="[email protected]",
1313
description="A client library for jsonstore",

tests.py

+23-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
1+
import asyncio
2+
import random
13
import unittest
4+
25
import json_store_client
3-
import random
46

57
TOKEN = "4aca8a426a3d8f3b0230f8dd83806b10d25237e22393bdcddb710f548c373d7e"
68
KEY = 'testKey'
7-
DATA = {'testDataKey': 'testDataValue'}
9+
DATA = {'testDataKey': 'testDataValue' + '😀'}
10+
11+
12+
def async_test(f):
13+
def wrapper(*args, **kwargs):
14+
coro = asyncio.coroutine(f)
15+
future = coro(*args, **kwargs)
16+
loop = asyncio.get_event_loop()
17+
loop.run_until_complete(future)
18+
19+
return wrapper
820

921

1022
class TestSyncClient(unittest.TestCase):
@@ -19,12 +31,12 @@ def testEmptyKey(self):
1931
self.client.get(str(random.randint(0, 10)))
2032

2133
def testSave(self):
22-
self.assertEqual(self.client.store(KEY, DATA), '"{\\"testDataKey\\": \\"testDataValue\\"}"')
34+
self.assertEqual(self.client.store(KEY, DATA), '{"testDataKey":"testDataValue\\ud83d\\ude00"}')
2335
self.assertEqual(self.client.get(KEY), DATA)
2436

2537
def testSaveMultiple(self):
2638
self.assertIsNone(self.client.store_multiple(DATA))
27-
self.assertEqual(self.client.get('testDataKey'), 'testDataValue')
39+
self.assertEqual(self.client.get('testDataKey'), 'testDataValue😀')
2840

2941
def testDelete(self):
3042
self.assertEqual(self.client.delete(KEY), KEY)
@@ -40,21 +52,26 @@ def setUp(self):
4052
def testInit(self):
4153
self.assertIsInstance(self.client, json_store_client.AsyncClient)
4254

55+
@async_test
4356
async def testEmptyKey(self):
4457
with self.assertWarns(json_store_client.EmptyResponseWarning):
4558
await self.client.get(str(random.randint(0, 10)))
4659

60+
@async_test
4761
async def testSave(self):
48-
self.assertEqual(await self.client.store(KEY, DATA), '"{\\"testDataKey\\": \\"testDataValue\\"}"')
62+
self.assertEqual(await self.client.store(KEY, DATA), '{"testDataKey":"testDataValue\\ud83d\\ude00"}')
4963
self.assertEqual(await self.client.get(KEY), DATA)
5064

65+
@async_test
5166
async def testSaveMultiple(self):
5267
self.assertIsNone(await self.client.store_multiple(DATA))
53-
self.assertEqual(await self.client.get('testDataKey'), 'testDataValue')
68+
self.assertEqual(await self.client.get('testDataKey'), 'testDataValue😀')
5469

70+
@async_test
5571
async def testDelete(self):
5672
self.assertEqual(await self.client.delete(KEY), KEY)
5773

74+
@async_test
5875
async def doCleanups(self):
5976
await self.client.session.close()
6077

0 commit comments

Comments
 (0)