Skip to main content

Yuanfen Python Library

Project description

Yuanfen Python Library

Installation

pip install yuanfen

Config

Supports .json, .yaml / .yml, and .ini files. Instances are singletons per file path. Auto-reloads when the config file changes (uses polling by default).

from yuanfen import Config

config = Config("configs/config.yaml")

# Access via key (raises KeyError if missing)
print(config["app"]["name"])

# Access with default fallback
print(config.get("debug", False))
Parameter Type Default Description
path str Path to the config file
poll bool True Use polling observer (more compatible); set False for native FS events
logger Logger Logger() Logger instance for reload messages

Logger

Writes to both stdout and a daily-rotated file at logs/log (kept for 365 days).

import logging
from yuanfen import Logger

logger = Logger(name="my-service", level=logging.DEBUG)

logger.debug("debug log")
logger.info("info log")
logger.warning("warning log")
logger.error("error log")
Parameter Type Default Description
name str None Prefix added to every log message as [name]
level int logging.INFO Minimum log level
logger logging.Logger root logger Use a custom logger instance

Response

Pydantic response models for FastAPI.

from yuanfen import BaseResponse, SuccessResponse, ErrorResponse

# Default: code=0, message="SUCCESS"
SuccessResponse(data={"id": 1})

# Default: code=1000, message="ERROR"
ErrorResponse(message="Something went wrong")

# Custom
BaseResponse(code=404, message="Not found")
import uvicorn
from fastapi import FastAPI
from yuanfen import SuccessResponse, ErrorResponse

app = FastAPI()

@app.get("/health-check")
def health_check():
    return SuccessResponse(data="OK")

@app.get("/items/{item_id}")
def get_item(item_id: int):
    if item_id != 1:
        return ErrorResponse(code=404, message="Item not found")
    return SuccessResponse(data={"id": item_id})

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

time

Timezone-aware time utilities (defaults to Asia/Shanghai).

from yuanfen import time
from datetime import datetime

# Current time (no tzinfo attached)
dt = time.now()

# Current time with timezone info
dt_tz = time.now(tz="Asia/Shanghai", with_tz=True)

# Strip timezone from a tz-aware datetime
dt_naive = time.remove_tz(dt_tz)

# Format datetime to string
time.format(dt=datetime.now(), format="%Y-%m-%dT%H:%M:%S")

# Parse string to datetime
time.parse(dt_str="2023-11-25T10:51:19", format="%Y-%m-%dT%H:%M:%S")

# Format duration in seconds to HH:MM:SS or MM:SS
time.format_duration(90)   # "01:30"
time.format_duration(3661) # "01:01:01"

# Timestamps (default 16-digit microseconds)
time.current_timestamp()          # current timestamp
time.get_timestamp(dt, length=13) # milliseconds from datetime

# Passthrough to standard library
time.sleep(1.5)
time.time()

GroupRobot

Send messages to a webhook-based group robot (e.g. DingTalk, Feishu).

from yuanfen import GroupRobot

robot = GroupRobot(webhook="https://your-robot-webhook-url")
robot.send({"msgtype": "text", "text": {"content": "Hello!"}})

Email

Send and receive emails via SMTP/IMAP.

from yuanfen import Email

mail = Email(
    address="you@example.com",
    password="your-password",
    smtp_host="smtp.example.com",
    smtp_port=465,
    imap_host="imap.example.com",
    imap_port=993,
    sender_name="My App",  # optional display name
)

# Send a plain-text email
mail.send_text(to="recipient@example.com", subject="Hello", text="World")

# Search latest N email UIDs matching IMAP criteria
ids = mail.search_ids(count=5, "UNSEEN")

# Fetch a single email by UID
msg = mail.fetch(message_id="123", content_type="text/plain")
# msg keys: subject, from, to, date, charset, content

# Search + fetch in one call
messages = mail.search(count=5, content_type="text/plain", "UNSEEN")

Redis

A Redis client wrapper with optional key prefix and a distributed lock helper.

from yuanfen import Redis, RedisLock

redis = Redis({
    "host": "localhost",
    "port": 6379,
    "password": "secret",
    "db": 0,
    "prefix": "myapp",       # optional; keys are stored as "myapp:<key>"
    "decode_responses": True, # optional, default True
})

redis.set("foo", "bar", ex=60)  # set with 60s expiry
redis.get("foo")                 # "bar"
redis.setex("foo", 60, "bar")
redis.setnx("counter", "0")
redis.incr("counter")
redis.delete("foo")
redis.exists("foo")
redis.expire("foo", 120)
redis.ttl("foo")
redis.getset("foo", "new")

RedisLock

lock = RedisLock(
    redis_client=redis.redis_client,
    lock_key="my-job",
    timeout=10,          # lock expiry in seconds
    retry_interval=0.5,  # seconds between retries; None = no retry
)

if lock.acquire():
    try:
        # critical section
        pass
    finally:
        lock.release()

SMS

SMS verification code service built on Alibaba Cloud SMS (async).

from yuanfen import Config, Logger, SmsService, SmsSendCodeRequest, SmsVerifyCodeRequest

config = Config("config.yaml")
logger = Logger()
sms = SmsService(config=config, logger=logger)

# config.yaml must contain:
# redis: { host, port, password, db, prefix }
# aliyun: { access_key_id, access_key_secret, sms_sign_name, sms_template_code }

# Send a 6-digit code (raises on cooldown or send failure)
await sms.send_code(SmsSendCodeRequest(system="myapp", phone="13800138000", length=6))

# Verify the code (raises on wrong code / expiry / too many attempts)
await sms.verify_code(SmsVerifyCodeRequest(system="myapp", phone="13800138000", code="123456"))

Behavior:

  • Code TTL: 300 seconds (5 minutes)
  • Resend cooldown: 60 seconds
  • Max verify attempts: 5 (code is deleted on exceeded)

hash

from yuanfen import hash

# SHA-256 (default)
digest = hash.get_file_hash("path/to/file")

# Other algorithm, truncated to 8 chars
digest = hash.get_file_hash("path/to/file", algorithm="md5", length=8)

ip

from yuanfen import ip

# Get public IP (tries ipify then ipip.net)
public_ip = ip.get_public_ip()

# Get IP location (sources: "baidu" or "ip-api")
location = ip.get_ip_location("8.8.8.8", source="baidu")
location = ip.get_ip_location("8.8.8.8", source="ip-api")

Version

Semantic version parsing and comparison.

from yuanfen import Version

v = Version(1, 2, 3)
v = Version.parse("1.2.3")

str(v)          # "1.2.3"
v.to_tuple()    # (1, 2, 3)
v.to_dict()     # {"major": 1, "minor": 2, "patch": 3}

# compare() returns -1, 0, or 1
v.compare("1.2.4")           # -1
v.compare(Version(1, 2, 3))  # 0
v.compare({"major": 1, "minor": 2, "patch": 0})  # 1

APP_ENV

Reads the APP_ENV environment variable (defaults to "dev").

from yuanfen import APP_ENV

if APP_ENV == "prod":
    ...

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

yuanfen-2026.3.16.1.tar.gz (15.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

yuanfen-2026.3.16.1-py3-none-any.whl (14.5 kB view details)

Uploaded Python 3

File details

Details for the file yuanfen-2026.3.16.1.tar.gz.

File metadata

  • Download URL: yuanfen-2026.3.16.1.tar.gz
  • Upload date:
  • Size: 15.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for yuanfen-2026.3.16.1.tar.gz
Algorithm Hash digest
SHA256 7f6c9d923e77e4dfc138d1571246e3f9e1b0e95a03dd88a56c8772baebea893e
MD5 d4fbb5f29b2684fd9f2a41bb742adc88
BLAKE2b-256 cd97269d5f3e8c31d81575a938e8549e96ab55fce82c52ed802c913e58105c93

See more details on using hashes here.

File details

Details for the file yuanfen-2026.3.16.1-py3-none-any.whl.

File metadata

  • Download URL: yuanfen-2026.3.16.1-py3-none-any.whl
  • Upload date:
  • Size: 14.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for yuanfen-2026.3.16.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1633c953bdfe560989166d704e9bd44f22feb0ebee187632140c97c290312d39
MD5 d50c7b0e5ca89caff42888845dc4d094
BLAKE2b-256 2a47f653199290d1935b26a552df4f3792f929a269a480ee1ad27b39aade9fb4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page