def test_missing_father(self): ''' Test an error is raised if the father is missing. ''' # remove father M2 from pedigree pedigree_file = deepcopy(self.pedigree_file) PedigreeFile.validate(pedigree_file.pedigrees) m2 = pedigree_file.pedigrees[0].get_person_by_name('M2') pedigree_file.pedigrees[0].people.remove(m2) with self.assertRaisesRegex(PersonError, r"The father (.*) is missing"): PedigreeFile.validate(pedigree_file.pedigrees)
def test_pathology_status(self): """ Check that the pathology results are correctly set (0, N, P). """ pedigree_file = deepcopy(self.pedigree_file) f1 = pedigree_file.pedigrees[0].get_person_by_name('F1') f1.pathology.er.result = 'X' with self.assertRaisesRegex( PathologyError, "must be 'N' for negative, 'P' for positive, or '0' for unknown" ): PedigreeFile.validate(pedigree_file.pedigrees)
def test_bc1_and_bc2(self): """ Test an error is raised if the age of a first breast cancer exceeds that of the second. """ pedigree_file = deepcopy(self.pedigree_file) f1 = pedigree_file.pedigrees[0].get_person_by_name('F1') f1.cancers.diagnoses.bc1.age = "22" f1.cancers.diagnoses.bc2.age = "21" with self.assertRaisesRegex( CancerError, f1.pid + "*. contralateral breast cancer, (.*) " + "age at diagnosis of the first breast cancer exceeds"): PedigreeFile.validate(pedigree_file.pedigrees)
def test_result_specified(self): """ Check that the mutation status is specified if tested. """ pedigree_file = deepcopy(self.pedigree_file) f1 = pedigree_file.pedigrees[0].get_person_by_name('F1') f1.gtests.brca1.test_type = "S" f1.gtests.brca1.result = "0" with self.assertRaisesRegex( GeneticTestError, "\"" + f1.pid + "\" .* corresponding test result has not been specified"): PedigreeFile.validate(pedigree_file.pedigrees)
def test_type_specified(self): """ Check if there is a genetic test result check the test type is specified. """ pedigree_file = deepcopy(self.pedigree_file) f1 = pedigree_file.pedigrees[0].get_person_by_name('F1') f1.gtests.brca1.test_type = "0" f1.gtests.brca1.result = "P" with self.assertRaisesRegex( GeneticTestError, "\"" + f1.pid + "\" .* genetic test type has not been specified"): PedigreeFile.validate(pedigree_file.pedigrees)
def test_cancer_age2(self): ''' Test an error is raised if the cancer diagnosis age is greater than age at last follow up. ''' pedigree_file = deepcopy(self.pedigree_file) m2 = pedigree_file.pedigrees[0].get_person_by_name('M2') m2.cancers.diagnoses.bc1.age = "59" m2.age = "53" with self.assertRaisesRegex( CancerError, m2.pid + "*. diagnosis that exceeds age at last follow up"): PedigreeFile.validate(pedigree_file.pedigrees)
def test_bc1_missing2(self): """ Test an error is raised if the age of a second breast cancer is AU but age of first is missing. """ pedigree_file = deepcopy(self.pedigree_file) f1 = pedigree_file.pedigrees[0].get_person_by_name('F1') f1.cancers.diagnoses.bc1.age = "-1" f1.cancers.diagnoses.bc2.age = "AU" with self.assertRaisesRegex( CancerError, f1.pid + "*. contralateral breast cancer, (.*) " + "first breast cancer is missing"): PedigreeFile.validate(pedigree_file.pedigrees)
def test_canrisk_header(self): ''' Test canrisk file header. ''' PedigreeFile(self.canrisk_data) canrisk_data = copy.copy(self.canrisk_data) canrisk_data = canrisk_data.replace('CanRisk ', 'CanRisky ', 1) with self.assertRaisesRegex( PedigreeFileError, r"header record in the pedigree file has unexpected characters" ): PedigreeFile(canrisk_data)
def test_mztwin_yob(self): """ Check if an error is raised if MZ twin have different years of birth. """ pedigree_file = deepcopy(self.pedigree_file) pedigree = pedigree_file.pedigrees[0] m2 = pedigree.get_person_by_name('M2') self._add_twin(pedigree, twin=m2) m2.yob = str(int(m2.yob) + 2) with self.assertRaisesRegex( PedigreeError, r"MZ twins must have the same year of birth"): PedigreeFile.validate(pedigree_file.pedigrees)
def test_dead(self): ''' Test an error is raised if the dead attribute is incorrectly specified (not 0 or 1). ''' pedigree_file = deepcopy(self.pedigree_file) PedigreeFile.validate(pedigree_file.pedigrees) m2 = pedigree_file.pedigrees[0].get_person_by_name('M2') m2.dead = "3" with self.assertRaisesRegex( PersonError, r"alive must be specified as '0', and dead specified as '1'"): PedigreeFile.validate(pedigree_file.pedigrees)
def test_result(self): """ Check that the mutation status is valid. """ pedigree_file = deepcopy(self.pedigree_file) f1 = pedigree_file.pedigrees[0].get_person_by_name('F1') f1.gtests.brca1.test_type = "S" f1.gtests.brca1.result = "X" with self.assertRaisesRegex( GeneticTestError, "\"" + f1.pid + "\" .* invalid genetic test result"): PedigreeFile.validate(pedigree_file.pedigrees)
def test_pedigree_remaining_lifetime(self): """ Test pedigree for remaining lifetime risk calculation. """ p1 = deepcopy(self.pedigree) PedigreeFile.validate(p1) calcs = Predictions(p1, cwd=self.cwd, run_risks=False) self.assertTrue(calcs.pedi.is_carrier_probs_viable()) self.assertTrue(calcs.pedi.is_risks_calc_viable()) remaining_life = RemainingLifetimeRisk(calcs) p2 = remaining_life._get_pedi() self.assertEqual(len(p1.people), len(p2.people)) self.assertEqual(p1.get_target().age, p2.get_target().age)
def test_pedigree_range_baseline(self): """ Test pedigree for baseline time range (e.g. lifetime, 10yr range) risk calculation. """ p1 = deepcopy(self.pedigree) PedigreeFile.validate(p1) calcs = Predictions(p1, cwd=self.cwd, run_risks=False) range_baseline = RangeRiskBaseline(calcs, 40, 50, "10 YR RANGE BASELINE") p2 = range_baseline._get_pedi() self.assertEqual(len(p2.people), 1) self.assertEqual(p2.get_target().age, 40) self.assertNotEqual(p1.get_target().age, p2.get_target().age)
def test_patholgy_bc1_setting(self): """ Check that pathology test results are only provided for family members with a first breast cancer """ pedigree_file = deepcopy(self.pedigree_file) f1 = pedigree_file.pedigrees[0].get_person_by_name('F1') f1.cancers.diagnoses.bc1.age = "-1" f1.pathology.er.result = "P" with self.assertRaisesRegex( PathologyError, "Pathology test results can only be assigned to family " + "members who have developed breast cancer."): PedigreeFile.validate(pedigree_file.pedigrees)
def test_mztwin_parents(self): """ Check if an error is raised if MZ twin have different parents. """ pedigree_file = deepcopy(self.pedigree_file) pedigree = pedigree_file.pedigrees[0] m2 = pedigree.get_person_by_name('M2') self._add_twin(pedigree, twin=m2) m2.mothid = "313" pedigree.people.append(Female(m2.famid, "F3A", "313", "0", "0")) with self.assertRaisesRegex(PedigreeError, r"MZ twins must have the same parents"): PedigreeFile.validate(pedigree_file.pedigrees)
def test_age(self): ''' Test an error is raised if the age attribute is incorrectly specified (not 0 or 1-MAX_AGE). ''' pedigree_file = deepcopy(self.pedigree_file) PedigreeFile.validate(pedigree_file.pedigrees) m2 = pedigree_file.pedigrees[0].get_person_by_name('M2') m2.age = "222" with self.assertRaisesRegex( PersonError, r"Ages must be specified with as '0' for unknown, or in the range" ): PedigreeFile.validate(pedigree_file.pedigrees)
def test_bc1_missing(self): """ Test an error is raised if the age of a second breast cancer is present but age of first is missing. """ pfile = self.get_pedigree_file() f1 = pfile.pedigrees[0].get_person_by_name('F1') f1.cancers.diagnoses.bc1.age = "-1" f1.cancers.diagnoses.bc2.age = "21" with self.assertRaisesRegex( CancerError, ".*\"" + f1.pid + "\".* contralateral breast cancer, (.*) " + "first breast cancer is missing"): PedigreeFile.validate(pfile.pedigrees)
def test_cancer_age(self): ''' Test an error is raised if the cancer diagnosis age is incorrectly specified (not 0 or 1-MAX_AGE). ''' pedigree_file = deepcopy(self.pedigree_file) f1 = pedigree_file.pedigrees[0].get_person_by_name('F1') f1.cancers.diagnoses.bc1.age = "xyz" with self.assertRaisesRegex(CancerError, r"Age at cancer diagnosis"): PedigreeFile.validate(pedigree_file.pedigrees) f1.cancers.diagnoses.bc1.age = "199" with self.assertRaisesRegex(CancerError, r"Age at cancer diagnosis"): PedigreeFile.validate(pedigree_file.pedigrees)
def test_mother_sex(self): ''' Test an error is raised if the sex of the mother is not 'F'. ''' # change sex of mother to 'M' pedigree_file = deepcopy(self.pedigree_file) f2 = pedigree_file.pedigrees[0].get_person_by_name('F2') pedigree_file.pedigrees[0].people.remove(f2) pedigree_file.pedigrees[0].people.append( Male(f2.famid, f2.name, f2.pid, f2.fathid, f2.mothid)) with self.assertRaisesRegex( PersonError, r"All mothers in the pedigree must have sex specified as 'F'"): PedigreeFile.validate(pedigree_file.pedigrees)
def test_multiple_pedigrees(self): ''' Test multiple pedigrees in a single file. ''' pedigree_data1 = copy.copy(self.pedigree_data) pedigree_data2 = '\n'.join(pedigree_data1.split('\n')[2:]).replace( "XXX", "YYY") pedigree_data3 = pedigree_data2.replace("YYY", "ZZZ") pedigree_data = pedigree_data1 + '\n\n' + pedigree_data2 + '\n\n' + pedigree_data3 pedigrees = PedigreeFile(pedigree_data).pedigrees self.assertEqual(len(pedigrees), 3) for p in pedigrees: warnings = PedigreeFile.validate(p) self.assertEqual(len(warnings), 0)
def test_mztwin_age(self): """ Check if an error is raised if MZ twin are alive and have different ages at last followup. """ pedigree_file = deepcopy(self.pedigree_file) pedigree = pedigree_file.pedigrees[0] m2 = pedigree.get_person_by_name('M2') self._add_twin(pedigree, twin=m2) m2.age = "44" with self.assertRaisesRegex( PedigreeError, r"If both MZ twins are alive, they must have the same age at last" ): PedigreeFile.validate(pedigree_file.pedigrees)
def get_rfs(bwa): ''' Get risk factor names and values plus PRS from CanRisk file for CSV file ''' rfsnames = [] rfs = {} f = open(bwa, "r") for line in f: if line.startswith( "##") and "##CanRisk" not in line and "##FamID" not in line: if "PRS_BC" in line: # alpha=0.45,zscore=0.1234 add_prs(line, 'BC', rfsnames, rfs) elif "PRS_OC" in line: # alpha=0.45,zscore=0.1234 add_prs(line, 'OC', rfsnames, rfs) else: line = line.replace("##", "").strip().split("=") if line[0].isupper(): if line[0] == 'TL': name = 'Tubal_Ligation' else: name = line[0] elif line[0] == 'mht_use': name = 'MHT_use' elif line[0] == 'height': name = line[0] line[1] = ("%8.4f" % float(line[1])) elif line[0] == 'oc_use': name = 'OC_Use' if line[1] == "N" or line[1] == "C": rfsnames.append(['OC_Duration', 'OC_Duration']) rfs['OC_Duration'] = '0' elif ":" in line[1]: rfsnames.append(['OC_Duration', 'OC_Duration']) parts = line[1].split(":") rfs['OC_Duration'] = parts[1] line[1] = parts[0] elif line[0] == 'birads': name = 'BIRADS' elif line[0] == 'endo': name = 'Endometriosis' else: name = line[0].capitalize() rfsnames.append([line[0], name]) rfs[line[0]] = line[1] f.close() with open(bwa, 'r') as f: pedigree_data = f.read() pedigree = PedigreeFile(pedigree_data).pedigrees[0] ashkn = pedigree.is_ashkn() return rfsnames, rfs, ashkn
def test_calculations2(self): """ Test prediction of cancer risk and mutation probability. """ pedigree = deepcopy(self.pedigree) target = pedigree.get_target() target.age = str(int(target.age) + 43) # sister # diagnoses = CancerDiagnoses(bc1=Cancer("20"), bc2=Cancer(), oc=Cancer(), # prc=Cancer(), pac=Cancer()) # sister = Female("FAM1", "F01", "0011", target.fathid, target.mothid, age="22", yob=str(self.year-23), # cancers=Cancers(diagnoses=diagnoses)) # pedigree.people.append(sister) # parents mother = pedigree.get_person(target.mothid) mother.yob = str(self.year - 84) mother.age = "85" mother.cancers = Cancers(bc1=Cancer("52"), bc2=Cancer(), oc=Cancer(), prc=Cancer(), pac=Cancer()) # maternal grandparents (_maternal_grandfather, maternal_grandmother) = pedigree.add_parents(mother) maternal_grandmother.age = "81" maternal_grandmother.yob = "1912" maternal_grandmother.dead = "1" maternal_grandmother.cancers = Cancers(bc1=Cancer("42"), bc2=Cancer(), oc=Cancer(), prc=Cancer(), pac=Cancer()) PedigreeFile.validate(pedigree) calcs = Predictions(pedigree, cwd=self.cwd) # each gene should have a mutation probability plus a result for no mutations for mp in calcs.mutation_probabilties: key = list(mp.keys())[0] self.assertTrue(key in settings.BC_MODEL['GENES'] or key == "no mutation") self.assertEqual(len(calcs.mutation_probabilties), len(settings.BC_MODEL['GENES']) + 1) # risks calculated at different ages: self.assertEqual(len(calcs.cancer_risks), 9) self.assertTrue([c.get('age') for c in calcs.cancer_risks] == [64, 65, 66, 67, 68, 70, 73, 75, 80])
def test_siblings(self): """ Check max no. of siblings not exceeded. """ pedigree_file = deepcopy(self.pedigree_file) pedigree = pedigree_file.pedigrees[0] f1 = pedigree.get_person_by_name('F1') self.assertEqual(len(pedigree.get_siblings(f1)[0]), 0) pedigree.people.append( Male(f1.famid, "M1A", "111", f1.fathid, f1.mothid)) pedigree.people.append( Male(f1.famid, "M1B", "112", f1.fathid, f1.mothid)) self.assertEqual(len(pedigree.get_siblings(f1)[0]), 2) with self.assertRaisesRegex(PersonError, r"exeeded the maximum number of siblings"): PedigreeFile.validate(pedigree_file.pedigrees)
def test_siblings_same_yob(self): """ Check max no. of siblings with same year of birth is not exceeded. """ pedigree_file = deepcopy(self.pedigree_file) pedigree = pedigree_file.pedigrees[0] f1 = pedigree.get_person_by_name('F1') self.assertEqual(len(pedigree.get_siblings(f1)[1]), 0) pedigree.people.append( Male(f1.famid, "M1A", "111", f1.fathid, f1.mothid, yob=f1.yob)) pedigree.people.append( Male(f1.famid, "M1B", "112", f1.fathid, f1.mothid, yob=f1.yob)) self.assertEqual(len(pedigree.get_siblings(f1)[1]), 2) with self.assertRaisesRegex( PersonError, r"siblings with the same year of birth exceeded"): PedigreeFile.validate(pedigree_file.pedigrees)
def test_target_risk_prob_calcs(self): """ Check if an error is raised if the carrier probabilities and cancer risk can not be calculated. If the target has a positive genetic test carrier probs cannot be calculated. Had bilateral BC or OC or PanC, or she is too old. """ pedigree_file = deepcopy(self.pedigree_file) f1 = pedigree_file.pedigrees[0].get_person_by_name('F1') f1.gtests.brca1.result = "P" f1.cancers.diagnoses.bc2.age = 18 with self.assertRaisesRegex( PedigreeError, r"cannot compute mutation carrier probabilities"): PedigreeFile.validate(pedigree_file.pedigrees)
def get_censoring_ages(bwa): with open(bwa, 'r') as f: pedigree_data = f.read() f.close() pedigree = PedigreeFile(pedigree_data).pedigrees[0] # get ages to calculate risks target = pedigree.get_target() tage = int(target.age) # target age at last follow up c_ages = [] alf = tage while alf <= 79: alf += 1 if alf - tage in [1, 5, 10]: c_ages.append(alf) c_ages.append(80) return c_ages
def is_canrisk(bwa): ''' Return true if CanRisk file type ''' with open(bwa, 'r') as f: pedigree_data = f.read() pedigree = PedigreeFile(pedigree_data).pedigrees[0] return isinstance(pedigree, CanRiskPedigree)
def test_sex(self): """ Test an error is raised if individuals sex is not M or F. """ pedigree_data = copy.copy(self.pedigree_data) pedigree_data = re.sub(r"\s+F\s+", ' FF ', pedigree_data) with self.assertRaisesRegex(PedigreeError, r"individuals sex must be specified as"): PedigreeFile(pedigree_data)
def test_no_target(self): """ Test an error is raised if there is no target. """ pedigree_data = copy.copy(self.pedigree_data) pedigree_data = re.sub(r"F1\s+1", 'F1 0', pedigree_data) with self.assertRaisesRegex(PedigreeError, r"has either no index or more than 1"): PedigreeFile(pedigree_data)