Module cvpysdk.cvpysdk
Helper file for session operations.
This file is used to perform Authentication for the user on the Commcell.
#. Check if the web server and service is valid and running
#. Perform Login operation to the Commcell using the credentials provided by the user
#. Store the Authtoken received after Login REST API call to use for the entire session
#. Renew Authtoken if credentials were given by the user during Commcell object
initialization, and the current token has expired
#. Logout the current user from the Commcell, and disconnect the API session
#. Common method to be used in the entire SDK to perform REST API call on the Web Server
Cvpysdk
init(commcell_object) – initialise object of the CVPySDK class and bind to the commcell
_is_valid_service() – checks if the service is valid and running or not
_login() – sign in the user to the commcell with the credentials provided
_renew_login_token() – renews the Authtoken for the currently logged in user
_logout() – sign out the current logged in user from the commcell, and ends the session
_request() – executes the request on the server and return the Response
who_am_i() – Fetches the username of the user to whom authtoken is mapped
make_request() – run the http request specified on the URL/WebService provided, and return the flag specifying success/fail, and response
Expand source code Browse git
# -*- coding: utf-8 -*-
# --------------------------------------------------------------------------
# Copyright Commvault Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# --------------------------------------------------------------------------
# pylint: disable=R1705
"""Helper file for session operations.
This file is used to perform Authentication for the user on the Commcell.
#. Check if the web server and service is valid and running
#. Perform Login operation to the Commcell using the credentials provided by the user
#. Store the Authtoken received after Login REST API call to use for the entire session
#. Renew Authtoken if credentials were given by the user during Commcell object
initialization, and the current token has expired
#. Logout the current user from the Commcell, and disconnect the API session
#. Common method to be used in the entire SDK to perform REST API call on the Web Server
CVPySDK:
__init__(commcell_object) -- initialise object of the CVPySDK class and bind to the commcell
_is_valid_service() -- checks if the service is valid and running or not
_login() -- sign in the user to the commcell with the credentials provided
_renew_login_token() -- renews the Authtoken for the currently logged in user
_logout() -- sign out the current logged in user from the commcell,
and ends the session
_request() -- executes the request on the server and return the Response
who_am_i() -- Fetches the username of the user to whom authtoken is mapped
make_request() -- run the http request specified on the URL/WebService provided,
and return the flag specifying success/fail, and response
"""
from __future__ import absolute_import
from __future__ import unicode_literals
from xml.parsers.expat import ExpatError
import requests
import xmltodict
try:
# Python 2 import
import httplib
except ImportError:
# Python 3 import
import http.client as httplib
from .exception import SDKException
class CVPySDK(object):
"""Helper class for login, and logout operations.
Also contains common method for running all HTTP requests.
"""
def __init__(self, commcell_object, certificate_path=None):
"""Initialize the CVPySDK object for running various operations.
Args:
commcell_object (object) -- instance of the Commcell class
certificate_path (str) -- path of the CA_BUNDLE or directory with
certificates of trusted CAs (including trusted self-signed certificates)
default: None
Returns:
object - instance of the CVPySDK class
"""
self._commcell_object = commcell_object
self._certificate_path = certificate_path
def _is_valid_service(self):
"""Checks if the service url is a valid url or not.
Returns:
True - if the service url is valid
False - if the service url is invalid
Raises:
requests Connection Error:
requests.exceptions.ConnectionError
requests Timeout Error:
requests.exceptions.Timeout
"""
try:
response = self._request(
method='GET',
url=self._commcell_object._web_service,
timeout=184
)
# Valid service if the status code is 200 and response is True
return response.status_code == httplib.OK and response.ok
except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as error:
raise error
def _login(self):
"""Posts a login request to the server.
Returns:
str - Authtoken received from the WebServer upon successfull login
Raises:
SDKException:
if login failed
if response is empty
if response is not success
requests Connection Error:
requests.exceptions.ConnectionError
"""
try:
if isinstance(self._commcell_object._password, dict):
raise SDKException('CVPySDK', '104')
if self._commcell_object.is_service_commcell:
json_login_request = {
"mode": 4,
"clientType": 30,
"autoLogin": {
"autoLoginType": 5,
"encryptedMessage": self._commcell_object.master_saml_token
}
}
else:
json_login_request = {
"mode": 4,
"username": self._commcell_object._user,
"password": self._commcell_object._password,
"deviceId": self._commcell_object.device_id,
"clientType": 30,
}
flag, response = self.make_request(
'POST', self._commcell_object._services['LOGIN'], json_login_request
)
if flag:
if response.json():
if "userName" in response.json() and "token" in response.json():
return response.json()['token']
else:
error_message = response.json()['errList'][0]['errLogMessage']
err_msg = 'Error: "{0}"'.format(error_message)
raise SDKException('CVPySDK', '101', err_msg)
else:
raise SDKException('Response', '102')
else:
response_string = self._commcell_object._update_response_(response.text)
raise SDKException('Response', '101', response_string)
except requests.exceptions.ConnectionError as con_err:
raise con_err
def _renew_login_token(self):
"""Posts a Renew Login-Token request to the server.
Returns:
str - new token received from the WebServer
Raises:
SDKException:
if token renew failed
if response is empty
if response is not success
requests Connection Error:
requests.exceptions.ConnectionError
"""
try:
if self._commcell_object._is_saml_login and not self._commcell_object.is_service_commcell:
raise SDKException('CVPySDK', '106')
token_renew_request = {
"sessionId": self._commcell_object._headers['Authtoken'],
"deviceId": self._commcell_object.device_id
}
flag, response = self.make_request(
'POST', self._commcell_object._services['RENEW_LOGIN_TOKEN'], token_renew_request
)
if flag:
if response.json():
if "token" in response.json():
return response.json()['token']
else:
error_message = response.json()['error']['errLogMessage']
err_msg = 'Error: "{0}"'.format(error_message)
raise SDKException('CVPySDK', '101', err_msg)
else:
raise SDKException('Response', '102')
else:
response_string = self._commcell_object._update_response_(response.text)
raise SDKException('Response', '101', response_string)
except requests.exceptions.ConnectionError as con_err:
raise con_err
def _logout(self):
"""Posts a logout request to the server.
Returns:
str - response string from server upon logout success
"""
flag, response = self.make_request('POST', self._commcell_object._services['LOGOUT'])
if flag:
self._commcell_object._headers['Authtoken'] = None
if response.status_code == httplib.OK:
return response.text
else:
return 'Failed to logout the user'
else:
return 'User already logged out'
def _request(self, **kwargs):
"""Executes the request on the Server with the given parameters.
If the certificate path is given and the Web Service starts with **https**,
it adds the **verify** parameter to the request, and passes the certificate path as
its value.
Args:
**kwargs -- dict of keyword arguments, same as accepted by the
**requests.request** method
Returns:
object - **requests.Response** class instance, as received from calling the
**requests.request** method
"""
if self._certificate_path and self._commcell_object._web_service.startswith('https'):
return requests.request(verify=self._certificate_path, **kwargs)
return requests.request(**kwargs)
def who_am_i(self, authtoken=None):
"""Get the username of the user, to whom the Authtoken belongs to.
Args:
authtoken (str) -- QSDK or SAML authentication token
Returns:
str - username of the user respective to the token
Raises:
SDKException:
if no user mapping found
"""
temp_headers = self._commcell_object._headers.copy()
if authtoken:
temp_headers['Authtoken'] = authtoken
flag, response = self.make_request(
'POST', self._commcell_object._services['WHO_AM_I'], headers=temp_headers
)
if flag:
if 'application/json' in response.headers['Content-Type']:
if response.json().get('errorCode', 0) == 0:
return response.json()['user']['userName']
else:
raise SDKException('CVPySDK', '107')
else:
user_dict = xmltodict.parse(response.content)
if 'CvEntities_ProcessingInstructionInfo' in user_dict:
return user_dict['CvEntities_ProcessingInstructionInfo']['user']['@userName']
else:
raise SDKException('CVPySDK', '107')
else:
response_string = self._commcell_object._update_response_(response.text)
raise SDKException('Response', '101', response_string)
def make_request(
self,
method,
url,
payload=None,
attempts=0,
headers=None,
stream=False,
files=None,
**kwargs):
"""Makes the request of the type specified in the argument 'method'.
Args:
method (str) -- HTTP operation to perform
e.g.:
- GET
- POST
- PUT
- DELETE
url (str) -- the web url or service to run the HTTP request on
payload (dict / str) -- data to be passed along with the request
default: None
attempts (int) -- number of attempts made with the same request
default: 0
headers (dict) -- dict of request headers for the request
if not specified we use default headers
default: None
stream (bool) -- boolean specifying whether the request should get
data via stream or normal get
default: False
files (dict) -- file to upload in the form of
{
'file': open('report.txt', 'rb')
}
default: None
Kwargs supported values:
remove_processing_info (bool) -- removes the processing instruction info from response.json()
Returns:
tuple:
(True, response) - in case of success
(False, response) - in case of failure
Raises:
SDKException:
if the method passed is incorrect / not supported
if the number of attempts exceed 3
requests Connection Error:
requests.exceptions.ConnectionError
"""
try:
if headers is None:
headers = self._commcell_object._headers.copy()
if method == 'POST':
if isinstance(payload, (dict, list)):
if files is not None:
response = self._request(method=method, url=url, files=files, data=payload)
else:
response = self._request(
method=method, url=url, headers=headers, json=payload, stream=stream
)
else:
try:
# call encode on the payload in case the characters in the payload
# are not encoded, and to encode the string payload to bytes
payload = payload.encode()
except AttributeError:
# pass silently if payload is alredy encoded in bytes
pass
if 'Content-type' in headers and headers['Content-type'] not in [
'application/x-www-form-urlencoded']:
try:
if payload is not None:
xmltodict.parse(payload)
headers['Content-type'] = 'application/xml'
except ExpatError:
headers['Content-type'] = 'text/plain'
response = self._request(
method=method, url=url, headers=headers, data=payload, stream=stream
)
elif method == 'GET':
response = self._request(method=method, url=url, headers=headers, stream=stream)
elif method == 'PUT':
response = self._request(method=method, url=url, headers=headers, json=payload)
elif method == 'DELETE':
response = self._request(method=method, url=url, headers=headers)
else:
raise SDKException('CVPySDK', '102', 'HTTP method {} not supported'.format(method))
# Processinginfo removal from response. It is under try catch to handle different response cases
# (Eg:DownloadStream API will return file stream in response)
try:
if kwargs.get('remove_processing_info', True) and 'processinginstructioninfo' in response.json():
del response.json()['processinginstructioninfo']
except Exception as e:
pass
if response.status_code == httplib.UNAUTHORIZED and headers.get('Authtoken') is not None:
if headers['Authtoken'].startswith('Bearer '):
raise SDKException('CVPySDK', '106')
if attempts < 3:
self._commcell_object._headers['Authtoken'] = self._renew_login_token()
return self.make_request(method, url, payload, attempts + 1)
else:
# Raise max attempts exception, if attempts exceeds 3
raise SDKException('CVPySDK', '103')
if (response.status_code == httplib.OK or response.status_code == httplib.CREATED) and response.ok:
return (True, response)
else:
return (False, response)
except requests.exceptions.ConnectionError as con_err:
raise con_err
Classes
class CVPySDK (commcell_object, certificate_path=None)
-
Helper class for login, and logout operations.
Also contains common method for running all HTTP requests.
Initialize the CVPySDK object for running various operations.
Args
commcell_object (object) – instance of the Commcell class
certificate_path (str) – path of the CA_BUNDLE or directory with certificates of trusted CAs (including trusted self-signed certificates)
default: None
Returns
object - instance of the CVPySDK class
Expand source code Browse git
class CVPySDK(object): """Helper class for login, and logout operations. Also contains common method for running all HTTP requests. """ def __init__(self, commcell_object, certificate_path=None): """Initialize the CVPySDK object for running various operations. Args: commcell_object (object) -- instance of the Commcell class certificate_path (str) -- path of the CA_BUNDLE or directory with certificates of trusted CAs (including trusted self-signed certificates) default: None Returns: object - instance of the CVPySDK class """ self._commcell_object = commcell_object self._certificate_path = certificate_path def _is_valid_service(self): """Checks if the service url is a valid url or not. Returns: True - if the service url is valid False - if the service url is invalid Raises: requests Connection Error: requests.exceptions.ConnectionError requests Timeout Error: requests.exceptions.Timeout """ try: response = self._request( method='GET', url=self._commcell_object._web_service, timeout=184 ) # Valid service if the status code is 200 and response is True return response.status_code == httplib.OK and response.ok except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as error: raise error def _login(self): """Posts a login request to the server. Returns: str - Authtoken received from the WebServer upon successfull login Raises: SDKException: if login failed if response is empty if response is not success requests Connection Error: requests.exceptions.ConnectionError """ try: if isinstance(self._commcell_object._password, dict): raise SDKException('CVPySDK', '104') if self._commcell_object.is_service_commcell: json_login_request = { "mode": 4, "clientType": 30, "autoLogin": { "autoLoginType": 5, "encryptedMessage": self._commcell_object.master_saml_token } } else: json_login_request = { "mode": 4, "username": self._commcell_object._user, "password": self._commcell_object._password, "deviceId": self._commcell_object.device_id, "clientType": 30, } flag, response = self.make_request( 'POST', self._commcell_object._services['LOGIN'], json_login_request ) if flag: if response.json(): if "userName" in response.json() and "token" in response.json(): return response.json()['token'] else: error_message = response.json()['errList'][0]['errLogMessage'] err_msg = 'Error: "{0}"'.format(error_message) raise SDKException('CVPySDK', '101', err_msg) else: raise SDKException('Response', '102') else: response_string = self._commcell_object._update_response_(response.text) raise SDKException('Response', '101', response_string) except requests.exceptions.ConnectionError as con_err: raise con_err def _renew_login_token(self): """Posts a Renew Login-Token request to the server. Returns: str - new token received from the WebServer Raises: SDKException: if token renew failed if response is empty if response is not success requests Connection Error: requests.exceptions.ConnectionError """ try: if self._commcell_object._is_saml_login and not self._commcell_object.is_service_commcell: raise SDKException('CVPySDK', '106') token_renew_request = { "sessionId": self._commcell_object._headers['Authtoken'], "deviceId": self._commcell_object.device_id } flag, response = self.make_request( 'POST', self._commcell_object._services['RENEW_LOGIN_TOKEN'], token_renew_request ) if flag: if response.json(): if "token" in response.json(): return response.json()['token'] else: error_message = response.json()['error']['errLogMessage'] err_msg = 'Error: "{0}"'.format(error_message) raise SDKException('CVPySDK', '101', err_msg) else: raise SDKException('Response', '102') else: response_string = self._commcell_object._update_response_(response.text) raise SDKException('Response', '101', response_string) except requests.exceptions.ConnectionError as con_err: raise con_err def _logout(self): """Posts a logout request to the server. Returns: str - response string from server upon logout success """ flag, response = self.make_request('POST', self._commcell_object._services['LOGOUT']) if flag: self._commcell_object._headers['Authtoken'] = None if response.status_code == httplib.OK: return response.text else: return 'Failed to logout the user' else: return 'User already logged out' def _request(self, **kwargs): """Executes the request on the Server with the given parameters. If the certificate path is given and the Web Service starts with **https**, it adds the **verify** parameter to the request, and passes the certificate path as its value. Args: **kwargs -- dict of keyword arguments, same as accepted by the **requests.request** method Returns: object - **requests.Response** class instance, as received from calling the **requests.request** method """ if self._certificate_path and self._commcell_object._web_service.startswith('https'): return requests.request(verify=self._certificate_path, **kwargs) return requests.request(**kwargs) def who_am_i(self, authtoken=None): """Get the username of the user, to whom the Authtoken belongs to. Args: authtoken (str) -- QSDK or SAML authentication token Returns: str - username of the user respective to the token Raises: SDKException: if no user mapping found """ temp_headers = self._commcell_object._headers.copy() if authtoken: temp_headers['Authtoken'] = authtoken flag, response = self.make_request( 'POST', self._commcell_object._services['WHO_AM_I'], headers=temp_headers ) if flag: if 'application/json' in response.headers['Content-Type']: if response.json().get('errorCode', 0) == 0: return response.json()['user']['userName'] else: raise SDKException('CVPySDK', '107') else: user_dict = xmltodict.parse(response.content) if 'CvEntities_ProcessingInstructionInfo' in user_dict: return user_dict['CvEntities_ProcessingInstructionInfo']['user']['@userName'] else: raise SDKException('CVPySDK', '107') else: response_string = self._commcell_object._update_response_(response.text) raise SDKException('Response', '101', response_string) def make_request( self, method, url, payload=None, attempts=0, headers=None, stream=False, files=None, **kwargs): """Makes the request of the type specified in the argument 'method'. Args: method (str) -- HTTP operation to perform e.g.: - GET - POST - PUT - DELETE url (str) -- the web url or service to run the HTTP request on payload (dict / str) -- data to be passed along with the request default: None attempts (int) -- number of attempts made with the same request default: 0 headers (dict) -- dict of request headers for the request if not specified we use default headers default: None stream (bool) -- boolean specifying whether the request should get data via stream or normal get default: False files (dict) -- file to upload in the form of { 'file': open('report.txt', 'rb') } default: None Kwargs supported values: remove_processing_info (bool) -- removes the processing instruction info from response.json() Returns: tuple: (True, response) - in case of success (False, response) - in case of failure Raises: SDKException: if the method passed is incorrect / not supported if the number of attempts exceed 3 requests Connection Error: requests.exceptions.ConnectionError """ try: if headers is None: headers = self._commcell_object._headers.copy() if method == 'POST': if isinstance(payload, (dict, list)): if files is not None: response = self._request(method=method, url=url, files=files, data=payload) else: response = self._request( method=method, url=url, headers=headers, json=payload, stream=stream ) else: try: # call encode on the payload in case the characters in the payload # are not encoded, and to encode the string payload to bytes payload = payload.encode() except AttributeError: # pass silently if payload is alredy encoded in bytes pass if 'Content-type' in headers and headers['Content-type'] not in [ 'application/x-www-form-urlencoded']: try: if payload is not None: xmltodict.parse(payload) headers['Content-type'] = 'application/xml' except ExpatError: headers['Content-type'] = 'text/plain' response = self._request( method=method, url=url, headers=headers, data=payload, stream=stream ) elif method == 'GET': response = self._request(method=method, url=url, headers=headers, stream=stream) elif method == 'PUT': response = self._request(method=method, url=url, headers=headers, json=payload) elif method == 'DELETE': response = self._request(method=method, url=url, headers=headers) else: raise SDKException('CVPySDK', '102', 'HTTP method {} not supported'.format(method)) # Processinginfo removal from response. It is under try catch to handle different response cases # (Eg:DownloadStream API will return file stream in response) try: if kwargs.get('remove_processing_info', True) and 'processinginstructioninfo' in response.json(): del response.json()['processinginstructioninfo'] except Exception as e: pass if response.status_code == httplib.UNAUTHORIZED and headers.get('Authtoken') is not None: if headers['Authtoken'].startswith('Bearer '): raise SDKException('CVPySDK', '106') if attempts < 3: self._commcell_object._headers['Authtoken'] = self._renew_login_token() return self.make_request(method, url, payload, attempts + 1) else: # Raise max attempts exception, if attempts exceeds 3 raise SDKException('CVPySDK', '103') if (response.status_code == httplib.OK or response.status_code == httplib.CREATED) and response.ok: return (True, response) else: return (False, response) except requests.exceptions.ConnectionError as con_err: raise con_err
Methods
def make_request(self, method, url, payload=None, attempts=0, headers=None, stream=False, files=None, **kwargs)
-
Makes the request of the type specified in the argument 'method'.
Args
method (str) – HTTP operation to perform
e.g.: - GET - POST - PUT - DELETE
url (str) – the web url or service to run the HTTP request on
payload (dict / str) – data to be passed along with the request
default: None
attempts (int) – number of attempts made with the same request
default: 0
headers (dict) – dict of request headers for the request
if not specified we use default headers default: None
stream (bool) – boolean specifying whether the request should get data via stream or normal get
default: False
files (dict) – file to upload in the form of
{ 'file': open('report.txt', 'rb') } default: None
Kwargs supported values:
remove_processing_info (bool) -- removes the processing instruction info from response.json()
Returns
tuple: (True, response) - in case of success
(False, response) - in case of failure
Raises
SDKException: if the method passed is incorrect / not supported
if the number of attempts exceed 3
requests Connection Error: requests.exceptions.ConnectionError
Expand source code Browse git
def make_request( self, method, url, payload=None, attempts=0, headers=None, stream=False, files=None, **kwargs): """Makes the request of the type specified in the argument 'method'. Args: method (str) -- HTTP operation to perform e.g.: - GET - POST - PUT - DELETE url (str) -- the web url or service to run the HTTP request on payload (dict / str) -- data to be passed along with the request default: None attempts (int) -- number of attempts made with the same request default: 0 headers (dict) -- dict of request headers for the request if not specified we use default headers default: None stream (bool) -- boolean specifying whether the request should get data via stream or normal get default: False files (dict) -- file to upload in the form of { 'file': open('report.txt', 'rb') } default: None Kwargs supported values: remove_processing_info (bool) -- removes the processing instruction info from response.json() Returns: tuple: (True, response) - in case of success (False, response) - in case of failure Raises: SDKException: if the method passed is incorrect / not supported if the number of attempts exceed 3 requests Connection Error: requests.exceptions.ConnectionError """ try: if headers is None: headers = self._commcell_object._headers.copy() if method == 'POST': if isinstance(payload, (dict, list)): if files is not None: response = self._request(method=method, url=url, files=files, data=payload) else: response = self._request( method=method, url=url, headers=headers, json=payload, stream=stream ) else: try: # call encode on the payload in case the characters in the payload # are not encoded, and to encode the string payload to bytes payload = payload.encode() except AttributeError: # pass silently if payload is alredy encoded in bytes pass if 'Content-type' in headers and headers['Content-type'] not in [ 'application/x-www-form-urlencoded']: try: if payload is not None: xmltodict.parse(payload) headers['Content-type'] = 'application/xml' except ExpatError: headers['Content-type'] = 'text/plain' response = self._request( method=method, url=url, headers=headers, data=payload, stream=stream ) elif method == 'GET': response = self._request(method=method, url=url, headers=headers, stream=stream) elif method == 'PUT': response = self._request(method=method, url=url, headers=headers, json=payload) elif method == 'DELETE': response = self._request(method=method, url=url, headers=headers) else: raise SDKException('CVPySDK', '102', 'HTTP method {} not supported'.format(method)) # Processinginfo removal from response. It is under try catch to handle different response cases # (Eg:DownloadStream API will return file stream in response) try: if kwargs.get('remove_processing_info', True) and 'processinginstructioninfo' in response.json(): del response.json()['processinginstructioninfo'] except Exception as e: pass if response.status_code == httplib.UNAUTHORIZED and headers.get('Authtoken') is not None: if headers['Authtoken'].startswith('Bearer '): raise SDKException('CVPySDK', '106') if attempts < 3: self._commcell_object._headers['Authtoken'] = self._renew_login_token() return self.make_request(method, url, payload, attempts + 1) else: # Raise max attempts exception, if attempts exceeds 3 raise SDKException('CVPySDK', '103') if (response.status_code == httplib.OK or response.status_code == httplib.CREATED) and response.ok: return (True, response) else: return (False, response) except requests.exceptions.ConnectionError as con_err: raise con_err
def who_am_i(self, authtoken=None)
-
Get the username of the user, to whom the Authtoken belongs to.
Args
authtoken (str) – QSDK or SAML authentication token
Returns
str - username of the user respective to the token
Raises
SDKException: if no user mapping found
Expand source code Browse git
def who_am_i(self, authtoken=None): """Get the username of the user, to whom the Authtoken belongs to. Args: authtoken (str) -- QSDK or SAML authentication token Returns: str - username of the user respective to the token Raises: SDKException: if no user mapping found """ temp_headers = self._commcell_object._headers.copy() if authtoken: temp_headers['Authtoken'] = authtoken flag, response = self.make_request( 'POST', self._commcell_object._services['WHO_AM_I'], headers=temp_headers ) if flag: if 'application/json' in response.headers['Content-Type']: if response.json().get('errorCode', 0) == 0: return response.json()['user']['userName'] else: raise SDKException('CVPySDK', '107') else: user_dict = xmltodict.parse(response.content) if 'CvEntities_ProcessingInstructionInfo' in user_dict: return user_dict['CvEntities_ProcessingInstructionInfo']['user']['@userName'] else: raise SDKException('CVPySDK', '107') else: response_string = self._commcell_object._update_response_(response.text) raise SDKException('Response', '101', response_string)