5050))
5151
5252
53+ def _build_transport (url , proxy , timeout , user_agent , verify ):
54+ """Construct the appropriate transport based on the endpoint URL.
55+
56+ Selects RestTransport when the URL contains '/rest', otherwise falls back
57+ to XmlRpcTransport. Extracted to avoid duplicating this logic across
58+ ``create_client_from_env``, ``employee_client``, and ``BaseClient``.
59+
60+ :param str url: The API endpoint URL.
61+ :param str proxy: Optional proxy URL.
62+ :param timeout: Request timeout in seconds (``None`` means no timeout).
63+ :param str user_agent: Optional User-Agent string override.
64+ :param verify: SSL verification — ``True``, ``False``, or a path to a CA bundle.
65+ :returns: A :class:`~SoftLayer.transports.RestTransport` or
66+ :class:`~SoftLayer.transports.XmlRpcTransport` instance.
67+ """
68+ if url is not None and '/rest' in url :
69+ return transports .RestTransport (
70+ endpoint_url = url ,
71+ proxy = proxy ,
72+ timeout = timeout ,
73+ user_agent = user_agent ,
74+ verify = verify ,
75+ )
76+ return transports .XmlRpcTransport (
77+ endpoint_url = url ,
78+ proxy = proxy ,
79+ timeout = timeout ,
80+ user_agent = user_agent ,
81+ verify = verify ,
82+ )
83+
84+
5385def create_client_from_env (username = None ,
5486 api_key = None ,
5587 endpoint_url = None ,
@@ -62,7 +94,7 @@ def create_client_from_env(username=None,
6294 verify = True ):
6395 """Creates a SoftLayer API client using your environment.
6496
65- Settings are loaded via keyword arguments, environemtal variables and
97+ Settings are loaded via keyword arguments, environmental variables and
6698 config file.
6799
68100 :param username: an optional API username if you wish to bypass the
@@ -104,25 +136,13 @@ def create_client_from_env(username=None,
104136 config_file = config_file )
105137
106138 if transport is None :
107- url = settings .get ('endpoint_url' )
108- if url is not None and '/rest' in url :
109- # If this looks like a rest endpoint, use the rest transport
110- transport = transports .RestTransport (
111- endpoint_url = settings .get ('endpoint_url' ),
112- proxy = settings .get ('proxy' ),
113- timeout = settings .get ('timeout' ),
114- user_agent = user_agent ,
115- verify = verify ,
116- )
117- else :
118- # Default the transport to use XMLRPC
119- transport = transports .XmlRpcTransport (
120- endpoint_url = settings .get ('endpoint_url' ),
121- proxy = settings .get ('proxy' ),
122- timeout = settings .get ('timeout' ),
123- user_agent = user_agent ,
124- verify = verify ,
125- )
139+ transport = _build_transport (
140+ url = settings .get ('endpoint_url' ),
141+ proxy = settings .get ('proxy' ),
142+ timeout = settings .get ('timeout' ),
143+ user_agent = user_agent ,
144+ verify = verify ,
145+ )
126146
127147 # If we have enough information to make an auth driver, let's do it
128148 if auth is None and settings .get ('username' ) and settings .get ('api_key' ):
@@ -157,13 +177,13 @@ def employee_client(username=None,
157177 verify = True ):
158178 """Creates an INTERNAL SoftLayer API client using your environment.
159179
160- Settings are loaded via keyword arguments, environemtal variables and config file.
180+ Settings are loaded via keyword arguments, environmental variables and config file.
161181
162182 :param username: your user ID
163- :param access_token: hash from SoftLayer_User_Employee::performExternalAuthentication(username, password, token)
164- :param password: password to use for employee authentication
183+ :param access_token: hash from SoftLayer_User_Employee::performExternalAuthentication
165184 :param endpoint_url: the API endpoint base URL you wish to connect to.
166- Set this to API_PRIVATE_ENDPOINT to connect via SoftLayer's private network.
185+ Must contain 'internal'. Set this to API_PRIVATE_ENDPOINT to connect
186+ via SoftLayer's private network.
167187 :param proxy: proxy to be used to make API calls
168188 :param integer timeout: timeout for API requests
169189 :param auth: an object which responds to get_headers() to be inserted into the xml-rpc headers.
@@ -173,56 +193,54 @@ def employee_client(username=None,
173193 calls if you wish to bypass the packages built in User Agent string
174194 :param transport: An object that's callable with this signature: transport(SoftLayer.transports.Request)
175195 :param bool verify: decide to verify the server's SSL/TLS cert.
196+ DO NOT SET TO FALSE WITHOUT UNDERSTANDING THE IMPLICATIONS.
176197 """
198+ # Pass caller-supplied verify so it is not silently discarded; the config
199+ # file value will take precedence if present (via get_client_settings).
177200 settings = config .get_client_settings (username = username ,
178201 api_key = None ,
179202 endpoint_url = endpoint_url ,
180203 timeout = timeout ,
181204 proxy = proxy ,
182- verify = None ,
205+ verify = verify ,
183206 config_file = config_file )
184207
185208 url = settings .get ('endpoint_url' , '' )
186- verify = settings .get ('verify' , True )
209+ # Honour the config-file value; fall back to the caller-supplied default.
210+ verify = settings .get ('verify' , verify )
187211
188212 if 'internal' not in url :
189213 raise exceptions .SoftLayerError (f"{ url } does not look like an Internal Employee url." )
190214
215+ # url is guaranteed non-empty here (the guard above ensures it contains
216+ # 'internal'), so no additional None-check is needed.
191217 if transport is None :
192- if url is not None and '/rest' in url :
193- # If this looks like a rest endpoint, use the rest transport
194- transport = transports .RestTransport (
195- endpoint_url = url ,
196- proxy = settings .get ('proxy' ),
197- timeout = settings .get ('timeout' ),
198- user_agent = user_agent ,
199- verify = verify ,
200- )
201- else :
202- # Default the transport to use XMLRPC
203- transport = transports .XmlRpcTransport (
204- endpoint_url = url ,
205- proxy = settings .get ('proxy' ),
206- timeout = settings .get ('timeout' ),
207- user_agent = user_agent ,
208- verify = verify ,
209- )
210-
218+ transport = _build_transport (
219+ url = url ,
220+ proxy = settings .get ('proxy' ),
221+ timeout = settings .get ('timeout' ),
222+ user_agent = user_agent ,
223+ verify = verify ,
224+ )
225+
226+ # Resolve all settings-derived credentials together before auth selection.
211227 if access_token is None :
212228 access_token = settings .get ('access_token' )
213-
214229 user_id = settings .get ('userid' )
215- # Assume access_token is valid for now, user has logged in before at least.
216- if settings .get ('auth_cert' , False ):
217- auth = slauth .X509Authentication (settings .get ('auth_cert' ), verify )
218- return EmployeeClient (auth = auth , transport = transport , config_file = config_file )
219- elif access_token and user_id :
220- auth = slauth .EmployeeAuthentication (user_id , access_token )
221- return EmployeeClient (auth = auth , transport = transport , config_file = config_file )
222- else :
223- # This is for logging in mostly.
224- LOGGER .info ("No access_token or userid found in settings, creating a No Auth client for now." )
225- return EmployeeClient (auth = None , transport = transport , config_file = config_file )
230+
231+ # Select the appropriate auth driver only when the caller has not already
232+ # supplied one. A single return keeps construction separate from selection.
233+ if auth is None :
234+ if settings .get ('auth_cert' ):
235+ auth = slauth .X509Authentication (settings .get ('auth_cert' ), verify )
236+ elif access_token and user_id :
237+ auth = slauth .EmployeeAuthentication (user_id , access_token )
238+ else :
239+ # No credentials available — caller must authenticate explicitly
240+ # (e.g. via EmployeeClient.authenticate_with_internal).
241+ LOGGER .info ("No access_token or userid found in settings, creating a No Auth client for now." )
242+
243+ return EmployeeClient (auth = auth , transport = transport , config_file = config_file )
226244
227245
228246def Client (** kwargs ):
@@ -237,7 +255,7 @@ class BaseClient(object):
237255 :param transport: An object that's callable with this signature: transport(SoftLayer.transports.Request)
238256 """
239257 _prefix = "SoftLayer_"
240- auth : slauth .AuthenticationBase
258+ auth : slauth .AuthenticationBase | None
241259
242260 def __init__ (self , auth = None , transport = None , config_file = None ):
243261 if config_file is None :
@@ -247,7 +265,7 @@ def __init__(self, auth=None, transport=None, config_file=None):
247265 self .__setAuth (auth )
248266 self .__setTransport (transport )
249267
250- def __setAuth (self , auth = None ):
268+ def __setAuth (self , auth : slauth . AuthenticationBase | None = None ):
251269 """Prepares the authentication property"""
252270 self .auth = auth
253271
@@ -751,7 +769,7 @@ def refresh_token(self, userId, auth_token):
751769
752770 def call (self , service , method , * args , ** kwargs ):
753771 """Handles refreshing Employee tokens in case of a HTTP 401 error"""
754- if self .account_id :
772+ if self .account_id and not kwargs . get ( 'id' , False ) :
755773 kwargs ['id' ] = self .account_id
756774
757775 try :
0 commit comments