File: typechecking_test.py

package info (click to toggle)
python-pysam 0.23.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 18,468 kB
  • sloc: ansic: 158,936; python: 8,604; sh: 338; makefile: 264; perl: 41
file content (135 lines) | stat: -rw-r--r-- 3,662 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import inspect
import os
import pytest
import re
from typing import TYPE_CHECKING

import pysam
import pysam.samtools
import pysam.bcftools

from TestUtils import BAM_DATADIR, make_data_files

try:
    import mypy.api
except ImportError:
    pytest.skip('mypy API not available', allow_module_level=True)

PREAMBLE = """
import re
from typing import TYPE_CHECKING

import pysam
import pysam.samtools
import pysam.bcftools

def typecheck(check_locals = True): pass
"""

MYPY_OPTIONS = ['--no-incremental', '--no-error-summary', '--follow-imports', 'silent']


def typecheck(check_locals: bool = True):
    myframe = inspect.currentframe()
    if not myframe: pytest.skip('current stack frame not available')
    caller = myframe.f_back
    if not caller: pytest.skip('caller stack frame not available')

    code = inspect.getsource(caller)
    stdout, stderr, status = mypy.api.run(MYPY_OPTIONS + ['--command', PREAMBLE + code])
    assert status == 0, f'mypy failed:\n{stdout}{stderr}'

    types = {}
    for line in stdout.splitlines():
        m = re.search(r'note:   *(\w+): ([\w.]*)', line)
        if m: types[m.group(1)] = m.group(2)

    def _plain(s):
        s = re.sub(r"<class '([^']*)'>", r'\1', s)
        s = re.sub(r'builtins\.', '', s)
        return s

    if check_locals:
        for var, vartype in types.items():
            assert _plain(vartype) == _plain(repr(type(caller.f_locals[var]))), f'Incorrect type for {var!r}'

    return types


def setUpModule():
    make_data_files(BAM_DATADIR)


@pytest.fixture
def aln():
    header = pysam.AlignmentHeader.from_references(['chr1', 'chr2'], [50000, 20000])
    a = pysam.AlignedSegment(header)
    a.query_name = 'read_one'
    a.flag = pysam.FPAIRED | pysam.FREAD1
    a.reference_id = 0
    a.reference_start = 1000
    a.mapping_quality = 20
    a.next_reference_id = 1
    a.next_reference_start = 5000
    a.template_length = 0
    a.cigartuples = ((pysam.CMATCH, 6), (pysam.CINS, 4), (pysam.CMATCH, 2))
    a.query_sequence = 'ATGCATGCATGC'
    a.query_qualities = pysam.qualitystring_to_array('abcdefghijkl')
    return a


@pytest.fixture
def sam_fname():
    return os.path.join(BAM_DATADIR, 'ex3.sam')


@pytest.fixture
def bam_fname():
    return os.path.join(BAM_DATADIR, 'ex1.bam')


def test_AlignedSegment_is_mapped(aln: pysam.AlignedSegment) -> None:
    rmap = aln.is_mapped
    mmap = aln.mate_is_mapped
    rfwd = aln.is_forward
    mfwd = aln.mate_is_forward

    if TYPE_CHECKING: reveal_locals()
    types = typecheck()


def test_AlignmentHeader_get_reference_length(sam_fname: str) -> None:
    inf = pysam.AlignmentFile(sam_fname)
    n1 = inf.get_reference_length('chr1')
    hdr = inf.header
    n2 = hdr.get_reference_length('chr1')

    if TYPE_CHECKING: reveal_locals()
    types = typecheck()


def test_pileup_iterator_column(bam_fname: str) -> None:
    inf = pysam.AlignmentFile(bam_fname)
    pu = inf.pileup('chr1')
    for p in pu:
        pid = p.reference_id
        ppos = p.reference_pos

    if TYPE_CHECKING: reveal_locals()
    types = typecheck(check_locals=False)
    assert re.search(r'\.IteratorColumn(|All|AllRefs|Region)$', types['pu'])
    assert types['p'].endswith('PileupColumn')
    assert types['pid'] == 'builtins.int'
    assert types['ppos'] == 'builtins.int'


def test_samtools_subcommands() -> None:
    p1_samtools_faidx = pysam.samtools.faidx
    p2_faidx = pysam.faidx
    p3_view = pysam.view
    p4_bcftools_view = pysam.bcftools.view

    if TYPE_CHECKING: reveal_locals()
    types = typecheck()
    for var, vartype in types.items():
        assert vartype.endswith('PysamDispatcher'), f'{var!r} is not a dispatcher'