Skip to content

Commit 3bf94a0

Browse files
author
dehidehidehi
committed
Fix: merged responses.order.py into responses.asset.py, to prevent import errors.
Also optimized imports.
1 parent 6d3a3db commit 3bf94a0

File tree

8 files changed

+80
-86
lines changed

8 files changed

+80
-86
lines changed

open_sea_v1/endpoints/client.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,12 @@ class BaseClient(ABC):
7474
client_params:
7575
ClientParams instance.
7676
77-
_rate_limit: int = 18
77+
_rate_limit: int
7878
Rate limit for the API is 20 when you have an API key.
7979
However, you run the risk of losing a a few seconds if you get throttled by the server.
8080
After some testing, it seems 18 is the sweet spot.
8181
82-
_concurrency_limit: int = 9
82+
_concurrency_limit: int
8383
Concurrency limit: number of simultaneous connections at a time.
8484
Best results obtained by using the largest multiple of _rate_limit, or second largest multiple.
8585
Otherwise you risk more throttling on the serverside than necessary.
@@ -117,13 +117,13 @@ def get_parsed_pages(self, flat: bool = True) -> list:
117117
if sys.platform == 'win32':
118118
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) # prevents closed loops errors on windows
119119
self._latest_json_response = None # reset: required for pagination function
120-
results = asyncio.run(self._aget_parsed_pages()) # implement async generator so i can use yield from
120+
results = asyncio.run(self._aget_parsed_pages())
121121
if not flat:
122122
return results
123123
flattened = list(chain.from_iterable(results))
124124
return flattened
125125

126-
async def _aget_parsed_pages(self) -> list[list[Type[BaseResponse]]]: # cant be a synchronous generator
126+
async def _aget_parsed_pages(self) -> list[list[Type[BaseResponse]]]:
127127
all_parsed_jsons = list()
128128

129129
async with RateLimiter(rate_limit=self._rate_limit, concurrency_limit=self._concurrency_limit) as rate_limiter:
@@ -136,6 +136,7 @@ async def _aget_parsed_pages(self) -> list[list[Type[BaseResponse]]]: # cant be
136136

137137
async def _async_get_pages_jsons(self, session, *, rate_limiter: RateLimiter) -> Optional[list[dict]]:
138138
responses = list()
139+
processed_pages = 0
139140
while self._remaining_pages():
140141

141142
self.client_params.offset += self.client_params.page_size
@@ -147,10 +148,12 @@ async def _async_get_pages_jsons(self, session, *, rate_limiter: RateLimiter) ->
147148
json_resp = await resp.json()
148149
self._latest_json_response = json_resp
149150
self.client_params._decrement_max_pages_attr()
151+
processed_pages += 1
150152

151153
if potential_error_occurred := isinstance(json_resp, dict) and 'detail' in json_resp.keys():
152154
raise ConnectionError(f'{(error_msg := json_resp["detail"])}')
153155

156+
logger.info(f'Fetched page #{processed_pages} (~{self.client_params.page_size} elements)')
154157
responses.append(json_resp)
155158
return responses
156159

open_sea_v1/endpoints/orders.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from open_sea_v1.endpoints.abc import BaseEndpoint
55
from open_sea_v1.endpoints.client import BaseClient, ClientParams
66
from open_sea_v1.endpoints.urls import EndpointURLS
7-
from open_sea_v1.responses.order import OrderResponse
7+
from open_sea_v1.responses.asset import OrderResponse
88

99

1010
@dataclass

open_sea_v1/endpoints/tests/test_client.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from itertools import chain
21
from os import environ
32
from unittest import TestCase, skipIf
43

open_sea_v1/helpers/rate_limiter.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import time
44
from contextlib import asynccontextmanager
55

6-
# GLOBAL_QUEUE = None # singleton queue
7-
86

97
class RateLimiter:
108
"""
@@ -19,10 +17,6 @@ def __init__(self, rate_limit: int, concurrency_limit: int) -> None:
1917
raise ValueError('concurrent limit must be non zero positive number')
2018

2119
self.rate_limit = rate_limit
22-
# global GLOBAL_QUEUE
23-
# if not GLOBAL_QUEUE:
24-
# GLOBAL_QUEUE = asyncio.Queue(rate_limit)
25-
# self.tokens_queue = GLOBAL_QUEUE
2620
self.tokens_queue = asyncio.Queue(rate_limit)
2721
self.tokens_consumer_task = asyncio.create_task(self.consume_tokens())
2822
self.semaphore = asyncio.Semaphore(concurrency_limit)

open_sea_v1/helpers/testing_class.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from abc import ABC, abstractmethod
2-
from itertools import chain
32
from typing import Type
43
from unittest import TestCase
54

open_sea_v1/responses/asset.py

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,72 @@ def __post_init__(self):
7474
self.external_link = self._contract['external_link']
7575

7676

77+
@dataclass
78+
class OrderResponse(BaseResponse):
79+
_json: dict
80+
81+
def __str__(self):
82+
return f"{self.id=}" if self.id else f"{self.order_hash=}"
83+
84+
def __post_init__(self):
85+
self._set_optional_attrs()
86+
self._set_common_attrs()
87+
88+
@property
89+
def asset(self) -> 'AssetResponse':
90+
return AssetResponse(self._json['asset'])
91+
92+
def _set_optional_attrs(self):
93+
"""Depending on the endpoint you use, the Order response object will contain optional attributes."""
94+
self.id: Optional = self._json.get('id') # id is only provided if you use the OrdersEndpoint
95+
self.asset_bundle = self._json.get('asset_bundle')
96+
97+
def _set_common_attrs(self):
98+
self.order_hash = self._json.get('order_hash')
99+
self.created_date = self._json['created_date']
100+
self.closing_date = self._json['closing_date']
101+
self.closing_extendable = self._json['closing_extendable']
102+
self.expiration_time = self._json['expiration_time']
103+
self.listing_time = self._json['listing_time']
104+
self.order_hash = self._json['order_hash']
105+
self.exchange = self._json['exchange']
106+
self.current_price = self._json['current_price']
107+
self.current_bounty = self._json['current_bounty']
108+
self.bounty_multiple = self._json['bounty_multiple']
109+
self.maker_relayer_fee = self._json['maker_relayer_fee']
110+
self.taker_relayer_fee = self._json['taker_relayer_fee']
111+
self.maker_protocol_fee = self._json['maker_protocol_fee']
112+
self.taker_protocol_fee = self._json['taker_protocol_fee']
113+
self.maker_referrer_fee = self._json['maker_referrer_fee']
114+
self.fee_method = self._json['fee_method']
115+
self.side = self._json['side']
116+
self.sale_kind = self._json['sale_kind']
117+
self.target = self._json['target']
118+
self.how_to_call = self._json['how_to_call']
119+
self.calldata = self._json['calldata']
120+
self.replacement_pattern = self._json['replacement_pattern']
121+
self.static_target = self._json['static_target']
122+
self.static_extradata = self._json['static_extradata']
123+
self.payment_token = self._json['payment_token']
124+
self.base_price = self._json['base_price']
125+
self.extra = self._json['extra']
126+
self.quantity = self._json['quantity']
127+
self.salt = self._json['salt']
128+
self.v = self._json['v']
129+
self.r = self._json['r']
130+
self.s = self._json['s']
131+
self.approved_on_chain = self._json['approved_on_chain']
132+
self.cancelled = self._json['cancelled']
133+
self.finalized = self._json['finalized']
134+
self.marked_invalid = self._json['marked_invalid']
135+
self.prefixed_hash = self._json['prefixed_hash']
136+
self.metadata: dict = self._json['metadata']
137+
self.maker: dict = self._json['maker']
138+
self.taker: dict = self._json['taker']
139+
self.fee_recipient: dict = self._json['fee_recipient']
140+
self.payment_token_contract: dict = self._json['payment_token_contract']
141+
142+
77143
@dataclass
78144
class AssetResponse(BaseResponse):
79145
_json: dict
@@ -112,7 +178,6 @@ def _set_common_attrs(self):
112178
self.is_presale = self._json.get("is_presale")
113179
self.listing_date = self._json.get("listing_date")
114180
self.top_bid = self._json.get("top_bid")
115-
self.sell_orders = self._json.get("sell_orders")
116181

117182
@property
118183
def asset_contract(self) -> _Contract:
@@ -140,6 +205,12 @@ def last_sale(self) -> Optional[_LastSale]:
140205
def collection(self):
141206
return CollectionResponse(self._json['collection'])
142207

208+
@property
209+
def sell_orders(self) -> Optional[list[OrderResponse]]:
210+
if sell_orders := self._json.get('sell_orders'):
211+
return [OrderResponse(order) for order in sell_orders]
212+
return None
213+
143214
@property
144215
def creator(self) -> Optional[dict]:
145216
return self._json.get('creator')

open_sea_v1/responses/order.py

Lines changed: 0 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,5 @@
11
"""
22
Assigns attributes to dictionnary values for easier object navigation.
33
"""
4-
from dataclasses import dataclass
54

6-
from open_sea_v1.responses.abc import BaseResponse
7-
from open_sea_v1.responses.asset import AssetResponse
85

9-
10-
@dataclass
11-
class OrderResponse(BaseResponse):
12-
_json: dict
13-
14-
def __str__(self):
15-
return f"order_id={self.id}"
16-
17-
def __post_init__(self):
18-
self._set_common_attrs()
19-
self._set_optional_attrs()
20-
21-
def _set_common_attrs(self):
22-
self.id = self._json['id']
23-
self.asset_bundle = self._json['asset_bundle']
24-
self.created_date = self._json['created_date']
25-
self.closing_date = self._json['closing_date']
26-
self.closing_extendable = self._json['closing_extendable']
27-
self.expiration_time = self._json['expiration_time']
28-
self.listing_time = self._json['listing_time']
29-
self.order_hash = self._json['order_hash']
30-
self.exchange = self._json['exchange']
31-
self.current_price = self._json['current_price']
32-
self.current_bounty = self._json['current_bounty']
33-
self.bounty_multiple = self._json['bounty_multiple']
34-
self.maker_relayer_fee = self._json['maker_relayer_fee']
35-
self.taker_relayer_fee = self._json['taker_relayer_fee']
36-
self.maker_protocol_fee = self._json['maker_protocol_fee']
37-
self.taker_protocol_fee = self._json['taker_protocol_fee']
38-
self.maker_referrer_fee = self._json['maker_referrer_fee']
39-
self.fee_method = self._json['fee_method']
40-
self.side = self._json['side']
41-
self.sale_kind = self._json['sale_kind']
42-
self.target = self._json['target']
43-
self.how_to_call = self._json['how_to_call']
44-
self.calldata = self._json['calldata']
45-
self.replacement_pattern = self._json['replacement_pattern']
46-
self.static_target = self._json['static_target']
47-
self.static_extradata = self._json['static_extradata']
48-
self.payment_token = self._json['payment_token']
49-
self.base_price = self._json['base_price']
50-
self.extra = self._json['extra']
51-
self.quantity = self._json['quantity']
52-
self.salt = self._json['salt']
53-
self.v = self._json['v']
54-
self.r = self._json['r']
55-
self.s = self._json['s']
56-
self.approved_on_chain = self._json['approved_on_chain']
57-
self.cancelled = self._json['cancelled']
58-
self.finalized = self._json['finalized']
59-
self.marked_invalid = self._json['marked_invalid']
60-
self.prefixed_hash = self._json['prefixed_hash']
61-
self.metadata: dict = self._json['metadata']
62-
self.maker: dict = self._json['maker']
63-
self.taker: dict = self._json['taker']
64-
self.fee_recipient: dict = self._json['fee_recipient']
65-
self.payment_token_contract: dict = self._json['payment_token_contract']
66-
67-
@property
68-
def asset(self) -> AssetResponse:
69-
return AssetResponse(self._json['asset'])
70-
71-
def _set_optional_attrs(self):
72-
"""
73-
Most asset responses are alike, but some are returned with less information.
74-
To avoid raising KeyErrors, we will use the .get method when setting these attributes.
75-
"""
76-
...

open_sea_v1/responses/tests/_response_helpers.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from itertools import chain
21
from typing import Type
32
from unittest import TestCase
43

0 commit comments

Comments
 (0)