29
29
import os
30
30
import tempfile
31
31
import textwrap
32
+ import warnings
32
33
33
34
import msprime
34
35
import numpy as np
@@ -335,12 +336,13 @@ class TestInterface:
335
336
def test_bad_ploidy (self ):
336
337
ts = msprime .simulate (10 , mutation_rate = 0.1 , random_seed = 2 )
337
338
for bad_ploidy in [- 1 , 0 ]:
338
- with pytest .raises (ValueError , match = "Ploidy must be >= 1 " ):
339
+ with pytest .raises (ValueError , match = "Ploidy must be a positive integer " ):
339
340
ts .write_vcf (io .StringIO , bad_ploidy )
340
341
# Non divisible
341
342
for bad_ploidy in [3 , 7 ]:
342
343
with pytest .raises (
343
- ValueError , match = "Sample size must be divisible by ploidy"
344
+ ValueError ,
345
+ match = "Number of sample nodes 10 is not a multiple of ploidy" ,
344
346
):
345
347
ts .write_vcf (io .StringIO , bad_ploidy )
346
348
@@ -349,17 +351,32 @@ def test_individuals_no_nodes_default_args(self):
349
351
tables = ts1 .dump_tables ()
350
352
tables .individuals .add_row ()
351
353
ts2 = tables .tree_sequence ()
352
- assert ts1 .as_vcf (allow_position_zero = True ) == ts2 .as_vcf (
353
- allow_position_zero = True
354
- )
354
+ # ts1 should work as it has no individuals
355
+ ts1 .as_vcf (allow_position_zero = True )
356
+ # ts2 should fail as it has individuals but no nodes
357
+ with warnings .catch_warnings (record = True ) as w :
358
+ with pytest .raises (ValueError , match = "No samples in resulting VCF model" ):
359
+ ts2 .as_vcf (allow_position_zero = True )
360
+ assert len (w ) == 2
361
+ assert "At least one sample node does not have an individual ID" in str (
362
+ w [0 ].message
363
+ )
364
+ assert "Individual 0 has no nodes associated with it." in str (w [1 ].message )
355
365
356
366
def test_individuals_no_nodes_as_argument (self ):
357
367
ts1 = msprime .simulate (10 , mutation_rate = 0.1 , random_seed = 2 )
358
368
tables = ts1 .dump_tables ()
359
369
tables .individuals .add_row ()
360
370
ts2 = tables .tree_sequence ()
361
- with pytest .raises (ValueError , match = "0 not associated with a node" ):
362
- ts2 .as_vcf (individuals = [0 ])
371
+ with warnings .catch_warnings (record = True ) as w :
372
+ with pytest .raises (
373
+ ValueError , match = "Individual 0 has no nodes associated with it."
374
+ ):
375
+ ts2 .as_vcf (individuals = [0 ])
376
+ assert len (w ) == 1
377
+ assert "At least one sample node does not have an individual ID" in str (
378
+ w [0 ].message
379
+ )
363
380
364
381
def test_ploidy_with_sample_individuals (self ):
365
382
ts = msprime .sim_ancestry (3 , random_seed = 2 )
@@ -378,7 +395,7 @@ def test_ploidy_with_no_node_individuals(self):
378
395
def test_empty_individuals (self ):
379
396
ts = msprime .sim_ancestry (3 , random_seed = 2 )
380
397
ts = tsutil .insert_branch_sites (ts )
381
- with pytest .raises (ValueError , match = "List of sample individuals empty " ):
398
+ with pytest .raises (ValueError , match = "No samples in resulting VCF model " ):
382
399
ts .as_vcf (individuals = [])
383
400
384
401
def test_duplicate_individuals (self ):
@@ -397,12 +414,17 @@ def test_mixed_sample_non_sample_individuals(self):
397
414
tables .nodes .individual = individual
398
415
ts = tables .tree_sequence ()
399
416
ts = tsutil .insert_branch_sites (ts )
400
- with pytest .raises (
401
- ValueError , match = "0 has nodes that are sample and non-sample"
402
- ):
403
- ts .as_vcf ()
404
- # but it's OK if we run without the affected individual
405
- assert len (ts .as_vcf (individuals = [1 , 2 ], allow_position_zero = True )) > 0
417
+ with warnings .catch_warnings (record = True ) as w :
418
+ ts .map_to_vcf_model ()
419
+ assert len (w ) == 2
420
+ assert (
421
+ "Individual 0 has both sample and non-sample nodes associated with it."
422
+ in str (w [0 ].message )
423
+ )
424
+ assert "Individual 3 has no nodes associated with it." in str (w [1 ].message )
425
+ with warnings .catch_warnings (record = True ) as w :
426
+ assert len (ts .as_vcf (individuals = [1 , 2 ], allow_position_zero = True )) > 0
427
+ assert len (w ) == 0
406
428
407
429
def test_samples_with_and_without_individuals (self ):
408
430
ts = tskit .Tree .generate_balanced (3 ).tree_sequence
@@ -414,19 +436,19 @@ def test_samples_with_and_without_individuals(self):
414
436
tables .nodes .individual = individual
415
437
ts = tables .tree_sequence ()
416
438
ts = tsutil .insert_branch_sites (ts )
417
- with pytest . raises (
418
- ValueError , match = "Sample nodes must either all be associated"
419
- ):
420
- ts . as_vcf ()
421
- # But it's OK if explicitly specify that sample
422
- assert len ( ts . as_vcf ( individuals = [ 0 ], allow_position_zero = True )) > 0
439
+ with warnings . catch_warnings ( record = True ) as w :
440
+ ts . as_vcf ( allow_position_zero = True )
441
+ assert len ( w ) == 1
442
+ assert "At least one sample node does not have an individual ID" in str (
443
+ w [ 0 ]. message
444
+ )
423
445
424
446
def test_bad_individuals (self ):
425
447
ts = msprime .simulate (10 , mutation_rate = 0.1 , random_seed = 2 )
426
448
ts = tsutil .insert_individuals (ts , ploidy = 2 )
427
- with pytest .raises (ValueError , match = "Invalid individual IDs provided. " ):
449
+ with pytest .raises (ValueError , match = "Invalid individual ID " ):
428
450
ts .write_vcf (io .StringIO (), individuals = [0 , - 1 ])
429
- with pytest .raises (ValueError , match = "Invalid individual IDs provided. " ):
451
+ with pytest .raises (ValueError , match = "Invalid individual ID " ):
430
452
ts .write_vcf (io .StringIO (), individuals = [1 , 2 , ts .num_individuals ])
431
453
432
454
def test_ploidy_positional (self ):
@@ -527,20 +549,17 @@ def test_bad_length_individuals(self):
527
549
ts = tsutil .insert_individuals (ts , ploidy = 2 )
528
550
with pytest .raises (
529
551
ValueError ,
530
- match = "individual_names must have length equal to"
531
- " the number of individuals" ,
552
+ match = "The number of individuals does not match the number of names" ,
532
553
):
533
554
ts .write_vcf (io .StringIO (), individual_names = [])
534
555
with pytest .raises (
535
556
ValueError ,
536
- match = "individual_names must have length equal to"
537
- " the number of individuals" ,
557
+ match = "The number of individuals does not match the number of names" ,
538
558
):
539
559
ts .write_vcf (io .StringIO (), individual_names = ["x" for _ in range (4 )])
540
560
with pytest .raises (
541
561
ValueError ,
542
- match = "individual_names must have length equal to"
543
- " the number of individuals" ,
562
+ match = "The number of individuals does not match the number of names" ,
544
563
):
545
564
ts .write_vcf (
546
565
io .StringIO (),
@@ -549,8 +568,7 @@ def test_bad_length_individuals(self):
549
568
)
550
569
with pytest .raises (
551
570
ValueError ,
552
- match = "individual_names must have length equal to"
553
- " the number of individuals" ,
571
+ match = "The number of individuals does not match the number of names" ,
554
572
):
555
573
ts .write_vcf (
556
574
io .StringIO (),
@@ -563,14 +581,12 @@ def test_bad_length_ploidy(self):
563
581
assert ts .num_sites > 0
564
582
with pytest .raises (
565
583
ValueError ,
566
- match = "individual_names must have length equal to"
567
- " the number of individuals" ,
584
+ match = "The number of individuals does not match the number of names" ,
568
585
):
569
586
ts .write_vcf (io .StringIO (), ploidy = 2 , individual_names = [])
570
587
with pytest .raises (
571
588
ValueError ,
572
- match = "individual_names must have length equal to"
573
- " the number of individuals" ,
589
+ match = "The number of individuals does not match the number of names" ,
574
590
):
575
591
ts .write_vcf (
576
592
io .StringIO (), ploidy = 2 , individual_names = ["x" for _ in range (4 )]
@@ -907,7 +923,7 @@ def test_no_individuals_ploidy_3_names(self):
907
923
expected = textwrap .dedent (s )
908
924
assert (
909
925
drop_header (
910
- ts .as_vcf (ploidy = 3 , individual_names = "A" , allow_position_zero = True )
926
+ ts .as_vcf (ploidy = 3 , individual_names = [ "A" ] , allow_position_zero = True )
911
927
)
912
928
== expected
913
929
)
@@ -940,7 +956,7 @@ def test_individual_0(self):
940
956
def test_individual_1 (self ):
941
957
ts = self .ts ()
942
958
s = """\
943
- #CHROM\t POS\t ID\t REF\t ALT\t QUAL\t FILTER\t INFO\t FORMAT\t tsk_0
959
+ #CHROM\t POS\t ID\t REF\t ALT\t QUAL\t FILTER\t INFO\t FORMAT\t tsk_1
944
960
1\t 0\t 0\t 0\t 1\t .\t PASS\t .\t GT\t 0
945
961
1\t 2\t 1\t 0\t 1\t .\t PASS\t .\t GT\t 1
946
962
1\t 4\t 2\t 0\t 1\t .\t PASS\t .\t GT\t 1
@@ -954,7 +970,7 @@ def test_individual_1(self):
954
970
def test_reversed (self ):
955
971
ts = self .ts ()
956
972
s = """\
957
- #CHROM\t POS\t ID\t REF\t ALT\t QUAL\t FILTER\t INFO\t FORMAT\t tsk_0 \ t tsk_1
973
+ #CHROM\t POS\t ID\t REF\t ALT\t QUAL\t FILTER\t INFO\t FORMAT\t tsk_1\t tsk_0
958
974
1\t 0\t 0\t 0\t 1\t .\t PASS\t .\t GT\t 0\t 1|0
959
975
1\t 2\t 1\t 0\t 1\t .\t PASS\t .\t GT\t 1\t 0|1
960
976
1\t 4\t 2\t 0\t 1\t .\t PASS\t .\t GT\t 1\t 0|0
0 commit comments