{ "info": { "author": "mFabrik Research Oy", "author_email": "research@mfabrik.com", "bugtrack_url": null, "classifiers": [ "Programming Language :: Python" ], "description": ".. contents ::\n\nIntroduction\n------------\n\n``mobile.sniffer`` is Python framework for abstracting mobile browser detection and feature database access.\n\nWhen rendering web pages for mobile phones one must deal with varying handset features: \ndifferent screen sizes and shapes, different supported file formats, different sets of web browser features. \nAlso, the fact that you know the user is browsing on a mobile phone is most critical for building\nsuccessful mobile web user experience.\n\n``mobile.sniffer`` provides two phase mobile phone detection (a.k.a sniffing) \n\n* *mobile detection* - this simply detects whether a browser is a mobile phone based or not.\n This is done in ``mobile/sniffer/detect.py`` module. This is useful to redirect to your\n visitors from a web site to a mobile site if they are using a mobile phone to arrive on your web site.\n \n* *mobile handset feature extraction* - the handset database is looked for a mobile web browser\n user agent match. Since there might be version changes, local varieties, etc. in user agent \n strings, heurestics are applied to the string matching. If a database entry is found, with\n certain match accuracy, it's records like device screen width and height are made\n available to the web server so that it can tailor HTML, image and video output suitable\n for this particular mobile phone.\n\nMobile detection can be done with a fast regular expression match. Mobile handset feature\nextraction always requires a some sort of database of mobile phone entries and mobile.sniffer framework\nprovides abstraction of these databases.\n\nFeatures\n--------\n\n* Easily plug-in mobile redirects to your Python based web sites\n\n* Able to source data from multiple sniffing backends leading better handset coverage\n\n* Automatically download, parse and cache complex RDF based WAP profiles\n\n* Very convenient Python API designed by professionals\n\n* Open source\n\n* Unit test coverage\n\nThe code is Django, WSGI and Zope/Plone compatible.\n\nSupported sniffing backends\n----------------------------\n\n* `Wurfl `_ \n\n* ApexVertex. Commercially available from `mFabrik `_.\n\n* DeviceAtlas. Commercially available.\n\n* WAP profiles. User agents post a link to their WAP profile data, which is an XML file\n and maintained by the handset manufacturer. (note: as WAP is deprecating protocol these are not supported on newer smartphones)\n\nInstallation\n------------\n\n``mobile.sniffer`` is distributed as Python egg in PyPi repository.\n\nYou can install it using standard Python egg installation methods\n\n* easy_install\n\n* pip\n\n* buildout\n\nDependencies\n============\n\n.. note::\n\n Python package comes with a copy of Wurfl database which dates around the release.\n You might want to update this.\n\nYou might need to install additional libraries depending on what handset database you use\n\n* Wurfl: `pywurlf library `_ and\n `python-Levenshtein `_\n\n* WAP profiles: Django (for database abstraction) and rdflib\n\n* Apex Vertex: Django (for database abstraction) \n\nUsage examples\n--------------\n\nThere is no single standard to name properties queried from the handset database.\nFor legacy reasons, we use DeviceAtlas database column names (keys)\nand then map them to database-dependent keys. \n\nRedirection example\n====================================\n\n``detect_mobile_browser(user_agent)`` will return True of False\nwhether the HTTP request was made by a mobile phone.\n\nExample::\n\n from mobile.sniffer.detect import detect_mobile_browser\n from mobile.sniffer.utilities import get_user_agent\n\n # Get HTTP_USER_AGENT from HTTP request object\n ua = get_user_agent(self.request)\n if ua:\n # Apply reg\n if detect_mobile_browser(ua):\n # Redirect the visitor from a web site to a mobile site \n pass\n else:\n # A regular web site visitor\n pass\n else:\n # User agent header is missing from HTTP request\n return False\n \n\nFeature extraction example\n===================================\n\nThis example will work out of the box with the included pywurlf database.\n\nExample::\n\n try:\n from mobile.sniffer.wurlf.sniffer import WurlfSniffer\n \n # Wrapper sniffer instance\n # All start-up delay goes on this line\n sniffer = WurlfSniffer()\n except ImportError, e:\n import traceback\n traceback.print_exc()\n logger.exception(e)\n logger.error(\"Could not import Wurlf sniffer... add pywurfl and python-Lehvenstein to buildout.cfg eggs section\")\n sniffer = None\n\n\tdef sniff_request(request):\n\t \"\"\"\n\t @param request: Request can be Django, WSGI or Zope HTTPRequest object\n \"\"\"\n \n if not sniffer:\n # We failed to initialize Wurfl\n return None\n\n\t user_agent = sniffer.sniff(request)\n\n\t if user_agent == None:\n\t # No match in the handset database,\n\t return None\n else:\n return user_agent # mobile.sniffer.wurlf.sniffer.UserAgent object\n\n\n def web_or_mobile(request)\n ua = sniff_request(request)\n \n # How certain we must be about UA \n # match to make decisions\n # float 0...1, the actual value is UA search algorithm specific\n # We use JaroWinkler as the default algorithm\n certainty_threshold = 0.7\n \n if ua.get(\"is_wireless_device\") and ua.getCertainty() > certainty_threshold:\n # Mobile code\n pass\n else:\n # Webby code\n pass\n \nMatch-making process for Wurfl\n==============================\n\nSince Wurfl is the default backend the process of finding UA record is explained more carefully\n\n* Wurlf database is usually loaded during the start-up (slow operation) - it is possible\n to make this to use lazy initialization pattern\n\n* The search algorithm is initialized with certain match threshold - all matches below this threshold\n will be ignored. The default search algorithm is JaroWinkler from Lehvenstein Python package.\n\n* When the user agent is searched\n\n * Take in HTTP request User-Agent header\n \n * Go through all entries in database\n \n * Match this entry against incoming User-Agent using the search algorithm\n \n * First search pass is doing using exact string matches (no algorithm involved). In this \n case exposed certainty will be 1.1.\n \n * If there was no match in the first pass, do the second pass using the search algorithm\n \n * If match is found and threshold is exceed return this user agent record \n \n * User agent record is retrofitted with the information how accurate the match was\n (ua.getCertainty() method exposes this)\n \nChained example\n====================\n\nUse all available handset information sources to accurately get device data.\nMatching is done on property level - if one data source lacks the property information the next data source is tried. Finally if the handset is unknown, but it publishes WAP profile information, the profile is downloaded and analyzed and saved for further requests.\n\nExample::\n\n from mobile.sniffer.chain import ChainedSniffer\n from mobile.sniffer.apexvertex.sniffer import ApexVertexSniffer\n from mobile.sniffer.wapprofile.sniffer import WAPProfileSniffer\n from mobile.sniffer.deviceatlas.sniffer import DeviceAtlasSniffer\n\n # Create all supported sniffers\n da = DeviceAtlasSniffer(da_api_file)\n apex = ApexVertexSniffer()\n wap = WAPProfileSniffer()\n\n # Preferred order of sniffers\n sniffer = ChainedSniffer([apex, da, wap])\n\n ua = sniffer.sniff(request) # Sniff HTTP_USER_AGENT, HTTP_PROFILE and many other fields\n property = ua.get(\"usableDisplayWidth\") # This will look up data from all the databases in the chain\n\nAutomatic database installers\n--------------------------------\n\nProprietary handset databases do not publicly distribute their APIs or data. \nmobile.sniffer deals with the problem by automatic installation wrappers. \nAlso, these handset database APIs are not open source compatible which makes \nit further difficult to use them in open source projects. \nInstead of manually download and set up bunch of files each time \nyou deploy your code on a new server, just make call to one magical Python function which \nwill take care of all of this for you.\n\nSource code and issue tracking\n-----------------------------------\n\nThe project is hosted at `Google Code project repository `_.\n\nCommercial support and development\n-----------------------------------\n\nThis package is licenced under open source GPL 2 license.\n\n`Commercial CMS and mobile development support options `_\nare available from Web and Mobiel web site.\n\nOur top class Python developers are ready to help you with \nany software development needs.\n \nAuthor\n------\n\n`mFabrik Research Oy `_ - Python and Plone professionals for hire.\n\n* `mFabrik Web & Mobile - multichannel CMS made easy `_ \n\n* `mFabrik web site `_ \n\n* `mFabrik mobile site `_ \n\n* `Blog `_\n\n\n\n\nChangelog\n=========\n\n1.0.0\n------\n\n* Updated Wurfl db [miohtama]\n\n0.9.3\n-----\n\n* It's spellt LeveNshtein - why this guy would have just be called John Doe [miohtama]\n\n\n0.9.2\n-----\n\n* It's spellt Leveshtein [miohtama]\n\n\n0.9.1\n-----\n\n* Depend on Levehstein [miohtama]\n\n\n0.9\n-----\n\n* Major product rework [miohtama]\n\n\n0.1.1\n-----\n\n* Updated README to describe detection and redirects [miohtama]\n\n0.1\n-----\n\n* Initial release", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://mfabrik.com", "keywords": "mobile django plone user-agent http sniffer", "license": "GPL", "maintainer": null, "maintainer_email": null, "name": "mobile.sniffer", "package_url": "https://pypi.org/project/mobile.sniffer/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/mobile.sniffer/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://mfabrik.com" }, "release_url": "https://pypi.org/project/mobile.sniffer/1.0.0/", "requires_dist": null, "requires_python": null, "summary": "Mobile browser feature detection using multiple backends", "version": "1.0.0" }, "last_serial": 1459633, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "9978a1109332bf8bbc258cb1ced30aca", "sha256": "e765033288cea36e56ec2539729ffff9093f8bfb52eee25f35545fa1fd7af1b9" }, "downloads": -1, "filename": "mobile.sniffer-0.1.tar.gz", "has_sig": false, "md5_digest": "9978a1109332bf8bbc258cb1ced30aca", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 727485, "upload_time": "2010-07-18T09:16:51", "url": "https://files.pythonhosted.org/packages/9c/fb/3d46088a8ca05ff4d95447919e71b22c963150a5bd8d1ce251c6205ae531/mobile.sniffer-0.1.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "5739808d700cfb9d5271dabb99d4ab7b", "sha256": "5e6bf9794735077a1336605e1cefaec8a81fea150c7816b8e0b3547f92e7561d" }, "downloads": -1, "filename": "mobile.sniffer-0.1.1.tar.gz", "has_sig": false, "md5_digest": "5739808d700cfb9d5271dabb99d4ab7b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 728185, "upload_time": "2010-07-18T09:34:26", "url": "https://files.pythonhosted.org/packages/32/b6/390c9ab43972df999a2078b4ac33ca04021aedd3a770bcd736c4724fa319/mobile.sniffer-0.1.1.tar.gz" } ], "0.1dev-r63": [ { "comment_text": "", "digests": { "md5": "fe9c87a9c260a7312697a72c066268b5", "sha256": "0d2afae8fb01e8c9079332a5db3c74431b52d8b569912e8e8fb5d9cba773fcac" }, "downloads": -1, "filename": "mobile.sniffer-0.1dev-r63.tar.gz", "has_sig": false, "md5_digest": "fe9c87a9c260a7312697a72c066268b5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 727519, "upload_time": "2010-07-18T09:16:27", "url": "https://files.pythonhosted.org/packages/ec/58/a9698cb3ed726a4224b8d546997618b019f7ff538fa016c48b0856d8481b/mobile.sniffer-0.1dev-r63.tar.gz" } ], "0.9": [ { "comment_text": "", "digests": { "md5": "269801ee0817bea9b4a025374b6799e3", "sha256": "5ab7231aa86e4f416374f725067243782423c54011fb081064b767637ace34b1" }, "downloads": -1, "filename": "mobile.sniffer-0.9.zip", "has_sig": false, "md5_digest": "269801ee0817bea9b4a025374b6799e3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 786551, "upload_time": "2010-10-21T09:53:01", "url": "https://files.pythonhosted.org/packages/1a/6f/ff217862fbfbf5ef5dd1e17576146147cf6976d78eb5b5935b30b4feb9be/mobile.sniffer-0.9.zip" } ], "0.9.1": [ { "comment_text": "", "digests": { "md5": "9a39c5147e7c255f8e7ae298bffd6fa7", "sha256": "2dcbc0a9fc02aaef1dc6058ebeeafb2a408ca3e99634e66324c350969f001256" }, "downloads": -1, "filename": "mobile.sniffer-0.9.1.zip", "has_sig": false, "md5_digest": "9a39c5147e7c255f8e7ae298bffd6fa7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 786830, "upload_time": "2010-10-28T17:11:01", "url": "https://files.pythonhosted.org/packages/b9/1d/5839f9f12ce5e959389c3f9b18c3f5193ef06ebb2975cf7dd685e512d343/mobile.sniffer-0.9.1.zip" } ], "0.9.2": [ { "comment_text": "", "digests": { "md5": "58e4a0ed5d56295aecc0033565d3add2", "sha256": "79e37afc0a3a3e726682373b4e4f5bf52e0e8e683721980a37a3e78d3d0e6f17" }, "downloads": -1, "filename": "mobile.sniffer-0.9.2.zip", "has_sig": false, "md5_digest": "58e4a0ed5d56295aecc0033565d3add2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 786883, "upload_time": "2010-10-28T17:23:36", "url": "https://files.pythonhosted.org/packages/43/f5/fd8b9cad0b64b22a9d63a0ab715e98851b19a84e62bc518bb991a06510d2/mobile.sniffer-0.9.2.zip" } ], "0.9.3": [ { "comment_text": "", "digests": { "md5": "74a4f1958b16e6bd4b4bd0b1c62dd59a", "sha256": "7aeecd2a929b30f8c8611f56839ec546dc92b23fc7c99dce6b062de40cc75f27" }, "downloads": -1, "filename": "mobile.sniffer-0.9.3.zip", "has_sig": false, "md5_digest": "74a4f1958b16e6bd4b4bd0b1c62dd59a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 787013, "upload_time": "2010-10-28T17:29:08", "url": "https://files.pythonhosted.org/packages/6d/69/1db9b310b71faf5c8fae0c9c1fce8729e4961687ba1cdfe0bbf1224a0c16/mobile.sniffer-0.9.3.zip" } ], "1.0.0": [ { "comment_text": "", "digests": { "md5": "d896c2b392d29528eda692a7702204df", "sha256": "9ecd6228acac62b6efe658b93e7ac14a4d1aed361d393712c6daad385ba1b1d7" }, "downloads": -1, "filename": "mobile.sniffer-1.0.0.zip", "has_sig": false, "md5_digest": "d896c2b392d29528eda692a7702204df", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 848459, "upload_time": "2011-01-31T22:00:21", "url": "https://files.pythonhosted.org/packages/4f/6a/c0886cbceef6f2a4b0a6cbf5ce2dac6a62cdaf10ee02cecd3a1a70d4f92c/mobile.sniffer-1.0.0.zip" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "d896c2b392d29528eda692a7702204df", "sha256": "9ecd6228acac62b6efe658b93e7ac14a4d1aed361d393712c6daad385ba1b1d7" }, "downloads": -1, "filename": "mobile.sniffer-1.0.0.zip", "has_sig": false, "md5_digest": "d896c2b392d29528eda692a7702204df", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 848459, "upload_time": "2011-01-31T22:00:21", "url": "https://files.pythonhosted.org/packages/4f/6a/c0886cbceef6f2a4b0a6cbf5ce2dac6a62cdaf10ee02cecd3a1a70d4f92c/mobile.sniffer-1.0.0.zip" } ] }