StarRailCopilot/module/device/pkg_resources/__init__.py

110 lines
3.1 KiB
Python

import os
import re
import sys
from module.base.decorator import cached_property
from module.logger import logger
"""
Importing pkg_resources is so slow, like 0.4 ~ 1.0s, just google it you will find it indeed really slow.
Since it was some kind of standard library there is no way to modify it or speed it up.
So here's a poor but fast implementation of pkg_resources returning the things in need.
To patch:
```
# Patch pkg_resources before importing adbutils and uiautomator2
from module.device.pkg_resources import get_distribution
# Just avoid being removed by import optimization
_ = get_distribution
```
"""
# Inject sys.modules, pretend we have pkg_resources imported
try:
sys.modules['pkg_resources'] = sys.modules['module.device.pkg_resources']
except KeyError:
logger.error('Patch pkg_resources failed, patch module does not exists')
def remove_suffix(s, suffix):
"""
Remove suffix of a string or bytes like `string.removesuffix(suffix)`, which is on Python3.9+
Args:
s (str, bytes):
suffix (str, bytes):
Returns:
str, bytes:
"""
return s[:-len(suffix)] if s.endswith(suffix) else s
class FakeDistributionObject:
def __init__(self, dist, version):
self.dist = dist
self.version = version
def __str__(self):
return f'{self.__class__.__name__}({self.dist}={self.version})'
__repr__ = __str__
class PackageCache:
@cached_property
def site_packages(self):
# Just whatever library to locate the `site-packages` directory
import requests
path = os.path.abspath(os.path.join(requests.__file__, '../../'))
return path
@cached_property
def dict_installed_packages(self):
"""
Returns:
dict: Key: str, package name
Value: FakeDistributionObject
"""
dic = {}
for file in os.listdir(self.site_packages):
# mxnet_cu101-1.6.0.dist-info
# adbutils-0.11.0-py3.7.egg-info
res = re.match(r'^([a-zA-Z0-9._]+)-([a-zA-Z0-9._]+)-', file)
if res:
version = remove_suffix(res.group(2), '.dist')
# version = res.group(2)
obj = FakeDistributionObject(
dist=res.group(1),
version=version,
)
dic[obj.dist] = obj
return dic
PACKAGE_CACHE = PackageCache()
def resource_filename(*args):
if args == ("adbutils", "binaries"):
path = os.path.abspath(os.path.join(PACKAGE_CACHE.site_packages, *args))
return path
def get_distribution(dist):
"""Return a current distribution object for a Requirement or string"""
if dist == 'adbutils':
return PACKAGE_CACHE.dict_installed_packages.get(
'adbutils',
FakeDistributionObject('adbutils', '0.11.0'),
)
if dist == 'uiautomator2':
return PACKAGE_CACHE.dict_installed_packages.get(
'uiautomator2',
FakeDistributionObject('uiautomator2', '2.16.17'),
)
class DistributionNotFound(Exception):
pass