Skip to content

Commit 661d5da

Browse files
committed
feat: initial setup for python SDK
1 parent 2388338 commit 661d5da

File tree

10 files changed

+1268
-0
lines changed

10 files changed

+1268
-0
lines changed

sdk/python/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
src/rrelayer/__pycache__/

sdk/python/.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.13

sdk/python/README.md

Whitespace-only changes.

sdk/python/pyproject.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[project]
2+
name = "rrelayer"
3+
version = "0.1.0"
4+
description = "The rrelayer sdk"
5+
readme = "README.md"
6+
authors = [
7+
{ name = "parizval", email = "[email protected]" }
8+
]
9+
requires-python = ">=3.13"
10+
dependencies = [
11+
"pydantic>=2.12.3",
12+
"web3>=7.14.0",
13+
]
14+
15+
[build-system]
16+
requires = ["uv_build>=0.9.2,<0.10.0"]
17+
build-backend = "uv_build"

sdk/python/src/rrelayer/__init__.py

Whitespace-only changes.

sdk/python/src/rrelayer/api.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import aiohttp
2+
import asyncio
3+
from pydantic import BaseModel, ConfigDict, PrivateAttr
4+
5+
6+
class API(BaseModel):
7+
_session: aiohttp.ClientSession | None = PrivateAttr(default=None)
8+
9+
model_config = ConfigDict(arbitrary_types_allowed=True)
10+
11+
def __del__(self):
12+
if self._session and not self._session.closed:
13+
try:
14+
loop = asyncio.get_running_loop()
15+
loop.create_task(self._session.close())
16+
except RuntimeError:
17+
# No running event loop (e.g., program exit) — close synchronously
18+
asyncio.run(self._session.close())
19+
print("Destroyed API Session")
20+
21+
async def _get_session(self):
22+
if self._session is None or self._session.closed:
23+
self._session = aiohttp.ClientSession()
24+
return self._session
25+
26+
async def getApi(self, url: str) -> dict:
27+
session = await self._get_session()
28+
async with session.get(url) as response:
29+
print(response.content_type)
30+
return await response.json()
31+
32+
async def postApi(self, url: str, headers, body) -> dict:
33+
session = await self._get_session()
34+
35+
async with session.post(url) as response:
36+
return await response.json()
37+
38+
async def putApi(self, url: str, headers, body) -> dict:
39+
session = await self._get_session()
40+
41+
async with session.put(url) as response:
42+
return await response.json()
43+
44+
async def deleteApi(self, url: str, headers, body) -> dict:
45+
session = await self._get_session()
46+
47+
async with session.delete(url) as response:
48+
return await response.json()
49+
50+
async def close(self):
51+
if self._session and not self._session.closed:
52+
await self._session.close()

sdk/python/src/rrelayer/client.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
from pydantic import BaseModel, validate_call, ConfigDict, PrivateAttr
2+
from rrelayer.api import API
3+
4+
5+
class Client(BaseModel):
6+
_serverURL: str = PrivateAttr()
7+
_auth_username: str = PrivateAttr()
8+
_auth_password: str = PrivateAttr()
9+
_api: API = PrivateAttr()
10+
11+
relayer: "Client.Relayer" = None
12+
network: "Client.Network | None" = None
13+
transaction: "Client.Transaction | None" = None
14+
allowlist: "Client.AllowList | None" = None
15+
16+
model_config = ConfigDict(arbitrary_types_allowed=True)
17+
18+
def __init__(self, serverURL: str, auth_username: str, auth_password: str, **data):
19+
super().__init__(**data)
20+
21+
self._serverURL = serverURL
22+
self._auth_username = auth_username
23+
self._auth_password = auth_password
24+
25+
self._api = API()
26+
27+
self.relayer = self.Relayer(self)
28+
self.network = self.Network(self)
29+
self.transaction = self.Transaction(self)
30+
self.allowlist = self.AllowList(self)
31+
32+
class Relayer:
33+
def __init__(self, client: "Client"):
34+
self._client: "Client" = client
35+
36+
@validate_call
37+
async def create(self, chainId: int, name: str):
38+
pass
39+
40+
@validate_call
41+
async def clone(self, relayerId: str, chainId: int, name: str):
42+
pass
43+
44+
@validate_call
45+
async def delete(self, id: str):
46+
pass
47+
48+
@validate_call
49+
async def get(self, id: str):
50+
pass
51+
52+
@validate_call
53+
async def getAll(self):
54+
pass
55+
56+
def printValues(self):
57+
print("Print Values")
58+
print(self._client._auth_username)
59+
60+
class Network:
61+
def __init__(self, client: "Client"):
62+
self._client: "Client" = client
63+
64+
class Transaction:
65+
def __init__(self, client: "Client"):
66+
self._client: "Client" = client
67+
68+
class AllowList:
69+
def __init__(self, client: "Client"):
70+
self._client: "Client" = client
71+
72+
73+
@validate_call
74+
def createClient(serverURL: str, auth_username: str, auth_password: str) -> Client:
75+
return Client(
76+
serverURL=serverURL,
77+
auth_username=auth_username,
78+
auth_password=auth_password,
79+
)

sdk/python/src/rrelayer/py.typed

Whitespace-only changes.

sdk/python/src/rrelayer/relayer.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from pydantic import BaseModel, ConfigDict, PrivateAttr
2+
from asyncinit import asyncinit
3+
from web3 import AsyncWeb3
4+
5+
6+
@asyncinit
7+
class Relayer(BaseModel):
8+
_id: str = PrivateAttr()
9+
10+
_apiBaseConfig: dict = PrivateAttr()
11+
model_config = ConfigDict(arbitrary_types_allowed=True)
12+
_ethereumProvider: AsyncWeb3 | None = None
13+
14+
def __init__(
15+
self,
16+
serverURL: str,
17+
providerUrl: str,
18+
relayerId: str,
19+
auth: dict[str, str],
20+
**data,
21+
):
22+
super().__init__(**data)
23+
24+
self._id = relayerId
25+
26+
self._ethereumProvider = await AsyncWeb3(
27+
AsyncWeb3.AsyncHTTPProvider(providerUrl)
28+
)
29+
30+
if "apiKey" in auth:
31+
self._apiBaseConfig = {"apiKey": auth["apiKey"], "serverURL": serverURL}
32+
elif "username" in auth and "password" in auth:
33+
self._apiBaseConfig = {
34+
"username": auth["username"],
35+
"password": auth["password"],
36+
"serverURL": serverURL,
37+
}
38+
else:
39+
raise ValueError("Invalid authentication credentials")
40+
41+
@property
42+
def name(self):
43+
return self._id

0 commit comments

Comments
 (0)