lusid-sdk 2.1.405__py3-none-any.whl → 2.1.537__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lusid/__init__.py +142 -8
- lusid/api/__init__.py +2 -2
- lusid/api/abor_api.py +126 -133
- lusid/api/abor_configuration_api.py +46 -45
- lusid/api/address_key_definition_api.py +28 -27
- lusid/api/aggregation_api.py +37 -36
- lusid/api/allocations_api.py +39 -38
- lusid/api/amortisation_rule_sets_api.py +55 -54
- lusid/api/application_metadata_api.py +28 -27
- lusid/api/blocks_api.py +37 -36
- lusid/api/calendars_api.py +469 -111
- lusid/api/chart_of_accounts_api.py +454 -279
- lusid/api/complex_market_data_api.py +37 -36
- lusid/api/compliance_api.py +136 -135
- lusid/api/configuration_recipe_api.py +100 -99
- lusid/api/conventions_api.py +109 -108
- lusid/api/corporate_action_sources_api.py +82 -81
- lusid/api/counterparties_api.py +73 -72
- lusid/api/custom_entities_api.py +102 -101
- lusid/api/custom_entity_definitions_api.py +37 -36
- lusid/api/custom_entity_types_api.py +37 -36
- lusid/api/cut_label_definitions_api.py +46 -45
- lusid/api/data_types_api.py +248 -72
- lusid/api/derived_transaction_portfolios_api.py +19 -18
- lusid/api/entities_api.py +431 -46
- lusid/api/executions_api.py +37 -36
- lusid/api/fee_types_api.py +55 -54
- lusid/api/{fund_configurations_api.py → fund_configuration_api.py} +222 -46
- lusid/api/funds_api.py +337 -162
- lusid/api/group_reconciliations_api.py +2182 -63
- lusid/api/instrument_event_types_api.py +64 -63
- lusid/api/instrument_events_api.py +46 -45
- lusid/api/instruments_api.py +374 -186
- lusid/api/legacy_compliance_api.py +73 -72
- lusid/api/legal_entities_api.py +167 -166
- lusid/api/order_graph_api.py +32 -31
- lusid/api/order_instructions_api.py +37 -36
- lusid/api/order_management_api.py +251 -90
- lusid/api/orders_api.py +37 -36
- lusid/api/packages_api.py +37 -36
- lusid/api/participations_api.py +37 -36
- lusid/api/persons_api.py +163 -162
- lusid/api/placements_api.py +37 -36
- lusid/api/portfolio_groups_api.py +235 -234
- lusid/api/portfolios_api.py +307 -309
- lusid/api/property_definitions_api.py +100 -99
- lusid/api/queryable_keys_api.py +10 -9
- lusid/api/quotes_api.py +82 -81
- lusid/api/reconciliations_api.py +136 -135
- lusid/api/reference_lists_api.py +39 -38
- lusid/api/reference_portfolio_api.py +213 -36
- lusid/api/relation_definitions_api.py +28 -27
- lusid/api/relations_api.py +19 -18
- lusid/api/relationship_definitions_api.py +46 -45
- lusid/api/relationships_api.py +19 -18
- lusid/api/schemas_api.py +37 -36
- lusid/api/scopes_api.py +19 -18
- lusid/api/scripted_translation_api.py +73 -72
- lusid/api/search_api.py +37 -36
- lusid/api/sequences_api.py +37 -36
- lusid/api/staged_modifications_api.py +37 -36
- lusid/api/staging_rule_set_api.py +46 -45
- lusid/api/structured_result_data_api.py +82 -81
- lusid/api/system_configuration_api.py +64 -63
- lusid/api/tax_rule_sets_api.py +46 -45
- lusid/api/transaction_configuration_api.py +100 -99
- lusid/api/transaction_fees_api.py +46 -45
- lusid/api/transaction_portfolios_api.py +771 -328
- lusid/api/translation_api.py +19 -18
- lusid/api/workspace_api.py +181 -180
- lusid/api_client.py +26 -17
- lusid/configuration.py +87 -2
- lusid/extensions/api_client.py +25 -17
- lusid/extensions/api_client_factory.py +14 -5
- lusid/extensions/api_configuration.py +50 -1
- lusid/extensions/configuration_loaders.py +39 -11
- lusid/extensions/configuration_options.py +67 -0
- lusid/extensions/rest.py +78 -26
- lusid/extensions/retry.py +109 -37
- lusid/models/__init__.py +140 -6
- lusid/models/access_metadata_value.py +1 -1
- lusid/models/accounting_method.py +7 -0
- lusid/models/accumulation_event.py +3 -3
- lusid/models/address_key_list.py +3 -3
- lusid/models/amortisation_event.py +3 -3
- lusid/models/amount.py +69 -0
- lusid/models/applicable_instrument_event.py +7 -2
- lusid/models/asset_leg.py +1 -1
- lusid/models/basket.py +3 -3
- lusid/models/batch_update_user_review_for_comparison_result_request.py +81 -0
- lusid/models/batch_update_user_review_for_comparison_result_response.py +146 -0
- lusid/models/batch_upsert_dates_for_calendar_response.py +146 -0
- lusid/models/batch_upsert_portfolio_access_metadata_request.py +27 -17
- lusid/models/batch_upsert_portfolio_access_metadata_response.py +56 -16
- lusid/models/{metadata_key_value.py → batch_upsert_portfolio_access_metadata_response_item.py} +15 -9
- lusid/models/bond.py +3 -3
- lusid/models/bond_coupon_event.py +10 -5
- lusid/models/bond_default_event.py +3 -3
- lusid/models/bond_principal_event.py +10 -5
- lusid/models/bonus_issue_event.py +166 -0
- lusid/models/{component_rule.py → break_code_source.py} +17 -21
- lusid/models/call_on_intermediate_securities_event.py +139 -0
- lusid/models/cancel_order_and_move_remaining_result.py +84 -0
- lusid/models/cancel_orders_and_move_remaining_request.py +83 -0
- lusid/models/cancel_orders_and_move_remaining_response.py +153 -0
- lusid/models/cap_floor.py +3 -3
- lusid/models/capital_distribution_event.py +3 -3
- lusid/models/cash.py +3 -3
- lusid/models/cash_dividend_event.py +3 -3
- lusid/models/cash_flow_event.py +3 -3
- lusid/models/cash_perpetual.py +3 -3
- lusid/models/cds_credit_event.py +6 -6
- lusid/models/cds_index.py +3 -3
- lusid/models/cdx_credit_event.py +6 -6
- lusid/models/change_interval.py +123 -0
- lusid/models/change_interval_with_order_management_detail.py +3 -3
- lusid/models/close_event.py +3 -3
- lusid/models/comparison_attribute_value_pair.py +71 -0
- lusid/models/complex_bond.py +3 -3
- lusid/models/component_transaction.py +10 -3
- lusid/models/contract_for_difference.py +3 -3
- lusid/models/create_derived_transaction_portfolio_request.py +3 -3
- lusid/models/create_group_reconciliation_definition_request.py +113 -0
- lusid/models/create_staging_rule_set_request.py +1 -6
- lusid/models/create_transaction_portfolio_request.py +3 -3
- lusid/models/credit_default_swap.py +3 -3
- lusid/models/credit_premium_cash_flow_event.py +3 -3
- lusid/models/custodian_account_request.py +1 -1
- lusid/models/custom_entity_entity.py +146 -0
- lusid/models/custom_entity_response.py +7 -1
- lusid/models/decimal_list.py +3 -3
- lusid/models/delete_instrument_properties_response.py +7 -1
- lusid/models/delete_instrument_response.py +7 -1
- lusid/models/delete_instruments_response.py +22 -1
- lusid/models/deleted_entity_response.py +7 -1
- lusid/models/diary_entry_request.py +10 -1
- lusid/models/dividend_option_event.py +3 -3
- lusid/models/dividend_reinvestment_event.py +9 -4
- lusid/models/effective_range.py +71 -0
- lusid/models/equity.py +3 -3
- lusid/models/equity_option.py +22 -7
- lusid/models/equity_swap.py +3 -3
- lusid/models/exchange_traded_option.py +3 -3
- lusid/models/exchange_traded_option_contract_details.py +1 -1
- lusid/models/exercise_event.py +3 -3
- lusid/models/exotic_instrument.py +3 -3
- lusid/models/expiry_event.py +3 -3
- lusid/models/fee.py +17 -10
- lusid/models/fee_request.py +20 -13
- lusid/models/fee_type.py +4 -4
- lusid/models/fee_type_request.py +3 -3
- lusid/models/fixed_leg.py +3 -3
- lusid/models/fixed_schedule.py +3 -3
- lusid/models/flexible_loan.py +3 -3
- lusid/models/float_schedule.py +4 -4
- lusid/models/floating_leg.py +3 -3
- lusid/models/flow_conventions.py +7 -1
- lusid/models/forward_rate_agreement.py +3 -3
- lusid/models/fund_configuration.py +44 -17
- lusid/models/fund_configuration_request.py +31 -19
- lusid/models/fund_id_list.py +99 -0
- lusid/models/fund_share_class.py +23 -8
- lusid/models/funding_leg.py +3 -3
- lusid/models/future.py +3 -3
- lusid/models/future_expiry_event.py +3 -3
- lusid/models/fx_forward.py +3 -3
- lusid/models/fx_forward_settlement_event.py +3 -3
- lusid/models/fx_option.py +3 -3
- lusid/models/fx_swap.py +3 -3
- lusid/models/group_reconciliation_aggregate_attribute_rule.py +2 -2
- lusid/models/group_reconciliation_aggregate_attribute_values.py +86 -0
- lusid/models/group_reconciliation_aggregate_comparison_rule_operand.py +1 -1
- lusid/models/group_reconciliation_comparison_result.py +148 -0
- lusid/models/group_reconciliation_core_attribute_values.py +86 -0
- lusid/models/group_reconciliation_core_comparison_rule_operand.py +1 -1
- lusid/models/group_reconciliation_date_pair.py +81 -0
- lusid/models/group_reconciliation_dates.py +78 -0
- lusid/models/group_reconciliation_definition.py +136 -0
- lusid/models/group_reconciliation_definition_comparison_ruleset_ids.py +83 -0
- lusid/models/group_reconciliation_definition_currencies.py +71 -0
- lusid/models/group_reconciliation_definition_portfolio_entity_ids.py +86 -0
- lusid/models/group_reconciliation_definition_recipe_ids.py +78 -0
- lusid/models/group_reconciliation_instance_id.py +71 -0
- lusid/models/group_reconciliation_result_statuses.py +89 -0
- lusid/models/group_reconciliation_result_types.py +96 -0
- lusid/models/group_reconciliation_review_statuses.py +96 -0
- lusid/models/group_reconciliation_run_details.py +76 -0
- lusid/models/group_reconciliation_run_request.py +75 -0
- lusid/models/{metadata_key_value_response.py → group_reconciliation_run_response.py} +20 -29
- lusid/models/group_reconciliation_summary.py +121 -0
- lusid/models/group_reconciliation_user_review.py +112 -0
- lusid/models/group_reconciliation_user_review_add.py +88 -0
- lusid/models/group_reconciliation_user_review_break_code.py +80 -0
- lusid/models/group_reconciliation_user_review_comment.py +80 -0
- lusid/models/group_reconciliation_user_review_match_key.py +80 -0
- lusid/models/group_reconciliation_user_review_remove.py +88 -0
- lusid/models/holding_contributor.py +11 -4
- lusid/models/holding_ids_request.py +69 -0
- lusid/models/inflation_leg.py +3 -3
- lusid/models/inflation_linked_bond.py +3 -3
- lusid/models/inflation_swap.py +3 -3
- lusid/models/informational_error_event.py +3 -3
- lusid/models/informational_event.py +3 -3
- lusid/models/instrument.py +7 -1
- lusid/models/instrument_definition.py +8 -2
- lusid/models/instrument_event.py +17 -5
- lusid/models/instrument_event_holder.py +9 -1
- lusid/models/instrument_event_type.py +12 -0
- lusid/models/instrument_leg.py +3 -3
- lusid/models/instrument_list.py +3 -3
- lusid/models/instrument_type.py +2 -0
- lusid/models/interest_rate_swap.py +3 -3
- lusid/models/interest_rate_swaption.py +3 -3
- lusid/models/intermediate_securities_distribution_event.py +140 -0
- lusid/models/lapse_election.py +73 -0
- lusid/models/loan_facility.py +97 -0
- lusid/models/lusid_instrument.py +7 -5
- lusid/models/market_data_key_rule.py +5 -3
- lusid/models/market_data_specific_rule.py +5 -3
- lusid/models/mastered_instrument.py +139 -0
- lusid/models/maturity_event.py +3 -3
- lusid/models/mbs_coupon_event.py +102 -0
- lusid/models/mbs_interest_deferral_event.py +102 -0
- lusid/models/mbs_interest_shortfall_event.py +102 -0
- lusid/models/mbs_principal_event.py +102 -0
- lusid/models/mbs_principal_write_off_event.py +102 -0
- lusid/models/merger_event.py +22 -22
- lusid/models/new_instrument.py +1 -1
- lusid/models/open_event.py +3 -3
- lusid/models/option_exercise_cash_event.py +144 -0
- lusid/models/option_exercise_election.py +73 -0
- lusid/models/option_exercise_physical_event.py +149 -0
- lusid/models/output_transaction.py +9 -2
- lusid/models/paged_resource_list_of_group_reconciliation_comparison_result.py +113 -0
- lusid/models/paged_resource_list_of_group_reconciliation_comparison_ruleset.py +113 -0
- lusid/models/paged_resource_list_of_group_reconciliation_definition.py +113 -0
- lusid/models/portfolio.py +3 -3
- lusid/models/portfolio_details.py +3 -3
- lusid/models/portfolio_group_id_list.py +3 -3
- lusid/models/portfolio_id_list.py +3 -3
- lusid/models/portfolio_without_href.py +3 -3
- lusid/models/pricing_options.py +8 -2
- lusid/models/property_list.py +3 -3
- lusid/models/protection_payout_cash_flow_event.py +102 -0
- lusid/models/raw_vendor_event.py +3 -3
- lusid/models/reference_instrument.py +3 -3
- lusid/models/reference_list.py +6 -5
- lusid/models/reference_list_type.py +1 -0
- lusid/models/repo.py +3 -3
- lusid/models/reset_event.py +3 -3
- lusid/models/resource_list_of_change_interval.py +113 -0
- lusid/models/resource_list_of_output_transaction.py +113 -0
- lusid/models/return_zero_pv_options.py +69 -0
- lusid/models/reverse_stock_split_event.py +21 -7
- lusid/models/scrip_dividend_event.py +3 -3
- lusid/models/settlement_cycle.py +79 -0
- lusid/models/share_class_dealing_breakdown.py +3 -2
- lusid/models/share_class_details.py +18 -1
- lusid/models/simple_cash_flow_loan.py +3 -3
- lusid/models/simple_instrument.py +3 -3
- lusid/models/simple_rounding_convention.py +76 -0
- lusid/models/spin_off_event.py +3 -3
- lusid/models/staged_modification_effective_range.py +2 -2
- lusid/models/stock_dividend_event.py +20 -6
- lusid/models/stock_split_event.py +3 -3
- lusid/models/string_list.py +3 -3
- lusid/models/swap_cash_flow_event.py +3 -3
- lusid/models/swap_principal_event.py +3 -3
- lusid/models/target_tax_lot.py +23 -2
- lusid/models/target_tax_lot_request.py +23 -2
- lusid/models/tender_event.py +172 -0
- lusid/models/term_deposit.py +3 -3
- lusid/models/total_return_swap.py +4 -4
- lusid/models/transaction.py +9 -2
- lusid/models/transaction_date_windows.py +85 -0
- lusid/models/transaction_price.py +3 -3
- lusid/models/transaction_price_type.py +2 -0
- lusid/models/transaction_request.py +9 -2
- lusid/models/transition_event.py +3 -3
- lusid/models/trigger_event.py +3 -3
- lusid/models/update_fee_type_request.py +4 -4
- lusid/models/update_group_reconciliation_comparison_ruleset_request.py +91 -0
- lusid/models/update_group_reconciliation_definition_request.py +107 -0
- lusid/models/update_reference_data_request.py +87 -0
- lusid/models/update_staging_rule_set_request.py +1 -6
- lusid/models/upsert_custom_entities_response.py +20 -1
- lusid/models/upsert_reference_portfolio_constituent_properties_request.py +84 -0
- lusid/models/upsert_reference_portfolio_constituent_properties_response.py +115 -0
- lusid/models/valuation_point_data_query_parameters.py +3 -3
- lusid/models/valuation_point_data_response.py +8 -13
- lusid/rest.py +70 -20
- {lusid_sdk-2.1.405.dist-info → lusid_sdk-2.1.537.dist-info}/METADATA +118 -26
- {lusid_sdk-2.1.405.dist-info → lusid_sdk-2.1.537.dist-info}/RECORD +294 -226
- {lusid_sdk-2.1.405.dist-info → lusid_sdk-2.1.537.dist-info}/WHEEL +0 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
class ConfigurationOptions:
|
4
|
+
|
5
|
+
def __init__(
|
6
|
+
self,
|
7
|
+
total_timeout_ms: Optional[int] = None,
|
8
|
+
connect_timeout_ms: Optional[int] = None,
|
9
|
+
read_timeout_ms: Optional[int] = None,
|
10
|
+
rate_limit_retries: Optional[int] = None
|
11
|
+
):
|
12
|
+
self.total_timeout_ms = total_timeout_ms
|
13
|
+
self.connect_timeout_ms = connect_timeout_ms
|
14
|
+
self.read_timeout_ms = read_timeout_ms
|
15
|
+
self.rate_limit_retries = rate_limit_retries
|
16
|
+
|
17
|
+
@property
|
18
|
+
def total_timeout_ms(self):
|
19
|
+
return self.__total_timeout_ms
|
20
|
+
|
21
|
+
@total_timeout_ms.setter
|
22
|
+
def total_timeout_ms(self, value):
|
23
|
+
if value:
|
24
|
+
if not isinstance(value, int):
|
25
|
+
raise TypeError(f"total_timeout_ms must be type int but type '{type(value)}' used")
|
26
|
+
if value < 0:
|
27
|
+
raise ValueError(f"total_timeout_ms must be an integer greater than or equal to zero")
|
28
|
+
self.__total_timeout_ms = value
|
29
|
+
|
30
|
+
@property
|
31
|
+
def connect_timeout_ms(self):
|
32
|
+
return self.__connect_timeout_ms
|
33
|
+
|
34
|
+
@connect_timeout_ms.setter
|
35
|
+
def connect_timeout_ms(self, value):
|
36
|
+
if value:
|
37
|
+
if not isinstance(value, int):
|
38
|
+
raise TypeError(f"connect_timeout_ms must be type int but type '{type(value)}' used")
|
39
|
+
if value < 0:
|
40
|
+
raise ValueError(f"connect_timeout_ms must be an integer greater than or equal to zero")
|
41
|
+
self.__connect_timeout_ms = value
|
42
|
+
|
43
|
+
@property
|
44
|
+
def read_timeout_ms(self):
|
45
|
+
return self.__read_timeout_ms
|
46
|
+
|
47
|
+
@read_timeout_ms.setter
|
48
|
+
def read_timeout_ms(self, value):
|
49
|
+
if value:
|
50
|
+
if not isinstance(value, int):
|
51
|
+
raise TypeError(f"read_timeout_ms must be type int but type '{type(value)}' used")
|
52
|
+
if value < 0:
|
53
|
+
raise ValueError(f"read_timeout_ms must be an integer greater than or equal to zero")
|
54
|
+
self.__read_timeout_ms = value
|
55
|
+
|
56
|
+
@property
|
57
|
+
def rate_limit_retries(self):
|
58
|
+
return self.__rate_limit_retries
|
59
|
+
|
60
|
+
@rate_limit_retries.setter
|
61
|
+
def rate_limit_retries(self, value):
|
62
|
+
if value:
|
63
|
+
if not isinstance(value, int):
|
64
|
+
raise TypeError(f"rate_limit_retries must be type int but type '{type(value)}' used")
|
65
|
+
if value < 0:
|
66
|
+
raise ValueError(f"rate_limit_retries must be an integer greater than or equal to zero")
|
67
|
+
self.__rate_limit_retries = value
|
lusid/extensions/rest.py
CHANGED
@@ -103,9 +103,15 @@ class RESTClientObject(object):
|
|
103
103
|
**addition_pool_args
|
104
104
|
)
|
105
105
|
|
106
|
+
self.timeout = self.get_timeout(
|
107
|
+
total=configuration.timeouts.total_timeout_ms / 1000.0,
|
108
|
+
connect=configuration.timeouts.connect_timeout_ms / 1000.0,
|
109
|
+
read=configuration.timeouts.read_timeout_ms / 1000.0,
|
110
|
+
)
|
111
|
+
|
106
112
|
def request(self, method, url, query_params=None, headers=None,
|
107
113
|
body=None, post_params=None, _preload_content=True,
|
108
|
-
_request_timeout=None):
|
114
|
+
_request_timeout=None, opts=None):
|
109
115
|
"""Perform requests.
|
110
116
|
|
111
117
|
:param method: http request method
|
@@ -119,10 +125,9 @@ class RESTClientObject(object):
|
|
119
125
|
:param _preload_content: if False, the urllib3.HTTPResponse object will
|
120
126
|
be returned without reading/decoding response
|
121
127
|
data. Default is True.
|
122
|
-
:param _request_timeout:
|
123
|
-
|
124
|
-
|
125
|
-
(connection, read) timeouts.
|
128
|
+
:param _request_timeout: Timeout setting. Do not use - use the opts parameter instead
|
129
|
+
:param opts: Configuration options for this request
|
130
|
+
:type opts: ConfigurationOptions, optional
|
126
131
|
"""
|
127
132
|
method = method.upper()
|
128
133
|
assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT',
|
@@ -139,14 +144,45 @@ class RESTClientObject(object):
|
|
139
144
|
# so reset query_params to empty dict
|
140
145
|
query_params = {}
|
141
146
|
|
147
|
+
# _request_timeout param cannot be removed for backwards compatability
|
148
|
+
# values from opts override values from _request_timeout
|
149
|
+
# try to get values from opts first, then _request_timeout, then self.timeout, else set to None
|
150
|
+
# timeout = _request_timeout or self.timeout
|
142
151
|
timeout = None
|
143
|
-
if
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
152
|
+
opts_total_timeout = opts.total_timeout_ms / 1000.0 if opts and opts.total_timeout_ms != None else None
|
153
|
+
opts_connect_timeout = opts.connect_timeout_ms / 1000.0 if opts and opts.connect_timeout_ms != None else None
|
154
|
+
opts_read_timeout = opts.read_timeout_ms / 1000.0 if opts and opts.read_timeout_ms != None else None
|
155
|
+
if not _request_timeout:
|
156
|
+
timeout = self.get_timeout(
|
157
|
+
total=opts_total_timeout if opts_total_timeout != None
|
158
|
+
else self.timeout.total,
|
159
|
+
connect=opts_connect_timeout if opts_connect_timeout != None
|
160
|
+
else self.timeout._connect,
|
161
|
+
read=opts_read_timeout if opts_read_timeout != None
|
162
|
+
else self.timeout._read)
|
163
|
+
elif isinstance(_request_timeout, urllib3.Timeout):
|
164
|
+
timeout = self.get_timeout(
|
165
|
+
total=opts_total_timeout if opts_total_timeout != None
|
166
|
+
else _request_timeout.total if _request_timeout.total != None
|
167
|
+
else self.timeout.total,
|
168
|
+
connect=opts_connect_timeout if opts_connect_timeout != None
|
169
|
+
else _request_timeout._connect if _request_timeout._connect != None
|
170
|
+
else self.timeout._connect,
|
171
|
+
read=opts_read_timeout if opts_read_timeout != None
|
172
|
+
else _request_timeout._read if _request_timeout._read != None
|
173
|
+
else self.timeout._read)
|
174
|
+
elif isinstance(_request_timeout, (int, float)):
|
175
|
+
timeout = self.get_timeout(
|
176
|
+
total=opts_total_timeout if opts_total_timeout != None else _request_timeout,
|
177
|
+
connect=opts_connect_timeout if opts_connect_timeout != None else self.timeout._connect,
|
178
|
+
read=opts_read_timeout if opts_read_timeout != None else self.timeout._read)
|
179
|
+
elif (isinstance(_request_timeout, tuple) and len(_request_timeout) == 2):
|
180
|
+
timeout = self.get_timeout(
|
181
|
+
total=opts_total_timeout if opts_total_timeout != None else self.timeout.total,
|
182
|
+
connect=opts_connect_timeout if opts_connect_timeout != None else _request_timeout[0],
|
183
|
+
read=opts_read_timeout if opts_read_timeout != None else _request_timeout[1])
|
184
|
+
else:
|
185
|
+
raise f"unexpected type '{type(_request_timeout)}' for _request_timeout"
|
150
186
|
|
151
187
|
try:
|
152
188
|
# For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`
|
@@ -235,66 +271,82 @@ class RESTClientObject(object):
|
|
235
271
|
return r
|
236
272
|
|
237
273
|
def get_request(self, url, headers=None, query_params=None, _preload_content=True,
|
238
|
-
_request_timeout=None):
|
274
|
+
_request_timeout=None, opts=None):
|
239
275
|
return self.request("GET", url,
|
240
276
|
headers=headers,
|
241
277
|
_preload_content=_preload_content,
|
242
278
|
_request_timeout=_request_timeout,
|
243
|
-
query_params=query_params
|
279
|
+
query_params=query_params,
|
280
|
+
opts=opts)
|
244
281
|
|
245
282
|
def head_request(self, url, headers=None, query_params=None, _preload_content=True,
|
246
|
-
_request_timeout=None):
|
283
|
+
_request_timeout=None, opts=None):
|
247
284
|
return self.request("HEAD", url,
|
248
285
|
headers=headers,
|
249
286
|
_preload_content=_preload_content,
|
250
287
|
_request_timeout=_request_timeout,
|
251
|
-
query_params=query_params
|
288
|
+
query_params=query_params,
|
289
|
+
opts=opts)
|
252
290
|
|
253
291
|
def options_request(self, url, headers=None, query_params=None, post_params=None,
|
254
|
-
body=None, _preload_content=True, _request_timeout=None):
|
292
|
+
body=None, _preload_content=True, _request_timeout=None, opts=None):
|
255
293
|
return self.request("OPTIONS", url,
|
256
294
|
headers=headers,
|
257
295
|
query_params=query_params,
|
258
296
|
post_params=post_params,
|
259
297
|
_preload_content=_preload_content,
|
260
298
|
_request_timeout=_request_timeout,
|
261
|
-
body=body
|
299
|
+
body=body,
|
300
|
+
opts=opts)
|
262
301
|
|
263
302
|
def delete_request(self, url, headers=None, query_params=None, body=None,
|
264
|
-
_preload_content=True, _request_timeout=None):
|
303
|
+
_preload_content=True, _request_timeout=None, opts=None):
|
265
304
|
return self.request("DELETE", url,
|
266
305
|
headers=headers,
|
267
306
|
query_params=query_params,
|
268
307
|
_preload_content=_preload_content,
|
269
308
|
_request_timeout=_request_timeout,
|
270
|
-
body=body
|
309
|
+
body=body,
|
310
|
+
opts=opts)
|
271
311
|
|
272
312
|
def post_request(self, url, headers=None, query_params=None, post_params=None,
|
273
|
-
body=None, _preload_content=True, _request_timeout=None):
|
313
|
+
body=None, _preload_content=True, _request_timeout=None, opts=None):
|
274
314
|
return self.request("POST", url,
|
275
315
|
headers=headers,
|
276
316
|
query_params=query_params,
|
277
317
|
post_params=post_params,
|
278
318
|
_preload_content=_preload_content,
|
279
319
|
_request_timeout=_request_timeout,
|
280
|
-
body=body
|
320
|
+
body=body,
|
321
|
+
opts=opts)
|
281
322
|
|
282
323
|
def put_request(self, url, headers=None, query_params=None, post_params=None,
|
283
|
-
body=None, _preload_content=True, _request_timeout=None):
|
324
|
+
body=None, _preload_content=True, _request_timeout=None, opts=None):
|
284
325
|
return self.request("PUT", url,
|
285
326
|
headers=headers,
|
286
327
|
query_params=query_params,
|
287
328
|
post_params=post_params,
|
288
329
|
_preload_content=_preload_content,
|
289
330
|
_request_timeout=_request_timeout,
|
290
|
-
body=body
|
331
|
+
body=body,
|
332
|
+
opts=opts)
|
291
333
|
|
292
334
|
def patch_request(self, url, headers=None, query_params=None, post_params=None,
|
293
|
-
body=None, _preload_content=True, _request_timeout=None):
|
335
|
+
body=None, _preload_content=True, _request_timeout=None, opts=None):
|
294
336
|
return self.request("PATCH", url,
|
295
337
|
headers=headers,
|
296
338
|
query_params=query_params,
|
297
339
|
post_params=post_params,
|
298
340
|
_preload_content=_preload_content,
|
299
341
|
_request_timeout=_request_timeout,
|
300
|
-
body=body
|
342
|
+
body=body,
|
343
|
+
opts=opts)
|
344
|
+
|
345
|
+
def get_timeout(self, total: int, connect: int, read: int):
|
346
|
+
# zero is used in the sdk config to explicitly set to infinity (and None is used to indicate the value has not been set)
|
347
|
+
# but zero is not an allowed value for urllib3.Timeout so change any zeros to Nones
|
348
|
+
return urllib3.Timeout(
|
349
|
+
total=total if total != 0 else None,
|
350
|
+
connect=connect if connect != 0 else None,
|
351
|
+
read=read if read != 0 else None,
|
352
|
+
)
|
lusid/extensions/retry.py
CHANGED
@@ -1,19 +1,33 @@
|
|
1
1
|
import time
|
2
|
-
from typing import
|
2
|
+
from typing import Optional
|
3
3
|
|
4
|
-
from lusid import ApiException
|
5
4
|
import asyncio
|
6
5
|
|
6
|
+
from lusid.configuration import Configuration
|
7
|
+
from lusid.exceptions import ApiException
|
8
|
+
|
7
9
|
|
8
10
|
class RetryingRestWrapper:
|
9
11
|
"""Wrapper for HTTP requests
|
10
12
|
Which retries on failure
|
11
13
|
And waits the amount of time specified in the Retry After header.
|
12
14
|
"""
|
13
|
-
def __init__(
|
15
|
+
def __init__(
|
16
|
+
self,
|
17
|
+
rest_object,
|
18
|
+
retries: int = Configuration.DEFAULT_RETRIES,
|
19
|
+
rate_limit_retries: int = Configuration.DEFAULT_RATE_LIMIT_RETRIES
|
20
|
+
):
|
14
21
|
if not isinstance(retries, int):
|
15
|
-
raise
|
22
|
+
raise TypeError(f"retries should be an int, found {type(retries)}")
|
23
|
+
if retries < 0:
|
24
|
+
raise ValueError(f"retries should be greater than or equal to zero but was '{retries}'")
|
25
|
+
if not isinstance(rate_limit_retries, int):
|
26
|
+
raise TypeError(f"rate_limit_retries should be an int, found {type(rate_limit_retries)}")
|
27
|
+
if rate_limit_retries < 0:
|
28
|
+
raise ValueError(f"rate_limit_retries should be greater than or equal to zero but was '{rate_limit_retries}'")
|
16
29
|
self.retries: int = retries
|
30
|
+
self.rate_limit_retries: int = rate_limit_retries
|
17
31
|
self.rest_object = rest_object
|
18
32
|
|
19
33
|
def request(
|
@@ -26,9 +40,12 @@ class RetryingRestWrapper:
|
|
26
40
|
post_params=None,
|
27
41
|
_preload_content=True,
|
28
42
|
_request_timeout=None,
|
43
|
+
opts=None,
|
29
44
|
):
|
30
|
-
|
31
|
-
|
45
|
+
retries_count = 0
|
46
|
+
rate_limit_retries_count = 0
|
47
|
+
|
48
|
+
while True:
|
32
49
|
try:
|
33
50
|
return self.rest_object.request(
|
34
51
|
method,
|
@@ -39,17 +56,26 @@ class RetryingRestWrapper:
|
|
39
56
|
post_params,
|
40
57
|
_preload_content,
|
41
58
|
_request_timeout,
|
59
|
+
opts,
|
42
60
|
)
|
43
61
|
except ApiException as ex:
|
44
|
-
|
45
|
-
retry_after = ex.headers.get("Retry-After")
|
46
62
|
|
47
|
-
|
48
|
-
|
49
|
-
|
63
|
+
if ex.status == 429 and ((opts != None and opts.rate_limit_retries != None) or self.rate_limit_retries != None):
|
64
|
+
# check for limit of rate limit retries
|
65
|
+
limit = opts.rate_limit_retries if (opts and opts.rate_limit_retries != None) else self.rate_limit_retries
|
66
|
+
if rate_limit_retries_count >= limit:
|
67
|
+
raise
|
68
|
+
rate_limit_retries_count += 1
|
69
|
+
else:
|
70
|
+
# check for limit of all other retries
|
71
|
+
if retries_count >= self.retries:
|
72
|
+
raise
|
73
|
+
retries_count += 1
|
74
|
+
|
75
|
+
retry_after = ex.headers.get("Retry-After")
|
50
76
|
|
51
77
|
# try after delay
|
52
|
-
|
78
|
+
if retry_after is not None:
|
53
79
|
if not isinstance(retry_after, float):
|
54
80
|
try:
|
55
81
|
retry_after = float(retry_after)
|
@@ -61,7 +87,6 @@ class RetryingRestWrapper:
|
|
61
87
|
# no retry header
|
62
88
|
else:
|
63
89
|
raise
|
64
|
-
tries += 1
|
65
90
|
|
66
91
|
def get_request(
|
67
92
|
self,
|
@@ -70,12 +95,14 @@ class RetryingRestWrapper:
|
|
70
95
|
query_params=None,
|
71
96
|
_preload_content=True,
|
72
97
|
_request_timeout=None,
|
98
|
+
opts=None,
|
73
99
|
):
|
74
100
|
return self.request("GET", url,
|
75
101
|
headers=headers,
|
76
102
|
_preload_content=_preload_content,
|
77
103
|
_request_timeout=_request_timeout,
|
78
|
-
query_params=query_params
|
104
|
+
query_params=query_params,
|
105
|
+
opts=opts)
|
79
106
|
|
80
107
|
def head_request(
|
81
108
|
self,
|
@@ -84,12 +111,14 @@ class RetryingRestWrapper:
|
|
84
111
|
query_params=None,
|
85
112
|
_preload_content=True,
|
86
113
|
_request_timeout=None,
|
114
|
+
opts=None,
|
87
115
|
):
|
88
116
|
return self.request("HEAD", url,
|
89
117
|
headers=headers,
|
90
118
|
_preload_content=_preload_content,
|
91
119
|
_request_timeout=_request_timeout,
|
92
|
-
query_params=query_params
|
120
|
+
query_params=query_params,
|
121
|
+
opts=opts)
|
93
122
|
|
94
123
|
def options_request(
|
95
124
|
self,
|
@@ -100,6 +129,7 @@ class RetryingRestWrapper:
|
|
100
129
|
body=None,
|
101
130
|
_preload_content=True,
|
102
131
|
_request_timeout=None,
|
132
|
+
opts=None,
|
103
133
|
):
|
104
134
|
return self.request("OPTIONS", url,
|
105
135
|
headers=headers,
|
@@ -107,7 +137,8 @@ class RetryingRestWrapper:
|
|
107
137
|
post_params=post_params,
|
108
138
|
_preload_content=_preload_content,
|
109
139
|
_request_timeout=_request_timeout,
|
110
|
-
body=body
|
140
|
+
body=body,
|
141
|
+
opts=opts)
|
111
142
|
|
112
143
|
def delete_request(
|
113
144
|
self,
|
@@ -117,13 +148,15 @@ class RetryingRestWrapper:
|
|
117
148
|
body=None,
|
118
149
|
_preload_content=True,
|
119
150
|
_request_timeout=None,
|
151
|
+
opts=None,
|
120
152
|
):
|
121
153
|
return self.request("DELETE", url,
|
122
154
|
headers=headers,
|
123
155
|
query_params=query_params,
|
124
156
|
_preload_content=_preload_content,
|
125
157
|
_request_timeout=_request_timeout,
|
126
|
-
body=body
|
158
|
+
body=body,
|
159
|
+
opts=opts)
|
127
160
|
|
128
161
|
def post_request(
|
129
162
|
self,
|
@@ -134,6 +167,7 @@ class RetryingRestWrapper:
|
|
134
167
|
body=None,
|
135
168
|
_preload_content=True,
|
136
169
|
_request_timeout=None,
|
170
|
+
opts=None,
|
137
171
|
):
|
138
172
|
return self.request("POST", url,
|
139
173
|
headers=headers,
|
@@ -141,7 +175,8 @@ class RetryingRestWrapper:
|
|
141
175
|
post_params=post_params,
|
142
176
|
_preload_content=_preload_content,
|
143
177
|
_request_timeout=_request_timeout,
|
144
|
-
body=body
|
178
|
+
body=body,
|
179
|
+
opts=opts)
|
145
180
|
|
146
181
|
def put_request(
|
147
182
|
self,
|
@@ -152,6 +187,7 @@ class RetryingRestWrapper:
|
|
152
187
|
body=None,
|
153
188
|
_preload_content=True,
|
154
189
|
_request_timeout=None,
|
190
|
+
opts=None,
|
155
191
|
):
|
156
192
|
return self.request("PUT", url,
|
157
193
|
headers=headers,
|
@@ -159,7 +195,8 @@ class RetryingRestWrapper:
|
|
159
195
|
post_params=post_params,
|
160
196
|
_preload_content=_preload_content,
|
161
197
|
_request_timeout=_request_timeout,
|
162
|
-
body=body
|
198
|
+
body=body,
|
199
|
+
opts=opts)
|
163
200
|
|
164
201
|
def patch_request(
|
165
202
|
self,
|
@@ -170,6 +207,7 @@ class RetryingRestWrapper:
|
|
170
207
|
body=None,
|
171
208
|
_preload_content=True,
|
172
209
|
_request_timeout=None,
|
210
|
+
opts=None,
|
173
211
|
):
|
174
212
|
return self.request("PATCH", url,
|
175
213
|
headers=headers,
|
@@ -177,7 +215,8 @@ class RetryingRestWrapper:
|
|
177
215
|
post_params=post_params,
|
178
216
|
_preload_content=_preload_content,
|
179
217
|
_request_timeout=_request_timeout,
|
180
|
-
body=body
|
218
|
+
body=body,
|
219
|
+
opts=opts)
|
181
220
|
|
182
221
|
|
183
222
|
class RetryingRestWrapperAsync:
|
@@ -185,10 +224,17 @@ class RetryingRestWrapperAsync:
|
|
185
224
|
Which retries on failure
|
186
225
|
And waits the amount of time specified in the Retry After header.
|
187
226
|
"""
|
188
|
-
def __init__(self, rest_object, retries: int = 3):
|
227
|
+
def __init__(self, rest_object, retries: int = 3, rate_limit_retries: Optional[int] = Configuration.DEFAULT_RATE_LIMIT_RETRIES):
|
189
228
|
if not isinstance(retries, int):
|
190
|
-
raise
|
229
|
+
raise TypeError(f"retries should be an int, found {type(retries)}")
|
230
|
+
if retries < 0:
|
231
|
+
raise ValueError(f"retries should be greater than or equal to zero but was '{retries}'")
|
232
|
+
if not isinstance(rate_limit_retries, int):
|
233
|
+
raise TypeError(f"rate_limit_retries should be an int, found {type(rate_limit_retries)}")
|
234
|
+
if rate_limit_retries < 0:
|
235
|
+
raise ValueError(f"rate_limit_retries should be greater than or equal to zero but was '{rate_limit_retries}'")
|
191
236
|
self.retries: int = retries
|
237
|
+
self.rate_limit_retries: Optional[int] = rate_limit_retries
|
192
238
|
self.rest_object = rest_object
|
193
239
|
|
194
240
|
async def close(self):
|
@@ -204,9 +250,12 @@ class RetryingRestWrapperAsync:
|
|
204
250
|
post_params=None,
|
205
251
|
_preload_content=True,
|
206
252
|
_request_timeout=None,
|
253
|
+
opts=None,
|
207
254
|
):
|
208
|
-
|
209
|
-
|
255
|
+
retries_count = 0
|
256
|
+
rate_limit_retries_count = 0
|
257
|
+
|
258
|
+
while True:
|
210
259
|
try:
|
211
260
|
return await self.rest_object.request(
|
212
261
|
method,
|
@@ -217,16 +266,26 @@ class RetryingRestWrapperAsync:
|
|
217
266
|
post_params,
|
218
267
|
_preload_content,
|
219
268
|
_request_timeout,
|
269
|
+
opts
|
220
270
|
)
|
221
271
|
except ApiException as ex:
|
222
|
-
retry_after = ex.headers.get("Retry-After")
|
223
272
|
|
224
|
-
|
225
|
-
|
226
|
-
|
273
|
+
if ex.status == 429 and ((opts and opts.rate_limit_retries != None) or self.rate_limit_retries != None):
|
274
|
+
# check for limit of rate limit retries
|
275
|
+
limit = opts.rate_limit_retries if (opts and opts.rate_limit_retries != None) else self.rate_limit_retries
|
276
|
+
if rate_limit_retries_count >= limit:
|
277
|
+
raise
|
278
|
+
rate_limit_retries_count += 1
|
279
|
+
else:
|
280
|
+
# check for limit of all other retries
|
281
|
+
if retries_count >= self.retries:
|
282
|
+
raise
|
283
|
+
retries_count += 1
|
284
|
+
|
285
|
+
retry_after = ex.headers.get("Retry-After")
|
227
286
|
|
228
287
|
# try after delay
|
229
|
-
|
288
|
+
if retry_after is not None:
|
230
289
|
if not isinstance(retry_after, float):
|
231
290
|
try:
|
232
291
|
retry_after = float(retry_after)
|
@@ -238,7 +297,6 @@ class RetryingRestWrapperAsync:
|
|
238
297
|
# no retry header
|
239
298
|
else:
|
240
299
|
raise
|
241
|
-
tries += 1
|
242
300
|
|
243
301
|
async def get_request(
|
244
302
|
self,
|
@@ -247,12 +305,14 @@ class RetryingRestWrapperAsync:
|
|
247
305
|
query_params=None,
|
248
306
|
_preload_content=True,
|
249
307
|
_request_timeout=None,
|
308
|
+
opts=None,
|
250
309
|
):
|
251
310
|
return (await self.request("GET", url,
|
252
311
|
headers=headers,
|
253
312
|
_preload_content=_preload_content,
|
254
313
|
_request_timeout=_request_timeout,
|
255
|
-
query_params=query_params
|
314
|
+
query_params=query_params,
|
315
|
+
opts=opts))
|
256
316
|
|
257
317
|
async def head_request(
|
258
318
|
self,
|
@@ -261,12 +321,14 @@ class RetryingRestWrapperAsync:
|
|
261
321
|
query_params=None,
|
262
322
|
_preload_content=True,
|
263
323
|
_request_timeout=None,
|
324
|
+
opts=None,
|
264
325
|
):
|
265
326
|
return (await self.request("HEAD", url,
|
266
327
|
headers=headers,
|
267
328
|
_preload_content=_preload_content,
|
268
329
|
_request_timeout=_request_timeout,
|
269
|
-
query_params=query_params
|
330
|
+
query_params=query_params,
|
331
|
+
opts=opts))
|
270
332
|
|
271
333
|
async def options_request(
|
272
334
|
self,
|
@@ -277,6 +339,7 @@ class RetryingRestWrapperAsync:
|
|
277
339
|
body=None,
|
278
340
|
_preload_content=True,
|
279
341
|
_request_timeout=None,
|
342
|
+
opts=None,
|
280
343
|
):
|
281
344
|
return (await self.request("OPTIONS", url,
|
282
345
|
headers=headers,
|
@@ -284,7 +347,8 @@ class RetryingRestWrapperAsync:
|
|
284
347
|
post_params=post_params,
|
285
348
|
_preload_content=_preload_content,
|
286
349
|
_request_timeout=_request_timeout,
|
287
|
-
body=body
|
350
|
+
body=body,
|
351
|
+
opts=opts))
|
288
352
|
|
289
353
|
async def delete_request(
|
290
354
|
self,
|
@@ -294,13 +358,15 @@ class RetryingRestWrapperAsync:
|
|
294
358
|
body=None,
|
295
359
|
_preload_content=True,
|
296
360
|
_request_timeout=None,
|
361
|
+
opts=None,
|
297
362
|
):
|
298
363
|
return (await self.request("DELETE", url,
|
299
364
|
headers=headers,
|
300
365
|
query_params=query_params,
|
301
366
|
_preload_content=_preload_content,
|
302
367
|
_request_timeout=_request_timeout,
|
303
|
-
body=body
|
368
|
+
body=body,
|
369
|
+
opts=opts))
|
304
370
|
|
305
371
|
async def post_request(
|
306
372
|
self,
|
@@ -311,6 +377,7 @@ class RetryingRestWrapperAsync:
|
|
311
377
|
body=None,
|
312
378
|
_preload_content=True,
|
313
379
|
_request_timeout=None,
|
380
|
+
opts=None,
|
314
381
|
):
|
315
382
|
return (await self.request("POST", url,
|
316
383
|
headers=headers,
|
@@ -318,7 +385,8 @@ class RetryingRestWrapperAsync:
|
|
318
385
|
post_params=post_params,
|
319
386
|
_preload_content=_preload_content,
|
320
387
|
_request_timeout=_request_timeout,
|
321
|
-
body=body
|
388
|
+
body=body,
|
389
|
+
opts=opts))
|
322
390
|
|
323
391
|
async def put_request(
|
324
392
|
self,
|
@@ -329,6 +397,7 @@ class RetryingRestWrapperAsync:
|
|
329
397
|
body=None,
|
330
398
|
_preload_content=True,
|
331
399
|
_request_timeout=None,
|
400
|
+
opts=None,
|
332
401
|
):
|
333
402
|
return (await self.request("PUT", url,
|
334
403
|
headers=headers,
|
@@ -336,7 +405,8 @@ class RetryingRestWrapperAsync:
|
|
336
405
|
post_params=post_params,
|
337
406
|
_preload_content=_preload_content,
|
338
407
|
_request_timeout=_request_timeout,
|
339
|
-
body=body
|
408
|
+
body=body,
|
409
|
+
opts=opts))
|
340
410
|
|
341
411
|
async def patch_request(
|
342
412
|
self,
|
@@ -347,6 +417,7 @@ class RetryingRestWrapperAsync:
|
|
347
417
|
body=None,
|
348
418
|
_preload_content=True,
|
349
419
|
_request_timeout=None,
|
420
|
+
opts=None,
|
350
421
|
):
|
351
422
|
return (await self.request("PATCH", url,
|
352
423
|
headers=headers,
|
@@ -354,4 +425,5 @@ class RetryingRestWrapperAsync:
|
|
354
425
|
post_params=post_params,
|
355
426
|
_preload_content=_preload_content,
|
356
427
|
_request_timeout=_request_timeout,
|
357
|
-
body=body
|
428
|
+
body=body,
|
429
|
+
opts=opts))
|