Skip to main content

29 posts tagged with "Python"

View All Tags

  • 显示最近创建的笔记,可以考虑是否要发布到博客
  • 频繁发布前 修改 '.vscode\settings.json' 下
    • '"noteSync.enableNoteSync": true, -> "noteSync.enableNoteSync": false,'

输入

  • 开始时间 (--since): 定义“最近”的时间起点,例如 "2025-01-01"
  • 过滤地址/路径 (path_filter): 限定笔记文件所在的目录,例如 note/docs/备忘/note/docs/备忘
  • 文件状态 (--diff-filter=A): 仅查找新增 (Added) 的文件。

git log 方式

方案一:Git Bash/Shell 命令行方式

这种方式简洁高效,但需要解决编码乱码路径去重的问题。

  • 基础 Git 命令(查找新增文件路径):
git log --since="2025-01-01" --name-status --pretty=format:'' \
| grep -E '^A' \
| awk '{print $2}' \
| grep -E '^(note|docs|备忘)/' \
| sort -u
  • 不支持 powershell

  • 编码配置

  • 为了解决 Git Bash/Shell 下中文路径或内容乱码问题:

git config --global core.quotepath false
git config --global i18n.commitencoding utf-8
git config --global i18n.logencoding utf-8
export LESSCHARSET=utf-8 # 针对 git log 等分页显示工具

git log --since="2025-01-01" --name-status --pretty=format:"COMMIT_TIME:%cd" --date=format:"%Y-%m-%d %H:%M:%S" |
Where-Object { $_ -match '^(COMMIT_TIME:|A\s+note\\docs)' } |
ForEach-Object {
if ($_ -match '^COMMIT_TIME:(.*)') {
$script:commitTime = $matches[1].Trim() # 记录当前提交时间
} else {
$filePath = ($_ -split '\s+', 2)[1] # 提取文件路径(兼容空格)
"$commitTime`t$filePath" # 时间+制表符+路径
}
} |
Group-Object -Property { $_ -split '\t' | Select-Object -Last 1 } | # 按路径去重
ForEach-Object { $_.Group[0] } |
Sort-Object # 按时间排序

  • 乱码 git log 后输出的应该是 utf8, 和后面的 windows 命令有关系导致不显示了。放弃。
  • 考虑到换环境,不想每次都重复这种操作,那么考虑做成环境设置脚本,既然都脚本了,不如 python 搞定。

Python 脚本方式

  • 还是乱码,又不想改默认环境,干脆换成 python 脚本
import subprocess
import re
from datetime import datetime
# 移除了 os, time 模块,因为不再需要文件系统操作

def decode_octal(data_str):
"""解码 Git 输出中的八进制编码。"""

def byte_creator(match):
octal_str = match.group(1)
decimal_val = int(octal_str, 8)
# 使用 latin-1 编码桥接,确保单字节字符正确返回
return bytes([decimal_val]).decode('latin-1')

intermediate_str = re.sub(r'\\(\d{3})', byte_creator, data_str)
final_bytes = intermediate_str.encode('latin-1')

# 最终使用 UTF-8 解码为中文
return final_bytes.decode('utf-8', errors='replace')

def get_git_info(since_date="2025-01-01", path_filter=None):
"""执行 Git 命令,获取指定日期至今的新增文件及其首次提交时间。"""

# 1. 运行 Git 命令获取新增文件列表、提交哈希和日期
GIT_FORMAT = '%H|%ad' # 格式:[哈希]|[作者日期]
try:
result = subprocess.run(
[
"git", "log", f"--since={since_date}",
"--diff-filter=A", "--name-status",
f"--pretty=format:{GIT_FORMAT}", "--date=format:%Y-%m-%d %H:%M:%S"
],
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)

output_data = result.stdout.decode('utf-8', errors='replace').strip()

except subprocess.CalledProcessError as e:
# 解码错误信息并打印
print(f"Git 命令执行失败:{e.stderr.decode('utf-8', errors='replace')}")
return []
except FileNotFoundError:
print("错误:未找到 Git 命令,请确保 Git 已安装并添加到系统环境变量")
return []

# 2. 解析输出,提取信息,并处理去重和过滤
file_info_map = {} # { 文件路径:{git_time, hash, status} }

current_hash = None
current_time = None

for line in output_data.split('\n'):
line = line.strip()

# 检查是否是提交信息行
if '|' in line and re.match(r'^[0-9a-f]{40}\|', line):
parts = line.split('|', 1)
current_hash = parts[0]
current_time = parts[1].strip()
continue

# 检查是否是文件状态行 (如 A\tpath/to/file)
if len(line) > 2 and line[1].isspace():
status = line[0]
file_path_encoded = line[2:].strip()
file_path = decode_octal(file_path_encoded)

# 仅处理新增文件 ('A')
if status != 'A':
continue

# 过滤功能:跳过不匹配路径的文件
# 注意:如果 path_filter 是 None 或空字符串,则不进行过滤
if path_filter and path_filter in file_path:
pass # 路径匹配,继续
elif path_filter:
continue # 路径不匹配,跳过

# 记录文件的首次提交信息 (由于 git log 默认是新的在前,第一次遇到即为最早记录)
if file_path not in file_info_map:
file_info_map[file_path] = {
"status": status,
"git_time": current_time,
"commit_hash": current_hash,
"path": file_path
}

# 3. 整理和排序结果
final_list = list(file_info_map.values())

# 按 Git 首次提交时间排序
return sorted(final_list, key=lambda x: x['git_time'])

# ------------------- 主执行逻辑 -------------------
if __name__ == "__main__":
# --- 配置项 ---
target_date = "2025-02-13" # 查询起始日期

# 路径过滤器:设置您想要包含的地址片段。
# 例如:如果要查找 'note/docs' 目录下的文件,设置为 'note/docs'
# 如果不需要过滤,设置为 None 或空字符串。
path_filter = "note/docs/备忘"
# -------------

print(f"正在查询 {target_date} 至今的 Git 新增文件。..")
if path_filter:
print(f"应用地址过滤器:'{path_filter}'")

new_files = get_git_info(target_date, path_filter)

if new_files:
print(f"\n 共找到 {len(new_files)} 个新增文件(去重后):")
print("-" * 65)
# 打印表头
print(f"{'No.':<4}{'状态':<4}{'Git 首次提交时间':<22}{'文件路径'}")
print("-" * 65)

for idx, file_info in enumerate(new_files, 1):
print(f"{idx:<4}{file_info['status']:<4}{file_info['git_time']:<22}{file_info['path']}")
print("-" * 65)
else:
print(f"\n 未找到 {target_date} 至今的新增文件,或所有文件已被过滤器排除。")

方案二:读 md 文件的 header

既然都读 python 文件了,那干脆读 md 文件的 header 信息,直接读取创建时间

  • 写一个 python 脚本
  • 读取指定文件夹下的所有 md 文件
  • 过滤 header 中 date 数据小于输入时间的文件
  • 排序由远到近输出到控制台
import os
import frontmatter # 新增导入
from datetime import datetime

# --- 配置区 ---
# 1. 待扫描的根文件夹路径
TARGET_DIR = "note\docs\备忘"
# 2. 筛选日期阈值(只保留日期晚于此时间的笔记)
FILTER_DATE_STR = "2025-04-20"
# ----------------

def parse_md_header_date(filepath: str) -> datetime | None:
"""
使用 'frontmatter' 库读取 Markdown 文件,提取并返回 date 字段的 datetime 对象。
"""
try:
post = frontmatter.load(filepath)

if 'date' not in post.metadata:
print(f"警告:文件 {filepath} 缺少 'date' 字段。")
return None

date_value = post.metadata['date']

# 检查是否已经是 datetime 对象(由 YAML 解析器自动处理)
if isinstance(date_value, datetime):
return date_value

# 否则,尝试将字符串转换为 datetime 对象
date_str = str(date_value).strip()

try:
return datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
except ValueError:
try:
return datetime.strptime(date_str, '%Y-%m-%d')
except ValueError:
print(f"警告:文件 {filepath} 的 date 格式无法识别:'{date_str}'")
return None

except FileNotFoundError:
print(f"错误:文件未找到 {filepath}")
return None
except frontmatter.FrontmatterError as e:
# 当文件开头没有合法的 '---' 区块时会抛出此错误
# print(f"警告:文件 {filepath} 无法解析 YAML Front Matter: {e}")
return None
except Exception as e:
print(f"处理文件 {filepath} 时发生未知错误: {e}")
return None


def main():
"""主执行逻辑:扫描、筛选、排序并输出结果。"""

# 处理 TARGET_DIR 路径并获取绝对路径
absolute_target_dir = os.path.abspath(TARGET_DIR)

# 检查文件夹是否存在
if not os.path.isdir(absolute_target_dir):
print(f"错误:目标文件夹 '{TARGET_DIR}' (绝对路径: {absolute_target_dir}) 不存在。")
return

try:
# 将输入的筛选时间字符串转换为 datetime 对象
filter_date = datetime.strptime(FILTER_DATE_STR.split()[0], '%Y-%m-%d')
except ValueError:
print(f"错误:输入的筛选日期格式 '{FILTER_DATE_STR}' 无效。请使用 YYYY-MM-DD 格式。")
return

print(f"--- 笔记筛选工具 ---")
print(f"原始目标目录: {TARGET_DIR}")
print(f"**绝对路径**: {absolute_target_dir}")
print(f"筛选时间阈值 (晚于): {filter_date.strftime('%Y-%m-%d')}")
print("-" * 30)

filtered_notes = []

for root, _, files in os.walk(absolute_target_dir):
for filename in files:
if filename.endswith(('.md', '.markdown')):
filepath = os.path.join(root, filename)

# 使用优化的解析函数
note_date = parse_md_header_date(filepath)

if note_date and note_date > filter_date:
filtered_notes.append((note_date, filepath))

# 排序:按日期由远到近(升序)排序
filtered_notes.sort(key=lambda x: x[0])

# 输出结果
if filtered_notes:
print(f"\n✅ 找到 {len(filtered_notes)} 篇符合条件的笔记(日期晚于 {filter_date.strftime('%Y-%m-%d')}):")
print("-" * 60)
print(f"{'No.':<4}{'文件日期':<22}{'文件相对路径'}")
print("-" * 60)

for idx, (note_date, filepath) in enumerate(filtered_notes, 1):
relative_path = os.path.relpath(filepath, absolute_target_dir)
print(f"{idx:<4}{note_date.strftime('%Y-%m-%d'):<12}{relative_path}")
print("-" * 60)
else:
print("\n❌ 未找到符合条件的笔记。")

if __name__ == "__main__":
main()
Python6 min read

  • 用于盗版游戏和未知安全工具的批量断网设置
@Echo Off
chcp 936
SetLocal EnableDelayedExpansion

echo 正在以当前权限运行防火墙规则创建。..
echo 如果看不到完整规则,请尝试以管理员身份运行
echo:

Set "Cmnd=netsh advfirewall firewall add rule action=block"

Set "TargetDir=E:\Games\CrackedGame"
For /R "%TargetDir%" %%a In (*.exe) Do (
For %%b In (in out) Do (
set "ruleName=blocked %%~fa %%b"
netsh advfirewall firewall show rule name="!ruleName!" >nul 2>&1
if !errorlevel! equ 0 (
echo 跳过已存在的规则【%%~fa】方向:%%b
) else (
echo 创建禁止 %%b 规则【%%~fa】
%Cmnd% name="!ruleName!" dir=%%b program="%%a"
if !errorlevel! equ 0 (
echo -- 成功创建规则:!ruleName!
) else (
echo -- 创建规则失败,请检查权限
)
)
)
)

echo:
echo 处理完成
echo ----------------------------
pause

管理员方式启动

  1. 创建快捷方式:按住Alt键拖动bat文件到目标位置
  2. 设置管理员运行
    • 右键快捷方式→属性→快捷方式选项卡
    • 点击“高级”,勾选“用管理员身份运行”
    • 点击“确定”
PythonOne min read

import os

target_dir = r"D:\CodeProjects\WG" # 目标目录(可改为 '.' 表示当前目录)

# 存储符合条件的文件路径
matching_files = []

# 递归查找符合条件的文件
for root, dirs, files in os.walk(target_dir):
for filename in files:
if filename.endswith(".md"):
file_path = os.path.join(root, filename)
try:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read().strip()
if content.startswith("#") and "\n" not in content:
matching_files.append(file_path)
print(f"找到符合条件的文件:{file_path} - 内容: {content}")
except Exception as e:
print(f"读取 {file_path} 失败: {e}")

# 处理删除操作
if matching_files:
choice = input("\n输入 1 确认删除上述文件,输入其他数字取消:")
if choice == "1":
for file_path in matching_files:
try:
os.remove(file_path) # 直接删除文件
print(f"✅ 已删除:{file_path}")
except Exception as e:
print(f"❌ 删除失败 {file_path}: {e}")
print("\n操作完成,文件已永久删除。")
else:
print("操作已取消。")
else:
print("未找到符合条件的文件。")
PythonOne min read

如何在 python 异步函数中 debug


import asyncio
from aredis import StrictRedis
import nest_asyncio

# pip3 install aredis[hiredis]
# pip3 install nest_asyncio

async def example():
client = StrictRedis(host='127.0.0.1', port=6379, db=0)
await client.flushdb()
# error await client.flushdb()
# error asyncio.get_event_loop().run_until_complete(client.flushdb())
# error asyncio.new_event_loop().run_until_complete(client.flushdb())
# error asyncio.run(client.flushdb())

await client.set('foo', 1)
assert await client.exists('foo') is True
await client.incr('foo', 100)

assert int(await client.get('foo')) == 101
await client.expire('foo', 1)
await asyncio.sleep(0.1)
await client.ttl('foo')
await asyncio.sleep(1)
assert not await client.exists('foo')

loop = asyncio.get_event_loop()
# success nest_asyncio.apply()
loop.run_until_complete(example())

PythonOne min read

参考

想法

  • 接微信机器人
    • 群友对话直接 at 机器人、以指令开头、触发逻辑。
  • 接 chatgpt
    • 根据问题与获取的卦辞或者表达的象征,通过有预设的 gpt 做解释后发回给群友。

代码部分

十二地支时间换算


import datetime
from lunardate import LunarDate

Zhi = ["子", "醜", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]

def get_factor_time(time:datetime.datetime=None):
if time is None:
time = datetime.datetime.now()
# 获取农历时间
lunar_time = LunarDate.fromSolarDate(time.year, time.month, time.day)
# 输出农历时间
lunar_month = lunar_time.month
lunar_day = lunar_time.day
lunar_hour = time.hour//2
print(f"农历时间:{lunar_month}{lunar_day}{lunar_hour}({Zhi[lunar_hour]}) 时")

完整代码

#!/usr/bin/env python
# encoding: utf-8
# @Time : 2023/07/04 01:05:33
# @author : zza
# @Email : z740713651@outlook.com
# @File : xiao_liu_ren.py
from collections import defaultdict
import datetime
from lunardate import LunarDate

Zhi = ["子", "醜", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]
xiao_liu_ren = [
"大安",
"留连",
"速喜",
"赤口",
"小吉",
"空亡",
]

def get_factor_time(time: datetime.datetime = None):
if time is None:
time = datetime.datetime.now()
print(f"阳历时间:{time.isoformat()}")
# 获取农历时间
lunar_time = LunarDate.fromSolarDate(time.year, time.month, time.day)
# 输出农历时间
lunar_month = lunar_time.month
lunar_day = lunar_time.day
lunar_hour = (time.hour + 1) // 2
print(f"农历时间:{lunar_month}{lunar_day}{Zhi[lunar_hour]}({lunar_hour}) 时")

factor_month = xiao_liu_ren[(lunar_month - 1) % 6]
factor_day = xiao_liu_ren[(lunar_month - 1 + lunar_day - 1) % 6]
factor_hour = xiao_liu_ren[(lunar_month - 1 + lunar_day - 1 + lunar_hour) % 6]
print(f"小六壬月日时:{factor_month} {factor_day} {factor_hour}")

return factor_month, factor_day, factor_hour

def lost_item(factor):
guaci = {
"大安": {
"留连": "大安加留连,失物西北去。",
"速喜": "大安加速喜,失物当日见。",
"赤口": "大安加赤口,失物不用找。",
"小吉": "大安加小吉,失物不出门。",
"空亡": "大安加空亡,失物无踪影。",
"大安": "大安加大安,失物在家里。",
},
"留连": {
"大安": "留连加大安,物在家中藏。",
"速喜": "留连加速喜,失物三天里。",
"赤口": "留连加赤口,失物准丢失。",
"小吉": "留连加小吉,失物东南去。",
"空亡": "留连加空亡,失物不见面。",
"留连": "留连加留连,失物落在南。",
},
"速喜": {
"赤口": "速喜加赤口,失物往正北。",
"小吉": "速喜加小吉,失物在家里。",
"空亡": "速喜加空亡,失物不久见。",
"大安": "速喜加大安,失物不丢失。",
"留连": "速喜加留连,失物无信息。",
"速喜": "速喜加速喜,失物落正南。",
},
"赤口": {
"小吉": "赤口加小吉,失物无信息。",
"空亡": "赤口加空亡,失物不用找。",
"大安": "赤口加大安,失物东北找。",
"留连": "赤口加留连,失物不回还。",
"速喜": "赤口加速喜,失物有着落。",
"赤口": "赤口加赤口,失物正西找。",
},
"小吉": {
"空亡": "小吉加空亡,失物正东找。",
"大安": "小吉加大安,失物自己出。",
"留连": "小吉加留连,失物上西南。",
"速喜": "小吉加速喜,失物在院里。",
"赤口": "小吉加赤口,失物丢了手。",
"小吉": "小吉加小吉,失物在西南。",
},
"空亡": {
"大安": "空亡加大安,失物反复间。",
"留连": "空亡加留连,失物永不还。",
"速喜": "空亡加速喜,失物在家里。",
"赤口": "空亡加赤口,失物往远走。",
"小吉": "空亡加小吉,失物回家里。",
"空亡": "空亡加空亡,失物寻不见。",
},
}
return guaci[factor[1]][factor[2]]

if __name__ == "__main__":
# get_factor_time()
# 日上起時。 假如三月初五日辰時:三月在速喜上;就速喜上起初一;初五在大安;大安上起子時;數至辰時即是小吉; 以類推占,餘皆倣此。
# 速喜 大安 小吉
res = get_factor_time(datetime.datetime(2023, 4, 24, 7, 15))
assert res == ("速喜", "大安", "小吉"), res
res = lost_item(res)
assert res == "大安加小吉,失物不出门。", res

res = get_factor_time(datetime.datetime(2022, 4, 30, 8, 20))
assert res == ("速喜", "留连", "空亡"), res
res = lost_item(res)
assert res == "留连加空亡,失物不见面。", res

表象属性

大安
不动 木 青色 东 吉祥
大安事事昌,求谋在东方,失物去不远

留连
慢 四方土 黑色 纠狸 拖延
留连事难成,求谋日未明,官事只宜缓

速喜
快速 火 红色 南方
吉利求财向南行,失物申未午(南或西南)

赤口
吵 金 白色 西方 凶险
赤口主口舌,官非切要防,失物急去寻

小吉
主动 缓慢 水 北方 吉利
小吉最吉昌,失物在坤方(西南)

空亡
无 随性 中央土 黄色 难以找回
空亡事不禅,失物寻不见

卦辞

大安日

  • 大安加留連,辦事不周全,失物西北去,婚姻晚幾天。
  • 大安加速喜,事事自己起,失物當日見,婚姻自己提。
  • 大安加赤口,辦事不順手,失物不用找,婚姻兩分手。
  • 大安加小吉,事事從己及,失物不出門,婚姻成就地。
  • 大安加空亡,病人要上床,失物無蹤影,事事不順情。

留連日

  • 留連加大安,辦事兩分張,婚姻有喜事,先苦後來甜。
  • 留連加速喜,事事由自己,婚姻有成意,失物三天裡。
  • 留連加赤口,病者死人口,失物準丟失,婚姻兩分手。
  • 留連加小吉,事事不用提,失物東南去,病者出人齊。
  • 留連加空亡,病人準死亡,失物不見面,婚姻兩分張。

速喜日

  • 速喜加赤口,自己往外走,失物往正北,婚姻得勤走。
  • 速喜加小吉,婚姻有人提,病人當天好,時物在家裡。
  • 速喜加空亡,婚姻有分張,病者積極治,失物不久見。
  • 速喜加大安,事事都平安,姻姻成全了,佔病都相安。
  • 速喜加留連,婚姻不可言,失物無資訊,病人有仙緣。

赤口日

  • 赤口加小吉,辦事自己提,婚姻不能成,失物無資訊。
  • 赤口加空亡,無病也上床,失物不用找,婚姻不能成。
  • 赤口加大安,辦事險和難,失物東北找,婚姻指定難。
  • 赤口加留連,辦事有困難,行人在外走,失物不回還。
  • 赤口加速喜,婚姻在自己,失物有著落,辦事官事起。

小吉日

  • 小吉加空亡,病人不妥當,失物正東找,婚姻再想想。
  • 小吉加大安,事事兩週全,婚姻當日定,失物自己損。
  • 小吉加留連,事事有反還,婚姻有人破,失物上西南。
  • 小吉加速喜,事事從頭起,婚姻能成就,失物在院裡。
  • 小吉加赤口,辦事往外走,婚姻有難處,失物丟了手。

空亡日

  • 空亡加大安,事事不周全,婚姻從和好,失物反覆間。
  • 空亡加留連,辦事處處難,婚姻重新定,失物永不還。
  • 空亡加速喜,事事怨自己,婚姻有一定,失物在家裡。
  • 空亡加赤口,辦事官非有,婚姻難定準,失物往遠走。
  • 空亡加小吉,事事有猜疑,婚姻有喜事,失物回家裡。
Python6 min read

老方案

save_dir = os.path.join(os.path.expanduser("~"), "Pictures", "wallpaper")
os.makedirs(save_dir, exist_ok=True)

新方案

In [16]: import ctypes
...: from ctypes.wintypes import MAX_PATH
...:
...: dll = ctypes.windll.shell32
...: buf = ctypes.create_unicode_buffer(MAX_PATH + 1)
...: for i in range(100):
...: if dll.SHGetSpecialFolderPathW(None, buf, 0x0000 +i, False):
...: print( 0x0000 +i,buf.value)
...: else:
...: pass
...: # print("Failure!")
...:
0 C:\Users\tmp_user\Desktop
2 C:\Users\tmp_user\AppData\Roaming\Microsoft\Windows\Start Menu\Programs
5 E:\Users\tmp_user\Documents
6 E:\Users\tmp_user\Favorites
7 C:\Users\tmp_user\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
8 C:\Users\tmp_user\AppData\Roaming\Microsoft\Windows\Recent
9 C:\Users\tmp_user\AppData\Roaming\Microsoft\Windows\SendTo
11 C:\Users\tmp_user\AppData\Roaming\Microsoft\Windows\Start Menu
13 E:\Users\tmp_user\Music
14 E:\Users\tmp_user\Videos
16 C:\Users\tmp_user\Desktop
19 C:\Users\tmp_user\AppData\Roaming\Microsoft\Windows\Network Shortcuts
20 C:\WINDOWS\Fonts
21 C:\Users\tmp_user\AppData\Roaming\Microsoft\Windows\Templates
22 C:\ProgramData\Microsoft\Windows\Start Menu
23 C:\ProgramData\Microsoft\Windows\Start Menu\Programs
24 C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
25 C:\Users\Public\Desktop
26 C:\Users\tmp_user\AppData\Roaming
27 C:\Users\tmp_user\AppData\Roaming\Microsoft\Windows\Printer Shortcuts
28 C:\Users\tmp_user\AppData\Local
29 C:\Users\tmp_user\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
30 C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
31 E:\Users\tmp_user\Favorites
32 C:\Users\tmp_user\AppData\Local\Microsoft\Windows\INetCache
33 C:\Users\tmp_user\AppData\Local\Microsoft\Windows\INetCookies
34 C:\Users\tmp_user\AppData\Local\Microsoft\Windows\History
35 C:\ProgramData
36 C:\WINDOWS
37 C:\WINDOWS\system32
38 C:\Program Files
39 E:\Users\tmp_user\Pictures
40 C:\Users\tmp_user
41 C:\WINDOWS\SysWOW64
42 C:\Program Files (x86)
43 C:\Program Files\Common Files
44 C:\Program Files (x86)\Common Files
45 C:\ProgramData\Microsoft\Windows\Templates
46 C:\Users\Public\Documents
47 C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools
48 C:\Users\tmp_user\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Administrative Tools
53 C:\Users\Public\Music
54 C:\Users\Public\Pictures
55 C:\Users\Public\Videos
56 C:\WINDOWS\resources
59 C:\Users\tmp_user\AppData\Local\Microsoft\Windows\Burn\Burn

整合以后

def get_default_save_dir(dir_name:str= "Pictures"):
# windows platform
res_path = os.path.join(os.path.expanduser("~"), dir_name)
if os.name == "nt":
import ctypes
from ctypes.wintypes import MAX_PATH
...:
dll = ctypes.windll.shell32
buf = ctypes.create_unicode_buffer(MAX_PATH + 1)
for i in range(100):
if dll.SHGetSpecialFolderPathW(None, buf, 0x0000 +i, False) and dir_name in buf.value:
return buf.value
return res_path
PythonOne min read

  • 参考 (doc just the docs 主题蛮好看的)
  • 基本不用,现场不方便改代码 debug。
python -m pdb my_script.py

cat my_script.py

import pdb

def make_bread():
pdb.set_trace()
return "I don't have time"

print(make_bread())

命令列表:

  • c(continue): 继续执行
  • w(where): 显示当前正在执行的代码行的上下文信息
  • a(args): 打印当前函数的参数列表
  • s(step): 执行当前代码行,并停在第一个能停的地方(相当于单步进入)
  • n(next): 继续执行到当前函数的下一行,或者当前行直接返回(单步跳过)

单步跳过(next)和单步进入(step)的区别在于,单步进入会进入当前行调用的函数内部并停在里面,而单步跳过会(几乎)全速执行完当前行调用的函数,并停在当前函数的下一行。

PythonOne min read

在项目中写了 doctest,但是需要先初始化环境才方便使用。

在运行 pytest 的目录下创建conftest.py

#!/usr/bin/python3
# encoding: utf-8
# @author : zza
# @File : conftest.py
""" FOR DOCTEST """
import pytest

@pytest.fixture(autouse=True)
def init_env(doctest_namespace):
print("doctest_namespace", doctest_namespace)
import os
sql_url = "sqlite:///data.db"
os.environ['sql_uri'] = sql_url
init(sql_url)
  • pytest 启动就用 pytest 命令就好了:pytest
  • coverage 启动时使用该命令启动:coverage run --source my_pachage -m pytest

更多使用案例建议 github 直接 搜索conftest.py文件。

PythonOne min read

fire 是一个比 click 更有使用体验的命令行工具包。

但是在 help 命令中,会进入 man 的交互模式里,不能直接打印到标准输出里。

看了下 Issue,有几种解决方案,记录一下。

修改 fire.core.Display

if __name__ == "__main__":
# Make Python Fire not use a pager when it prints a help text
fire.core.Display = lambda lines, out: print(*lines, file=out)
fire.Fire(...)

更改 PAGER 环境变量(推荐)

* windows 上设置 setx PAGER type
* linux 上设置 export PAGER=cat

在程序中修改环境变量

os.environ["PAGER"] = 'cat'

  • 一个写完后发现没必要的代码
def _fire_print_prepare() -> None:
"""help to print mode `setx PAGER cat`"""
import os
import platform
from shutil import which

if os.environ.get("PAGER"):
return
if which("cat"):
os.environ["PAGER"] = "cat"
elif platform.platform().startswith("Windows"):
os.environ["PAGER"] = "type"
PythonOne min read