<commit_before># -*- coding: utf-8 -*-
"""Provides classes for dealing with the locations of HGVS variants

This module provides for Representing the location of variants in HGVS nomenclature, including:

  * integers and integer intervals (e.g., NC_012345.6:g.3403243_3403248A>C)
  * CDS positions and intervals (e.g., NM_01234.5:c.56+12_56+14delAC)
  * CDS stop coordinates (e.g., NM_01234.5:c.*13A>C)  

Classes:

  * :class:`SimplePosition` -- a simple integer
  * :class:`BaseOffsetPosition` -- a position with datum, base, and offset for c. and r. coordinates
  * :class:`AAPosition` -- an amino acid position (with AA)
  * :class:`Interval` -- an interval of Positions
"""

from __future__ import absolute_import, division, print_function, unicode_literals

import recordtype

from bioutils.sequences import aa1_to_aa3

import hgvs
from hgvs.exceptions import HGVSError, HGVSUnsupportedOperationError, HGVSInvalidIntervalError


SEQ_START = 0
CDS_START = 1
CDS_END = 2


@total_ordering
class SimplePosition(recordtype.recordtype("SimplePosition", field_names=[("base", None), ("uncertain", False)])):
    def __str__(self):
        self.validate()
        s = "?" if self.base is None else str(self.base)
        return "(" + s + ")" if self.uncertain else s

    def format(self, conf):
        return str(self)

    @property
    def is_uncertain(self):
        """return True if the position is marked uncertain or undefined"""
        return self.uncertain or self.base in None

    def _set_uncertain(self):
        "mark this location as uncertain and return reference to self; this is called during parsing (see hgvs.ometa)"
        self.uncertain = True
        return self

    def validate(self):
        "raise AssertionError if instance variables are invalid; otherwise return True"
        assert self.base is None or self.base >= 1, self.__class__.__name__ + ": base must be >= 1"
        return True

    def __sub__(lhs, rhs):
        assert type(lhs) == type(rhs), "Cannot substract coordinates of different representations"
        return lhs.base - rhs.base

    def __eq__(lhs, rhs):
        assert type(lhs) == type(rhs), "Cannot compare coordinates of different representations"
        if lhs.uncertain or rhs.uncertain:
            raise HGVSUnsupportedOperationError("Cannot compare coordinates of uncertain positions")
        return lhs.base == rhs.base
    
    def __lt__(lhs, rhs):
        assert type(lhs) == type(rhs), "Cannot compare coordinates of different representations"
        if lhs.uncertain or rhs.uncertain:
            raise HGVSUnsupportedOperationError("Cannot compare coordinates of uncertain positions")
        return lhs.base < rhs.base


@total_ordering
class BaseOffsetPosition(recordtype.recordtype(
    'BaseOffsetPosition',
    field_names=[('base', None), ('offset', 0), ('datum', SEQ_START), ('uncertain', False)])):
    """
    Class for dealing with CDS coordinates in transcript variants.

    This class models CDS positions using a `base` coordinate, which is
    measured relative to a specified `datum` (CDS_START or CDS_END), and
    an `offset`, which is 0 for exonic positions and non-zero for intronic
    positions.  **Positions and offsets are 1-based**, with no 0, per the HGVS
    recommendations.  (If you"re using this with UTA, be aware that UTA
    uses interbase coordinates.)

    +----------+------------+-------+---------+------------------------------------------+
    | hgvs     | datum      | base  | offset  | meaning                                  |
    +==========+============+=======+=========+==========================================+
    | r.55     | SEQ_START  |   55  |      0  | RNA position 55                          |
    +----------+------------+-------+---------+------------------------------------------+
    | c.55     | CDS_START  |   55  |      0  | CDS position 55                          |
    +----------+------------+-------+---------+------------------------------------------+
    | c.55     | CDS_START  |   55  |      0  | CDS position 55                          |
    +----------+------------+-------+---------+------------------------------------------+
    | c.55+1   | CDS_START  |   55  |      1  | intronic variant +1 from boundary        |
    +----------+------------+-------+---------+------------------------------------------+
    | c.-55    | CDS_START  |  -55  |      0  | 5' UTR variant, 55 nt upstream of ATG    |
    +----------+------------+-------+---------+------------------------------------------+
    | c.1      | CDS_START  |    1  |      0  | start codon                              |
    +----------+------------+-------+---------+------------------------------------------+
    | c.1234   | CDS_START  | 1234  |      0  | stop codon (assuming CDS length is 1233) |
    +----------+------------+-------+---------+------------------------------------------+
    | c.*1     | CDS_END    |    0  |      1  | STOP + 1                                 |
    +----------+------------+-------+---------+------------------------------------------+
    | c.*55    | CDS_END    |    0  |     55  | 3' UTR variant, 55 nt after STOP         |
    +----------+------------+-------+---------+------------------------------------------+
    """

    def validate(self):
        "raise AssertionError if instance variables are invalid; otherwise return True"
        assert self.base is None or self.base != 0, "BaseOffsetPosition base may not be 0"
        assert (self.base is None or self.datum == CDS_START or self.base >= 1), \
            "BaseOffsetPosition base must be >=1 for datum = SEQ_START or CDS_END"
        return True

    def __str__(self):
        self.validate()
        base_str = ("?" if self.base is None else "*" + str(self.base) if self.datum == CDS_END else str(self.base))
        offset_str = ("+?" if self.offset is None else "" if self.offset == 0 else "%+d" % self.offset)
        pos = base_str + offset_str
        return "(" + pos + ")" if self.uncertain else pos

    def format(self, conf):
        return str(self)

    def _set_uncertain(self):
        "mark this location as uncertain and return reference to self; this is called during parsing (see hgvs.ometa)"
        self.uncertain = True
        return self

    @property
    def is_uncertain(self):
        """return True if the position is marked uncertain or undefined"""
        return self.uncertain or self.base is None or self.offset is None

    @property
    def is_intronic(self):
        """returns True if the variant is intronic (if the offset is None or non-zero)"""
        return (self.offset is None or self.offset != 0)

    def __sub__(lhs, rhs):
        assert type(lhs) == type(rhs), "Cannot substract coordinates of different representations"
        if lhs.datum != rhs.datum:
            raise HGVSUnsupportedOperationError("Interval length measured from different datums is ill-defined")
        if lhs.offset != 0 or rhs.offset != 0:
            raise HGVSUnsupportedOperationError("Interval length with intronic offsets is ill-defined")
        if lhs.base == rhs.base:
            return lhs.offset - rhs.offset
        straddles_zero = 1 if (lhs.base > 0 and rhs.base < 0) else 0
        return lhs.base - rhs.base - straddles_zero

    def __eq__(lhs, rhs):
        assert type(lhs) == type(rhs), "Cannot compare coordinates of different representations"
        if lhs.uncertain or rhs.uncertain:
            raise HGVSUnsupportedOperationError("Cannot compare coordinates of uncertain positions")
        return lhs.datum == rhs.datum and lhs.base == rhs.base and lhs.offset == rhs.offset

    def __lt__(lhs, rhs):
        assert type(lhs) == type(rhs), "Cannot compare coordinates of different representations"
        if lhs.uncertain or rhs.uncertain:
            raise HGVSUnsupportedOperationError("Cannot compare coordinates of uncertain positions")
        if lhs.datum == rhs.datum:
            if lhs.base == rhs.base:
                return lhs.offset < rhs.offset
            else:
                if (rhs.base - lhs.base == 1 and lhs.offset > 0 and rhs.offset < 0) or
                   (lhs.base - rhs.base == 1 and rhs.offset > 0 and lhs.offset < 0):
                    raise HGVSUnsupportedOperationError("Cannot compare coordinates in the same intron with one based on end of exon and the other based on start of next exon")
                else:
                    return lhs.base < rhs.base
        else:
            if lhs.datum == SEQ_START or rhs.datum == SEQ_START:
                raise HGVSUnsupportedOperationError("Cannot compare coordinates of datum SEQ_START with CDS_START or CDS_END")
            else:
                return lhs.datum < rhs.datum



class AAPosition(recordtype.recordtype("AAPosition", field_names=[("base", None), ("aa", None), ("uncertain", False)])):<commit_msg>Fix syntax error in comparision operator<commit_after># -*- coding: utf-8 -*-
"""Provides classes for dealing with the locations of HGVS variants

This module provides for Representing the location of variants in HGVS nomenclature, including:

  * integers and integer intervals (e.g., NC_012345.6:g.3403243_3403248A>C)
  * CDS positions and intervals (e.g., NM_01234.5:c.56+12_56+14delAC)
  * CDS stop coordinates (e.g., NM_01234.5:c.*13A>C)  

Classes:

  * :class:`SimplePosition` -- a simple integer
  * :class:`BaseOffsetPosition` -- a position with datum, base, and offset for c. and r. coordinates
  * :class:`AAPosition` -- an amino acid position (with AA)
  * :class:`Interval` -- an interval of Positions
"""

from __future__ import absolute_import, division, print_function, unicode_literals

import recordtype

from functools import total_ordering
from bioutils.sequences import aa1_to_aa3

import hgvs
from hgvs.exceptions import HGVSError, HGVSUnsupportedOperationError, HGVSInvalidIntervalError


SEQ_START = 0
CDS_START = 1
CDS_END = 2


@total_ordering
class SimplePosition(recordtype.recordtype("SimplePosition", field_names=[("base", None), ("uncertain", False)])):
    def __str__(self):
        self.validate()
        s = "?" if self.base is None else str(self.base)
        return "(" + s + ")" if self.uncertain else s

    def format(self, conf):
        return str(self)

    @property
    def is_uncertain(self):
        """return True if the position is marked uncertain or undefined"""
        return self.uncertain or self.base in None

    def _set_uncertain(self):
        "mark this location as uncertain and return reference to self; this is called during parsing (see hgvs.ometa)"
        self.uncertain = True
        return self

    def validate(self):
        "raise AssertionError if instance variables are invalid; otherwise return True"
        assert self.base is None or self.base >= 1, self.__class__.__name__ + ": base must be >= 1"
        return True

    def __sub__(lhs, rhs):
        assert type(lhs) == type(rhs), "Cannot substract coordinates of different representations"
        return lhs.base - rhs.base

    def __eq__(lhs, rhs):
        assert type(lhs) == type(rhs), "Cannot compare coordinates of different representations"
        if lhs.uncertain or rhs.uncertain:
            raise HGVSUnsupportedOperationError("Cannot compare coordinates of uncertain positions")
        return lhs.base == rhs.base
    
    def __lt__(lhs, rhs):
        assert type(lhs) == type(rhs), "Cannot compare coordinates of different representations"
        if lhs.uncertain or rhs.uncertain:
            raise HGVSUnsupportedOperationError("Cannot compare coordinates of uncertain positions")
        return lhs.base < rhs.base


@total_ordering
class BaseOffsetPosition(recordtype.recordtype(
    'BaseOffsetPosition',
    field_names=[('base', None), ('offset', 0), ('datum', SEQ_START), ('uncertain', False)])):
    """
    Class for dealing with CDS coordinates in transcript variants.

    This class models CDS positions using a `base` coordinate, which is
    measured relative to a specified `datum` (CDS_START or CDS_END), and
    an `offset`, which is 0 for exonic positions and non-zero for intronic
    positions.  **Positions and offsets are 1-based**, with no 0, per the HGVS
    recommendations.  (If you"re using this with UTA, be aware that UTA
    uses interbase coordinates.)

    +----------+------------+-------+---------+------------------------------------------+
    | hgvs     | datum      | base  | offset  | meaning                                  |
    +==========+============+=======+=========+==========================================+
    | r.55     | SEQ_START  |   55  |      0  | RNA position 55                          |
    +----------+------------+-------+---------+------------------------------------------+
    | c.55     | CDS_START  |   55  |      0  | CDS position 55                          |
    +----------+------------+-------+---------+------------------------------------------+
    | c.55     | CDS_START  |   55  |      0  | CDS position 55                          |
    +----------+------------+-------+---------+------------------------------------------+
    | c.55+1   | CDS_START  |   55  |      1  | intronic variant +1 from boundary        |
    +----------+------------+-------+---------+------------------------------------------+
    | c.-55    | CDS_START  |  -55  |      0  | 5' UTR variant, 55 nt upstream of ATG    |
    +----------+------------+-------+---------+------------------------------------------+
    | c.1      | CDS_START  |    1  |      0  | start codon                              |
    +----------+------------+-------+---------+------------------------------------------+
    | c.1234   | CDS_START  | 1234  |      0  | stop codon (assuming CDS length is 1233) |
    +----------+------------+-------+---------+------------------------------------------+
    | c.*1     | CDS_END    |    0  |      1  | STOP + 1                                 |
    +----------+------------+-------+---------+------------------------------------------+
    | c.*55    | CDS_END    |    0  |     55  | 3' UTR variant, 55 nt after STOP         |
    +----------+------------+-------+---------+------------------------------------------+
    """

    def validate(self):
        "raise AssertionError if instance variables are invalid; otherwise return True"
        assert self.base is None or self.base != 0, "BaseOffsetPosition base may not be 0"
        assert (self.base is None or self.datum == CDS_START or self.base >= 1), \
            "BaseOffsetPosition base must be >=1 for datum = SEQ_START or CDS_END"
        return True

    def __str__(self):
        self.validate()
        base_str = ("?" if self.base is None else "*" + str(self.base) if self.datum == CDS_END else str(self.base))
        offset_str = ("+?" if self.offset is None else "" if self.offset == 0 else "%+d" % self.offset)
        pos = base_str + offset_str
        return "(" + pos + ")" if self.uncertain else pos

    def format(self, conf):
        return str(self)

    def _set_uncertain(self):
        "mark this location as uncertain and return reference to self; this is called during parsing (see hgvs.ometa)"
        self.uncertain = True
        return self

    @property
    def is_uncertain(self):
        """return True if the position is marked uncertain or undefined"""
        return self.uncertain or self.base is None or self.offset is None

    @property
    def is_intronic(self):
        """returns True if the variant is intronic (if the offset is None or non-zero)"""
        return (self.offset is None or self.offset != 0)

    def __sub__(lhs, rhs):
        assert type(lhs) == type(rhs), "Cannot substract coordinates of different representations"
        if lhs.datum != rhs.datum:
            raise HGVSUnsupportedOperationError("Interval length measured from different datums is ill-defined")
        if lhs.offset != 0 or rhs.offset != 0:
            raise HGVSUnsupportedOperationError("Interval length with intronic offsets is ill-defined")
        if lhs.base == rhs.base:
            return lhs.offset - rhs.offset
        straddles_zero = 1 if (lhs.base > 0 and rhs.base < 0) else 0
        return lhs.base - rhs.base - straddles_zero

    def __eq__(lhs, rhs):
        assert type(lhs) == type(rhs), "Cannot compare coordinates of different representations"
        if lhs.uncertain or rhs.uncertain:
            raise HGVSUnsupportedOperationError("Cannot compare coordinates of uncertain positions")
        return lhs.datum == rhs.datum and lhs.base == rhs.base and lhs.offset == rhs.offset

    def __lt__(lhs, rhs):
        assert type(lhs) == type(rhs), "Cannot compare coordinates of different representations"
        if lhs.uncertain or rhs.uncertain:
            raise HGVSUnsupportedOperationError("Cannot compare coordinates of uncertain positions")
        if lhs.datum == rhs.datum:
            if lhs.base == rhs.base:
                return lhs.offset < rhs.offset
            else:
                if ((rhs.base - lhs.base == 1 and lhs.offset > 0 and rhs.offset < 0) or
                    (lhs.base - rhs.base == 1 and rhs.offset > 0 and lhs.offset < 0)):
                    raise HGVSUnsupportedOperationError("Cannot compare coordinates in the same intron with one based on end of exon and the other based on start of next exon")
                else:
                    return lhs.base < rhs.base
        else:
            if lhs.datum == SEQ_START or rhs.datum == SEQ_START:
                raise HGVSUnsupportedOperationError("Cannot compare coordinates of datum SEQ_START with CDS_START or CDS_END")
            else:
                return lhs.datum < rhs.datum



class AAPosition(recordtype.recordtype("AAPosition", field_names=[("base", None), ("aa", None), ("uncertain", False)])):
{'fraction_non_alphanumeric': 0.18879353861686018, 'fraction_numerical': 0.015368220315216782, 'mean_word_length': 1.8180812391338708, 'pattern_counts': {'":': 2, '<': 17, '<?xml version=': 0, '>': 21, 'https://': 0, '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': '5583706', 'n_tokens_mistral': 5061, 'n_tokens_neox': 4735, 'n_words': 1586}