1
1
import unittest
2
2
import os
3
- import re
4
3
from poplars .common import convert_fasta
5
- from poplars .hypermut import make_results
6
- from poplars .hypermut import hypermut
7
- from poplars .hypermut import rate_ratio
8
- from poplars .hypermut import make_data_file
4
+ from poplars .hypermut import *
9
5
10
- TEST_HIV = os .path .join (os .path .dirname (__file__ ), 'fixtures/hiv-test-genome.fasta' )
11
- TEST_DATA = os .path .join (os .path .dirname (__file__ ), 'fixtures/aligned_HIV1_Mgroup.fasta' )
12
6
7
+ class HIVTestCase (unittest .TestCase ):
13
8
14
- class TestMakeResults (unittest .TestCase ):
15
9
def setUp (self ):
16
- self .hiv_data = open (TEST_HIV )
17
- self .data = open (TEST_DATA )
18
-
19
- def testDSMotifs (self ):
20
- mut = re .compile ('[AGCT](?=[AG][AGT])' ) # Matches potential mutation sites (GRD)
21
- s = convert_fasta (self .hiv_data )[0 ][1 ]
22
- result = [match .start () for match in mut .finditer (s )]
23
- expected = [0 , 1 , 2 , 3 , 4 , 5 , 9 , 10 , 20 , 23 , 24 , 25 , 26 , 29 , 30 , 31 , 32 , 34 , 40 , 41 , 45 , 47 , 48 , 49 , 62 ,
24
- 63 , 64 , 76 , 77 , 80 , 83 , 84 , 85 , 96 , 97 , 98 , 102 , 103 , 104 , 105 , 106 , 109 , 110 , 111 , 113 , 120 ,
25
- 127 , 128 , 129 , 131 , 132 , 139 , 140 , 144 , 145 , 150 , 151 , 154 , 155 , 159 , 160 , 161 , 162 , 163 , 164 ,
26
- 165 , 168 , 169 , 170 , 171 , 172 , 173 , 174 , 178 , 181 , 182 , 183 , 184 , 185 , 186 , 187 , 188 , 189 , 190 ,
27
- 196 , 201 , 211 , 213 , 214 , 221 , 223 , 224 , 225 , 226 , 228 , 229 , 230 , 232 , 237 , 238 , 239 , 240 , 241 ,
28
- 242 , 243 , 244 , 245 , 246 , 247 , 249 , 252 , 253 , 254 , 255 , 257 , 258 , 259 , 260 , 261 , 265 , 268 , 276 ,
29
- 279 , 284 , 289 , 291 , 296 , 297 , 298 , 299 , 305 , 309 , 310 , 311 , 312 , 319 , 320 , 321 , 322 , 329 , 332 ,
30
- 335 , 336 , 346 , 347 ]
31
- self .assertEqual (expected , result )
32
-
33
- def testCtrlMotifs (self ):
34
- ctrl = re .compile ('[AGCT](?=[CT].|[AG]C)' )
35
- s = convert_fasta (self .hiv_data )[0 ][1 ]
36
- result = [match .start () for match in ctrl .finditer (s )]
37
- expected = [6 , 7 , 8 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 21 , 22 , 27 , 28 , 33 , 35 , 36 , 37 , 38 , 39 , 42 , 43 ,
38
- 44 , 46 , 50 , 51 , 52 , 53 , 54 , 55 , 56 , 57 , 58 , 59 , 60 , 61 , 65 , 66 , 67 , 68 , 69 , 70 , 71 , 72 , 73 ,
39
- 74 , 75 , 78 , 79 , 81 , 82 , 86 , 87 , 88 , 89 , 90 , 91 , 92 , 93 , 94 , 95 , 99 , 100 , 101 , 107 , 108 , 112 ,
40
- 114 , 115 , 116 , 117 , 118 , 119 , 121 , 122 , 123 , 124 , 125 , 126 , 130 , 133 , 134 , 135 , 136 , 137 , 138 ,
41
- 141 , 142 , 143 , 146 , 147 , 148 , 149 , 152 , 153 , 156 , 157 , 158 , 166 , 167 , 175 , 176 , 177 , 179 , 180 ,
42
- 191 , 192 , 193 , 194 , 195 , 197 , 198 , 199 , 200 , 202 , 203 , 204 , 205 , 206 , 207 , 208 , 209 , 210 , 212 ,
43
- 215 , 216 , 217 , 218 , 219 , 220 , 222 , 227 , 231 , 233 , 234 , 235 , 236 , 248 , 250 , 251 , 256 , 262 , 263 ,
44
- 264 , 266 , 267 , 269 , 270 , 271 , 272 , 273 , 274 , 275 , 277 , 278 , 280 , 281 , 282 , 283 , 285 , 286 , 287 ,
45
- 288 , 290 , 292 , 293 , 294 , 295 , 300 , 301 , 302 , 303 , 304 , 306 , 307 , 308 , 313 , 314 , 315 , 316 , 317 ,
46
- 318 , 323 , 324 , 325 , 326 , 327 , 328 , 330 , 331 , 333 , 334 , 337 , 338 , 339 , 340 , 341 , 342 , 343 , 344 , 345 ]
47
- self .assertEqual (expected , result )
48
-
49
- def test_alignmentA1 (self ):
50
- fasta = convert_fasta (self .data )
51
- refseq = fasta [0 ][1 ]
52
- gees = [i for i , nt in enumerate (refseq ) if nt .upper () == 'G' ]
53
- seq = fasta [1 ]
54
- output = make_results (seq , gees )
55
-
56
- ex_num_muts = 47
57
- self .assertEqual (ex_num_muts , output .num_muts )
58
-
59
- ex_pot_muts = 1068
60
- self .assertEqual (ex_pot_muts , output .pot_muts )
61
-
62
- ex_ctrl_muts = 53
63
- self .assertEqual (ex_ctrl_muts , output .ctrl_muts )
64
-
65
- ex_pot_ctrl_muts = 986
66
- self .assertEqual (ex_pot_ctrl_muts , output .potential_ctrls )
67
-
68
- ex_rate_ratio = 0.82
69
- self .assertEqual (ex_rate_ratio , round (output .rate_ratio , 2 ))
70
-
71
- ex_p_value = 0.870295
72
- self .assertEqual (ex_p_value , output .p_value )
73
10
74
- ex_ctable = [[47 , 1068 ], [53 , 986 ]]
75
- self .assertEqual (ex_ctable , output .ctable )
76
-
77
- # ex_mut_sites = None
78
- # ex_ctrl_sites = None
79
-
80
- def tearDown (self ):
81
- self .hiv_data .close ()
82
- self .data .close ()
83
-
84
-
85
- class TestHypermut (unittest .TestCase ):
86
-
87
- def setUp (self ):
88
- self .hiv_data = open (TEST_HIV )
89
-
90
- def testGees (self ):
91
- fasta = convert_fasta (self .hiv_data )
92
- refseq = fasta [0 ][1 ] # Reference sequence is the first entry
93
- result = [i for i , nt in enumerate (refseq ) if nt .upper () == 'G' ]
94
- expected = [1 , 2 , 5 , 6 , 7 , 24 , 27 , 32 , 41 , 46 , 48 , 49 , 65 , 66 , 77 , 82 , 85 , 98 , 99 , 100 , 104 , 105 , 106 , 111 ,
95
- 121 , 128 , 129 , 132 , 133 , 135 , 142 , 146 , 152 , 155 , 157 , 161 , 163 , 166 , 170 , 173 , 176 , 185 , 186 ,
96
- 188 , 190 , 198 , 202 , 212 , 214 , 216 , 220 , 224 , 225 , 229 , 230 , 233 , 238 , 239 , 241 , 243 , 245 , 248 ,
97
- 250 , 254 , 256 , 258 , 259 , 261 , 262 , 266 , 270 , 273 , 278 , 292 , 293 , 297 , 299 , 301 , 304 , 310 , 311 ,
98
- 313 , 322 , 327 , 330 , 336 , 338 , 342 , 349 ]
99
- self .assertEqual (expected , result )
100
-
101
- def tearDown (self ):
102
- self .hiv_data .close ()
11
+ genome_path = os .path .join (os .path .dirname (__file__ ), 'fixtures/hiv-test-genome.fasta' )
12
+ infile_path = os .path .join (os .path .dirname (__file__ ), 'fixtures/aligned_HIV1_Mgroup.fasta' )
13
+ test_data = os .path .join (os .path .dirname (__file__ ), 'fixtures/hypermut-test.fasta' )
14
+
15
+ with open (genome_path ) as handle , open (infile_path ) as in_handle , open (test_data ) as test_handle :
16
+ self .hiv_genome = handle .read ()
17
+ self .hiv_data = in_handle .read ()
18
+ self .simple_data = convert_fasta (test_handle .read ().split ())
19
+
20
+ self .mut = re .compile ('[AGCT](?=[AG][AGT])' ) # Matches potential mutation sites (RD)
21
+ self .ctrl = re .compile ('[AGCT](?=[CT].|[AG]C)' ) # Matches potential control sites (YN or RC)
22
+
23
+
24
+ class Hypermut (HIVTestCase ):
25
+
26
+ maxDiff = None
27
+
28
+ def testSimpleData (self ):
29
+
30
+ # Test potential mutation sites
31
+ test_matches = ['GAA' , 'GAG' , 'GAT' , 'GGA' , 'GGG' , 'GGT' , 'CGAA' ]
32
+ for s in test_matches :
33
+ self .assertTrue (self .mut .match (s ))
34
+ test_mismatches = ['CTC' , 'GTC' , 'GGCGC' ]
35
+ for s in test_mismatches :
36
+ self .assertFalse (self .mut .match (s ))
37
+
38
+ # Test potential control sites
39
+ test_matches = ['TAC' , 'CCC' , 'CAC' , 'TTGC' ]
40
+ for s in test_matches :
41
+ self .assertTrue (self .ctrl .match (s ))
42
+ test_mismatches = ['TAT' , 'CGGC' , 'CAA' ]
43
+ for s in test_mismatches :
44
+ self .assertFalse (self .ctrl .match (s ))
45
+
46
+ # Test gees
47
+ refseq = self .simple_data [0 ][1 ] # Reference sequence is the first entry
48
+ res_gees = [i for i , nt in enumerate (refseq ) if nt .upper () == 'G' ]
49
+ exp_gees = [5 , 8 , 15 , 16 , 19 , 24 , 27 , 30 , 33 , 35 , 36 , 39 , 46 , 51 , 62 , 69 , 84 , 89 , 92 , 96 , 102 , 111 ,
50
+ 115 , 121 , 139 , 145 , 156 , 157 , 162 , 163 , 164 , 166 , 168 , 183 , 184 , 186 , 195 , 196 , 198 , 205 ,
51
+ 210 , 217 , 226 , 230 , 234 , 238 , 239 , 246 , 257 , 261 , 274 , 289 , 297 , 307 , 315 , 316 , 318 , 319 ,
52
+ 320 , 321 , 327 , 333 , 338 , 343 , 352 , 354 , 355 , 357 , 358 , 359 , 360 , 373 , 389 , 397 , 403 , 404 ,
53
+ 408 , 415 , 421 , 422 , 426 , 432 , 435 , 436 , 437 , 450 , 453 , 454 , 472 , 475 , 497 , 499 , 500 , 503 ,
54
+ 504 , 507 , 510 , 511 , 516 , 521 , 525 , 538 , 540 , 541 , 550 , 553 , 570 , 571 , 572 , 586 , 588 , 591 ,
55
+ 592 , 594 , 595 , 606 , 607 , 608 , 612 , 615 , 616 , 627 , 628 , 629 , 633 , 643 ]
56
+ self .assertEqual (exp_gees , res_gees )
57
+
58
+ query_seq = self .simple_data [1 :]
59
+
60
+ outputs = []
61
+ for seq in query_seq :
62
+ outputs .append (make_results (seq , res_gees ))
63
+
64
+ for i in range (len (outputs )):
65
+ ex_num_muts = [0 , 4 , 26 , 48 ]
66
+ self .assertEqual (ex_num_muts [i ], outputs [i ].num_muts ) # Test match sites
67
+
68
+ ex_pot_muts = [71 , 69 , 71 , 71 ]
69
+ self .assertEqual (ex_pot_muts [i ], outputs [i ].pot_muts ) # Test potential mutation sites
70
+
71
+ ex_ctrl_muts = [0 , 1 , 1 , 9 ]
72
+ self .assertEqual (ex_ctrl_muts [i ], outputs [i ].ctrl_muts ) # Test control mutations
73
+
74
+ ex_pot_ctrl_muts = [54 , 52 , 54 , 54 ]
75
+ self .assertEqual (ex_pot_ctrl_muts [i ], outputs [i ].potential_ctrls ) # Test potential controls
76
+
77
+ ex_rate_ratio = ['undef' , 3.01 , 19.77 , 4.06 ]
78
+ if type (ex_rate_ratio ) == str :
79
+ self .assertEqual (ex_rate_ratio [i ], outputs [i ].rate_ratio ) # Test rate ratio
80
+ else :
81
+ self .assertAlmostEqual (ex_rate_ratio [i ], outputs [i ].rate_ratio , places = 2 )
82
+
83
+ ex_p_value = [1 , 0.282669 , 5.35061e-07 , 8.26961e-09 ]
84
+ self .assertAlmostEqual (ex_p_value [i ], outputs [i ].p_value , places = 2 ) # Test p-value
85
+
86
+ ex_ctable = [[[0 , 71 ], [0 , 54 ]], # Seq2
87
+
88
+ [[4 , 65 ], [1 , 51 ]], # Seq5
89
+
90
+ [[26 , 45 ], [1 , 53 ]], # Seq7
91
+
92
+ [[48 , 23 ], [9 , 45 ]]] # Seq14
93
+ self .assertEqual (ex_ctable [i ], outputs [i ].ctable ) # Test contingency table
94
+
95
+ # Test mutation sites
96
+ ex_mut_sites = [{28 : 0 , 31 : 0 , 34 : 0 , 36 : 0 , 47 : 0 , 52 : 0 , 63 : 0 , 93 : 0 , 97 : 0 , 112 : 0 , 140 : 0 , 157 : 0 ,
97
+ 163 : 0 , 164 : 0 , 165 : 0 , 167 : 0 , 184 : 0 , 185 : 0 , 187 : 0 , 196 : 0 , 197 : 0 , 199 : 0 , 231 : 0 ,
98
+ 235 : 0 , 239 : 0 , 240 : 0 , 258 : 0 , 290 : 0 , 308 : 0 , 316 : 0 , 317 : 0 , 319 : 0 , 320 : 0 , 321 : 0 ,
99
+ 328 : 0 , 355 : 0 , 356 : 0 , 358 : 0 , 359 : 0 , 360 : 0 , 361 : 0 , 404 : 0 , 405 : 0 , 422 : 0 , 423 : 0 ,
100
+ 433 : 0 , 436 : 0 , 437 : 0 , 451 : 0 , 454 : 0 , 455 : 0 , 476 : 0 , 504 : 0 , 505 : 0 , 511 : 0 , 512 : 0 ,
101
+ 539 : 0 , 541 : 0 , 551 : 0 , 571 : 0 , 587 : 0 , 589 : 0 , 592 : 0 , 595 : 0 , 607 : 0 , 608 : 0 , 613 : 0 ,
102
+ 616 : 0 , 628 : 0 , 629 : 0 , 634 : 0 },
103
+
104
+ {28 : 0 , 31 : 0 , 34 : 0 , 36 : 0 , 47 : 0 , 52 : 0 , 63 : 0 , 93 : 0 , 97 : 0 , 112 : 0 , 140 : 0 , 157 : 0 ,
105
+ 163 : 0 , 164 : 0 , 165 : 0 , 167 : 0 , 184 : 0 , 185 : 0 , 187 : 0 , 196 : 0 , 197 : 0 , 199 : 1 , 231 : 0 ,
106
+ 235 : 0 , 239 : 0 , 240 : 0 , 258 : 0 , 290 : 1 , 316 : 0 , 317 : 0 , 319 : 0 , 320 : 0 , 321 : 0 , 328 : 0 ,
107
+ 355 : 0 , 356 : 0 , 358 : 0 , 359 : 0 , 360 : 0 , 361 : 0 , 422 : 0 , 423 : 0 , 427 : 0 , 433 : 0 , 436 : 0 ,
108
+ 437 : 0 , 451 : 0 , 454 : 0 , 455 : 0 , 476 : 0 , 504 : 0 , 505 : 0 , 511 : 0 , 512 : 0 , 539 : 0 , 541 : 0 ,
109
+ 551 : 0 , 571 : 0 , 587 : 0 , 589 : 0 , 592 : 0 , 595 : 0 , 607 : 1 , 608 : 0 , 613 : 0 , 616 : 0 , 628 : 1 ,
110
+ 629 : 0 , 634 : 0 },
111
+
112
+ {28 : 0 , 31 : 0 , 34 : 0 , 36 : 1 , 47 : 0 , 52 : 1 , 63 : 0 , 93 : 1 , 97 : 0 , 112 : 1 , 140 : 0 , 157 : 1 ,
113
+ 163 : 0 , 164 : 1 , 165 : 0 , 167 : 0 , 184 : 0 , 185 : 0 , 187 : 0 , 196 : 1 , 197 : 0 , 199 : 0 , 231 : 0 ,
114
+ 235 : 0 , 239 : 1 , 240 : 1 , 258 : 0 , 290 : 0 , 308 : 0 , 316 : 0 , 317 : 0 , 319 : 1 , 320 : 1 , 321 : 0 ,
115
+ 328 : 0 , 355 : 1 , 356 : 0 , 358 : 0 , 359 : 1 , 360 : 1 , 361 : 0 , 404 : 1 , 405 : 1 , 422 : 1 , 423 : 0 ,
116
+ 433 : 0 , 436 : 1 , 437 : 0 , 451 : 0 , 454 : 0 , 455 : 0 , 476 : 0 , 504 : 1 , 505 : 0 , 511 : 1 , 512 : 0 ,
117
+ 539 : 0 , 541 : 0 , 551 : 0 , 571 : 1 , 587 : 0 , 589 : 0 , 592 : 0 , 595 : 1 , 607 : 1 , 608 : 1 , 613 : 0 ,
118
+ 616 : 1 , 628 : 1 , 629 : 0 , 634 : 0 },
119
+
120
+ {28 : 0 , 31 : 0 , 34 : 1 , 36 : 0 , 47 : 1 , 52 : 1 , 63 : 1 , 93 : 1 , 97 : 1 , 112 : 1 , 140 : 1 , 157 : 0 ,
121
+ 163 : 1 , 164 : 0 , 165 : 0 , 167 : 1 , 184 : 0 , 185 : 1 , 187 : 1 , 196 : 0 , 197 : 0 , 199 : 1 , 231 : 1 ,
122
+ 235 : 1 , 239 : 1 , 240 : 1 , 258 : 0 , 290 : 0 , 308 : 1 , 316 : 0 , 317 : 1 , 319 : 1 , 320 : 0 , 321 : 1 ,
123
+ 328 : 0 , 355 : 1 , 356 : 1 , 358 : 0 , 359 : 0 , 360 : 0 , 361 : 0 , 404 : 1 , 405 : 1 , 422 : 1 , 423 : 1 ,
124
+ 433 : 1 , 436 : 1 , 437 : 1 , 451 : 1 , 454 : 1 , 455 : 1 , 476 : 1 , 504 : 1 , 505 : 1 , 511 : 0 , 512 : 1 ,
125
+ 539 : 1 , 541 : 1 , 551 : 1 , 571 : 0 , 587 : 1 , 589 : 1 , 592 : 1 , 595 : 1 , 607 : 0 , 608 : 1 , 613 : 1 ,
126
+ 616 : 1 , 628 : 1 , 629 : 0 , 634 : 0 }]
127
+
128
+ self .assertEqual (ex_mut_sites [i ], outputs [i ].mut_sites )
129
+
130
+ # Test control sites
131
+ ex_ctrl_sites = [{6 : 0 , 9 : 0 , 16 : 0 , 17 : 0 , 20 : 0 , 25 : 0 , 37 : 0 , 40 : 0 , 70 : 0 , 85 : 0 , 90 : 0 , 103 : 0 ,
132
+ 116 : 0 , 122 : 0 , 146 : 0 , 158 : 0 , 169 : 0 , 206 : 0 , 211 : 0 , 218 : 0 , 227 : 0 , 247 : 0 , 262 : 0 ,
133
+ 275 : 0 , 298 : 0 , 322 : 0 , 334 : 0 , 339 : 0 , 344 : 0 , 353 : 0 , 374 : 0 , 390 : 0 , 398 : 0 , 409 : 0 ,
134
+ 416 : 0 , 427 : 0 , 438 : 0 , 473 : 0 , 498 : 0 , 500 : 0 , 501 : 0 , 508 : 0 , 517 : 0 , 522 : 0 , 526 : 0 ,
135
+ 542 : 0 , 554 : 0 , 572 : 0 , 573 : 0 , 593 : 0 , 596 : 0 , 609 : 0 , 617 : 0 , 630 : 0 },
136
+
137
+ {6 : 0 , 9 : 0 , 16 : 0 , 17 : 0 , 20 : 0 , 25 : 0 , 37 : 0 , 40 : 0 , 70 : 0 , 85 : 0 , 90 : 0 , 103 : 0 ,
138
+ 116 : 0 , 122 : 0 , 146 : 0 , 158 : 0 , 169 : 0 , 206 : 0 , 211 : 0 , 218 : 0 , 227 : 0 , 247 : 0 , 262 : 0 ,
139
+ 275 : 0 , 298 : 0 , 308 : 1 , 322 : 0 , 334 : 0 , 339 : 0 , 344 : 0 , 353 : 0 , 374 : 0 , 390 : 0 , 416 : 0 ,
140
+ 438 : 0 , 473 : 0 , 498 : 0 , 500 : 0 , 501 : 0 , 508 : 0 , 517 : 0 , 522 : 0 , 526 : 0 , 542 : 0 , 554 : 0 ,
141
+ 572 : 0 , 573 : 0 , 593 : 0 , 596 : 0 , 609 : 0 , 617 : 0 , 630 : 0 },
142
+
143
+ {6 : 0 , 9 : 0 , 16 : 0 , 17 : 0 , 20 : 0 , 25 : 0 , 37 : 0 , 40 : 0 , 70 : 0 , 85 : 0 , 90 : 0 , 103 : 0 ,
144
+ 116 : 0 , 122 : 0 , 146 : 0 , 158 : 0 , 169 : 0 , 206 : 0 , 211 : 0 , 218 : 0 , 227 : 0 , 247 : 0 , 262 : 0 ,
145
+ 275 : 0 , 298 : 0 , 322 : 0 , 334 : 0 , 339 : 0 , 344 : 0 , 353 : 0 , 374 : 0 , 390 : 0 , 398 : 0 , 409 : 0 ,
146
+ 416 : 0 , 427 : 0 , 438 : 0 , 473 : 0 , 498 : 0 , 500 : 0 , 501 : 0 , 508 : 0 , 517 : 0 , 522 : 0 , 526 : 0 ,
147
+ 542 : 0 , 554 : 0 , 572 : 0 , 573 : 0 , 593 : 0 , 596 : 1 , 609 : 0 , 617 : 0 , 630 : 0 },
148
+
149
+ {6 : 0 , 9 : 0 , 16 : 0 , 17 : 0 , 20 : 0 , 25 : 0 , 37 : 0 , 40 : 0 , 70 : 0 , 85 : 0 , 90 : 0 , 103 : 0 ,
150
+ 116 : 0 , 122 : 1 , 146 : 0 , 158 : 1 , 169 : 0 , 206 : 1 , 211 : 0 , 218 : 0 , 227 : 0 , 247 : 0 , 262 : 0 ,
151
+ 275 : 1 , 298 : 0 , 322 : 1 , 334 : 0 , 339 : 0 , 344 : 0 , 353 : 0 , 374 : 0 , 390 : 0 , 398 : 0 , 409 : 0 ,
152
+ 416 : 0 , 427 : 0 , 438 : 0 , 473 : 0 , 498 : 0 , 500 : 0 , 501 : 0 , 508 : 0 , 517 : 0 , 522 : 0 , 526 : 1 ,
153
+ 542 : 1 , 554 : 0 , 572 : 0 , 573 : 0 , 593 : 0 , 596 : 0 , 609 : 1 , 617 : 0 , 630 : 1 }]
154
+ self .assertEqual (ex_ctrl_sites [i ], outputs [i ].ctrl_sites )
103
155
104
156
105
157
class TestRateRatio (unittest .TestCase ):
158
+
106
159
def testRateRatio (self ):
107
160
ctable = [[4 , 17 ], [7 , 33 ]]
108
161
expected = 1.1
@@ -123,3 +176,5 @@ def test2UndefinedRateRatio(self):
123
176
self .assertEqual (expected , result )
124
177
125
178
179
+ if __name__ == '__main__' :
180
+ unittest .main ()
0 commit comments