def parse(self, args=None):
        """Parse textual keywords as described by this class’s attributes, and update
        this instance’s attributes with the parsed values. *args* is a list of
        strings; if ``None``, it defaults to ``sys.argv[1:]``. Returns *self*
        for convenience. Raises :exc:`KwargvError` if invalid keywords are
        encountered.

        See also :meth:`ParseKeywords.parse_or_die`.

        """
        if args is None:
            import sys
            args = sys.argv[1:]

        seen = set()

        for arg in args:
            t = arg.split('=', 1)
            if len(t) < 2:
                raise KwargvError('don\'t know what to do with argument "%s"', arg)

            kw, val = t
            ki = self._kwinfos.get(kw)

            if ki is None:
                raise KwargvError('unrecognized keyword argument "%s"', kw)

            if not len(val):
                raise KwargvError('empty value for keyword argument "%s"', kw)

            try:
                pval = ki.parser(val)
            except ParseError as e :
                raise KwargvError('cannot parse value "%s" for keyword '
                                  'argument "%s": %s', val, kw, e)
            except Exception as e:
                if ki.printexc:
                    raise KwargvError('cannot parse value "%s" for keyword '
                                      'argument "%s": %s', val, kw, e)
                raise KwargvError('cannot parse value "%s" for keyword '
                                  'argument "%s"', val, kw)

            if ki.maxvals is not None and len(pval) > ki.maxvals:
                raise KwargvError('keyword argument "%s" may have at most %d'
                                  ' values, but got %s ("%s")', kw,
                                  ki.maxvals, len(pval), val)

            if ki.scale is not None:
                pval = pval * ki.scale

            if ki.fixupfunc is not None:
                pval = ki.fixupfunc(pval)

            if ki.repeatable:
                # We can't just unilaterally append to the preexisting
                # list, since if we did that starting with the default value
                # we'd mutate the default list.
                cur = self.get(ki._attrname)
                if not len(cur):
                    pval = [pval]
                else:
                    cur.append(pval)
                    pval = cur

            seen.add(kw)
            self.set_one(ki._attrname, pval)

        for kw, ki in six.iteritems(self._kwinfos):
            if kw not in seen:
                if ki.required:
                    raise KwargvError('required keyword argument "%s" was not provided', kw)

                # If there's a fixup, process it even if the keyword wasn't
                # provided. This lets code use "interesting" defaults with
                # types that you might prefer to use when launching a task
                # programmatically; e.g. a default output stream that is
                # `sys.stdout`, not "-".
                if ki.fixupfunc is not None:
                    self.set_one(ki._attrname, ki.fixupfunc(None))

        return self