anylearn.interfaces.base 源代码

from typing import Optional
from abc import ABC, abstractclassmethod, abstractmethod

from anylearn.utils.api import (
    url_base,
    post_with_token,
    put_with_token,
    delete_with_token
)
from anylearn.utils.errors import (
    AnyLearnException,
    AnyLearnMissingParamException
)


[文档]class BaseObject(ABC): """具体资源信息配置""" _fields = { # 资源创建/更新请求包体中必须包含且不能为空的字段 'required': { 'create': [], 'update': [], }, # 资源创建/更新请求包体中包含的所有字段 'payload': { 'create': [], 'update': [], }, } """ 所有子类中需定制 :obj:`_fields` 的字段内容以满足创建/更新所需要的字段 创建/更新对象时: - 必须包含且不能为空的字段 :obj:`_fields['required']` - 所有字段 :obj:`_fields['payload']` """
[文档] def __init__(self, id: Optional[str]=None, load_detail=False): """ Parameters ---------- id 对象的ID load_detail 初始化对象时是否加载详情 """ self.id = id if load_detail: self.get_detail()
[文档] @abstractclassmethod def get_list(self) -> list: """ 获取对象列表,子类需实现此抽象方法 """ raise NotImplementedError
[文档] @abstractmethod def get_detail(self): """ 获取对象详情,子类需实现此抽象方法 """ raise NotImplementedError
[文档] @abstractmethod def _namespace(self): """ - 子类的命名空间,调用此方法以获取子类的名称用于异常信息输出等,以 :obj:`User` 为例, :obj:`_namespace` 可以为 :obj:`user` - 子类需实现此抽象方法 """ raise NotImplementedError
[文档] def save(self): """ 创建或更新对象 - 对象包含非空属性 :obj:`id` 时为更新,否则为创建 - 创建对象时必须包含且不能为空的字段: :obj:`_fields['required']['create']` - 创建对象时包含的所有字段: :obj:`_fields['payload']['create']` - 更新对象时必须包含且不能为空的字段: :obj:`_fields['required']['update']` - 更新对象时包含的所有字段: :obj:`_fields['payload']['update']` Returns ------- bool True or False """ if self.id: self._check_fields(required=self._fields['required']['update']) return self._update() else: self._check_fields(required=self._fields['required']['create']) return self._create()
[文档] def _update(self): """ 更新对象,如果子类更新方法与此有较大差异可以重写此方法 """ data = self._payload_update() res = put_with_token(self._url_update(), data=data) if not res or 'data' not in res: raise AnyLearnException("请求未能得到有效响应") return self.id == res['data']
def _payload_update(self): return {k: self.__getattribute__(k) for k in self._fields['payload']['update']}
[文档] def _create(self): """ 创建对象,如果子类创建方法与此有较大差异可以重写此方法 """ data = self._payload_create() res = post_with_token(self._url_create(), data=data) if not res or 'data' not in res: raise AnyLearnException("请求未能得到有效响应") self.id = res['data'] return True
def _payload_create(self): return {k: self.__getattribute__(k) for k in self._fields['payload']['create']}
[文档] def delete(self, force: bool=False): """ 删除对象 - 对象属性 :obj:`id` 应为非空 Returns ------- bool True or False """ self._check_fields(required=['id']) res = delete_with_token(self._url_delete(), params={ 'id': self.id, 'force': 1 if force else 0, }) if not res or 'data' not in res: raise AnyLearnException("请求未能得到有效响应") return self.id == res['data']
[文档] def _check_fields(self, required=[]): """ 对象检查属性是否存在 """ missed = [field for field in required if not self.__getattribute__(field)] if missed: msg = f"{self.__class__.__name__}缺少必要字段:{missed}" raise AnyLearnMissingParamException(msg)
[文档] def _url_create(self): """ 创建对象url,如果子类创建对象接口名称不是 :obj:`add` ,可以重写此方法来定制接口名称 """ return f"{url_base()}/{self._namespace()}/add"
[文档] def _url_update(self): """ 更新对象url,如果子类更新对象接口名称不是 :obj:`update` ,可以重写此方法来定制接口名称 """ return f"{url_base()}/{self._namespace()}/update"
[文档] def _url_delete(self): """ 删除对象url,如果子类删除对象接口名称不是 :obj:`delete` ,可以重写此方法来定制接口名称 """ return f"{url_base()}/{self._namespace()}/delete"
def __repr__(self): d = self.__dict__ kv = ", ".join([f"{k}={d[k]!r}" for k in d]) return f"{self.__class__.__name__}({kv})"