Package fedex :: Module base_service
[hide private]
[frames] | no frames]

Source Code for Module fedex.base_service

  1  """ 
  2  The L{base_service} module contains classes that form the low level foundations 
  3  of the Web Service API. Things that many different kinds of requests have in 
  4  common may be found here. 
  5   
  6  In particular, the L{FedexBaseService} class handles most of the basic, 
  7  repetetive setup work that most requests do. 
  8  """ 
  9  import os 
 10  import logging 
 11  import suds 
 12  from suds.client import Client 
 13   
14 -class FedexBaseServiceException(Exception):
15 """ 16 Exception: Serves as the base exception that other service-related 17 exception objects are sub-classed from. 18 """
19 - def __init__(self, error_code, value):
20 self.error_code = error_code 21 self.value = value
22 - def __unicode__(self):
23 return "%s (Error code: %s)" % (repr(self.value), self.error_code)
24 - def __str__(self):
25 return self.__unicode__()
26
27 -class FedexFailure(FedexBaseServiceException):
28 """ 29 Exception: The request could not be handled at this time. This is generally 30 a server problem. 31 """ 32 pass
33
34 -class FedexError(FedexBaseServiceException):
35 """ 36 Exception: These are generally problems with the client-provided data. 37 """ 38 pass
39
40 -class SchemaValidationError(FedexBaseServiceException):
41 """ 42 Exception: There is probably a problem in the data you provided. 43 """
44 - def __init__(self):
45 self.error_code = -1 46 self.value = "suds encountered an error validating your data against this service's WSDL schema. Please double-check for missing or invalid values, filling all required fields."
47
48 -class FedexBaseService(object):
49 """ 50 This class is the master class for all Fedex request objects. It gets all 51 of the common SOAP objects created via suds and populates them with 52 values from a L{FedexConfig} object, along with keyword arguments 53 via L{__init__}. 54 55 @note: This object should never be used directly, use one of the included 56 sub-classes. 57 """
58 - def __init__(self, config_obj, wsdl_name, *args, **kwargs):
59 """ 60 This constructor should only be called by children of the class. As is 61 such, only the optional keyword arguments caught by C{**kwargs} will 62 be documented. 63 64 @type customer_transaction_id: L{str} 65 @keyword customer_transaction_id: A user-specified identifier to 66 differentiate this transaction from others. This value will be 67 returned with the response from Fedex. 68 """ 69 self.logger = logging.getLogger('fedex') 70 """@ivar: Python logger instance with name 'fedex'.""" 71 self.config_obj = config_obj 72 """@ivar: The FedexConfig object to pull auth info from.""" 73 74 # If the config object is set to use the test server, point 75 # suds at the test server WSDL directory. 76 if config_obj.use_test_server: 77 self.logger.info("Using test server.") 78 self.wsdl_path = os.path.join(config_obj.wsdl_path, 79 'test_server_wsdl', wsdl_name) 80 else: 81 self.logger.info("Using production server.") 82 self.wsdl_path = os.path.join(config_obj.wsdl_path, wsdl_name) 83 84 self.client = Client('file://%s' % self.wsdl_path) 85 86 #print self.client 87 88 self.VersionId = None 89 """@ivar: Holds details on the version numbers of the WSDL.""" 90 self.WebAuthenticationDetail = None 91 """@ivar: WSDL object that holds authentication info.""" 92 self.ClientDetail = None 93 """@ivar: WSDL object that holds client account details.""" 94 self.response = None 95 """@ivar: The response from Fedex. You will want to pick what you 96 want out here here. This object does have a __str__() method, 97 you'll want to print or log it to see what possible values 98 you can pull.""" 99 self.TransactionDetail = None 100 """@ivar: Holds customer-specified transaction IDs.""" 101 102 self.__set_web_authentication_detail() 103 self.__set_client_detail() 104 self.__set_version_id() 105 self.__set_transaction_detail(*args, **kwargs) 106 self._prepare_wsdl_objects()
107
109 """ 110 Sets up the WebAuthenticationDetail node. This is required for all 111 requests. 112 """ 113 # Start of the authentication stuff. 114 WebAuthenticationCredential = self.client.factory.create('WebAuthenticationCredential') 115 WebAuthenticationCredential.Key = self.config_obj.key 116 WebAuthenticationCredential.Password = self.config_obj.password 117 118 # Encapsulates the auth credentials. 119 WebAuthenticationDetail = self.client.factory.create('WebAuthenticationDetail') 120 WebAuthenticationDetail.UserCredential = WebAuthenticationCredential 121 self.WebAuthenticationDetail = WebAuthenticationDetail
122
123 - def __set_client_detail(self):
124 """ 125 Sets up the ClientDetail node, which is required for all shipping 126 related requests. 127 """ 128 ClientDetail = self.client.factory.create('ClientDetail') 129 ClientDetail.AccountNumber = self.config_obj.account_number 130 ClientDetail.MeterNumber = self.config_obj.meter_number 131 ClientDetail.IntegratorId = self.config_obj.integrator_id 132 self.ClientDetail = ClientDetail
133
134 - def __set_transaction_detail(self, *args, **kwargs):
135 """ 136 Checks kwargs for 'customer_transaction_id' and sets it if present. 137 """ 138 customer_transaction_id = kwargs.get('customer_transaction_id', False) 139 if customer_transaction_id: 140 TransactionDetail = self.client.factory.create('TransactionDetail') 141 TransactionDetail.CustomerTransactionId = customer_transaction_id 142 self.logger.debug(TransactionDetail) 143 self.TransactionDetail = TransactionDetail
144
145 - def __set_version_id(self):
146 """ 147 Pulles the versioning info for the request from the child request. 148 """ 149 VersionId = self.client.factory.create('VersionId') 150 VersionId.ServiceId = self._version_info['service_id'] 151 VersionId.Major = self._version_info['major'] 152 VersionId.Intermediate = self._version_info['intermediate'] 153 VersionId.Minor = self._version_info['minor'] 154 self.logger.debug(VersionId) 155 self.VersionId = VersionId
156
157 - def __prepare_wsdl_objects(self):
158 """ 159 This method should be over-ridden on each sub-class. It instantiates 160 any of the required WSDL objects so the user can just print their 161 __str__() methods and see what they need to fill in. 162 """ 163 pass
164
166 """ 167 This checks the response for general Fedex errors that aren't related 168 to any one WSDL. 169 """ 170 if self.response.HighestSeverity == "FAILURE": 171 for notification in self.response.Notifications: 172 if notification.Severity == "FAILURE": 173 raise FedexFailure(notification.Code, 174 notification.Message)
175
177 """ 178 Override this in each service module to check for errors that are 179 specific to that module. For example, invalid tracking numbers in 180 a Tracking request. 181 """ 182 if self.response.HighestSeverity == "ERROR": 183 for notification in self.response.Notifications: 184 if notification.Severity == "ERROR": 185 raise FedexError(notification.Code, 186 notification.Message)
187
188 - def create_wsdl_object_of_type(self, type_name):
189 """ 190 Creates and returns a WSDL object of the specified type. 191 """ 192 return self.client.factory.create(type_name)
193
194 - def send_request(self, send_function=None):
195 """ 196 Sends the assembled request on the child object. 197 @type send_function: function reference 198 @keyword send_function: A function reference (passed without the 199 parenthesis) to a function that will send the request. This 200 allows for overriding the default function in cases such as 201 validation requests. 202 """ 203 # Send the request and get the response back. 204 try: 205 # If the user has overridden the send function, use theirs 206 # instead of the default. 207 if send_function: 208 # Follow the overridden function. 209 self.response = send_function() 210 else: 211 # Default scenario, business as usual. 212 self.response = self._assemble_and_send_request() 213 except suds.WebFault: 214 # When this happens, throw an informative message reminding the 215 # user to check all required variables, making sure they are 216 # populated and valid. 217 raise SchemaValidationError() 218 219 # Check the response for general Fedex errors/failures that aren't 220 # specific to any given WSDL/request. 221 self.__check_response_for_fedex_error() 222 # Check the response for errors specific to the particular request. 223 # This is handled by an overridden method on the child object. 224 self._check_response_for_request_errors() 225 226 # Debug output. 227 self.logger.debug("== FEDEX QUERY RESULT ==") 228 self.logger.debug(self.response)
229