NDOJ/judge/utils/caniuse.py

158 lines
4.3 KiB
Python
Raw Permalink Normal View History

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