<commit_before># -*- coding: utf-8 -*-

"""
A message for "General Parser Failure" is displayed when a problem was caused due to an unforseen error. The line
number and original statement are printed for the user to debug.
"""

from ..exceptions import PyBelWarning


class PyBelParserWarning(PyBelWarning):
    """Base PyBEL parser exception, which holds the line and position where a parsing problem occurred"""

    def __init__(self, line_number, line, position, *args):
        """
        :param int line_number: The line number on which this warning occurred
        :param str line: The content of the line
        :param int position: The position within the line where the warning occurred
        :param args: Additional arguments to supply to the super class
        """
        super(PyBelParserWarning, self).__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)


class InconsistentDefinitionError(PyBelParserWarning):
    """Base PyBEL error for redefinition"""

    def __init__(self, line_number, line, position, definition):
        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)


class RedefinedNamespaceError(InconsistentDefinitionError):
    """Raised when a namespace is redefined"""


class RedefinedAnnotationError(InconsistentDefinitionError):
    """Raised when an annotation is redefined"""


# Naming Warnings

class NameWarning(PyBelParserWarning):
    """The base class for errors related to nomenclature"""

    def __init__(self, line_number, line, position, name, *args):
        super(NameWarning, self).__init__(line_number, line, position, name, *args)
        self.name = name


class NakedNameWarning(NameWarning):
    """Raised when there is an identifier without a namespace. Enable lenient mode to suppress"""

    def __str__(self):
        return '[pos:{}] "{}" should be qualified with a valid namespace'.format(self.position, self.name)


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)


class NamespaceIdentifierWarning(NameWarning):
    """The base class for warnings related to namespace:name identifiers"""

    def __init__(self, line_number, line, position, namespace, name):
        """
        :param int line_number: The line number of the line that caused the exception
        :param str line: The line that caused the exception
        :param int position: The line's position of the exception
        :param str namespace: The namespace of the identifier
        :param str name: The name of the identifier
        """
        super(NamespaceIdentifierWarning, self).__init__(line_number, line, position, name, namespace)
        self.namespace = namespace


class UndefinedNamespaceWarning(NamespaceIdentifierWarning):
    """Raised if reference made to undefined namespace"""

    def __str__(self):
        return '"{}" is not a defined namespace'.format(self.namespace)


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)


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)


class AnnotationWarning(PyBelParserWarning):
    """Base exception for annotation warnings"""

    def __init__(self, line_number, line, position, annotation, *args):
        super(AnnotationWarning, self).__init__(line_number, line, position, annotation, *args)
        self.annotation = annotation


class UndefinedAnnotationWarning(AnnotationWarning):
    """Raised when an undefined annotation is used"""

    def __str__(self):
        return '''"{}" is not defined'''.format(self.annotation)


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)


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


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)


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

class VersionFormatWarning(PyBelParserWarning):
    """Raised if the version string doesn't adhere to semantic versioning or ``YYYYMMDD`` format"""

    def __init__(self, line_number, line, position, version_string):
        super(VersionFormatWarning, self).__init__(line_number, line, position, version_string)
        self.version_string = version_string

    def __str__(self):
        return '''Version string "{}" neither is a date like YYYYMMDD nor adheres to semantic versioning'''.format(
            self.version_string)


class MetadataException(PyBelWarning):
    def __init__(self, line_number, line, *args):
        super(MetadataException, self).__init__(line_number, line, *args)
        self.line = line
        self.line_number = line_number

    def __str__(self):
        return '[line:{}] Invalid metadata - "{}"'.format(self.line_number, self.line)


class MalformedMetadataException(MetadataException):
    """Raised when an invalid metadata line is encountered"""


class MissingBelResource(MetadataException):
    """Raised when a missing resource is encountered"""

    def __str__(self):
        return "Can't locate resource [line:{}] - {}".format(self.line_number, self.line)


class InvalidMetadataException(PyBelParserWarning):
    """Raised when an incorrect document metadata key is used. Valid document metadata keys are:

- ``Authors``
- ``ContactInfo``
- ``Copyright``
- ``Description``
- ``Disclaimer``
- ``Licenses``
- ``Name``
- ``Version``

.. seealso:: BEL specification on the `properties section <http://openbel.org/language/web/version_1.0/bel_specification_version_1.0.html#_properties_section>`_
    """

    def __init__(self, line_number, line, position, key, value):
        super(InvalidMetadataException, self).__init__(line_number, line, position, key, value)
        self.key = key
        self.value = value

    def __str__(self):
        return 'Invalid document metadata key: {}'.format(self.key)


class MissingMetadataException(PyBelWarning):
    """Raised when a BEL Script is missing critical metadata."""

    def __init__(self, key):
        super(MissingMetadataException, self).__init__(key)
        self.key = key

    def __str__(self):
        return 'Missing required document metadata: {}'.format(self.key)


class InvalidCitationLengthException(PyBelParserWarning):
    """Base exception raised when the format for a citation is wrong."""


class CitationTooShortException(InvalidCitationLengthException):
    """Raised when a citation does not have the minimum of {type, name, reference}."""

    def __str__(self):
        return "[pos:{}] Citation is missing required fields: {}".format(self.position, self.line)


class CitationTooLongException(InvalidCitationLengthException):
    """Raised when a citation has more than the allowed entries, {type, name, reference, date, authors, comments}."""

    def __str__(self):
        return "[pos:{}] Citation contains too many entries: {}".format(self.position, self.line)


class MissingCitationException(PyBelParserWarning):
    """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 absolutly 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)


class MissingSupportWarning(PyBelParserWarning):
    """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)


class InvalidCitationType(PyBelParserWarning):
    """Raise when a citation is set with an incorrect type. 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 '[pos:{}] "{}" is not a valid citation type'.format(self.position, self.citation_type)


class InvalidPubMedIdentifierWarning(PyBelParserWarning):
    """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 '[pos:{}] "{}" is not a valid PubMed identifier'.format(self.position, self.reference)


# BEL Syntax Warnings

class MalformedTranslocationWarning(PyBelParserWarning):
    """Raised when there is a translocation statement without location information."""

    def __init__(self, line_number, line, position, tokens):
        super(MalformedTranslocationWarning, self).__init__(line_number, line, position, tokens)
        self.tokens = tokens

    def __str__(self):
        return '[pos:{}] Unqualified translocation: {} {}'.format(self.position, self.line, self.tokens)


class PlaceholderAminoAcidWarning(PyBelParserWarning):
    """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 '[pos:{}] Placeholder amino acid found: {}'.format(self.position, self.code)


class NestedRelationWarning(PyBelParserWarning):
    """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)


class LexicographyWarning(PyBelWarning):
    """Raised when encountering improper capitalization of namespace/annotation names."""


# Semantic Warnings

class InvalidFunctionSemantic(PyBelParserWarning):
    """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, function, namespace, name, allowed_functions):
        super(InvalidFunctionSemantic, self).__init__(line_number, line, position, function, namespace, name,
                                                      allowed_functions)
        self.function = function
        self.namespace = namespace
        self.name = name
        self.allowed_functions = allowed_functions

    def __str__(self):
        return "{} {}:{} should be encoded as one of: {}".format(
            self.function,
            self.namespace,
            self.name,
            ', '.join(self.allowed_functions)
        )


class RelabelWarning(PyBelParserWarning):
    """Raised when a node is relabeled"""

    def __init__(self, line_number, line, position, node, old_label, new_label):
        super(RelabelWarning, self).__init__(line_number, line, position, node, old_label, new_label)
        self.node = node
        self.old_label = old_label
        self.new_label = new_label

    def __str__(self):
        return 'Tried to relabel {} from {} to {}'.format(self.node, self.old_label, self.new_label)
<commit_msg>Update explanation of semantic versioning<commit_after># -*- coding: utf-8 -*-

"""
A message for "General Parser Failure" is displayed when a problem was caused due to an unforseen error. The line
number and original statement are printed for the user to debug.
"""

from ..exceptions import PyBelWarning


class PyBelParserWarning(PyBelWarning):
    """Base PyBEL parser exception, which holds the line and position where a parsing problem occurred"""

    def __init__(self, line_number, line, position, *args):
        """
        :param int line_number: The line number on which this warning occurred
        :param str line: The content of the line
        :param int position: The position within the line where the warning occurred
        :param args: Additional arguments to supply to the super class
        """
        super(PyBelParserWarning, self).__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)


class InconsistentDefinitionError(PyBelParserWarning):
    """Base PyBEL error for redefinition"""

    def __init__(self, line_number, line, position, definition):
        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)


class RedefinedNamespaceError(InconsistentDefinitionError):
    """Raised when a namespace is redefined"""


class RedefinedAnnotationError(InconsistentDefinitionError):
    """Raised when an annotation is redefined"""


# Naming Warnings

class NameWarning(PyBelParserWarning):
    """The base class for errors related to nomenclature"""

    def __init__(self, line_number, line, position, name, *args):
        super(NameWarning, self).__init__(line_number, line, position, name, *args)
        self.name = name


class NakedNameWarning(NameWarning):
    """Raised when there is an identifier without a namespace. Enable lenient mode to suppress"""

    def __str__(self):
        return '[pos:{}] "{}" should be qualified with a valid namespace'.format(self.position, self.name)


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)


class NamespaceIdentifierWarning(NameWarning):
    """The base class for warnings related to namespace:name identifiers"""

    def __init__(self, line_number, line, position, namespace, name):
        """
        :param int line_number: The line number of the line that caused the exception
        :param str line: The line that caused the exception
        :param int position: The line's position of the exception
        :param str namespace: The namespace of the identifier
        :param str name: The name of the identifier
        """
        super(NamespaceIdentifierWarning, self).__init__(line_number, line, position, name, namespace)
        self.namespace = namespace


class UndefinedNamespaceWarning(NamespaceIdentifierWarning):
    """Raised if reference made to undefined namespace"""

    def __str__(self):
        return '"{}" is not a defined namespace'.format(self.namespace)


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)


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)


class AnnotationWarning(PyBelParserWarning):
    """Base exception for annotation warnings"""

    def __init__(self, line_number, line, position, annotation, *args):
        super(AnnotationWarning, self).__init__(line_number, line, position, annotation, *args)
        self.annotation = annotation


class UndefinedAnnotationWarning(AnnotationWarning):
    """Raised when an undefined annotation is used"""

    def __str__(self):
        return '''"{}" is not defined'''.format(self.annotation)


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)


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


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)


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

class VersionFormatWarning(PyBelParserWarning):
    """Raised if the version string doesn't adhere to semantic versioning or ``YYYYMMDD`` format"""

    def __init__(self, line_number, line, position, version_string):
        super(VersionFormatWarning, self).__init__(line_number, line, position, version_string)
        self.version_string = version_string

    def __str__(self):
        return (
            'Version string "{}" neither is a date like YYYYMMDD nor adheres to semantic versioning.'
            ' See http://semver.org/'.format(self.version_string)
        )


class MetadataException(PyBelWarning):
    def __init__(self, line_number, line, *args):
        super(MetadataException, self).__init__(line_number, line, *args)
        self.line = line
        self.line_number = line_number

    def __str__(self):
        return '[line:{}] Invalid metadata - "{}"'.format(self.line_number, self.line)


class MalformedMetadataException(MetadataException):
    """Raised when an invalid metadata line is encountered"""


class MissingBelResource(MetadataException):
    """Raised when a missing resource is encountered"""

    def __str__(self):
        return "Can't locate resource [line:{}] - {}".format(self.line_number, self.line)


class InvalidMetadataException(PyBelParserWarning):
    """Raised when an incorrect document metadata key is used. Valid document metadata keys are:

- ``Authors``
- ``ContactInfo``
- ``Copyright``
- ``Description``
- ``Disclaimer``
- ``Licenses``
- ``Name``
- ``Version``

.. seealso:: BEL specification on the `properties section <http://openbel.org/language/web/version_1.0/bel_specification_version_1.0.html#_properties_section>`_
    """

    def __init__(self, line_number, line, position, key, value):
        super(InvalidMetadataException, self).__init__(line_number, line, position, key, value)
        self.key = key
        self.value = value

    def __str__(self):
        return 'Invalid document metadata key: {}'.format(self.key)


class MissingMetadataException(PyBelWarning):
    """Raised when a BEL Script is missing critical metadata."""

    def __init__(self, key):
        super(MissingMetadataException, self).__init__(key)
        self.key = key

    def __str__(self):
        return 'Missing required document metadata: {}'.format(self.key)


class InvalidCitationLengthException(PyBelParserWarning):
    """Base exception raised when the format for a citation is wrong."""


class CitationTooShortException(InvalidCitationLengthException):
    """Raised when a citation does not have the minimum of {type, name, reference}."""

    def __str__(self):
        return "[pos:{}] Citation is missing required fields: {}".format(self.position, self.line)


class CitationTooLongException(InvalidCitationLengthException):
    """Raised when a citation has more than the allowed entries, {type, name, reference, date, authors, comments}."""

    def __str__(self):
        return "[pos:{}] Citation contains too many entries: {}".format(self.position, self.line)


class MissingCitationException(PyBelParserWarning):
    """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 absolutly 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)


class MissingSupportWarning(PyBelParserWarning):
    """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)


class InvalidCitationType(PyBelParserWarning):
    """Raise when a citation is set with an incorrect type. 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 '[pos:{}] "{}" is not a valid citation type'.format(self.position, self.citation_type)


class InvalidPubMedIdentifierWarning(PyBelParserWarning):
    """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 '[pos:{}] "{}" is not a valid PubMed identifier'.format(self.position, self.reference)


# BEL Syntax Warnings

class MalformedTranslocationWarning(PyBelParserWarning):
    """Raised when there is a translocation statement without location information."""

    def __init__(self, line_number, line, position, tokens):
        super(MalformedTranslocationWarning, self).__init__(line_number, line, position, tokens)
        self.tokens = tokens

    def __str__(self):
        return '[pos:{}] Unqualified translocation: {} {}'.format(self.position, self.line, self.tokens)


class PlaceholderAminoAcidWarning(PyBelParserWarning):
    """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 '[pos:{}] Placeholder amino acid found: {}'.format(self.position, self.code)


class NestedRelationWarning(PyBelParserWarning):
    """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)


class LexicographyWarning(PyBelWarning):
    """Raised when encountering improper capitalization of namespace/annotation names."""


# Semantic Warnings

class InvalidFunctionSemantic(PyBelParserWarning):
    """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, function, namespace, name, allowed_functions):
        super(InvalidFunctionSemantic, self).__init__(line_number, line, position, function, namespace, name,
                                                      allowed_functions)
        self.function = function
        self.namespace = namespace
        self.name = name
        self.allowed_functions = allowed_functions

    def __str__(self):
        return "{} {}:{} should be encoded as one of: {}".format(
            self.function,
            self.namespace,
            self.name,
            ', '.join(self.allowed_functions)
        )


class RelabelWarning(PyBelParserWarning):
    """Raised when a node is relabeled"""

    def __init__(self, line_number, line, position, node, old_label, new_label):
        super(RelabelWarning, self).__init__(line_number, line, position, node, old_label, new_label)
        self.node = node
        self.old_label = old_label
        self.new_label = new_label

    def __str__(self):
        return 'Tried to relabel {} from {} to {}'.format(self.node, self.old_label, self.new_label)

{'fraction_non_alphanumeric': 0.10020742436163364, 'fraction_numerical': 0.0003576282097131822, 'mean_word_length': 3.8245341614906834, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3207179', 'n_tokens_mistral': 7622, 'n_tokens_neox': 7132, 'n_words': 2565}