kevy 5.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kevy-5.1.0/PKG-INFO +119 -0
- kevy-5.1.0/README.md +94 -0
- kevy-5.1.0/kevy/__init__.py +148 -0
- kevy-5.1.0/kevy/_client.py +381 -0
- kevy-5.1.0/kevy/_client_async.py +358 -0
- kevy-5.1.0/kevy/_client_async_remote.py +231 -0
- kevy-5.1.0/kevy/_client_remote.py +288 -0
- kevy-5.1.0/kevy/_cluster.py +249 -0
- kevy-5.1.0/kevy/_decode.py +172 -0
- kevy-5.1.0/kevy/_embedded.py +350 -0
- kevy-5.1.0/kevy/_enums.py +70 -0
- kevy-5.1.0/kevy/_errors.py +159 -0
- kevy-5.1.0/kevy/_ops.py +340 -0
- kevy-5.1.0/kevy/_parse.py +127 -0
- kevy-5.1.0/kevy/_pipeline.py +41 -0
- kevy-5.1.0/kevy/_reply.py +337 -0
- kevy-5.1.0/kevy/_resp_conn.py +136 -0
- kevy-5.1.0/kevy/_resp_conn_async.py +127 -0
- kevy-5.1.0/kevy/_subscriber.py +314 -0
- kevy-5.1.0/kevy/_subscriber_async.py +152 -0
- kevy-5.1.0/kevy/_transaction.py +235 -0
- kevy-5.1.0/kevy/_transaction_async.py +134 -0
- kevy-5.1.0/kevy/_types.py +121 -0
- kevy-5.1.0/kevy/_url.py +182 -0
- kevy-5.1.0/kevy.egg-info/PKG-INFO +119 -0
- kevy-5.1.0/kevy.egg-info/SOURCES.txt +47 -0
- kevy-5.1.0/kevy.egg-info/dependency_links.txt +1 -0
- kevy-5.1.0/kevy.egg-info/requires.txt +5 -0
- kevy-5.1.0/kevy.egg-info/top_level.txt +1 -0
- kevy-5.1.0/pyproject.toml +50 -0
- kevy-5.1.0/setup.cfg +4 -0
- kevy-5.1.0/tests/test_async.py +108 -0
- kevy-5.1.0/tests/test_blocking.py +71 -0
- kevy-5.1.0/tests/test_cluster.py +48 -0
- kevy-5.1.0/tests/test_collections.py +66 -0
- kevy-5.1.0/tests/test_core.py +96 -0
- kevy-5.1.0/tests/test_crc16.py +20 -0
- kevy-5.1.0/tests/test_embedded.py +69 -0
- kevy-5.1.0/tests/test_errors.py +84 -0
- kevy-5.1.0/tests/test_feed.py +51 -0
- kevy-5.1.0/tests/test_hashttl.py +47 -0
- kevy-5.1.0/tests/test_index.py +72 -0
- kevy-5.1.0/tests/test_pipeline.py +58 -0
- kevy-5.1.0/tests/test_pubsub.py +73 -0
- kevy-5.1.0/tests/test_reconnect.py +30 -0
- kevy-5.1.0/tests/test_reply.py +62 -0
- kevy-5.1.0/tests/test_transaction.py +79 -0
- kevy-5.1.0/tests/test_url.py +65 -0
- kevy-5.1.0/tests/test_zalgebra.py +53 -0
kevy-5.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kevy
|
|
3
|
+
Version: 5.1.0
|
|
4
|
+
Summary: First-party Python client for kevy — the pure-Rust Redis-compatible engine (embedded + remote, blocking + asyncio).
|
|
5
|
+
Author: GOLIA K.K.
|
|
6
|
+
License-Expression: MIT OR Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://kevy.golia.jp
|
|
8
|
+
Project-URL: Documentation, https://kevy.golia.jp
|
|
9
|
+
Project-URL: Repository, https://github.com/goliajp/kevy
|
|
10
|
+
Project-URL: Changelog, https://kevy.golia.jp/changelog/
|
|
11
|
+
Project-URL: Issues, https://github.com/goliajp/kevy/issues
|
|
12
|
+
Keywords: kevy,redis,resp,key-value,database,asyncio
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Database
|
|
17
|
+
Classifier: Topic :: Database :: Front-Ends
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Provides-Extra: test
|
|
22
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
23
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "test"
|
|
24
|
+
Requires-Dist: pytest-timeout>=2; extra == "test"
|
|
25
|
+
|
|
26
|
+
# kevy — Python client
|
|
27
|
+
|
|
28
|
+
First-party Python client for **kevy**, the pure-Rust, Redis-compatible
|
|
29
|
+
engine. One package ships **both faces** (contract §1.4): a blocking
|
|
30
|
+
`Client` and an asyncio `AsyncClient` — the same shape as redis-py's
|
|
31
|
+
`redis` + `redis.asyncio`.
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
pip install kevy
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
import kevy
|
|
39
|
+
|
|
40
|
+
# Remote — native RESP2/3 over TCP. Standard library only.
|
|
41
|
+
r = kevy.connect("kevy://127.0.0.1:6379")
|
|
42
|
+
r.set("k", "v")
|
|
43
|
+
assert r.get(b"k") == b"v"
|
|
44
|
+
|
|
45
|
+
# Asyncio — same package, same results.
|
|
46
|
+
ac = await kevy.AsyncClient.connect("kevy://127.0.0.1:6379")
|
|
47
|
+
await ac.set("k", "v")
|
|
48
|
+
|
|
49
|
+
# Embedded (in-process), over the C ABI with ctypes. Needs the engine —
|
|
50
|
+
# see below; this line raises a message naming where to get it otherwise.
|
|
51
|
+
c = kevy.connect("mem://app") # or file:///var/lib/app
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## The embedded engine
|
|
55
|
+
|
|
56
|
+
`mem://` and `file://` run kevy inside your process through
|
|
57
|
+
`libkevy_ffi`, a per-platform native library. A Python wheel does not
|
|
58
|
+
carry it: it would work on the handful of targets we happened to build
|
|
59
|
+
and nowhere else, while the remote client above works everywhere
|
|
60
|
+
CPython does. So the engine comes from the engine's own repository —
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
git clone https://github.com/goliajp/kevy
|
|
64
|
+
cd kevy && cargo build --release -p kevy-ffi # → target/release/
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
— and is found automatically from a kevy checkout, or by pointing
|
|
68
|
+
`KEVY_FFI_LIB` at the built library. Without it, the first embedded call
|
|
69
|
+
raises an error saying exactly this. Nothing else in the API differs.
|
|
70
|
+
|
|
71
|
+
## One URL, two transports (§1.1)
|
|
72
|
+
|
|
73
|
+
| Scheme | Backend |
|
|
74
|
+
|---|---|
|
|
75
|
+
| `mem://` | embedded, isolated in-memory store |
|
|
76
|
+
| `mem://<name>` | embedded, shared by name (pub/sub works cross-connect) |
|
|
77
|
+
| `file:///abs/path` | embedded, persistent (snapshot + AOF) |
|
|
78
|
+
| `kevy://` / `redis://` / `tcp://` | remote RESP over TCP |
|
|
79
|
+
|
|
80
|
+
`rediss://` / `kevys://` (TLS) and `redis://user:pass@host` (AUTH) are
|
|
81
|
+
rejected — kevy has neither.
|
|
82
|
+
|
|
83
|
+
## Embedded door (§5)
|
|
84
|
+
|
|
85
|
+
`kevy.open_mem()` / `kevy.open_persistent(dir)` return a `DB` — the
|
|
86
|
+
in-process store over `libkevy_ffi`, driven by ctypes (no C-extension
|
|
87
|
+
build). Every verb is reachable through `db.cmd(*argv) -> Reply`; `db.get`
|
|
88
|
+
/ `db.set` are the scalar fast paths; `db.subscribe(chan)` gives a polled
|
|
89
|
+
(`next()`) + blocking (`wait(ms)`) subscription. The library is located via
|
|
90
|
+
`$KEVY_FFI_LIB` or the repo `target/{release,debug}` build.
|
|
91
|
+
|
|
92
|
+
## Command families
|
|
93
|
+
|
|
94
|
+
Every family of the contract (§3): core string/generic, hash, list, set,
|
|
95
|
+
sorted set, sorted-set algebra, hash-field TTL, declarative indexes
|
|
96
|
+
(`idx_*`, remote-only) — with any other `IDX.*` subcommand reachable through
|
|
97
|
+
the raw `do(*argv)` / `idx_query_raw` escape hatches — change feed
|
|
98
|
+
(`feed_*`), pub/sub
|
|
99
|
+
(`Subscriber` / `AsyncSubscriber`), transactions (`Transaction`),
|
|
100
|
+
pipelines, blocking pops (`blpop`/`brpop`/`bzpopmin`), and the cluster
|
|
101
|
+
client (`ClusterClient`). Bytes and `str` are both accepted; the wire is
|
|
102
|
+
bytes (§7).
|
|
103
|
+
|
|
104
|
+
## Errors (§2)
|
|
105
|
+
|
|
106
|
+
Raised as a `KevyError` hierarchy inspectable by type: `StoreError`
|
|
107
|
+
(`WrongTypeError`, `NotIntegerError`, …), `ProtocolError`, `IoError`,
|
|
108
|
+
`UnsupportedError`, `InvalidInputError`, `NotFoundError`, `ReadOnlyError`,
|
|
109
|
+
`TimedOutError`, `ClosedError`.
|
|
110
|
+
|
|
111
|
+
## Tests
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
pip install -e '.[test]'
|
|
115
|
+
pytest # embedded + remote (spawns a real kevy server)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Remote tests build and boot `kevy` on a temp port; they skip cleanly if the
|
|
119
|
+
server binary is absent (`cargo build --release -p kevy`).
|
kevy-5.1.0/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# kevy — Python client
|
|
2
|
+
|
|
3
|
+
First-party Python client for **kevy**, the pure-Rust, Redis-compatible
|
|
4
|
+
engine. One package ships **both faces** (contract §1.4): a blocking
|
|
5
|
+
`Client` and an asyncio `AsyncClient` — the same shape as redis-py's
|
|
6
|
+
`redis` + `redis.asyncio`.
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
pip install kevy
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
import kevy
|
|
14
|
+
|
|
15
|
+
# Remote — native RESP2/3 over TCP. Standard library only.
|
|
16
|
+
r = kevy.connect("kevy://127.0.0.1:6379")
|
|
17
|
+
r.set("k", "v")
|
|
18
|
+
assert r.get(b"k") == b"v"
|
|
19
|
+
|
|
20
|
+
# Asyncio — same package, same results.
|
|
21
|
+
ac = await kevy.AsyncClient.connect("kevy://127.0.0.1:6379")
|
|
22
|
+
await ac.set("k", "v")
|
|
23
|
+
|
|
24
|
+
# Embedded (in-process), over the C ABI with ctypes. Needs the engine —
|
|
25
|
+
# see below; this line raises a message naming where to get it otherwise.
|
|
26
|
+
c = kevy.connect("mem://app") # or file:///var/lib/app
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## The embedded engine
|
|
30
|
+
|
|
31
|
+
`mem://` and `file://` run kevy inside your process through
|
|
32
|
+
`libkevy_ffi`, a per-platform native library. A Python wheel does not
|
|
33
|
+
carry it: it would work on the handful of targets we happened to build
|
|
34
|
+
and nowhere else, while the remote client above works everywhere
|
|
35
|
+
CPython does. So the engine comes from the engine's own repository —
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
git clone https://github.com/goliajp/kevy
|
|
39
|
+
cd kevy && cargo build --release -p kevy-ffi # → target/release/
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
— and is found automatically from a kevy checkout, or by pointing
|
|
43
|
+
`KEVY_FFI_LIB` at the built library. Without it, the first embedded call
|
|
44
|
+
raises an error saying exactly this. Nothing else in the API differs.
|
|
45
|
+
|
|
46
|
+
## One URL, two transports (§1.1)
|
|
47
|
+
|
|
48
|
+
| Scheme | Backend |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `mem://` | embedded, isolated in-memory store |
|
|
51
|
+
| `mem://<name>` | embedded, shared by name (pub/sub works cross-connect) |
|
|
52
|
+
| `file:///abs/path` | embedded, persistent (snapshot + AOF) |
|
|
53
|
+
| `kevy://` / `redis://` / `tcp://` | remote RESP over TCP |
|
|
54
|
+
|
|
55
|
+
`rediss://` / `kevys://` (TLS) and `redis://user:pass@host` (AUTH) are
|
|
56
|
+
rejected — kevy has neither.
|
|
57
|
+
|
|
58
|
+
## Embedded door (§5)
|
|
59
|
+
|
|
60
|
+
`kevy.open_mem()` / `kevy.open_persistent(dir)` return a `DB` — the
|
|
61
|
+
in-process store over `libkevy_ffi`, driven by ctypes (no C-extension
|
|
62
|
+
build). Every verb is reachable through `db.cmd(*argv) -> Reply`; `db.get`
|
|
63
|
+
/ `db.set` are the scalar fast paths; `db.subscribe(chan)` gives a polled
|
|
64
|
+
(`next()`) + blocking (`wait(ms)`) subscription. The library is located via
|
|
65
|
+
`$KEVY_FFI_LIB` or the repo `target/{release,debug}` build.
|
|
66
|
+
|
|
67
|
+
## Command families
|
|
68
|
+
|
|
69
|
+
Every family of the contract (§3): core string/generic, hash, list, set,
|
|
70
|
+
sorted set, sorted-set algebra, hash-field TTL, declarative indexes
|
|
71
|
+
(`idx_*`, remote-only) — with any other `IDX.*` subcommand reachable through
|
|
72
|
+
the raw `do(*argv)` / `idx_query_raw` escape hatches — change feed
|
|
73
|
+
(`feed_*`), pub/sub
|
|
74
|
+
(`Subscriber` / `AsyncSubscriber`), transactions (`Transaction`),
|
|
75
|
+
pipelines, blocking pops (`blpop`/`brpop`/`bzpopmin`), and the cluster
|
|
76
|
+
client (`ClusterClient`). Bytes and `str` are both accepted; the wire is
|
|
77
|
+
bytes (§7).
|
|
78
|
+
|
|
79
|
+
## Errors (§2)
|
|
80
|
+
|
|
81
|
+
Raised as a `KevyError` hierarchy inspectable by type: `StoreError`
|
|
82
|
+
(`WrongTypeError`, `NotIntegerError`, …), `ProtocolError`, `IoError`,
|
|
83
|
+
`UnsupportedError`, `InvalidInputError`, `NotFoundError`, `ReadOnlyError`,
|
|
84
|
+
`TimedOutError`, `ClosedError`.
|
|
85
|
+
|
|
86
|
+
## Tests
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
pip install -e '.[test]'
|
|
90
|
+
pytest # embedded + remote (spawns a real kevy server)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Remote tests build and boot `kevy` on a temp port; they skip cleanly if the
|
|
94
|
+
server binary is absent (`cargo build --release -p kevy`).
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""kevy — the first-party Python client for the pure-Rust, Redis-compatible
|
|
2
|
+
kevy engine.
|
|
3
|
+
|
|
4
|
+
One package, both faces (contract §1.4): a blocking :class:`Client` and an
|
|
5
|
+
asyncio :class:`AsyncClient`, exactly as redis-py ships ``redis`` +
|
|
6
|
+
``redis.asyncio``. A single ``connect(url)`` chooses the backend from the URL
|
|
7
|
+
scheme (§1.1): ``mem://`` / ``file://`` open the in-process **embedded**
|
|
8
|
+
engine (a ctypes binding over the C ABI ``libkevy_ffi`` — the new Python
|
|
9
|
+
embedded door, §5); ``kevy://`` / ``redis://`` / ``tcp://`` open a native
|
|
10
|
+
RESP2/3 TCP client. The wire is bytes; every key/value is binary-safe (§7).
|
|
11
|
+
|
|
12
|
+
import kevy
|
|
13
|
+
|
|
14
|
+
c = kevy.connect("mem://app") # embedded, blocking
|
|
15
|
+
c.set("k", "v"); print(c.get(b"k")) # -> b"v"
|
|
16
|
+
|
|
17
|
+
ac = await kevy.AsyncClient.connect("kevy://127.0.0.1:6379")
|
|
18
|
+
await ac.set("k", "v")
|
|
19
|
+
|
|
20
|
+
Errors are raised as a :class:`KevyError` hierarchy inspectable by type (§2).
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
from ._client import Client
|
|
26
|
+
from ._client_async import AsyncClient
|
|
27
|
+
from ._cluster import ClusterClient, crc16, key_hash_slot
|
|
28
|
+
from ._embedded import DB, Sub, abi, open_mem, open_persistent, version
|
|
29
|
+
from ._enums import EvictionPolicy, HExpireCond, IdxType, RespVersion, ZAggregate
|
|
30
|
+
from ._errors import (
|
|
31
|
+
ClosedError,
|
|
32
|
+
InvalidInputError,
|
|
33
|
+
IoError,
|
|
34
|
+
KevyError,
|
|
35
|
+
NoSuchKeyError,
|
|
36
|
+
NotFloatError,
|
|
37
|
+
NotFoundError,
|
|
38
|
+
NotIntegerError,
|
|
39
|
+
OutOfMemoryStoreError,
|
|
40
|
+
OutOfRangeError,
|
|
41
|
+
OverflowStoreError,
|
|
42
|
+
ProtocolError,
|
|
43
|
+
ReadOnlyError,
|
|
44
|
+
StoreError,
|
|
45
|
+
StoreErrorKind,
|
|
46
|
+
TimedOutError,
|
|
47
|
+
UnsupportedError,
|
|
48
|
+
WrongTypeError,
|
|
49
|
+
)
|
|
50
|
+
from ._pipeline import PipelineBuf
|
|
51
|
+
from ._reply import Reply, ReplyKind
|
|
52
|
+
from ._subscriber import Subscriber
|
|
53
|
+
from ._subscriber_async import AsyncSubscriber
|
|
54
|
+
from ._transaction import Transaction, TransactionReplies
|
|
55
|
+
from ._transaction_async import AsyncTransaction
|
|
56
|
+
from ._types import (
|
|
57
|
+
FeedBatch,
|
|
58
|
+
FeedFrame,
|
|
59
|
+
IdxInfo,
|
|
60
|
+
IdxPage,
|
|
61
|
+
IdxRow,
|
|
62
|
+
PubsubEvent,
|
|
63
|
+
PubsubKind,
|
|
64
|
+
Ranked,
|
|
65
|
+
ZMember,
|
|
66
|
+
ZPopHit,
|
|
67
|
+
KV,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
__version__ = "5.1.0"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def connect(url: str) -> Client:
|
|
74
|
+
"""Open a blocking :class:`Client` for ``url`` (§1.1). Equivalent to
|
|
75
|
+
:meth:`Client.connect`."""
|
|
76
|
+
return Client.connect(url)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
async def aconnect(url: str) -> AsyncClient:
|
|
80
|
+
"""Open an asyncio :class:`AsyncClient` for ``url`` (§1.4). Equivalent to
|
|
81
|
+
:meth:`AsyncClient.connect`."""
|
|
82
|
+
return await AsyncClient.connect(url)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
__all__ = [
|
|
86
|
+
"__version__",
|
|
87
|
+
"connect",
|
|
88
|
+
"aconnect",
|
|
89
|
+
# clients
|
|
90
|
+
"Client",
|
|
91
|
+
"AsyncClient",
|
|
92
|
+
"ClusterClient",
|
|
93
|
+
"Subscriber",
|
|
94
|
+
"AsyncSubscriber",
|
|
95
|
+
"Transaction",
|
|
96
|
+
"AsyncTransaction",
|
|
97
|
+
"TransactionReplies",
|
|
98
|
+
"PipelineBuf",
|
|
99
|
+
# embedded store
|
|
100
|
+
"DB",
|
|
101
|
+
"Sub",
|
|
102
|
+
"open_mem",
|
|
103
|
+
"open_persistent",
|
|
104
|
+
"abi",
|
|
105
|
+
"version",
|
|
106
|
+
# reply / enums
|
|
107
|
+
"Reply",
|
|
108
|
+
"ReplyKind",
|
|
109
|
+
"ZAggregate",
|
|
110
|
+
"HExpireCond",
|
|
111
|
+
"IdxType",
|
|
112
|
+
"RespVersion",
|
|
113
|
+
"EvictionPolicy",
|
|
114
|
+
# data types
|
|
115
|
+
"ZMember",
|
|
116
|
+
"KV",
|
|
117
|
+
"ZPopHit",
|
|
118
|
+
"IdxRow",
|
|
119
|
+
"IdxPage",
|
|
120
|
+
"IdxInfo",
|
|
121
|
+
"Ranked",
|
|
122
|
+
"FeedFrame",
|
|
123
|
+
"FeedBatch",
|
|
124
|
+
"PubsubEvent",
|
|
125
|
+
"PubsubKind",
|
|
126
|
+
# cluster helpers
|
|
127
|
+
"crc16",
|
|
128
|
+
"key_hash_slot",
|
|
129
|
+
# errors
|
|
130
|
+
"KevyError",
|
|
131
|
+
"StoreError",
|
|
132
|
+
"StoreErrorKind",
|
|
133
|
+
"WrongTypeError",
|
|
134
|
+
"NotIntegerError",
|
|
135
|
+
"OverflowStoreError",
|
|
136
|
+
"OutOfRangeError",
|
|
137
|
+
"NoSuchKeyError",
|
|
138
|
+
"NotFloatError",
|
|
139
|
+
"OutOfMemoryStoreError",
|
|
140
|
+
"IoError",
|
|
141
|
+
"ProtocolError",
|
|
142
|
+
"ReadOnlyError",
|
|
143
|
+
"InvalidInputError",
|
|
144
|
+
"NotFoundError",
|
|
145
|
+
"UnsupportedError",
|
|
146
|
+
"TimedOutError",
|
|
147
|
+
"ClosedError",
|
|
148
|
+
]
|