Skip to content

Commit 02bf875

Browse files
CopilotAdamtaranto
andauthored
fix: tests no longer create files in working directory or test data dirs (#853)
* Initial plan * Initial commit * fix: prevent pytest tests from creating files in working directory or data dirs * Fix test side effects: isolate file I/O in tmp dirs * update pre-commit hooks * Fix liftover outfile default to None to prevent stdout fallback --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Adam Taranto <adam.p.taranto@gmail.com>
1 parent 6e8e10b commit 02bf875

34 files changed

Lines changed: 514792 additions & 105 deletions

.pre-commit-config.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,19 @@ repos:
1818
- id: check-executables-have-shebangs
1919
#- id: debug-statements
2020
- repo: https://github.com/rhysd/actionlint
21-
rev: v1.7.9
21+
rev: v1.7.12
2222
hooks:
2323
- id: actionlint
2424
- repo: https://github.com/google/yamlfmt
25-
rev: v0.20.0
25+
rev: v0.21.0
2626
hooks:
2727
- id: yamlfmt
2828
- repo: https://github.com/psf/black
29-
rev: 25.12.0
29+
rev: 26.5.1
3030
hooks:
3131
- id: black
3232
- repo: https://github.com/PyCQA/isort
33-
rev: 7.0.0
33+
rev: 9.0.0a3
3434
hooks:
3535
- id: isort
3636
args: ["--profile", "black"]

src/jcvi/assembly/hic.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,10 @@ def bam2mat(args):
946946
"--seqids",
947947
help="Use a given seqids file, a single line with seqids joined by comma",
948948
)
949+
p.add_argument(
950+
"--outdir",
951+
help="Output directory for generated files (default: same dir as input BAM)",
952+
)
949953
opts, args = p.parse_args(args)
950954

951955
if len(args) != 1:
@@ -954,7 +958,8 @@ def bam2mat(args):
954958
(bamfilename,) = args
955959
pf = bamfilename.rsplit(".", 1)[0]
956960
N = opts.resolution
957-
pf += f".resolution_{N}"
961+
pf_name = op.basename(pf) + f".resolution_{N}"
962+
pf = op.join(opts.outdir, pf_name) if opts.outdir else pf + f".resolution_{N}"
958963
bins = 1500 # Distance distribution bins
959964
minsize = 100 # Record distance if it is at least minsize
960965
seqids = opts.seqids

src/jcvi/compara/synteny.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1930,6 +1930,7 @@ def liftover(args):
19301930
"""
19311931
p = OptionParser(liftover.__doc__)
19321932
p.set_stripnames()
1933+
p.set_outfile(outfile=None)
19331934

19341935
blast_file, anchor_file, dist, opts = add_arguments(p, args)
19351936
qbed, sbed, qorder, sorder, is_self = check_beds(blast_file, p, opts)
@@ -1961,7 +1962,7 @@ def liftover(args):
19611962
lifted += 1
19621963

19631964
logger.debug("%d new pairs found (dist=%d).", lifted, dist)
1964-
newanchorfile = anchor_file.rsplit(".", 1)[0] + ".lifted.anchors"
1965+
newanchorfile = opts.outfile or anchor_file.rsplit(".", 1)[0] + ".lifted.anchors"
19651966
if accepted:
19661967
ac.filter_blocks(accepted)
19671968
ac.print_to_file(filename=newanchorfile)

tests/apps/test_base.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,11 @@ def test_sample_N():
3535
assert a == [2, 3, 1, 2]
3636

3737

38-
def test_download():
38+
def test_download(tmp_path, monkeypatch):
3939
from jcvi.apps.base import cleanup, download
4040
from jcvi.apps.vecscreen import ECOLI_URL, UNIVEC_URL
4141

42+
monkeypatch.chdir(tmp_path)
4243
ret = download("http://www.google.com")
4344
assert ret == "index.html"
4445
cleanup(ret)
@@ -83,10 +84,11 @@ def test_flatten(input_list, output_list):
8384
assert flatten(input_list) == output_list
8485

8586

86-
def test_cleanup():
87+
def test_cleanup(tmp_path, monkeypatch):
8788
from jcvi.apps.base import cleanup, mkdir
8889
from jcvi.formats.base import write_file
8990

91+
monkeypatch.chdir(tmp_path)
9092
write_file("a", "content_a", skipcheck=True)
9193
write_file("b", "content_b", skipcheck=True)
9294
write_file("c", "content_c", skipcheck=True)
@@ -109,11 +111,11 @@ def test_cleanup():
109111
assert not op.exists(path)
110112

111113

112-
def test_need_update():
114+
def test_need_update(tmp_path, monkeypatch):
113115
from jcvi.apps.base import cleanup, need_update
114116
from jcvi.formats.base import write_file
115117

116-
cleanup("a", "b", "c")
118+
monkeypatch.chdir(tmp_path)
117119
assert need_update("does_not_exist.txt", "does_not_exist.txt")
118120

119121
write_file("a", "content_a", skipcheck=True)
@@ -130,7 +132,6 @@ def test_need_update():
130132
assert need_update(["c", "b"], "a")
131133
assert not need_update("a", ["b", "c"])
132134
assert need_update(["a", "b"], ["c", "d"])
133-
cleanup("a", "b", "c")
134135

135136

136137
def test_set_image_options():
@@ -155,9 +156,10 @@ def test_set_image_options():
155156
g.add_argument("--group", default="jcvi", help="pytest coverage")
156157

157158

158-
def test_getpath():
159+
def test_getpath(tmp_path, monkeypatch):
159160
from jcvi.apps.base import getpath
160161

162+
monkeypatch.chdir(tmp_path)
161163
with mock.patch("builtins.input", lambda _: "e\rvvvvvvvv = zzzzzzzz\n"):
162164
assert getpath("not-part-of-path", name="CLUSTALW2", warn="warn") is None
163165

tests/apps/test_fetch.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,15 @@
88

99
@patch("builtins.input", return_value="username")
1010
@patch("getpass.getpass", return_value="password")
11-
def test_get_cookies(mock_username, mock_password):
11+
def test_get_cookies(mock_username, mock_password, tmp_path, monkeypatch):
1212
from jcvi.apps.fetch import get_cookies, PHYTOZOME_COOKIES
13-
from jcvi.apps.base import cleanup, which
13+
from jcvi.apps.base import which
1414

15-
cleanup(PHYTOZOME_COOKIES)
15+
monkeypatch.chdir(tmp_path)
1616
if which("curl"):
1717
assert get_cookies() == PHYTOZOME_COOKIES
1818
else:
1919
assert get_cookies() is None # errored out with "curl not found"
20-
cleanup(PHYTOZOME_COOKIES)
2120

2221

2322
def test_usage_with_percent_prog():
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
##agp-version 2.1
2+
# COMMENT: Generated by ALLMAPS 0.1.dev2+g2ce5bee02 (2026-07-05)
3+
# COMMAND: python -m jcvi.assembly.allmaps path /home/runner/work/jcvi/jcvi/tests/assembly/allmaps.py/inputs/JM-2.bed /home/runner/work/jcvi/jcvi/tests/assembly/allmaps.py/inputs/scaffolds.fasta.gz -w /home/runner/work/jcvi/jcvi/tests/assembly/allmaps.py/inputs/weights.txt
4+
# FIELDS: object, object_beg, object_end, part_number, component_type, component_id/gap_length, component_beg/gap_type, component_end/linkage, orientation/linkage_evidence
5+
chr23 1 137336 1 W scaffold_821 1 137336 ?
6+
chr23 137337 137436 2 U 100 scaffold yes map
7+
chr23 137437 284865 3 W scaffold_792 1 147429 ?
8+
chr23 284866 284965 4 U 100 scaffold yes map
9+
chr23 284966 412560 5 W scaffold_866 1 127595 ?
10+
chr23 412561 412660 6 U 100 scaffold yes map
11+
chr23 412661 484207 7 W scaffold_1189 1 71547 -
12+
chr23 484208 484307 8 U 100 scaffold yes map
13+
chr23 484308 891092 9 W scaffold_375 1 406785 -
14+
chr23 891093 891192 10 U 100 scaffold yes map
15+
chr23 891193 1393339 11 W scaffold_310 1 502147 -
16+
chr23 1393340 1393439 12 U 100 scaffold yes map
17+
chr23 1393440 2982363 13 W scaffold_95 1 1588924 ?
18+
chr23 2982364 2982463 14 U 100 scaffold yes map
19+
chr23 2982464 4080317 15 W scaffold_148 1 1097854 -
20+
chr23 4080318 4080417 16 U 100 scaffold yes map
21+
chr23 4080418 4781064 17 W scaffold_225 1 700647 ?
22+
chr23 4781065 4781164 18 U 100 scaffold yes map
23+
chr23 4781165 5760583 19 W scaffold_164 1 979419 -
24+
chr23 5760584 5760683 20 U 100 scaffold yes map
25+
chr23 5760684 6999179 21 W scaffold_129 1 1238496 +
26+
chr23 6999180 6999279 22 U 100 scaffold yes map
27+
chr23 6999280 9562302 23 W scaffold_43 1 2563023 -
28+
chr23 9562303 9562402 24 U 100 scaffold yes map
29+
chr23 9562403 11388199 25 W scaffold_80 1 1825797 -
30+
chr23 11388200 11388299 26 U 100 scaffold yes map
31+
chr23 11388300 12471757 27 W scaffold_150 1 1083458 -
32+
chr23 12471758 12471857 28 U 100 scaffold yes map
33+
chr23 12471858 12942229 29 W scaffold_331 1 470372 ?
34+
chr23 12942230 12942329 30 U 100 scaffold yes map
35+
chr23 12942330 13145841 31 W scaffold_642 1 203512 ?
36+
chr23 13145842 13145941 32 U 100 scaffold yes map
37+
chr23 13145942 13277112 33 W scaffold_829 1 131171 -
38+
chr23 13277113 13277212 34 U 100 scaffold yes map
39+
chr23 13277213 13540514 35 W scaffold_513 1 263302 -
40+
chr23 13540515 13540614 36 U 100 scaffold yes map
41+
chr23 13540615 13742295 37 W scaffold_648 1 201681 ?
42+
chr23 13742296 13742395 38 U 100 scaffold yes map
43+
chr23 13742396 14146998 39 W scaffold_382 1 404603 +
44+
chr23 14146999 14147098 40 U 100 scaffold yes map
45+
chr23 14147099 14246084 41 W scaffold_1006 1 98986 ?
46+
chr23 14246085 14246184 42 U 100 scaffold yes map
47+
chr23 14246185 15272643 43 W scaffold_158 1 1026459 ?
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
##agp-version 2.1
2+
# COMMENT: Generated by ALLMAPS 0.1.dev2+g2ce5bee02 (2026-07-05)
3+
# COMMAND: python -m jcvi.assembly.allmaps path /home/runner/work/jcvi/jcvi/tests/assembly/allmaps.py/inputs/JM-2.bed /home/runner/work/jcvi/jcvi/tests/assembly/allmaps.py/inputs/scaffolds.fasta.gz -w /home/runner/work/jcvi/jcvi/tests/assembly/allmaps.py/inputs/weights.txt
4+
# FIELDS: object, object_beg, object_end, part_number, component_type, component_id/gap_length, component_beg/gap_type, component_end/linkage, orientation/linkage_evidence
5+
chr23 1 137336 1 W scaffold_821 1 137336 ?
6+
chr23 137337 137436 2 U 100 scaffold yes map
7+
chr23 137437 284865 3 W scaffold_792 1 147429 ?
8+
chr23 284866 284965 4 U 100 scaffold yes map
9+
chr23 284966 412560 5 W scaffold_866 1 127595 ?
10+
chr23 412561 412660 6 U 100 scaffold yes map
11+
chr23 412661 484207 7 W scaffold_1189 1 71547 -
12+
chr23 484208 484307 8 U 100 scaffold yes map
13+
chr23 484308 891092 9 W scaffold_375 1 406785 -
14+
chr23 891093 891192 10 U 100 scaffold yes map
15+
chr23 891193 1393339 11 W scaffold_310 1 502147 -
16+
chr23 1393340 1393439 12 U 100 scaffold yes map
17+
chr23 1393440 2982363 13 W scaffold_95 1 1588924 ?
18+
chr23 2982364 2982463 14 U 100 scaffold yes map
19+
chr23 2982464 4080317 15 W scaffold_148 1 1097854 -
20+
chr23 4080318 4080417 16 U 100 scaffold yes map
21+
chr23 4080418 4781064 17 W scaffold_225 1 700647 ?
22+
chr23 4781065 4781164 18 U 100 scaffold yes map
23+
chr23 4781165 5760583 19 W scaffold_164 1 979419 -
24+
chr23 5760584 5760683 20 U 100 scaffold yes map
25+
chr23 5760684 6999179 21 W scaffold_129 1 1238496 +
26+
chr23 6999180 6999279 22 U 100 scaffold yes map
27+
chr23 6999280 9562302 23 W scaffold_43 1 2563023 -
28+
chr23 9562303 9562402 24 U 100 scaffold yes map
29+
chr23 9562403 11388199 25 W scaffold_80 1 1825797 -
30+
chr23 11388200 11388299 26 U 100 scaffold yes map
31+
chr23 11388300 12471757 27 W scaffold_150 1 1083458 -
32+
chr23 12471758 12471857 28 U 100 scaffold yes map
33+
chr23 12471858 12942229 29 W scaffold_331 1 470372 ?
34+
chr23 12942230 12942329 30 U 100 scaffold yes map
35+
chr23 12942330 13145841 31 W scaffold_642 1 203512 ?
36+
chr23 13145842 13145941 32 U 100 scaffold yes map
37+
chr23 13145942 13277112 33 W scaffold_829 1 131171 -
38+
chr23 13277113 13277212 34 U 100 scaffold yes map
39+
chr23 13277213 13540514 35 W scaffold_513 1 263302 -
40+
chr23 13540515 13540614 36 U 100 scaffold yes map
41+
chr23 13540615 13742295 37 W scaffold_648 1 201681 ?
42+
chr23 13742296 13742395 38 U 100 scaffold yes map
43+
chr23 13742396 14146998 39 W scaffold_382 1 404603 +
44+
chr23 14146999 14147098 40 U 100 scaffold yes map
45+
chr23 14147099 14246084 41 W scaffold_1006 1 98986 ?
46+
chr23 14246085 14246184 42 U 100 scaffold yes map
47+
chr23 14246185 15272643 43 W scaffold_158 1 1026459 ?

0 commit comments

Comments
 (0)