Skip to content

Commit 813c7ac

Browse files
committed
✨ feat: endpoint & sql support
1 parent 332ab18 commit 813c7ac

File tree

7 files changed

+299
-1
lines changed

7 files changed

+299
-1
lines changed

tests/test_endpoints.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
from datetime import datetime
2+
from transpose import Transpose, api_key
3+
from transpose.src.base import TransposeBadRequest
4+
5+
def test_basic():
6+
try:
7+
api = Transpose(api_key)
8+
9+
parameters = {
10+
'start_date': datetime.now().isoformat().split("T")[0],
11+
'time_interval': '1 day',
12+
'token_address': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
13+
}
14+
15+
response = api.endpoint.query('ohlc', parameters)
16+
17+
assert response['stats']['count'] >= 1
18+
assert len(response['results']) >= 1
19+
20+
except Exception:
21+
assert False
22+
23+
def test_normalize_1():
24+
try:
25+
api = Transpose(api_key)
26+
27+
parameters = {
28+
'start_date': datetime.now().isoformat().split("T")[0],
29+
'time_interval': '1 day',
30+
'token_address': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
31+
}
32+
33+
response = api.endpoint.query('https://api.transpose.io/endpoint/ohlc', parameters)
34+
35+
assert response['stats']['count'] >= 1
36+
assert len(response['results']) >= 1
37+
38+
except Exception:
39+
assert False
40+
41+
def test_normalize_2():
42+
try:
43+
api = Transpose(api_key)
44+
45+
parameters = {
46+
'start_date': datetime.now().isoformat().split("T")[0],
47+
'time_interval': '1 day',
48+
'token_address': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
49+
}
50+
51+
response = api.endpoint.query('https://api.transpose.io/ohlc', parameters)
52+
53+
assert response['stats']['count'] >= 1
54+
assert len(response['results']) >= 1
55+
56+
except Exception:
57+
assert False
58+
59+
def test_normalize_3():
60+
try:
61+
api = Transpose(api_key)
62+
63+
parameters = {
64+
'start_date': datetime.now().isoformat().split("T")[0],
65+
'time_interval': '1 day',
66+
'token_address': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
67+
}
68+
69+
response = api.endpoint.query('https://api.transpose.io/ohlc/', parameters)
70+
71+
assert response['stats']['count'] >= 1
72+
assert len(response['results']) >= 1
73+
74+
except Exception:
75+
assert False
76+
77+
def test_normalize_4():
78+
try:
79+
api = Transpose(api_key)
80+
81+
parameters = {
82+
'start_date': datetime.now().isoformat().split("T")[0],
83+
'time_interval': '1 day',
84+
'token_address': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
85+
}
86+
87+
response = api.endpoint.query('https://api.transpose.io/endpoint/ohlc/', parameters)
88+
89+
assert response['stats']['count'] >= 1
90+
assert len(response['results']) >= 1
91+
92+
except Exception:
93+
assert False
94+
95+
def test_normalize_5():
96+
try:
97+
api = Transpose(api_key)
98+
99+
parameters = {
100+
'start_date': datetime.now().isoformat().split("T")[0],
101+
'time_interval': '1 day',
102+
'token_address': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
103+
}
104+
105+
response = api.endpoint.query('https://api.transpose.io/endpoint/ohlc/1', parameters)
106+
107+
assert response['stats']['count'] >= 1
108+
assert len(response['results']) >= 1
109+
110+
except Exception:
111+
assert False
112+
113+
def test_normalize_6():
114+
try:
115+
api = Transpose(api_key)
116+
117+
parameters = {
118+
'start_date': datetime.now().isoformat().split("T")[0],
119+
'time_interval': '1 day',
120+
'token_address': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
121+
}
122+
123+
response = api.endpoint.query('https://api.transpose.io/endpoint/ohlc/1/', parameters)
124+
125+
assert response['stats']['count'] >= 1
126+
assert len(response['results']) >= 1
127+
128+
except Exception:
129+
assert False
130+

tests/test_raw_sql.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from transpose import Transpose, api_key
2+
from transpose.src.base import TransposeBadRequest
3+
4+
def test_basic():
5+
try:
6+
api = Transpose(api_key)
7+
8+
response = api.sql.query("SELECT * FROM ethereum.logs LIMIT 1;")
9+
10+
assert response['stats']['count'] == 1
11+
assert len(response['results']) == 1
12+
13+
except Exception:
14+
assert False
15+
16+
17+
def test_batch():
18+
try:
19+
api = Transpose(api_key)
20+
21+
response = api.sql.query("SELECT * FROM ethereum.logs LIMIT 100;")
22+
23+
assert response['stats']['count'] == 100
24+
assert len(response['results']) == 100
25+
26+
except Exception:
27+
assert False
28+
29+
30+
def test_invalid_query():
31+
try:
32+
api = Transpose(api_key)
33+
34+
response = api.sql.query("SELECT * FROM ethereum.lgos LIMIT 1;")
35+
36+
# assert throws
37+
assert False
38+
39+
except TransposeBadRequest:
40+
assert True
41+
42+
except Exception:
43+
assert False

transpose/src/api/endpoint/__init__.py

Whitespace-only changes.

transpose/src/api/endpoint/base.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import urllib.parse
2+
3+
class Endpoint():
4+
def __init__(self, base_class) -> None:
5+
self.super = base_class
6+
7+
# Performs the given custom endpoint query
8+
# https://docs.transpose.io/custom-endpoints/integrate/
9+
def query(self,
10+
endpoint: str,
11+
parameters: dict={}) -> dict:
12+
13+
# save json preference
14+
temp = self.super.json
15+
self.super.json = True
16+
17+
# normalize the endpoint
18+
endpoint = endpoint.replace("https://api.transpose.io/endpoint/", "").replace("https://api.transpose.io/", "").split("?")[0]
19+
20+
# remove the / if it ends the string
21+
endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint
22+
23+
# convert parameters to URI
24+
uri_params = urllib.parse.urlencode(parameters)
25+
26+
# build final endpoint
27+
endpoint = "https://api.transpose.io/endpoint/{}{}{}".format(
28+
endpoint,
29+
"?" if len(parameters) >= 1 else "",
30+
uri_params
31+
)
32+
33+
# make request
34+
response = self.super.perform_authorized_request(None, endpoint)
35+
36+
# update pref
37+
self.super.json = temp
38+
39+
return response

transpose/src/api/sql/__init__.py

Whitespace-only changes.

transpose/src/api/sql/base.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import json
2+
import requests
3+
4+
from ....src.util.errors import raise_custom_error
5+
6+
7+
class SQL():
8+
def __init__(self, base_class) -> None:
9+
self.super = base_class
10+
11+
# Performs the given SQL query
12+
# https://docs.transpose.io/sql/parameters/
13+
def query(self,
14+
sql_query: str,
15+
parameters: dict={}) -> dict:
16+
17+
# build headers
18+
request_headers = {
19+
'x-api-key': self.super.api_key,
20+
'Accept': 'application/json',
21+
}
22+
23+
# buold body
24+
body = {
25+
'sql': sql_query,
26+
'parameters': parameters
27+
}
28+
29+
# if in verbose mode, log the endpoint
30+
print("\n{}\n {}\n".format("https://api.transpose.io/sql", json.dumps(body, indent=4))) if self.super.verbose else None
31+
request = requests.post(
32+
"https://api.transpose.io/sql",
33+
headers=request_headers,
34+
json=body
35+
)
36+
37+
# check for a successful response
38+
if request.status_code == 200:
39+
40+
response = request.json()
41+
return response
42+
else:
43+
raise_custom_error(request.status_code, request.json()['message'])

transpose/src/base.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
from ..src.api.nft.base import NFT
99
from ..src.api.block.base import Block
1010
from ..src.api.token.base import Token
11-
11+
from ..src.api.sql.base import SQL
12+
from ..src.api.endpoint.base import Endpoint
1213

1314
# base class for the Transpose python SDK
1415
class Transpose:
@@ -46,6 +47,8 @@ def __init__(
4647
self.nft = NFT(self)
4748
self.block = Block(self)
4849
self.token = Token(self)
50+
self.sql = SQL(self)
51+
self.endpoint = Endpoint(self)
4952

5053
# deprecated in favor of the new API
5154
self.ENS = self.ens
@@ -116,6 +119,46 @@ def perform_authorized_request(self, model: type, endpoint: str, api_key: str=No
116119
if self.json:
117120
return response
118121

122+
return list(model(dict(each)) for each in response['results'])
123+
else:
124+
raise_custom_error(request.status_code, request.json()['message'])
125+
126+
# the base function for performing authorized requests to the Transpose API suite
127+
def perform_authorized_request(self, model: type, endpoint: str, api_key: str=None):
128+
if endpoint is None:
129+
return None
130+
131+
# build the request
132+
request_headers = {
133+
'x-api-key': api_key if api_key else self.api_key,
134+
'Accept': 'application/json',
135+
}
136+
137+
# add chain_id to the request
138+
endpoint += f'&chain_id={self.chain_id}'
139+
140+
# if in verbose mode, log the endpoint
141+
print("\n{}\n {}\n".format(endpoint.replace("https://api.transpose.io", self.host).split("?")[0], "\n ".join(endpoint.split("?")[1].split("&")))) if self.verbose else None
142+
request = requests.get(endpoint.replace("https://api.transpose.io", self.host), headers=request_headers)
143+
144+
# check for a successful response
145+
if request.status_code == 200:
146+
147+
response = request.json()
148+
149+
# If the response contains a paginator, set the paginator's next endpoint
150+
if 'next' in response:
151+
if response['next'] is None:
152+
self._next = None
153+
self._next_class_name = None
154+
else:
155+
self._next = response['next']
156+
self._next_class_name = model
157+
158+
# if we are in json mode, return the raw json
159+
if self.json:
160+
return response
161+
119162
return list(model(dict(each)) for each in response['results'])
120163
else:
121164
raise_custom_error(request.status_code, request.json()['message'])

0 commit comments

Comments
 (0)