|
14 | 14 | from seqr.utils.search.constants import INHERITANCE_FILTERS, ANY_AFFECTED, AFFECTED, UNAFFECTED, MALE_SEXES, \
|
15 | 15 | X_LINKED_RECESSIVE, REF_REF, REF_ALT, ALT_ALT, HAS_ALT, HAS_REF, SPLICE_AI_FIELD, SCREEN_KEY, UTR_ANNOTATOR_KEY, \
|
16 | 16 | EXTENDED_SPLICE_KEY, MOTIF_FEATURES_KEY, REGULATORY_FEATURES_KEY, CLINVAR_KEY, HGMD_KEY, NEW_SV_FIELD, \
|
17 |
| - EXTENDED_SPLICE_REGION_CONSEQUENCE, CLINVAR_PATH_RANGES, CLINVAR_PATH_SIGNIFICANCES, PATH_FREQ_OVERRIDE_CUTOFF, \ |
| 17 | + EXTENDED_SPLICE_REGION_CONSEQUENCE, CLINVAR_PATH_RANGES, CLINVAR_PATH_SIGNIFICANCES, CLINVAR_LIKELY_PATH_FILTER, \ |
| 18 | + CLINVAR_CONFLICTING_P_LP, PATH_FREQ_OVERRIDE_CUTOFF, \ |
18 | 19 | HGMD_CLASS_FILTERS, SV_TYPE_FILTER_FIELD, SV_CONSEQUENCES_FIELD, COMPOUND_HET, COMPOUND_HET_ALLOW_HOM_ALTS
|
19 | 20 | from seqr.utils.xpos_utils import get_xpos, MIN_POS, MAX_POS
|
20 | 21 |
|
@@ -42,6 +43,36 @@ def _clinvar_tuple(self):
|
42 | 43 | output_field=NamedTupleField(list(self.clinvar_fields.values()), null_if_empty=True, null_empty_arrays=True),
|
43 | 44 | )
|
44 | 45 |
|
| 46 | + @classmethod |
| 47 | + def _clinvar_path_q(cls, pathogenicity): |
| 48 | + clinvar_path_filters = [ |
| 49 | + f for f in (pathogenicity or {}).get(CLINVAR_KEY) or [] if f in CLINVAR_PATH_SIGNIFICANCES |
| 50 | + ] |
| 51 | + return cls._clinvar_filter_q(clinvar_path_filters) if clinvar_path_filters else None |
| 52 | + |
| 53 | + @classmethod |
| 54 | + def _clinvar_filter_q(cls, clinvar_filters): |
| 55 | + ranges = [[None, None]] |
| 56 | + for path_filter, start, end in CLINVAR_PATH_RANGES: |
| 57 | + if path_filter in clinvar_filters: |
| 58 | + ranges[-1][1] = end |
| 59 | + if ranges[-1][0] is None: |
| 60 | + ranges[-1][0] = start |
| 61 | + elif ranges[-1] != [None, None]: |
| 62 | + ranges.append([None, None]) |
| 63 | + ranges = [r for r in ranges if r[0] is not None] |
| 64 | + |
| 65 | + clinvar_qs = [cls._clinvar_range_q(path_range) for path_range in ranges] |
| 66 | + |
| 67 | + if CLINVAR_CONFLICTING_P_LP in clinvar_filters: |
| 68 | + max_path = next(end for path_filter, _, end in CLINVAR_PATH_RANGES if path_filter == CLINVAR_LIKELY_PATH_FILTER) |
| 69 | + clinvar_qs.append(cls._clinvar_conflicting_path_filter({1: (max_path, "{field} <= '{value}'")})) |
| 70 | + |
| 71 | + clinvar_q = clinvar_qs[0] |
| 72 | + for q in clinvar_qs[1:]: |
| 73 | + clinvar_q |= q |
| 74 | + return clinvar_q |
| 75 | + |
45 | 76 | def _seqr_pop_fields(self, seqr_populations):
|
46 | 77 | sample_types = [
|
47 | 78 | sample_type.lower() for sample_type in
|
@@ -605,34 +636,13 @@ def _hgmd_filter(hgmd):
|
605 | 636 | return ('{field}__classification__range', (min_class, max_class))
|
606 | 637 | return ('{field}__classification__gt', min_class)
|
607 | 638 |
|
608 |
| - @classmethod |
609 |
| - def _clinvar_filter_q(cls, clinvar_filters, _get_range_q=None): |
610 |
| - ranges = [[None, None]] |
611 |
| - for path_filter, start, end in CLINVAR_PATH_RANGES: |
612 |
| - if path_filter in clinvar_filters: |
613 |
| - ranges[-1][1] = end |
614 |
| - if ranges[-1][0] is None: |
615 |
| - ranges[-1][0] = start |
616 |
| - elif ranges[-1] != [None, None]: |
617 |
| - ranges.append([None, None]) |
618 |
| - ranges = [r for r in ranges if r[0] is not None] |
619 |
| - |
620 |
| - clinvar_qs = [(_get_range_q or cls._clinvar_range_q)(path_range) for path_range in ranges] |
621 |
| - clinvar_q = clinvar_qs[0] |
622 |
| - for q in clinvar_qs[1:]: |
623 |
| - clinvar_q |= q |
624 |
| - return clinvar_q |
625 |
| - |
626 |
| - @classmethod |
627 |
| - def _clinvar_range_q(cls, path_range): |
| 639 | + @staticmethod |
| 640 | + def _clinvar_range_q(path_range): |
628 | 641 | return Q(clinvar__0__range=path_range, clinvar_key__isnull=False)
|
629 | 642 |
|
630 |
| - @classmethod |
631 |
| - def _clinvar_path_q(cls, pathogenicity, _get_range_q=None): |
632 |
| - clinvar_path_filters = [ |
633 |
| - f for f in (pathogenicity or {}).get(CLINVAR_KEY) or [] if f in CLINVAR_PATH_SIGNIFICANCES |
634 |
| - ] |
635 |
| - return cls._clinvar_filter_q(clinvar_path_filters, _get_range_q=_get_range_q) if clinvar_path_filters else None |
| 643 | + @staticmethod |
| 644 | + def _clinvar_conflicting_path_filter(conflicting_filter): |
| 645 | + return Q(clinvar__5__array_exists=conflicting_filter, clinvar_key__isnull=False) |
636 | 646 |
|
637 | 647 | def explode_gene_id(self, gene_id_key):
|
638 | 648 | consequence_field = self.GENE_CONSEQUENCE_FIELD if self.has_annotation(self.GENE_CONSEQUENCE_FIELD) else self.transcript_field
|
@@ -766,6 +776,14 @@ def result_values(self, sample_data=None):
|
766 | 776 | def _has_clinvar(self):
|
767 | 777 | return hasattr(self.model, 'clinvar_join')
|
768 | 778 |
|
| 779 | + @staticmethod |
| 780 | + def _clinvar_range_q(path_range): |
| 781 | + return Q(clinvar_join__pathogenicity__range=path_range) |
| 782 | + |
| 783 | + @staticmethod |
| 784 | + def _clinvar_conflicting_path_filter(conflicting_filter): |
| 785 | + return Q(clinvar_join__conflicting_pathogenicities__array_exists=conflicting_filter) |
| 786 | + |
769 | 787 | def _search_call_data(self, entries, sample_data, inheritance_mode=None, inheritance_filter=None, qualityFilter=None, pathogenicity=None, annotate_carriers=False, annotate_hom_alts=False, skip_individual_guid=False, **kwargs):
|
770 | 788 | project_guids = sample_data['project_guids']
|
771 | 789 | project_filter = Q(project_guid__in=project_guids) if len(project_guids) > 1 else Q(project_guid=project_guids[0])
|
@@ -797,9 +815,7 @@ def _search_call_data(self, entries, sample_data, inheritance_mode=None, inherit
|
797 | 815 | quality_filter = qualityFilter or {}
|
798 | 816 | individual_genotype_filter = (inheritance_filter or {}).get('genotype')
|
799 | 817 | if inheritance_mode or individual_genotype_filter or quality_filter:
|
800 |
| - clinvar_override_q = AnnotationsQuerySet._clinvar_path_q( |
801 |
| - pathogenicity, _get_range_q=lambda path_range: Q(clinvar_join__pathogenicity__range=path_range), |
802 |
| - ) if self._has_clinvar() else None |
| 818 | + clinvar_override_q = self._clinvar_path_q(pathogenicity) if self._has_clinvar() else None |
803 | 819 | inheritance_q, quality_q, gt_filter, family_missing_type_samples, unaffected_samples = self._get_inheritance_quality_qs(
|
804 | 820 | sample_data, multi_sample_type_families, inheritance_mode, individual_genotype_filter, quality_filter, clinvar_override_q,
|
805 | 821 | annotate_carriers, inheritance_filter=inheritance_filter or {},
|
|
0 commit comments