NDOJ/judge/utils/caniuse.py
2023-05-20 08:53:43 +09:00

157 lines
4.3 KiB
Python

import requests
from ua_parser import user_agent_parser
_SUPPORT_DATA = requests.get(
"https://raw.githubusercontent.com/Fyrd/caniuse/master/data.json"
).json()["data"]
SUPPORT = "y"
PARTIAL_SUPPORT = "a"
UNSUPPORTED = "n"
POLYFILL = "p"
UNKNOWN = "u"
PREFIX = "x"
DISABLED = "d"
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():
if version == "all":
self.max_support = support
elif "-" in version:
start, end = version.split("-")
start = tuple(map(int, start.split(".")))
end = tuple(map(int, end.split("."))) + (1e3000,)
ranges.append((start, end, support))
if end > max_version:
max_version = end
max_support = support
else:
try:
version = tuple(map(int, version.split(".")))
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
for key in (
(int_major, int_minor, int_patch),
(int_major, int_minor),
(int_major,),
major,
):
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
self._family = {
name: BrowserFamily(data) for name, data in data["stats"].items()
}
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)
os_family = self._agent["os"]["family"]
browser_family = self._agent["user_agent"]["family"]
family = None
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"
else:
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"
self._family = family
def _check_feat(self, feat):
if not self._family:
return UNKNOWN
try:
stats = feat[self._family]
except KeyError:
return UNKNOWN
else:
ua = self._agent["user_agent"]
return stats.check(ua["major"], ua["minor"], ua["patch"])[0]
def __getattr__(self, attr):
try:
feat = database[attr.replace("_", "-")]
except KeyError:
raise AttributeError(attr)
else:
result = self._check_feat(feat)
setattr(self, attr, result)
return result