Skip to content

Commit

Permalink
Merge pull request #38 from MtkN1/develop
Browse files Browse the repository at this point in the history
✨v0.2.0リリース

同期リクエストをサポートした #27
apisの暗黙的な読み込みに対応した #36
FTXのサブアカウントのWebSocket認証に対応した #37
  • Loading branch information
MtkN1 committed Apr 30, 2021
2 parents 9341d65 + 0868507 commit aa57c85
Show file tree
Hide file tree
Showing 8 changed files with 352 additions and 35 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -13,7 +13,7 @@ An advanced api client for python botters.
`pybotters` は現在 ** **BETAバージョン** ** です。
一部機能は開発中です。

正式バージョンの開発状況については [こちら](https://github.com/MtkN1/pybotters/issues/25) を参照してください。
開発状況については [こちら(Issues)](https://github.com/MtkN1/pybotters/issues) を参照してください。

## 🚀 Features

Expand Down
24 changes: 12 additions & 12 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

142 changes: 141 additions & 1 deletion pybotters/__init__.py
@@ -1,3 +1,143 @@
import asyncio
from typing import Any, Dict, List, Mapping, Optional, Union

import aiohttp
from aiohttp import hdrs
from rich import print

from .client import Client
from .models.bybit import BybitDataStore
from .models.btcmex import BTCMEXDataStore
from .models.bybit import BybitDataStore
from .models.ftx import FTXDataStore
from .typedefs import WsJsonHandler, WsStrHandler


def print_handler(msg: Any, ws: aiohttp.ClientWebSocketResponse):
print(msg)


class SyncClientResponse(aiohttp.ClientResponse):
def text(self, *args, **kwargs) -> str:
return self._loop.run_until_complete(super().text(*args, **kwargs))

def json(self, *args, **kwargs) -> Any:
return self._loop.run_until_complete(super().json(*args, **kwargs))


async def _request(
method: str,
url: str,
*,
params: Optional[Mapping[str, str]]=None,
data: Any=None,
apis: Union[Dict[str, List[str]], str]={},
**kwargs: Any,
) -> SyncClientResponse:
async with Client(apis=apis, response_class=SyncClientResponse) as client:
async with client.request(method, url, params=params, data=data, **kwargs) as resp:
await resp.read()
return resp


def request(
method: str,
url: str,
*,
params: Optional[Mapping[str, str]]=None,
data: Any=None,
apis: Union[Dict[str, List[str]], str]={},
**kwargs: Any,
) -> SyncClientResponse:
loop = asyncio.get_event_loop()
return loop.run_until_complete(_request(method, url, params=params, data=data, apis=apis, **kwargs))


def get(
url: str,
*,
params: Optional[Mapping[str, str]]=None,
apis: Union[Dict[str, List[str]], str]={},
**kwargs: Any,
) -> SyncClientResponse:
loop = asyncio.get_event_loop()
return loop.run_until_complete(_request(hdrs.METH_GET, url, params=params, apis=apis, **kwargs))


def post(
url: str,
*,
data: Any=None,
apis: Union[Dict[str, List[str]], str]={},
**kwargs: Any,
) -> SyncClientResponse:
loop = asyncio.get_event_loop()
return loop.run_until_complete(_request(hdrs.METH_POST, url, data=data, apis=apis, **kwargs))


def put(
url: str,
*,
data: Any=None,
apis: Union[Dict[str, List[str]], str]={},
**kwargs: Any,
) -> SyncClientResponse:
loop = asyncio.get_event_loop()
return loop.run_until_complete(_request(hdrs.METH_PUT, url, data=data, apis=apis, **kwargs))


def delete(
url: str,
*,
data: Any=None,
apis: Union[Dict[str, List[str]], str]={},
**kwargs: Any,
) -> SyncClientResponse:
loop = asyncio.get_event_loop()
return loop.run_until_complete(_request(hdrs.METH_DELETE, url, data=data, apis=apis, **kwargs))


async def _ws_connect(
url: str,
*,
send_str: Optional[Union[str, List[str]]]=None,
send_json: Any=None,
hdlr_str: Optional[WsStrHandler]=None,
hdlr_json: Optional[WsJsonHandler]=None,
apis: Union[Dict[str, List[str]], str]={},
**kwargs: Any,
) -> None:
async with Client(apis=apis) as client:
wstask = await client.ws_connect(
url,
send_str=send_str,
send_json=send_json,
hdlr_str=hdlr_str,
hdlr_json=hdlr_json,
**kwargs,
)
await wstask


def ws_connect(
url: str,
*,
send_str: Optional[Union[str, List[str]]]=None,
send_json: Any=None,
hdlr_str: Optional[WsStrHandler]=None,
hdlr_json: Optional[WsJsonHandler]=None,
apis: Union[Dict[str, List[str]], str]={},
**kwargs: Any,
) -> None:
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(_ws_connect(
url,
send_str=send_str,
send_json=send_json,
hdlr_str=hdlr_str,
hdlr_json=hdlr_json,
apis=apis,
**kwargs,
))
except KeyboardInterrupt:
pass
40 changes: 27 additions & 13 deletions pybotters/client.py
@@ -1,6 +1,7 @@
import asyncio
import json
import logging
import os
from typing import Any, Dict, List, Mapping, Optional, Tuple, Union

import aiohttp
Expand All @@ -24,23 +25,12 @@ def __init__(
base_url: str='',
**kwargs: Any,
) -> None:
if isinstance(apis, dict):
pass
elif isinstance(apis, str):
with open(apis, encoding='utf-8') as fp:
try:
apis = json.load(fp)
except json.JSONDecodeError as e:
logger.warning('apis file format must be JSON')
raise e
else:
logger.warning(f'apis must be dict or str(filepath), not {apis.__class__.__name__}')
apis = {}
self._session = aiohttp.ClientSession(
request_class=ClientRequest,
ws_response_class=ClientWebSocketResponse,
**kwargs,
)
apis = self._load_apis(apis)
self._session.__dict__['_apis'] = self._encode_apis(apis)
self._base_url = base_url

Expand Down Expand Up @@ -143,10 +133,34 @@ async def ws_connect(
await event.wait()
return task

@staticmethod
def _load_apis(apis: Union[Dict[str, List[str]], str]) -> Dict[str, List[str]]:
if isinstance(apis, dict):
if apis:
return apis
else:
current_apis = os.path.join(os.getcwd(), 'apis.json')
if os.path.isfile(current_apis):
with open(current_apis) as fp:
return json.load(fp)
else:
env_apis = os.getenv('PYBOTTERS_APIS')
if env_apis and os.path.isfile(env_apis):
with open(env_apis) as fp:
return json.load(fp)
else:
return apis
elif isinstance(apis, str):
with open(apis) as fp:
return json.load(fp)
else:
logger.warning(f'apis must be dict or str, not {apis.__class__.__name__}')
return {}

@staticmethod
def _encode_apis(apis: Dict[str, List[str]]) -> Dict[str, Tuple[str, bytes]]:
encoded = {}
for name in apis:
if len(apis[name]) == 2:
encoded[name] = (apis[name][0], apis[name][1].encode(), )
encoded[name] = (apis[name][0], apis[name][1].encode())
return encoded

0 comments on commit aa57c85

Please sign in to comment.