"""
To use lexor as a module you should explore in detail the packages
provided with lexor. These packages contain many other functions and
information which can help you convert your document in the way you
desire.
:`core <lexor.core>`_:
The core of lexor defines basic objects such as ``Document`` and
provides the main objects that define the functions provided in
this module.
:`command <lexor.command>`_:
This module is in charge of providing all the available commands
to lexor.
----------------------------------------------------------------------
In this module we can find useful functions to quickly parse, convert
and write files without first creating any of the main lexor objects.
"""
import re
import os
import os.path as pth
from sys import stdout
from os.path import realpath, basename, splitext
from lexor.__version__ import get_version
from lexor.command import error
from lexor.command.lang import load_aux
from lexor import core
__all__ = [
'lexor',
'parse',
'read',
'convert',
'write',
'init',
]
def _read_text(src, search=False):
"""Attempt to read a file and return its contents. """
try:
return open(src, 'r').read()
except IOError:
if search is False:
return None
try:
lexorinputs = os.environ['LEXORINPUTS']
except KeyError:
return None
for directory in lexorinputs.split(':'):
path = '%s/%s' % (directory, src)
try:
return open(path, 'r').read()
except IOError:
pass
return None
[docs]def lexor(src, search=False, **keywords):
"""Utility function to parse and convert a file or string
specified by `src`. If `search` is ``True`` then it will
attemp to search for `src` in the paths specified by the
enviromental variable ``$LEXORINPUTS``. The following are all the
valid keywords and its defaults that this function accepts:
- parser_style: ``'_'``
- parser_lang: ``None``
- parser_defaults: ``None``,
- convert_style: ``'_'``,
- convert_from: ``None``,
- convert_to: ``'html'``,
- convert_defaults: ``None``,
- convert: ``'true'``
Returns the converted ``Document`` object and the log
``Document`` containing possible warning or error messages.
"""
info = {
'parser_style': '_',
'parser_lang': None,
'parser_defaults': None,
'convert_style': '_',
'convert_from': None,
'convert_to': 'html',
'convert_defaults': None,
'convert': 'true'
}
for key in keywords:
info[key] = keywords[key]
text = _read_text(src, search)
if text is None:
match = re.match(r'^(\.|/)(.*/)?(?:$|(.+?)(?:(\.[^.]*$)|$))', src)
if match:
raise IOError('file `%s` not found' % src)
else:
text = src
if info['parser_lang'] is None:
info['parser_lang'] = 'lexor'
src = 'string@0x%x' % id(text)
elif info['parser_lang'] is None:
path = pth.realpath(src)
name = pth.basename(path)
name = pth.splitext(name)
info['parser_lang'] = name[1][1:]
parser = core.Parser(info['parser_lang'],
info['parser_style'],
info['parser_defaults'])
parser.parse(text, src)
if info['convert'] == 'true' and info['convert_to'] is not None:
if info['convert_from'] is None:
info['convert_from'] = info['parser_lang']
converter = core.Converter(info['convert_from'],
info['convert_to'],
info['convert_style'],
info['convert_defaults'])
converter.convert(parser.doc)
if parser.log:
converter.update_log(parser.log, False)
cdoc = converter.doc.pop()
clog = converter.log.pop()
else:
cdoc = parser.doc
clog = parser.log
return cdoc, clog
[docs]def parse(text, lang='xml', style='default'):
"""Parse the `text` in the language specified by `lang` and
return its ``Document`` form and a ``Document`` log containing
the errors encountered during parsing. """
parser = core.Parser(lang, style)
parser.parse(text)
return (parser.document, parser.log)
[docs]def read(filename, style="default", lang=None):
"""Read and parse a file. If `lang` is not specified then the
language is assummed from the `filename` extension. Returns the
``Document`` form and a ``Document`` log containing the errors
encountered during parsing. """
if lang is None:
path = realpath(filename)
name = basename(path)
name = splitext(name)
lang = name[1][1:]
with open(filename, 'r') as tmpf:
text = tmpf.read()
parser = core.Parser(lang, style)
parser.parse(text, filename)
return (parser.document, parser.log)
[docs]def convert(doc, lang=None, style="default"):
"""Convert the ``Document`` `doc` to another language in a given
style. If the `lang` is not specified then the `doc` is
tranformed to the same language as the ``Document`` using the
default style. """
if lang is None:
lang = doc.owner.lang
converter = core.Converter(doc.owner.lang, lang, style)
converter.convert(doc)
return (converter.document, converter.log)
[docs]def write(doc, filename=None, mode='w', **options):
"""Write `doc` to a file. To write to the standard output use the
default parameters, otherwise provide `filename`. If `filename`
is provided you have the option of especifying the mode: ``'w'``
or ``'a'``.
You may also provide a file you may have opened yourself in place
of filename so that the writer writes to that file, in this case
the `mode` is ignored.
The valid `options` depends on the language the document
specifies. See the ``DEFAULT`` values a particular writer style
has to obtain the valid options. """
if doc.owner is None:
style = 'default'
lang = 'xml'
else:
style = doc.owner.style
lang = doc.owner.lang
writer = core.Writer(lang, style)
if doc.owner is not None and doc.owner.defaults is not None:
for var, val in doc.owner.defaults.iteritems():
writer.defaults[var] = os.path.expandvars(str(val))
for var, val in options.iteritems():
writer.defaults[var] = os.path.expandvars(str(val))
if filename:
writer.write(doc, filename, mode)
else:
writer.write(doc, stdout)
[docs]def init(**keywords):
"""Every lexor style needs to call the ``init`` function. These
are the valid keywords to initialize a style:
- version: ``(major, minor, micro, alpha/beta/rc/final, #)``
- lang
- [to_lang]
- type
- description
- author
- author_email
- [url]
- license
- path: Must be set to ``__file__``.
"""
valid_keys = ['version', 'lang', 'to_lang', 'type', 'description',
'author', 'author_email', 'url', 'path', 'license']
info = dict()
for key in valid_keys:
info[key] = None
for key in keywords.keys():
if key not in valid_keys:
error("ERROR: Valid keys for lexor.init are %s" % valid_keys)
else:
info[key] = keywords[key]
info['style'] = splitext(basename(info['path']))[0]
info['style'] = info['style'].split('-')[0]
info['ver'] = get_version(info['version'])
return info