text: from .exceptions import UnitError
  
  
  def onlybytes(msg):
      def decorator(func):
          def check_other(self, other):
              if not isinstance(other, Bytes):
                  raise UnitError(msg)
              return func(self, other)
          return check_other
      return decorator
  
  
  class Bytes(object):
  
      units = {'B': 1,
               'KiB': 1024,
               'MiB': 1024 * 1024,
               'GiB': 1024 * 1024 * 1024,
               'TiB': 1024 * 1024 * 1024 * 1024,
               }
  
      def __init__(self, qty):
          if isinstance(qty, (int, long)):
              self.qty = qty
          else:
              self.qty = Bytes.parse(qty)
  
      @staticmethod
      def parse(qty_str):
          import re
          regex = re.compile('^(?P<qty>\d+)(?P<unit>[KMGT]i?B|B)$')
          parsed = regex.match(qty_str)
          if parsed is None:
              raise UnitError('Unable to parse ' + qty_str)
  
          qty = int(parsed.group('qty'))
          unit = parsed.group('unit')
          if unit[0] in 'KMGT':
              unit = unit[0] + 'iB'
          byte_qty = qty * Bytes.units[unit]
          return byte_qty
  
      def get_qty_in(self, unit):
          if unit[0] in 'KMGT':
              unit = unit[0] + 'iB'
          if unit not in Bytes.units:
              raise UnitError('Unrecognized unit: ' + unit)
          if self.qty % Bytes.units[unit] != 0:
              msg = 'Unable to convert {qty} bytes to a whole number in {unit}'.format(qty=self.qty, unit=unit)
              raise UnitError(msg)
          return self.qty / Bytes.units[unit]
  
      def __repr__(self):
          converted = str(self.get_qty_in('B')) + 'B'
          if self.qty == 0:
              return converted
          for unit in ['TiB', 'GiB', 'MiB', 'KiB']:
              try:
                  converted = str(self.get_qty_in(unit)) + unit
                  break
              except UnitError:
                  pass
          return converted
  
      def __str__(self):
          return self.__repr__()
  
      def __int__(self):
          return self.qty
  
      def __long__(self):
          return self.qty
  
      @onlybytes('Can only compare Bytes to Bytes')
      def __lt__(self, other):
          return self.qty < other.qty
  
      @onlybytes('Can only compare Bytes to Bytes')
      def __le__(self, other):
          return self.qty <= other.qty
  
      @onlybytes('Can only compare Bytes to Bytes')
      def __eq__(self, other):
          return self.qty == other.qty
  
      @onlybytes('Can only compare Bytes to Bytes')
      def __ne__(self, other):
          return self.qty != other.qty
  
      @onlybytes('Can only compare Bytes to Bytes')
      def __ge__(self, other):
          return self.qty >= other.qty
  
      @onlybytes('Can only compare Bytes to Bytes')
      def __gt__(self, other):
          return self.qty > other.qty
  
      @onlybytes('Can only add Bytes to Bytes')
      def __add__(self, other):
          return Bytes(self.qty + other.qty)
  
      @onlybytes('Can only add Bytes to Bytes')
      def __iadd__(self, other):
          self.qty += other.qty
          return self
  
      @onlybytes('Can only subtract Bytes from Bytes')
      def __sub__(self, other):
          return Bytes(self.qty - other.qty)
  
      @onlybytes('Can only subtract Bytes from Bytes')
      def __isub__(self, other):
          self.qty -= other.qty
          return self
  
      def __mul__(self, other):
          if not isinstance(other, (int, long)):
              raise UnitError('Can only multiply Bytes with integers')
          return Bytes(self.qty * other)
  
      def __imul__(self, other):
          if not isinstance(other, (int, long)):
              raise UnitError('Can only multiply Bytes with integers')
          self.qty *= other
          return self
  
      def __div__(self, other):
          if isinstance(other, Bytes):
              return self.qty / other.qty
          if not isinstance(other, (int, long)):
              raise UnitError('Can only divide Bytes with integers or Bytes')
          return Bytes(self.qty / other)
  
      def __idiv__(self, other):
          if isinstance(other, Bytes):
              self.qty /= other.qty
          else:
              if not isinstance(other, (int, long)):
                  raise UnitError('Can only divide Bytes with integers or Bytes')
              self.qty /= other
          return self
  
      @onlybytes('Can only take modulus of Bytes with Bytes')
      def __mod__(self, other):
          return Bytes(self.qty % other.qty)
  
      @onlybytes('Can only take modulus of Bytes with Bytes')
      def __imod__(self, other):
          self.qty %= other.qty
          return self
  
      def __getstate__(self):
          return {'__class__': self.__module__ + '.' + self.__class__.__name__,
                  'qty': self.qty,
                  }
  
      def __setstate__(self, state):
          self.qty = state['qty']
  