Skip to content

Commit 2a8df3a

Browse files
committed
refactored and introduced more optionals for stricter use
1 parent 718723d commit 2a8df3a

File tree

5 files changed

+147
-82
lines changed

5 files changed

+147
-82
lines changed

examples/launchpad/README.md

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
1-
# LaunchPad
1+
# Launchpad
22

33
Users of the Launchpad product will need to pass in certain headers in order to make API requests.
44

5-
## EdgeHeaders
6-
EdgeHeaders can be passed into request calls, the additional parameter is available in all reference client functions,
7-
get_aggs, and snapshots
5+
```python
86

9-
###### X-Polygon-Edge-ID
10-
...[DESCRIPTION PENDING]
11-
###### X-Polygon-Edge-IP-Address
12-
...[DESCRIPTION PENDING]
13-
###### X-Polygon-Edge-User-Agent
14-
...[DESCRIPTION PENDING]
7+
# import RESTClient
8+
from polygon import RESTClient
9+
from polygon.rest.models.request import RequestOptionBuilder
1510

16-
## Example
11+
# create client
12+
c = RESTClient(api_key="API_KEY")
13+
14+
# create request options
15+
options = RequestOptionBuilder().edge_headers(
16+
edge_id="YOUR_EDGE_ID", # required
17+
edge_ip_address="IP_ADDRESS", # required
18+
)
19+
# get response
20+
res = c.get_aggs("AAPL", 1, "day", "2022-04-04", "2022-04-04", options=options)
21+
22+
# do something with response
23+
24+
```
25+
Launchpad users can also provide the optional User Agent value describing their Edge User's origination request.
1726

1827
```python
1928

@@ -25,15 +34,15 @@ from polygon.rest.models.request import RequestOptionBuilder
2534
c = RESTClient(api_key="API_KEY")
2635

2736
# create request options
28-
options = RequestOptionBuilder().required_edge_headers(
37+
options = RequestOptionBuilder().edge_headers(
2938
edge_id="YOUR_EDGE_ID", # required
3039
edge_ip_address="IP_ADDRESS" # required
31-
).optional_edge_headers(
32-
user_agent="USER_AGENT_ID" # optional
33-
)
40+
).update_edge_header(
41+
edge_user="EDGE_USER" # optional
42+
)
3443

3544
# get response
36-
res = c.get_ticker_events("META", options=options)
45+
res = c.get_aggs("AAPL", 1, "day", "2022-04-04", "2022-04-04", options=options)
3746

3847
# do something with response
3948

examples/launchpad/launchpad.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,18 @@ def get_aggs_launchpad():
1111
Example:
1212
`options = RequestOptionBuilder(edge_id="", edge_ip_address="")
1313
14-
or you can use the builder patten
14+
or you can use the builder patten for future modifications to
15+
underlying edge header dictionary.
1516
Example:
1617
options = RequestOptionBuilder()
17-
.required_edge_headers(edge_id="EDGE_ID", edge_ip_address="EDGE_ID_ADDRESS")
18-
.optional_edge_headers(user_agent="EDGE_USER_AGENT")
18+
.edge_headers(edge_id="EDGE_ID", edge_ip_address="EDGE_ID_ADDRESS")
19+
.update(edge_id="NEW")
20+
options = options.update_edge_header(edge_ip_address="NEW_IP")
1921
"""
2022
options = (
2123
RequestOptionBuilder()
22-
.required_edge_headers(edge_id="EDGE_ID", edge_ip_address="EDGE_ID_ADDRESS")
23-
.optional_edge_headers(user_agent="EDGE_USER_AGENT")
24+
.edge_headers(edge_id="EDGE_ID", edge_ip_address="EDGE_ID_ADDRESS")
25+
.update_edge_header(edge_user="EDGE_USER")
2426
)
2527

2628
trades = []

polygon/rest/base.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,14 @@ def _get(
7979
params = {str(k): str(v) for k, v in params.items() if v is not None}
8080
logger.debug("_get %s params %s", path, params)
8181

82-
option = RequestOptionBuilder() if options is None else options
82+
option = options if options is not None else RequestOptionBuilder()
8383

8484
resp = self.client.request(
8585
"GET",
8686
self.BASE + path,
8787
fields=params,
8888
retries=self.retries,
89-
headers=self._concat_headers(
90-
option.edge_headers
91-
), # merge supplied headers with standard headers
89+
headers=self._concat_headers(option.headers),
9290
)
9391

9492
if resp.status != 200:
@@ -159,7 +157,9 @@ def _get_params(
159157

160158
return params
161159

162-
def _concat_headers(self, headers: Dict[str, str]) -> Dict[str, str]:
160+
def _concat_headers(self, headers: Optional[Dict[str, str]]) -> Dict[str, str]:
161+
if headers is None:
162+
return {**self.headers}
163163
return {**headers, **self.headers}
164164

165165
def _paginate_iter(

polygon/rest/models/request.py

Lines changed: 64 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -20,65 +20,85 @@ def __init__(
2020
:param edge_ip_address: is a required Launchpad header. It denotes the originating IP Address of the Edge User
2121
:param edge_user: is an optional Launchpad header. It denotes the originating UserAgent of the Edge User requesting data.
2222
"""
23-
self.edge_headers: Dict[str, str] = {}
24-
self.__handle_edge_header_options(
25-
edge_id=edge_id, edge_ip_address=edge_ip_address, edge_user=edge_user
26-
)
23+
self.headers: Optional[Dict[str, str]] = None
24+
if edge_id is not None and edge_ip_address is not None:
25+
self.edge_headers(
26+
edge_id=edge_id, edge_ip_address=edge_ip_address, edge_user=edge_user
27+
)
2728

28-
def __handle_edge_header_options(
29+
def edge_headers(
2930
self,
30-
edge_id: Optional[str],
31+
edge_id: Optional[str] = None,
3132
edge_ip_address: Optional[str] = None,
3233
edge_user: Optional[str] = None,
3334
):
34-
edge_headers = {}
35-
if edge_id is not None:
36-
edge_headers[X_POLYGON_EDGE_ID] = edge_id
37-
if edge_ip_address is not None:
38-
edge_headers[X_POLYGON_EDGE_IP_ADDRESS] = edge_ip_address
35+
"""
36+
require_edge_headers adds required headers to the headers' dictionary
37+
:param edge_id: is a required Launchpad header. It identifies the Edge User requesting data
38+
:param edge_ip_address: is a required Launchpad header. It denotes the originating IP Address of the Edge User
39+
requesting data
40+
:param edge_user: user_agent: is an optional Launchpad header. It denotes the originating UserAgent of the Edge
41+
User requesting data
42+
:return ResponseOptionBuilder
43+
"""
44+
if edge_id is None or edge_ip_address is None:
45+
raise RequestOptionError(f"edge_id and edge_ip_address required.")
46+
47+
edge_headers: Dict[str, str] = {
48+
X_POLYGON_EDGE_ID: edge_id,
49+
X_POLYGON_EDGE_IP_ADDRESS: edge_ip_address,
50+
}
51+
3952
if edge_user is not None:
4053
edge_headers[X_POLYGON_EDGE_USER_AGENT] = edge_user
41-
self.__set_edge_headers(edge_headers)
4254

43-
def __set_edge_headers(self, headers: Dict[str, str]):
44-
self.edge_headers = headers
55+
self._add_to_edge_headers(**edge_headers)
4556

46-
def __add_to_edge_headers(self, **headers):
47-
for k, v in headers.items():
48-
self.edge_headers[k] = v
57+
return self
4958

50-
def required_edge_headers(
59+
def update_edge_header(
5160
self,
52-
edge_id: str,
53-
edge_ip_address: str,
61+
edge_id: Optional[str] = None,
62+
edge_ip_address: Optional[str] = None,
63+
edge_user: Optional[str] = None,
5464
):
5565
"""
56-
require_edge_headers adds required headers to the headers' dictionary
66+
used to change individual edge elements of underlying headers' dictionary.
5767
:param edge_id: is a required Launchpad header. It identifies the Edge User requesting data
5868
:param edge_ip_address: is a required Launchpad header. It denotes the originating IP Address of the Edge User
59-
requesting data.
60-
:return: RequestOptionBuilder
69+
requesting data
70+
:param edge_user: user_agent: is an optional Launchpad header. It denotes the originating UserAgent of the Edge
71+
User requesting data
72+
:return:
6173
"""
62-
self.__add_to_edge_headers(
63-
**{
64-
X_POLYGON_EDGE_ID: edge_id,
65-
X_POLYGON_EDGE_IP_ADDRESS: edge_ip_address,
66-
} # object destructure is needed for correct key formatting.
67-
)
68-
return self
74+
if self.headers is None:
75+
raise RequestOptionError(
76+
"must set required fields prior to using update function."
77+
)
78+
edge_headers: Dict[str, str] = {}
79+
80+
if edge_id is not None:
81+
edge_headers[X_POLYGON_EDGE_ID] = edge_id
82+
83+
if edge_ip_address is not None:
84+
edge_headers[X_POLYGON_EDGE_IP_ADDRESS] = edge_ip_address
85+
86+
if edge_user is not None:
87+
edge_headers[X_POLYGON_EDGE_USER_AGENT] = edge_user
88+
89+
self._add_to_edge_headers(**edge_headers)
6990

70-
def optional_edge_headers(
71-
self,
72-
user_agent: str,
73-
):
74-
"""
75-
edge_user_agent_header is used to add the optional X-Polygon-Edge-User-Agent key to the header dictionary
76-
:param user_agent: is an optional Launchpad header. It denotes the originating UserAgent of the Edge User requesting data.
77-
:return: RequestOptionBuilder
78-
"""
79-
self.__add_to_edge_headers(
80-
**{
81-
X_POLYGON_EDGE_USER_AGENT: user_agent,
82-
}
83-
)
8491
return self
92+
93+
def _add_to_edge_headers(self, **headers):
94+
if self.headers is None:
95+
self.headers = {}
96+
97+
for k, v in headers.items():
98+
self.headers[k] = v
99+
100+
101+
class RequestOptionError(Exception):
102+
"""
103+
Missing required option.
104+
"""

test_rest/models/test_requests.py

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ class RequestTest(unittest.TestCase):
1313
def test_empty_request_options(self):
1414
options = RequestOptionBuilder()
1515

16-
expected_edge_headers = {}
17-
assert expected_edge_headers == options.edge_headers
16+
expected_edge_headers = None
17+
assert expected_edge_headers == options.headers
1818

1919
def test_request_options_with_initialized_values(self):
2020
options = RequestOptionBuilder(
@@ -27,45 +27,79 @@ def test_request_options_with_initialized_values(self):
2727
X_POLYGON_EDGE_USER_AGENT: "test",
2828
}
2929

30-
assert expected_object == options.edge_headers
30+
assert expected_object == options.headers
3131

3232
def test_request_options_builder(self):
33-
options = RequestOptionBuilder().required_edge_headers(
33+
options = RequestOptionBuilder().edge_headers(
3434
edge_id="test", edge_ip_address="test"
3535
)
3636

3737
required_options = {
3838
X_POLYGON_EDGE_ID: "test",
3939
X_POLYGON_EDGE_IP_ADDRESS: "test",
4040
}
41-
print(options.edge_headers, required_options)
42-
self.assertDictEqual(required_options, options.edge_headers)
41+
print(options.headers, required_options)
42+
self.assertDictEqual(required_options, options.headers)
4343

4444
all_options = {
4545
X_POLYGON_EDGE_ID: "test",
4646
X_POLYGON_EDGE_IP_ADDRESS: "test",
4747
X_POLYGON_EDGE_USER_AGENT: "test",
4848
}
4949

50-
options = options.optional_edge_headers("test")
51-
self.assertDictEqual(all_options, options.edge_headers)
50+
options = options.update_edge_header(edge_user="test")
51+
self.assertDictEqual(all_options, options.headers)
52+
53+
def test_header_update(self):
5254

53-
def test_header_combination(self):
54-
client = RESTClient(api_key="test")
5555
options = RequestOptionBuilder(
5656
edge_id="test", edge_ip_address="test", edge_user="test"
5757
)
5858

5959
# this mocks the expected behavior during the request.get function call
6060
# in the BaseClient.
61-
headers = client._concat_headers(options.edge_headers)
61+
headers = options.headers
62+
63+
expected_headers = {
64+
"X-Polygon-Edge-ID": "test",
65+
"X-Polygon-Edge-IP-Address": "test",
66+
"X-Polygon-Edge-User-Agent": "test",
67+
}
68+
69+
self.assertDictEqual(headers, expected_headers)
6270

6371
expected_headers = {
72+
"X-Polygon-Edge-ID": "test2",
73+
"X-Polygon-Edge-IP-Address": "test2",
74+
"X-Polygon-Edge-User-Agent": "test2",
75+
}
76+
77+
options = options.update_edge_header(
78+
edge_id="test2", edge_ip_address="test2", edge_user="test2"
79+
)
80+
81+
self.assertDictEqual(options.headers, expected_headers)
82+
83+
def test_clint_headers_concat(self):
84+
client = RESTClient(api_key="test")
85+
options = RequestOptionBuilder("test", "test", "test")
86+
concat_headers = client._concat_headers(options.headers)
87+
88+
expected = {
6489
"Authorization": "Bearer test",
6590
"User-Agent": "Polygon.io PythonClient/0.0.0",
6691
"X-Polygon-Edge-ID": "test",
6792
"X-Polygon-Edge-IP-Address": "test",
6893
"X-Polygon-Edge-User-Agent": "test",
6994
}
7095

71-
self.assertDictEqual(headers, expected_headers)
96+
self.assertDictEqual(concat_headers, expected)
97+
98+
headers = None
99+
expected = {
100+
"Authorization": "Bearer test",
101+
"User-Agent": "Polygon.io PythonClient/0.0.0",
102+
}
103+
104+
self.assertDictEqual(expected, client._concat_headers(headers))
105+

0 commit comments

Comments
 (0)