hobbyrpc 0.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.
- hobbyrpc-0.1.0/PKG-INFO +56 -0
- hobbyrpc-0.1.0/README.md +47 -0
- hobbyrpc-0.1.0/pyproject.toml +23 -0
- hobbyrpc-0.1.0/src/hobbyrpc/__init__.py +1 -0
- hobbyrpc-0.1.0/src/hobbyrpc/client/__init__.py +32 -0
- hobbyrpc-0.1.0/src/hobbyrpc/client/call.py +30 -0
- hobbyrpc-0.1.0/src/hobbyrpc/client/exceptions.py +11 -0
- hobbyrpc-0.1.0/src/hobbyrpc/client/unix.py +12 -0
hobbyrpc-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: hobbyrpc
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: To make RPC clients and servers with Python
|
|
5
|
+
Author: Anatoly Chernov
|
|
6
|
+
Author-email: Anatoly Chernov <chertoly@gmail.com>
|
|
7
|
+
Requires-Python: >=3.13
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
|
|
10
|
+
## Introduction
|
|
11
|
+
|
|
12
|
+
It is a Python package to make [Hobby-RPC][hobby_rpc] clients and servers.
|
|
13
|
+
|
|
14
|
+
To install:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
pip install hobbyrpc
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Clients
|
|
21
|
+
|
|
22
|
+
A usage example:
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from hobbyrpc import Client
|
|
26
|
+
|
|
27
|
+
# via tcp
|
|
28
|
+
call = Client(
|
|
29
|
+
address='http://127.0.0.1:8080',
|
|
30
|
+
token="authorization token",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# or via unix socket
|
|
34
|
+
call = Client(
|
|
35
|
+
address='/tmp/path/to/rpc.socket',
|
|
36
|
+
token="authorization token",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
output = call('SomeNullaryFunction')
|
|
40
|
+
output = call('SomeUnaryFunction', **input)
|
|
41
|
+
|
|
42
|
+
# a call to Compile that compiles CoffeeScript code to JavaScript
|
|
43
|
+
output = call(
|
|
44
|
+
'Compile',
|
|
45
|
+
code='answer = 42',
|
|
46
|
+
bare=True,
|
|
47
|
+
)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`input` and `output` are Python objects serializable to and deserializable from JSON.
|
|
51
|
+
|
|
52
|
+
## Servers
|
|
53
|
+
|
|
54
|
+
Not implemented yet.
|
|
55
|
+
|
|
56
|
+
[hobby_rpc]: https://github.com/ch1c0t/hobby-rpc.protocol
|
hobbyrpc-0.1.0/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
## Introduction
|
|
2
|
+
|
|
3
|
+
It is a Python package to make [Hobby-RPC][hobby_rpc] clients and servers.
|
|
4
|
+
|
|
5
|
+
To install:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
pip install hobbyrpc
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Clients
|
|
12
|
+
|
|
13
|
+
A usage example:
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from hobbyrpc import Client
|
|
17
|
+
|
|
18
|
+
# via tcp
|
|
19
|
+
call = Client(
|
|
20
|
+
address='http://127.0.0.1:8080',
|
|
21
|
+
token="authorization token",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# or via unix socket
|
|
25
|
+
call = Client(
|
|
26
|
+
address='/tmp/path/to/rpc.socket',
|
|
27
|
+
token="authorization token",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
output = call('SomeNullaryFunction')
|
|
31
|
+
output = call('SomeUnaryFunction', **input)
|
|
32
|
+
|
|
33
|
+
# a call to Compile that compiles CoffeeScript code to JavaScript
|
|
34
|
+
output = call(
|
|
35
|
+
'Compile',
|
|
36
|
+
code='answer = 42',
|
|
37
|
+
bare=True,
|
|
38
|
+
)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`input` and `output` are Python objects serializable to and deserializable from JSON.
|
|
42
|
+
|
|
43
|
+
## Servers
|
|
44
|
+
|
|
45
|
+
Not implemented yet.
|
|
46
|
+
|
|
47
|
+
[hobby_rpc]: https://github.com/ch1c0t/hobby-rpc.protocol
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "hobbyrpc"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "To make RPC clients and servers with Python"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Anatoly Chernov", email = "chertoly@gmail.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.13"
|
|
10
|
+
dependencies = []
|
|
11
|
+
|
|
12
|
+
[project.scripts]
|
|
13
|
+
hobbyrpc = "hobbyrpc:main"
|
|
14
|
+
|
|
15
|
+
[build-system]
|
|
16
|
+
requires = ["uv_build>=0.9.26,<0.10.0"]
|
|
17
|
+
build-backend = "uv_build"
|
|
18
|
+
|
|
19
|
+
[dependency-groups]
|
|
20
|
+
dev = [
|
|
21
|
+
"pytest>=9.0.3",
|
|
22
|
+
"pytest-xprocess>=1.0.2",
|
|
23
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .client import Client
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from urllib.parse import urlparse
|
|
2
|
+
from http.client import HTTPConnection, HTTPSConnection
|
|
3
|
+
|
|
4
|
+
from .unix import UnixSocketConnection
|
|
5
|
+
from .exceptions import NotImplementedScheme
|
|
6
|
+
|
|
7
|
+
class Client:
|
|
8
|
+
def __init__(self, address, token=None):
|
|
9
|
+
if address.startswith('/'):
|
|
10
|
+
self.http = UnixSocketConnection(address)
|
|
11
|
+
self.http_path = '/'
|
|
12
|
+
else:
|
|
13
|
+
url = urlparse(address)
|
|
14
|
+
match url.scheme:
|
|
15
|
+
case 'http':
|
|
16
|
+
Connection = HTTPConnection
|
|
17
|
+
case 'https':
|
|
18
|
+
Connection = HTTPSConnection
|
|
19
|
+
case _:
|
|
20
|
+
raise NotImplementedScheme(f'#{url.scheme} of #{url}')
|
|
21
|
+
self.http = Connection(url.hostname, url.port)
|
|
22
|
+
self.http_path = url.path
|
|
23
|
+
|
|
24
|
+
self.headers = {
|
|
25
|
+
'Content-type': 'application/json',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if token:
|
|
29
|
+
self.headers['Authorization'] = token
|
|
30
|
+
|
|
31
|
+
from .call import call
|
|
32
|
+
Client.__call__ = call
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from .exceptions import BadRequest, Forbidden, UnexpectedStatus
|
|
3
|
+
|
|
4
|
+
def call(self, name, **input):
|
|
5
|
+
body = {
|
|
6
|
+
'fn': name,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if input:
|
|
10
|
+
body['in'] = input
|
|
11
|
+
|
|
12
|
+
self.http.request(
|
|
13
|
+
'POST', self.http_path,
|
|
14
|
+
body=json.dumps(body),
|
|
15
|
+
headers=self.headers,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
response = self.http.getresponse()
|
|
19
|
+
raw_data = response.read()
|
|
20
|
+
|
|
21
|
+
match response.status:
|
|
22
|
+
case 200:
|
|
23
|
+
data = json.loads(raw_data.decode('utf-8'))
|
|
24
|
+
return data
|
|
25
|
+
case 400:
|
|
26
|
+
raise BadRequest
|
|
27
|
+
case 403:
|
|
28
|
+
raise Forbidden
|
|
29
|
+
case _:
|
|
30
|
+
raise UnexpectedStatus(f'{response.status} in response {response}')
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from http.client import HTTPConnection
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import socket
|
|
4
|
+
|
|
5
|
+
class UnixSocketConnection(HTTPConnection):
|
|
6
|
+
def __init__(self, path):
|
|
7
|
+
self.socket_path = Path(path)
|
|
8
|
+
super().__init__(host='0.0.0.0')
|
|
9
|
+
|
|
10
|
+
def connect(self):
|
|
11
|
+
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
12
|
+
self.sock.connect(self.socket_path.as_posix())
|