new user agent, thananks Angelo

This commit is contained in:
Massimo DiPierro
2011-12-02 16:16:30 -06:00
parent 3b017cb0e9
commit 32b0ff3289
2 changed files with 210 additions and 108 deletions
+1 -1
View File
@@ -1 +1 @@
Version 1.99.3 (2011-11-30 22:36:21) dev
Version 1.99.3 (2011-12-02 16:16:28) dev
+209 -107
View File
@@ -9,6 +9,9 @@ Aim is
Taken from http://pypi.python.org/pypi/httpagentparser (MIT license)
Modified my Ross Peoples for web2py to better support iPhone and iPad.
Modified by Angelo Compagnucci <angelo.compagnucci@gmail.com> to better support a wide ringe of mobile devices.
Now it supports: tablet device (is_tablet), BlackBerry, BlackBerry PlayBook, Android Tablets, Windows Mobile,
Symbian.
"""
import sys
@@ -52,13 +55,14 @@ class DetectorsHub(dict):
class DetectorBase(object):
name = "" # "to perform match in DetectorsHub object"
info_type = "override me"
result_key = "override me"
info_type = '' #override me
result_key = '' #override me
order = 10 # 0 is highest
look_for = "string to look for"
look_for = [] # list of words to look for
skip_if_found = [] # strings if present stop processin
can_register = False
is_mobile = False
is_tablet = False
prefs = dict() # dict(info_type = [name1, name2], ..)
version_splitters = ["/", " "]
_suggested_detectors = None
@@ -71,9 +75,16 @@ class DetectorBase(object):
def detect(self, agent, result):
if agent and self.checkWords(agent):
result[self.info_type] = dict(name=self.name)
result[self.info_type]['is_mobile'] = self.is_mobile
if not result.get('is_mobile',None):
result['is_mobile'] = result[self.info_type]['is_mobile']
is_mobile=self.is_mobile
is_tablet=self.is_tablet
if result.get('is_mobile') is None:
result['is_mobile'] = False
if is_mobile:
result['is_mobile'] = is_mobile
if result.get('is_tablet') is None:
result['is_tablet'] = False
if is_tablet:
result['is_tablet'] = is_tablet
version = self.getVersion(agent)
if version:
@@ -86,14 +97,18 @@ class DetectorBase(object):
for w in self.skip_if_found:
if w in agent:
return False
if self.look_for in agent:
return True
return False
for w in self.look_for:
if not w in agent:
return False
return True
# It get the version correctly only if the words list
# contains only one element, alternatively, you have to
# override this method
def getVersion(self, agent):
# -> version string /None
vs = self.version_splitters
return agent.split(self.look_for + vs[0])[-1].split(vs[1])[0].strip()
return agent.split(self.look_for[0] + vs[0])[1].split(vs[1])[0].strip()
class OS(DetectorBase):
@@ -118,85 +133,128 @@ class Browser(DetectorBase):
class Macintosh(OS):
look_for = 'Macintosh'
look_for = ['Macintosh']
prefs = dict(dist=None)
def getVersion(self, agent):
pass
class Firefox(Browser):
look_for = "Firefox"
look_for = ["Firefox"]
class Konqueror(Browser):
look_for = "Konqueror"
look_for = ["Konqueror"]
version_splitters = ["/", ";"]
class Opera(Browser):
look_for = "Opera"
look_for = ["Opera"]
def getVersion(self, agent):
return agent.split(self.look_for)[1][1:].split(' ')[0]
return agent.split(self.look_for[0])[1][1:].split(' ')[0]
class Netscape(Browser):
look_for = "Netscape"
look_for = ["Netscape"]
class MSIE(Browser):
look_for = "MSIE"
look_for = ["MSIE"]
skip_if_found = ["Opera"]
name = "Microsoft Internet Explorer"
version_splitters = [" ", ";"]
class Galeon(Browser):
look_for = "Galeon"
look_for = ["Galeon"]
class Safari(Browser):
look_for = "Safari"
def checkWords(self, agent):
unless_list = ["Chrome", "OmniWeb"]
if self.look_for in agent:
for word in unless_list:
if word in agent:
return False
return True
look_for = ["Safari"]
skip_if_found = ["Chrome", "OmniWeb", "Mobile", "iPad", 'Android']
def getVersion(self, agent):
if "Version/" in agent:
return agent.split('Version/')[-1].split(' ')[0].strip()
else:
# Mobile Safari
return agent.split('Safari ')[-1].split(' ')[0].strip()
return agent.split('Version/')[1].split(' ')[0].strip()
class SafariTablet(Browser):
name = "Safari"
look_for = ['Safari', 'Android']
skip_if_found = ["Chrome", "OmniWeb", "Mobile", "iPad"]
is_mobile = True
is_tablet = True
def getVersion(self, agent):
if "Version/" in agent:
return agent.split('Version/')[1].split(' ')[0].strip()
class SafariMobile(Browser):
name = "Safari"
look_for = ["Safari", "Mobile"]
is_mobile = True
def getVersion(self, agent):
if "Version/" in agent:
return agent.split('Version/')[1].split(' ')[0].strip()
class SafariNokia(Browser):
name = "Safari"
look_for = ["Safari", "SymbianOS"]
is_mobile = True
def getVersion(self, agent):
pass
class SafariiPad(Browser):
name = "Safari"
look_for = ["Safari", "iPad"]
skip_if_found = ["Chrome", "OmniWeb"]
is_mobile = True
is_tablet = True
def getVersion(self, agent):
if "Version/" in agent:
return agent.split('Version/')[1].split(' ')[0].strip()
class Linux(OS):
look_for = 'Linux'
prefs = dict(browser=["Firefox"],
dist=["Ubuntu", "Android"], flavor=None)
look_for = ["Linux"]
prefs = dict(dist=["Ubuntu", "Android", "Debian"], flavor=None)
def getVersion(self, agent):
pass
class RIM(OS):
look_for = 'BlackBerry'
prefs = dict(dist=[None], flavor=None)
class BlackBerry(OS):
look_for = ['BlackBerry']
prefs = dict( flavor=['PlayBook'])
is_mobile = True
# Manual check for tablet
def checkWords(self, agent):
if 'BlackBerry' in agent or 'PlayBook' in agent:
return True
return False
def getVersion(self, agent):
pass
class PlayBook(Flavor):
look_for = ['PlayBook']
is_mobile=True
is_tablet=True
def getVersion(self, agent):
return agent.partition('Tablet OS')[2].partition(';')[0].strip()
class Macintosh(OS):
look_for = 'Macintosh'
look_for = ['Macintosh']
prefs = dict(dist=None, flavor=['MacOS'])
def getVersion(self, agent):
pass
class MacOS(Flavor):
look_for = 'Mac OS'
prefs = dict(browser=['Firefox', 'Opera', "Microsoft Internet Explorer"])
look_for = ['Mac OS']
prefs = dict(browser=['Safari','SafariMobile', 'SafariIpad', 'Firefox', 'Opera', "Microsoft Internet Explorer"])
def getVersion(self, agent):
version_end_chars = [';', ')']
@@ -209,63 +267,81 @@ class MacOS(Flavor):
class Windows(OS):
look_for = 'Windows'
look_for = ['Windows', 'NT']
prefs = dict(browser=["Microsoft Internet Explorer", 'Firefox'],
dist=['WindowsMobile'], flavor=None)
def getVersion(self, agent):
v = agent.split('Windows')[-1].split(';')[0].strip()
if ')' in v:
v = v.split(')')[0]
return v
v = agent.partition('NT')
return v[1]+' '+v[2].replace(')',';').partition(';')[0].strip()
class WindowsMobile(Dist):
name = 'Phone'
look_for = ['Windows', 'Phone']
is_mobile = True
def getVersion(self, agent):
return agent.partition('Windows Phone')[2].replace(')','').partition(';')[0].strip()
class Ubuntu(Dist):
look_for = 'Ubuntu'
look_for = ['Ubuntu']
version_splitters = ["/", " "]
prefs = dict(browser=['Firefox'])
class Debian(Dist):
look_for = 'Debian'
look_for = ['Debian']
version_splitters = ["/", " "]
prefs = dict(browser=['Firefox'])
class Chrome(Browser):
look_for = "Chrome"
look_for = ['Chrome']
version_splitters = ["/", " "]
class ChromeOS(OS):
look_for = "CrOS"
look_for = ['CrOS']
version_splitters = [" ", " "]
prefs = dict(browser=['Chrome'])
def getVersion(self, agent):
vs = self.version_splitters
return agent.split(self.look_for+vs[0])[-1].split(vs[1])[1].strip()[:-1]
class WindowsMobile(Dist):
look_for = 'Windows Phone'
is_mobile = True
def getVersion(self, agent):
return agent.split('Windows Phone')[-1].split(';')[0].strip().split(' ')[-1]
return agent.split(self.look_for[0]+vs[0])[1].split(vs[1])[1].strip()[:-1]
class Android(Dist):
look_for = 'Android'
look_for = ['Android']
prefs = dict(browser=['SafariTablet', 'SafariMobile'])
is_mobile = True
def getVersion(self, agent):
return agent.split('Android')[-1].split(';')[0].strip()
return agent.split('Android')[1].split(';')[0].strip()
class SymbianOS(OS):
look_for = ['SymbianOS']
prefs = dict(dist = ['Series'], browser = ['Safari', 'Opera'])
is_mobile = True
version_splitters = ['/', '; ']
class Series(Flavor):
look_for = ['SymbianOS', 'Series']
version_splitters = ['/', ';']
def getVersion(self, agent):
return agent.partition('Series')[2].partition(' ')[0].replace('/',' ')
class BrowserNG(Browser):
look_for = ['BrowserNG']
version_splitters = ['/', ';']
class iPhone(Dist):
look_for = 'iPhone'
is_mobile = True
look_for = ['iPhone']
is_mobile = True
prefs = dict(browser=['SafariMobile'])
def getVersion(self, agent):
version_end_chars = ['like', ';', ')']
part = agent.split('CPU OS')[-1].strip()
if (not 'CPU iPhone OS' in agent) and (not 'CPU OS' in agent):
return 'X'
part = agent.split('OS')[1].strip()
for c in version_end_chars:
if c in part:
version = 'iOS ' + part.split(c)[0].strip()
@@ -273,12 +349,15 @@ class iPhone(Dist):
return version.replace('_', '.')
class iPad(Dist):
look_for = 'iPad'
look_for = ['iPad']
is_mobile = True
is_tablet = True
def getVersion(self, agent):
version_end_chars = ['like', ';', ')']
part = agent.split('CPU OS')[-1].strip()
if not 'OS' in agent:
return ''
part = agent.split('OS')[1].strip()
for c in version_end_chars:
if c in part:
version = 'iOS ' + part.split(c)[0].strip()
@@ -290,21 +369,13 @@ detectorshub = DetectorsHub()
def detect(agent):
result = dict()
prefs = dict()
_suggested_detectors = []
for info_type in detectorshub:
if not _suggested_detectors:
detectors = detectorshub[info_type]
_d_prefs = prefs.get(info_type, [])
detectors = detectorshub.reorderByPrefs(detectors, _d_prefs)
if "detector" in locals():
detector._suggested_detectors = detectors
else:
detectors = _suggested_detectors
detectors = detectorshub[info_type]
_d_prefs = prefs.get(info_type, [])
detectors = detectorshub.reorderByPrefs(detectors, _d_prefs)
for detector in detectors:
# print "detector name: ", detector.name
if detector.detect(agent, result):
prefs = detector.prefs
_suggested_detectors = detector._suggested_detectors
break
return result
@@ -327,8 +398,7 @@ def simple_detect(agent):
os_version = os_list and ('flavor' in result and result['flavor'] and result['flavor'].get(
'version')) or ('dist' in result and result['dist'] and result['dist'].get('version')) \
or ('os' in result and result['os'] and result['os'].get('version')) or ""
browser = 'browser' in result and result['browser']['name'] \
or 'Unknown Browser'
browser = 'browser' in result and result['browser']['name'] or 'Unknown Browser'
browser_version = 'browser' in result \
and result['browser'].get('version') or ""
if browser_version:
@@ -336,7 +406,7 @@ def simple_detect(agent):
if os_version:
os = " ".join((os, os_version))
#is_mobile = ('dist' in result and result.dist.is_mobile) or ('os' in result and result.os.is_mobile) or False
return os, browser, result.is_mobile
return os, browser, result['is_mobile']
if __name__ == '__main__':
@@ -344,38 +414,70 @@ if __name__ == '__main__':
import unittest
data = (
("Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-GB; rv:1.9.0.10) Gecko/2009042315 Firefox/3.0.10",
('MacOS Macintosh X 10.5', 'Firefox 3.0.10'),
{'flavor': {'version': 'X 10.5', 'name': 'MacOS'}, 'os': {'name': 'Macintosh'}, 'browser': {'version': '3.0.10', 'name': 'Firefox'}},),
("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.3 Safari/534.24,gzip(gfe)",
('MacOS Macintosh X 10.6.6', 'Chrome 11.0.696.3'),
{'flavor': {'version': 'X 10.6.6', 'name': 'MacOS'}, 'os': {'name': 'Macintosh'}, 'browser': {'version': '11.0.696.3', 'name': 'Chrome'}},),
("Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2) Gecko/20100308 Ubuntu/10.04 (lucid) Firefox/3.6 GTB7.1",
('Ubuntu Linux 10.04', 'Firefox 3.6'),
{'dist': {'version': '10.04', 'name': 'Ubuntu'}, 'os': {'name': 'Linux'}, 'browser': {'version': '3.6', 'name': 'Firefox'}},),
("Mozilla/5.0 (Linux; U; Android 2.2.1; fr-ch; A43 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
('Android Linux 2.2.1', 'Safari 4.0'),
{'dist': {'version': '2.2.1', 'name': 'Android'}, 'os': {'name': 'Linux'}, 'browser': {'version': '4.0', 'name': 'Safari'}},),
("Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3",
('MacOS IPhone X', 'Safari 3.0'),
{'flavor': {'version': 'X', 'name': 'MacOS'}, 'dist': {'version': 'X', 'name': 'IPhone'}, 'browser': {'version': '3.0', 'name': 'Safari'}},),
("Mozilla/5.0 (X11; CrOS i686 0.0.0) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.27 Safari/534.24,gzip(gfe)",
('ChromeOS 0.0.0', 'Chrome 11.0.696.27'),
{'os': {'name': 'ChromeOS', 'version': '0.0.0'}, 'browser': {'name': 'Chrome', 'version': '11.0.696.27'}},),
("Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.02 [en]",
('Windows NT 5.1', 'Opera 7.02'),
{'os': {'name': 'Windows', 'version': 'NT 5.1'}, 'browser': {'name': 'Opera', 'version': '7.02'}},),
("Opera/9.80 (X11; Linux i686; U; en) Presto/2.9.168 Version/11.50",
("Linux", "Opera 9.80"),
{"os": {"name": "Linux"}, "browser": {"name": "Opera", "version": "9.80"}},),
("Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20060127 Netscape/8.1",
("Windows NT 5.1", "Netscape 8.1"),
{'os': {'name': 'Windows', 'version': 'NT 5.1'}, 'browser': {'name': 'Netscape', 'version': '8.1'}},),
('Mozilla/5.0 (SymbianOS/9.2; U; Series60/3.1 Nokia6120c/3.83; Profile/MIDP-2.0 Configuration/CLDC-1.1) AppleWebKit/413 (KHTML, like Gecko) Safari/413',
('Series SymbianOS 60 3.1', 'Safari', True),
{'is_mobile': True, 'is_tablet': False, 'flavor': {'name': 'Series', 'version': '60 3.1'}, 'os': {'name': 'SymbianOS', 'version': '9.2'}, 'browser': {'name': 'Safari'}},),
('Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaN97-1/20.0.019; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) BrowserNG/7.1.18124',
('Series SymbianOS 60 5.0', 'BrowserNG 7.1.18124', True),
{'is_mobile': True, 'is_tablet': False, 'flavor': {'name': 'Series', 'version': '60 5.0'}, 'os': {'name': 'SymbianOS', 'version': '9.4'}, 'browser': {'name': 'BrowserNG', 'version': '7.1.18124'}},),
('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Windows Phone 6.5.3.5)',
('Phone Windows 6.5.3.5', 'Microsoft Internet Explorer 6.0', True),
{'is_mobile': True, 'is_tablet': False, 'dist': {'name': 'Phone', 'version': '6.5.3.5'}, 'os': {'name': 'Windows', 'version': 'NT 5.1'}, 'browser': {'name': 'Microsoft Internet Explorer', 'version': '6.0'}},),
('Mozilla/5.0 (PlayBook; U; RIM Tablet OS 1.0.0; en-US) AppleWebKit/534.8+ (KHTML, like Gecko) Version/0.0.1 Safari/534.8+',
('PlayBook BlackBerry 1.0.0', 'Safari 0.0.1', True),
{'is_mobile': True, 'is_tablet': True, 'flavor': {'name': 'PlayBook', 'version': '1.0.0'}, 'os': {'name': 'BlackBerry'}, 'browser': {'name': 'Safari', 'version': '0.0.1'}},),
('Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en-US) AppleWebKit/534.1+ (KHTML, like Gecko) Version/6.0.0.246 Mobile Safari/534.1+',
('BlackBerry', 'Safari 6.0.0.246', True),
{'is_mobile': True, 'is_tablet': False, 'os': {'name': 'BlackBerry'}, 'browser': {'name': 'Safari', 'version': '6.0.0.246'}},),
('Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en-US) AppleWebKit/534.8+ (KHTML, like Gecko) Version/6.0.0.600 Mobile Safari/534.8+',
('BlackBerry', 'Safari 6.0.0.600', True),
{'is_mobile': True, 'is_tablet': False, 'os': {'name': 'BlackBerry'}, 'browser': {'name': 'Safari', 'version': '6.0.0.600'}},),
('Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5',
('MacOS iPad X', 'Safari 5.0.2', True),
{'is_mobile': True, 'is_tablet': True, 'flavor': {'version': 'X', 'name': 'MacOS'}, 'dist': {'version': 'iOS 4.2.1', 'name': 'iPad'}, 'browser': {'name': 'Safari', 'version': '5.0.2'}},),
('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20060127 Netscape/8.1',
('Windows NT 5.1', 'Netscape 8.1', False),
{'is_mobile': False, 'is_tablet': False, 'os': {'name': 'Windows', 'version': 'NT 5.1'}, 'browser': {'name': 'Netscape', 'version': '8.1'}},),
('Mozilla/5.0 (Linux; U; Android 3.0.1; en-us; A500 Build/HRI66) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13',
('Android Linux 3.0.1', 'Safari 4.0', True),
{'is_mobile': True, 'is_tablet': True, 'dist': {'version': '3.0.1', 'name': 'Android'}, 'os': {'name': 'Linux'}, 'browser': {'version': '4.0', 'name': 'Safari'}},),
('Mozilla/5.0 (Linux; U; Android 2.3.7; it-it; Dream/Sapphire Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1',
('Android Linux 2.3.7', 'Safari 4.0', True),
{'is_mobile': True, 'is_tablet': False, 'dist': {'version': '2.3.7', 'name': 'Android'}, 'os': {'name': 'Linux'}, 'browser': {'version': '4.0', 'name': 'Safari'}},),
('Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-GB; rv:1.9.0.10) Gecko/2009042315 Firefox/3.0.10',
('MacOS Macintosh X 10.5', 'Firefox 3.0.10', False),
{ 'is_mobile': False, 'is_tablet': False, 'flavor': {'version': 'X 10.5', 'name': 'MacOS'}, 'os': {'name': 'Macintosh'}, 'browser': {'version': '3.0.10', 'name': 'Firefox'}},),
('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_6) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.3 Safari/534.24,gzip(gfe)',
('MacOS Macintosh X 10.6.6', 'Chrome 11.0.696.3', False),
{'is_mobile': False, 'is_tablet': False, 'flavor': {'version': 'X 10.6.6', 'name': 'MacOS'}, 'os': {'name': 'Macintosh'}, 'browser': {'version': '11.0.696.3', 'name': 'Chrome'}},),
('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2) Gecko/20100308 Ubuntu/10.04 (lucid) Firefox/3.6 GTB7.1',
('Ubuntu Linux 10.04', 'Firefox 3.6', False),
{'is_mobile': False, 'is_tablet': False, 'dist': {'version': '10.04', 'name': 'Ubuntu'}, 'os': {'name': 'Linux'}, 'browser': {'version': '3.6', 'name': 'Firefox'}},),
('Mozilla/5.0 (Linux; U; Android 2.2.1; fr-ch; A43 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1',
('Android Linux 2.2.1', 'Safari 4.0', True),
{'is_mobile': True, 'is_tablet': False, 'dist': {'version': '2.2.1', 'name': 'Android'}, 'os': {'name': 'Linux'}, 'browser': {'version': '4.0', 'name': 'Safari'}},),
('Mozilla/5.0 (Linux; U; Android 2.3.4; it-it; LG-P990 Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 MMS/LG-Android-MMS-V1.0/1.2',
('Android Linux 2.3.4', 'Safari 4.0', True),
{'is_mobile': True, 'is_tablet': False, 'dist': {'version': '2.3.4', 'name': 'Android'}, 'os': {'name': 'Linux'}, 'browser': {'version': '4.0', 'name': 'Safari'}},),
('Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3',
('MacOS iPhone X', 'Safari 3.0', True),
{'is_mobile': True, 'is_tablet': False, 'flavor': {'version': 'X', 'name': 'MacOS'}, 'dist': {'version': 'X', 'name': 'iPhone'}, 'browser': {'version': '3.0', 'name': 'Safari'}},),
('Mozilla/5.0 (X11; CrOS i686 0.0.0) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.27 Safari/534.24,gzip(gfe)',
('ChromeOS 0.0.0', 'Chrome 11.0.696.27', False),
{'is_mobile': False, 'is_tablet': False, 'os': {'name': 'ChromeOS', 'version': '0.0.0'}, 'browser': {'name': 'Chrome', 'version': '11.0.696.27'}},),
('Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.02 [en]',
('Windows NT 5.1', 'Opera 7.02', False),
{'is_mobile': False, 'is_tablet': False, 'os': {'name': 'Windows', 'version': 'NT 5.1'}, 'browser': {'name': 'Opera', 'version': '7.02'}},),
('Opera/9.80 (X11; Linux i686; U; en) Presto/2.9.168 Version/11.50',
('Linux', 'Opera 9.80', False),
{'is_mobile': False, 'is_tablet': False, 'os': {'name': 'Linux'}, 'browser': {'name': 'Opera', 'version': '9.80'}},),
)
class TestHAP(unittest.TestCase):
def setUp(self):
self.harass_repeat = 1000
self.harass_repeat = 100
self.data = data
def test_simple_detect(self):