Skip to content

Commit c0f2cac

Browse files
committed
refactor: use CloudantBaseService as a super of CloudantV1
1 parent 22d1b05 commit c0f2cac

File tree

3 files changed

+97
-107
lines changed

3 files changed

+97
-107
lines changed

ibmcloudant/__init__.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,10 @@
1919
from ibm_cloud_sdk_core import IAMTokenManager, DetailedResponse, BaseService, ApiException, get_authenticator
2020
from .couchdb_session_authenticator import CouchDbSessionAuthenticator
2121
from .couchdb_session_get_authenticator_patch import new_construct_authenticator
22-
from .cloudant_base_service import new_init, new_prepare_request, new_set_default_headers, new_set_http_client, new_set_service_url, new_set_disable_ssl_verification
2322
from .couchdb_session_token_manager import CouchDbSessionTokenManager
2423
from .cloudant_v1 import CloudantV1
2524
from .features.changes_follower import ChangesFollower
2625
from .features.pagination import Pager, PagerType, Pagination
2726

2827
# sdk-core's __construct_authenticator works with a long switch-case so monkey-patching is required
2928
get_authenticator.__construct_authenticator = new_construct_authenticator
30-
31-
CloudantV1.__init__ = new_init
32-
33-
CloudantV1.set_service_url = new_set_service_url
34-
35-
CloudantV1.set_default_headers = new_set_default_headers
36-
37-
CloudantV1.prepare_request = new_prepare_request
38-
39-
CloudantV1.set_http_client = new_set_http_client
40-
41-
CloudantV1.set_disable_ssl_verification = new_set_disable_ssl_verification

ibmcloudant/cloudant_base_service.py

Lines changed: 93 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@
2424
from json.decoder import JSONDecodeError
2525
from io import BytesIO
2626

27+
from ibm_cloud_sdk_core import BaseService
2728
from ibm_cloud_sdk_core.authenticators import Authenticator
2829
from requests import Response, Session
2930
from requests.cookies import RequestsCookieJar
3031

3132
from .common import get_sdk_headers
32-
from .cloudant_v1 import CloudantV1
3333
from .couchdb_session_authenticator import CouchDbSessionAuthenticator
3434

3535
# pylint: disable=missing-docstring
@@ -72,52 +72,99 @@ def __hash__(self):
7272
# Since Py3.6 dict is ordered so use a key only dict for our set
7373
rules_by_operation.setdefault(operation_id, dict()).setdefault(rule)
7474

75-
_old_init = CloudantV1.__init__
76-
77-
def new_init(self, authenticator: Authenticator = None):
78-
_old_init(self, authenticator)
79-
# Overwrite default read timeout to 2.5 minutes
80-
if not ('timeout' in self.http_config):
81-
new_http_config = self.http_config.copy()
82-
new_http_config['timeout'] = (CONNECT_TIMEOUT, READ_TIMEOUT)
83-
self.set_http_config(new_http_config)
84-
# Custom actions for CouchDbSessionAuthenticator
85-
if isinstance(authenticator, CouchDbSessionAuthenticator):
86-
# Replacing BaseService's http.cookiejar.CookieJar as RequestsCookieJar supports update(CookieJar)
87-
self.jar = RequestsCookieJar(self.jar)
88-
self.authenticator.set_jar(self.jar) # Authenticators don't have access to cookie jars by default
89-
add_hooks(self)
90-
91-
_old_set_service_url = CloudantV1.set_service_url
92-
93-
def new_set_service_url(self, service_url: str):
94-
_old_set_service_url(self, service_url)
95-
try:
75+
class CloudantBaseService(BaseService):
76+
"""
77+
The base class for service classes.
78+
"""
79+
def __init__(
80+
self,
81+
service_url: str = None,
82+
authenticator: Authenticator = None,
83+
) -> None:
84+
"""
85+
Construct a new client for the Cloudant service.
86+
87+
:param Authenticator authenticator: The authenticator specifies the authentication mechanism.
88+
Get up to date information from https://github.com/IBM/python-sdk-core/blob/main/README.md
89+
about initializing the authenticator of your choice.
90+
"""
91+
BaseService.__init__(self, service_url=service_url, authenticator=authenticator)
92+
# Overwrite default read timeout to 2.5 minutes
93+
if not ('timeout' in self.http_config):
94+
new_http_config = self.http_config.copy()
95+
new_http_config['timeout'] = (CONNECT_TIMEOUT, READ_TIMEOUT)
96+
self.set_http_config(new_http_config)
97+
# Custom actions for CouchDbSessionAuthenticator
98+
if isinstance(authenticator, CouchDbSessionAuthenticator):
99+
# Replacing BaseService's http.cookiejar.CookieJar as RequestsCookieJar supports update(CookieJar)
100+
self.jar = RequestsCookieJar(self.jar)
101+
self.authenticator.set_jar(self.jar) # Authenticators don't have access to cookie jars by default
102+
add_hooks(self)
103+
104+
def set_service_url(self, service_url: str):
105+
super().set_service_url(service_url)
106+
try:
107+
if isinstance(self.authenticator, CouchDbSessionAuthenticator):
108+
self.authenticator.token_manager.set_service_url(service_url)
109+
except AttributeError:
110+
pass # in case no authenticator is configured yet, pass
111+
112+
def set_default_headers(self, headers: Dict[str, str]):
113+
super().set_default_headers(headers)
96114
if isinstance(self.authenticator, CouchDbSessionAuthenticator):
97-
self.authenticator.token_manager.set_service_url(service_url)
98-
except AttributeError:
99-
pass # in case no authenticator is configured yet, pass
100-
101-
_old_set_default_headers = CloudantV1.set_default_headers
102-
103-
def new_set_default_headers(self, headers: Dict[str, str]):
104-
_old_set_default_headers(self, headers)
105-
if isinstance(self.authenticator, CouchDbSessionAuthenticator):
106-
combined_headers = {}
107-
combined_headers.update(headers)
108-
combined_headers.update(get_sdk_headers(
109-
service_name=self.DEFAULT_SERVICE_NAME,
110-
service_version='V1',
111-
operation_id='authenticator_post_session')
112-
)
113-
self.authenticator.token_manager.set_default_headers(combined_headers)
114-
115-
_old_set_disable_ssl_verification = CloudantV1.set_disable_ssl_verification
116-
117-
def new_set_disable_ssl_verification(self, status: bool = False) -> None:
118-
_old_set_disable_ssl_verification(self, status)
119-
if isinstance(self.authenticator, CouchDbSessionAuthenticator):
120-
self.authenticator.token_manager.set_disable_ssl_verification(status)
115+
combined_headers = {}
116+
combined_headers.update(headers)
117+
combined_headers.update(get_sdk_headers(
118+
service_name=self.DEFAULT_SERVICE_NAME,
119+
service_version='V1',
120+
operation_id='authenticator_post_session')
121+
)
122+
self.authenticator.token_manager.set_default_headers(combined_headers)
123+
124+
def set_disable_ssl_verification(self, status: bool = False) -> None:
125+
super().set_disable_ssl_verification(status)
126+
if isinstance(self.authenticator, CouchDbSessionAuthenticator):
127+
self.authenticator.token_manager.set_disable_ssl_verification(status)
128+
129+
def set_http_client(self, http_client: Session) -> None:
130+
super().set_http_client(http_client)
131+
add_hooks(self)
132+
133+
def prepare_request(self,
134+
method: str,
135+
url: str,
136+
*args,
137+
headers: Optional[dict] = None,
138+
params: Optional[dict] = None,
139+
data: Optional[Union[str, dict]] = None,
140+
files: Optional[Union[Dict[str, Tuple[str]],
141+
List[Tuple[str,
142+
Tuple[str,
143+
...]]]]] = None,
144+
**kwargs) -> dict:
145+
# Extract the operation ID from the request headers.
146+
operation_id = None
147+
header = headers.get('X-IBMCloud-SDK-Analytics')
148+
if header is not None:
149+
for element in header.split(';'):
150+
if element.startswith('operation_id'):
151+
operation_id = element.split('=')[1]
152+
break
153+
if operation_id is not None:
154+
# Check each validation rule that applies to the operation.
155+
# Until the request URL is passed to old_prepare_request it does not include the
156+
# service URL and is relative to it
157+
request_url_path_segments = urlsplit(url).path.strip('/').split('/')
158+
if len(request_url_path_segments) == 1 and request_url_path_segments[0] == '':
159+
request_url_path_segments = []
160+
# Note the get returns a value-less dict, we are iterating only the keys
161+
for rule in rules_by_operation.get(operation_id, {}):
162+
if len(request_url_path_segments) > rule.path_segment_index:
163+
segment_to_validate = request_url_path_segments[rule.path_segment_index]
164+
if segment_to_validate.startswith('_'):
165+
raise ValueError('{0} {1} starts with the invalid _ character.'.format(rule.error_parameter_name,
166+
unquote(segment_to_validate)))
167+
return super().prepare_request(method, url, *args, headers=headers, params=params, data=data, files=files, **kwargs)
121168

122169
def _error_response_hook(response:Response, *args, **kwargs) -> Optional[Response]:
123170
# pylint: disable=W0613
@@ -186,52 +233,7 @@ def _error_response_hook(response:Response, *args, **kwargs) -> Optional[Respons
186233
# so the exception can surface elsewhere.
187234
pass
188235
return response
189-
190-
_old_prepare_request = CloudantV1.prepare_request
191-
192-
def new_prepare_request(self,
193-
method: str,
194-
url: str,
195-
*args,
196-
headers: Optional[dict] = None,
197-
params: Optional[dict] = None,
198-
data: Optional[Union[str, dict]] = None,
199-
files: Optional[Union[Dict[str, Tuple[str]],
200-
List[Tuple[str,
201-
Tuple[str,
202-
...]]]]] = None,
203-
**kwargs) -> dict:
204-
# Extract the operation ID from the request headers.
205-
operation_id = None
206-
header = headers.get('X-IBMCloud-SDK-Analytics')
207-
if header is not None:
208-
for element in header.split(';'):
209-
if element.startswith('operation_id'):
210-
operation_id = element.split('=')[1]
211-
break
212-
if operation_id is not None:
213-
# Check each validation rule that applies to the operation.
214-
# Until the request URL is passed to old_prepare_request it does not include the
215-
# service URL and is relative to it
216-
request_url_path_segments = urlsplit(url).path.strip('/').split('/')
217-
if len(request_url_path_segments) == 1 and request_url_path_segments[0] == '':
218-
request_url_path_segments = []
219-
# Note the get returns a value-less dict, we are iterating only the keys
220-
for rule in rules_by_operation.get(operation_id, {}):
221-
if len(request_url_path_segments) > rule.path_segment_index:
222-
segment_to_validate = request_url_path_segments[rule.path_segment_index]
223-
if segment_to_validate.startswith('_'):
224-
raise ValueError('{0} {1} starts with the invalid _ character.'.format(rule.error_parameter_name,
225-
unquote(segment_to_validate)))
226-
return _old_prepare_request(self, method, url, *args, headers=headers, params=params, data=data, files=files, **kwargs)
227-
228236
def add_hooks(self):
229237
response_hooks = self.get_http_client().hooks['response']
230238
if _error_response_hook not in response_hooks:
231239
response_hooks.append(_error_response_hook)
232-
233-
_old_set_http_client = CloudantV1.set_http_client
234-
235-
def new_set_http_client(self, http_client: Session) -> None:
236-
_old_set_http_client(self, http_client)
237-
add_hooks(self)

ibmcloudant/cloudant_v1.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,20 @@
2727
import json
2828
import logging
2929

30-
from ibm_cloud_sdk_core import BaseService, DetailedResponse
30+
from ibm_cloud_sdk_core import DetailedResponse
3131
from ibm_cloud_sdk_core.authenticators.authenticator import Authenticator
3232
from ibm_cloud_sdk_core.get_authenticator import get_authenticator_from_environment
3333
from ibm_cloud_sdk_core.utils import convert_list, convert_model, datetime_to_string, string_to_datetime
3434

35+
from .cloudant_base_service import CloudantBaseService
3536
from .common import get_sdk_headers
3637

3738
##############################################################################
3839
# Service
3940
##############################################################################
4041

4142

42-
class CloudantV1(BaseService):
43+
class CloudantV1(CloudantBaseService):
4344
"""The Cloudant V1 service."""
4445

4546
DEFAULT_SERVICE_URL = 'https://~replace-with-cloudant-host~.cloudantnosqldb.appdomain.cloud'
@@ -72,7 +73,7 @@ def __init__(
7273
Get up to date information from https://github.com/IBM/python-sdk-core/blob/main/README.md
7374
about initializing the authenticator of your choice.
7475
"""
75-
BaseService.__init__(self, service_url=self.DEFAULT_SERVICE_URL, authenticator=authenticator)
76+
CloudantBaseService.__init__(self, service_url=self.DEFAULT_SERVICE_URL, authenticator=authenticator)
7677
# enable gzip compression of request bodies
7778
self.set_enable_gzip_compression(True)
7879

0 commit comments

Comments
 (0)