reroot-trees 0.1.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.
reroot_trees/_init_.py ADDED
@@ -0,0 +1,2 @@
1
+ # src/reroot_trees/__init__.py
2
+ __version__ = "1.0.0"
reroot_trees/cli.py ADDED
@@ -0,0 +1,136 @@
1
+ def main():
2
+ EXAMPLES = r"""
3
+ 示例:
4
+ 1) 默认外类群(脚本内置),处理当前目录所有 .tre
5
+ python reroot_trees.py "*.tre"
6
+
7
+ 2) 替换“默认外类群”(仅当不提供 --outgroups/--outgroup_file 时生效)
8
+ python reroot_trees.py "*.tre" --default_outgroups AJ01,AJ02,AJ03
9
+
10
+ 3) 指定外类群(逗号分隔),至少命中1个即尝试定根
11
+ python reroot_trees.py "*.tre" --outgroups AJBB1124,AJBB1128,AJKa01
12
+
13
+ 4) 用外类群文件(每行一个标签),至少命中2个才定根
14
+ python reroot_trees.py "*.tre" --outgroup_file outgroups.txt --min_match 2
15
+
16
+ 5) 总是使用 -l(以内群为根)
17
+ python reroot_trees.py "*.tre" --outgroups AJBB1124,AJBB1128 --always_lax
18
+
19
+ 6) 指定输出目录与后缀
20
+ python reroot_trees.py "*.tre" --outdir rooted --suffix _rerooted
21
+
22
+ 7) 原地覆盖(谨慎)
23
+ python reroot_trees.py "*.tre" --in_place
24
+
25
+ 8) 指定输入文件编码(例如 Windows 生成文件)
26
+ python reroot_trees.py "*.tre" --encoding cp936
27
+
28
+ 9) 关闭自动安装 newick_utils(服务器不允许装软件时用)
29
+ python reroot_trees.py "*.tre" --no_auto_install
30
+ """
31
+ parser = argparse.ArgumentParser(
32
+ description="Batch reroot Newick trees via nw_reroot(每行一棵树)",
33
+ formatter_class=argparse.RawDescriptionHelpFormatter,
34
+ epilog=EXAMPLES
35
+ )
36
+
37
+ # 让 pattern 变为可选,以便 --print-examples 独立使用
38
+ parser.add_argument("pattern", nargs="?", help="输入通配符,如 '*.tre'(请用引号避免被 shell 预展开)")
39
+ parser.add_argument("--print-examples", action="store_true", help="只打印用法示例后退出")
40
+
41
+ parser.add_argument("--outgroups", help="逗号分隔的外类群标签,例如 A,B,C")
42
+ parser.add_argument("--outgroup_file", help="外类群文件(每行一个标签)")
43
+
44
+ # ✅ 你要的:替换默认外类群(作为新的默认)
45
+ parser.add_argument("--default_outgroups",
46
+ help="替换脚本内置默认外类群(逗号分隔)。仅当不提供 --outgroups/--outgroup_file 时生效")
47
+
48
+ parser.add_argument("--min_match", type=int, default=1,
49
+ help="至少出现多少个外类群标签才尝试定根(默认1)")
50
+ parser.add_argument("--always_lax", action="store_true",
51
+ help="总是使用 -l(以内群为根)")
52
+ parser.add_argument("--suffix", default="_rooted", help="输出文件后缀(默认 _rooted)")
53
+ parser.add_argument("--outdir", default="", help="输出目录(默认与输入同目录)")
54
+ parser.add_argument("--in_place", action="store_true", help="覆盖原文件(忽略 --suffix/--outdir)")
55
+ parser.add_argument("--encoding", default="utf-8", help="输入文件编码(默认 utf-8)")
56
+
57
+ # ✅ 自动检测/安装 newick_utils
58
+ parser.add_argument("--no_auto_install", action="store_true",
59
+ help="关闭自动安装 newick_utils(默认会自动安装)")
60
+
61
+ args = parser.parse_args()
62
+
63
+ if args.print_examples:
64
+ print(EXAMPLES.strip("\n"))
65
+ return
66
+
67
+ if not args.pattern:
68
+ sys.exit("⚠️ 需要提供输入通配符(例如 \"*.tre\")。或使用 --print-examples 查看示例。")
69
+
70
+ if args.min_match < 1:
71
+ sys.exit("❌ --min_match 必须 >= 1")
72
+
73
+ # 先确保 nw_reroot 可用
74
+ ensure_nw_reroot(auto_install=(not args.no_auto_install))
75
+
76
+ # 读外类群(带替换默认逻辑)
77
+ OUTGROUPS = read_outgroups(args.outgroup_file, args.outgroups, args.default_outgroups)
78
+
79
+ files = sorted(glob.glob(args.pattern))
80
+ if not files:
81
+ sys.exit(f"⚠️ 未找到匹配文件:{args.pattern}")
82
+ print(f"\n🔍 待处理文件数:{len(files)}")
83
+
84
+ changed, skipped = 0, 0
85
+ for infile in files:
86
+ outdir = Path(os.path.dirname(infile)) if not args.outdir else Path(args.outdir)
87
+ outdir.mkdir(parents=True, exist_ok=True)
88
+
89
+ if args.in_place:
90
+ outfile = Path(infile)
91
+ tmpfile = outfile.with_suffix(outfile.suffix + ".tmp")
92
+ else:
93
+ stem, ext = os.path.splitext(os.path.basename(infile))
94
+ outfile = outdir / f"{stem}{args.suffix}{ext}"
95
+ tmpfile = outfile
96
+
97
+ print(f"\n🌳 {infile} -> {outfile}")
98
+ n_total, n_rooted = 0, 0
99
+
100
+ with open(infile, encoding=args.encoding) as fin, open(tmpfile, "w", encoding="utf-8") as fout:
101
+ for line in fin:
102
+ tree = line.strip()
103
+ if not tree:
104
+ continue
105
+ n_total += 1
106
+
107
+ labels = extract_labels(tree)
108
+ present = [og for og in OUTGROUPS if og in labels]
109
+
110
+ if len(present) >= args.min_match:
111
+ newick = run_reroot(tree, present, args.always_lax)
112
+ if newick:
113
+ fout.write(newick + "\n")
114
+ n_rooted += 1
115
+ continue
116
+
117
+ # 未定根或不满足门槛:原样写回
118
+ fout.write(tree + "\n")
119
+
120
+ if args.in_place:
121
+ # 用 tmp 覆盖原文件
122
+ with open(tmpfile, "r", encoding="utf-8") as fr, open(outfile, "w", encoding="utf-8") as fw:
123
+ fw.write(fr.read())
124
+ try:
125
+ os.remove(tmpfile)
126
+ except OSError:
127
+ pass
128
+
129
+ print(f" ✅ 定根 {n_rooted}/{n_total}")
130
+ changed += n_rooted
131
+ skipped += (n_total - n_rooted)
132
+
133
+ print(f"\n✅ 完成。共定根 {changed} 棵;保留原状 {skipped} 棵。")
134
+
135
+ if __name__ == "__main__":
136
+ main()
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.4
2
+ Name: reroot-trees
3
+ Version: 0.1.0
4
+ Summary: Batch reroot Newick trees using nw_reroot (newick_utils).
5
+ Author: Your Name
6
+ License: MIT
7
+ Keywords: phylogeny,newick,raxml,tree
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+
14
+ # reroot-trees
15
+
16
+ Install:
17
+
18
+ pip install reroot-trees
@@ -0,0 +1,7 @@
1
+ reroot_trees/_init_.py,sha256=oAnPCEq9o7aNog3kkxQ_2dIkeCjJPt9PGd9Hi8JH-V0,53
2
+ reroot_trees/cli.py,sha256=LJxDImY-NEjpaEkl3FulLXVGGPiZm601a0UEi-7PTHc,5801
3
+ reroot_trees-0.1.0.dist-info/METADATA,sha256=HmnZABlGnpzbUQm-IZ9qQHHyPd2mx-xC4i6xZaNW1sU,453
4
+ reroot_trees-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
5
+ reroot_trees-0.1.0.dist-info/entry_points.txt,sha256=2nLcsOjZ0dtY48EFWi8glKcNMimnq2Hw55XFWEbGj9A,55
6
+ reroot_trees-0.1.0.dist-info/top_level.txt,sha256=C7-PfETor7DJnJ4g4w9SwW0LJFSIDfVtUOMN2_lcYVc,13
7
+ reroot_trees-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ reroot-trees = reroot_trees.cli:main
@@ -0,0 +1 @@
1
+ reroot_trees