Skip to content

Commit

Permalink
Merge pull request #85 from griffithlab/master
Browse files Browse the repository at this point in the history
merge master to 1.0 ahead of 1.0.1 release
  • Loading branch information
ahwagner authored May 14, 2020
2 parents fee942c + 5723c48 commit 07e7325
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 24 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ ENV/

# data folders
analysis/data/
civicpy/data/

# vcf files
*.vcf
6 changes: 6 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ python:
install:
- pip install -e .[test]
script:
- mkdir -p /home/travis/build/griffithlab/civicpy/civicpy/data
#testing_civicpy_cache.pkl is a symlink that points to one of the monthly
#pkl releases. This is so that test data stays static. As the CIViC data
#model changes, updating the target of this symlink might be necessary to
#ensure that the tests capture the latest data model.
- wget -O /home/travis/build/griffithlab/civicpy/civicpy/data/test_cache.pkl https://civicdb.org/downloads/testing_civicpy_cache.pkl
- pytest --cov civicpy --cov-report term-missing
after_success:
- coveralls
2 changes: 1 addition & 1 deletion civicpy/__version__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
__url__ = 'http://civicpy.org'
__major__ = '1'
__minor__ = '0'
__patch__ = '0'
__patch__ = '1'
__meta_label__ = ''
__short_version__ = f"{__major__}.{__minor__}"
__version__ = f"{__short_version__}.{__patch__}"
Expand Down
40 changes: 31 additions & 9 deletions civicpy/civic.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,14 @@ def groups(self):
def types(self):
return self.variant_types

@property
def summary(self):
return self.description

@summary.setter
def summary(self, value):
self.description = value

@property
def evidence(self):
return self.evidence_items
Expand All @@ -483,18 +491,24 @@ def gene(self):

@property
def is_insertion(self):
return self.coordinates.reference_bases is None and self.coordinates.variant_bases is not None
ref = self.coordinates.reference_bases
alt = self.coordinates.variant_bases
return (ref is None and alt is not None) or (ref is not None and alt is not None and len(ref) < len(alt))

@property
def is_deletion(self):
return self.coordinates.reference_bases is not None and (self.coordinates.variant_bases is None or self.coordinates.variant_bases == '-' or self.coordinates.variant_bases == '')
ref = self.coordinates.reference_bases
alt = self.coordinates.variant_bases
if alt is not None and (alt == '-' or alt == ''):
alt = None
return (ref is not None and alt is None) or (ref is not None and alt is not None and len(ref) > len(alt))

def is_valid_for_vcf(self, emit_warnings=False):
if self.coordinates.chromosome2 or self.coordinates.start2 or self.coordinates.stop2:
warning = "Variant {} has a second set of coordinates. Skipping".format(self.id)
if self.coordinates.chromosome and self.coordinates.start and (self.coordinates.reference_bases or self.coordinates.variant_bases):
if self._valid_ref_bases:
if self._valid_alt_bases:
if self._valid_ref_bases():
if self._valid_alt_bases():
return True
else:
warning = "Unsupported variant base(s) for variant {}. Skipping.".format(self.id)
Expand All @@ -508,9 +522,9 @@ def is_valid_for_vcf(self, emit_warnings=False):

def _valid_ref_bases(self):
if self.coordinates.reference_bases is not None:
return True
else:
return all([c.upper() in ['A', 'C', 'G', 'T', 'N'] for c in self.coordinates.reference_bases])
else:
return True

def _valid_alt_bases(self):
if self.coordinates.variant_bases is not None:
Expand Down Expand Up @@ -568,7 +582,7 @@ class Evidence(CivicRecord):
'evidence_type',
'gene_id',
'name',
'open_change_count',
# 'open_change_count',
'rating',
'status',
'variant_id',
Expand All @@ -577,8 +591,8 @@ class Evidence(CivicRecord):
'assertions',
'disease',
'drugs',
'errors',
'fields_with_pending_changes',
# 'errors',
# 'fields_with_pending_changes',
'lifecycle_actions',
'phenotypes',
'source'})
Expand All @@ -599,6 +613,14 @@ def assertions(self):
def assertions(self, value):
self._assertions = value

@property
def statement(self):
return self.description

@statement.setter
def statement(self, value):
self.description = value


class Assertion(CivicRecord):
_SIMPLE_FIELDS = CivicRecord._SIMPLE_FIELDS.union({
Expand Down
Binary file removed civicpy/data/test_cache.pkl
Binary file not shown.
13 changes: 11 additions & 2 deletions civicpy/exports.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ def writerecords(self, with_header=True):
ensembl_server = "https://grch37.rest.ensembl.org"

# write them
rows = []
for variant in sorted_records:
if variant.coordinates.reference_build != 'GRCh37':
continue
Expand All @@ -161,7 +162,10 @@ def writerecords(self, with_header=True):
start = variant.coordinates.start
ext = "/sequence/region/human/{}:{}-{}".format(variant.coordinates.chromosome, start, start)
r = requests.get(ensembl_server+ext, headers={ "Content-Type" : "text/plain"})
ref = r.text
if variant.coordinates.reference_bases == None or variant.coordinates.reference_bases == '-' or variant.coordinates.reference_bases == '':
ref = r.text
else:
ref = "{}{}".format(r.text, variant.coordinates.reference_bases)
alt = "{}{}".format(r.text, variant.coordinates.variant_bases)
csq_alt = variant.coordinates.variant_bases
elif variant.is_deletion:
Expand All @@ -172,7 +176,10 @@ def writerecords(self, with_header=True):
ext = "/sequence/region/human/{}:{}-{}".format(variant.coordinates.chromosome, start, start)
r = requests.get(ensembl_server+ext, headers={ "Content-Type" : "text/plain"})
ref = "{}{}".format(r.text, variant.coordinates.reference_bases)
alt = r.text
if variant.coordinates.variant_bases == None or variant.coordinates.variant_bases == '-' or variant.coordinates.variant_bases == '':
alt = r.text
else:
alt = "{}{}".format(r.text, variant.coordinates.variant_bases)
csq_alt = "-"
else:
start = variant.coordinates.start
Expand Down Expand Up @@ -260,6 +267,8 @@ def writerecords(self, with_header=True):
out_dict['INFO'] = ';'.join(out)

super().writerow(out_dict)
rows.append(out_dict)
return rows

def _write_meta_file_lines(self):
self._f.write(f'##fileformat=VCFv{self.version}\n')
Expand Down
70 changes: 66 additions & 4 deletions civicpy/tests/test_exports.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,81 @@ def vcf_stream():
return io.StringIO()


@pytest.fixture(scope='module')
@pytest.fixture(scope='function')
def vcf_writer(vcf_stream):
return exports.VCFWriter(vcf_stream)

#snv
@pytest.fixture(scope="module")
def v600e():
return civic.get_variant_by_id(12)

class TestVcfExport(object):
#simple insertion
@pytest.fixture(scope="module")
def a56fs():
return civic.get_variant_by_id(1785)

#@pytest.mark.skip(reason="Implementation under development")
#simple deletion
@pytest.fixture(scope="module")
def v273fs():
return civic.get_variant_by_id(762)

#complex insertion
@pytest.fixture(scope="module")
def v2444fs():
return civic.get_variant_by_id(137)

#complex deletion
@pytest.fixture(scope="module")
def l158fs():
return civic.get_variant_by_id(2137)

class TestVcfExport(object):
def test_protein_altering(self, vcf_writer, caplog, v600e):
vcf_writer.addrecord(v600e)
assert not caplog.records
assert len(vcf_writer.variant_records) == 1
vcf_writer.writerecords()
out_dict = vcf_writer.writerecords()
assert out_dict[0]['POS'] == '140453136'
assert out_dict[0]['REF'] == 'A'
assert out_dict[0]['ALT'] == 'T'

def test_simple_insertion(self, vcf_writer, caplog, a56fs):
assert a56fs.is_insertion
vcf_writer.addrecord(a56fs)
assert not caplog.records
assert len(vcf_writer.variant_records) == 1
out_dict = vcf_writer.writerecords()
assert out_dict[0]['POS'] == '10183697'
assert out_dict[0]['REF'] == 'G'
assert out_dict[0]['ALT'] == 'GA'

def test_simple_deletion(self, vcf_writer, caplog, v273fs):
assert v273fs.is_deletion
vcf_writer.addrecord(v273fs)
assert not caplog.records
assert len(vcf_writer.variant_records) == 1
out_dict = vcf_writer.writerecords()
assert out_dict[0]['POS'] == '47641432'
assert out_dict[0]['REF'] == 'GT'
assert out_dict[0]['ALT'] == 'G'

def test_complex_insertion(self, vcf_writer, caplog, v2444fs):
assert v2444fs.is_insertion
vcf_writer.addrecord(v2444fs)
assert not caplog.records
assert len(vcf_writer.variant_records) == 1
out_dict = vcf_writer.writerecords()
assert out_dict[0]['POS'] == '139390861'
assert out_dict[0]['REF'] == 'GG'
assert out_dict[0]['ALT'] == 'GTGT'

def test_complex_deletion(self, vcf_writer, caplog, l158fs):
assert l158fs.is_deletion
vcf_writer.addrecord(l158fs)
assert not caplog.records
assert len(vcf_writer.variant_records) == 1
out_dict = vcf_writer.writerecords()
assert out_dict[0]['POS'] == '10191480'
assert out_dict[0]['REF'] == 'TGAA'
assert out_dict[0]['ALT'] == 'TC'
Loading

0 comments on commit 07e7325

Please sign in to comment.