# -*- coding: utf-8 -*-
"""This module contains base exceptions that are shared through the package.
A message for "General Parser Failure" is displayed when a problem was caused due to an unforeseen error. The line
number and original statement are printed for the user to debug.
"""
from .utils import ensure_quotes
[docs]class PyBELWarning(Exception):
"""The base class for warnings during compilation from which PyBEL can recover."""
[docs]class BELParserWarning(PyBELWarning):
"""The base PyBEL parser exception, which holds the line and position where a parsing problem occurred."""
def __init__(self, line_number: int, line: str, position: int, *args):
"""Initialize the BEL parser warning.
:param line_number: The line number on which this warning occurred
:param line: The content of the line
:param position: The position within the line where the warning occurred
"""
super().__init__(line_number, line, position, *args)
self.line_number = line_number
self.line = line
self.position = position
def __str__(self):
return "General Parser Failure on line {} at pos {}: {}".format(self.line_number, self.position, self.line)
[docs]class BELSyntaxError(BELParserWarning, SyntaxError):
"""For general syntax errors."""
[docs]class InconsistentDefinitionError(BELParserWarning):
"""Base PyBEL error for redefinition."""
def __init__(self, line_number: int, line: str, position: int, definition: str):
super(InconsistentDefinitionError, self).__init__(line_number, line, position, definition)
self.definition = definition
def __str__(self):
return "Tried to redefine {} with: {}".format(self.definition, self.line)
[docs]class RedefinedNamespaceError(InconsistentDefinitionError):
"""Raised when a namespace is redefined."""
[docs]class RedefinedAnnotationError(InconsistentDefinitionError):
"""Raised when an annotation is redefined."""
# Naming Warnings
[docs]class NameWarning(BELParserWarning):
"""The base class for errors related to nomenclature."""
def __init__(self, line_number: int, line: str, position: int, name: str, *args):
"""Build a warning wrapping a given name."""
super().__init__(line_number, line, position, name, *args)
self.name = name
[docs]class NakedNameWarning(NameWarning):
"""Raised when there is an identifier without a namespace. Enable lenient mode to suppress."""
def __str__(self):
return '"{}" should be qualified with a valid namespace'.format(self.name)
[docs]class MissingDefaultNameWarning(NameWarning):
"""Raised if reference to value not in default namespace."""
def __str__(self):
return '"{}" is not in the default namespace'.format(self.name)
[docs]class NamespaceIdentifierWarning(NameWarning):
"""The base class for warnings related to namespace:name identifiers."""
def __init__(self, line_number: int, line: str, position: int, namespace: str, name: str):
"""Initialize the namespace identifier warning.
:param line_number: The line number of the line that caused the exception
:param line: The line that caused the exception
:param position: The line's position of the exception
:param namespace: The namespace of the identifier
:param name: The name of the identifier
"""
super(NamespaceIdentifierWarning, self).__init__(line_number, line, position, name, namespace)
self.namespace = namespace
[docs]class UndefinedNamespaceWarning(NamespaceIdentifierWarning):
"""Raised if reference made to undefined namespace."""
def __str__(self):
return '"{}" is not a defined namespace'.format(self.namespace)
[docs]class MissingNamespaceNameWarning(NamespaceIdentifierWarning):
"""Raised if reference to value not in namespace."""
def __str__(self):
return '"{}" is not in the {} namespace'.format(self.name, self.namespace)
[docs]class MissingNamespaceRegexWarning(NamespaceIdentifierWarning):
"""Raised if reference not matching regex."""
def __str__(self):
return """"{}" doesn't match the regex for {} namespace""".format(self.name, self.namespace)
[docs]class AnnotationWarning(BELParserWarning):
"""Base exception for annotation warnings."""
def __init__(self, line_number, line, position, annotation, *args):
"""Build an AnnotationWarning.
:param int line_number: The line number on which the warning occurred
:param str line: The line on which the warning occurred
:param int position: The position in the line that caused the warning
:param str annotation: The annotation name that caused the warning
"""
super(AnnotationWarning, self).__init__(line_number, line, position, annotation, *args)
self.annotation = annotation
[docs]class UndefinedAnnotationWarning(AnnotationWarning):
"""Raised when an undefined annotation is used."""
def __str__(self):
return """"{}" is not defined""".format(self.annotation)
[docs]class MissingAnnotationKeyWarning(AnnotationWarning):
"""Raised when trying to unset an annotation that is not set."""
def __str__(self):
return """"{}" is not set, so it can't be unset""".format(self.annotation)
[docs]class AnnotationIdentifierWarning(AnnotationWarning):
"""Base exception for annotation:value pairs."""
def __init__(self, line_number, line, position, annotation, value):
super(AnnotationIdentifierWarning, self).__init__(line_number, line, position, annotation, value)
self.value = value
[docs]class IllegalAnnotationValueWarning(AnnotationIdentifierWarning):
"""Raised when an annotation has a value that does not belong to the original set of valid annotation values."""
def __str__(self):
return '"{}" is not defined in the {} annotation'.format(self.value, self.annotation)
[docs]class MissingAnnotationRegexWarning(AnnotationIdentifierWarning):
"""Raised if annotation doesn't match regex."""
def __str__(self):
return """"{}" doesn't match the regex for {} annotation""".format(self.value, self.annotation)
# Provenance Warnings
[docs]class InvalidCitationLengthException(BELParserWarning):
"""Base exception raised when the format for a citation is wrong."""
[docs]class CitationTooShortException(InvalidCitationLengthException):
"""Raised when a citation does not have the minimum of {type, name, reference}."""
def __str__(self):
return "Citation is missing required fields: {}".format(self.line)
[docs]class MissingCitationException(BELParserWarning):
"""Raised when trying to parse a BEL statement, but no citation is currently set.
This might be due to a previous error in the formatting of a citation.
Though it's not a best practice, some BEL curators set other annotations before the citation. If this is the case
in your BEL document, and you're *absolutely* sure that all ``UNSET`` statements are correctly written, you can use
``citation_clearing=True`` as a keyword argument in any of the IO functions in :func:`pybel.from_lines`,
:func:`pybel.from_url`, or :func:`pybel.from_path`.
"""
def __str__(self):
return "Missing citation; can't add: {}".format(self.line)
[docs]class MissingSupportWarning(BELParserWarning):
"""Raised when trying to parse a BEL statement, but no evidence is currently set.
All BEL statements must be qualified with evidence.
If your data is serialized from a database and provenance information is not readily
accessible, consider referencing the publication for the database, or a url pointing to the data from either
a programmatically or human-readable endpoint.
"""
def __str__(self):
return "Missing evidence; can't add: {}".format(self.line)
[docs]class MissingAnnotationWarning(BELParserWarning):
"""Raised when trying to parse a BEL statement and a required annotation is not present."""
def __init__(self, line_number, line, position, required_annotations):
super(MissingAnnotationWarning, self).__init__(line_number, line, position, required_annotations)
self.required_annotations = required_annotations
def __str__(self):
return "Missing annotations: {}".format(", ".join(sorted(self.required_annotations)))
[docs]class InvalidCitationType(BELParserWarning):
"""Raised when a citation is set with an incorrect type.
.. hint:: Valid citation types include:
- ``Book``
- ``PubMed``
- ``Journal``
- ``Online Resource``
- ``URL``
- ``DOI``
- ``Other``
.. seealso:: OpenBEL wiki on `citations <https://wiki.openbel.org/display/BELNA/Citation>`_
"""
def __init__(self, line_number, line, position, citation_type):
super(InvalidCitationType, self).__init__(line_number, line, position, citation_type)
self.citation_type = citation_type
def __str__(self):
return '"{}" is not a valid citation type'.format(self.citation_type)
[docs]class InvalidPubMedIdentifierWarning(BELParserWarning):
"""Raised when a citation is set whose type is ``PubMed`` but whose database identifier is not a valid integer."""
def __init__(self, line_number, line, position, reference):
super(InvalidPubMedIdentifierWarning, self).__init__(line_number, line, position, reference)
self.reference = reference
def __str__(self):
return '"{}" is not a valid PubMed identifier'.format(self.reference)
# BEL Syntax Warnings
[docs]class PlaceholderAminoAcidWarning(BELParserWarning):
"""Raised when an invalid amino acid code is given.
One example might be the usage of X, which is a colloquial signifier for a truncation in a given position. Text
mining efforts for knowledge extraction make this mistake often. X might also signify a placeholder amino acid.
"""
def __init__(self, line_number, line, position, code):
super(PlaceholderAminoAcidWarning, self).__init__(line_number, line, position, code)
self.code = code
def __str__(self):
return "Placeholder amino acid found: {}".format(self.code)
[docs]class NestedRelationWarning(BELParserWarning):
"""Raised when encountering a nested statement.
See our the docs for an explanation of why we explicitly do not support nested statements.
"""
def __str__(self):
return "Nesting is not supported. Split this statement: {}".format(self.line)
# Semantic Warnings
[docs]class InvalidEntity(BELParserWarning):
"""Raised when using a non-entity name for a name."""
def __init__(self, line_number, line, position, namespace, name):
super().__init__(line_number, line, position, namespace, name)
self.namespace = namespace
self.name = name
def __str__(self):
return "{}:{} should not be coded as an entity".format(self.namespace, ensure_quotes(self.name))
[docs]class InvalidFunctionSemantic(BELParserWarning):
"""Raised when an invalid function is used for a given node.
For example, an HGNC symbol for a protein-coding gene YFG cannot be referenced as an miRNA with ``m(HGNC:YFG)``
"""
def __init__(self, line_number, line, position, func, namespace, name, allowed_functions):
super().__init__(line_number, line, position, func, namespace, name, allowed_functions)
self.func = func
self.namespace = namespace
self.name = name
self.allowed_functions = allowed_functions
def __str__(self):
return "{} {}:{} should be encoded as one of: {}".format(
self.func,
self.namespace,
ensure_quotes(self.name),
", ".join(self.allowed_functions),
)