#!/usr/bin/env python3
# encoding: utf-8
__all__ = [
"P115Error", "P115Warning", "P115OSError", "P115AccessError",
"P115AuthenticationError", "P115BusyOSError", "P115DataError",
"P115OperationalError", "P115FileTooBig", "P115ExceededError",
"P115InvalidArgumentError", "P115NoSpaceError", "P115NotSupportedError",
"P115LoginError", "P115AccessTokenError", "P115OpenAppAuthLimitExceeded",
"error", "throw", "errno2error"
]
import warnings
from itertools import count
from collections.abc import Mapping
from functools import cached_property
from typing import Never
from errno2 import errno, errno2error as _errno2error
warnings.filterwarnings("always", category=UserWarning)
setattr(warnings, "formatwarning", lambda message, category, filename, lineno, line=None, _getid=count(1).__next__:
f"\r\x1b[K\x1b[1;31;43m{category.__qualname__}\x1b[0m(\x1b[32m{_getid()}\x1b[0m) @ \x1b[3;4;34m{filename}\x1b[0m:\x1b[36m{lineno}\x1b[0m \x1b[5;31m➜\x1b[0m \x1b[1m{message}\x1b[0m\n"
)
[docs]
class P115Error(Exception):
"""本模块的最基础异常类
"""
[docs]
class P115Warning(P115Error, UserWarning):
"""本模块的最基础警示类
"""
[docs]
class P115OSError(P115Error, OSError):
"""本模块的最基础输出输出异常类
"""
def __getattr__(self, attr, /):
try:
return self[attr]
except KeyError as e:
raise AttributeError(attr) from e
def __getitem__(self, key, /):
message = self.message
if isinstance(message, Mapping):
return message[key]
raise KeyError(key)
@cached_property
def message(self, /):
if args := self.args:
if len(args) >= 2 and isinstance(args[0], int):
return args[1]
return args[0]
[docs]
class P115AuthenticationError(P115OSError):
"""当登录状态无效时抛出
"""
[docs]
class P115BusyOSError(P115OSError):
"""当操作繁忙时抛出(115 网盘的复制、移动、删除、还原只允许最多一个操作进行中)
"""
[docs]
class P115DataError(P115OSError):
"""当响应数据解析失败时抛出
"""
[docs]
class P115OperationalError(P115OSError):
"""当接口使用方法错误时抛出,例如参数错误、空间不足、超出允许数量范围等
"""
[docs]
class P115AccessError(P115OperationalError, PermissionError):
"""当不可访问时抛出,可能是文件被和谐了
"""
[docs]
class P115FileTooBig(P115OperationalError, PermissionError):
"""文件过大
"""
[docs]
class P115ExceededError(P115OperationalError, PermissionError):
"""超出允许数量范围
"""
[docs]
class P115InvalidArgumentError(P115OperationalError, ValueError):
"""参数错误
"""
[docs]
class P115NoSpaceError(P115OperationalError, PermissionError):
"""空间不足
"""
[docs]
class P115NotSupportedError(P115OperationalError):
"""当调用不存在的接口或者接口不支持此操作时抛出
"""
[docs]
class P115LoginError(P115AuthenticationError):
"""当登录失败时抛出
"""
[docs]
class P115AccessTokenError(P115OSError, ValueError):
"""access_token 错误或者无效
"""
[docs]
class P115OpenAppAuthLimitExceeded(P115AuthenticationError):
"""当授权应用数达到上限时抛出
"""
[docs]
def error(*args, **kwds) -> BaseException:
"""构建异常
.. tip::
会根据传入的位置参数,做一些类型推断
- 第 1 个位置参数,记作 `errcode`,大概是一个 `errno2.errno` 的枚举类型,不能成功推断则用 `errno2.errno.EIO`
- 第 2 个位置参数(若第 1 个位置参数不满足上一条,则用此参数),记作 `exctype`,大概是一个 `P115Error` 类型或其子类型,不能成功推断则用 `P115OSError`
假设剩余的所有没被提取的位置参数记作 `rargs`,最终构建的异常为 `exctype(errcode, *rargs, **kwds)`
"""
if args and isinstance(args[0], errno):
errcode = args[0]
args = args[1:]
else:
errcode = errno.EIO
if not (args and isinstance(args[0], type) and issubclass(args[0], BaseException)):
args = errno2error.get(errcode, P115OSError), *args
return errcode.error(*args, **kwds)
[docs]
def throw(*args, **kwds) -> Never:
"""抛出异常
.. tip::
会根据传入的位置参数,做一些类型推断
- 第 1 个位置参数,记作 `errcode`,大概是一个 `errno2.errno` 的枚举类型,不能成功推断则用 `errno2.errno.EIO`
- 第 2 个位置参数(若第 1 个位置参数不满足上一条,则用此参数),记作 `exctype`,大概是一个 `P115Error` 类型或其子类型,不能成功推断则用 `P115OSError`
假设剩余的所有没被提取的位置参数记作 `rargs`,最终抛出的异常为 `exctype(errcode, *rargs, **kwds)`
"""
raise error(*args, **kwds)
#: errno 到的异常类的映射
errno2error: dict[errno, type[P115Error]] = {
errno.EAUTH: P115AuthenticationError,
errno.EBUSY: P115BusyOSError,
errno.ENODATA: P115DataError,
errno.EACCES: P115AccessError,
errno.EFBIG: P115FileTooBig,
errno.ERANGE: P115ExceededError,
errno.EINVAL: P115InvalidArgumentError,
errno.ENOSPC: P115NoSpaceError,
errno.ENOTSUP: P115NotSupportedError,
errno.ENOSYS: P115NotSupportedError,
}
_modns = globals()
for errcode, exctype in _errno2error.items():
typename = "P115" + exctype.__name__
if typename not in _modns:
cls = _modns[typename] = type(typename, (P115OSError, exctype), {"__doc__": errcode.description})
__all__.append(typename)
errno2error[errcode] = cls
def __getattr__(attr: str, /) -> type[P115OSError]:
raise AttributeError(attr)