tbtools-cli 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tbtools_cli/__init__.py +18 -0
- tbtools_cli/auto_commands.py +1149 -0
- tbtools_cli/cli.py +528 -0
- tbtools_cli/cli_load.py +352 -0
- tbtools_cli/cli_rpc.py +303 -0
- tbtools_cli/cli_tools_registry.py +93 -0
- tbtools_cli/cli_top.py +1160 -0
- tbtools_cli/command_metadata.json +4606 -0
- tbtools_cli/command_spec.py +382 -0
- tbtools_cli/config.example.toml +19 -0
- tbtools_cli/config.py +43 -0
- tbtools_cli/core.py +508 -0
- tbtools_cli/errors.py +38 -0
- tbtools_cli/presets.py +100 -0
- tbtools_cli/scenarios.py +92 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/AdmixtureCli.java +91 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/AmazingMetaCli.java +78 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/AssemblyRecommandCli.java +47 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/BamIndexCli.java +31 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/BamSortCli.java +43 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/BamStateCli.java +49 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/BarPlotterCli.java +18 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/BarplotCli.java +168 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/BatchVizMotifsCli.java +47 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/BlastXmlConvertCli.java +45 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/BlatExecutorCli.java +66 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/CalcRepeatCli.java +62 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/CalculateSimilarityCli.java +34 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/CddMotifCli.java +46 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/CircleGeneViewerCli.java +81 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/CircosCli.java +76 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/ColorSchemeCli.java +29 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/CtgGroupCli.java +29 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/CubeHeatmapCli.java +70 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/DeHistCli.java +46 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/DegramdomCli.java +33 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/DiffExpCli.java +44 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/DistanceCli.java +53 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/DualSynCli.java +147 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/EggnogCli.java +39 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/ExprCorrCli.java +27 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/FastaMergerCli.java +36 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/FastaTableConvertCli.java +38 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/FileCleanerCli.java +31 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/FileSplitCli.java +15 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/FindBlockDualCli.java +71 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/FindBlockMultipleCli.java +67 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/FindPathCli.java +15 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/GSEAWrapperCli.java +33 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/GenBank2FastaCli.java +32 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/GeneDensityCli.java +38 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/GeneLocGffCli.java +140 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/GeneStructureCli.java +90 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/GenericCli.java +177 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/GetENALinksCli.java +36 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/GetSubNewickTreeCli.java +50 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/GoEnrichCli.java +42 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/GoLevelCli.java +59 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/GroupedBarCli.java +95 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/GsaDiagCli.java +45 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/GxfFilterCli.java +39 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/GxfSortCli.java +23 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/HclustCli.java +43 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/HeatmapCli.java +89 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/HmmerSuiteCli.java +47 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/JgblocksCli.java +65 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/KeggEnrichCli.java +31 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/LayoutHeatmapCli.java +90 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MCScanXCli.java +80 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MCScanXFastCli.java +41 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MSACli.java +46 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MakeMotifCli.java +39 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MarkerDesignCli.java +62 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MarkerToolsCli.java +57 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/Mast2TabCli.java +27 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MastCli.java +54 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MastRunCli.java +39 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/Meme2TabCli.java +26 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MemeCli.java +74 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MemeRunCli.java +40 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MgGxfCli.java +35 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MicroSynCli.java +118 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MirIdentifyCli.java +55 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MotifCli.java +75 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MotifPatternCli.java +67 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MotifShiftCli.java +30 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MountainPlotCli.java +44 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/MultiSuperHeatCli.java +64 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/NeedlemanWunschCli.java +76 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/PafGC.java +15 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/PafVizCli.java +67 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/PeakDistCli.java +58 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/Pep2CodonCli.java +26 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/PfamMotifCli.java +43 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/PhyloTreeCli.java +92 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/PileUpCli.java +55 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/PlantCAREResultClassifyCli.java +36 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/PubmedSearchCli.java +25 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/QpcrCli.java +69 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/QpcrDdctCli.java +28 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/QpcrProcCli.java +28 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/QuickGenomeDotCli.java +66 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/QuickProteinAnnoCli.java +34 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/QuickRunIQtreeCli.java +69 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/QuickTrimALCli.java +67 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/RNAplotCli.java +129 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/RegionBedToGFF3Cli.java +43 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/RegionDepthCli.java +29 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/SamBamCovCli.java +33 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/SeqConverterCli.java +17 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/SeqLenTrackCli.java +41 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/SeveralSpeciesCli.java +132 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/SimpleEnricherCli.java +44 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/SimpleHmmscanCli.java +32 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/SixFrameTranlaterCli.java +35 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/StructAnnoCompareCli.java +66 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/SubmitSMARTCli.java +30 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/SuperCircosCli.java +330 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/TableColManipCli.java +56 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/TableCollapseCli.java +33 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/TargetScoreCli.java +47 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/TauCalcCli.java +28 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/TaxonomyBatchCli.java +72 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/TreeCli.java +75 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/TreeRootingCli.java +30 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/TrimMSACli.java +33 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/UnrootedTreeCli.java +44 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/UpSetCli.java +90 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/Venn5Cli.java +60 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/Venn6Cli.java +65 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/ViolinCli.java +66 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/VisualizeCli.java +57 -0
- tbtools_cli-1.2.0.data/data/tbtools_cli/bridges/VizGFACli.java +39 -0
- tbtools_cli-1.2.0.dist-info/METADATA +504 -0
- tbtools_cli-1.2.0.dist-info/RECORD +139 -0
- tbtools_cli-1.2.0.dist-info/WHEEL +5 -0
- tbtools_cli-1.2.0.dist-info/entry_points.txt +2 -0
- tbtools_cli-1.2.0.dist-info/licenses/LICENSE +21 -0
- tbtools_cli-1.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
"""command_spec.py — 统一命令模型(CommandSpec, 第八轮评审核心建议骨架)。
|
|
2
|
+
|
|
3
|
+
目标: 所有命令产物(metadata/docs/help/search/统计)从单一 CommandSpec 模型派生,
|
|
4
|
+
不再各自从 ENGINE_REGISTRY / CLI_TOOLS / cli.py / CATEGORY_MAP 分散读取。
|
|
5
|
+
|
|
6
|
+
当前为兼容层骨架: 从现有注册源构建统一 specs(不改运行时行为),
|
|
7
|
+
gen_metadata 与后续工具以 specs 为唯一输入。
|
|
8
|
+
"""
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
|
|
11
|
+
from tbtools_cli import auto_commands as _ac
|
|
12
|
+
from tbtools_cli.cli_tools_registry import CLI_TOOLS
|
|
13
|
+
from tbtools_cli.cli_load import CATEGORY_MAP
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class InputSpec:
|
|
18
|
+
"""命令输入定义(二期 schema: 类型/格式/必填)"""
|
|
19
|
+
name: str
|
|
20
|
+
role: str = "file" # file | param
|
|
21
|
+
format: str = "" # gff3 | fasta | tsv | newick | ...
|
|
22
|
+
required: bool = True
|
|
23
|
+
note: str = ""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class CommandSpec:
|
|
28
|
+
"""单一命令定义(第八轮评审 CommandSpec 模型)"""
|
|
29
|
+
name: str
|
|
30
|
+
group: str
|
|
31
|
+
kind: str # bridge | direct | tool | manual
|
|
32
|
+
class_name: str = ""
|
|
33
|
+
runner: str = "" # plot | java | ""
|
|
34
|
+
xmx: str = "2g"
|
|
35
|
+
doc: str = ""
|
|
36
|
+
status: str = "stable" # stable|beta|legacy|platform-limited|network-required
|
|
37
|
+
aliases: list[str] = field(default_factory=list) # 反向: canonical → 别名们
|
|
38
|
+
alias_of: str = "" # 本命令是某 canonical 的兼容别名(如 treeRooting→rooting)
|
|
39
|
+
inputs: list[InputSpec] = field(default_factory=list)
|
|
40
|
+
outputs: list[str] = field(default_factory=list) # 输出类型(如 svg/png/tsv)
|
|
41
|
+
capabilities: list[str] = field(default_factory=list) # 能力标签(能力图搜索)
|
|
42
|
+
dependencies: list[str] = field(default_factory=list) # 外部依赖(环境解析, GLM #22)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# 核心命令输入输出 schema 样例(证明模型模式; 全量标注为二期)
|
|
46
|
+
KNOWN_SCHEMAS = {
|
|
47
|
+
"volcano": ([InputSpec("deg", format="tsv", note="GeneID\tLog2FC\tpvalue")], ["svg"]),
|
|
48
|
+
"heatmap": ([InputSpec("matrix", format="tsv", note="表达矩阵 gene×sample")], ["svg"]),
|
|
49
|
+
"hclust": ([InputSpec("distance", format="tsv", note="三列: GeneA\tGeneB\tdist")], ["svg"]),
|
|
50
|
+
"venn2": ([InputSpec("list1", format="txt"), InputSpec("list2", format="txt")], ["svg"]),
|
|
51
|
+
"msy": ([InputSpec("pos", format="tsv", note="Chr\tGene\tStart\tEnd"),
|
|
52
|
+
InputSpec("links", format="tsv"), InputSpec("layout", format="txt")], ["svg"]),
|
|
53
|
+
"genestructure": ([InputSpec("gff", format="gff3"), InputSpec("ids", format="txt")], ["svg"]),
|
|
54
|
+
"motif": ([InputSpec("meme_xml", format="xml"), InputSpec("ids", format="txt")], ["svg"]),
|
|
55
|
+
"peaktss": ([InputSpec("gxf", format="gff3"), InputSpec("peaks", format="tsv", note="MACS2")], ["svg"]),
|
|
56
|
+
"tableMerge": ([InputSpec("tables", format="tsv", note="多个输入表")], ["tsv"]),
|
|
57
|
+
"qdot": ([InputSpec("gff", format="tsv", note="4 列简化: Chr\tGene\tStart\tEnd")], ["svg"]),
|
|
58
|
+
# 二期扩展批(高频绘图/工具)
|
|
59
|
+
"dehist": ([InputSpec("deg", format="tsv", note="DEG 表")], ["svg"]),
|
|
60
|
+
"pca": ([InputSpec("matrix", format="tsv", note="表达矩阵")], ["svg"]),
|
|
61
|
+
"barplot": ([InputSpec("enrichment", format="tsv", note="富集表: 列名 Term/Pvalue")], ["svg"]),
|
|
62
|
+
"circos": ([InputSpec("chrLen", format="tsv"), InputSpec("link", format="tsv"),
|
|
63
|
+
InputSpec("genePos", format="tsv")], ["svg"]),
|
|
64
|
+
"dotplot": ([InputSpec("gff", format="tsv", note="4 列简化"), InputSpec("pairs", format="tsv")], ["svg"]),
|
|
65
|
+
"dualsyn": ([InputSpec("gff", format="tsv", note="简化 GFF"), InputSpec("pairs", format="tsv")], ["svg"]),
|
|
66
|
+
"mcscanx": ([InputSpec("gff", format="tsv", note="chr\tgene\tstart\tend"),
|
|
67
|
+
InputSpec("blast", format="tsv", note="tab6")], ["tsv"]),
|
|
68
|
+
"iqtree": ([InputSpec("aln", format="fasta")], ["nwk", "treefile"]),
|
|
69
|
+
"muscle": ([InputSpec("fasta", format="fasta")], ["aln"]),
|
|
70
|
+
"trimal": ([InputSpec("aln", format="fasta")], ["aln"]),
|
|
71
|
+
"blastp": ([InputSpec("query", format="fasta"), InputSpec("db", format="fasta")], ["out"]),
|
|
72
|
+
"sixframe": ([InputSpec("pep", format="fasta", note="蛋白(输出核酸)")], ["fa"]),
|
|
73
|
+
"longestorf": ([InputSpec("seq", format="fasta", note="核酸输入")], ["fa"]),
|
|
74
|
+
"seqlogo": ([InputSpec("seqs", format="fasta")], ["svg"]),
|
|
75
|
+
"stat-fasta": ([InputSpec("fasta", format="fasta")], ["xls"]),
|
|
76
|
+
# 三期批次(schema 标注继续)
|
|
77
|
+
"venn3": ([InputSpec("list1", format="txt"), InputSpec("list2", format="txt"),
|
|
78
|
+
InputSpec("list3", format="txt")], ["svg"]),
|
|
79
|
+
"venn4": ([InputSpec("list1", format="txt"), InputSpec("list2", format="txt"),
|
|
80
|
+
InputSpec("list3", format="txt"), InputSpec("list4", format="txt")], ["svg"]),
|
|
81
|
+
"upset": ([InputSpec("sets", format="txt", note="多个集合文件, 末参为输出")], ["svg"]),
|
|
82
|
+
"tpmCalc": ([InputSpec("counts", format="tsv"), InputSpec("lenInfo", format="tsv")], ["tsv"]),
|
|
83
|
+
"gxfSplit": ([InputSpec("gff", format="gff3")], ["tsv"]),
|
|
84
|
+
"gxfAttr": ([InputSpec("gff", format="gff3")], ["tsv"]),
|
|
85
|
+
"gxfIdAppender": ([InputSpec("gff", format="gff3")], ["gff3"]),
|
|
86
|
+
"recipBlast": ([InputSpec("db", format="fasta"), InputSpec("query", format="fasta")], ["tsv"]),
|
|
87
|
+
"autoMakeBlastDb": ([InputSpec("fasta", format="fasta")], ["db"]),
|
|
88
|
+
"genelocgff": ([InputSpec("gff", format="gff3"), InputSpec("ids", format="txt")], ["svg"]),
|
|
89
|
+
"treeRooting": ([InputSpec("nwk", format="newick", note="需枝长")], ["nwk"]),
|
|
90
|
+
"memerun": ([InputSpec("fasta", format="fasta")], ["meme"]),
|
|
91
|
+
"mastrun": ([InputSpec("meme", format="meme")], ["xml"]),
|
|
92
|
+
"goEnrich": ([InputSpec("background", format="tsv"), InputSpec("target", format="tsv")], ["tsv"]),
|
|
93
|
+
"keggEnrich": ([InputSpec("background", format="tsv"), InputSpec("target", format="tsv")], ["tsv"]),
|
|
94
|
+
"gsea": ([InputSpec("expr", format="tsv"), InputSpec("cls", format="txt")], ["xls"]),
|
|
95
|
+
"efpHeat": ([InputSpec("tga", format="tga", note="TrueColor type2"), InputSpec("expMat", format="tsv")], ["svg"]),
|
|
96
|
+
"multiEfp": ([InputSpec("tga", format="tga"), InputSpec("expMat", format="tsv")], ["svg"]),
|
|
97
|
+
"layoutheatmap": ([InputSpec("expr", format="tsv"), InputSpec("layout", format="tsv")], ["svg"]),
|
|
98
|
+
# 第三批(常用绘图/工具)
|
|
99
|
+
"microsyn": ([InputSpec("gff", format="tsv", note="简化 GFF"),
|
|
100
|
+
InputSpec("links", format="tsv")], ["svg"]),
|
|
101
|
+
"multisyn": ([InputSpec("gff", format="tsv"), InputSpec("gxf_lst", format="txt")], ["svg"]),
|
|
102
|
+
"pafviz": ([InputSpec("paf", format="tsv", note="13 列 PAF")], ["svg"]),
|
|
103
|
+
"pafref": ([InputSpec("paf", format="tsv", note="含 cg:Z CIGAR")], ["svg"]),
|
|
104
|
+
"peakanno": ([InputSpec("peaks", format="tsv", note="MACS2, 百万级坐标")], ["tsv"]),
|
|
105
|
+
"supercircos": ([InputSpec("config", format="txt", note="[chrLen] 等节")], ["svg"]),
|
|
106
|
+
"gel": ([InputSpec("lanes", format="tsv", note="LaneLabels 逗号分隔")], ["svg"]),
|
|
107
|
+
"plotrna": ([InputSpec("seq", format="fasta")], ["pdf"]),
|
|
108
|
+
"pep2codon": ([InputSpec("cds", format="fasta"), InputSpec("pep_aln", format="fasta")], ["fa"]),
|
|
109
|
+
"mcscanxd": ([InputSpec("gff", format="tsv"), InputSpec("blast", format="tsv")], ["collinearity"]),
|
|
110
|
+
"notung": ([InputSpec("tree", format="newick"), InputSpec("gene_tree", format="newick")], ["nwk"]),
|
|
111
|
+
"newickRename": ([InputSpec("nwk", format="newick")], ["nwk"]),
|
|
112
|
+
"hmmerSearch": ([InputSpec("hmm", format="hmm"), InputSpec("seq", format="fasta")], ["tsv"]),
|
|
113
|
+
"memeViz": ([InputSpec("meme", format="meme")], ["svg"]),
|
|
114
|
+
"kallisto": ([InputSpec("fastq", format="fastq", note="RNA-seq")], ["tsv"]),
|
|
115
|
+
"tfbsShift": ([InputSpec("motif", format="meme")], ["tsv"]),
|
|
116
|
+
"smart": ([InputSpec("seq", format="fasta")], ["tsv"]),
|
|
117
|
+
"barplotter": ([InputSpec("gff", format="gff3"), InputSpec("synteny", format="tsv")], ["svg"]),
|
|
118
|
+
"calcRepeat": ([InputSpec("fasta", format="fasta")], ["tsv"]),
|
|
119
|
+
"rnaplot": ([InputSpec("seq", format="fasta")], ["svg"]),
|
|
120
|
+
"preparespecies": ([InputSpec("genome", format="fasta"), InputSpec("gff", format="gff3")], ["fasta"]),
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# 命令外部依赖(env 工具级解析; 无依赖命令默认 [])
|
|
125
|
+
KNOWN_DEPENDENCIES = {
|
|
126
|
+
"hmmsearch": ["hmmer"], "simplehmmscan": ["hmmer"],
|
|
127
|
+
"calcRepeat": ["jellyfish"],
|
|
128
|
+
"rnaplot": ["rnafold"], "plotrna": ["rnafold"],
|
|
129
|
+
"kallisto": ["kallisto"],
|
|
130
|
+
"diamond": ["diamond"],
|
|
131
|
+
"mcscanxd": ["mcscanx"],
|
|
132
|
+
"blastp": ["blast+"], "blastn": ["blast+"],
|
|
133
|
+
"muscle": ["muscle"], "mafft": ["mafft"],
|
|
134
|
+
"iqtree": ["iqtree2"], "onesteptree": ["iqtree2"],
|
|
135
|
+
"trimal": ["trimal"],
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# 组级能力兜底(无精确标注的命令按组归能力域; 优先精确标注, 后兜底)
|
|
140
|
+
GROUP_CAPABILITIES = {
|
|
141
|
+
"expr": ["expression"], "syn": ["synteny"], "gxf": ["annotation"],
|
|
142
|
+
"table": ["table_operations"], "fastq": ["ngs", "sequence"],
|
|
143
|
+
"blast": ["homology"], "asm": ["assembly"], "chipseq": ["chip_seq"],
|
|
144
|
+
"tree": ["phylogeny"], "seq": ["sequence"], "efp": ["expression"],
|
|
145
|
+
"sets": ["set_operations"], "enrich": ["enrichment"], "virus": ["viral_analysis"],
|
|
146
|
+
"genome": ["genome_analysis"], "assembly": ["assembly"],
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# 工具语义关系(能力图: 输入输出衔接; GLM #24)——核心命令标注
|
|
151
|
+
KNOWN_RELATIONS = {
|
|
152
|
+
"volcano": {"accepts": ["DEG_TABLE"], "produces": ["VOLCANO_PLOT"],
|
|
153
|
+
"next_step": ["goEnrich", "keggEnrich"], "related_to": ["dehist", "heatmap"]},
|
|
154
|
+
"dehist": {"accepts": ["DEG_TABLE"], "produces": ["DEG_HISTOGRAM"],
|
|
155
|
+
"related_to": ["volcano"]},
|
|
156
|
+
"heatmap": {"accepts": ["EXPRESSION_MATRIX"], "produces": ["HEATMAP"],
|
|
157
|
+
"next_step": ["hclust"], "related_to": ["pca"]},
|
|
158
|
+
"pca": {"accepts": ["EXPRESSION_MATRIX"], "produces": ["PCA_PLOT"]},
|
|
159
|
+
"hclust": {"accepts": ["DISTANCE_TABLE"], "produces": ["DENDROGRAM"],
|
|
160
|
+
"related_to": ["heatmap"]},
|
|
161
|
+
"mcscanx": {"accepts": ["GFF", "BLAST_TAB6"], "produces": ["COLLINEARITY"],
|
|
162
|
+
"next_step": ["dualsyn", "dotplot"]},
|
|
163
|
+
"dualsyn": {"accepts": ["SIMPLIFIED_GFF", "COLLINEARITY"], "produces": ["SYNTENY_PLOT"]},
|
|
164
|
+
"dotplot": {"accepts": ["SIMPLIFIED_GFF", "COLLINEARITY"], "produces": ["DOTPLOT"]},
|
|
165
|
+
"muscle": {"accepts": ["FASTA"], "produces": ["ALIGNMENT"], "next_step": ["trimal", "iqtree"]},
|
|
166
|
+
"trimal": {"accepts": ["ALIGNMENT"], "produces": ["TRIMMED_ALIGNMENT"], "next_step": ["iqtree"]},
|
|
167
|
+
"iqtree": {"accepts": ["ALIGNMENT"], "produces": ["PHYLOGENY_NWK"], "next_step": ["tree"]},
|
|
168
|
+
"tpmCalc": {"accepts": ["COUNTS_TABLE", "GENE_LENGTH"], "produces": ["TPM_TABLE"],
|
|
169
|
+
"next_step": ["pca", "heatmap", "volcano"]},
|
|
170
|
+
"gsea": {"accepts": ["EXPRESSION_TABLE", "PHENOTYPE_CLS"], "produces": ["GSEA_REPORT"]},
|
|
171
|
+
"genestructure": {"accepts": ["GFF3", "GENE_ID_LIST"], "produces": ["GENE_STRUCTURE_PLOT"]},
|
|
172
|
+
"kallisto": {"accepts": ["FASTQ"], "produces": ["QUANT_TABLE"], "next_step": ["tpmCalc"]},
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# 已知别名(兼容层命名; canonical → 命令)
|
|
177
|
+
KNOWN_CAPABILITIES = {
|
|
178
|
+
"volcano": ["differential_expression", "visualization"],
|
|
179
|
+
"heatmap": ["expression_matrix", "clustering", "visualization"],
|
|
180
|
+
"dehist": ["differential_expression", "visualization"],
|
|
181
|
+
"pca": ["dimension_reduction", "expression_matrix"],
|
|
182
|
+
"hclust": ["clustering", "distance"],
|
|
183
|
+
"genestructure": ["gene_structure", "annotation", "visualization"],
|
|
184
|
+
"seqlogo": ["motif", "visualization"],
|
|
185
|
+
"msa": ["alignment", "visualization"],
|
|
186
|
+
"motif": ["motif", "visualization"],
|
|
187
|
+
"sixframe": ["translation", "sequence"],
|
|
188
|
+
"longestorf": ["orf_prediction", "sequence"],
|
|
189
|
+
"blastp": ["homology", "alignment"],
|
|
190
|
+
"mcscanx": ["synteny", "collinearity"],
|
|
191
|
+
"dualsyn": ["synteny", "visualization"],
|
|
192
|
+
"dotplot": ["synteny", "visualization"],
|
|
193
|
+
"msy": ["microsynteny", "visualization"],
|
|
194
|
+
"iqtree": ["phylogeny"],
|
|
195
|
+
"muscle": ["alignment"],
|
|
196
|
+
"trimal": ["alignment", "filtering"],
|
|
197
|
+
"kallisto": ["rna_seq", "quantification"],
|
|
198
|
+
"gsea": ["enrichment"],
|
|
199
|
+
"goEnrich": ["enrichment"],
|
|
200
|
+
"keggEnrich": ["enrichment"],
|
|
201
|
+
"tpmCalc": ["rna_seq", "normalization"],
|
|
202
|
+
"peaktss": ["chip_seq"],
|
|
203
|
+
}
|
|
204
|
+
# 精确标注补充(2026-09-23): 覆盖组级兜底的粗标签, 核心命令细化
|
|
205
|
+
KNOWN_CAPABILITIES.update({
|
|
206
|
+
"mcscanx": ["synteny", "collinearity_detection"],
|
|
207
|
+
"dualsyn": ["synteny", "visualization"],
|
|
208
|
+
"dotplot": ["synteny", "visualization"],
|
|
209
|
+
"circos": ["visualization", "genome_circos"],
|
|
210
|
+
"collinearRegion": ["synteny", "visualization"],
|
|
211
|
+
"pafviz": ["synteny", "visualization"],
|
|
212
|
+
"pafref": ["synteny", "visualization"],
|
|
213
|
+
"microsyn": ["synteny", "visualization"],
|
|
214
|
+
"multisyn": ["synteny", "visualization"],
|
|
215
|
+
"qdot": ["synteny", "visualization"],
|
|
216
|
+
"fimo": ["motif", "scanning"],
|
|
217
|
+
"mastrun": ["motif", "scanning"],
|
|
218
|
+
"memerun": ["motif", "discovery"],
|
|
219
|
+
"memeViz": ["motif", "visualization"],
|
|
220
|
+
"seqlogo": ["motif", "visualization"],
|
|
221
|
+
"tfbsShift": ["motif", "genome_scan"],
|
|
222
|
+
"smart": ["domain", "annotation"],
|
|
223
|
+
"hmmsearch": ["homology", "hmm_scan"],
|
|
224
|
+
"diamond": ["homology", "alignment"],
|
|
225
|
+
"blastp": ["homology", "alignment"],
|
|
226
|
+
"blastn": ["homology", "alignment"],
|
|
227
|
+
"recipBlast": ["homology", "reciprocal_best_hit"],
|
|
228
|
+
"filterCScore": ["homology", "filtering"],
|
|
229
|
+
"kallisto": ["rna_seq", "quantification"],
|
|
230
|
+
"fqTrim": ["ngs", "preprocessing"],
|
|
231
|
+
"fqfaConv": ["sequence", "conversion"],
|
|
232
|
+
"fastaExtract": ["sequence", "extraction"],
|
|
233
|
+
"fastaSubseq": ["sequence", "extraction"],
|
|
234
|
+
"gffFix": ["annotation", "gff_fixing"],
|
|
235
|
+
"gxfAppend": ["annotation", "gff_ops"],
|
|
236
|
+
"genelocation": ["annotation", "visualization"],
|
|
237
|
+
"peaktss": ["chip_seq", "peak_calling"],
|
|
238
|
+
"peakanno": ["chip_seq", "peak_annotation"],
|
|
239
|
+
"tpmCalc": ["rna_seq", "normalization"],
|
|
240
|
+
"efpHeat": ["expression", "visualization"],
|
|
241
|
+
"layoutheatmap": ["expression", "visualization"],
|
|
242
|
+
"gsea": ["enrichment"],
|
|
243
|
+
"goEnrich": ["enrichment", "gene_ontology"],
|
|
244
|
+
"keggEnrich": ["enrichment", "pathway"],
|
|
245
|
+
"multiEfp": ["expression", "visualization"],
|
|
246
|
+
"treeRooting": ["phylogeny", "rooting"],
|
|
247
|
+
"onesteptree": ["phylogeny", "tree_building"],
|
|
248
|
+
"notung": ["phylogeny", "reconciliation"],
|
|
249
|
+
"newickRename": ["phylogeny", "tree_editing"],
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
KNOWN_ALIASES = {
|
|
255
|
+
"treeRooting": "rooting",
|
|
256
|
+
"TableCast": "tableCast",
|
|
257
|
+
"gbar": "groupedbar",
|
|
258
|
+
"gdensity": "genedensity",
|
|
259
|
+
"getLongestCompleteORF": "longestorf",
|
|
260
|
+
"one-step": "onesteptree",
|
|
261
|
+
"genestructure": "structure", # 旧名 → seq structure? 保留注释: genestructure 是独立命令
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
# 已知状态(engine 级/环境限制; 未列默认为 stable)
|
|
265
|
+
KNOWN_STATUS = {
|
|
266
|
+
"srr2ena": "network-required",
|
|
267
|
+
"pubmed": "network-required",
|
|
268
|
+
"seqfetch": "network-required",
|
|
269
|
+
"rnaplot": "platform-limited", # 需 RNAfold 在 PATH(Windows 默认缺)
|
|
270
|
+
"calcRepeat": "platform-limited", # 需 jellyfish(Windows 默认缺)
|
|
271
|
+
"hmmsearch": "platform-limited", # 需系统 hmmsearch
|
|
272
|
+
"simplehmmscan": "platform-limited",
|
|
273
|
+
"cubeheatmap": "beta", # 引擎列数假设严格(官方数据仍 ArrayIndexOutOfBounds)
|
|
274
|
+
"groupedbar": "beta",
|
|
275
|
+
"nwAlign": "beta", # 输入格式易错(FASTA 头被当序列)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def build_command_specs() -> dict[str, CommandSpec]:
|
|
280
|
+
"""构建统一命令模型(单一源, 兼容层: 不改变现运行行为)。
|
|
281
|
+
|
|
282
|
+
来源:
|
|
283
|
+
1. ENGINE_REGISTRY 表驱动(组 CATEGORY_MAP 归属)
|
|
284
|
+
2. CLI_TOOLS 工具注册表
|
|
285
|
+
3. 手动命令(经 cli_load 分组注册的 manual 命令, 从分组命令集补)
|
|
286
|
+
"""
|
|
287
|
+
specs: dict[str, CommandSpec] = {}
|
|
288
|
+
|
|
289
|
+
# 1. 表驱动引擎命令
|
|
290
|
+
for name, kind, cls, xmx, runner, doc in _ac.ENGINE_REGISTRY:
|
|
291
|
+
specs[name] = CommandSpec(
|
|
292
|
+
name=name, group=CATEGORY_MAP.get(name, "engine"),
|
|
293
|
+
kind=kind, class_name=cls, runner=runner, xmx=xmx, doc=doc,
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
# 2. CLI 工具(runner/xmx 对齐现 metadata 条目: java/3g)
|
|
297
|
+
for name, cls in CLI_TOOLS.items():
|
|
298
|
+
specs.setdefault(name, CommandSpec(name=name, group="tool", kind="tool", class_name=cls,
|
|
299
|
+
runner="java", xmx="3g"))
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
# 3. 手动命令: 从现有 metadata 回退(kind=manual 且未被表驱动/工具覆盖)
|
|
303
|
+
# (完整版应遍历 cli 分组命令树; 骨架期以 metadata 为准, 单一模型逐步接管)
|
|
304
|
+
try:
|
|
305
|
+
import json as _json
|
|
306
|
+
import os as _os
|
|
307
|
+
meta_path = _os.path.join(_os.path.dirname(_os.path.dirname(_os.path.abspath(__file__))),
|
|
308
|
+
"tbtools_cli", "command_metadata.json")
|
|
309
|
+
if _os.path.isfile(meta_path):
|
|
310
|
+
meta = _json.load(open(meta_path, encoding="utf-8"))
|
|
311
|
+
for name, v in meta.items():
|
|
312
|
+
if v.get("kind") == "manual" and name not in specs:
|
|
313
|
+
specs[name] = CommandSpec(
|
|
314
|
+
name=name, group=v.get("group", "engine"), kind="manual",
|
|
315
|
+
doc=v.get("help", ""),
|
|
316
|
+
)
|
|
317
|
+
except Exception:
|
|
318
|
+
pass
|
|
319
|
+
|
|
320
|
+
# 别名/状态/schema 标注(统一模型增强; 在所有来源构建完成后)
|
|
321
|
+
for name, spec in specs.items():
|
|
322
|
+
spec.aliases = [a for a, target in KNOWN_ALIASES.items() if target == name]
|
|
323
|
+
spec.alias_of = KNOWN_ALIASES.get(name, "")
|
|
324
|
+
spec.status = KNOWN_STATUS.get(name, "stable")
|
|
325
|
+
if name in KNOWN_SCHEMAS:
|
|
326
|
+
ins, outs = KNOWN_SCHEMAS[name]
|
|
327
|
+
spec.inputs, spec.outputs = ins, outs
|
|
328
|
+
spec.capabilities = KNOWN_CAPABILITIES.get(name, []) or GROUP_CAPABILITIES.get(spec.group, [])
|
|
329
|
+
spec.dependencies = KNOWN_DEPENDENCIES.get(name, [])
|
|
330
|
+
return specs
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def specs_from_scans(reg, tools, manual, infer_group=None) -> dict[str, dict]:
|
|
334
|
+
"""扫描结果 → CommandSpec → metadata 投影(单一组装逻辑, gen_metadata 与工具共用)。
|
|
335
|
+
|
|
336
|
+
reg/tools/manual: scan_* 输出的条目 dict(含 name/kind/class/runner/xmx/help/group)。
|
|
337
|
+
infer_group: 可选分组推断函数(name, kind, src) -> str(manual 命令分组)。
|
|
338
|
+
"""
|
|
339
|
+
from tbtools_cli.cli_load import CATEGORY_MAP as _CM
|
|
340
|
+
specs = {}
|
|
341
|
+
for name, e in reg.items():
|
|
342
|
+
specs[name] = CommandSpec(name, _CM.get(name, "engine"), e.get("kind", "direct"),
|
|
343
|
+
e.get("class", ""), e.get("runner") or "plot",
|
|
344
|
+
e.get("xmx") or "2g", e.get("help", ""))
|
|
345
|
+
for name, e in tools.items():
|
|
346
|
+
specs.setdefault(name, CommandSpec(name, "tool", "tool", e.get("class", ""),
|
|
347
|
+
"java", "3g", e.get("help", "")))
|
|
348
|
+
for name, e in manual.items():
|
|
349
|
+
grp = e.get("group") or (infer_group(name, "manual", e.get("src", "")) if infer_group else _CM.get(name, "engine"))
|
|
350
|
+
specs.setdefault(name, CommandSpec(name, grp, "manual", runner="plot", doc=e.get("help", "")))
|
|
351
|
+
for name, s in specs.items():
|
|
352
|
+
s.aliases = [a for a, t in KNOWN_ALIASES.items() if t == name]
|
|
353
|
+
s.alias_of = KNOWN_ALIASES.get(name, "")
|
|
354
|
+
s.status = KNOWN_STATUS.get(name, "stable")
|
|
355
|
+
if name in KNOWN_SCHEMAS:
|
|
356
|
+
s.inputs, s.outputs = KNOWN_SCHEMAS[name]
|
|
357
|
+
s.capabilities = KNOWN_CAPABILITIES.get(name, []) or GROUP_CAPABILITIES.get(s.group, [])
|
|
358
|
+
s.dependencies = KNOWN_DEPENDENCIES.get(name, [])
|
|
359
|
+
return {n: to_metadata_entry(s) for n, s in specs.items()}
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def to_metadata_entry(spec: CommandSpec) -> dict:
|
|
363
|
+
"""CommandSpec → metadata 条目(与现有 command_metadata.json 结构兼容)"""
|
|
364
|
+
e: dict[str, object] = {"name": spec.name, "kind": spec.kind, "mode": spec.kind,
|
|
365
|
+
"class": spec.class_name, "xmx": spec.xmx, "runner": spec.runner,
|
|
366
|
+
"group": spec.group, "help": spec.doc}
|
|
367
|
+
if spec.alias_of:
|
|
368
|
+
e["alias_of"] = spec.alias_of
|
|
369
|
+
if spec.capabilities:
|
|
370
|
+
e["capabilities"] = spec.capabilities
|
|
371
|
+
if spec.dependencies:
|
|
372
|
+
e["dependencies"] = spec.dependencies
|
|
373
|
+
if spec.inputs:
|
|
374
|
+
e["inputs"] = [{"name": i.name, "role": i.role, "format": i.format,
|
|
375
|
+
"required": i.required, "note": i.note} for i in spec.inputs]
|
|
376
|
+
if spec.outputs:
|
|
377
|
+
e["outputs"] = spec.outputs
|
|
378
|
+
if spec.status != "stable":
|
|
379
|
+
e["status"] = spec.status
|
|
380
|
+
if spec.aliases:
|
|
381
|
+
e["aliases"] = spec.aliases
|
|
382
|
+
return e
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# tbtools-cli 配置文件
|
|
2
|
+
# 位置: ~/.config/tbtools-cli/config.toml
|
|
3
|
+
# 首次运行 install.sh 自动生成(可手改)
|
|
4
|
+
|
|
5
|
+
# TBtools JAR 路径(优先级: 环境变量 > 配置文件 > 自动探测)
|
|
6
|
+
jar = "/path/to/TBtools_JRE1.6.jar"
|
|
7
|
+
|
|
8
|
+
# 默认参数(可被命令行 --option 覆盖)
|
|
9
|
+
[defaults]
|
|
10
|
+
threads = 4
|
|
11
|
+
format = "svg"
|
|
12
|
+
# preset = "nature" # 取消注释启用默认预设
|
|
13
|
+
# verbose = false
|
|
14
|
+
# quiet = false
|
|
15
|
+
|
|
16
|
+
# 自定义画布尺寸(0=自动)
|
|
17
|
+
[canvas]
|
|
18
|
+
width = 0
|
|
19
|
+
height = 0
|
tbtools_cli/config.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""配置文件加载 — ~/.config/tbtools-cli/config.toml"""
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
try:
|
|
5
|
+
import tomllib
|
|
6
|
+
except ImportError:
|
|
7
|
+
tomllib = None # type: ignore[assignment]
|
|
8
|
+
|
|
9
|
+
DEFAULT_CONFIG_PATH = os.path.expanduser("~/.config/tbtools-cli/config.toml")
|
|
10
|
+
|
|
11
|
+
_config_cache: tuple[str, dict] | None = None # (config路径, 数据)
|
|
12
|
+
|
|
13
|
+
def load_config():
|
|
14
|
+
"""加载配置文件。返回 dict(可能为空)。
|
|
15
|
+
|
|
16
|
+
_config_cache 缓存 (路径, 数据)——TBTOOLS_CONFIG env 变化时自动重读
|
|
17
|
+
(第十四轮审计: 原缓存不感知 env 变化,测试/库场景拿旧配置)。
|
|
18
|
+
"""
|
|
19
|
+
global _config_cache
|
|
20
|
+
path = os.environ.get("TBTOOLS_CONFIG", DEFAULT_CONFIG_PATH)
|
|
21
|
+
if _config_cache is not None and _config_cache[0] == path:
|
|
22
|
+
return _config_cache[1]
|
|
23
|
+
if not tomllib:
|
|
24
|
+
return {}
|
|
25
|
+
if not os.path.isfile(path):
|
|
26
|
+
return {}
|
|
27
|
+
try:
|
|
28
|
+
with open(path, "rb") as f:
|
|
29
|
+
_config_cache = (path, tomllib.load(f))
|
|
30
|
+
except Exception:
|
|
31
|
+
_config_cache = (path, {})
|
|
32
|
+
return _config_cache[1]
|
|
33
|
+
|
|
34
|
+
def get_default(key, fallback=None):
|
|
35
|
+
"""获取默认值(配置文件 < 环境变量 < 命令行)"""
|
|
36
|
+
cfg = load_config()
|
|
37
|
+
defaults = cfg.get("defaults", {})
|
|
38
|
+
return defaults.get(key, fallback)
|
|
39
|
+
|
|
40
|
+
def get_jar():
|
|
41
|
+
"""获取 JAR 路径(配置文件优先)"""
|
|
42
|
+
cfg = load_config()
|
|
43
|
+
return cfg.get("jar", "")
|