вторник, 15 января 2013 г.

New Literate Programming Tool: Nano-LP

Yes, yet another and, I thing, last of my attempts. Done WiKi (on project page). Main goal is to keep input file clean and readable (not so cryptic like many other tools) with very "regualar" and simple, intuitive syntax. Main features:
  • OpenOffice/LibreOffice
  • MarkDown/MultiMarkdown
  • Creole
  • reStructuredText
  • TeX/LaTeX
  • txt2tags
  • Asciidoc
  • HTML/XML
  • ... all based on these
Utility is little Python script and supports:
  • defining command (macros) with placeholders in the body (code chunk)
  • pasting command code chunk
  • defining multiple parts code-chunks
  • joining, 'ending', etc. several code chunks
  • globbing command when paste
  • including one file to another (library)
  • auto-detecting of cycles
  • configurable via simple .INI like file
  • works with Python 2.7.x - Python 3.x
  • works with Unicode (UTF8)
TODO:
  1. Improvements of error reporting: file, line locating, (a special in OO - missed)
  2. More tests, better testing
  3. Improve Asciidoc parser
  4. Realize 1.0 beta
  5. ...

воскресенье, 13 января 2013 г.

Re-raise exceptions in Python in compatible (2to3) way

Good practice is to keep original traceback (stack-trace) when you re-raise modified exception. In Python 2 it's simple:
        try:
            return buggy()
        except Exception as x:
            cls,obj,tb = sys.exc_info()
            # modify obj OR create new the same class (cls), like here
            raise cls, SOME_ARGS, tb
In Python 3 it's simple too, but now there is a special BaseException method for this and new syntax, so:
        try:
            return buggy()
        except Exception as x:
            cls,obj,tb = sys.exc_info()
            # modify obj OR create new the same class (cls), like here
            raise cls(SOME_ARGS).with_traceback(tb)
Now to make common code compatible with Python 2 and 3 we SHOULD save it in DIFFERENT files, to avoid syntax errors when Python compile it to byte-code. For example, let's save it to 'comp2.py' and 'comp3.py'. And lets represent it as function... with signature reraise(exclass, msg, traceb). In 'comp2.py':
def reraise(exc, msg, tb):
    raise exc, msg, tb

and similar in 'comp3.py' but with with_traceback() usage. Now use it:
import sys
_PY23 = 3 if sys.version_info.major > 2 else 2
if _PY23 == 2:
    from comp2 import *
elif _PY23 == 3:
    from comp3 import *
That is it :)