docs: def parse_size(self, size=None):
          """Parse the size component of the path.
  
          /full/ -> self.size_full = True
          /max/ -> self.size_mac = True  (2.1 and up)
          /w,/ -> self.size_wh = (w,None)
          /,h/ -> self.size_wh = (None,h)
          /w,h/ -> self.size_wh = (w,h)
          /pct:p/ -> self.size_pct = p
          /!w,h/ -> self.size_wh = (w,h), self.size_bang = True
  
          Expected use:
            (w,h) = iiif.size_to_apply(region_w,region_h)
            if (q is None):
                # full image
            else:
                # scale to w by h
          Returns (None,None) if no scaling is required.
          """
          if (size is not None):
              self.size = size
          self.size_pct = None
          self.size_bang = False
          self.size_full = False
          self.size_wh = (None, None)
          if (self.size is None or self.size == 'full'):
              self.size_full = True
              return
          elif (self.size == 'max' and self.api_version >= '2.1'):
              self.size_max = True
              return
          pct_match = re.match('pct:(.*)$', self.size)
          if (pct_match is not None):
              pct_str = pct_match.group(1)
              try:
                  self.size_pct = float(pct_str)
              except ValueError:
                  raise IIIFRequestError(
                      code=400, parameter="size",
                      text="Percentage size value must be a number, got "
                           "'%s'." % (pct_str))
              # Note that Image API specificaton places no upper limit on
              # size so none is implemented here.
              if (self.size_pct < 0.0):
                  raise IIIFRequestError(
                      code=400, parameter="size",
                      text="Base size percentage, must be > 0.0, got %f." %
                      (self.size_pct))
          else:
              if (self.size[0] == '!'):
                  # Have "!w,h" form
                  size_no_bang = self.size[1:]
                  (mw, mh) = self._parse_w_comma_h(size_no_bang, 'size')
                  if (mw is None or mh is None):
                      raise IIIFRequestError(
                          code=400, parameter="size",
                          text="Illegal size requested: both w,h must be "
                               "specified in !w,h requests.")
                  self.size_wh = (mw, mh)
                  self.size_bang = True
              else:
                  # Must now be "w,h", "w," or ",h"
                  self.size_wh = self._parse_w_comma_h(self.size, 'size')
              # Sanity check w,h
              (w, h) = self.size_wh
              if ((w is not None and w <= 0) or
                      (h is not None and h <= 0)):
                  raise IIIFZeroSizeError(
                      code=400, parameter='size',
                      text="Size parameters request zero size result image.")