Skip to content

Commit

Permalink
Enhance general output of acmg prediction (#128)
Browse files Browse the repository at this point in the history
* initilize new result model

* PVS1

* other criteria

* remove artifacts

* export method

* solve linting problems

* fix failing tests

* fix e2e tests

* add config=config to super().__init__

* add docs
  • Loading branch information
gromdimon authored Jun 10, 2024
1 parent a7888ca commit a14aa37
Show file tree
Hide file tree
Showing 23 changed files with 1,215 additions and 840 deletions.
8 changes: 7 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ If you want to **use** auto-acmg, the best place is to start at :ref:`dev_quicks
acmg_pvs1
acmg_pvs1_algorithm_details

.. toctree::
:maxdepth: 2
:caption: Usage:

usage

.. toctree::
:maxdepth: 2
:caption: Development:
Expand All @@ -28,4 +34,4 @@ If you want to **use** auto-acmg, the best place is to start at :ref:`dev_quicks
:maxdepth: 2
:caption: API Documentation:

api_reference
api_reference
269 changes: 269 additions & 0 deletions docs/usage.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
.. _usage:

=====
Usage
=====

The following section describe the usage of the AutoACMG package.

.. _installation:

Installation
------------
TODO

.. _configuration:

Configuration
-------------

To run the AutoACMG package, you'll need to create config. Example one can be found in
`.env.dev`. Change the settings to match your environment.

.. code-block:: bash
cp .env.dev .env
.. _running:

Running
-------

To run the AutoACMG package, you'll need to run the following command:

.. code-block:: bash
make run VAR=<variant_name> GR=<genome_release>
Where:
- ``<variant_name>`` is the name of the variant you want to analyze.
- ``<genome_release>`` is the genome release you want to use.

Alternatively you can use it inline:

.. code-block:: python
from src.auto_acmg import AutoACMG
autoacmg = AutoACMG(variant_name, genome_release)
prediction = autoacmg.predict()
Note that the ``predict`` method will return a dictionary with the prediction.
This dictionary contains all ACMG criteria with their:
- ``name``: the name of the ACMG criteria.
- ``prediction``: the prediction of the ACMG criteria.
- ``summary``: the details of the prediction.
- ``description``: the description of the ACMG criteria.

The valid values for the ``prediction`` are:
- ``NotSet``: the ACMG criteria was not set (also due to errors).
- ``Positive``: the ACMG criteria is positive.
- ``Negative``: the ACMG criteria is negative.
- ``NotAutomated``: the ACMG criteria is not automated (e.g. due to the need of manual curation).
- ``NotApplicable``: the ACMG criteria is not applicable.
- ``Depricated``: the ACMG criteria is depricated (e.g. PP5 or BP6).

The evidence level and the prediction path for the PVS1 ACMG criteria is returned at the summary
field in regards to "PVS1 Paper". The values represent the following:

For evidence level:
- ``NotSet``: the evidence level was not set (also due to errors).
- ``PVS1``: the strongest evidence level.
- ``PVS1_Strong``: the strong evidence level.
- ``PVS1_Moderate``: the moderate evidence level.
- ``PVS1_Supporting``: the supporting evidence level.
- ``NotPVS1``: the evidence level is not PVS1.
- ``UnsupportedConsequence``: PVS1 is not applicable due to unsupported consequence.

For prediction path:

.. code-block:: python
#: Mapping of PVS1 prediction path to description for sequence variant
PVS1PredictionPathMapping: Dict[
Union[PVS1PredictionSeqVarPath, PVS1PredictionStrucVarPath], str
] = {
PVS1PredictionSeqVarPath.NotSet: "Not Set",
PVS1PredictionSeqVarPath.PTEN: "Special guideline for PTEN -> Predicted to undergo NMD",
PVS1PredictionSeqVarPath.NF1: (
"Predicted to undergo NMD -> Exon is present in biologically-relevant transcript(s)"
),
PVS1PredictionSeqVarPath.NF2: (
"Predicted to undergo NMD -> Exon is absent from biologically-relevant transcript(s)"
),
PVS1PredictionSeqVarPath.NF3: (
"Not predicted to undergo NMD -> "
"Truncated/altered region is critical to protein function"
),
PVS1PredictionSeqVarPath.NF4: (
"Not predicted to undergo NMD -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are frequent in the general population and/or "
"exon is absent from biologically-relevant transcript(s)"
),
PVS1PredictionSeqVarPath.NF5: (
"Not predicted to undergo NMD -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are not frequent in the general population and "
"exon is present in biologically-relevant transcript(s) -> "
"Variant removes >10% of protein"
),
PVS1PredictionSeqVarPath.NF6: (
"Not predicted to undergo NMD -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are not frequent in the general population and "
"exon is present in biologically-relevant transcript(s) -> "
"Variant removes <10% of protein"
),
PVS1PredictionSeqVarPath.SS1: (
"Exon skipping or use of a cryptic slice site disrupts reading frame and "
"is predicted to undergo NMD -> "
"Exon is present in biologically-relevant transcript(s)"
),
PVS1PredictionSeqVarPath.SS2: (
"Exon skipping or use of a cryptic slice site disrupts reading frame and "
"is predicted to undergo NMD -> "
"Exon is absent from biologically-relevant transcript(s)"
),
PVS1PredictionSeqVarPath.SS3: (
"Exon skipping or use of a cryptic slice site disrupts reading frame and "
"is not predicted to undergo NMD -> "
"Truncated/altered region is critical to protein function"
),
PVS1PredictionSeqVarPath.SS4: (
"Exon skipping or use of a cryptic slice site disrupts reading frame and "
"is not predicted to undergo NMD -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are frequent in the general population and/or "
"exon is absent from biologically-relevant transcript(s)"
),
PVS1PredictionSeqVarPath.SS5: (
"Exon skipping or use of a cryptic slice site disrupts reading frame and "
"is not predicted to undergo NMD -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are not frequent in the general population and "
"exon is present in biologically-relevant transcript(s) -> "
"Variant removes >10% of protein"
),
PVS1PredictionSeqVarPath.SS6: (
"Exon skipping or use of a cryptic slice site disrupts reading frame and "
"is not predicted to undergo NMD -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are not frequent in the general population and "
"exon is present in biologically-relevant transcript(s) -> "
"Variant removes <10% of protein"
),
PVS1PredictionSeqVarPath.SS7: (
"Exon skipping or use of a cryptic slice site preserves reading frame -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are frequent in the general population and/or "
"exon is absent from biologically-relevant transcript(s)"
),
PVS1PredictionSeqVarPath.SS8: (
"Exon skipping or use of a cryptic slice site preserves reading frame -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are not frequent in the general population and "
"exon is present in biologically-relevant transcript(s) -> "
"Variant removes >10% of protein"
),
PVS1PredictionSeqVarPath.SS9: (
"Exon skipping or use of a cryptic slice site preserves reading frame -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are not frequent in the general population and "
"exon is present in biologically-relevant transcript(s) -> "
"Variant removes <10% of protein"
),
PVS1PredictionSeqVarPath.SS10: (
"Exon skipping or use of a cryptic slice site preserves reading frame -> "
"Truncated/altered region is critical to protein function"
),
PVS1PredictionSeqVarPath.IC1: (
"No known alternative start codon in other transcripts -> "
">=1 pathogenic variant(s) upstream of closest potential in-frame start codon"
),
PVS1PredictionSeqVarPath.IC2: (
"No known alternative start codon in other transcripts -> "
"No pathogenic variant(s) upstream of closest potential in-frame start codon"
),
PVS1PredictionSeqVarPath.IC3: "Different functional transcript uses alternative start codon",
PVS1PredictionStrucVarPath.NotSet: "Not Set",
PVS1PredictionStrucVarPath.DEL1: "Full gene deletion",
PVS1PredictionStrucVarPath.DEL2: (
"Single to multi exon deletion disrupts reading frame and "
"is predicted to undergo NMD -> "
"Exon is present in biologically-relevant transcript(s)"
),
PVS1PredictionStrucVarPath.DEL3: (
"Single to multi exon deletion disrupts reading frame and "
"is predicted to undergo NMD -> "
"Exon is absent from biologically-relevant transcript(s)"
),
PVS1PredictionStrucVarPath.DEL4: (
"Single to multi exon deletion disrupts reading frame and "
"is not predicted to undergo NMD -> "
"Truncated/altered region is critical to protein function"
),
PVS1PredictionStrucVarPath.DEL5_1: (
"Single to multi exon deletion disrupts reading frame and "
"is not predicted to undergo NMD -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are frequent in the general population and/or "
"exon is absent from biologically-relevant transcript(s)"
),
PVS1PredictionStrucVarPath.DEL6_1: (
"Single to multi exon deletion disrupts reading frame and "
"is not predicted to undergo NMD -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are not frequent in the general population and "
"exon is present in biologically-relevant transcript(s) -> "
"Variant removes >10% of protein"
),
PVS1PredictionStrucVarPath.DEL7_1: (
"Single to multi exon deletion disrupts reading frame and "
"is not predicted to undergo NMD -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are not frequent in the general population and "
"exon is present in biologically-relevant transcript(s) -> "
"Variant removes <10% of protein"
),
PVS1PredictionStrucVarPath.DEL5_2: (
"Single to multi exon deletion preserves reading frame -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are frequent in the general population and/or "
"exon is absent from biologically-relevant transcript(s)"
),
PVS1PredictionStrucVarPath.DEL6_2: (
"Single to multi exon deletion preserves reading frame -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are not frequent in the general population and "
"exon is present in biologically-relevant transcript(s) -> "
"Variant removes >10% of protein"
),
PVS1PredictionStrucVarPath.DEL7_2: (
"Single to multi exon deletion preserves reading frame -> "
"Role of region in protein function is unknown -> "
"LoF variants in this exon are not frequent in the general population and "
"exon is present in biologically-relevant transcript(s) -> "
"Variant removes <10% of protein"
),
PVS1PredictionStrucVarPath.DEL8: (
"Single to multi exon deletion preserves reading frame -> "
"Truncated/altered region is critical to protein function"
),
PVS1PredictionStrucVarPath.DUP1: (
"Proven in tandem -> " "Reading frame disrupted and NMD predicted to occur"
),
PVS1PredictionStrucVarPath.DUP2_1: (
"Proven in tandem -> " "No or unknown impact on reading frame and NMD"
),
PVS1PredictionStrucVarPath.DUP2_2: (
"Presumed in tandem -> " "No or unknown impact on reading frame and NMD"
),
PVS1PredictionStrucVarPath.DUP3: (
"Proven in tandem -> " "Reading frame presumed disrupted and NMD predicted to occur"
),
PVS1PredictionStrucVarPath.DUP4: "Proven not in tandem",
}
63 changes: 32 additions & 31 deletions src/auto_acmg.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from src.core.config import Config
from src.criteria.auto_criteria import AutoACMGCriteria
from src.defs.auto_acmg import ACMGPrediction, AutoACMGResult
from src.defs.auto_acmg import ACMGPrediction, AutoACMGPrediction, AutoACMGResult
from src.defs.auto_pvs1 import PVS1Prediction, PVS1PredictionPathMapping, PVS1PredictionStrucVarPath
from src.defs.exceptions import AutoAcmgBaseException, ParseError
from src.defs.genome_builds import GenomeRelease
Expand Down Expand Up @@ -138,25 +138,9 @@ def predict(self) -> Optional[AutoACMGResult]:
self.seqvar: SeqVar = variant
self.prediction: AutoACMGResult = AutoACMGResult()

# PP5 and BP6 criteria
self.prediction.pp5.prediction = ACMGPrediction.NotSet
self.prediction.pp5.comment = "PP5 prediction is deprecated."
self.prediction.bp6.prediction = ACMGPrediction.NotSet
self.prediction.bp6.comment = "BP6 prediction is deprecated."
# PP5 and BP6 criteria are depricated
logger.warning("Note, that PP5 and BP6 criteria are depricated and not predicted.")

# Not implemented criteria
for crit in NOT_IMPLEMENTED_CRITERIA:
setattr(
getattr(self.prediction, crit.lower()),
"prediction",
ACMGPrediction.NotSet,
)
setattr(
getattr(self.prediction, crit.lower()),
"comment",
f"{crit} prediction is not implemented.",
)
logger.warning(
"Some criteria are not implemented yet: {}",
NOT_IMPLEMENTED_CRITERIA,
Expand All @@ -166,26 +150,33 @@ def predict(self) -> Optional[AutoACMGResult]:
try:
logger.info("Predicting PVS1.")
pvs1 = AutoPVS1(self.seqvar, self.genome_release, config=self.config)
seqvar_prediction, seqvar_prediction_path = pvs1.predict()
seqvar_prediction, seqvar_prediction_path, comment = pvs1.predict()
if seqvar_prediction is None or seqvar_prediction_path is None:
raise AutoAcmgBaseException(
"PVS1 prediction failed: prediction or prediction path is None."
)
else:
if seqvar_prediction == PVS1Prediction.NotSet:
raise AutoAcmgBaseException("PVS1 prediction failed: prediction NotSet.")
self.prediction.pvs1.prediction = (
ACMGPrediction.Positive
if seqvar_prediction in PVS1_POSITIVE_SEQVAR_PREDICTIONS
else ACMGPrediction.Negative
)
self.prediction.pvs1.comment = (
f"PVS1 strength: {seqvar_prediction.name}. "
f"PVS1 prediction path: {PVS1PredictionPathMapping[seqvar_prediction_path]}."
)
elif seqvar_prediction == PVS1Prediction.UnsupportedConsequence:
self.prediction.pvs1.prediction = AutoACMGPrediction.NotApplicable
self.prediction.pvs1.summary = "Unsupported consequence"
self.prediction.pvs1.description = comment
else:
self.prediction.pvs1.prediction = (
AutoACMGPrediction.Positive
if seqvar_prediction in PVS1_POSITIVE_SEQVAR_PREDICTIONS
else AutoACMGPrediction.Negative
)
self.prediction.pvs1.summary = (
f"PVS1 strength: {seqvar_prediction.name}. "
f"PVS1 prediction path: {PVS1PredictionPathMapping[seqvar_prediction_path]}."
)
self.prediction.pvs1.description = comment
except AutoAcmgBaseException as e:
self.prediction.pvs1.prediction = ACMGPrediction.NotSet
self.prediction.pvs1.comment = "PVS1 prediction failed."
self.prediction.pvs1.prediction = AutoACMGPrediction.NotSet
self.prediction.pvs1.description = "PVS1 prediction failed."
self.comment = f"Error: {e}"
logger.error("Failed to predict PVS1 criteria. Error: {}", e)

# Other criteria
Expand All @@ -202,12 +193,22 @@ def predict(self) -> Optional[AutoACMGResult]:
setattr(
getattr(self.prediction, criteria.lower()),
"prediction",
ACMGPrediction.Positive if prediction else ACMGPrediction.Negative,
(
AutoACMGPrediction.Positive
if prediction["prediction"] == ACMGPrediction.Positive
else AutoACMGPrediction.Negative
),
)
setattr(
getattr(self.prediction, criteria.lower()),
"summary",
prediction["comment"],
)
except AutoAcmgBaseException as e:
logger.error("Failed to predict other ACMG criteria. Error: {}", e)

logger.info("ACMG criteria prediction completed.")
logger.debug("ACMG criteria prediction result: {}", self.prediction)
return self.prediction

elif isinstance(variant, StrucVar):
Expand Down
Loading

0 comments on commit a14aa37

Please sign in to comment.