<commit_before># Copyright (C) 2015  Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# the GNU General Public License v.2, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY expressed or implied, including the implied warranties of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
# Public License for more details.  You should have received a copy of the
# GNU General Public License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
# source code or documentation are not subject to the GNU General Public
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#
# Red Hat Author(s): <NAME> <<EMAIL>>

""" Size class, for creating instances of Size objects.

    Contains a few documented methods and a number of __*__ methods
    implementing arithmetic operations. Precise numeric types
    such as int and Decimal may also occur in some arithmetic expressions,
    but all occurrances of floating point numbers in arithmetic expressions
    will cause an exception to be raised.
"""

from fractions import Fraction

import six

from ._config import SizeConfig

from ._errors import SizeFractionalResultError
from ._errors import SizeNonsensicalBinOpError
from ._errors import SizeNonsensicalBinOpValueError
from ._errors import SizePowerResultError
from ._errors import SizeValueError

from ._constants import B
from ._constants import BinaryUnits
from ._constants import DecimalUnits
from ._constants import PRECISE_NUMERIC_TYPES
from ._constants import UNIT_TYPES

from ._util.math_util import round_fraction

from ._util.misc import get_decimal_info
from ._util.misc import get_string_info

_BYTES_SYMBOL = "B"

class Size(object):
    """ Class for instantiating Size objects. """

    _FMT_STR = "".join([
       "%(approx)s",
       "%(sign)s",
       "%(left)s",
       "%(radix)s",
       "%(right)s",
       " ",
       "%(units)s",
       "%(bytes)s"
    ])

    @classmethod
    def _get_unit_value(cls, unit):
        """
        Returns numeric value for unit.

        :param unit: the unit
        :type unit: object
        :returns: None if not convertable, else numeric value
        :rtype: Fraction or NoneType
        """
        if not isinstance(unit, UNIT_TYPES) and  not isinstance(unit, Size):
            return None
        factor = getattr(unit, 'factor', getattr(unit, 'magnitude', None))
        try:
            return Fraction(factor if factor is not None else unit)
        except (ValueError, TypeError):
            return None

    def __init__(self, value=0, units=None):
        """ Initialize a new Size object.

            :param value: a size value, default is 0
            :type value: Size, or any finite numeric type (possibly as str)
            :param units: the units of the size, default is None
            :type units: any of the publicly defined units constants or a Size
            :raises SizeValueError: on bad parameters

            Must pass None as units argument if value has type Size.

            The units number must be a precise numeric type.
        """
        if isinstance(value, six.string_types) or \
           isinstance(value, PRECISE_NUMERIC_TYPES):
            try:
                units = B if units is None else units
                factor = self._get_unit_value(units)
                if factor is None:
                    raise SizeValueError(units, "units")
                magnitude = Fraction(value) * factor
            except (ValueError, TypeError):
                raise SizeValueError(value, "value")

        elif isinstance(value, Size):
            if units is not None:
                raise SizeValueError(
                   units,
                   "units",
                   "meaningless when Size value is passed"
                )
            magnitude = value.magnitude # pylint: disable=no-member
        else:
            raise SizeValueError(value, "value")

        if SizeConfig.STRICT is True and magnitude.denominator != 1:
            raise SizeFractionalResultError()
        self._magnitude = magnitude

    @property
    def magnitude(self):
        """
        :returns: the number of bytes
        :rtype: Fraction
        """
        return self._magnitude

    def getDecimalInfo(self, config):
        """
        Get information for the decimal representation of ``self``.

        :param StrConfig config: the display configuration
        :returns: a tuple representing the value
        :rtype: tuple of int * int * list of int * list of int

        Components:
        1. sign, -1 if negative else 1
        2. portion on the left of the decimal point
        3. non-repeating portion to the right of the decimal point
        4. repeating portion to the right of the decimal point
        5. units specifier
        """
        (magnitude, units) = self.components(config)
        radix_num = get_decimal_info(magnitude)
        return (
           radix_num.sign,
           radix_num.left,
           radix_num.non_repeating,
           radix_num.repeating,
           units
        )

    def getStringInfo(self, config):
        """
        Return a representation of the size.

        :param :class:`StrConfig` config: representation configuration
        :returns: a tuple representing the string to display
        :rtype: tuple of bool * int * str * str * unit

        Components are:
        1. If true, the value is approximate
        2. -1 for a negative number, 1 for a positive
        3. a string with the decimal digits to the left of the decimal point
        4. a string with the decimal digits to the right of the decimal point
        5. a unit specifier

        """
        (magnitude, units) = self.components(config)
        (exact, sign, left, right) = get_string_info(
           magnitude,
           places=config.max_places
        )

        return (not exact, sign, left, right, units)

    def getString(self, config, display):
        """ Return a string representation of the size.

            :param :class:`StrConfig` config: representation configuration
            :param DisplayConfig display: configuration for display
            :returns: a string representation
            :rtype: str<commit_msg>Fix some bad formatting in doc strings.<commit_after># Copyright (C) 2015  Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# the GNU General Public License v.2, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY expressed or implied, including the implied warranties of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
# Public License for more details.  You should have received a copy of the
# GNU General Public License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
# source code or documentation are not subject to the GNU General Public
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#
# Red Hat Author(s): <NAME> <<EMAIL>>

""" Size class, for creating instances of Size objects.

    Contains a few documented methods and a number of __*__ methods
    implementing arithmetic operations. Precise numeric types
    such as int and Decimal may also occur in some arithmetic expressions,
    but all occurrances of floating point numbers in arithmetic expressions
    will cause an exception to be raised.
"""

from fractions import Fraction

import six

from ._config import SizeConfig

from ._errors import SizeFractionalResultError
from ._errors import SizeNonsensicalBinOpError
from ._errors import SizeNonsensicalBinOpValueError
from ._errors import SizePowerResultError
from ._errors import SizeValueError

from ._constants import B
from ._constants import BinaryUnits
from ._constants import DecimalUnits
from ._constants import PRECISE_NUMERIC_TYPES
from ._constants import UNIT_TYPES

from ._util.math_util import round_fraction

from ._util.misc import get_decimal_info
from ._util.misc import get_string_info

_BYTES_SYMBOL = "B"

class Size(object):
    """ Class for instantiating Size objects. """

    _FMT_STR = "".join([
       "%(approx)s",
       "%(sign)s",
       "%(left)s",
       "%(radix)s",
       "%(right)s",
       " ",
       "%(units)s",
       "%(bytes)s"
    ])

    @classmethod
    def _get_unit_value(cls, unit):
        """
        Returns numeric value for unit.

        :param unit: the unit
        :type unit: object
        :returns: None if not convertable, else numeric value
        :rtype: Fraction or NoneType
        """
        if not isinstance(unit, UNIT_TYPES) and  not isinstance(unit, Size):
            return None
        factor = getattr(unit, 'factor', getattr(unit, 'magnitude', None))
        try:
            return Fraction(factor if factor is not None else unit)
        except (ValueError, TypeError):
            return None

    def __init__(self, value=0, units=None):
        """ Initialize a new Size object.

            :param value: a size value, default is 0
            :type value: Size, or any finite numeric type (possibly as str)
            :param units: the units of the size, default is None
            :type units: any of the publicly defined units constants or a Size
            :raises SizeValueError: on bad parameters

            Must pass None as units argument if value has type Size.

            The units number must be a precise numeric type.
        """
        if isinstance(value, six.string_types) or \
           isinstance(value, PRECISE_NUMERIC_TYPES):
            try:
                units = B if units is None else units
                factor = self._get_unit_value(units)
                if factor is None:
                    raise SizeValueError(units, "units")
                magnitude = Fraction(value) * factor
            except (ValueError, TypeError):
                raise SizeValueError(value, "value")

        elif isinstance(value, Size):
            if units is not None:
                raise SizeValueError(
                   units,
                   "units",
                   "meaningless when Size value is passed"
                )
            magnitude = value.magnitude # pylint: disable=no-member
        else:
            raise SizeValueError(value, "value")

        if SizeConfig.STRICT is True and magnitude.denominator != 1:
            raise SizeFractionalResultError()
        self._magnitude = magnitude

    @property
    def magnitude(self):
        """
        :returns: the number of bytes
        :rtype: Fraction
        """
        return self._magnitude

    def getDecimalInfo(self, config):
        """
        Get information for the decimal representation of ``self``.

        :param StrConfig config: the display configuration
        :returns: a tuple representing the value
        :rtype: tuple of int * int * list of int * list of int

        Components:
          1. sign, -1 if negative else 1
          2. portion on the left of the decimal point
          3. non-repeating portion to the right of the decimal point
          4. repeating portion to the right of the decimal point
          5. units specifier
        """
        (magnitude, units) = self.components(config)
        radix_num = get_decimal_info(magnitude)
        return (
           radix_num.sign,
           radix_num.left,
           radix_num.non_repeating,
           radix_num.repeating,
           units
        )

    def getStringInfo(self, config):
        """
        Return a representation of the size.

        :param `StrConfig` config: representation configuration
        :returns: a tuple representing the string to display
        :rtype: tuple of bool * int * str * str * unit

        Components are:
          1. If true, the value is approximate
          2. -1 for a negative number, 1 for a positive
          3. a string with the decimal digits to the left of the decimal point
          4. a string with the decimal digits to the right of the decimal point
          5. a unit specifier

        """
        (magnitude, units) = self.components(config)
        (exact, sign, left, right) = get_string_info(
           magnitude,
           places=config.max_places
        )

        return (not exact, sign, left, right, units)

    def getString(self, config, display):
        """
        Return a string representation of the size.

        :param StrConfig config: representation configuration
        :param DisplayConfig display: configuration for display
        :returns: a string representation
        :rtype: str
{'fraction_non_alphanumeric': 0.06725811343645739, 'fraction_numerical': 0.005004549590536852, 'mean_word_length': 2.333923154701719, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '624161', 'n_tokens_mistral': 3476, 'n_tokens_neox': 3328, 'n_words': 1443}