Skip to content

Commit 8a159e7

Browse files
committed
Implemented OrdersEndpoint and OrderResponse
1 parent 41274cd commit 8a159e7

19 files changed

+485
-61
lines changed

open_sea_v1/endpoints/abc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from abc import ABC, abstractmethod
2-
from typing import Optional, Union, Generator
2+
from typing import Union, Generator
33

44
from requests import Response
55

open_sea_v1/endpoints/assets.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from dataclasses import dataclass
22
from enum import Enum
3-
from typing import Optional, Generator
3+
from typing import Optional
44

55
from open_sea_v1.endpoints.abc import BaseEndpoint
66
from open_sea_v1.endpoints.client import BaseClient, ClientParams
@@ -12,12 +12,16 @@ class AssetsOrderBy(str, Enum):
1212
"""
1313
Helper Enum for remembering the possible values for the order_by param of the AssetsEndpoint class.
1414
"""
15-
TOKEN_ID = "token_id"
1615
SALE_DATE = "sale_date"
1716
SALE_COUNT = "sale_count"
1817
VISITOR_COUNT = "visitor_count"
1918
SALE_PRICE = "sale_price"
2019

20+
@classmethod
21+
def list(cls) -> list[str]:
22+
"""Returns list of values of each attribute of this String Enum."""
23+
return list(map(lambda c: c.value, cls))
24+
2125

2226
@dataclass
2327
class AssetsEndpoint(BaseClient, BaseEndpoint):
@@ -63,16 +67,16 @@ class AssetsEndpoint(BaseClient, BaseEndpoint):
6367

6468
def __post_init__(self):
6569
self._validate_request_params()
70+
if not self.client_params:
71+
raise AttributeError('Attribute client_params is missing.')
6672

6773
@property
6874
def url(self):
6975
return EndpointURLS.ASSETS.value
7076

7177
@property
7278
def parsed_http_response(self) -> list[AssetResponse]:
73-
assets_json = self._http_response.json()['assets']
74-
assets = [AssetResponse(asset_json) for asset_json in assets_json]
75-
return assets
79+
return self.parse_http_response(AssetResponse, 'assets')
7680

7781
def _get_request(self, **kwargs):
7882
params = dict(
@@ -129,7 +133,7 @@ def _validate_order_by(self) -> None:
129133
if self.order_by is None:
130134
return
131135

132-
if self.order_by not in (AssetsOrderBy.TOKEN_ID, AssetsOrderBy.SALE_COUNT, AssetsOrderBy.SALE_DATE, AssetsOrderBy.SALE_PRICE, AssetsOrderBy.VISITOR_COUNT):
136+
if self.order_by not in AssetsOrderBy.list():
133137
raise ValueError(
134138
f"order_by param value ({self.order_by}) is invalid. "
135139
f"Must be a value from {AssetsOrderBy.list()}, case sensitive."

open_sea_v1/endpoints/collections.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ class CollectionsEndpoint(BaseClient, BaseEndpoint):
1818
Maintainer observations:
1919
----------
2020
You cannot specify the collection name for the data you wish to retrieve.
21-
The only way to retrieve such data, is by getting ALL collections from OpenSea, then
22-
iterating over them.
21+
In that situation, it is better to make a call to the Assets or Asset endpoint,
22+
and extract the information from the collection field.
2323
2424
2525
Parameters
@@ -41,6 +41,8 @@ class CollectionsEndpoint(BaseClient, BaseEndpoint):
4141

4242
def __post_init__(self):
4343
self._validate_request_params()
44+
if not self.client_params:
45+
raise AttributeError('Attribute client_params is missing.')
4446

4547
@property
4648
def url(self):

open_sea_v1/endpoints/events.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
from requests import Response
66

7-
from open_sea_v1.endpoints.client import BaseClient, ClientParams
87
from open_sea_v1.endpoints.abc import BaseEndpoint
8+
from open_sea_v1.endpoints.client import BaseClient, ClientParams
99
from open_sea_v1.endpoints.urls import EndpointURLS
1010
from open_sea_v1.helpers.extended_classes import ExtendedStrEnum
1111
from open_sea_v1.responses.event import EventResponse
@@ -79,6 +79,8 @@ class EventsEndpoint(BaseClient, BaseEndpoint):
7979

8080
def __post_init__(self):
8181
self._validate_request_params()
82+
if not self.client_params:
83+
raise AttributeError('Attribute client_params is missing.')
8284

8385
@property
8486
def url(self) -> str:
@@ -104,9 +106,7 @@ def _get_request(self, **kwargs) -> Response:
104106

105107
@property
106108
def parsed_http_response(self) -> list[EventResponse]:
107-
events_json = self._http_response.json()['asset_events']
108-
events = [EventResponse(event) for event in events_json]
109-
return events
109+
return self.parse_http_response(EventResponse, 'asset_events')
110110

111111
def _validate_request_params(self) -> None:
112112
self._validate_param_auction_type()

open_sea_v1/endpoints/orders.py

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
from dataclasses import dataclass
2+
from datetime import datetime
3+
4+
from open_sea_v1.endpoints.abc import BaseEndpoint
5+
from open_sea_v1.endpoints.client import BaseClient, ClientParams
6+
from open_sea_v1.endpoints.urls import EndpointURLS
7+
from open_sea_v1.responses.order import OrderResponse
8+
9+
10+
@dataclass
11+
class OrdersEndpoint(BaseClient, BaseEndpoint):
12+
"""
13+
How to fetch orders from the OpenSea system.
14+
15+
Parameters
16+
----------
17+
client_params:
18+
ClientParams instance.
19+
20+
asset_contract_address: str
21+
Filter by smart contract address for the asset category.
22+
Needs to be defined together with token_id or token_ids.
23+
24+
payment_token_address: str
25+
Filter by the address of the smart contract of the payment
26+
token that is accepted or offered by the order
27+
28+
maker: str
29+
Filter by the order maker's wallet address
30+
31+
taker: str
32+
Filter by the order taker's wallet address.
33+
Orders open for any taker have the null address as their taker.
34+
35+
owner: str
36+
Filter by the asset owner's wallet address
37+
38+
is_english: bool
39+
When "true", only show English Auction sell orders, which wait for the highest bidder.
40+
When "false", exclude those.
41+
42+
bundled: bool
43+
Only show orders for bundles of assets
44+
45+
include_bundled: bool
46+
Include orders on bundles where all assets in the bundle share the address
47+
provided in asset_contract_address or where the bundle's maker is the address provided in owner.
48+
49+
include_invalid: bool
50+
Include orders marked invalid by the orderbook, typically due to makers
51+
not owning enough of the token/asset anymore.
52+
53+
listed_after: datetime
54+
Only show orders listed after this timestamp.
55+
56+
listed_before: datetime
57+
Only show orders listed before this timestamp.
58+
59+
token_id: str
60+
Filter by the token ID of the order's asset.
61+
Needs to be defined together with asset_contract_address.
62+
63+
token_ids: list[str]
64+
Filter by a list of token IDs for the order's asset.
65+
Needs to be defined together with asset_contract_address.
66+
67+
side: int
68+
Filter by the side of the order.
69+
0 for buy orders and 1 for sell orders.
70+
71+
sale_kind: int
72+
Filter by the kind of sell order.
73+
0 for fixed-price sales or min-bid auctions, and 1 for declining-price Dutch Auctions.
74+
NOTE=use only_english=true for filtering for only English Auctions
75+
76+
limit: int
77+
Number of orders to return (capped at 50).
78+
79+
offset: int
80+
Number of orders to offset by (for pagination)
81+
82+
order_by: str
83+
How to sort the orders. Can be created_date for when they were made,
84+
or eth_price to see the lowest-priced orders first (converted to their ETH values).
85+
eth_price is only supported when asset_contract_address and token_id are also defined.
86+
87+
order_direction: str
88+
Can be asc or desc for ascending or descending sort.
89+
For example, to see the cheapest orders, do order_direction asc and order_by eth_price.
90+
91+
:return=Parsed JSON
92+
"""
93+
client_params: ClientParams = None
94+
asset_contract_address: str = None
95+
payment_token_address: str = None
96+
maker: str = None
97+
taker: str = None
98+
owner: str = None
99+
is_english: bool = None
100+
bundled: bool = None
101+
include_bundled: bool = None
102+
include_invalid: bool = None
103+
listed_after: datetime = None
104+
listed_before: datetime = None
105+
token_id: str = None
106+
token_ids: list[str] = None
107+
side: int = None
108+
sale_kind: int = None
109+
order_by: str = None
110+
order_direction: str = None
111+
112+
def __post_init__(self):
113+
self._validate_request_params()
114+
if not self.client_params:
115+
raise AttributeError('Attribute client_params is missing.')
116+
117+
@property
118+
def url(self):
119+
return EndpointURLS.ORDERS.value
120+
121+
@property
122+
def parsed_http_response(self) -> list[CollectionResponse]:
123+
orders_jsons = self._http_response.json()['orders']
124+
orders = [OrderResponse(order_json) for order_json in orders_jsons]
125+
return orders
126+
127+
def _get_request(self, **kwargs):
128+
params = dict(
129+
asset_contract_address=self.asset_contract_address,
130+
payment_token_address=self.payment_token_address,
131+
maker=self.maker,
132+
taker=self.taker,
133+
owner=self.owner,
134+
is_english=self.is_english,
135+
bundled=self.bundled,
136+
include_bundled=self.include_bundled,
137+
include_invalid=self.include_invalid,
138+
listed_after=self.listed_after,
139+
listed_before=self.listed_before,
140+
token_id=self.token_id,
141+
token_ids=self.token_ids,
142+
side=self.side,
143+
sale_kind=self.sale_kind,
144+
limit=self.client_params.limit,
145+
offset=self.client_params.offset,
146+
order_by=self.order_by,
147+
order_direction=self.order_direction,
148+
)
149+
get_request_kwargs = dict(params=params)
150+
self._http_response = super()._get_request(**get_request_kwargs)
151+
return self._http_response
152+
153+
def _validate_request_params(self) -> None:
154+
self._validate_contract_address_defined_with_token_id_or_tokens_ids()
155+
self._validate_token_id_defined_with_contract_address()
156+
self._validate_token_ids_defined_with_contract_address()
157+
self._validate_token_id_and_token_ids_cannot_be_defined_together()
158+
159+
def _validate_contract_address_defined_with_token_id_or_tokens_ids(self) -> None:
160+
if self.asset_contract_address is None:
161+
return
162+
if not any([self.token_id, self.token_ids]):
163+
raise AttributeError('attribute asset_contract_address must be defined together with either token_id or token_ids.')
164+
165+
def _validate_token_id_defined_with_contract_address(self) -> None:
166+
if self.token_id is None:
167+
return
168+
if not self.asset_contract_address:
169+
raise AttributeError('attribute token_id must be defined together with asset_contract_address')
170+
171+
def _validate_token_ids_defined_with_contract_address(self) -> None:
172+
if self.token_ids is None:
173+
return
174+
if not self.asset_contract_address:
175+
raise AttributeError('attribute token_ids must be defined together with asset_contract_address')
176+
177+
def _validate_token_id_and_token_ids_cannot_be_defined_together(self) -> None:
178+
if self.token_ids and self.token_id:
179+
raise AttributeError('attribute token_id and token_ids cannot be defined together.')

open_sea_v1/endpoints/tests/test_assets.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
class TestAssetsRequest(TestCase):
99
sample_contract = "0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb" # punk
1010
sample_wallet = "0x5ca12f79e4d33b0bd153b40df59f6db9ee03482e" # punk
11-
default_client_params = ClientParams(limit=5)
11+
default_client_params = ClientParams(limit=5, page_size=5)
1212
default_asset_params = dict(
1313
client_params=default_client_params, token_ids=[5, 6, 7], asset_contract_address=sample_contract,
1414
)
@@ -49,11 +49,6 @@ def test_param_order_direction_can_only_be_asc_or_desc(self):
4949
params = dict(token_ids=[1], asset_contract_address=self.sample_contract, order_direction=invalid_order)
5050
self.assertRaises((ValueError, TypeError), AssetsEndpoint, **params)
5151

52-
def test_param_order_by_token_id(self):
53-
params = self.default_asset_params | dict(token_ids=[3, 2, 1], order_by=AssetsOrderBy.TOKEN_ID, order_direction='desc')
54-
punks_ids = [punk.token_id for punk in self.create_and_get(**params)]
55-
self.assertEqual(['3', '2', '1'], punks_ids)
56-
5752
def test_param_order_by_sale_date(self):
5853
params = self.default_asset_params | dict(token_ids=[1, 14, 33], order_by=AssetsOrderBy.SALE_DATE)
5954
punks_sales = [punk.last_sale.event_timestamp for punk in self.create_and_get(**params)]

0 commit comments

Comments
 (0)