webull-openapi-python-sdk 1.0.0__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.
- samples/__init__.py +1 -0
- samples/data/__init__.py +1 -0
- samples/data/data_client.py +57 -0
- samples/data/data_streaming_client.py +86 -0
- samples/data/data_streaming_client_async.py +101 -0
- samples/trade/__init__.py +0 -0
- samples/trade/trade_client.py +163 -0
- samples/trade/trade_client_v2.py +181 -0
- samples/trade/trade_event_client.py +47 -0
- webull/__init__.py +1 -0
- webull/core/__init__.py +12 -0
- webull/core/auth/__init__.py +0 -0
- webull/core/auth/algorithm/__init__.py +0 -0
- webull/core/auth/algorithm/sha_hmac1.py +65 -0
- webull/core/auth/algorithm/sha_hmac256.py +75 -0
- webull/core/auth/composer/__init__.py +0 -0
- webull/core/auth/composer/default_signature_composer.py +125 -0
- webull/core/auth/credentials.py +46 -0
- webull/core/auth/signers/__init__.py +0 -0
- webull/core/auth/signers/app_key_signer.py +72 -0
- webull/core/auth/signers/signer.py +48 -0
- webull/core/auth/signers/signer_factory.py +58 -0
- webull/core/cache/__init__.py +225 -0
- webull/core/client.py +410 -0
- webull/core/common/__init__.py +0 -0
- webull/core/common/api_type.py +19 -0
- webull/core/common/easy_enum.py +35 -0
- webull/core/common/region.py +7 -0
- webull/core/compat.py +85 -0
- webull/core/context/__init__.py +0 -0
- webull/core/context/request_context_holder.py +33 -0
- webull/core/data/endpoints.json +22 -0
- webull/core/data/retry_config.json +15 -0
- webull/core/endpoint/__init__.py +8 -0
- webull/core/endpoint/chained_endpoint_resolver.py +57 -0
- webull/core/endpoint/default_endpoint_resolver.py +60 -0
- webull/core/endpoint/local_config_regional_endpoint_resolver.py +77 -0
- webull/core/endpoint/resolver_endpoint_request.py +46 -0
- webull/core/endpoint/user_customized_endpoint_resolver.py +55 -0
- webull/core/exception/__init__.py +0 -0
- webull/core/exception/error_code.py +23 -0
- webull/core/exception/error_msg.py +21 -0
- webull/core/exception/exceptions.py +53 -0
- webull/core/headers.py +57 -0
- webull/core/http/__init__.py +0 -0
- webull/core/http/initializer/__init__.py +0 -0
- webull/core/http/initializer/client_initializer.py +79 -0
- webull/core/http/initializer/token/__init__.py +0 -0
- webull/core/http/initializer/token/bean/__init__.py +0 -0
- webull/core/http/initializer/token/bean/access_token.py +40 -0
- webull/core/http/initializer/token/bean/check_token_request.py +44 -0
- webull/core/http/initializer/token/bean/create_token_request.py +45 -0
- webull/core/http/initializer/token/bean/refresh_token_request.py +44 -0
- webull/core/http/initializer/token/token_manager.py +208 -0
- webull/core/http/initializer/token/token_operation.py +72 -0
- webull/core/http/method_type.py +43 -0
- webull/core/http/protocol_type.py +43 -0
- webull/core/http/request.py +121 -0
- webull/core/http/response.py +166 -0
- webull/core/request.py +278 -0
- webull/core/retry/__init__.py +0 -0
- webull/core/retry/backoff_strategy.py +102 -0
- webull/core/retry/retry_condition.py +214 -0
- webull/core/retry/retry_policy.py +63 -0
- webull/core/retry/retry_policy_context.py +51 -0
- webull/core/utils/__init__.py +0 -0
- webull/core/utils/common.py +62 -0
- webull/core/utils/data.py +25 -0
- webull/core/utils/desensitize.py +33 -0
- webull/core/utils/validation.py +49 -0
- webull/core/vendored/__init__.py +0 -0
- webull/core/vendored/requests/__init__.py +94 -0
- webull/core/vendored/requests/__version__.py +28 -0
- webull/core/vendored/requests/_internal_utils.py +56 -0
- webull/core/vendored/requests/adapters.py +539 -0
- webull/core/vendored/requests/api.py +166 -0
- webull/core/vendored/requests/auth.py +307 -0
- webull/core/vendored/requests/certs.py +34 -0
- webull/core/vendored/requests/compat.py +85 -0
- webull/core/vendored/requests/cookies.py +555 -0
- webull/core/vendored/requests/exceptions.py +136 -0
- webull/core/vendored/requests/help.py +134 -0
- webull/core/vendored/requests/hooks.py +48 -0
- webull/core/vendored/requests/models.py +960 -0
- webull/core/vendored/requests/packages/__init__.py +17 -0
- webull/core/vendored/requests/packages/certifi/__init__.py +17 -0
- webull/core/vendored/requests/packages/certifi/__main__.py +16 -0
- webull/core/vendored/requests/packages/certifi/cacert.pem +4433 -0
- webull/core/vendored/requests/packages/certifi/core.py +51 -0
- webull/core/vendored/requests/packages/chardet/__init__.py +53 -0
- webull/core/vendored/requests/packages/chardet/big5freq.py +400 -0
- webull/core/vendored/requests/packages/chardet/big5prober.py +61 -0
- webull/core/vendored/requests/packages/chardet/chardistribution.py +247 -0
- webull/core/vendored/requests/packages/chardet/charsetgroupprober.py +120 -0
- webull/core/vendored/requests/packages/chardet/charsetprober.py +159 -0
- webull/core/vendored/requests/packages/chardet/cli/__init__.py +1 -0
- webull/core/vendored/requests/packages/chardet/cli/chardetect.py +99 -0
- webull/core/vendored/requests/packages/chardet/codingstatemachine.py +102 -0
- webull/core/vendored/requests/packages/chardet/compat.py +48 -0
- webull/core/vendored/requests/packages/chardet/cp949prober.py +63 -0
- webull/core/vendored/requests/packages/chardet/enums.py +90 -0
- webull/core/vendored/requests/packages/chardet/escprober.py +115 -0
- webull/core/vendored/requests/packages/chardet/escsm.py +260 -0
- webull/core/vendored/requests/packages/chardet/eucjpprober.py +106 -0
- webull/core/vendored/requests/packages/chardet/euckrfreq.py +209 -0
- webull/core/vendored/requests/packages/chardet/euckrprober.py +61 -0
- webull/core/vendored/requests/packages/chardet/euctwfreq.py +401 -0
- webull/core/vendored/requests/packages/chardet/euctwprober.py +60 -0
- webull/core/vendored/requests/packages/chardet/gb2312freq.py +297 -0
- webull/core/vendored/requests/packages/chardet/gb2312prober.py +60 -0
- webull/core/vendored/requests/packages/chardet/hebrewprober.py +306 -0
- webull/core/vendored/requests/packages/chardet/jisfreq.py +339 -0
- webull/core/vendored/requests/packages/chardet/jpcntx.py +247 -0
- webull/core/vendored/requests/packages/chardet/langbulgarianmodel.py +242 -0
- webull/core/vendored/requests/packages/chardet/langcyrillicmodel.py +347 -0
- webull/core/vendored/requests/packages/chardet/langgreekmodel.py +239 -0
- webull/core/vendored/requests/packages/chardet/langhebrewmodel.py +214 -0
- webull/core/vendored/requests/packages/chardet/langhungarianmodel.py +239 -0
- webull/core/vendored/requests/packages/chardet/langthaimodel.py +213 -0
- webull/core/vendored/requests/packages/chardet/langturkishmodel.py +207 -0
- webull/core/vendored/requests/packages/chardet/latin1prober.py +159 -0
- webull/core/vendored/requests/packages/chardet/mbcharsetprober.py +105 -0
- webull/core/vendored/requests/packages/chardet/mbcsgroupprober.py +68 -0
- webull/core/vendored/requests/packages/chardet/mbcssm.py +586 -0
- webull/core/vendored/requests/packages/chardet/sbcharsetprober.py +146 -0
- webull/core/vendored/requests/packages/chardet/sbcsgroupprober.py +87 -0
- webull/core/vendored/requests/packages/chardet/sjisprober.py +106 -0
- webull/core/vendored/requests/packages/chardet/universaldetector.py +300 -0
- webull/core/vendored/requests/packages/chardet/utf8prober.py +96 -0
- webull/core/vendored/requests/packages/chardet/version.py +23 -0
- webull/core/vendored/requests/packages/urllib3/__init__.py +114 -0
- webull/core/vendored/requests/packages/urllib3/_collections.py +346 -0
- webull/core/vendored/requests/packages/urllib3/connection.py +405 -0
- webull/core/vendored/requests/packages/urllib3/connectionpool.py +910 -0
- webull/core/vendored/requests/packages/urllib3/contrib/__init__.py +0 -0
- webull/core/vendored/requests/packages/urllib3/contrib/_appengine_environ.py +44 -0
- webull/core/vendored/requests/packages/urllib3/contrib/_securetransport/__init__.py +0 -0
- webull/core/vendored/requests/packages/urllib3/contrib/_securetransport/bindings.py +607 -0
- webull/core/vendored/requests/packages/urllib3/contrib/_securetransport/low_level.py +360 -0
- webull/core/vendored/requests/packages/urllib3/contrib/appengine.py +303 -0
- webull/core/vendored/requests/packages/urllib3/contrib/ntlmpool.py +125 -0
- webull/core/vendored/requests/packages/urllib3/contrib/pyopenssl.py +484 -0
- webull/core/vendored/requests/packages/urllib3/contrib/securetransport.py +818 -0
- webull/core/vendored/requests/packages/urllib3/contrib/socks.py +206 -0
- webull/core/vendored/requests/packages/urllib3/exceptions.py +260 -0
- webull/core/vendored/requests/packages/urllib3/fields.py +192 -0
- webull/core/vendored/requests/packages/urllib3/filepost.py +112 -0
- webull/core/vendored/requests/packages/urllib3/packages/__init__.py +19 -0
- webull/core/vendored/requests/packages/urllib3/packages/backports/__init__.py +0 -0
- webull/core/vendored/requests/packages/urllib3/packages/backports/makefile.py +67 -0
- webull/core/vendored/requests/packages/urllib3/packages/ordered_dict.py +273 -0
- webull/core/vendored/requests/packages/urllib3/packages/six.py +882 -0
- webull/core/vendored/requests/packages/urllib3/packages/socks.py +887 -0
- webull/core/vendored/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py +19 -0
- webull/core/vendored/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.py +170 -0
- webull/core/vendored/requests/packages/urllib3/poolmanager.py +467 -0
- webull/core/vendored/requests/packages/urllib3/request.py +164 -0
- webull/core/vendored/requests/packages/urllib3/response.py +721 -0
- webull/core/vendored/requests/packages/urllib3/util/__init__.py +68 -0
- webull/core/vendored/requests/packages/urllib3/util/connection.py +148 -0
- webull/core/vendored/requests/packages/urllib3/util/queue.py +35 -0
- webull/core/vendored/requests/packages/urllib3/util/request.py +132 -0
- webull/core/vendored/requests/packages/urllib3/util/response.py +101 -0
- webull/core/vendored/requests/packages/urllib3/util/retry.py +426 -0
- webull/core/vendored/requests/packages/urllib3/util/selectors.py +601 -0
- webull/core/vendored/requests/packages/urllib3/util/ssl_.py +396 -0
- webull/core/vendored/requests/packages/urllib3/util/timeout.py +256 -0
- webull/core/vendored/requests/packages/urllib3/util/url.py +252 -0
- webull/core/vendored/requests/packages/urllib3/util/wait.py +164 -0
- webull/core/vendored/requests/packages.py +28 -0
- webull/core/vendored/requests/sessions.py +750 -0
- webull/core/vendored/requests/status_codes.py +105 -0
- webull/core/vendored/requests/structures.py +119 -0
- webull/core/vendored/requests/utils.py +916 -0
- webull/core/vendored/six.py +905 -0
- webull/data/__init__.py +3 -0
- webull/data/common/__init__.py +0 -0
- webull/data/common/category.py +26 -0
- webull/data/common/connect_ack.py +29 -0
- webull/data/common/direction.py +25 -0
- webull/data/common/exchange_code.py +33 -0
- webull/data/common/exercise_style.py +22 -0
- webull/data/common/expiration_cycle.py +26 -0
- webull/data/common/instrument_status.py +23 -0
- webull/data/common/option_type.py +20 -0
- webull/data/common/subscribe_type.py +22 -0
- webull/data/common/timespan.py +29 -0
- webull/data/data_client.py +35 -0
- webull/data/data_streaming_client.py +89 -0
- webull/data/internal/__init__.py +0 -0
- webull/data/internal/default_retry_policy.py +84 -0
- webull/data/internal/exceptions.py +60 -0
- webull/data/internal/quotes_client.py +314 -0
- webull/data/internal/quotes_decoder.py +40 -0
- webull/data/internal/quotes_payload_decoder.py +35 -0
- webull/data/internal/quotes_topic.py +36 -0
- webull/data/quotes/__init__.py +0 -0
- webull/data/quotes/instrument.py +33 -0
- webull/data/quotes/market_data.py +187 -0
- webull/data/quotes/market_streaming_data.py +66 -0
- webull/data/quotes/subscribe/__init__.py +0 -0
- webull/data/quotes/subscribe/ask_bid_result.py +49 -0
- webull/data/quotes/subscribe/basic_result.py +45 -0
- webull/data/quotes/subscribe/broker_result.py +33 -0
- webull/data/quotes/subscribe/message_pb2.py +37 -0
- webull/data/quotes/subscribe/order_result.py +30 -0
- webull/data/quotes/subscribe/payload_type.py +19 -0
- webull/data/quotes/subscribe/quote_decoder.py +28 -0
- webull/data/quotes/subscribe/quote_result.py +47 -0
- webull/data/quotes/subscribe/snapshot_decoder.py +30 -0
- webull/data/quotes/subscribe/snapshot_result.py +69 -0
- webull/data/quotes/subscribe/tick_decoder.py +29 -0
- webull/data/quotes/subscribe/tick_result.py +47 -0
- webull/data/request/__init__.py +0 -0
- webull/data/request/get_batch_historical_bars_request.py +43 -0
- webull/data/request/get_corp_action_request.py +47 -0
- webull/data/request/get_eod_bars_request.py +32 -0
- webull/data/request/get_historical_bars_request.py +43 -0
- webull/data/request/get_instruments_request.py +30 -0
- webull/data/request/get_quotes_request.py +35 -0
- webull/data/request/get_snapshot_request.py +38 -0
- webull/data/request/get_tick_request.py +37 -0
- webull/data/request/subscribe_request.py +43 -0
- webull/data/request/unsubscribe_request.py +42 -0
- webull/trade/__init__.py +2 -0
- webull/trade/common/__init__.py +0 -0
- webull/trade/common/account_type.py +22 -0
- webull/trade/common/category.py +29 -0
- webull/trade/common/combo_ticker_type.py +23 -0
- webull/trade/common/combo_type.py +31 -0
- webull/trade/common/currency.py +24 -0
- webull/trade/common/forbid_reason.py +27 -0
- webull/trade/common/instrument_type.py +27 -0
- webull/trade/common/markets.py +27 -0
- webull/trade/common/order_entrust_type.py +21 -0
- webull/trade/common/order_side.py +23 -0
- webull/trade/common/order_status.py +25 -0
- webull/trade/common/order_tif.py +24 -0
- webull/trade/common/order_type.py +30 -0
- webull/trade/common/trade_policy.py +22 -0
- webull/trade/common/trading_date_type.py +24 -0
- webull/trade/common/trailing_type.py +23 -0
- webull/trade/events/__init__.py +0 -0
- webull/trade/events/default_retry_policy.py +64 -0
- webull/trade/events/events_pb2.py +43 -0
- webull/trade/events/events_pb2_grpc.py +66 -0
- webull/trade/events/signature_composer.py +61 -0
- webull/trade/events/types.py +21 -0
- webull/trade/request/__init__.py +0 -0
- webull/trade/request/cancel_order_request.py +28 -0
- webull/trade/request/get_account_balance_request.py +28 -0
- webull/trade/request/get_account_positions_request.py +30 -0
- webull/trade/request/get_account_profile_request.py +26 -0
- webull/trade/request/get_app_subscriptions.py +28 -0
- webull/trade/request/get_open_orders_request.py +30 -0
- webull/trade/request/get_order_detail_request.py +27 -0
- webull/trade/request/get_today_orders_request.py +31 -0
- webull/trade/request/get_trade_calendar_request.py +30 -0
- webull/trade/request/get_trade_instrument_detail_request.py +24 -0
- webull/trade/request/get_trade_security_detail_request.py +42 -0
- webull/trade/request/get_tradeable_instruments_request.py +27 -0
- webull/trade/request/palce_order_request.py +91 -0
- webull/trade/request/place_order_request_v2.py +58 -0
- webull/trade/request/replace_order_request.py +73 -0
- webull/trade/request/replace_order_request_v2.py +38 -0
- webull/trade/request/v2/__init__.py +0 -0
- webull/trade/request/v2/cancel_option_request.py +28 -0
- webull/trade/request/v2/cancel_order_request.py +28 -0
- webull/trade/request/v2/get_account_balance_request.py +28 -0
- webull/trade/request/v2/get_account_list.py +23 -0
- webull/trade/request/v2/get_account_positions_request.py +24 -0
- webull/trade/request/v2/get_order_detail_request.py +26 -0
- webull/trade/request/v2/get_order_history_request.py +35 -0
- webull/trade/request/v2/palce_order_request.py +87 -0
- webull/trade/request/v2/place_option_request.py +64 -0
- webull/trade/request/v2/preview_option_request.py +28 -0
- webull/trade/request/v2/preview_order_request.py +59 -0
- webull/trade/request/v2/replace_option_request.py +28 -0
- webull/trade/request/v2/replace_order_request.py +57 -0
- webull/trade/trade/__init__.py +0 -0
- webull/trade/trade/account_info.py +83 -0
- webull/trade/trade/order_operation.py +246 -0
- webull/trade/trade/trade_calendar.py +37 -0
- webull/trade/trade/trade_instrument.py +72 -0
- webull/trade/trade/v2/__init__.py +0 -0
- webull/trade/trade/v2/account_info_v2.py +55 -0
- webull/trade/trade/v2/order_operation_v2.py +206 -0
- webull/trade/trade_client.py +43 -0
- webull/trade/trade_events_client.py +233 -0
- webull_openapi_python_sdk-1.0.0.dist-info/METADATA +28 -0
- webull_openapi_python_sdk-1.0.0.dist-info/RECORD +295 -0
- webull_openapi_python_sdk-1.0.0.dist-info/WHEEL +5 -0
- webull_openapi_python_sdk-1.0.0.dist-info/licenses/LICENSE +202 -0
- webull_openapi_python_sdk-1.0.0.dist-info/licenses/NOTICE +56 -0
- webull_openapi_python_sdk-1.0.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Copyright 2022 Webull
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
16
|
+
# or more contributor license agreements. See the NOTICE file
|
|
17
|
+
# distributed with this work for additional information
|
|
18
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
19
|
+
# to you under the Apache License, Version 2.0 (the
|
|
20
|
+
# "License"); you may not use this file except in compliance
|
|
21
|
+
# with the License. You may obtain a copy of the License at
|
|
22
|
+
#
|
|
23
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
24
|
+
#
|
|
25
|
+
#
|
|
26
|
+
#
|
|
27
|
+
# Unless required by applicable law or agreed to in writing,
|
|
28
|
+
# software distributed under the License is distributed on an
|
|
29
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
30
|
+
# KIND, either express or implied. See the License for the
|
|
31
|
+
# specific language governing permissions and limitations
|
|
32
|
+
# under the License.
|
|
33
|
+
|
|
34
|
+
# coding=utf-8
|
|
35
|
+
|
|
36
|
+
"""
|
|
37
|
+
This file borrowed some of its methods from a modified fork of the
|
|
38
|
+
https://github.com/aliyun/aliyun-openapi-python-sdk/blob/master/aliyun-python-sdk-core/aliyunsdkcore/retry/retry_condition.py
|
|
39
|
+
which was part of Alibaba Group.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
import logging
|
|
43
|
+
import jmespath
|
|
44
|
+
from webull.core.utils import data
|
|
45
|
+
from webull.core.utils import validation
|
|
46
|
+
from webull.core.exception.exceptions import ClientException, ServerException
|
|
47
|
+
from webull.core.exception import error_code
|
|
48
|
+
from webull.core.common.api_type import DEFAULT as HTTP_API_TYPE
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
logger = logging.getLogger(__name__)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _find_data_in_retry_config(key_name, request, retry_config, api_type=HTTP_API_TYPE):
|
|
55
|
+
path = '"{0}"."{1}"'.format(api_type, key_name)
|
|
56
|
+
return jmespath.search(path, retry_config)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class RetryCondition(object):
|
|
60
|
+
BLANK_STATUS = 0
|
|
61
|
+
NO_RETRY = 1
|
|
62
|
+
RETRY = 2
|
|
63
|
+
SHOULD_RETRY_WITH_THROTTLING_BACKOFF = 4
|
|
64
|
+
|
|
65
|
+
def should_retry(self, retry_policy_context):
|
|
66
|
+
"""Decide whether the previous request should be retried."""
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class NoRetryCondition(RetryCondition):
|
|
71
|
+
def should_retry(self, retry_policy_context):
|
|
72
|
+
return RetryCondition.NO_RETRY
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class MaxRetryTimesCondition(RetryCondition):
|
|
76
|
+
|
|
77
|
+
def __init__(self, max_retry_times):
|
|
78
|
+
validation.assert_integer_positive(max_retry_times, "max_retry_times")
|
|
79
|
+
self.max_retry_times = max_retry_times
|
|
80
|
+
|
|
81
|
+
def should_retry(self, retry_policy_context):
|
|
82
|
+
|
|
83
|
+
if retry_policy_context.retries_attempted < self.max_retry_times:
|
|
84
|
+
return RetryCondition.RETRY
|
|
85
|
+
else:
|
|
86
|
+
logger.debug("Reached the maximum number of retry. Attempts:%d",
|
|
87
|
+
retry_policy_context.retries_attempted)
|
|
88
|
+
return RetryCondition.NO_RETRY
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class RetryOnExceptionCondition(RetryCondition):
|
|
92
|
+
def __init__(self, retry_config):
|
|
93
|
+
self.retry_config = retry_config
|
|
94
|
+
|
|
95
|
+
def should_retry(self, retry_policy_context):
|
|
96
|
+
request = retry_policy_context.original_request
|
|
97
|
+
exception = retry_policy_context.exception
|
|
98
|
+
|
|
99
|
+
if isinstance(exception, ClientException) and exception.get_error_code() == error_code.SDK_HTTP_ERROR:
|
|
100
|
+
logger.debug("Retryable ClientException:%s", exception)
|
|
101
|
+
return RetryCondition.RETRY
|
|
102
|
+
|
|
103
|
+
if isinstance(exception, ServerException):
|
|
104
|
+
_error_code = exception.get_error_code()
|
|
105
|
+
errors = _find_data_in_retry_config(
|
|
106
|
+
"RetryableNormalErrors", request, self.retry_config)
|
|
107
|
+
if isinstance(errors, list) and _error_code in errors:
|
|
108
|
+
logger.debug("Retryable ServerException:%s", exception)
|
|
109
|
+
return RetryCondition.RETRY
|
|
110
|
+
errors = _find_data_in_retry_config(
|
|
111
|
+
"RetryableThrottlingErrors", request, self.retry_config)
|
|
112
|
+
if isinstance(errors, list) and _error_code in errors:
|
|
113
|
+
logger.debug("Retryable ThrottlingError:%s", exception)
|
|
114
|
+
return RetryCondition.RETRY | RetryCondition.SHOULD_RETRY_WITH_THROTTLING_BACKOFF
|
|
115
|
+
|
|
116
|
+
return RetryCondition.NO_RETRY
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class RetryOnMethodTypeCondition(RetryCondition):
|
|
120
|
+
def __init__(self, retry_config):
|
|
121
|
+
self.retry_config = retry_config
|
|
122
|
+
|
|
123
|
+
def should_retry(self, retry_policy_context):
|
|
124
|
+
request = retry_policy_context.original_request
|
|
125
|
+
exception = retry_policy_context.exception
|
|
126
|
+
|
|
127
|
+
if isinstance(exception, (ClientException, ServerException)):
|
|
128
|
+
method = request.get_method()
|
|
129
|
+
methods = _find_data_in_retry_config(
|
|
130
|
+
"RetryableMethods", request, self.retry_config)
|
|
131
|
+
if isinstance(methods, list) and method in methods:
|
|
132
|
+
logger.debug("Retryable MethodType:%s", method)
|
|
133
|
+
return RetryCondition.RETRY
|
|
134
|
+
|
|
135
|
+
return RetryCondition.NO_RETRY
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class RetryOnHttpStatusCondition(RetryCondition):
|
|
139
|
+
|
|
140
|
+
DEFAULT_RETRYABLE_HTTP_STATUS_LIST = [
|
|
141
|
+
500, 502, 503, 504
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
def __init__(self, retryable_http_status_list=None):
|
|
145
|
+
if retryable_http_status_list:
|
|
146
|
+
self.retryable_http_status_list = retryable_http_status_list
|
|
147
|
+
else:
|
|
148
|
+
self.retryable_http_status_list = self.DEFAULT_RETRYABLE_HTTP_STATUS_LIST
|
|
149
|
+
|
|
150
|
+
def should_retry(self, retry_policy_context):
|
|
151
|
+
if retry_policy_context.http_status_code in self.retryable_http_status_list:
|
|
152
|
+
logger.debug(
|
|
153
|
+
"Retryable HTTP error occurred. HTTP status code: %s",
|
|
154
|
+
retry_policy_context.http_status_code)
|
|
155
|
+
return RetryCondition.RETRY
|
|
156
|
+
else:
|
|
157
|
+
return RetryCondition.NO_RETRY
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class MergeRetryCondition(RetryCondition):
|
|
161
|
+
def __init__(self, conditions):
|
|
162
|
+
self.conditions = conditions
|
|
163
|
+
|
|
164
|
+
def should_retry(self, retry_policy_context):
|
|
165
|
+
retryable = RetryCondition.BLANK_STATUS
|
|
166
|
+
for condition in self.conditions:
|
|
167
|
+
retryable |= condition.should_retry(retry_policy_context)
|
|
168
|
+
return retryable
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class MergeAndRetryCondition(RetryCondition):
|
|
172
|
+
def __init__(self, conditions):
|
|
173
|
+
self.conditions = conditions
|
|
174
|
+
|
|
175
|
+
def should_retry(self, retry_policy_context):
|
|
176
|
+
retryable = RetryCondition.BLANK_STATUS
|
|
177
|
+
no_retry = RetryCondition.NO_RETRY
|
|
178
|
+
retry_mask = RetryCondition.RETRY | RetryCondition.SHOULD_RETRY_WITH_THROTTLING_BACKOFF
|
|
179
|
+
for condition in self.conditions:
|
|
180
|
+
ret = condition.should_retry(retry_policy_context)
|
|
181
|
+
retryable |= ret & retry_mask
|
|
182
|
+
no_retry &= ret & RetryCondition.NO_RETRY
|
|
183
|
+
return retryable | no_retry
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class DefaultMixedRetryCondition(RetryCondition):
|
|
187
|
+
def __init__(self, max_retry_times, retry_config):
|
|
188
|
+
RetryCondition.__init__(self)
|
|
189
|
+
self._condition = MergeRetryCondition([
|
|
190
|
+
MaxRetryTimesCondition(max_retry_times),
|
|
191
|
+
RetryOnMethodTypeCondition(retry_config),
|
|
192
|
+
MergeAndRetryCondition([
|
|
193
|
+
RetryOnExceptionCondition(retry_config),
|
|
194
|
+
RetryOnHttpStatusCondition(),
|
|
195
|
+
]),
|
|
196
|
+
])
|
|
197
|
+
|
|
198
|
+
def should_retry(self, retry_policy_context):
|
|
199
|
+
return self._condition.should_retry(retry_policy_context)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class DefaultConfigRetryCondition(DefaultMixedRetryCondition):
|
|
203
|
+
DEFAULT_MAX_RETRY_TIMES = 3
|
|
204
|
+
RETRY_CONFIG_FILE = "retry_config.json"
|
|
205
|
+
_loaded_config = None
|
|
206
|
+
|
|
207
|
+
def __init__(self, max_retry_times=None):
|
|
208
|
+
if not self._loaded_config:
|
|
209
|
+
self._loaded_config = data._load_json_from_data_dir(
|
|
210
|
+
self.RETRY_CONFIG_FILE)
|
|
211
|
+
if max_retry_times is None:
|
|
212
|
+
max_retry_times = self.DEFAULT_MAX_RETRY_TIMES
|
|
213
|
+
DefaultMixedRetryCondition.__init__(
|
|
214
|
+
self, max_retry_times, self._loaded_config)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Copyright 2022 Webull
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
16
|
+
# or more contributor license agreements. See the NOTICE file
|
|
17
|
+
# distributed with this work for additional information
|
|
18
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
19
|
+
# to you under the Apache License, Version 2.0 (the
|
|
20
|
+
# "License"); you may not use this file except in compliance
|
|
21
|
+
# with the License. You may obtain a copy of the License at
|
|
22
|
+
#
|
|
23
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
24
|
+
#
|
|
25
|
+
#
|
|
26
|
+
#
|
|
27
|
+
# Unless required by applicable law or agreed to in writing,
|
|
28
|
+
# software distributed under the License is distributed on an
|
|
29
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
30
|
+
# KIND, either express or implied. See the License for the
|
|
31
|
+
# specific language governing permissions and limitations
|
|
32
|
+
# under the License.
|
|
33
|
+
|
|
34
|
+
# coding=utf-8
|
|
35
|
+
|
|
36
|
+
"""
|
|
37
|
+
This file borrowed some of its methods from a modified fork of the
|
|
38
|
+
https://github.com/aliyun/aliyun-openapi-python-sdk/blob/master/aliyun-python-sdk-core/aliyunsdkcore/retry/retry_policy.py
|
|
39
|
+
which was part of Alibaba Group.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
from webull.core.retry.retry_condition import RetryCondition, NoRetryCondition, \
|
|
43
|
+
DefaultConfigRetryCondition
|
|
44
|
+
from webull.core.retry.backoff_strategy import BackoffStrategy, NoDelayStrategy, DefaultMixedBackoffStrategy
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class RetryPolicy(RetryCondition, BackoffStrategy):
|
|
48
|
+
def __init__(self, retry_condition, backoff_strategy):
|
|
49
|
+
self.retry_condition = retry_condition
|
|
50
|
+
self.backoff_strategy = backoff_strategy
|
|
51
|
+
|
|
52
|
+
def should_retry(self, retry_policy_context):
|
|
53
|
+
return self.retry_condition.should_retry(retry_policy_context)
|
|
54
|
+
|
|
55
|
+
def compute_delay_before_next_retry(self, retry_policy_context):
|
|
56
|
+
return self.backoff_strategy.compute_delay_before_next_retry(retry_policy_context)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
NO_RETRY_POLICY = RetryPolicy(NoRetryCondition(), NoDelayStrategy())
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_default_retry_policy(max_retry_times=None):
|
|
63
|
+
return RetryPolicy(DefaultConfigRetryCondition(max_retry_times), DefaultMixedBackoffStrategy())
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Copyright 2022 Webull
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
16
|
+
# or more contributor license agreements. See the NOTICE file
|
|
17
|
+
# distributed with this work for additional information
|
|
18
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
19
|
+
# to you under the Apache License, Version 2.0 (the
|
|
20
|
+
# "License"); you may not use this file except in compliance
|
|
21
|
+
# with the License. You may obtain a copy of the License at
|
|
22
|
+
#
|
|
23
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
24
|
+
#
|
|
25
|
+
#
|
|
26
|
+
#
|
|
27
|
+
# Unless required by applicable law or agreed to in writing,
|
|
28
|
+
# software distributed under the License is distributed on an
|
|
29
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
30
|
+
# KIND, either express or implied. See the License for the
|
|
31
|
+
# specific language governing permissions and limitations
|
|
32
|
+
# under the License.
|
|
33
|
+
|
|
34
|
+
# coding=utf-8
|
|
35
|
+
|
|
36
|
+
"""
|
|
37
|
+
This file borrowed some of its methods from a modified fork of the
|
|
38
|
+
https://github.com/aliyun/aliyun-openapi-python-sdk/blob/master/aliyun-python-sdk-core/aliyunsdkcore/retry/retry_policy_context.py
|
|
39
|
+
which was part of Alibaba Group.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
from webull.core.retry.retry_condition import RetryCondition
|
|
43
|
+
|
|
44
|
+
class RetryPolicyContext:
|
|
45
|
+
|
|
46
|
+
def __init__(self, original_request, exception, retries_attempted, http_status_code):
|
|
47
|
+
self.original_request = original_request
|
|
48
|
+
self.exception = exception
|
|
49
|
+
self.retries_attempted = retries_attempted
|
|
50
|
+
self.http_status_code = http_status_code
|
|
51
|
+
self.retryable = RetryCondition.BLANK_STATUS
|
|
File without changes
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Copyright 2022 Webull
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# coding=utf-8
|
|
16
|
+
import base64
|
|
17
|
+
import hashlib
|
|
18
|
+
import socket
|
|
19
|
+
from datetime import datetime
|
|
20
|
+
import uuid
|
|
21
|
+
import json
|
|
22
|
+
from webull.core.compat import ensure_bytes, ensure_string
|
|
23
|
+
|
|
24
|
+
TIME_ZONE = "UTC"
|
|
25
|
+
FORMAT_ISO_8601 = "%Y-%m-%dT%H:%M:%SZ"
|
|
26
|
+
FORMAT_ISO_8601_MILLIS = "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
27
|
+
|
|
28
|
+
def get_uuid():
|
|
29
|
+
name = socket.gethostname() + str(uuid.uuid1())
|
|
30
|
+
namespace = uuid.NAMESPACE_URL
|
|
31
|
+
return str(uuid.uuid5(namespace, name))
|
|
32
|
+
|
|
33
|
+
def get_iso_8601_date(dt_as_utc=None):
|
|
34
|
+
if dt_as_utc:
|
|
35
|
+
return dt_as_utc.strftime(FORMAT_ISO_8601)
|
|
36
|
+
d = datetime.utcnow()
|
|
37
|
+
return d.strftime(FORMAT_ISO_8601)
|
|
38
|
+
|
|
39
|
+
def get_iso_8601_date_with_millis(dt_as_utc=None):
|
|
40
|
+
if dt_as_utc:
|
|
41
|
+
d = dt_as_utc
|
|
42
|
+
else:
|
|
43
|
+
d = datetime.utcnow()
|
|
44
|
+
ret = d.strftime(FORMAT_ISO_8601_MILLIS)
|
|
45
|
+
if len(ret) != 27:
|
|
46
|
+
raise RuntimeError("failed to convent timestamp, result: %s" % ret)
|
|
47
|
+
return ret[:-4] + ret[-1:]
|
|
48
|
+
|
|
49
|
+
def parse_timestamp_to_dt(timestamp_of_millis):
|
|
50
|
+
return datetime.utcfromtimestamp(timestamp_of_millis / 1000.0)
|
|
51
|
+
|
|
52
|
+
def md5_sum(content):
|
|
53
|
+
content_bytes = ensure_bytes(content)
|
|
54
|
+
md5_bytes = hashlib.md5(content_bytes).digest()
|
|
55
|
+
return ensure_string(base64.standard_b64encode(md5_bytes))
|
|
56
|
+
|
|
57
|
+
def md5_hex(content):
|
|
58
|
+
content_bytes = ensure_bytes(content)
|
|
59
|
+
return hashlib.md5(content_bytes).hexdigest()
|
|
60
|
+
|
|
61
|
+
def json_dumps_compact(content):
|
|
62
|
+
return json.dumps(content, ensure_ascii=False, separators=(',', ':'))
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Copyright 2022 Webull
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# coding=utf-8
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import os.path
|
|
19
|
+
import webull.core
|
|
20
|
+
|
|
21
|
+
def _load_json_from_data_dir(name):
|
|
22
|
+
entry_dir = os.path.dirname(os.path.abspath(webull.core.__file__))
|
|
23
|
+
json_file = os.path.join(entry_dir, "data", name)
|
|
24
|
+
with open(json_file) as fp:
|
|
25
|
+
return json.load(fp)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Copyright 2022 Webull
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# coding=utf-8
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def desensitize_token(token, keep_length=6, mask_length=6):
|
|
19
|
+
if not token:
|
|
20
|
+
return token
|
|
21
|
+
|
|
22
|
+
total_length = len(token)
|
|
23
|
+
|
|
24
|
+
# 如果字符串长度不足需要保留长度的两倍,则返回全部内容
|
|
25
|
+
if total_length <= keep_length * 2:
|
|
26
|
+
return token
|
|
27
|
+
|
|
28
|
+
# 提取前保留部分、后保留部分,并用星号连接
|
|
29
|
+
front_part = token[:keep_length]
|
|
30
|
+
rear_part = token[-keep_length:] if keep_length > 0 else ''
|
|
31
|
+
mask = '*' * mask_length
|
|
32
|
+
|
|
33
|
+
return f"{front_part}{mask}{rear_part}"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Copyright 2022 Webull
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
16
|
+
# or more contributor license agreements. See the NOTICE file
|
|
17
|
+
# distributed with this work for additional information
|
|
18
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
19
|
+
# to you under the Apache License, Version 2.0 (the
|
|
20
|
+
# "License"); you may not use this file except in compliance
|
|
21
|
+
# with the License. You may obtain a copy of the License at
|
|
22
|
+
#
|
|
23
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
24
|
+
#
|
|
25
|
+
#
|
|
26
|
+
#
|
|
27
|
+
# Unless required by applicable law or agreed to in writing,
|
|
28
|
+
# software distributed under the License is distributed on an
|
|
29
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
30
|
+
# KIND, either express or implied. See the License for the
|
|
31
|
+
# specific language governing permissions and limitations
|
|
32
|
+
# under the License.
|
|
33
|
+
|
|
34
|
+
# coding=utf-8
|
|
35
|
+
|
|
36
|
+
"""
|
|
37
|
+
This file borrowed some of its methods from a modified fork of the
|
|
38
|
+
https://github.com/aliyun/aliyun-openapi-python-sdk/blob/master/aliyun-python-sdk-core/aliyunsdkcore/utils/validation.py
|
|
39
|
+
which was part of Alibaba Group.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
from webull.core.exception.exceptions import ClientException
|
|
43
|
+
from webull.core.exception import error_code
|
|
44
|
+
|
|
45
|
+
def assert_integer_positive(integer, name):
|
|
46
|
+
if isinstance(integer, int) and integer > 0:
|
|
47
|
+
return
|
|
48
|
+
raise ClientException(error_code.SDK_INVALID_PARAMETER,
|
|
49
|
+
"{0} should be a positive integer.".format(name))
|
|
File without changes
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Copyright 2022 Webull
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# -*- coding: utf-8 -*-
|
|
16
|
+
|
|
17
|
+
# __
|
|
18
|
+
# /__) _ _ _ _ _/ _
|
|
19
|
+
# / ( (- (/ (/ (- _) / _)
|
|
20
|
+
# /
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
Requests HTTP Library
|
|
24
|
+
~~~~~~~~~~~~~~~~~~~~~
|
|
25
|
+
|
|
26
|
+
Requests is an HTTP library, written in Python, for human beings. Basic GET
|
|
27
|
+
usage:
|
|
28
|
+
|
|
29
|
+
>>> import requests
|
|
30
|
+
>>> r = requests.get('https://www.python.org')
|
|
31
|
+
>>> r.status_code
|
|
32
|
+
200
|
|
33
|
+
>>> 'Python is a programming language' in r.content
|
|
34
|
+
True
|
|
35
|
+
|
|
36
|
+
... or POST:
|
|
37
|
+
|
|
38
|
+
>>> payload = dict(key1='value1', key2='value2')
|
|
39
|
+
>>> r = requests.post('http://httpbin.org/post', data=payload)
|
|
40
|
+
>>> print(r.text)
|
|
41
|
+
{
|
|
42
|
+
...
|
|
43
|
+
"form": {
|
|
44
|
+
"key2": "value2",
|
|
45
|
+
"key1": "value1"
|
|
46
|
+
},
|
|
47
|
+
...
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
The other HTTP methods are supported - see `requests.api`. Full documentation
|
|
51
|
+
is at <http://python-requests.org>.
|
|
52
|
+
|
|
53
|
+
:copyright: (c) 2017 by Kenneth Reitz.
|
|
54
|
+
:license: Apache 2.0, see LICENSE for more details.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
__title__ = 'requests'
|
|
58
|
+
__version__ = '2.18.3'
|
|
59
|
+
|
|
60
|
+
# Attempt to enable urllib3's SNI support, if possible
|
|
61
|
+
try:
|
|
62
|
+
from .packages.urllib3.contrib import pyopenssl
|
|
63
|
+
pyopenssl.inject_into_urllib3()
|
|
64
|
+
except ImportError:
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
from . import utils
|
|
69
|
+
from .models import Request, Response, PreparedRequest
|
|
70
|
+
from .api import request, get, head, post, patch, put, delete, options
|
|
71
|
+
from .sessions import session, Session
|
|
72
|
+
from .status_codes import codes
|
|
73
|
+
from .exceptions import (
|
|
74
|
+
RequestException, Timeout, URLRequired,
|
|
75
|
+
TooManyRedirects, HTTPError, ConnectionError,
|
|
76
|
+
FileModeWarning, ConnectTimeout, ReadTimeout
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Set default logging handler to avoid "No handler found" warnings.
|
|
80
|
+
import logging
|
|
81
|
+
try: # Python 2.7+
|
|
82
|
+
from logging import NullHandler
|
|
83
|
+
except ImportError:
|
|
84
|
+
class NullHandler(logging.Handler):
|
|
85
|
+
def emit(self, record):
|
|
86
|
+
"""
|
|
87
|
+
null handler
|
|
88
|
+
"""
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
logging.getLogger(__name__).addHandler(NullHandler())
|
|
92
|
+
logging.getLogger(__name__).setLevel(logging.CRITICAL)
|
|
93
|
+
|
|
94
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Copyright 2022 Webull
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# .-. .-. .-. . . .-. .-. .-. .-.
|
|
16
|
+
# |( |- |.| | | |- `-. | `-.
|
|
17
|
+
# ' ' `-' `-`.`-' `-' `-' ' `-'
|
|
18
|
+
|
|
19
|
+
__title__ = 'requests'
|
|
20
|
+
__description__ = 'Python HTTP for Humans.'
|
|
21
|
+
__url__ = 'http://python-requests.org'
|
|
22
|
+
__version__ = '2.18.3'
|
|
23
|
+
__build__ = 0x021803
|
|
24
|
+
__author__ = 'Kenneth Reitz'
|
|
25
|
+
__author_email__ = 'me@kennethreitz.org'
|
|
26
|
+
__license__ = 'Apache 2.0'
|
|
27
|
+
__copyright__ = 'Copyright 2017 Kenneth Reitz'
|
|
28
|
+
__cake__ = u'\u2728 \U0001f370 \u2728'
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Copyright 2022 Webull
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# -*- coding: utf-8 -*-
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
requests._internal_utils
|
|
19
|
+
~~~~~~~~~~~~~~
|
|
20
|
+
|
|
21
|
+
Provides utility functions that are consumed internally by Requests
|
|
22
|
+
which depend on extremely few external helpers (such as compat)
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from .compat import is_py2, builtin_str, str
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def to_native_string(string, encoding='ascii'):
|
|
29
|
+
"""Given a string object, regardless of type, returns a representation of
|
|
30
|
+
that string in the native string type, encoding and decoding where
|
|
31
|
+
necessary. This assumes ASCII unless told otherwise.
|
|
32
|
+
"""
|
|
33
|
+
if isinstance(string, builtin_str):
|
|
34
|
+
out = string
|
|
35
|
+
else:
|
|
36
|
+
if is_py2:
|
|
37
|
+
out = string.encode(encoding)
|
|
38
|
+
else:
|
|
39
|
+
out = string.decode(encoding)
|
|
40
|
+
|
|
41
|
+
return out
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def unicode_is_ascii(u_string):
|
|
45
|
+
"""Determine if unicode string only contains ASCII characters.
|
|
46
|
+
|
|
47
|
+
:param str u_string: unicode string to check. Must be unicode
|
|
48
|
+
and not Python 2 `str`.
|
|
49
|
+
:rtype: bool
|
|
50
|
+
"""
|
|
51
|
+
assert isinstance(u_string, str)
|
|
52
|
+
try:
|
|
53
|
+
u_string.encode('ascii')
|
|
54
|
+
return True
|
|
55
|
+
except UnicodeEncodeError:
|
|
56
|
+
return False
|