Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TRA-4042: Update Version #44

Merged
merged 3 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ You can find specific documentation on a per-product basis below.
## SDK Documentation
You can learn more about the Transpose SDK and how it works below.

### SDK Helpers

#### stringify_list
Converts a list of strings into a single string, separated by a delimiter.

```python
from transpose.src.util.format import stringify_list

stringify_list(['a', 'b', 'c'], ',')
>>> 'a,b,c'
```

### SDK Classes
The Transpose SDK uses custom classes to represent API responses:
Expand Down
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

# version compliant with PEP440
# https://peps.python.org/pep-0440/
version='4.0.2',
version='4.2.0',

# project meta
long_description = long_description,
Expand All @@ -33,8 +33,8 @@
url='https://github.com/TransposeData/transpose-python-sdk',

# Author details
author='Michael Calvey (michaeljohncalvey), Alex Langshur (alangshur), Jonathan Becker (jon-becker)',
author_email='michael@transpose.io, alex@transpose.io, jon@transpose.io',
author='Michael Calvey (michaeljohncalvey), Alex Langshur (alangshur), Jonathan Becker (jon-becker), Patrick Croke (tannishmango)',
author_email='michael@transpose.io, alex@transpose.io, jon@transpose.io, patrick@transpose.io',

# Find all packages in the directory
packages=find_packages(exclude=['tests', 'demo', 'docs']),
Expand Down
6 changes: 4 additions & 2 deletions tests/test_analytical.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ def test_query_df():

try:
api = Transpose(api_key)

response = api.analytical.query("SELECT * FROM cross_chain.transaction_flows LIMIT 10;", return_df=True)
query = "SELECT * FROM cross_chain.transaction_flows LIMIT 10;"
response = api.analytical.query(
query
).toPandas()

assert len(response) == 10
assert isinstance(response, DataFrame)
Expand Down
3 changes: 2 additions & 1 deletion tests/test_sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ def test_query_df():
try:
api = Transpose(api_key)

response = api.sql.query("SELECT * FROM ethereum.logs LIMIT 100;", return_df=True)
query = "SELECT * FROM ethereum.logs LIMIT 100;"
response = api.sql.query(query).toPandas()

assert type(response) is DataFrame
assert len(response) == 100
Expand Down
9 changes: 5 additions & 4 deletions transpose/src/api/analytical/base.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from ...util.models import QueryResult
from ....src.util.client import post_api_request


Expand All @@ -11,8 +12,7 @@ def query(
self,
sql_query: str,
parameters: dict = None,
return_df: bool = False
) -> dict:
) -> QueryResult:

parameters = {} if parameters is None else parameters

Expand All @@ -22,10 +22,11 @@ def query(
'parameters': parameters
}

return post_api_request(
result = post_api_request(
url=url,
api_key=self.super.api_key,
body=body,
return_df=return_df,
verbose=self.super.verbose
)

return QueryResult(result)
9 changes: 5 additions & 4 deletions transpose/src/api/sql/base.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from ...util.models import QueryResult
from ....src.util.client import get_api_request, post_api_request


Expand All @@ -11,23 +12,23 @@ def query(
self,
sql_query: str,
parameters: dict = {},
return_df: bool = False
) -> dict:
) -> QueryResult:

url = "https://api.transpose.io/sql"
body = {
'sql': sql_query,
'parameters': parameters
}

return post_api_request(
result = post_api_request(
url=url,
api_key=self.super.api_key,
body=body,
return_df=return_df,
verbose=self.super.verbose
)

return QueryResult(result)

# Gets the schema from the Transpose API
def schema(self) -> dict:

Expand Down
28 changes: 7 additions & 21 deletions transpose/src/util/client.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import json
from typing import Union

import requests
import pandas as pd
from pandas import DataFrame

from transpose.src.util.errors import raise_custom_error

Expand All @@ -16,22 +12,14 @@ def build_headers(api_key: str) -> dict:
}


def handle_response(request: requests.Response, return_df: bool = False) -> Union[dict, DataFrame]:
if request.status_code == 200:

# return the response as a DataFrame
if return_df:

# check if pandas is installed
if not pd:
raise ImportError("Pandas is not installed. Please install pandas to use this feature.")

return pd.DataFrame(request.json()['results'])
def handle_response(request: requests.Response) -> dict:

if request.status_code == 200:
# return the response as a dictionary
return request.json()

else:

raise_custom_error(request.status_code, request.json()['message'])


Expand All @@ -40,9 +28,8 @@ def get_api_request(
api_key: str,
body: dict = None,
params=None,
return_df: bool = False,
verbose: bool = False
) -> Union[dict, DataFrame]:
) -> dict:

# set body/parameters to an empty dictionary if not provided
body = {} if body is None else body
Expand All @@ -60,17 +47,16 @@ def get_api_request(
params=params
)

return handle_response(request, return_df)
return handle_response(request)


def post_api_request(
url: str,
api_key: str,
body: dict,
params=None,
return_df: bool = False,
verbose: bool = False
) -> Union[dict, DataFrame]:
) -> dict:

# set body/parameters to an empty dictionary if not provided
body = {} if body is None else body
Expand All @@ -88,4 +74,4 @@ def post_api_request(
params=params
)

return handle_response(request, return_df)
return handle_response(request)
4 changes: 4 additions & 0 deletions transpose/src/util/format.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@


def stringify_list(data: list[str], delimiter: str = ",") -> str:
return delimiter.join([f"'{x}'" for x in data])
34 changes: 29 additions & 5 deletions transpose/src/util/models.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,42 @@
import io
import json
import base64

from typing import List

import pandas as pd


# add a .to_dict and .__dict__ method to the list base class
class list(list):
def to_dict(self):
return [obj.to_dict() for obj in self]

def __dict__(self):
return [obj.to_dict() for obj in self]



class QueryResult:
def __init__(self, result):
self.result = result

def toPandas(self):
# Assumes the result is a dictionary and the data is in the 'results' key
return pd.DataFrame(self.result['results'])

def keys(self):
return self.result.keys()

def values(self):
return self.result.values()

def __getitem__(self, key):
return self.result[key]

def __setitem__(self, key, value):
self.result[key] = value

def __delitem__(self, key):
del self.result[key]

def __iter__(self):
return iter(self.result)
# these are used in static typing so we can return useful tooltips for users
# and allow for proper type checking and syntax highlighting

Expand Down