コード例 #1
0
ファイル: subcmd.py プロジェクト: caslav-ilic/divergloss
    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]
コード例 #2
0
ファイル: construct.py プロジェクト: happyaron/glossar
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})
コード例 #3
0
ファイル: tbx.py プロジェクト: caslav-ilic/divergloss
    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)
コード例 #4
0
ファイル: construct.py プロジェクト: happyaron/glossar
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})
コード例 #5
0
ファイル: subcmd.py プロジェクト: caslav-ilic/divergloss
    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
コード例 #6
0
ファイル: subcmd.py プロジェクト: caslav-ilic/divergloss
    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
コード例 #7
0
ファイル: subcmd.py プロジェクト: caslav-ilic/divergloss
    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
コード例 #8
0
ファイル: subcmd.py プロジェクト: caslav-ilic/divergloss
    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)
コード例 #9
0
ファイル: subcmd.py プロジェクト: caslav-ilic/divergloss
    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
コード例 #10
0
ファイル: subcmd.py プロジェクト: caslav-ilic/divergloss
    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)
コード例 #11
0
ファイル: subcmd.py プロジェクト: caslav-ilic/divergloss
    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
コード例 #12
0
ファイル: subcmd.py プロジェクト: caslav-ilic/divergloss
    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
コード例 #13
0
ファイル: dgproc.py プロジェクト: caslav-ilic/divergloss
def main ():

    # Use Psyco specializing compiler if available.
    try:
        import psyco
        psyco.full()
    except ImportError:
        pass

    reload(sys)
    cmdlenc = locale.getdefaultlocale()[1]
    sys.setdefaultencoding(cmdlenc)

    # Setup options and parse the command line.
    usage = p_("command usage",
               "%(cmd)s [OPTIONS] [SIEVES] DGFILE") % dict(cmd="%prog")
    description = p_("command description",
                     "Query a Divergloss XML document and "
                     "build various outputs. "
                     "Also fully validates the document, "
                     "past what the DTD only can do.")
    version = p_("command version",
                 "%(cmd)s experimental\n"
                 "Copyright 2008, Chusslove Illich <*****@*****.**>") \
              % dict(cmd="%prog")

    opars = OptionParser(usage=usage, description=description, version=version)
    opars.add_option(
        "--no-check",
        action="store_false", dest="check", default=True,
        help=p_("description of cmdline option",
                "do not check the glossary for validity"))
    opars.add_option(
        "-s", "--sieve-par",
        metavar=p_("placeholder for value to cmdline option", "PARSPEC"),
        dest="sieve_par", action="append", default=[],
        help=p_("description of cmdline option",
                "specify parameter to sieves"))
    opars.add_option(
        "-S", "--list-sieves",
        action="store_true", dest="list_sieves", default=False,
        help=p_("description of cmdline option",
                "list available sieves and exit"))
    opars.add_option(
        "-H", "--help-sieves",
        action="store_true", dest="help_sieves", default=False,
        help=p_("description of cmdline option",
                "display help on sieves and exit"))
    (options, free_args) = opars.parse_args()

    # Register subcommands.
    schandler = dg.subcmd.SubcmdHandler([(dg.sieve, None)])

    if len(free_args) > 2:
        error(p_("error in command line", "too many free arguments"))

    # If any subcommand listing required, show and exit.
    if options.list_sieves:
        print p_("header to listing", "Available sieves:")
        print schandler.subcmd_overview(dg.sieve, indent="  ")
        sys.exit(0)

    # Collect sieves and glossary file.
    if not options.help_sieves:
        if len(free_args) < 1:
            error(p_("error in command line", "no file given"))
        dgfile = free_args.pop()
        if not os.path.isfile(dgfile):
            error(p_("error in command line",
                     "file '%(file)s' does not exists") % dict(file=dgfile))
    else:
        free_args = free_args[:1]

    # Parse sieve names.
    sieve_names = []
    if free_args:
        sievespec = free_args.pop()
        sieve_names = [x for x in sievespec.split(",")]

    # If help on subcommands required, show and exit.
    if options.help_sieves:
        if sieve_names:
            print p_("header to listing", "Help on sieves:")
            print
            print schandler.help([(dg.sieve, sieve_names)])
        else:
            print p_("message", "No sieves specified to provide help on.")
        sys.exit(0)

    # Create subcommands.
    sieves = schandler.make_subcmds(
        [(dg.sieve, sieve_names, options.sieve_par)],
        options)[0]

    # Construct the glossary.
    gloss = dg.construct.from_file(dgfile, validate=options.check)

    # Sieve the glossary.
    for sieve in sieves:
        ret = sieve(gloss)
        if ret is not None:
            gloss = ret
コード例 #14
0
ファイル: po.py プロジェクト: caslav-ilic/divergloss
    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()
コード例 #15
0
ファイル: construct.py プロジェクト: happyaron/glossar
        errlins = "\n".join([str(x) for x in list(e.error_log)])
        error(p_("error message",
                 "XML parsing failed:\n"
                 "%(msg)s") % {"msg":errlins})

    if validate:
        # Work around a bug: non-unique identifiers do not produce any
        # message when validation fails.
        ids = tree.xpath("//*/@id")
        iddict = {}
        for id in ids:
            if id in iddict:
                # Keep the message format same as below, just report ids.
                error(p_("error message",
                         "DTD validation failed:\n"
                         "%(msg)s") % {"msg":p_("error message",
                                                "duplicate ID '%(id)s'")
                                             % {"id": id}})
            iddict[id] = True

        # Resolve the DTD file and validate the tree according to it.
        # FIXME: Better determination of dtd file (by public ID, etc.)
        if tree.docinfo.system_url:
            dtdname = tree.docinfo.system_url
        else:
            # Fallback to latest DTD.
            dtdname = "divergloss.dtd"
        dtdfile = os.path.join(_dtd_dir, dtdname)
        dtd = etree.DTD(dtdfile)
        if not dtd.validate(tree):
            errlins = "\n".join([str(x) for x in list(dtd.error_log)])
コード例 #16
0
ファイル: html_bidict.py プロジェクト: caslav-ilic/divergloss
    def __call__ (self, gloss):

        self._indent = "  "

        # 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))

        # Select all concepts which have a term in both langenvs.
        concepts = {}
        for ckey, concept in gloss.concepts.iteritems():
            if concept.term(olang, env) and concept.term(tlang, env):
                concepts[ckey] = concept
        if not concepts:
            warning(p_("warning message",
                       "no concepts found which have terms in both "
                       "the origin and the target language and environment"))

        # Prepare text formatters.
        refbase = dict([(ckey, "") for ckey in concepts])
        tfn = TextFormatterPlain(gloss, lang=tlang, env=env)
        tf = TextFormatterHtml(gloss, lang=tlang, env=env, refbase=refbase)
        tfp = TextFormatterHtml(gloss, lang=tlang, env=env, refbase=refbase,
                                wtag="p")

        # Dictionary is presented as follows:
        # - all unique terms in the origin language presented
        # - for each unique origin term, all corresponding unique terms
        #   in the target language presented
        # - for each unique (origin, target) term pair, the descriptions of
        #   all concepts named by it are presented in the target language

        # Collect dict(oterm: dict(tterm: set(ckey)))
        # Collect dict(tterm: dict(gr: set(decl)))
        tdecls = {}
        bidict = {}
        for ckey, concept in concepts.iteritems():
            oterms = concept.term(olang, env)
            tterms = concept.term(tlang, env)
            for oterm in oterms:
                otnom = tfn(oterm.nom.text)
                if otnom not in bidict:
                    bidict[otnom] = {}
                for tterm in tterms:
                    # Target terms.
                    ttnom = tfn(tterm.nom.text)
                    if ttnom not in bidict[otnom]:
                        bidict[otnom][ttnom] = set()
                    bidict[otnom][ttnom].add(ckey)

                    # Declensions.
                    if ttnom not in tdecls:
                        tdecls[ttnom] = {}
                    for decl in tterm.decl:
                        gr = gloss.grammar[decl.gr]
                        grnam = tfn(gr.shortname(tlang, env)[0].text)
                        if grnam not in tdecls[ttnom]:
                            tdecls[ttnom][grnam] = set()
                        ttdecl = tfn(decl.text)
                        tdecls[ttnom][grnam].add(ttdecl)

        # Alphabetically sort origin terms.
        oterms_sorted = bidict.keys()
        langsort(oterms_sorted, olang)

        # Compose the dictionary table.
        accl = LineAccumulator(self._indent, 2)

        accl(stag("table", {"class":"bd-table"}))
        accl()

        # Header.
        accl(stag("tr", {"class":"bd-header"}), 1)
        olname = tfn(gloss.languages[olang].name(tlang, env)[0].text)
        accl(wtext(olname, "th", {"class":"bd-header-ol"}), 2)
        tlname = tfn(gloss.languages[tlang].name(tlang, env)[0].text)
        accl(wtext(tlname, "th", {"class":"bd-header-tl"}), 2)
        accl(etag("tr"), 1)

        # Entries by origin term.
        anchored = {}
        n_entry = 0
        n_entry_by_alpha = 0
        curr_alpha = None
        for oterm in oterms_sorted:
            n_entry += 1
            n_entry_by_alpha += 1

            # Add new alphabetical separator if needed.
            prev_alpha = curr_alpha
            curr_alpha = _term_alpha(oterm)
            if prev_alpha != curr_alpha:
                n_entry_by_alpha = 1
                accl(stag("tr", {"class":"bd-alsep"}), 1)
                accl(wtext(curr_alpha, "td", {"class":"bd-alsep-al",
                                              "colspan":"2"}), 2)
                accl(etag("tr"), 1)

            # Collapse all target terms which have same concepts.
            # Sort them alphabetically within the group,
            # then groups alphabetically by first term in the group.
            tterms_by_ckeygr = {}
            for tterm in bidict[oterm]:
                ckeys = list(bidict[oterm][tterm])
                ckeys.sort()
                ckeygr = tuple(ckeys)
                if ckeygr not in tterms_by_ckeygr:
                    tterms_by_ckeygr[ckeygr] = []
                tterms_by_ckeygr[ckeygr].append(tterm)
            tterms_groups = []
            for ckeys, tterms in tterms_by_ckeygr.iteritems():
                langsort(tterms, tlang)
                tterms_groups.append((tterms[0], tterms, ckeys))
            langsort_tuples(tterms_groups, 0, tlang)
            tterms_ckeys = [x[1:] for x in tterms_groups]

            if n_entry_by_alpha % 2 == 1:
                accl(stag("tr", {"class":"bd-entry-odd"}), 1)
            else:
                #accl(stag("tr", {"class":"bd-entry-even"}), 1)
                #... provide as option; randomly increases VCS deltas.
                accl(stag("tr", {"class":"bd-entry-odd"}), 1)

            # Column with origin term and anchors.
            accl(stag("td", {"class":"bd-oterm"}), 2)

            # Dummy anchors, for cross-references in descriptions to work.
            # Add anchors for all concepts covered by this entry,
            # and remember them, to avoid duplicate anchors on synonyms.
            new_ckeys = []
            for tterms, ckeys in tterms_ckeys:
                for ckey in ckeys:
                    if ckey not in anchored:
                        anchored[ckey] = True
                        new_ckeys.append(ckey)
            accl("".join([stag("span", {"id":x}, close=True)
                          for x in new_ckeys]), 3)

            # Origin term.
            accl(wtext(oterm, "p", {"class":"bd-otline"}), 3)
            accl(etag("td"), 2)

            # Column with target terms.
            accl(stag("td", {"class":"bd-tterms"}), 2)

            n_ttgr = 0
            for tterms, ckeys in tterms_ckeys:
                n_ttgr += 1
                accl(stag("div", {"class":"bd-ttgroup"}), 3)

                # Equip each term with extra info.
                tterms_compgr = []
                for tterm in tterms:
                    # Declensions.
                    lsep_dc = p_("list separator: "
                                 "acceptable variants of the same declension",
                                 ", ")
                    fmt_dcgr = p_("declension group: single declension given "
                                  "by its name and acceptable variants",
                                  "<i>%(dname)s</i> %(dvars)s")
                    lsep_gr = p_("list separator: "
                                 "declension groups",
                                 "; ")
                    tdecl = None
                    if tterm in tdecls:
                        lst = []
                        for gr, decls in tdecls[tterm].iteritems():
                            lst2 = list(decls)
                            langsort(lst2, tlang)
                            lst.append((gr, lsep_dc.join(lst2)))
                        langsort_tuples(lst, 0, tlang)
                        tdecl = lsep_gr.join([fmt_dcgr % dict(dname=x[0],
                                                              dvars=x[1])
                                              for x in lst])
                    # Compose.
                    if tdecl:
                        ttcgr = p_("term with declensions",
                                   "%(term)s (%(decls)s)") \
                                % dict(term=tterm, decls=tdecl)
                    else:
                        ttcgr = tterm
                    tterms_compgr.append(ttcgr)

                # Collect details for each term.
                has_details = False
                # - descriptions
                descstrs = []
                for ckey in ckeys:
                    for desc in concepts[ckey].desc(tlang, env):
                        if tfn(desc.text):
                            descstrs.append(tfp(desc.text, pclass="bd-desc"))
                            has_details = True
                if len(descstrs) > 1:
                    for i in range(len(descstrs)):
                        dhead = "%d. " % (i + 1)
                        descstrs[i] = descstrs[i].replace(">", ">" + dhead, 1)

                # Entry display control (if any details present).
                details_id = "opt_%s_%d" % (oterm.replace(" ", "_"), n_ttgr)
                if has_details:
                    accl(stag("div", {"class":"bd-edctl"}), 4)
                    accl(wtext("[+]", "a",
                               {"class":"bd-edctl",
                                "title":p_("tooltip", "Show details"),
                                "href":"#",
                                "onclick":"return show_hide(this, '%s')"
                                          % details_id}), 5)
                    accl(etag("div"), 4)

                # Line with terms.
                lsep_tt = p_("list separator: synonymous terms",
                             ", ")
                ttstr = lsep_tt.join(tterms_compgr)
                if len(tterms_ckeys) > 1:
                    ttstr = p_("enumerated target term in the dictionary, "
                               "one of the meanings of the original term",
                               "%(num)d. %(term)s") \
                            % dict(num=n_ttgr, term=ttstr)
                accl(wtext(ttstr, "p", {"class":"bd-ttline"}), 4)

                # Optional details.
                if has_details:
                    accl(stag("div", {"id":details_id,
                                      "style":"display: none;"}), 4)

                    for descstr in descstrs:
                        accl(descstr, 5)

                    accl(etag("div"), 4)

                accl(etag("div"), 3)

            accl(etag("td"), 2)
            accl(etag("tr"), 1)
            accl()

        accl(etag("table"))
        accl()

        # Prepare style file path.
        stylepath = None
        if self._options.style:
            if self._options.cssfile:
                stylepath = self._options.cssfile
            else:
                stylepath = _replace_ext(os.path.basename(self._options.file),
                                         "css")
            stylepath_nr = os.path.join(os.path.dirname(self._options.file),
                                        stylepath)
            stylesrc = os.path.join(  _src_style_dir, self._options.style
                                    + ".css.in")

        # Prepare JavaScript file path.
        dctlpath = None
        if self._options.jsfile:
            dctlpath = self._options.jsfile
        else:
            dctlpath = _replace_ext(os.path.basename(self._options.file), "js")
        dctlpath_nr = os.path.join(os.path.dirname(self._options.file),
                                   dctlpath)

        # Prepare PHP inclusion file path.
        phpincpath = None
        if self._options.incfile:
            phpincpath = self._options.incfile
        else:
            phpincpath = _replace_ext(os.path.basename(self._options.file),
                                      "inc")
        phpincpath_nr = os.path.join(os.path.dirname(self._options.file),
                                     phpincpath)

        # If style requested, fetch the .in file and resolve placeholders.
        if self._options.style:
            # Parse values given in the command line.
            stodict = dict([x[:2] for x in _styleopt_spec])
            for sopt in self._options.styleopt:
                lst = [x.strip() for x in sopt.split("=", 1)]
                if len(lst) < 2:
                    warning(p_("warning message",
                               "malformed CSS style option '%(opt)s'")
                            % dict(opt=sopt))
                    continue
                name, value = lst
                if name not in stodict:
                    warning(p_("warning message",
                               "unknown CSS style option '%(opt)s'")
                            % dict(opt=sopt))
                    continue
                stodict[name] = value

            # Replace placeholders in the input style sheet.
            raccl = LineAccumulator()
            raccl.read(stylesrc)
            styleaccl = LineAccumulator()
            sto_rx = re.compile("@(\w+)@")
            for line in raccl.lines:
                nline = ""
                lastpos = 0
                for m in sto_rx.finditer(line):
                    nline += line[lastpos:m.span()[0]]
                    lastpos = m.span()[1]
                    soname = m.group(1)
                    sovalue = stodict.get(soname)
                    if soname not in stodict:
                        error(p_("error message",
                                 "unknown CSS style option '%(opt)s' "
                                 "requested by the input style sheet "
                                 "'%(fname)s'")
                              % dict(opt=soname, fname=stylesrc))
                    nline += sovalue
                nline += line[lastpos:]
                styleaccl(nline)

        # Create separate CSS and JS files, or raw inclusion file,
        # or collect everything for direct embedding.
        auxaccl = None
        if not self._options.phpinc and not self._options.allinone:
            shutil.copyfile(_src_dctl_file, dctlpath_nr)
            if self._options.style:
                styleaccl.write(stylepath_nr)
            phpincpath = None # _fmt_header checks this for what to include
        else:
            raccl = LineAccumulator()
            raccl("<script type='text/javascript'>")
            raccl.read(_src_dctl_file)
            raccl("</script>")
            raccl()
            if self._options.style:
                raccl("<style type='text/css'>")
                raccl(styleaccl)
                raccl("</style>")
                raccl()
            if not self._options.allinone:
                raccl.write(phpincpath_nr)
            else:
                auxaccl = raccl

        # Header.
        accl_head = LineAccumulator(self._indent, 0)
        if not self._options.header:
            gname = tfn(gloss.title(tlang, env)[0].text)
            if env:
                ename = tfn(gloss.environments[env].name(tlang, env)[0].text)
                title = p_("top page title",
                           "%(gloss)s (%(env)s)") \
                        % dict(gloss=gname, env=ename)
            else:
                title = gname
            self._fmt_header(accl_head, tlang, title,
                             stylepath, dctlpath, phpincpath)
        else:
            accl_head.read(self._options.header)

        # Footer.
        accl_foot = LineAccumulator(self._indent, 0)
        if not self._options.footer:
            self._fmt_footer(accl_foot)
        else:
            accl_foot.read(self._options.footer)

        # Collect everything and write out the HTML page.
        accl_all = LineAccumulator(self._indent, 0)
        accl_all(accl_head)
        if auxaccl:
            accl_all(auxaccl, 2)
        accl_all(accl)
        accl_all(accl_foot)
        accl_all.write(self._options.file)
コード例 #17
0
ファイル: plrules.py プロジェクト: happyaron/glossar
    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()
コード例 #18
0
ファイル: text_simple.py プロジェクト: caslav-ilic/divergloss
    def __call__ (self, gloss):

        # Resolve language and environment.
        lang = self._options.lang or gloss.lang
        if lang is not None and lang not in gloss.languages:
            error(p_("error message",
                     "language '%(lang)s' does not exist in the glossary")
                    % dict(lang=lang))

        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' does not exist in the glossary")
                  % dict(env=env))

        # Text formatter for selected language and environment.
        tfm = TextFormatterPlain(gloss, lang=lang, env=env)

        # Select all concepts which have a term in this langenv.
        # Collect terms for lexicographical ordering.
        concepts = {}
        ordering_links = []
        for ckey, concept in gloss.concepts.iteritems():
            terms = concept.term(lang, env)
            if terms:
                concepts[ckey] = concept
                # Use first of the synonymous terms for ordering.
                ordering_links.append((tfm(terms[0].nom.text).lower(), ckey))

        langsort_tuples(ordering_links, 0, lang)

        # Format glossary metadata for output.
        fmt_header_list = []
        fmt_title = tfm(gloss.title(lang, env)[0].text)
        if env is not None:
            fmt_envname = tfm(gloss.environments[env].name(lang, env)[0].text)
            fmt_title = "%s (%s)" % (fmt_title, fmt_envname)
        fmt_header_list.append(fmt_title)
        fmt_header_list.append("\n")
        fmt_header_list.append("-" * len(fmt_title) + "\n")
        fmt_header = "".join(fmt_header_list)

        # Format concepts for output.
        fmt_concepts = []
        for concept in [concepts[x[1]] for x in ordering_links]:
            fmtlist = []

            # Terms for this langenv.
            tft = TextFormatterPlain(gloss, lang=lang, env=env)
            terms = concept.term(lang, env)
            fmtlist.append("  ")
            fmtlist.append(", ".join([tft(x.nom.text) for x in terms]))
            # Also terms in other languages, but the same environment.
            fmt_ots = []
            for olang in [x for x in gloss.languages if x != lang]:
                oterms = concept.term(olang, env)
                lname = gloss.languages[olang].shortname(lang, env)
                if oterms and lname:
                    l = tft(lname[0].text)
                    ts = ", ".join([tft(x.nom.text) for x in oterms])
                    fmt_ots.append("%s /%s/" % (l, ts))
            if fmt_ots:
                fmtlist.append(" (%s)" % ("; ".join(fmt_ots)))

            # All descriptions for this langenv.
            tfd = TextFormatterPlain(gloss, lang=lang, env=env, indent="    ",
                                     wcol=self._options.wcol)
            descs = concept.desc(lang, env)
            if descs:
                fmtlist.append("\n")
                fmt_ds = []
                if len(descs) == 1:
                    fmt_ds.append(tfd(descs[0].text))
                elif len(descs) > 1:
                    # Enumerate descriptions.
                    for i in range(len(descs)):
                        fmt_ds.append(tfd(descs[i].text,
                                          prefix=("%d. " % (i + 1))))
                fmtlist.append("\n\n".join(fmt_ds))

            # Done formatting concept.
            fmt_concepts.append("".join(fmtlist))

        # 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\n".join(fmt_concepts)+"\n\n")

        if outf is not sys.stdout:
            outf.close()