def set_credentials(self, username, secret): """Set the username and generate the user token. username - your registered e-mail address secret - the auto-generated API version 2 secret """ if None not in [secret, username]: self._usertoken = WSSEUserTokenHeaderGenerator(username, secret) else: self._usertoken = None
class HandsetDetection(object): "An object for accessing the Handset Detection API v2.0" _baseUrl = "http://api.handsetdetection.com" # This API key is the key for this Python module. You should create a new # key if you substially modify this code. You can set a new key with # set_v2_api_key. _apikey = "f923560d264b752bcd84c2cd0b0695e7" # Initialization def __init__(self, username=None, secret=None): "Initialize the api object." self._usertoken = None self._usejson = JSON_FOUND self.set_credentials(username, secret) # Public methods def set_credentials(self, username, secret): """Set the username and generate the user token. username - your registered e-mail address secret - the auto-generated API version 2 secret """ if None not in [secret, username]: self._usertoken = WSSEUserTokenHeaderGenerator(username, secret) else: self._usertoken = None def set_v2_apikey(self, apikey): """Set the API key used by the object. This does not modify the API key of newly constructed objects. To do that, change the value on the class: HandsetDetection.set_class_v2_apikey(my_apikey) """ self._apikey = apikey @classmethod def set_class_v2_apikey(cls, apikey): "Set the API key used on all new HandsetDetection instances." cls._apikey = apikey def detect(self, data, options): """Detect a handset with the User-Agent and/or other information. data - a dictionary containing a User-Agent, IP address, x-wap-profile, and any other information that may be useful in identifying the handset options - a string or list of options to be returned from your query, e.g., "geoip,product_info,display" or ["geoip", "product_info"], etc. """ self._check_usertoken() assert isinstance(data, dict) if isinstance(options, list): options = ",".join(options) data["options"] = options result = self._do_request("detect", data) deviceinformation = HandsetDetectionDeviceInformation(result) deviceinformation.pop("status") deviceinformation.pop("message") return deviceinformation def model(self, vendorname): "Returns a list of models for the given vendor." self._check_usertoken() data = {"vendor": vendorname} # Yes, that's supposed to be "models" result = self._do_request("models", data) return "model" in result and result["model"] or [] def track(self, data): """Track a user's requests. data - a dictionary containing a User-Agent, IP address, x-wap-profile, and any other information that may be useful in identifying the handset """ self._check_usertoken() self._do_request("track", data) # There's nothing to return when this works. return None def vendor(self): "Returns a list of vendors." self._check_usertoken() data = {} # Yes, that's supposed to be "vendors" result = self._do_request("vendors", data) return "vendor" in result and result["vendor"] or [] # Private methods def _build_headers(self): "Send the request to Handset Detection." # Headers # Authorization headers headers = self._usertoken.next() # ApiKey header headers["ApiKey"] = self._apikey # Content-type header contenttype = self._usejson and "application/json" or "text/xml" headers["Content-type"] = contenttype return headers def _build_url(self, method): "Build the url for a request." # Yes, models and vendors are supposed to be plural... assert method in ["detect", "models", "track", "vendors"] import urlparse parts = {} parts["method"] = method parts["suffix"] = self._usejson and "json" or "xml" urlpath = "/devices/%(method)s.%(suffix)s" % parts url = urlparse.urljoin(self._baseUrl, urlpath) return url @staticmethod def _check_status(data): "Raise the appropriate error if status != '0'." status = int(data["status"]) if 0 != status: exception = { 100: exceptions.UnknownRequestTypeError, 200: exceptions.CredentialsFailedError, 201: exceptions.UnmatchedDigestError, 202: exceptions.ApiKeyError, 203: exceptions.MaxQueriesError, 204: exceptions.MalformedXmlError, 205: exceptions.MalformedJsonError, 206: exceptions.NoDataError, 207: exceptions.VendorMissingError, # This doesn't support version 1.0. #208: exceptions.ApiKeyNotFoundError, 209: exceptions.ApiKeyNotSetError, 300: exceptions.UserAgentOrProfileMissingWarning, 301: exceptions.DeviceNotFoundError, }.get(status, ValueError) raise exception(status, data["message"], data) else: return None def _check_usertoken(self): "Raise a ValueError if the module is not initialized before use." if not isinstance(self._usertoken, WSSEUserTokenHeaderGenerator): raise ValueError("Call set_credentials() before calling API " "functions.") def _do_request(self, method, data): "Send the request to Handset Detection." headers = self._build_headers() url = self._build_url(method) postdata = self._serialize_data(data) request = HandsetDetectionRequest(url, postdata, headers) response = request.send() if response.code == 200: data = self._parse_data(method, response) self._check_status(data) return data else: assert False, ("response.code != 200 - urllib2 should have thrown " "an exception.") def _parse_data(self, method, response): "Convert the server's response into something meaningful." if self._usejson: result = self._parse_json(response) else: result = self._parse_xml(method, response) return result @staticmethod def _parse_json(response): "Convert JSON into meaningful data." result = json.load(response) return result def _parse_xml(self, method, response): "Convert XML into meaningful data." class _ModelVendorHandler(xml.sax.handler.ContentHandler): "A content handler for HD API's XML." ignoretags = ["reply"] sequencetags = ["model", "vendor"] def __init__(self): "Initialize the ModelVendorHandler." xml.sax.handler.ContentHandler.__init__(self) self.newelement = False self.currentelement = None self.result = {} def startElement(self, name, attrs): "Entering an element" self.currentelement = name if (name not in self.ignoretags and name in self.sequencetags): self.newelement = True if name not in self.result: self.result[name] = [] def characters(self, data): "Encountered character data" # Ignore cases where data == "\n" if self.currentelement not in self.ignoretags and data.strip(): if self.currentelement in self.sequencetags: if self.newelement: self.result[self.currentelement].append(data) else: sequence = self.result[self.currentelement] if len(sequence) > 0: oldstring = sequence[-1] sequence[-1] = u"".join([oldstring, data]) else: self.result[self.currentelement].append(data) self.newelement = False else: self.result[self.currentelement] = data class _DetectTrackHandler(xml.sax.handler.ContentHandler): "A content handler for HD API's XML." ignoretags = ["reply"] grouptags = ["product_info", "wml_ui", "chtml_ui", "xhtml_ui", "ajax", "markup", "cache", "display", "image_format", "bugs", "wta", "security", "bearer", "storage", "object_download", "drm", "streaming", "wap_push", "mms", "sms", "j2me", "sound_format", "flash_lite", "geoip" ] def __init__(self): "Initialize the DetectTrackHandler." xml.sax.handler.ContentHandler.__init__(self) self.currentelement = None self.elementlist = [] self.result = {} def startElement(self, name, attrs): "Entering an element" self.elementlist.append(name) if (name not in self.ignoretags and name not in self.result and name in self.grouptags): self.result[name] = {} def endElement(self, name): "Leaving an element" self.elementlist.pop() def characters(self, data): "Encountered character data" name = self.elementlist and self.elementlist[-1] or None parent = (len(self.elementlist) > 1 and self.elementlist[-2] or None) # Ignore cases where data == "\n" if name not in self.ignoretags and data.strip(): if parent in self.grouptags: groupdictionary = self.result[parent] groupdictionary[name] = data else: self.result[name] = data # Now, parse the data parser = xml.sax.make_parser() if method in ["models", "vendors"]: contenthandler = _ModelVendorHandler() elif method in ["detect", "track"]: contenthandler = _DetectTrackHandler() else: raise ValueError("No handler for a %r method." % method) parser.setContentHandler(contenthandler) parser.parse(response) return contenthandler.result def _serialize_data(self, data): "Convert the data structure into something that can be posted." if self._usejson: result = self._serialize_json(data) else: result = self._serialize_xml(data) return result @staticmethod def _serialize_json(data): "Convert data into meaningful JSON." return json.dumps(data) @staticmethod def _serialize_xml(data): "Convert data into meaningful XML." # There is no document sent for empty data if not data: return "" import StringIO resultio = StringIO.StringIO() xmlgenerator = xml.sax.saxutils.XMLGenerator(resultio, "UTF-8") xmlgenerator.startDocument() # Start request element xmlgenerator.startElement(u"request", {}) # Fill in all the data for key, value in data.items(): xmlgenerator.startElement(key, {}) valuetext = xml.sax.saxutils.escape(value) xmlgenerator.characters(valuetext) xmlgenerator.endElement(key) # End request element xmlgenerator.endElement(u"request") xmlgenerator.endDocument() return resultio.getvalue()
class HandsetDetection(object): "An object for accessing the Handset Detection API v2.0" _baseUrl = "http://api.handsetdetection.com" # This API key is the key for this Python module. You should create a new # key if you substially modify this code. You can set a new key with # set_v2_api_key. _apikey = "f923560d264b752bcd84c2cd0b0695e7" # Initialization def __init__(self, username=None, secret=None): "Initialize the api object." self._usertoken = None self._usejson = JSON_FOUND self.set_credentials(username, secret) # Public methods def set_credentials(self, username, secret): """Set the username and generate the user token. username - your registered e-mail address secret - the auto-generated API version 2 secret """ if None not in [secret, username]: self._usertoken = WSSEUserTokenHeaderGenerator(username, secret) else: self._usertoken = None def set_v2_apikey(self, apikey): """Set the API key used by the object. This does not modify the API key of newly constructed objects. To do that, change the value on the class: HandsetDetection.set_class_v2_apikey(my_apikey) """ self._apikey = apikey @classmethod def set_class_v2_apikey(cls, apikey): "Set the API key used on all new HandsetDetection instances." cls._apikey = apikey def detect(self, data, options): """Detect a handset with the User-Agent and/or other information. data - a dictionary containing a User-Agent, IP address, x-wap-profile, and any other information that may be useful in identifying the handset options - a string or list of options to be returned from your query, e.g., "geoip,product_info,display" or ["geoip", "product_info"], etc. """ self._check_usertoken() assert isinstance(data, dict) if isinstance(options, list): options = ",".join(options) data["options"] = options result = self._do_request("detect", data) deviceinformation = HandsetDetectionDeviceInformation(result) deviceinformation.pop("status") deviceinformation.pop("message") return deviceinformation def model(self, vendorname): "Returns a list of models for the given vendor." self._check_usertoken() data = {"vendor": vendorname} # Yes, that's supposed to be "models" result = self._do_request("models", data) return "model" in result and result["model"] or [] def track(self, data): """Track a user's requests. data - a dictionary containing a User-Agent, IP address, x-wap-profile, and any other information that may be useful in identifying the handset """ self._check_usertoken() self._do_request("track", data) # There's nothing to return when this works. return None def vendor(self): "Returns a list of vendors." self._check_usertoken() data = {} # Yes, that's supposed to be "vendors" result = self._do_request("vendors", data) return "vendor" in result and result["vendor"] or [] # Private methods def _build_headers(self): "Send the request to Handset Detection." # Headers # Authorization headers headers = self._usertoken.next() # ApiKey header headers["ApiKey"] = self._apikey # Content-type header contenttype = self._usejson and "application/json" or "text/xml" headers["Content-type"] = contenttype return headers def _build_url(self, method): "Build the url for a request." # Yes, models and vendors are supposed to be plural... assert method in ["detect", "models", "track", "vendors"] import urlparse parts = {} parts["method"] = method parts["suffix"] = self._usejson and "json" or "xml" urlpath = "/devices/%(method)s.%(suffix)s" % parts url = urlparse.urljoin(self._baseUrl, urlpath) return url @staticmethod def _check_status(data): "Raise the appropriate error if status != '0'." status = int(data["status"]) if 0 != status: exception = { 100: exceptions.UnknownRequestTypeError, 200: exceptions.CredentialsFailedError, 201: exceptions.UnmatchedDigestError, 202: exceptions.ApiKeyError, 203: exceptions.MaxQueriesError, 204: exceptions.MalformedXmlError, 205: exceptions.MalformedJsonError, 206: exceptions.NoDataError, 207: exceptions.VendorMissingError, # This doesn't support version 1.0. #208: exceptions.ApiKeyNotFoundError, 209: exceptions.ApiKeyNotSetError, 300: exceptions.UserAgentOrProfileMissingWarning, 301: exceptions.DeviceNotFoundError, }.get(status, ValueError) raise exception(status, data["message"], data) else: return None def _check_usertoken(self): "Raise a ValueError if the module is not initialized before use." if not isinstance(self._usertoken, WSSEUserTokenHeaderGenerator): raise ValueError("Call set_credentials() before calling API " "functions.") def _do_request(self, method, data): "Send the request to Handset Detection." headers = self._build_headers() url = self._build_url(method) postdata = self._serialize_data(data) request = HandsetDetectionRequest(url, postdata, headers) response = request.send() if response.code == 200: data = self._parse_data(method, response) self._check_status(data) return data else: assert False, ("response.code != 200 - urllib2 should have thrown " "an exception.") def _parse_data(self, method, response): "Convert the server's response into something meaningful." if self._usejson: result = self._parse_json(response) else: result = self._parse_xml(method, response) return result @staticmethod def _parse_json(response): "Convert JSON into meaningful data." result = json.load(response) return result def _parse_xml(self, method, response): "Convert XML into meaningful data." class _ModelVendorHandler(xml.sax.handler.ContentHandler): "A content handler for HD API's XML." ignoretags = ["reply"] sequencetags = ["model", "vendor"] def __init__(self): "Initialize the ModelVendorHandler." xml.sax.handler.ContentHandler.__init__(self) self.newelement = False self.currentelement = None self.result = {} def startElement(self, name, attrs): "Entering an element" self.currentelement = name if (name not in self.ignoretags and name in self.sequencetags): self.newelement = True if name not in self.result: self.result[name] = [] def characters(self, data): "Encountered character data" # Ignore cases where data == "\n" if self.currentelement not in self.ignoretags and data.strip(): if self.currentelement in self.sequencetags: if self.newelement: self.result[self.currentelement].append(data) else: sequence = self.result[self.currentelement] if len(sequence) > 0: oldstring = sequence[-1] sequence[-1] = u"".join([oldstring, data]) else: self.result[self.currentelement].append(data) self.newelement = False else: self.result[self.currentelement] = data class _DetectTrackHandler(xml.sax.handler.ContentHandler): "A content handler for HD API's XML." ignoretags = ["reply"] grouptags = [ "product_info", "wml_ui", "chtml_ui", "xhtml_ui", "ajax", "markup", "cache", "display", "image_format", "bugs", "wta", "security", "bearer", "storage", "object_download", "drm", "streaming", "wap_push", "mms", "sms", "j2me", "sound_format", "flash_lite", "geoip" ] def __init__(self): "Initialize the DetectTrackHandler." xml.sax.handler.ContentHandler.__init__(self) self.currentelement = None self.elementlist = [] self.result = {} def startElement(self, name, attrs): "Entering an element" self.elementlist.append(name) if (name not in self.ignoretags and name not in self.result and name in self.grouptags): self.result[name] = {} def endElement(self, name): "Leaving an element" self.elementlist.pop() def characters(self, data): "Encountered character data" name = self.elementlist and self.elementlist[-1] or None parent = (len(self.elementlist) > 1 and self.elementlist[-2] or None) # Ignore cases where data == "\n" if name not in self.ignoretags and data.strip(): if parent in self.grouptags: groupdictionary = self.result[parent] groupdictionary[name] = data else: self.result[name] = data # Now, parse the data parser = xml.sax.make_parser() if method in ["models", "vendors"]: contenthandler = _ModelVendorHandler() elif method in ["detect", "track"]: contenthandler = _DetectTrackHandler() else: raise ValueError("No handler for a %r method." % method) parser.setContentHandler(contenthandler) parser.parse(response) return contenthandler.result def _serialize_data(self, data): "Convert the data structure into something that can be posted." if self._usejson: result = self._serialize_json(data) else: result = self._serialize_xml(data) return result @staticmethod def _serialize_json(data): "Convert data into meaningful JSON." return json.dumps(data) @staticmethod def _serialize_xml(data): "Convert data into meaningful XML." # There is no document sent for empty data if not data: return "" import StringIO resultio = StringIO.StringIO() xmlgenerator = xml.sax.saxutils.XMLGenerator(resultio, "UTF-8") xmlgenerator.startDocument() # Start request element xmlgenerator.startElement(u"request", {}) # Fill in all the data for key, value in data.items(): xmlgenerator.startElement(key, {}) valuetext = xml.sax.saxutils.escape(value) xmlgenerator.characters(valuetext) xmlgenerator.endElement(key) # End request element xmlgenerator.endElement(u"request") xmlgenerator.endDocument() return resultio.getvalue()