Exemplo n.º 1
0
    def __call__ (self, gloss):

        self._indent = "  "
        self._gloss = gloss

        # Resolve pivotal language and environment.
        self._lang = self._options.lang or gloss.lang
        if self._lang not in gloss.languages:
            error(p_("error message",
                     "language '%(lang)s' not present in the glossary")
                    % dict(lang=self._lang))
        self._env = self._options.env or gloss.env[0]
        if self._env and self._env not in gloss.environments:
            error(p_("error message",
                     "environment '%(env)s' not defined by the glossary")
                  % dict(env=self._env))

        # Determine concepts to present and in which order.
        concepts = self._select_concepts()

        # Prepare text formatters.
        self._tf = TextFormatterPlain(gloss, lang=self._lang, env=self._env,
                                      escape=escape_xml)

        # Create TBX.
        accl = LineAccumulator(self._indent)
        self._fmt_prologue(accl)
        self._fmt_concepts(accl.newind(2), concepts)
        self._fmt_epilogue(accl)

        if self._options.file:
            tbx_fname = self._options.file
        else:
            tbx_fname = gloss.id + ".tbx"
        accl.write(tbx_fname)
Exemplo n.º 2
0
def fill_optparser (parser_view):

    pv = parser_view

    pv.set_desc(p_("subcommand description",
                   "Create a PO file out of the glossary."))

    pv.add_subopt("olang", str,
                  metavar=p_("placeholder for parameter value", "LANGKEY"),
                  desc=p_("subcommand option description",
                          "Original language from the PO point of view."))
    pv.add_subopt("tlang", str,
                  metavar=p_("placeholder for parameter value", "LANGKEY"),
                  desc=p_("subcommand option description",
                          "Target language from the PO point of view."))
    pv.add_subopt("env", str, defval="",
                  metavar=p_("placeholder for parameter value", "ENVKEY"),
                  desc=p_("subcommand option description",
                          "Environment for which the PO file is produced."))
    pv.add_subopt("file", str, defval="",
                  metavar=p_("placeholder for parameter value", "FILE"),
                  desc=p_("subcommand option description",
                          "File to output the PO content (defaults to stdout)."))
    pv.add_subopt("condesc", bool, defval=False,
                  desc=p_("subcommand option description",
                          "Show descriptions only on conflicts, for concepts "
                          "having terms also used to name other concepts."))
Exemplo n.º 3
0
def _res_embsel_parse_one (seg, denvs):

    ntext = Text()
    envs = set()

    p1 = seg.find("~")
    p2 = -1

    while p1 >= 0:
        head = seg[p2+1:p1]
        if head:
            ntext.append(head)
        p2 = seg.find("~", p1 + 1)
        if p2 < 0:
            warning(p_("warning message",
                       "unterminated embedded selector '%(esel)s'")
                    % {"esel":seg})
            p2 = p1 - 1
            break

        class DictWProps (dict): pass
        envsegs = DictWProps()
        locenvs = set()
        for eseg in seg[p1+1:p2].split("|"):
            pc = eseg.find(":")
            if pc >= 0:
                cenvs = eseg[:pc].split()
                cseg = eseg[pc+1:]
            else:
                cenvs = denvs
                cseg = eseg

            repenvs = locenvs.intersection(cenvs)
            if repenvs:
                fmtes = " ".join([str(x) for x in list(repenvs)])
                warning(p_("warning message",
                           "segment '%(eseg)s' in embedded selector "
                           "'%(esel)s' repeats environments: %(envs)s")
                        % {"esel":seg, "eseg":eseg, "envs":fmtes})

            locenvs.update(cenvs)
            for cenv in cenvs:
                envsegs[cenv] = cseg

        # Add embedded selector string under a dummy environment,
        # needed later for error reporting.
        envsegs.unparsed = seg

        ntext.append(envsegs)
        envs.update(locenvs)

        p1 = seg.find("~", p2 + 1)

    tail = seg[p2+1:]
    if tail:
        ntext.append(tail)

    return ntext, envs
Exemplo n.º 4
0
def _post_dtd_error (gloss, gnode, msg):

    lmsg = p_("message with the location it speaks of",
              "%(file)s:%(line)s: %(msg)s") \
           % {"file":gnode.src_file, "line":gnode.src_line, "msg":msg,}

    error(p_("error message",
             "post-DTD validation failed:\n"
             "%(msg)s") % {"msg":lmsg})
Exemplo n.º 5
0
    def __init__ (self, subcmd_reg_bundle):
        """
        Constructor.

        Registeres the subcommand categories, using a list where every
        element is a tuple specifying a package and category name::

            import subcmds.foo
            import subcmds.bar
            ...
            sch = SubcmdHandler([(subcmds.foo, "Foos"), (subcmds.bar, "Bars")])

        @param subcmd_reg_bundle: subcommand registration bundle
        @rtype: list of tuples
        """

        # By package:
        self._packs = {} # subcommand packages (dummy true value)
        self._mods = {} # subcommand modules by package
        self._cats = {} # subcommand categories
        self._subcmds = {} # subcommand names
        self._optparsers = {} # suboption parsers

        # Collect available subcommands.
        for pack, cat in subcmd_reg_bundle:

            modfiles = fnmatch.filter(os.listdir(pack.__path__[0]), "[a-z]*.py")
            subcmds = [x.rstrip(".py").replace("_", "-") for x in modfiles]
            self._packs[pack] = True
            self._cats[pack] = cat
            self._subcmds[pack] = subcmds

            # Create option parser for subcommands in this category.
            optparser = SuboptParser(cat)
            self._optparsers[pack] = optparser

            # Load modules for requested subcommands in this category,
            # and fill their option parsers.
            self._mods[pack] = {}
            for subcmd in subcmds:
                if subcmd not in self._subcmds[pack]:
                    if cat:
                        error(p_("error in command line",
                                 "unknown subcommand requested in "
                                 "category '%(cat)s': %(cmd)s")
                              % dict(cat=cat, cmd=subcmd))
                    else:
                        error(p_("error in command line",
                                 "unknown subcommand requested: %(cmd)s")
                              % dict(cmd=subcmd))

                mod = self._import_submod(pack, subcmd)
                mod.fill_optparser(optparser.add_subcmd(subcmd))

                self._mods[pack][subcmd] = mod
Exemplo n.º 6
0
def fill_optparser (parser_view):

    pv = parser_view

    pv.set_desc(p_("subcommand description",
                   "Create a TBX view of the glossary."))

    pv.add_subopt("lang", str, defval="",
                  metavar=p_("placeholder for parameter value", "LANGKEY"),
                  desc=p_("subcommand option description",
                          "Pivotal language for the view. The glossary "
                          "default language is used if not given."))
    pv.add_subopt("env", str, defval="",
                  metavar=p_("placeholder for parameter value", "ENVKEY"),
                  desc=p_("subcommand option description",
                          "Pivotal environment for the view. The glossary "
                          "default environment is used if not given."))
    pv.add_subopt("file", str, defval="",
                  metavar=p_("placeholder for parameter value", "NAME"),
                  desc=p_("subcommand option description",
                          "Name of the TBX file to create. If not given, "
                          "the name is derived from glossary ID."))
    pv.add_subopt("wdecl", str, defval=[], seplist=True,
                  metavar=p_("placeholder for parameter value", "LANG,..."),
                  desc=p_("subcommand option description",
                          "Languages for which also to include declination "
                          "forms into TBX term sets."))
Exemplo n.º 7
0
def fill_optparser (parser_view):

    pv = parser_view

    pv.set_desc(p_("subcommand description",
                   "Create a simple plain text view of the glossary."))

    pv.add_subopt("lang", str, defval="",
                  metavar=p_("placeholder for parameter value", "LANGKEY"),
                  desc=p_("subcommand option description",
                          "Pivotal language for the view. The glossary "
                          "default language is used if not given."))
    pv.add_subopt("env", str, defval="",
                  metavar=p_("placeholder for parameter value", "ENVKEY"),
                  desc=p_("subcommand option description",
                          "Pivotal environment for the view. The glossary "
                          "default environment is used if not given."))
    pv.add_subopt("file", str, defval="",
                  metavar=p_("placeholder for parameter value", "FILE"),
                  desc=p_("subcommand option description",
                          "File to output the text into (defaults to stdout)."))
    pv.add_subopt("wcol", int, defval=70,
                  metavar=p_("placeholder for parameter value", "COLUMN"),
                  desc=p_("subcommand option description",
                          "Wrap text after this column."))
Exemplo n.º 8
0
    def _format_sub (self, text, pclass=None):

        pattrs = {}
        if pclass is not None:
            pattrs["class"] = pclass

        fmt_text = []
        for seg in text:
            if isinstance(seg, Para):
                fmt_seg = wtext(self._format_sub(seg), "p", pattrs)
            elif isinstance(seg, Ref):
                if self._refbase is None or seg.c in self._refbase:
                    if self._refbase is None:
                        target = "#%s" % seg.c
                    else:
                        target = "%s#%s" % (self._refbase[seg.c], seg.c)
                    fmt_seg = wtext(self._format_sub(seg),
                                    "a", {"class":"cref", "href":target})
                else:
                    fmt_seg = self._format_sub(seg)
            elif isinstance(seg, Em):
                fmt_seg = p_("formatting of an emphasized phrase in "
                             "running HTML text",
                             "<em>%(phrase)s</em>") \
                          % dict(phrase=self._format_sub(seg))
            elif isinstance(seg, Ol):
                if not seg.wl:
                    fmt_seg = p_("formatting of a foreign language phrase in "
                                 "running HTML text",
                                 "<em class='frlng'>%(phrase)s</em>") \
                              % dict(phrase=self._format_sub(seg))
                else:
                    lnode = self._gloss.languages[seg.lang]\
                                .shortname(self._lang, self._env)[0]
                    fmt_seg = p_("formatting of a foreign language phrase in "
                                 "running HTML text, where the short "
                                 "language name is provided too",
                                 "%(lang)s <em class='frlng'>%(phrase)s</em>") \
                              % dict(lang=self._format_sub(lnode.text),
                                     phrase=self._format_sub(seg))
            elif isinstance(seg, Link):
                phrase = self._format_sub(seg)
                fmt_seg = wtext(phrase, "a", {"class":"ext", "href":seg.url})
            elif isinstance(seg, Text):
                # Any unhandled text type.
                fmt_seg = self._format_sub(seg, pclass)
            else:
                # Must be a string.
                fmt_seg = seg

            fmt_text.append(fmt_seg)

        return "".join(fmt_text)
Exemplo n.º 9
0
def from_file (dgfile, validate=True):
    """
    Construct glossary from a Divergloss file.

    The glossary file may use XInclude to include subdocuments.

    @param dgfile: Divergloss file name
    @type dgfile: string
    @param validate: whether to validate the glossary
    @type validate: bool

    @return: constructed glossary
    @rtype: L{Gnode}
    """

    try:
        # Do not validate at parse time, but afterwards.
        # Must resolve xincludes beforehand.
        parser = etree.XMLParser(dtd_validation=False, remove_comments=True)
        tree = etree.parse(dgfile, parser=parser)
        tree.xinclude()
    except (etree.XMLSyntaxError, etree.XIncludeError), e:
        errlins = "\n".join([str(x) for x in list(e.error_log)])
        error(p_("error message",
                 "XML parsing failed:\n"
                 "%(msg)s") % {"msg":errlins})
Exemplo n.º 10
0
def _res_embsel_best_text (gloss, ntext, env):

    text = copy.copy(ntext)
    text[:] = []
    for seg in ntext:
        if isinstance(seg, Text):
            text.append(_res_embsel_best_text(gloss, seg, env))
        elif isinstance(seg, dict):
            # Try first direct match for environment.
            if env in seg:
                text.append(seg[env])
            else:
                # Try a close environment.
                found_close = False
                if env in gloss.environments:
                    for cenv in gloss.environments[env].closeto:
                        if cenv in seg:
                            text.append(seg[cenv])
                            found_close = True
                            break

                # Take a best shot.
                if not found_close:
                    if env not in gloss.env:
                        warning(p_("warning message",
                                   "no resolution for expected environment "
                                   "'%(env)s' in embedded selector '%(esel)s'")
                                % dict(env=env, esel=seg.unparsed))
                    # Pick at random.
                    text.append(random.choice(seg.values()))
        else:
            text.append(seg)

    return text
Exemplo n.º 11
0
    def add_subcmd (self, subcmd, desc=None):
        """
        Add a subcommand for which the suboptions may be added afterwards.

        Use double-newline in the description for splitting into paragraphs.
        The description can also be set later, using C{set_desc} method of
        subcommand view.

        @param subcmd: subcommand name
        @type subcmd: string
        @param desc: description of the subcommand
        @type desc: string or C{None}

        @return: subcommand view
        @rtype: L{SubcmdView}
        """

        if subcmd in self._scviews:
            error(p_("error message",
                     "trying to add subcommand '%(cmd)s' once again")
                  % dict(cmd=subcmd))

        self._scviews[subcmd] = SubcmdView(self, subcmd, desc)

        return self._scviews[subcmd]
Exemplo n.º 12
0
    def _format_sub (self, text):

        fmt_text = []
        for seg in text:
            if isinstance(seg, Para):
                fmt_seg = self._format_sub(seg) + "\x04\x04"
            elif isinstance(seg, Ref):
                # FIXME: Better way to handle reference?
                fmt_seg = self._format_sub(seg) + "°"
            elif isinstance(seg, Em):
                fmt_seg = p_("formatting of an emphasized phrase in "
                             "running plain text",
                             "*%(phrase)s*") \
                          % dict(phrase=self._format_sub(seg))
            elif isinstance(seg, Ol):
                if not seg.wl:
                    fmt_seg = p_("formatting of a foreign language phrase in "
                                 "running plain text",
                                 "/%(phrase)s/") \
                              % dict(phrase=self._format_sub(seg))
                else:
                    lnode = self._gloss.languages[seg.lang]\
                                .shortname(self._lang, self._env)[0]
                    fmt_seg = p_("formatting of a foreign language phrase in "
                                 "running plain text, where the short "
                                 "language name is provided too",
                                 "%(lang)s /%(phrase)s/") \
                              % dict(lang=self._format_sub(lnode.text),
                                     phrase=self._format_sub(seg))
            elif isinstance(seg, Text):
                # Any unhandled text type.
                fmt_seg = self._format_sub(seg)
            elif isinstance(seg, Link):
                fmt_seg = p_("formatting of a linked phrase "
                             "in running plain text",
                             "%(phrase)s (%(url)s)") \
                          % dict(phrase=self._format_sub(seg), url=seg.url)
            else:
                # Must be a string.
                if self._escape is not None:
                    fmt_seg = self._escape(seg)
                else:
                    fmt_seg = seg

            fmt_text.append(fmt_seg)

        return "".join(fmt_text)
Exemplo n.º 13
0
    def __init__ (self, parent, node=None):

        self.parent = parent

        self.src_line = 0
        self.src_file = p_("an unknown file", "<unknown>")
        if node is not None:
            self.src_line = node.sourceline
Exemplo n.º 14
0
 def fmt_opt (subopt, indent=""):
     s = ""
     s += indent + "  " + subopt
     otype = self._otypes[subopt]
     if otype is bool:
         s += " "*1 + p_("subcommand help: somewhere near the suboption "
                         "name, indicates the suboption is a flag",
                         "[flag]")
     else:
         metavar = self._metavars[subopt]
         if metavar is None:
             metavar = p_("subcommand help: default name for the "
                          "suboptions' parameter; do keep uppercase",
                          "ARG")
         s += ":%s" % metavar
     defval = self._defvals[subopt]
     admvals = self._admvals[subopt]
     if otype is not bool and defval is not None and str(defval):
         cpos = len(s) - s.rfind("\n") - 1
         s += " "*1 + p_("subcommand help: somewhere near the "
                         "suboption name, states the default value "
                         "of its argument",
                         "[default %(arg)s=%(val)s]") \
                      % dict(arg=metavar, val=defval)
         if admvals is not None:
             s += "\n" + (" " * cpos)
     if otype is not bool and admvals is not None:
         avals = self._parent._fmt_admvals(admvals)
         s += " "*1 + p_("subcommand help: somewhere near the "
                         "suboption name, states the admissible values "
                         "for its argument",
                         "[%(arg)s is one of: %(avals)s]") \
                      % dict(arg=metavar, avals=avals)
     s += "\n"
     desc = self._descs[subopt]
     if desc:
         fmt_desc = fmt_wrap(desc, indent + "    ")
         s += fmt_desc
         if "\n\n" in fmt_desc:
             # Wrap current option with empty lines if
             # the description spanned several lines.
             s = "\n" + s + "\n"
     return s
Exemplo n.º 15
0
    def _fmt_admvals (self, admvals, delim=" "):

        lst = []
        for aval in admvals:
            aval_str = str(aval)
            if aval_str != "":
                lst.append(aval_str)
            else:
                lst.append(p_("the name for an empty string as parameter value",
                              "<empty>"))
        return delim.join(lst)
Exemplo n.º 16
0
    def __init__ (self, node=None, tags=None):

        self.src_line = 0
        self.src_file = p_("an unknown file", "<unknown>")
        if node is not None:
            self.src_line = node.sourceline
            # self.src_file = ?

        if tags is None:
            tags = ["para", "ref", "em", "ol", "link"]

        self.extend(_text_segments(node, tags))
Exemplo n.º 17
0
    def _fmt_prologue (self, accl):

        gloss, lang, env = self._gloss, self._lang, self._env
        fle = self._by_langenv_fmt

        accl("<?xml version='1.0' encoding='UTF-8'?>");
        accl(  "<!DOCTYPE martif "
             + "PUBLIC 'ISO 12200:1999A//DTD MARTIF core (DXFcdV04)//EN' "
             + "'TBXcdv04.dtd' "
             + ">");
        accl(  "<!-- "
             + p_('comment in generated files (warning to user)',
                  '===== AUTOGENERATED FILE, DO NOT EDIT =====')
             + " -->")
        accl(stag("martif", {"type":"TBX", "xml:lang":lang}))

        accl(stag("martifHeader"), 1)

        accl(stag("fileDesc"), 2)
        accl(stag("titleStmt"), 3)
        ftitle = fle(gloss.title)
        if not ftitle:
            ftitle = p_("glossary title, when undefined", "Unnamed")
        if env:
            fenv = fle(gloss.environments[env].name)
            if fenv:
                ftitle = p_("glossary title format",
                            "%(title)s (%(env)s)") \
                         % dict(title=ftitle, env=fenv)
        accl(wtext(ftitle, "title"), 4)
        accl(etag("titleStmt"), 3)
        accl(etag("fileDesc"), 2)

        accl(etag("martifHeader"), 1)

        accl(stag("text"), 1)
Exemplo n.º 18
0
    def get_view (self, subcmd):
        """
        The view into previously defined subcommand.

        @param subcmd: subcommand name
        @type subcmd: string

        @return: subcommand view
        @rtype: L{SubcmdView}
        """

        scview = self._scviews.get(subcmd, None)
        if scview is None:
            error(p_("error message",
                     "trying to get a view for an unknown "
                     "subcommand '%(cmd)s'") % dict(cmd=subcmd))
        return scview
Exemplo n.º 19
0
    def _fmt_header (self, accl, lang, title,
                           stylepath=None, dctlpath=None, phpincpath=None):
        """
        If C{phpincpath} is given, then PHP inclusion for it is
        issued in the body, while C{stylepath} and C{dctlpath} are ignored.
        Otherwise, HTML inclusions for C{stylepath} and C{dctlpath} are issued
        in the header (if given themselves).
        """

        if not phpincpath:
            accl("<?xml version='1.0' encoding='UTF-8'?>");
        accl(  "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' "
             + "'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>");
        accl(  "<!-- "
             + p_('comment in generated files (warning to user)',
                  '===== AUTOGENERATED FILE, DO NOT EDIT =====')
             + " -->")

        accl(stag("html", {"xmlns":"http://www.w3.org/1999/xhtml",
                           "lang":lang, "xml:lang":lang}))

        accl(stag("head"), 1)

        accl(stag("meta", {"http-equiv":"Content-type",
                           "content":"text/html; charset=UTF-8"},
                  close=True), 2)

        if not phpincpath:
            if stylepath:
                accl(stag("link", {"rel":"stylesheet", "type":"text/css",
                                   "href":stylepath}, close=True), 2)
            if dctlpath:
                accl(wtext("", "script", {"type":"text/javascript",
                                          "src":dctlpath}), 2)

        accl(wtext(title, "title"), 2)

        accl(etag("head"), 1)

        accl(stag("body"), 1)

        if phpincpath:
            accl("<?php include('%s'); ?>" % phpincpath, 2)

        accl()
Exemplo n.º 20
0
    def subcmd_names (self, pack):
        """
        Names of all the subcommands found in the given category.

        @param pack: subcommand package (one from the constructor bundle)
        @type pack: module

        @return: names of the subcommands found in the package
        @rtype: list of strings
        """

        subcmds = self._subcmds.get(pack, None)
        if subcmds is None:
            error(p_("error message",
                     "requested names of subcommands from an "
                     "unknown category"))
        subcmds.sort()
        return subcmds
Exemplo n.º 21
0
    def subcmd_overview (self, pack, indent="", wcol=79):
        """
        Formatted list with names and short descriptions of all
        the subcommands in the given category.

        @param pack: subcommand package (one from the constructor bundle)
        @type pack: module
        @param indent: indentation for the list
        @type indent: string
        @param wcol: column to wrap text at (<= 0 for no wrapping)
        @type wcol: int

        @return: formatted list
        @rtype: string
        """

        subcmds = self._subcmds.get(pack, None)
        if subcmds is None:
            error(p_("error message",
                     "requested names of subcommands from an "
                     "unknown category"))
        subcmds.sort()

        maxlen = 0
        shdescs = []
        for subcmd in subcmds:
            maxlen = max(maxlen, len(subcmd))
            shdescs.append(self._optparsers[pack].get_view(subcmd).shdesc())

        itfmt = "%%-%ds - %%s" % maxlen # has 3 chars past maxlen
        wr = TextWrapper(initial_indent=indent,
                         subsequent_indent=(indent + " " * (maxlen + 3)),
                         width=wcol)
        flist = "\n".join([wr.fill(itfmt % x) for x in zip(subcmds, shdescs)])

        return flist
Exemplo n.º 22
0
    def help (self, subcmds, wcol=79):
        """
        Formatted help for requested subcommands.

        @param subcmds: subcommand names
        @type subcmds: list of strings
        @param wcol: column to wrap text at (<= 0 for no wrapping)
        @type wcol: int

        @return: formatted help
        @rtype: string
        """

        fmts = []
        for subcmd in subcmds:
            scview = self._scviews.get(subcmd, None)
            if scview is None:
                error(p_("error message",
                         "trying to get help for an unknown "
                         "subcommand '%(cmd)s'") % dict(cmd=subcmd))
            fmts.append(scview.help(wcol))
            fmts.append("")

        return "\n".join(fmts)
Exemplo n.º 23
0
def fill_optparser(parser_view):

    pv = parser_view

    pv.set_desc(p_("subcommand description", "Update rules files for Pology's check-rules sieve."))

    pv.add_subopt(
        "olang",
        str,
        metavar=p_("placeholder for parameter value", "LANGKEY"),
        desc=p_("subcommand option description", "Original language from the rules point of view."),
    )
    pv.add_subopt(
        "tlang",
        str,
        metavar=p_("placeholder for parameter value", "LANGKEY"),
        desc=p_("subcommand option description", "Target language from the rules point of view."),
    )
    pv.add_subopt(
        "file",
        str,
        metavar=p_("placeholder for parameter value", "FILE"),
        desc=p_("subcommand option description", "Rules file to update or create."),
    )
    pv.add_subopt(
        "env",
        str,
        defval="",
        metavar=p_("placeholder for parameter value", "ENVKEY"),
        desc=p_(
            "subcommand option description",
            "Environment for which the rules are updated. " "The glossary default environment is used " "if not given.",
        ),
    )
    pv.add_subopt(
        "benv",
        str,
        defval="",
        metavar=p_("placeholder for parameter value", "ENVKEY"),
        desc=p_("subcommand option description", "Base environment when making hierarchical rules."),
    )
Exemplo n.º 24
0
    def __call__(self, gloss):

        # Resolve languages and environments.
        olang = self._options.olang
        if olang not in gloss.languages:
            error(p_("error message", "origin language '%(lang)s' not present in the glossary") % dict(lang=olang))
        tlang = self._options.tlang
        if tlang not in gloss.languages:
            error(p_("error message", "target language '%(lang)s' not present in the glossary") % dict(lang=tlang))
        env = self._options.env or gloss.env[0]
        if env and env not in gloss.environments:
            error(p_("error message", "environment '%(env)s' not defined by the glossary") % dict(env=env))
        benv = self._options.benv
        if benv and benv not in gloss.environments:
            error(p_("error message", "environment '%(env)s' not defined by the glossary") % dict(env=benv))
        rulefile = self._options.file

        # Formatters for resolving glossary into plain text.
        tft = TextFormatterPlain(gloss, lang=tlang, env=env)
        tdelim = "|"  # to be able to send terms to regex too

        def format_terms(concept, env=env):

            oterms = concept.term(olang, env)
            tterms = concept.term(tlang, env)
            if not oterms or not tterms:
                return None, None

            oterms = [tft(x.nom.text) for x in oterms]
            langsort(oterms, olang)
            otermsall = tdelim.join(oterms)

            tterms = [tft(x.nom.text) for x in tterms]
            langsort(tterms, tlang)
            ttermsall = tdelim.join(tterms)

            return otermsall, ttermsall

        # From concepts which have a term in both langenvs,
        # assemble the data needed to construct rules.
        # Also collect keys of concepts which are shared with
        # the base environment *from the viewpoint of rules*.
        concepts_data = {}
        concepts_shared = set()
        for ckey, concept in gloss.concepts.iteritems():
            oterms, tterms = format_terms(concept)
            if oterms and tterms:
                concepts_data[ckey] = (oterms, tterms)
                if benv:
                    # Concept shared if original/target terminology same.
                    boterms, btterms = format_terms(concept, benv)
                    if oterms == boterms and tterms == btterms:
                        concepts_shared.add(ckey)

        if not concepts_data:
            warning(
                p_(
                    "warning message",
                    "no concepts found for PO view that have terms in both " "the requested origin and target language",
                )
            )

        # Parse rules file.
        rules, rmap, plines, elines = [], {}, [], []
        if os.path.isfile(rulefile):
            rules, rmap, plines, elines = self._load_rules(rulefile)

        # Flag all existing rules.
        for rkey, rule in rmap.iteritems():

            if rkey not in concepts_data:
                rule.set_flag("obsolete")
                continue

            oterms, tterms = concepts_data[rkey]

            if benv and rkey in concepts_shared:
                note = None
                if oterms != rule.oterms or tterms != rule.tterms:
                    note = "%s = %s" % (oterms, tterms)
                rule.set_flag("merge", note)
                continue

            if oterms != rule.oterms or tterms != rule.tterms:
                note = "%s = %s" % (oterms, tterms)
                rule.set_flag("fuzzy", note)
                continue

            if not rule.has_flag("new"):
                rule.set_flag("")

        # Add new rules, in lexicographical order by keys.
        ckeys = concepts_data.keys()
        ckeys.sort()
        last_ins_pos = -1
        for ckey in ckeys:
            if ckey in rmap:
                continue
            if ckey in concepts_shared:
                continue

            nrule = self._Rule()
            nrule.ckey = ckey
            nrule.oterms, nrule.tterms = concepts_data[ckey]
            nrule.disabled = True
            # Add all fields for establishing ordering;
            # some will get their real values on sync.
            if tdelim not in nrule.oterms:
                topmatch = "{\\b%s}" % nrule.oterms
            else:
                topmatch = "{\\b(%s)}" % nrule.oterms
            if nrule.oterms.islower():
                topmatch += "i"
            nrule.lines.append(topmatch)
            nrule.lines.append('id=""')
            nrule.lines.append('hint=""')
            if tdelim not in nrule.tterms:
                valmatch = 'valid msgstr="\\b%s"' % nrule.tterms
            else:
                valmatch = 'valid msgstr="\\b(%s)"' % nrule.tterms
            nrule.lines.append(valmatch)
            nrule.lines.append("disabled")
            nrule.set_flag("new")

            inserted = False
            for i in range(last_ins_pos + 1, len(rules)):
                if ckey < rules[i].ckey:
                    last_ins_pos = i
                    rules.insert(i, nrule)
                    inserted = True
                    break
            if not inserted:
                last_ins_pos = len(rules)
                rules.append(nrule)
            rmap[ckey] = nrule

        # Write rules back.
        ofl = codecs.open(rulefile, "w", "UTF-8")
        ofl.writelines([x + "\n" for x in plines])
        for rule in rules:
            ofl.writelines(rule.format_lines())
        ofl.writelines([x + "\n" for x in elines])
        ofl.close()
Exemplo n.º 25
0
def _post_dtd_check_keys (gloss, gnode):

    _post_dtd_ch_key(gloss, gnode, "lang", gloss.languages,
        p_("error message",
           "attribute '%(att)s' states a non-language key: %(key)s"))

    _post_dtd_ch_keyseq(gloss, gnode, "env", gloss.environments,
        p_("error message",
           "attribute '%(att)s' states non-environment keys: %(keys)s"))

    _post_dtd_ch_key(gloss, gnode, "by", gloss.editors,
        p_("error message",
           "attribute '%(att)s' states a non-editor key: %(key)s"))

    _post_dtd_ch_key(gloss, gnode, "src", gloss.sources,
        p_("error message",
           "attribute '%(att)s' states a non-source key: %(key)s"))

    _post_dtd_ch_key(gloss, gnode, "gr", gloss.grammar,
        p_("error message",
           "attribute '%(att)s' states a non-grammar key: %(key)s"))

    _post_dtd_ch_key(gloss, gnode, "root", gloss.extroots,
        p_("error message",
           "attribute '%(att)s' states a non-root key: %(key)s"))

    _post_dtd_ch_key(gloss, gnode, "c", gloss.concepts,
        p_("error message",
           "attribute '%(att)s' states a non-concept key: %(key)s"))

    _post_dtd_ch_keyseq(gloss, gnode, "closeto", gloss.environments,
        p_("error message",
           "attribute '%(att)s' states non-environment keys: %(keys)s"))

    _post_dtd_ch_keyseq(gloss, gnode, "topic", gloss.topics,
        p_("error message",
           "attribute '%(att)s' states non-topic keys: %(keys)s"))

    _post_dtd_ch_keyseq(gloss, gnode, "level", gloss.levels,
        p_("error message",
           "attribute '%(att)s' states non-level keys: %(keys)s"))

    _post_dtd_ch_keyseq(gloss, gnode, "related", gloss.concepts,
        p_("error message",
           "attribute '%(att)s' states non-concept keys: %(keys)s"))
Exemplo n.º 26
0
    def __call__ (self, gloss):

        # Resolve languages and environment.
        olang = self._options.olang
        if olang not in gloss.languages:
            error(p_("error message",
                     "origin language '%(lang)s' not present in the glossary")
                    % dict(lang=olang))
        tlang = self._options.tlang
        if tlang not in gloss.languages:
            error(p_("error message",
                     "target language '%(lang)s' not present in the glossary")
                    % dict(lang=tlang))
        env = self._options.env or gloss.env[0]
        if env is not None and env not in gloss.environments:
            error(p_("error message",
                     "environment '%(env)s' not defined by the glossary")
                  % dict(env=env))

        # Formatters for resolving glossary into plain text.
        tft = TextFormatterPlain(gloss, lang=tlang, env=env)
        s_desc = p_("message comment in the PO view: "
                    "short label preceeding a concept description",
                    "desc: ")
        cpref = "# "
        tfds = TextFormatterPlain(gloss, lang=tlang, env=env,
                                  first_indent=(cpref + s_desc),
                                  indent=(cpref + " " * len(s_desc)),
                                  wcol=79)
        s_decl = p_("message comment in the PO view: "
                    "short label preceeding a declination",
                    "decl: ")
        tfdl = TextFormatterPlain(gloss, lang=tlang, env=env,
                                  prefix=(cpref + s_decl))

        # Select all concepts which have a term in both langenvs.
        # Collect terms from the origin language for lexicographical ordering.
        concepts = {}
        ordering_links = []
        for ckey, concept in gloss.concepts.iteritems():
            oterms = concept.term(olang, env)
            tterms = concept.term(tlang, env)
            if oterms and tterms:
                concepts[ckey] = concept
                # Use first of the synonymous origin terms for ordering.
                # Must format it to plain text beforehand.
                ordering_links.append((tft(oterms[0].nom.text).lower(), ckey))

        if not concepts:
            warning(p_("warning message",
                       "no concepts found for PO view that have terms in both "
                       "the requested origin and target language"))

        langsort_tuples(ordering_links, 0, olang)

        if self._options.condesc:
            # Collect keys of all concepts which have same terms for different
            # concepts, in either of the languages.
            all_ckeys_by_term = {}
            for ckey, concept in concepts.iteritems():
                aterms = (  concept.term(olang, env)
                          + concept.term(tlang, env))
                for term in aterms:
                    nomstr = tft(term.nom.text)
                    if nomstr not in all_ckeys_by_term:
                        all_ckeys_by_term[nomstr] = []
                    all_ckeys_by_term[nomstr].append(ckey)
            conflicted = {}
            for nomstr, ckeys in all_ckeys_by_term.iteritems():
                if len(ckeys) > 1:
                    for ckey in ckeys:
                        conflicted[ckey] = True

        # Create PO messages by fields.
        class Message:
            def __init__ (self):
                self.comments = []
                self.msgctxt = ""
                self.msgid = ""
                self.msgstr = ""

        tdelim = "|" # delimiter for synonyms in msgid and msgstr

        messages = []
        for ckey in [x[1] for x in ordering_links]:
            concept = concepts[ckey]
            msg = Message()
            messages.append(msg)

            # Origin terms into the msgid.
            oterms = concept.term(olang, env)
            msg.msgid = tdelim.join([tft(x.nom.text) for x in oterms])

            # Target terms into the msgstr.
            tterms = concept.term(tlang, env)
            msg.msgstr = tdelim.join([tft(x.nom.text) for x in tterms])

            # Concept key into the msgctxt.
            msg.msgctxt = ckey

            # Auto comments.
            # - full description (possibly only if there is a term conflict)
            if not self._options.condesc or ckey in conflicted:
                # Give priority to description in target language.
                descs = concept.desc(tlang, env)
                if not descs:
                     descs = concept.desc(olang, env)
                if descs:
                    # Pick only first description if there are several.
                    msg.comments.append(tfds(descs[0].text))
            # - any declensions in target language
            for tterm in tterms:
                for decl in tterm.decl:
                    grn = gloss.grammar[decl.gr].shortname(tlang, env)[0]
                    msg.comments.append(tfdl(grn.text + [" "] + decl.text))

            # TODO: Implement source reference when lxml.etree can extract them.

        # Format PO header for output.
        fmt_header = ""
        s_title = tft(gloss.title(tlang, env)[0].text)
        fmt_header += (  '# '
                       + p_('header comment in the PO view (title)',
                            'PO view of a Divergloss glossary: %(title)s')
                         % dict(title=s_title)
                       + '\n')
        s_olang = tft(gloss.languages[olang].name(tlang, env)[0].text)
        s_tlang = tft(gloss.languages[tlang].name(tlang, env)[0].text)
        if env:
            s_env = tft(gloss.environments[env].name(tlang, env)[0].text)
            hcmnt = p_('header comment in the PO view (subtitle)',
                       'languages: %(ol)s->%(tl)s, environment: %(env)s') \
                    % dict(ol=s_olang, tl=s_tlang, env=s_env)
        else:
            hcmnt = p_('header comment in the PO view (subtitle)',
                       'languages: %(ol)s->%(tl)s') \
                    % dict(ol=s_olang, tl=s_tlang)
        fmt_header += (  '# '
                       + hcmnt
                       + '\n')
        fmt_header += (  '# '
                       + p_('comment in generated files (warning to user)',
                            '===== AUTOGENERATED FILE, DO NOT EDIT =====')
                       + '\n')
        fmt_header += 'msgid ""\n'
        fmt_header += 'msgstr ""\n'
        fmt_header += '"Project-Id-Version: %s\\n"\n' % gloss.id
        fmt_header += '"POT-Creation-Date: %s\\n"\n' % time.strftime("%F %R%z")
        fmt_header += '"PO-Revision-Date: %s\\n"\n' % time.strftime("%F %R%z")
        fmt_header += '"Last-Translator: n/a\\n"\n'
        fmt_header += '"Language-Team: n/a\\n"\n'
        fmt_header += '"MIME-Version: 1.0\\n"\n'
        fmt_header += '"Content-Type: text/plain; charset=UTF-8\\n"\n'
        fmt_header += '"Content-Transfer-Encoding: 8bit\\n"\n'

        # Format PO messages for output.
        def poescape (s):
            return s.replace('\n', '\\n').replace('"', '\\"')

        fmt_messages = []
        for msg in messages:
            fmt_msg = ''
            if msg.comments:
                fmt_msg += '\n'.join(msg.comments) + '\n'
            fmt_msg += 'msgctxt "%s"\n' % poescape(msg.msgctxt)
            fmt_msg += 'msgid "%s"\n' % poescape(msg.msgid)
            fmt_msg += 'msgstr "%s"\n' % poescape(msg.msgstr)
            fmt_messages.append(fmt_msg)

        # Output formatted concepts to requested stream.
        outf = sys.stdout
        if self._options.file:
            outf = open(self._options.file, "w")

        outf.write(fmt_header + "\n")
        outf.write("\n".join(fmt_messages) + "\n")

        if outf is not sys.stdout:
            outf.close()
Exemplo n.º 27
0
    def help (self, wcol=79):
        """
        Formatted help for the subcommand.

        @param wcol: column to wrap text at (<= 0 for no wrapping)
        @type wcol: int

        @return: formatted help
        @rtype: string
        """

        # Split parameters into mandatory and optional.
        m_subopts = []
        o_subopts = []
        for subopt in self._ordered:
            if self._defvals[subopt] is None:
                m_subopts.append(subopt)
            else:
                o_subopts.append(subopt)

        # Format output.

        def fmt_wrap (text, indent=""):
            wrapper = TextWrapper(initial_indent=indent,
                                  subsequent_indent=indent,
                                  width=wcol)
            paras = text.split("\n\n")
            fmtparas = []
            for para in paras:
                fmtparas.append(wrapper.fill(para))
            return "\n\n".join(fmtparas)

        def fmt_opt (subopt, indent=""):
            s = ""
            s += indent + "  " + subopt
            otype = self._otypes[subopt]
            if otype is bool:
                s += " "*1 + p_("subcommand help: somewhere near the suboption "
                                "name, indicates the suboption is a flag",
                                "[flag]")
            else:
                metavar = self._metavars[subopt]
                if metavar is None:
                    metavar = p_("subcommand help: default name for the "
                                 "suboptions' parameter; do keep uppercase",
                                 "ARG")
                s += ":%s" % metavar
            defval = self._defvals[subopt]
            admvals = self._admvals[subopt]
            if otype is not bool and defval is not None and str(defval):
                cpos = len(s) - s.rfind("\n") - 1
                s += " "*1 + p_("subcommand help: somewhere near the "
                                "suboption name, states the default value "
                                "of its argument",
                                "[default %(arg)s=%(val)s]") \
                             % dict(arg=metavar, val=defval)
                if admvals is not None:
                    s += "\n" + (" " * cpos)
            if otype is not bool and admvals is not None:
                avals = self._parent._fmt_admvals(admvals)
                s += " "*1 + p_("subcommand help: somewhere near the "
                                "suboption name, states the admissible values "
                                "for its argument",
                                "[%(arg)s is one of: %(avals)s]") \
                             % dict(arg=metavar, avals=avals)
            s += "\n"
            desc = self._descs[subopt]
            if desc:
                fmt_desc = fmt_wrap(desc, indent + "    ")
                s += fmt_desc
                if "\n\n" in fmt_desc:
                    # Wrap current option with empty lines if
                    # the description spanned several lines.
                    s = "\n" + s + "\n"
            return s

        ls = []
        if not self._parent._category:
            ls += ["  " + p_("subcommand help: header", "%(cmd)s")
                          % dict(cmd=self._subcmd)]
        else:
            ls += ["  " + p_("subcommand help: header", "%(cmd)s (%(cat)s)")
                          % dict(cmd=self._subcmd, cat=self._parent._category)]
        ls += ["  " + "=" * len(ls[-1].strip())]
        if self._desc:
            ls += [fmt_wrap(self._desc, "    ")]

        if m_subopts:
            ls += [""]
            ls += ["  " + p_("subcommand help: header",
                             "Mandatory parameters:")]
            for subopt in m_subopts:
                ls += [fmt_opt(subopt, "  ")]

        if o_subopts:
            ls += [""]
            ls += ["  " + p_("subcommand help: header",
                             "Optional parameters:")]
            for subopt in o_subopts:
                ls += [fmt_opt(subopt, "  ")]

        return "\n".join(ls)
Exemplo n.º 28
0
    def add_subopt (self, subopt, otype,
                    defval=None, admvals=None, metavar=None,
                    multival=False, seplist=False, desc=None):
        """
        Define a suboption.

        Different subcommands handled by the same parser share the semantics
        of a same-named option. This means the option type must be the same
        across subcommands, while its default value and descriptive elements
        may differ.

        If default value is C{None}, it means the option is mandatory.
        If option type is boolean, then the default value has a special
        meaning: the option is always given without an argument (a flag),
        and its value will become be negation of the default.

        Option can also be used to collect a list of values, in two ways,
        or both combined. One is by repeating the option several times
        with different values, and another by a single option value itself
        being a comma-separated list of values (in which case the values are
        parsed into elements of requested type).
        For such options the default value should be a list too (or None).

        Use double-newline in the description for splitting into paragraphs.

        @param subopt: option name
        @type subopt: string
        @param otype: type of the expected argument
        @type otype: type
        @param defval: default value for the argument
        @type defval: instance of C{otype} or C{None}
        @param admvals: admissible values for the argument
        @type admvals: list of C{otype} elements or C{None}
        @param metavar: name for option's value
        @type metavar: string or C{None}
        @param multival: whether option can be repeated to have list of values
        @type multival: bool
        @param seplist: whether option is a comma-separated list of values
        @type seplist: bool
        @param desc: description of the option
        @type desc: string or C{None}
        """

        islist = multival or seplist

        if defval is not None and not islist and not isinstance(defval, otype):
            error(p_("error message",
                     "trying to add suboption '%(opt)s' to "
                     "subcommand '%(cmd)s' with default value '%(val)s' "
                     "different from its stated type '%(type)s'")
                  % dict(opt=subopt, cmd=self._subcmd, val=defval, type=otype))

        if defval is not None and islist and not _isinstance_els(defval, otype):
            error(p_("error message",
                     "trying to add suboption '%(opt)s' to "
                     "subcommand '%(cmd)s' with default value '%(val)s' "
                     "which contains some elements different from their "
                     "stated type '%(type)s'")
                  % dict(opt=subopt, cmd=self._subcmd, val=defval, type=otype))

        if defval is not None and admvals is not None and defval not in admvals:
            error(p_("error message",
                     "trying to add suboption '%(opt)s' to "
                     "subcommand '%(cmd)s' with default value '%(val)s' "
                     "not from the admissible set: %(avals)s")
                  % dict(opt=subopt, cmd=self._subcmd, val=defval,
                         avals=self._parent._fmt_admvals(admvals)))

        if subopt in self._otypes:
            error(p_("error message",
                     "trying to add suboption '%(opt)s' to subcommand "
                     "'%(cmd)s' once again")
                  % dict(opt=subopt, cmd=self._subcmd))

        if islist and not isinstance(defval, (type(None), tuple, list)):
            error(p_("error message",
                     "suboption '%(opt)s' to subcommand '%(cmd)s' "
                     "stated to be list-valued, but the default value "
                     "is not given as a list")
                  % dict(opt=subopt, cmd=self._subcmd))

        general_otype = None
        general_islist = None
        for scview in self._parent._scviews.itervalues():
            general_otype = scview._otypes.get(subopt, None)
            general_islist = (   scview._multivals.get(subopt, None)
                              or scview._seplists.get(subopt, None))

        cat = self._parent._category

        if general_otype is not None and otype is not general_otype:
            if cat:
                error(p_("error message",
                         "trying to add suboption '%(opt)s' to "
                         "subcommand '%(cmd)s' with a type different from "
                         "other subcommands in the category '%(cat)s'")
                      % dict(opt=subopt, cmd=self._subcmd, cat=cat))
            else:
                error(p_("error message",
                         "trying to add suboption '%(opt)s' to "
                         "subcommand '%(cmd)s' with a type different from "
                         "other subcommands")
                      % dict(opt=subopt, cmd=self._subcmd))

        if general_islist is not None and islist is not general_islist:
            if cat:
                error(p_("error message",
                         "trying to add suboption '%(opt)s' to "
                         "subcommand '%(cmd)s' with a list-indicator different "
                         "from other subcommands in the category '%(cat)s'")
                      % dict(opt=subopt, cmd=self._subcmd, cat=cat))
            else:
                error(p_("error message",
                         "trying to add suboption '%(opt)s' to "
                         "subcommand '%(cmd)s' with a list-indicator different "
                         "from other subcommands")
                      % dict(opt=subopt, cmd=self._subcmd))


        self._otypes[subopt] = otype
        self._defvals[subopt] = defval
        self._admvals[subopt] = admvals
        self._metavars[subopt] = metavar
        self._multivals[subopt] = multival
        self._seplists[subopt] = seplist
        self._descs[subopt] = desc

        self._ordered.append(subopt)
Exemplo n.º 29
0
    def make_subcmds (self, subcmd_init_bundle, cmdline_options=None):
        """
        Create subcommand objects and parse and route parameters to them.

        After the client has parsed its command line, collected the names
        of issued subcommands and the inbound parameters (specified by
        the collector-options), it calls this function to create the
        subcommands.

        The initialization bundle is a list of tuples. Each tuple states
        the subcommand package of the issued subcommands, list of subcommand
        names from that package, and the raw parameters for those subcommands
        (list of arguments from the collector-option)::

            subcmds = sch.init_subcmds(
                [(subcmds.foo, # package
                  ["foo-alpha", "foo-beta"], # subcommand names
                  ["fpar1", "fpar2:val", "fpar3:val"]), # raw parameters
                 (subcmds.bar,
                  ["bar-sierra"],
                  ["bpar1", "bpar2:val"])])

        The packages given here must be a subset of those that were given
        to the constructor, and subcommands a subset of those that the
        constructor found inside the packages.

        If everything goes well -- all subcommands exist, no parameter errors --
        then the subcommand objects are created from the subcommand modules,
        and returned in a list of lists, according to the ordering of subcommand
        names in the initialization bundle.

        All options that the main command received, in the form of object with
        attributes (e.g. as created by C{optparse.OptionParser}) may also
        be routed to the subcommands if desired. This may be useful for
        subcommands to heed standard options like quiet, verbose, etc.

        @param subcmd_init_bundle: subcommand initialization bundle
        @type subcmd_init_bundle: list of tuples
        @param cmdline_options: global options
        @type cmdline_options: object

        @return: subcommand object
        @rtype: list of lists
        """

        scobjs = []

        for pack, subcmds, rawopts in subcmd_init_bundle:

            if pack not in self._packs:
                error(p_("error message",
                         "requested unknown category of subcommands"))

            # Parse options in this category.
            optparser = self._optparsers[pack]
            subopts = optparser.parse(rawopts, subcmds)

            # Create subcommand objects in this category.
            mods = self._mods[pack]
            scobjs.append([])
            for subcmd in subcmds:
                sc = mods[subcmd].Subcommand(subopts[subcmd], cmdline_options)
                scobjs[-1].append(sc)

        return scobjs
Exemplo n.º 30
0
    def parse (self, rawopts, subcmds):
        """
        Parse the list of suboptions collected from the command line.

        If the command line had suboptions specified as::

            -sfoo -sbar:xyz -sbaz:10

        then the function call should get the list::

            rawopts=['foo', 'bar:xyz', 'baz:10']

        Result of parsing will be a dictionary of objects by subcommand name,
        where each object has attributes named like subcommand options.
        If an option name is not a valid identifier name by itself,
        it will be normalized by replacing all troublesome characters with
        an underscore, collapsing contiguous underscore sequences to a single
        underscore, and prepending an 'x' if it does not start with a letter.

        If an option is parsed which is not accepted by any of the given
        subcommands, an error is signaled.

        @param rawopts: raw suboptions
        @type rawopts: list of strings
        @param subcmds: names of issued subcommands
        @type subcmds: list of strings

        @return: objects with options as attributes
        @rtype: dict of objects by subcommand name
        """

        # Assure only registered subcommands have been issued.
        for subcmd in subcmds:
            if subcmd not in self._scviews:
                error(p_("error in command line (subcommand)",
                         "unregistered subcommand '%(cmd)s' issued")
                      % dict(cmd=subcmd))

        # Parse all given parameters and collect their values.
        subopt_vals = dict([(x, {}) for x in subcmds])
        for opstr in rawopts:
            lst = opstr.split(":", 1)
            lst += [None] * (2 - len(lst))
            subopt, strval = lst

            if subopt in subopt_vals and not scview._multivals[subopt]:
                error(p_("error in command line (subcommand)",
                         "parameter '%(par)s' repeated more than once")
                       % dict(par=subopt))

            subopt_accepted = False
            for subcmd in subcmds:
                scview = self._scviews[subcmd]
                if subopt not in scview._otypes:
                    # Current subcommand does not have this option, skip.
                    continue

                otype = scview._otypes[subopt]
                if otype is bool and strval is not None:
                    error(p_("error in command line (subcommand)",
                             "parameter '%(par)s' is a flag, no value expected")
                          % dict(par=subopt))

                val = scview._defvals[subopt]
                if otype is bool:
                    val = not val

                if strval is not None:
                    if not scview._seplists[subopt]:
                        try:
                            val = otype(strval)
                        except:
                            error(p_("error in command line (subcommand)",
                                     "cannot convert value '%(val)s' to "
                                     "parameter '%(par)s' into expected "
                                     "type '%(type)s'")
                                  % dict(val=strval, par=subopt, type=otype))
                        val_lst = [val]
                    else:
                        tmplst = strval.split(",")
                        try:
                            val = [otype(x) for x in tmplst]
                        except:
                            error(p_("error in command line (subcommand)",
                                     "cannot convert value '%(val)s' to "
                                     "parameter '%(par)s' into list of "
                                     "elements of expected type '%(type)s'")
                                  % dict(val=strval, par=subopt, type=otype))
                        val_lst = val

                # Assure admissibility of option values.
                admvals = scview._admvals[subopt]
                if admvals is not None:
                    for val in val_lst:
                        if val not in admvals:
                            avals = self._fmt_admvals(admvals)
                            error(p_("error in command line (subcommand)",
                                     "value '%(val)s' to parameter '%(par)s' "
                                     "not from the admissible set: %(avals)s")
                                  % dict(val=strval, par=subopt, avals=avals))

                subopt_accepted = True
                if scview._multivals[subopt] or scview._seplists[subopt]:
                    if subopt not in subopt_vals[subcmd]:
                        subopt_vals[subcmd][subopt] = []
                    subopt_vals[subcmd][subopt].extend(val_lst)
                else:
                    subopt_vals[subcmd][subopt] = val

            if not subopt_accepted:
                error(p_("error in command line (subcommand)",
                         "parameter '%(par)s' not expected in any of the "
                         "issued subcommands") % dict(par=subopt))


        # Assure that all mandatory parameters have been supplied to each
        # issued subcommand, and set defaults for all optional parameters.
        for subcmd in subcmds:
            scview = self._scviews[subcmd]

            for subopt in scview._otypes:
                if subopt in subopt_vals[subcmd]:
                    # Option explicitly given, skip.
                    continue

                defval = scview._defvals[subopt]
                if defval is None:
                    error(p_("error in command line (subcommand)",
                             "mandatory parameter '%(par)s' to subcommand "
                             "'%(cmd)s' not given")
                          % dict(par=subopt, cmd=subcmd))

                subopt_vals[subcmd][subopt] = defval

        # Create dictionary of option objects.
        class SuboptsTemp (object): pass
        opts = {}
        for subcmd in subcmds:
            opts[subcmd] = SuboptsTemp()
            for subopt, val in subopt_vals[subcmd].iteritems():
                # Construct valid attribute name out option name.
                to_attr_rx = re.compile(r"[^a-z0-9]+", re.I|re.U)
                attr = to_attr_rx.sub("_", subopt)
                if not attr[:1].isalpha():
                    attr = "x" + attr
                opts[subcmd].__dict__[attr] = val

        return opts