2020-01-21 06:35:58 +00:00
|
|
|
import requests
|
|
|
|
from ua_parser import user_agent_parser
|
|
|
|
|
2022-05-14 17:57:27 +00:00
|
|
|
_SUPPORT_DATA = requests.get(
|
|
|
|
"https://raw.githubusercontent.com/Fyrd/caniuse/master/data.json"
|
|
|
|
).json()["data"]
|
2020-01-21 06:35:58 +00:00
|
|
|
|
2022-05-14 17:57:27 +00:00
|
|
|
SUPPORT = "y"
|
|
|
|
PARTIAL_SUPPORT = "a"
|
|
|
|
UNSUPPORTED = "n"
|
|
|
|
POLYFILL = "p"
|
|
|
|
UNKNOWN = "u"
|
|
|
|
PREFIX = "x"
|
|
|
|
DISABLED = "d"
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
def safe_int(string):
|
|
|
|
try:
|
|
|
|
return int(string)
|
|
|
|
except (ValueError, TypeError):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
class BrowserFamily(object):
|
|
|
|
def __init__(self, data):
|
|
|
|
self._data = data
|
|
|
|
self._ranges = ranges = []
|
|
|
|
self._versions = versions = {}
|
|
|
|
max_version = ()
|
|
|
|
max_support = UNKNOWN
|
|
|
|
|
|
|
|
for version, support in data.items():
|
2022-05-14 17:57:27 +00:00
|
|
|
if version == "all":
|
2020-01-21 06:35:58 +00:00
|
|
|
self.max_support = support
|
2022-05-14 17:57:27 +00:00
|
|
|
elif "-" in version:
|
|
|
|
start, end = version.split("-")
|
|
|
|
start = tuple(map(int, start.split(".")))
|
|
|
|
end = tuple(map(int, end.split("."))) + (1e3000,)
|
2020-01-21 06:35:58 +00:00
|
|
|
ranges.append((start, end, support))
|
|
|
|
if end > max_version:
|
|
|
|
max_version = end
|
|
|
|
max_support = support
|
|
|
|
else:
|
|
|
|
try:
|
2022-05-14 17:57:27 +00:00
|
|
|
version = tuple(map(int, version.split(".")))
|
2020-01-21 06:35:58 +00:00
|
|
|
except ValueError:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
if version > max_version:
|
|
|
|
max_version = version
|
|
|
|
max_support = support
|
|
|
|
versions[version] = support
|
|
|
|
|
|
|
|
self.max_version = max_version
|
|
|
|
self.max_support = max_support
|
|
|
|
|
|
|
|
def check(self, major, minor, patch):
|
|
|
|
int_major, int_minor, int_patch = map(safe_int, (major, minor, patch))
|
|
|
|
|
|
|
|
version = (int_major, int_minor, int_patch)
|
|
|
|
if version > self.max_version:
|
|
|
|
return self.max_support
|
|
|
|
|
2022-05-14 17:57:27 +00:00
|
|
|
for key in (
|
|
|
|
(int_major, int_minor, int_patch),
|
|
|
|
(int_major, int_minor),
|
|
|
|
(int_major,),
|
|
|
|
major,
|
|
|
|
):
|
2020-01-21 06:35:58 +00:00
|
|
|
try:
|
|
|
|
return self._versions[key]
|
|
|
|
except KeyError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
for start, end, support in self._ranges:
|
|
|
|
if start <= version < end:
|
|
|
|
return support
|
|
|
|
|
|
|
|
return UNKNOWN
|
|
|
|
|
|
|
|
|
|
|
|
class Feat(object):
|
|
|
|
def __init__(self, data):
|
|
|
|
self._data = data
|
2022-05-14 17:57:27 +00:00
|
|
|
self._family = {
|
|
|
|
name: BrowserFamily(data) for name, data in data["stats"].items()
|
|
|
|
}
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
def __getitem__(self, item):
|
|
|
|
return self._family[item]
|
|
|
|
|
|
|
|
|
|
|
|
class Database(object):
|
|
|
|
def __init__(self, data):
|
|
|
|
self._data = data
|
|
|
|
self._feats = {feat: Feat(data) for feat, data in data.items()}
|
|
|
|
|
|
|
|
def __getitem__(self, item):
|
|
|
|
return self._feats[item]
|
|
|
|
|
|
|
|
|
|
|
|
database = Database(_SUPPORT_DATA)
|
|
|
|
|
|
|
|
|
|
|
|
class CanIUse(object):
|
|
|
|
def __init__(self, ua):
|
|
|
|
self._agent = user_agent_parser.Parse(ua)
|
|
|
|
|
2022-05-14 17:57:27 +00:00
|
|
|
os_family = self._agent["os"]["family"]
|
|
|
|
browser_family = self._agent["user_agent"]["family"]
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
family = None
|
|
|
|
|
2022-05-14 17:57:27 +00:00
|
|
|
if os_family == "Android":
|
|
|
|
if "Firefox" in browser_family:
|
|
|
|
family = "and_ff"
|
|
|
|
elif "Chrome" in browser_family:
|
|
|
|
family = "and_chr"
|
|
|
|
elif "Android" in browser_family:
|
|
|
|
family = "android"
|
2020-01-21 06:35:58 +00:00
|
|
|
else:
|
2022-05-14 17:57:27 +00:00
|
|
|
if "Edge" in browser_family:
|
|
|
|
family = "edge"
|
|
|
|
elif "Firefox" in browser_family:
|
|
|
|
family = "firefox"
|
|
|
|
elif "Chrome" in browser_family:
|
|
|
|
family = "chrome"
|
|
|
|
elif "IE" in browser_family:
|
|
|
|
family = "ie"
|
|
|
|
elif "Opera" in browser_family:
|
|
|
|
family = "opera"
|
|
|
|
elif "Safari" in browser_family:
|
|
|
|
family = "safari"
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
self._family = family
|
|
|
|
|
|
|
|
def _check_feat(self, feat):
|
|
|
|
if not self._family:
|
|
|
|
return UNKNOWN
|
|
|
|
|
|
|
|
try:
|
|
|
|
stats = feat[self._family]
|
|
|
|
except KeyError:
|
|
|
|
return UNKNOWN
|
|
|
|
else:
|
2022-05-14 17:57:27 +00:00
|
|
|
ua = self._agent["user_agent"]
|
|
|
|
return stats.check(ua["major"], ua["minor"], ua["patch"])[0]
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
def __getattr__(self, attr):
|
|
|
|
try:
|
2022-05-14 17:57:27 +00:00
|
|
|
feat = database[attr.replace("_", "-")]
|
2020-01-21 06:35:58 +00:00
|
|
|
except KeyError:
|
|
|
|
raise AttributeError(attr)
|
|
|
|
else:
|
|
|
|
result = self._check_feat(feat)
|
|
|
|
setattr(self, attr, result)
|
|
|
|
return result
|