如何在Python的Typer中正确获取CLI命令的JSON参数并实现JSON内容追加到文件的功能?
如何在Python的Typer中正确获取CLI命令的JSON参数并实现JSON内容追加到文件的功能?
嗨,我来帮你解决这个问题~你遇到的核心问题其实是终端的shell把你输入的引号给解析掉了,导致Typer拿到的JSON字符串格式不合法,没法用json.loads()正常解析。下面给你几个可行的解决办法,从简单调整命令到代码层面的处理都有:
一、调整终端命令的引号写法(最推荐)
不同终端的shell对引号的解析规则不一样,只要让shell完整传递带引号的JSON字符串给Typer就行:
- Windows CMD:用双引号包裹整个JSON,内部的双引号用
""转义python main.py "{\"Name\": \"Lily\"}" "D:\students.json" - Windows PowerShell:用单引号包裹整个JSON,内部直接用双引号
python main.py '{"Name": "Lily"}' "D:\students.json" - Linux/macOS Bash:同样用单引号包裹整个JSON即可
python main.py '{"Name": "Lily"}' "/path/to/students.json"
这样Typer就能收到完整的{"Name": "Lily"}字符串,直接用json.loads()解析就没问题了。
二、代码层面修复不合法的JSON字符串
如果不方便调整终端命令,可以写个小函数,把Typer收到的无引号键值对转换成合法JSON格式:
import typer import json import re app = typer.Typer() def fix_json_string(s): # 给无引号的键添加双引号 s = re.sub(r'(\w+)\s*:', r'"\1":', s) # 给无引号的字符串值添加双引号(注意:这个逻辑对数字、布尔值可能不适用,需要根据你的场景调整) s = re.sub(r':\s*(\w+)', r': "\1"', s) return s @app.command() def append(argument: str, path: str): print(type(argument)) print(argument) try: # 先修复JSON格式再解析 fixed_arg = fix_json_string(argument) json_to_add = json.loads(fixed_arg) # 读取目标JSON文件 with open(path, 'r', encoding='utf-8') as f: data = json.load(f) # 追加内容(假设文件内容是列表,如果是单个字典可自行调整逻辑) if isinstance(data, list): data.append(json_to_add) else: # 把单个字典转成列表再追加 data = [data, json_to_add] # 写回文件,保留格式 with open(path, 'w', encoding='utf-8') as f: json.dump(data, f, indent=2, ensure_ascii=False) typer.echo("内容成功追加到文件!") except json.JSONDecodeError as e: typer.echo(f"解析JSON失败:{str(e)}") except FileNotFoundError: typer.echo(f"错误:目标文件 {path} 不存在!") except Exception as e: typer.echo(f"发生未知错误:{str(e)}") if __name__ == "__main__": app()
三、用Typer自定义类型自动解析JSON
可以定义一个自定义类型,让Typer在接收参数时自动完成JSON解析,代码更简洁:
import typer import json import re from typing import Dict, Any app = typer.Typer() class JSONDict(Dict[str, Any]): @classmethod def __get_validators__(cls): yield cls.validate @classmethod def validate(cls, v): if isinstance(v, str): try: return json.loads(v) except json.JSONDecodeError: # 解析失败时尝试修复格式 fixed_v = re.sub(r'(\w+)\s*:', r'"\1":', v) fixed_v = re.sub(r':\s*(\w+)', r': "\1"', fixed_v) return json.loads(fixed_v) elif isinstance(v, dict): return v else: raise typer.BadParameter("参数必须是合法的JSON字符串或字典") @app.command() def append(argument: JSONDict, path: str): # 这里argument已经是解析好的字典了 try: with open(path, 'r', encoding='utf-8') as f: data = json.load(f) if isinstance(data, list): data.append(argument) else: data = [data, argument] with open(path, 'w', encoding='utf-8') as f: json.dump(data, f, indent=2, ensure_ascii=False) typer.echo("内容成功追加到文件!") except FileNotFoundError: typer.echo(f"错误:目标文件 {path} 不存在!") except Exception as e: typer.echo(f"发生未知错误:{str(e)}") if __name__ == "__main__": app()
⚠️ 注意:代码里的修复逻辑只针对简单的键值对,如果你的JSON包含嵌套字典、数字、布尔值或者特殊字符,建议优先用第一种方法调整终端命令,确保传入的是标准JSON字符串。
备注:内容来源于stack exchange,提问作者Tamar .M
相关产品推荐
相关产品推荐

