pycorelibs


Namepycorelibs JSON
Version 0.2.7 PyPI version JSON
download
home_pageNone
SummaryA collection of reusable python core library from AI Lingues.
upload_time2025-10-23 04:52:54
maintainerNone
docs_urlNone
authorNone
requires_python>=3.11
licenseMIT
keywords ailingues components core library
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # PyCoreLibs

AI Lingues 基础组件库- PyCoreLibs

## Message

消息库,基于redis的异步消息框架

参考:redis/README.md

## Network

### search 搜索引擎

互联网搜索引擎

### requests 请求

- fetch_url 强化版通用网络请求函数,增加了重试机制,并适用于复杂场景。

- is_url 验证是否为合法url

### scrawer 网页文本获取

- HTMLContent 提取网页内容


## security 模块

### base64s 模块

### cryptographys 模块

----

#### AsymmetricCrypto: 稳健可靠的非对称加解密 + 签名/验签 工具类

##### 说明

- 加解密:RSA-OAEP(SHA-256) + AES-GCM(256) 的混合加密(任意长度数据)
- 签名:RSA-PSS(SHA-256),返回 JSON 打包(Base64)
- 设计目标:健壮、跨语言友好(JSON+Base64)、异常统一封装

|函数               |说明                           |
|-------------------|------------------------------|
|`generate_keypair`   |  生成密钥对(PEM)             |
|`encrypt`            |公钥加密(混合加密)             |
|`decrypt`            |私钥解密                       |
|`sign`               |私钥签名(RSA-PSS + SHA-256)  |
|`verify`             |公钥验签                       |

##### 示例

  ```python
      from pycorelibs.security.cryptographys import AsymmetricCrypto
      message = b"hello, asymmetric crypto! \xf0\x9f\x94\x90"

      # 1) 生成密钥对(内存)
      priv, pub = AsymmetricCrypto.generate_keypair(
          key_size=2048, private_password=b"pass"
      )

      # 2) 加密(可选 AAD)
      aad = b"meta:example"
      blob = AsymmetricCrypto.encrypt(message, pub, aad=aad)

      # 3) 解密
      plain = AsymmetricCrypto.decrypt(blob, priv, private_password=b"pass")
      assert plain == message
      print("Decrypt OK:", plain.decode("utf-8"))

      # 4) 签名
      sig_blob = AsymmetricCrypto.sign(message, priv, private_password=b"pass")

      # 5) 验签(成功)
      ok = AsymmetricCrypto.verify(message, sig_blob, pub)
      print("Verify OK:", ok)

      # 6) 验签(失败示例:数据被改动)
      tampered = message + b"!"
      bad = AsymmetricCrypto.verify(tampered, sig_blob, pub)
      print("Verify with tamper:", bad)

  ```

----

##### generate_keypair

生成 RSA 密钥对(PKCS#8 私钥 + X.509 公钥,PEM 格式)

###### 参数说明

- key_size (int, optional)

  2048/3072/4096(推荐 2048+). Defaults to 2048.

- private_password (Optional[bytes], optional)

  给私钥加密的口令(None 表示不加密). Defaults to None.

- save_to (Optional[str], optional)

  可选保存目录(写入 private.pem / public.pem). Defaults to None.

###### Raises

- ValueError:
  RSA key_size 仅支持 2048/3072/4096。

- AsymmetricCryptoError:
  生成密钥对失败

###### Returns

- Tuple[bytes, bytes]
  
  生成 RSA 密钥对(PKCS#8 私钥 + X.509 公钥,PEM 格式)

----

### fingerprints 模块

  跨平台硬件指纹

- 只用 Python 库,不走系统命令;信息更稳定
- 多网卡:枚举全部,带过滤选项(是否包含虚拟/回环、是否只取UP、是否要求有IP)
- 主 MAC 选择策略可配置
- 生成哈希指纹(可传入 salt 提高伪造成本)

#### generate_hardware_fingerprint

生成硬件指纹(不包含TPM)

##### 参数说明

- isGPU (bool):

  是否获取GPU信息,缺省为False

- salt (Optional[str], optional):

  额外盐值(字符串)。如用于授权/反爬,建议传入,提高伪造成本。. Defaults to None.

##### Returns

Dict[str, Any]: {
                    "fid": "\<sha512 hex\>",
                    "hash": "sha512",
                    "input": data,
                }

- "fid": "\<sha512 hex\>"

  最终指纹ID,长度128个字符

- "hash": "sha512"

  固定标记,加密算法名

- input": data
  
  加密原始数据

##### 示例

  ```python
      from pycorelibs.security.fingerprints import generate_hardware_fingerprint
      # 典型:只要UP、排除虚拟和回环;无IP也可(离线机器也能给出指纹)
      fp = generate_hardware_fingerprint()
      print(fp)
      print("*" * 80)
      # 更“联网语义”:要求接口必须有非回环IP
      fp_net = generate_hardware_fingerprint(require_ip=True)
      print(fp_net)
      print("*" * 80)
      # 有授权/反爬需求:加盐
      fp_salted = generate_hardware_fingerprint(salt="your-secret-salt-123")
      print(fp_salted)
      print("*" * 80)

  ```

### md5s 模块

#### md5

计算输入内容的 MD5 值

##### 参数说明

- text (Any):
  
  任意可转为字符串的输入内容。

- length (int):

  结果长度,可选 16 或 32(默认 32)。

- isHex (bool):

  是否以十六进制格式输出(默认为 True)。

##### 返回

- (bool, Optional[str])

  成功与否、以及 MD5 值字符串或 None。

----

## system模块

获取当前系统信息

- OS 操作系统
- CPU
- Macs 网卡
- MB 主板

### runtime 运行期信息模块

 获取运行期相关信息

#### RunTimeInfo类

##### get_boot_time

获取系统启动时间和系统已运行时长

跨平台细节:

- Linux:boot_time 基本来自 btime(自启动以来的挂钟差,包含睡眠/休眠的停留时间)。
- Windows:psutil 内部通常用系统 tick 估算,一般不包含睡眠时间(更接近“活跃运行时长”)。

###### 参数说明

- fmt (Optional[str], optional):
  
    时间格式化字符串,默认为 None 使用当前系统设定时区的本地格式.

###### Returns

- Dict[str, Any]:
    包含启动时间戳、格式化时间、已运行秒数和可读格式

----

###### get_uptime

获取自 start_mono(monotonic 起点)至今的运行时长(不受系统时钟跳变影响,如被 NTP/手动调整,或夏令时切换)

###### 参数说明

- start_mono (float, optional):

  计算开始时间. Defaults to _SERVICE_START_.

- fmt (Optional[str], optional):

  时间格式化字符串,默认为 None 使用当前系统设定时区的本地格式.. Defaults to None.

###### Returns

- Dict[str, Any]:
  
  包含启动时间戳、格式化时间、已运行秒数和可读格式

----

## Utils

----

### config配置模块

通用的本地配置存取层(与数据结构无关)

  1. 面向任意Python对象:通过可插拔 Serializer 适配(JSON/YAML/TOML/Pickle/自定义均可)
  2. 原子写入、自动创建目录、可选自动保存
  3. 多命名空间:各自文件、各自序列化器,互不干扰
  4. 默认保存到“应用同目录”
  5. 支持配置文件加密存储

#### ConfigRepo类

仓库:管理多个命名空间。

  一个应用一个仓库,里面可注册多个命名空间。

  每个命名空间:独立文件 + 独立序列化器 + 独立默认值

##### 构造函数

  ```python
    __init__(self, root: Optional[str] = None, subdir: Optional[str] = None)
  ```

**作用**:创建一个配置仓库实例,确定所有命名空间文件的根目录。

###### 参数说明

- root:str | None

  仓库根目录的绝对/相对路径。若为 None,则自动解析为**应用同目录**:

   - PyInstaller 打包后:os.path.dirname(sys.executable)

   - 普通脚本:os.path.dirname(os.path.abspath(sys.argv[0] or __file__))

- subdir:str | None

    root 下的子目录名(例如 "config"),用于把配置集中到 root/subdir。

###### 返回

无。

###### 副作用

若目录不存在会自动创建。

###### 示例

    ```python

    # 保存到应用目录下的 ./config/
    repo = ConfigRepo(subdir="config")

    # 保存到指定绝对路径
    repo = ConfigRepo(root="D:/myapp/config")
    ```

-  register注册命名空间
    ```python
    register(self, name: str, serializer: Serializer[Any], filename: Optional[str] = None, default_factory: Optional[Callable[[], Any]] = None, autosave: bool = False, backup_on_save: bool = False, cipher: Optional[AesGcmBox] = None, cipher_policy: str = "auto", encrypt_on_save_if_cipher: bool = True) -> Namespace[Any]
    ```

    **作用**:

    注册一个命名空间(即一个逻辑“配置空间”),绑定文件、序列化器、默认值与加密策略。

    **参数**:

    - name:str
    命名空间名称(在仓库内唯一)。

    - serializer:Serializer[Any]
    序列化器实例:如 JsonSerializer()、PickleSerializer() 或自定义实现(需提供 dumps(obj)->bytes 与 loads(bytes)->obj)。

    - filename:str | None
    文件名。若省略:当 serializer 为 JsonSerializer 时默认 "<name>.json",否则为 "<name>.bin"。

    - default_factory:() -> Any | None
    当文件不存在或需重置时,用此函数惰性生成默认对象(如 dict/list/自定义对象)。若省略,默认值为 None。

    - autosave:bool
    设为 True 时,调用 set() / update() / reset() 等修改后会自动保存到文件。

    - backup_on_save:bool
    保存前若目标文件已存在,将其重命名为 *.bak 作为备份。

    - cipher:AesGcmBox | None
    可选的加密盒;提供则进行加密存储(AES-GCM)。不提供则明文存储。

    - cipher_policy:"auto" | "require"(默认 "auto")

      - "auto":读取时若检测到加密魔数则解密,否则按明文加载(兼容旧文件);

      - "require":强制要求文件为加密格式,若无魔数直接抛错(适合敏感空间)。

    - encrypt_on_save_if_cipher:bool(默认 True)
    当 cipher 存在且此前是明文加载的旧文件,保存时会自动迁移为加密格式。

    **返回**:

    Namespace[Any]:已注册的命名空间对象。

    **异常**:
    
    无(但后续加载/保存时可能抛出序列化/IO/解密类异常)。

    **示例**:
    ```python
    # 明文 JSON 偏好设置
    ui = repo.register(
        name="ui",
        serializer=JsonSerializer(),
        filename="ui.json",
        default_factory=lambda: {"theme": "light", "recent_files": []},
        autosave=True
    )

    # 加密的 Pickle 缓存(旧明文文件可兼容读取,保存后自动迁移为密文)
    cache = repo.register(
        name="cache",
        serializer=PickleSerializer(),
        filename="cache.dat",
        default_factory=list,
        autosave=True,
        cipher=AesGcmBox(password=os.environ["CACHE_PASSWORD"]),
        cipher_policy="auto",
        encrypt_on_save_if_cipher=True,
    )
    ```
    ----

- space 取命名空间对象
  ```python
  space(self, name: str) -> Namespace[Any]
  ```
  **作用**:按名称获取已注册的命名空间对象。

  **参数**:

  - name:str
  注册时使用的命名空间名称。

  **返回**:

  - Namespace[Any]:命名空间对象。

  **异常**:

  - KeyError:当 name 尚未注册时抛出。

  **示例**:

  ```python
  cache_ns = repo.space("cache")
  ```
  ----

- get直接存取对象(便捷方法)

  ```python
  get(self, name: str) -> Any
  ```

  **作用**:从指定命名空间读取对象(内部若未加载会自动调用 Namespace.load())。

  **参数**:

    - name:str

  **返回**:

  - Any:命名空间中的对象(可能是 dict/list/自定义对象/None 等)。

  **异常**:

  - KeyError:命名空间未注册;

  - 反序列化/解密/IO 异常:底层抛出的 ValueError、OSError 等。

  **示例**:
  ```python
  ui_data = repo.get("ui")  # 例如: {"theme": "light", "recent_files": []}
  ```
  ----

- set(self, name: str, value: Any, save: Optional[bool] = None) -> None

  **作用**:设置命名空间对象并可选择保存。

  **参数**:

  - name:str

  - value:Any
  要写入的对象(会通过绑定的 serializer 持久化)。

  - save:bool | None

      **True**:立即保存;

      **False**:只更新内存缓存,不落盘;

      **None**:跟随命名空间的 autosave 设置(若为 True 则保存)。

  **返回**:无。

  **异常**:同 get()。

  **示例**:
  ```python
    repo.set("ui", {"theme": "dark"}, save=True)
  ```
  ----

- update(self, name: str, mutator: Callable[[Any], Any], save: Optional[bool] = None) -> Any

  **作用**:在原对象基础上以函数式方式变换并回写(读 -> 变换 -> 写)。

  **参数**:

  - name:str

  - mutator:(obj: Any) -> Any
  入参是当前对象,返回变换后的新对象(函数内应返回新值)。

  - save:bool | None
  语义同 set() 的 save。

  **返回**:

  - Any:变换后的新对象。

  **异常**:同 get()/set()。

  **示例**:
  ```python
  def add_recent(d):
      d = d or {}
      rec = (d.get("recent_files") or []) + ["a.sdf"]
      return {**d, "recent_files": rec[-10:]}  # 只保留最近10条

  new_ui = repo.update("ui", add_recent, save=True)
  ```
  ----

- 批量操作
save_all(self) -> None

  **作用**:对所有“已加载过”的命名空间执行 save()(避免无意义的空写)。

  **参数**:无。

  **返回**:无。

  **异常**:底层保存可能抛出 IO/序列化/加密相关异常。

  注意:

  仅对内部标记 _loaded == True 的空间生效;

  若你需要确保所有空间都有初值并保存,可先 load_all() 或逐个 space(...).get() 激活。

  **示例**:
  ```python
  # 某些空间 autosave=False,集中一次性保存
  repo.save_all()
  ```
  ----

- load_all(self) -> None

  **作用**:对所有已注册的命名空间执行 load()(将文件内容加载到内存缓存)。

  **参数**:无。

  **返回**:无。

  **异常**:底层加载可能抛出 IO/反序列化/解密相关异常。

  **示例**:

  ```python
  # 应用启动时预热全部配置
  repo.load_all()
  ```

#### 常见问题与注意事项

- 路径选择:

  默认落在应用同目录,便于“就地携带”。如需跨用户共享或写权限受限(Windows Program Files),建议显式指定 root。

- 默认值:

  default_factory 推荐传入 可调用(如 dict/list/lambda),避免可变对象作为默认参数带来的共享副作用。

- 加密策略:

  - **"auto"**:适合从旧明文平滑迁移为密文;

  - **"require"**:适合强约束的敏感空间(若非加密立刻报错)。

- 备份文件:

  backup_on_save=True 时会生成 *.bak;其内容可能为上一次保存时的明文或密文,读取时可用 AesGcmBox.is_encrypted() 判别。

- 异常处理:

  解密失败通常是口令/密钥不匹配或文件损坏;请捕获 ValueError 并引导用户检查口令来源。

- 线程/进程并发:
  
  当前实现是单进程内使用的简单本地层;若存在多进程/多实例同时写入同一文件,请自行加锁或采用更高级别的存储方案。

#### 典型用法示例(整合)
```python
from pycorelibs.utils.config import ConfigRepo, JsonSerializer, PickleSerializer
from pycorelibs.security.aesgcmbox import AesGcmBox
import os

repo = ConfigRepo(subdir="config")

# 明文 UI 配置
ui = repo.register(
    name="ui",
    serializer=JsonSerializer(),
    filename="ui.json",
    default_factory=lambda: {"theme": "light", "recent_files": []},
    autosave=True,
)

# 加密的缓存(从旧明文自动迁移)
cache = repo.register(
    name="cache",
    serializer=PickleSerializer(),
    filename="cache.dat",
    default_factory=list,
    autosave=True,
    cipher=AesGcmBox(password=os.environ.get("CACHE_PW", "CHANGE_ME")),
    cipher_policy="auto",
    encrypt_on_save_if_cipher=True,
)

# 读取 / 更新 / 批量保存
ui_data = repo.get("ui")
repo.update("ui", lambda d: {**(d or {}), "theme": "dark"})
repo.update("cache", lambda lst: (lst or []) + ["session#1"])
repo.save_all()

```
----

### files文件处理

- EnumFileSizeUnit

- FilesInfo 类

  - get_file_size
    获取文件大小,并返回指定单位的大小。

        支持B,KB,MB,GB,TB

  - line_count

        获取指定文件的总行数

        Windows系统: 使用换行符作为判断标记
        Linux系统: 使用系统自带的wc命令统计

        注: 近适用于文本类型文件,其他类型如二进制文件统计结果不具备参考意义

  - get_directory_last_modified_time
  获取指定目录最后修改时间

  - get_directory_last_modified_timestamp
  获取指定目录最后修改时间戳

### formate 数据格式化指定类型

Formates 类,静态方法如下:

- fInt 转换为整数
- fFloat 转换为浮点数
- fBool 转换为布尔值
- fDate 按指定格式解析日期
- fEnum 校验值是否在允许集合内(用于枚举字段)
- fJSON 解析为 JSON 对象

### logger日志

- 支持自动产生日志
- 支持同时向控制台和日志文件输出
- 支持进度条
- 支持info、warning和error三个级别的日志

### strings 字符串处理

- UniCodeGenerator 模块

  创建随机码,日期前缀 + 随机码

  可配置、使用 secrets 生成高强度随机码的编码生成类

  | 场景            | 参数示例                                        |
  | ----------------| ---------------------------------------------- |
  | 邀请码(短)     | `prefix_date=False, random_length=6`           |    
  | 订单号(当天唯一)| `prefix_date=True, random_length=4`            |
  | URL 安全短码     | `charset=string.ascii_letters + string.digits` |

- json_dumps_bytes 函数

  将 dict 序列化为紧凑 UTF-8 JSON bytes

- json_loads_bytes 函数

  将 UTF-8 JSON bytes 解析为 dict,并进行基本类型校验
    
- split_text_by_marker函数
  
  **作用**: 按照指定字符串 marker 分割文本,可选择是否保留 marker,并支持严格模式。

  **参数**:
  - text (str): 需要分割的原始文本。
  - marker (str): 分割标记字符串。
  - keep_marker (bool): 是否保留 marker 到结果中,默认为 True。
  - strict (bool): 严格模式。当 marker 不存在时抛异常。默认为 False。

  **返回**:
  - List[str]: 分割后的文本列表。
    如果 strict=False 且 marker 不存在,返回空列表。
    如果 strict=True 且 marker 不存在,抛出 ValueError。

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "pycorelibs",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.11",
    "maintainer_email": null,
    "keywords": "AILingues, components, core, library",
    "author": null,
    "author_email": "AI Lingues <support@ailingues.com>",
    "download_url": null,
    "platform": null,
    "description": "# PyCoreLibs\n\nAI Lingues \u57fa\u7840\u7ec4\u4ef6\u5e93- PyCoreLibs\n\n## Message\n\n\u6d88\u606f\u5e93\uff0c\u57fa\u4e8eredis\u7684\u5f02\u6b65\u6d88\u606f\u6846\u67b6\n\n\u53c2\u8003:redis/README.md\n\n## Network\n\n### search \u641c\u7d22\u5f15\u64ce\n\n\u4e92\u8054\u7f51\u641c\u7d22\u5f15\u64ce\n\n### requests \u8bf7\u6c42\n\n- fetch_url \u5f3a\u5316\u7248\u901a\u7528\u7f51\u7edc\u8bf7\u6c42\u51fd\u6570\uff0c\u589e\u52a0\u4e86\u91cd\u8bd5\u673a\u5236,\u5e76\u9002\u7528\u4e8e\u590d\u6742\u573a\u666f\u3002\n\n- is_url \u9a8c\u8bc1\u662f\u5426\u4e3a\u5408\u6cd5url\n\n### scrawer \u7f51\u9875\u6587\u672c\u83b7\u53d6\n\n- HTMLContent \u63d0\u53d6\u7f51\u9875\u5185\u5bb9\n\n\n## security \u6a21\u5757\n\n### base64s \u6a21\u5757\n\n### cryptographys \u6a21\u5757\n\n----\n\n#### AsymmetricCrypto: \u7a33\u5065\u53ef\u9760\u7684\u975e\u5bf9\u79f0\u52a0\u89e3\u5bc6 + \u7b7e\u540d/\u9a8c\u7b7e \u5de5\u5177\u7c7b\n\n##### \u8bf4\u660e\n\n- \u52a0\u89e3\u5bc6\uff1aRSA-OAEP(SHA-256) + AES-GCM(256) \u7684\u6df7\u5408\u52a0\u5bc6\uff08\u4efb\u610f\u957f\u5ea6\u6570\u636e\uff09\n- \u7b7e\u540d\uff1aRSA-PSS(SHA-256)\uff0c\u8fd4\u56de JSON \u6253\u5305\uff08Base64\uff09\n- \u8bbe\u8ba1\u76ee\u6807\uff1a\u5065\u58ee\u3001\u8de8\u8bed\u8a00\u53cb\u597d\uff08JSON+Base64\uff09\u3001\u5f02\u5e38\u7edf\u4e00\u5c01\u88c5\n\n|\u51fd\u6570               |\u8bf4\u660e                           |\n|-------------------|------------------------------|\n|`generate_keypair`   |  \u751f\u6210\u5bc6\u94a5\u5bf9\uff08PEM\uff09             |\n|`encrypt`            |\u516c\u94a5\u52a0\u5bc6\uff08\u6df7\u5408\u52a0\u5bc6\uff09             |\n|`decrypt`            |\u79c1\u94a5\u89e3\u5bc6                       |\n|`sign`               |\u79c1\u94a5\u7b7e\u540d\uff08RSA-PSS + SHA-256\uff09  |\n|`verify`             |\u516c\u94a5\u9a8c\u7b7e                       |\n\n##### \u793a\u4f8b\n\n  ```python\n      from pycorelibs.security.cryptographys import AsymmetricCrypto\n      message = b\"hello, asymmetric crypto! \\xf0\\x9f\\x94\\x90\"\n\n      # 1) \u751f\u6210\u5bc6\u94a5\u5bf9\uff08\u5185\u5b58\uff09\n      priv, pub = AsymmetricCrypto.generate_keypair(\n          key_size=2048, private_password=b\"pass\"\n      )\n\n      # 2) \u52a0\u5bc6\uff08\u53ef\u9009 AAD\uff09\n      aad = b\"meta:example\"\n      blob = AsymmetricCrypto.encrypt(message, pub, aad=aad)\n\n      # 3) \u89e3\u5bc6\n      plain = AsymmetricCrypto.decrypt(blob, priv, private_password=b\"pass\")\n      assert plain == message\n      print(\"Decrypt OK:\", plain.decode(\"utf-8\"))\n\n      # 4) \u7b7e\u540d\n      sig_blob = AsymmetricCrypto.sign(message, priv, private_password=b\"pass\")\n\n      # 5) \u9a8c\u7b7e\uff08\u6210\u529f\uff09\n      ok = AsymmetricCrypto.verify(message, sig_blob, pub)\n      print(\"Verify OK:\", ok)\n\n      # 6) \u9a8c\u7b7e\uff08\u5931\u8d25\u793a\u4f8b\uff1a\u6570\u636e\u88ab\u6539\u52a8\uff09\n      tampered = message + b\"!\"\n      bad = AsymmetricCrypto.verify(tampered, sig_blob, pub)\n      print(\"Verify with tamper:\", bad)\n\n  ```\n\n----\n\n##### generate_keypair\n\n\u751f\u6210 RSA \u5bc6\u94a5\u5bf9\uff08PKCS#8 \u79c1\u94a5 + X.509 \u516c\u94a5\uff0cPEM \u683c\u5f0f\uff09\n\n###### \u53c2\u6570\u8bf4\u660e\n\n- key_size (int, optional)\n\n  2048/3072/4096\uff08\u63a8\u8350 2048+\uff09. Defaults to 2048.\n\n- private_password (Optional[bytes], optional)\n\n  \u7ed9\u79c1\u94a5\u52a0\u5bc6\u7684\u53e3\u4ee4\uff08None \u8868\u793a\u4e0d\u52a0\u5bc6\uff09. Defaults to None.\n\n- save_to (Optional[str], optional)\n\n  \u53ef\u9009\u4fdd\u5b58\u76ee\u5f55\uff08\u5199\u5165 private.pem / public.pem\uff09. Defaults to None.\n\n###### Raises\n\n- ValueError:\n  RSA key_size \u4ec5\u652f\u6301 2048/3072/4096\u3002\n\n- AsymmetricCryptoError:\n  \u751f\u6210\u5bc6\u94a5\u5bf9\u5931\u8d25\n\n###### Returns\n\n- Tuple[bytes, bytes]\n  \n  \u751f\u6210 RSA \u5bc6\u94a5\u5bf9\uff08PKCS#8 \u79c1\u94a5 + X.509 \u516c\u94a5\uff0cPEM \u683c\u5f0f\uff09\n\n----\n\n### fingerprints \u6a21\u5757\n\n  \u8de8\u5e73\u53f0\u786c\u4ef6\u6307\u7eb9\n\n- \u53ea\u7528 Python \u5e93\uff0c\u4e0d\u8d70\u7cfb\u7edf\u547d\u4ee4\uff1b\u4fe1\u606f\u66f4\u7a33\u5b9a\n- \u591a\u7f51\u5361\uff1a\u679a\u4e3e\u5168\u90e8\uff0c\u5e26\u8fc7\u6ee4\u9009\u9879\uff08\u662f\u5426\u5305\u542b\u865a\u62df/\u56de\u73af\u3001\u662f\u5426\u53ea\u53d6UP\u3001\u662f\u5426\u8981\u6c42\u6709IP\uff09\n- \u4e3b MAC \u9009\u62e9\u7b56\u7565\u53ef\u914d\u7f6e\n- \u751f\u6210\u54c8\u5e0c\u6307\u7eb9\uff08\u53ef\u4f20\u5165 salt \u63d0\u9ad8\u4f2a\u9020\u6210\u672c\uff09\n\n#### generate_hardware_fingerprint\n\n\u751f\u6210\u786c\u4ef6\u6307\u7eb9\uff08\u4e0d\u5305\u542bTPM\uff09\n\n##### \u53c2\u6570\u8bf4\u660e\n\n- isGPU (bool):\n\n  \u662f\u5426\u83b7\u53d6GPU\u4fe1\u606f\uff0c\u7f3a\u7701\u4e3aFalse\n\n- salt (Optional[str], optional):\n\n  \u989d\u5916\u76d0\u503c\uff08\u5b57\u7b26\u4e32\uff09\u3002\u5982\u7528\u4e8e\u6388\u6743/\u53cd\u722c\uff0c\u5efa\u8bae\u4f20\u5165\uff0c\u63d0\u9ad8\u4f2a\u9020\u6210\u672c\u3002. Defaults to None.\n\n##### Returns\n\nDict[str, Any]: {\n                    \"fid\": \"\\<sha512 hex\\>\",\n                    \"hash\": \"sha512\",\n                    \"input\": data,\n                }\n\n- \"fid\": \"\\<sha512 hex\\>\"\n\n  \u6700\u7ec8\u6307\u7eb9ID\uff0c\u957f\u5ea6128\u4e2a\u5b57\u7b26\n\n- \"hash\": \"sha512\"\n\n  \u56fa\u5b9a\u6807\u8bb0\uff0c\u52a0\u5bc6\u7b97\u6cd5\u540d\n\n- input\": data\n  \n  \u52a0\u5bc6\u539f\u59cb\u6570\u636e\n\n##### \u793a\u4f8b\n\n  ```python\n      from pycorelibs.security.fingerprints import generate_hardware_fingerprint\n      # \u5178\u578b\uff1a\u53ea\u8981UP\u3001\u6392\u9664\u865a\u62df\u548c\u56de\u73af\uff1b\u65e0IP\u4e5f\u53ef\uff08\u79bb\u7ebf\u673a\u5668\u4e5f\u80fd\u7ed9\u51fa\u6307\u7eb9\uff09\n      fp = generate_hardware_fingerprint()\n      print(fp)\n      print(\"*\" * 80)\n      # \u66f4\u201c\u8054\u7f51\u8bed\u4e49\u201d\uff1a\u8981\u6c42\u63a5\u53e3\u5fc5\u987b\u6709\u975e\u56de\u73afIP\n      fp_net = generate_hardware_fingerprint(require_ip=True)\n      print(fp_net)\n      print(\"*\" * 80)\n      # \u6709\u6388\u6743/\u53cd\u722c\u9700\u6c42\uff1a\u52a0\u76d0\n      fp_salted = generate_hardware_fingerprint(salt=\"your-secret-salt-123\")\n      print(fp_salted)\n      print(\"*\" * 80)\n\n  ```\n\n### md5s \u6a21\u5757\n\n#### md5\n\n\u8ba1\u7b97\u8f93\u5165\u5185\u5bb9\u7684 MD5 \u503c\n\n##### \u53c2\u6570\u8bf4\u660e\n\n- text (Any):\n  \n  \u4efb\u610f\u53ef\u8f6c\u4e3a\u5b57\u7b26\u4e32\u7684\u8f93\u5165\u5185\u5bb9\u3002\n\n- length (int):\n\n  \u7ed3\u679c\u957f\u5ea6\uff0c\u53ef\u9009 16 \u6216 32\uff08\u9ed8\u8ba4 32\uff09\u3002\n\n- isHex (bool):\n\n  \u662f\u5426\u4ee5\u5341\u516d\u8fdb\u5236\u683c\u5f0f\u8f93\u51fa\uff08\u9ed8\u8ba4\u4e3a True\uff09\u3002\n\n##### \u8fd4\u56de\n\n- (bool, Optional[str])\n\n  \u6210\u529f\u4e0e\u5426\u3001\u4ee5\u53ca MD5 \u503c\u5b57\u7b26\u4e32\u6216 None\u3002\n\n----\n\n## system\u6a21\u5757\n\n\u83b7\u53d6\u5f53\u524d\u7cfb\u7edf\u4fe1\u606f\n\n- OS \u64cd\u4f5c\u7cfb\u7edf\n- CPU\n- Macs \u7f51\u5361\n- MB \u4e3b\u677f\n\n### runtime \u8fd0\u884c\u671f\u4fe1\u606f\u6a21\u5757\n\n \u83b7\u53d6\u8fd0\u884c\u671f\u76f8\u5173\u4fe1\u606f\n\n#### RunTimeInfo\u7c7b\n\n##### get_boot_time\n\n\u83b7\u53d6\u7cfb\u7edf\u542f\u52a8\u65f6\u95f4\u548c\u7cfb\u7edf\u5df2\u8fd0\u884c\u65f6\u957f\n\n\u8de8\u5e73\u53f0\u7ec6\u8282\uff1a\n\n- Linux\uff1aboot_time \u57fa\u672c\u6765\u81ea btime\uff08\u81ea\u542f\u52a8\u4ee5\u6765\u7684\u6302\u949f\u5dee\uff0c\u5305\u542b\u7761\u7720/\u4f11\u7720\u7684\u505c\u7559\u65f6\u95f4\uff09\u3002\n- Windows\uff1apsutil \u5185\u90e8\u901a\u5e38\u7528\u7cfb\u7edf tick \u4f30\u7b97\uff0c\u4e00\u822c\u4e0d\u5305\u542b\u7761\u7720\u65f6\u95f4\uff08\u66f4\u63a5\u8fd1\u201c\u6d3b\u8dc3\u8fd0\u884c\u65f6\u957f\u201d\uff09\u3002\n\n###### \u53c2\u6570\u8bf4\u660e\n\n- fmt (Optional[str], optional):\n  \n    \u65f6\u95f4\u683c\u5f0f\u5316\u5b57\u7b26\u4e32\uff0c\u9ed8\u8ba4\u4e3a None \u4f7f\u7528\u5f53\u524d\u7cfb\u7edf\u8bbe\u5b9a\u65f6\u533a\u7684\u672c\u5730\u683c\u5f0f.\n\n###### Returns\n\n- Dict[str, Any]:\n    \u5305\u542b\u542f\u52a8\u65f6\u95f4\u6233\u3001\u683c\u5f0f\u5316\u65f6\u95f4\u3001\u5df2\u8fd0\u884c\u79d2\u6570\u548c\u53ef\u8bfb\u683c\u5f0f\n\n----\n\n###### get_uptime\n\n\u83b7\u53d6\u81ea start_mono\uff08monotonic \u8d77\u70b9\uff09\u81f3\u4eca\u7684\u8fd0\u884c\u65f6\u957f\uff08\u4e0d\u53d7\u7cfb\u7edf\u65f6\u949f\u8df3\u53d8\u5f71\u54cd\uff0c\u5982\u88ab NTP/\u624b\u52a8\u8c03\u6574\uff0c\u6216\u590f\u4ee4\u65f6\u5207\u6362\uff09\n\n###### \u53c2\u6570\u8bf4\u660e\n\n- start_mono (float, optional):\n\n  \u8ba1\u7b97\u5f00\u59cb\u65f6\u95f4. Defaults to _SERVICE_START_.\n\n- fmt (Optional[str], optional)\uff1a\n\n  \u65f6\u95f4\u683c\u5f0f\u5316\u5b57\u7b26\u4e32\uff0c\u9ed8\u8ba4\u4e3a None \u4f7f\u7528\u5f53\u524d\u7cfb\u7edf\u8bbe\u5b9a\u65f6\u533a\u7684\u672c\u5730\u683c\u5f0f.. Defaults to None.\n\n###### Returns\n\n- Dict[str, Any]:\n  \n  \u5305\u542b\u542f\u52a8\u65f6\u95f4\u6233\u3001\u683c\u5f0f\u5316\u65f6\u95f4\u3001\u5df2\u8fd0\u884c\u79d2\u6570\u548c\u53ef\u8bfb\u683c\u5f0f\n\n----\n\n## Utils\n\n----\n\n### config\u914d\u7f6e\u6a21\u5757\n\n\u901a\u7528\u7684\u672c\u5730\u914d\u7f6e\u5b58\u53d6\u5c42\uff08\u4e0e\u6570\u636e\u7ed3\u6784\u65e0\u5173\uff09\n\n  1. \u9762\u5411\u4efb\u610fPython\u5bf9\u8c61\uff1a\u901a\u8fc7\u53ef\u63d2\u62d4 Serializer \u9002\u914d\uff08JSON/YAML/TOML/Pickle/\u81ea\u5b9a\u4e49\u5747\u53ef\uff09\n  2. \u539f\u5b50\u5199\u5165\u3001\u81ea\u52a8\u521b\u5efa\u76ee\u5f55\u3001\u53ef\u9009\u81ea\u52a8\u4fdd\u5b58\n  3. \u591a\u547d\u540d\u7a7a\u95f4\uff1a\u5404\u81ea\u6587\u4ef6\u3001\u5404\u81ea\u5e8f\u5217\u5316\u5668\uff0c\u4e92\u4e0d\u5e72\u6270\n  4. \u9ed8\u8ba4\u4fdd\u5b58\u5230\u201c\u5e94\u7528\u540c\u76ee\u5f55\u201d\n  5. \u652f\u6301\u914d\u7f6e\u6587\u4ef6\u52a0\u5bc6\u5b58\u50a8\n\n#### ConfigRepo\u7c7b\n\n\u4ed3\u5e93\uff1a\u7ba1\u7406\u591a\u4e2a\u547d\u540d\u7a7a\u95f4\u3002\n\n  \u4e00\u4e2a\u5e94\u7528\u4e00\u4e2a\u4ed3\u5e93\uff0c\u91cc\u9762\u53ef\u6ce8\u518c\u591a\u4e2a\u547d\u540d\u7a7a\u95f4\u3002\n\n  \u6bcf\u4e2a\u547d\u540d\u7a7a\u95f4\uff1a\u72ec\u7acb\u6587\u4ef6 + \u72ec\u7acb\u5e8f\u5217\u5316\u5668 + \u72ec\u7acb\u9ed8\u8ba4\u503c\n\n##### \u6784\u9020\u51fd\u6570\n\n  ```python\n    __init__(self, root: Optional[str] = None, subdir: Optional[str] = None)\n  ```\n\n**\u4f5c\u7528**\uff1a\u521b\u5efa\u4e00\u4e2a\u914d\u7f6e\u4ed3\u5e93\u5b9e\u4f8b\uff0c\u786e\u5b9a\u6240\u6709\u547d\u540d\u7a7a\u95f4\u6587\u4ef6\u7684\u6839\u76ee\u5f55\u3002\n\n###### \u53c2\u6570\u8bf4\u660e\n\n- root\uff1astr | None\n\n  \u4ed3\u5e93\u6839\u76ee\u5f55\u7684\u7edd\u5bf9/\u76f8\u5bf9\u8def\u5f84\u3002\u82e5\u4e3a None\uff0c\u5219\u81ea\u52a8\u89e3\u6790\u4e3a**\u5e94\u7528\u540c\u76ee\u5f55**\uff1a\n\n   - PyInstaller \u6253\u5305\u540e\uff1aos.path.dirname(sys.executable)\n\n   - \u666e\u901a\u811a\u672c\uff1aos.path.dirname(os.path.abspath(sys.argv[0] or __file__))\n\n- subdir\uff1astr | None\n\n    root \u4e0b\u7684\u5b50\u76ee\u5f55\u540d\uff08\u4f8b\u5982 \"config\"\uff09\uff0c\u7528\u4e8e\u628a\u914d\u7f6e\u96c6\u4e2d\u5230 root/subdir\u3002\n\n###### \u8fd4\u56de\n\n\u65e0\u3002\n\n###### \u526f\u4f5c\u7528\n\n\u82e5\u76ee\u5f55\u4e0d\u5b58\u5728\u4f1a\u81ea\u52a8\u521b\u5efa\u3002\n\n###### \u793a\u4f8b\n\n    ```python\n\n    # \u4fdd\u5b58\u5230\u5e94\u7528\u76ee\u5f55\u4e0b\u7684 ./config/\n    repo = ConfigRepo(subdir=\"config\")\n\n    # \u4fdd\u5b58\u5230\u6307\u5b9a\u7edd\u5bf9\u8def\u5f84\n    repo = ConfigRepo(root=\"D:/myapp/config\")\n    ```\n\n-  register\u6ce8\u518c\u547d\u540d\u7a7a\u95f4\n    ```python\n    register(self, name: str, serializer: Serializer[Any], filename: Optional[str] = None, default_factory: Optional[Callable[[], Any]] = None, autosave: bool = False, backup_on_save: bool = False, cipher: Optional[AesGcmBox] = None, cipher_policy: str = \"auto\", encrypt_on_save_if_cipher: bool = True) -> Namespace[Any]\n    ```\n\n    **\u4f5c\u7528**\uff1a\n\n    \u6ce8\u518c\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4\uff08\u5373\u4e00\u4e2a\u903b\u8f91\u201c\u914d\u7f6e\u7a7a\u95f4\u201d\uff09\uff0c\u7ed1\u5b9a\u6587\u4ef6\u3001\u5e8f\u5217\u5316\u5668\u3001\u9ed8\u8ba4\u503c\u4e0e\u52a0\u5bc6\u7b56\u7565\u3002\n\n    **\u53c2\u6570**\uff1a\n\n    - name\uff1astr\n    \u547d\u540d\u7a7a\u95f4\u540d\u79f0\uff08\u5728\u4ed3\u5e93\u5185\u552f\u4e00\uff09\u3002\n\n    - serializer\uff1aSerializer[Any]\n    \u5e8f\u5217\u5316\u5668\u5b9e\u4f8b\uff1a\u5982 JsonSerializer()\u3001PickleSerializer() \u6216\u81ea\u5b9a\u4e49\u5b9e\u73b0\uff08\u9700\u63d0\u4f9b dumps(obj)->bytes \u4e0e loads(bytes)->obj\uff09\u3002\n\n    - filename\uff1astr | None\n    \u6587\u4ef6\u540d\u3002\u82e5\u7701\u7565\uff1a\u5f53 serializer \u4e3a JsonSerializer \u65f6\u9ed8\u8ba4 \"<name>.json\"\uff0c\u5426\u5219\u4e3a \"<name>.bin\"\u3002\n\n    - default_factory\uff1a() -> Any | None\n    \u5f53\u6587\u4ef6\u4e0d\u5b58\u5728\u6216\u9700\u91cd\u7f6e\u65f6\uff0c\u7528\u6b64\u51fd\u6570\u60f0\u6027\u751f\u6210\u9ed8\u8ba4\u5bf9\u8c61\uff08\u5982 dict/list/\u81ea\u5b9a\u4e49\u5bf9\u8c61\uff09\u3002\u82e5\u7701\u7565\uff0c\u9ed8\u8ba4\u503c\u4e3a None\u3002\n\n    - autosave\uff1abool\n    \u8bbe\u4e3a True \u65f6\uff0c\u8c03\u7528 set() / update() / reset() \u7b49\u4fee\u6539\u540e\u4f1a\u81ea\u52a8\u4fdd\u5b58\u5230\u6587\u4ef6\u3002\n\n    - backup_on_save\uff1abool\n    \u4fdd\u5b58\u524d\u82e5\u76ee\u6807\u6587\u4ef6\u5df2\u5b58\u5728\uff0c\u5c06\u5176\u91cd\u547d\u540d\u4e3a *.bak \u4f5c\u4e3a\u5907\u4efd\u3002\n\n    - cipher\uff1aAesGcmBox | None\n    \u53ef\u9009\u7684\u52a0\u5bc6\u76d2\uff1b\u63d0\u4f9b\u5219\u8fdb\u884c\u52a0\u5bc6\u5b58\u50a8\uff08AES-GCM\uff09\u3002\u4e0d\u63d0\u4f9b\u5219\u660e\u6587\u5b58\u50a8\u3002\n\n    - cipher_policy\uff1a\"auto\" | \"require\"\uff08\u9ed8\u8ba4 \"auto\"\uff09\n\n      - \"auto\"\uff1a\u8bfb\u53d6\u65f6\u82e5\u68c0\u6d4b\u5230\u52a0\u5bc6\u9b54\u6570\u5219\u89e3\u5bc6\uff0c\u5426\u5219\u6309\u660e\u6587\u52a0\u8f7d\uff08\u517c\u5bb9\u65e7\u6587\u4ef6\uff09\uff1b\n\n      - \"require\"\uff1a\u5f3a\u5236\u8981\u6c42\u6587\u4ef6\u4e3a\u52a0\u5bc6\u683c\u5f0f\uff0c\u82e5\u65e0\u9b54\u6570\u76f4\u63a5\u629b\u9519\uff08\u9002\u5408\u654f\u611f\u7a7a\u95f4\uff09\u3002\n\n    - encrypt_on_save_if_cipher\uff1abool\uff08\u9ed8\u8ba4 True\uff09\n    \u5f53 cipher \u5b58\u5728\u4e14\u6b64\u524d\u662f\u660e\u6587\u52a0\u8f7d\u7684\u65e7\u6587\u4ef6\uff0c\u4fdd\u5b58\u65f6\u4f1a\u81ea\u52a8\u8fc1\u79fb\u4e3a\u52a0\u5bc6\u683c\u5f0f\u3002\n\n    **\u8fd4\u56de**\uff1a\n\n    Namespace[Any]\uff1a\u5df2\u6ce8\u518c\u7684\u547d\u540d\u7a7a\u95f4\u5bf9\u8c61\u3002\n\n    **\u5f02\u5e38**\uff1a\n    \n    \u65e0\uff08\u4f46\u540e\u7eed\u52a0\u8f7d/\u4fdd\u5b58\u65f6\u53ef\u80fd\u629b\u51fa\u5e8f\u5217\u5316/IO/\u89e3\u5bc6\u7c7b\u5f02\u5e38\uff09\u3002\n\n    **\u793a\u4f8b**\uff1a\n    ```python\n    # \u660e\u6587 JSON \u504f\u597d\u8bbe\u7f6e\n    ui = repo.register(\n        name=\"ui\",\n        serializer=JsonSerializer(),\n        filename=\"ui.json\",\n        default_factory=lambda: {\"theme\": \"light\", \"recent_files\": []},\n        autosave=True\n    )\n\n    # \u52a0\u5bc6\u7684 Pickle \u7f13\u5b58\uff08\u65e7\u660e\u6587\u6587\u4ef6\u53ef\u517c\u5bb9\u8bfb\u53d6\uff0c\u4fdd\u5b58\u540e\u81ea\u52a8\u8fc1\u79fb\u4e3a\u5bc6\u6587\uff09\n    cache = repo.register(\n        name=\"cache\",\n        serializer=PickleSerializer(),\n        filename=\"cache.dat\",\n        default_factory=list,\n        autosave=True,\n        cipher=AesGcmBox(password=os.environ[\"CACHE_PASSWORD\"]),\n        cipher_policy=\"auto\",\n        encrypt_on_save_if_cipher=True,\n    )\n    ```\n    ----\n\n- space \u53d6\u547d\u540d\u7a7a\u95f4\u5bf9\u8c61\n  ```python\n  space(self, name: str) -> Namespace[Any]\n  ```\n  **\u4f5c\u7528**\uff1a\u6309\u540d\u79f0\u83b7\u53d6\u5df2\u6ce8\u518c\u7684\u547d\u540d\u7a7a\u95f4\u5bf9\u8c61\u3002\n\n  **\u53c2\u6570**\uff1a\n\n  - name\uff1astr\n  \u6ce8\u518c\u65f6\u4f7f\u7528\u7684\u547d\u540d\u7a7a\u95f4\u540d\u79f0\u3002\n\n  **\u8fd4\u56de**\uff1a\n\n  - Namespace[Any]\uff1a\u547d\u540d\u7a7a\u95f4\u5bf9\u8c61\u3002\n\n  **\u5f02\u5e38**\uff1a\n\n  - KeyError\uff1a\u5f53 name \u5c1a\u672a\u6ce8\u518c\u65f6\u629b\u51fa\u3002\n\n  **\u793a\u4f8b**\uff1a\n\n  ```python\n  cache_ns = repo.space(\"cache\")\n  ```\n  ----\n\n- get\u76f4\u63a5\u5b58\u53d6\u5bf9\u8c61\uff08\u4fbf\u6377\u65b9\u6cd5\uff09\n\n  ```python\n  get(self, name: str) -> Any\n  ```\n\n  **\u4f5c\u7528**\uff1a\u4ece\u6307\u5b9a\u547d\u540d\u7a7a\u95f4\u8bfb\u53d6\u5bf9\u8c61\uff08\u5185\u90e8\u82e5\u672a\u52a0\u8f7d\u4f1a\u81ea\u52a8\u8c03\u7528 Namespace.load()\uff09\u3002\n\n  **\u53c2\u6570**\uff1a\n\n    - name\uff1astr\n\n  **\u8fd4\u56de**\uff1a\n\n  - Any\uff1a\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u5bf9\u8c61\uff08\u53ef\u80fd\u662f dict/list/\u81ea\u5b9a\u4e49\u5bf9\u8c61/None \u7b49\uff09\u3002\n\n  **\u5f02\u5e38**\uff1a\n\n  - KeyError\uff1a\u547d\u540d\u7a7a\u95f4\u672a\u6ce8\u518c\uff1b\n\n  - \u53cd\u5e8f\u5217\u5316/\u89e3\u5bc6/IO \u5f02\u5e38\uff1a\u5e95\u5c42\u629b\u51fa\u7684 ValueError\u3001OSError \u7b49\u3002\n\n  **\u793a\u4f8b**\uff1a\n  ```python\n  ui_data = repo.get(\"ui\")  # \u4f8b\u5982: {\"theme\": \"light\", \"recent_files\": []}\n  ```\n  ----\n\n- set(self, name: str, value: Any, save: Optional[bool] = None) -> None\n\n  **\u4f5c\u7528**\uff1a\u8bbe\u7f6e\u547d\u540d\u7a7a\u95f4\u5bf9\u8c61\u5e76\u53ef\u9009\u62e9\u4fdd\u5b58\u3002\n\n  **\u53c2\u6570**\uff1a\n\n  - name\uff1astr\n\n  - value\uff1aAny\n  \u8981\u5199\u5165\u7684\u5bf9\u8c61\uff08\u4f1a\u901a\u8fc7\u7ed1\u5b9a\u7684 serializer \u6301\u4e45\u5316\uff09\u3002\n\n  - save\uff1abool | None\n\n      **True**\uff1a\u7acb\u5373\u4fdd\u5b58\uff1b\n\n      **False**\uff1a\u53ea\u66f4\u65b0\u5185\u5b58\u7f13\u5b58\uff0c\u4e0d\u843d\u76d8\uff1b\n\n      **None**\uff1a\u8ddf\u968f\u547d\u540d\u7a7a\u95f4\u7684 autosave \u8bbe\u7f6e\uff08\u82e5\u4e3a True \u5219\u4fdd\u5b58\uff09\u3002\n\n  **\u8fd4\u56de**\uff1a\u65e0\u3002\n\n  **\u5f02\u5e38**\uff1a\u540c get()\u3002\n\n  **\u793a\u4f8b**\uff1a\n  ```python\n    repo.set(\"ui\", {\"theme\": \"dark\"}, save=True)\n  ```\n  ----\n\n- update(self, name: str, mutator: Callable[[Any], Any], save: Optional[bool] = None) -> Any\n\n  **\u4f5c\u7528**\uff1a\u5728\u539f\u5bf9\u8c61\u57fa\u7840\u4e0a\u4ee5\u51fd\u6570\u5f0f\u65b9\u5f0f\u53d8\u6362\u5e76\u56de\u5199\uff08\u8bfb -> \u53d8\u6362 -> \u5199\uff09\u3002\n\n  **\u53c2\u6570**\uff1a\n\n  - name\uff1astr\n\n  - mutator\uff1a(obj: Any) -> Any\n  \u5165\u53c2\u662f\u5f53\u524d\u5bf9\u8c61\uff0c\u8fd4\u56de\u53d8\u6362\u540e\u7684\u65b0\u5bf9\u8c61\uff08\u51fd\u6570\u5185\u5e94\u8fd4\u56de\u65b0\u503c\uff09\u3002\n\n  - save\uff1abool | None\n  \u8bed\u4e49\u540c set() \u7684 save\u3002\n\n  **\u8fd4\u56de**\uff1a\n\n  - Any\uff1a\u53d8\u6362\u540e\u7684\u65b0\u5bf9\u8c61\u3002\n\n  **\u5f02\u5e38**\uff1a\u540c get()/set()\u3002\n\n  **\u793a\u4f8b**\uff1a\n  ```python\n  def add_recent(d):\n      d = d or {}\n      rec = (d.get(\"recent_files\") or []) + [\"a.sdf\"]\n      return {**d, \"recent_files\": rec[-10:]}  # \u53ea\u4fdd\u7559\u6700\u8fd110\u6761\n\n  new_ui = repo.update(\"ui\", add_recent, save=True)\n  ```\n  ----\n\n- \u6279\u91cf\u64cd\u4f5c\nsave_all(self) -> None\n\n  **\u4f5c\u7528**\uff1a\u5bf9\u6240\u6709\u201c\u5df2\u52a0\u8f7d\u8fc7\u201d\u7684\u547d\u540d\u7a7a\u95f4\u6267\u884c save()\uff08\u907f\u514d\u65e0\u610f\u4e49\u7684\u7a7a\u5199\uff09\u3002\n\n  **\u53c2\u6570**\uff1a\u65e0\u3002\n\n  **\u8fd4\u56de**\uff1a\u65e0\u3002\n\n  **\u5f02\u5e38**\uff1a\u5e95\u5c42\u4fdd\u5b58\u53ef\u80fd\u629b\u51fa IO/\u5e8f\u5217\u5316/\u52a0\u5bc6\u76f8\u5173\u5f02\u5e38\u3002\n\n  \u6ce8\u610f\uff1a\n\n  \u4ec5\u5bf9\u5185\u90e8\u6807\u8bb0 _loaded == True \u7684\u7a7a\u95f4\u751f\u6548\uff1b\n\n  \u82e5\u4f60\u9700\u8981\u786e\u4fdd\u6240\u6709\u7a7a\u95f4\u90fd\u6709\u521d\u503c\u5e76\u4fdd\u5b58\uff0c\u53ef\u5148 load_all() \u6216\u9010\u4e2a space(...).get() \u6fc0\u6d3b\u3002\n\n  **\u793a\u4f8b**\uff1a\n  ```python\n  # \u67d0\u4e9b\u7a7a\u95f4 autosave=False\uff0c\u96c6\u4e2d\u4e00\u6b21\u6027\u4fdd\u5b58\n  repo.save_all()\n  ```\n  ----\n\n- load_all(self) -> None\n\n  **\u4f5c\u7528**\uff1a\u5bf9\u6240\u6709\u5df2\u6ce8\u518c\u7684\u547d\u540d\u7a7a\u95f4\u6267\u884c load()\uff08\u5c06\u6587\u4ef6\u5185\u5bb9\u52a0\u8f7d\u5230\u5185\u5b58\u7f13\u5b58\uff09\u3002\n\n  **\u53c2\u6570**\uff1a\u65e0\u3002\n\n  **\u8fd4\u56de**\uff1a\u65e0\u3002\n\n  **\u5f02\u5e38**\uff1a\u5e95\u5c42\u52a0\u8f7d\u53ef\u80fd\u629b\u51fa IO/\u53cd\u5e8f\u5217\u5316/\u89e3\u5bc6\u76f8\u5173\u5f02\u5e38\u3002\n\n  **\u793a\u4f8b**\uff1a\n\n  ```python\n  # \u5e94\u7528\u542f\u52a8\u65f6\u9884\u70ed\u5168\u90e8\u914d\u7f6e\n  repo.load_all()\n  ```\n\n#### \u5e38\u89c1\u95ee\u9898\u4e0e\u6ce8\u610f\u4e8b\u9879\n\n- \u8def\u5f84\u9009\u62e9\uff1a\n\n  \u9ed8\u8ba4\u843d\u5728\u5e94\u7528\u540c\u76ee\u5f55\uff0c\u4fbf\u4e8e\u201c\u5c31\u5730\u643a\u5e26\u201d\u3002\u5982\u9700\u8de8\u7528\u6237\u5171\u4eab\u6216\u5199\u6743\u9650\u53d7\u9650\uff08Windows Program Files\uff09\uff0c\u5efa\u8bae\u663e\u5f0f\u6307\u5b9a root\u3002\n\n- \u9ed8\u8ba4\u503c\uff1a\n\n  default_factory \u63a8\u8350\u4f20\u5165 \u53ef\u8c03\u7528\uff08\u5982 dict/list/lambda\uff09\uff0c\u907f\u514d\u53ef\u53d8\u5bf9\u8c61\u4f5c\u4e3a\u9ed8\u8ba4\u53c2\u6570\u5e26\u6765\u7684\u5171\u4eab\u526f\u4f5c\u7528\u3002\n\n- \u52a0\u5bc6\u7b56\u7565\uff1a\n\n  - **\"auto\"**\uff1a\u9002\u5408\u4ece\u65e7\u660e\u6587\u5e73\u6ed1\u8fc1\u79fb\u4e3a\u5bc6\u6587\uff1b\n\n  - **\"require\"**\uff1a\u9002\u5408\u5f3a\u7ea6\u675f\u7684\u654f\u611f\u7a7a\u95f4\uff08\u82e5\u975e\u52a0\u5bc6\u7acb\u523b\u62a5\u9519\uff09\u3002\n\n- \u5907\u4efd\u6587\u4ef6\uff1a\n\n  backup_on_save=True \u65f6\u4f1a\u751f\u6210 *.bak\uff1b\u5176\u5185\u5bb9\u53ef\u80fd\u4e3a\u4e0a\u4e00\u6b21\u4fdd\u5b58\u65f6\u7684\u660e\u6587\u6216\u5bc6\u6587\uff0c\u8bfb\u53d6\u65f6\u53ef\u7528 AesGcmBox.is_encrypted() \u5224\u522b\u3002\n\n- \u5f02\u5e38\u5904\u7406\uff1a\n\n  \u89e3\u5bc6\u5931\u8d25\u901a\u5e38\u662f\u53e3\u4ee4/\u5bc6\u94a5\u4e0d\u5339\u914d\u6216\u6587\u4ef6\u635f\u574f\uff1b\u8bf7\u6355\u83b7 ValueError \u5e76\u5f15\u5bfc\u7528\u6237\u68c0\u67e5\u53e3\u4ee4\u6765\u6e90\u3002\n\n- \u7ebf\u7a0b/\u8fdb\u7a0b\u5e76\u53d1\uff1a\n  \n  \u5f53\u524d\u5b9e\u73b0\u662f\u5355\u8fdb\u7a0b\u5185\u4f7f\u7528\u7684\u7b80\u5355\u672c\u5730\u5c42\uff1b\u82e5\u5b58\u5728\u591a\u8fdb\u7a0b/\u591a\u5b9e\u4f8b\u540c\u65f6\u5199\u5165\u540c\u4e00\u6587\u4ef6\uff0c\u8bf7\u81ea\u884c\u52a0\u9501\u6216\u91c7\u7528\u66f4\u9ad8\u7ea7\u522b\u7684\u5b58\u50a8\u65b9\u6848\u3002\n\n#### \u5178\u578b\u7528\u6cd5\u793a\u4f8b\uff08\u6574\u5408\uff09\n```python\nfrom pycorelibs.utils.config import ConfigRepo, JsonSerializer, PickleSerializer\nfrom pycorelibs.security.aesgcmbox import AesGcmBox\nimport os\n\nrepo = ConfigRepo(subdir=\"config\")\n\n# \u660e\u6587 UI \u914d\u7f6e\nui = repo.register(\n    name=\"ui\",\n    serializer=JsonSerializer(),\n    filename=\"ui.json\",\n    default_factory=lambda: {\"theme\": \"light\", \"recent_files\": []},\n    autosave=True,\n)\n\n# \u52a0\u5bc6\u7684\u7f13\u5b58\uff08\u4ece\u65e7\u660e\u6587\u81ea\u52a8\u8fc1\u79fb\uff09\ncache = repo.register(\n    name=\"cache\",\n    serializer=PickleSerializer(),\n    filename=\"cache.dat\",\n    default_factory=list,\n    autosave=True,\n    cipher=AesGcmBox(password=os.environ.get(\"CACHE_PW\", \"CHANGE_ME\")),\n    cipher_policy=\"auto\",\n    encrypt_on_save_if_cipher=True,\n)\n\n# \u8bfb\u53d6 / \u66f4\u65b0 / \u6279\u91cf\u4fdd\u5b58\nui_data = repo.get(\"ui\")\nrepo.update(\"ui\", lambda d: {**(d or {}), \"theme\": \"dark\"})\nrepo.update(\"cache\", lambda lst: (lst or []) + [\"session#1\"])\nrepo.save_all()\n\n```\n----\n\n### files\u6587\u4ef6\u5904\u7406\n\n- EnumFileSizeUnit\n\n- FilesInfo \u7c7b\n\n  - get_file_size\n    \u83b7\u53d6\u6587\u4ef6\u5927\u5c0f\uff0c\u5e76\u8fd4\u56de\u6307\u5b9a\u5355\u4f4d\u7684\u5927\u5c0f\u3002\n\n        \u652f\u6301B,KB,MB,GB,TB\n\n  - line_count\n\n        \u83b7\u53d6\u6307\u5b9a\u6587\u4ef6\u7684\u603b\u884c\u6570\n\n        Windows\u7cfb\u7edf: \u4f7f\u7528\u6362\u884c\u7b26\u4f5c\u4e3a\u5224\u65ad\u6807\u8bb0\n        Linux\u7cfb\u7edf: \u4f7f\u7528\u7cfb\u7edf\u81ea\u5e26\u7684wc\u547d\u4ee4\u7edf\u8ba1\n\n        \u6ce8: \u8fd1\u9002\u7528\u4e8e\u6587\u672c\u7c7b\u578b\u6587\u4ef6,\u5176\u4ed6\u7c7b\u578b\u5982\u4e8c\u8fdb\u5236\u6587\u4ef6\u7edf\u8ba1\u7ed3\u679c\u4e0d\u5177\u5907\u53c2\u8003\u610f\u4e49\n\n  - get_directory_last_modified_time\n  \u83b7\u53d6\u6307\u5b9a\u76ee\u5f55\u6700\u540e\u4fee\u6539\u65f6\u95f4\n\n  - get_directory_last_modified_timestamp\n  \u83b7\u53d6\u6307\u5b9a\u76ee\u5f55\u6700\u540e\u4fee\u6539\u65f6\u95f4\u6233\n\n### formate \u6570\u636e\u683c\u5f0f\u5316\u6307\u5b9a\u7c7b\u578b\n\nFormates \u7c7b\uff0c\u9759\u6001\u65b9\u6cd5\u5982\u4e0b\uff1a\n\n- fInt \u8f6c\u6362\u4e3a\u6574\u6570\n- fFloat \u8f6c\u6362\u4e3a\u6d6e\u70b9\u6570\n- fBool \u8f6c\u6362\u4e3a\u5e03\u5c14\u503c\n- fDate \u6309\u6307\u5b9a\u683c\u5f0f\u89e3\u6790\u65e5\u671f\n- fEnum \u6821\u9a8c\u503c\u662f\u5426\u5728\u5141\u8bb8\u96c6\u5408\u5185\uff08\u7528\u4e8e\u679a\u4e3e\u5b57\u6bb5\uff09\n- fJSON \u89e3\u6790\u4e3a JSON \u5bf9\u8c61\n\n### logger\u65e5\u5fd7\n\n- \u652f\u6301\u81ea\u52a8\u4ea7\u751f\u65e5\u5fd7\n- \u652f\u6301\u540c\u65f6\u5411\u63a7\u5236\u53f0\u548c\u65e5\u5fd7\u6587\u4ef6\u8f93\u51fa\n- \u652f\u6301\u8fdb\u5ea6\u6761\n- \u652f\u6301info\u3001warning\u548cerror\u4e09\u4e2a\u7ea7\u522b\u7684\u65e5\u5fd7\n\n### strings \u5b57\u7b26\u4e32\u5904\u7406\n\n- UniCodeGenerator \u6a21\u5757\n\n  \u521b\u5efa\u968f\u673a\u7801\uff0c\u65e5\u671f\u524d\u7f00 + \u968f\u673a\u7801\n\n  \u53ef\u914d\u7f6e\u3001\u4f7f\u7528 secrets \u751f\u6210\u9ad8\u5f3a\u5ea6\u968f\u673a\u7801\u7684\u7f16\u7801\u751f\u6210\u7c7b\n\n  | \u573a\u666f            | \u53c2\u6570\u793a\u4f8b                                        |\n  | ----------------| ---------------------------------------------- |\n  | \u9080\u8bf7\u7801\uff08\u77ed\uff09     | `prefix_date=False, random_length=6`           |    \n  | \u8ba2\u5355\u53f7\uff08\u5f53\u5929\u552f\u4e00\uff09| `prefix_date=True, random_length=4`            |\n  | URL \u5b89\u5168\u77ed\u7801     | `charset=string.ascii_letters + string.digits` |\n\n- json_dumps_bytes \u51fd\u6570\n\n  \u5c06 dict \u5e8f\u5217\u5316\u4e3a\u7d27\u51d1 UTF-8 JSON bytes\n\n- json_loads_bytes \u51fd\u6570\n\n  \u5c06 UTF-8 JSON bytes \u89e3\u6790\u4e3a dict\uff0c\u5e76\u8fdb\u884c\u57fa\u672c\u7c7b\u578b\u6821\u9a8c\n    \n- split_text_by_marker\u51fd\u6570\n  \n  **\u4f5c\u7528**: \u6309\u7167\u6307\u5b9a\u5b57\u7b26\u4e32 marker \u5206\u5272\u6587\u672c\uff0c\u53ef\u9009\u62e9\u662f\u5426\u4fdd\u7559 marker\uff0c\u5e76\u652f\u6301\u4e25\u683c\u6a21\u5f0f\u3002\n\n  **\u53c2\u6570**\uff1a\n  - text (str): \u9700\u8981\u5206\u5272\u7684\u539f\u59cb\u6587\u672c\u3002\n  - marker (str): \u5206\u5272\u6807\u8bb0\u5b57\u7b26\u4e32\u3002\n  - keep_marker (bool): \u662f\u5426\u4fdd\u7559 marker \u5230\u7ed3\u679c\u4e2d\uff0c\u9ed8\u8ba4\u4e3a True\u3002\n  - strict (bool): \u4e25\u683c\u6a21\u5f0f\u3002\u5f53 marker \u4e0d\u5b58\u5728\u65f6\u629b\u5f02\u5e38\u3002\u9ed8\u8ba4\u4e3a False\u3002\n\n  **\u8fd4\u56de**\uff1a\n  - List[str]: \u5206\u5272\u540e\u7684\u6587\u672c\u5217\u8868\u3002\n    \u5982\u679c strict=False \u4e14 marker \u4e0d\u5b58\u5728\uff0c\u8fd4\u56de\u7a7a\u5217\u8868\u3002\n    \u5982\u679c strict=True \u4e14 marker \u4e0d\u5b58\u5728\uff0c\u629b\u51fa ValueError\u3002\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A collection of reusable python core library from AI Lingues.",
    "version": "0.2.7",
    "project_urls": null,
    "split_keywords": [
        "ailingues",
        " components",
        " core",
        " library"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "a115502fdb197f28bc025799797901e1a1a3a643435eb2b4a1e3bc9f34ca4b66",
                "md5": "5aae032e111a0480caaf508f4950b19f",
                "sha256": "5ee4ea2eccc09ac8ce48c15cf5ad7463c4c9ce34153a1157be7db3f1e81b3e69"
            },
            "downloads": -1,
            "filename": "pycorelibs-0.2.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl",
            "has_sig": false,
            "md5_digest": "5aae032e111a0480caaf508f4950b19f",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.11",
            "size": 8703448,
            "upload_time": "2025-10-23T04:52:54",
            "upload_time_iso_8601": "2025-10-23T04:52:54.156575Z",
            "url": "https://files.pythonhosted.org/packages/a1/15/502fdb197f28bc025799797901e1a1a3a643435eb2b4a1e3bc9f34ca4b66/pycorelibs-0.2.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "761a30922e6e38a6da68a4ae99f61d953abe5885e085b023ae3ec6abd8bff541",
                "md5": "a84e8279919b28cd4d93bbe165d13341",
                "sha256": "3b0b9e492cc4613ffa5031daef540fc013a10d5684035f9aec95ab3c4202c6be"
            },
            "downloads": -1,
            "filename": "pycorelibs-0.2.7-cp311-cp311-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "a84e8279919b28cd4d93bbe165d13341",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.11",
            "size": 3746239,
            "upload_time": "2025-10-23T04:52:56",
            "upload_time_iso_8601": "2025-10-23T04:52:56.209232Z",
            "url": "https://files.pythonhosted.org/packages/76/1a/30922e6e38a6da68a4ae99f61d953abe5885e085b023ae3ec6abd8bff541/pycorelibs-0.2.7-cp311-cp311-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-23 04:52:54",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "pycorelibs"
}
        
Elapsed time: 0.52105s