#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2011, 2012, Wolfgang Scherer, <Wolfgang.Scherer at gmx.de>
#
# This file is part of AdHoc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>,
# or write to Wolfgang Scherer, <Wolfgang.Scherer at gmx.de>
# @:adhoc_uncomment:@
# @:adhoc_template:@ doc/index.rst
# AdHoc Standalone Python Script Generator
# ########################################
#
# The *AdHoc* compiler can be used as a program (see `Script Usage`_)
# as well as a module (see :class:`adhoc.AdHoc`).
#
# Since the *AdHoc* compiler itself is installed as a compiled *AdHoc*
# script, it serves as its own usage example.
#
# After installation of the *adhoc.py* script, the full source can be
# obtained in directory ``__adhoc__``, by executing::
#
# adhoc.py --explode
#
# .. @@contents@@
#
# @:adhoc_template:@ doc/index.rst # off
# @:adhoc_uncomment:@
"""\
.. _Script Usage:
adhoc.py - Python ad hoc compiler.
====== ====================
usage: adhoc.py [OPTIONS] [file ...]
or import adhoc
====== ====================
Options
=======
===================== ==================================================
-c, --compile compile file(s) or standard input into output file
(default: standard output).
-d, --decompile decompile file(s) or standard input into
output directory (default ``__adhoc__``).
-o, --output OUT output file for --compile/output directory for
--decompile.
-q, --quiet suppress warnings
-v, --verbose verbose test output
--debug[=NUM] show debug information
-h, --help display this help message
--documentation display module documentation.
--template list show available templates.
--template[=NAME] extract named template to standard
output. Default NAME is ``-``.
--extract[=DIR] extract adhoc files to directory DIR (default: ``.``)
--explode[=DIR] explode script with adhoc in directory DIR
(default ``__adhoc__``)
--implode implode script with adhoc
--install install adhoc.py script
-t, --test run doc tests
===================== ==================================================
*adhoc.py* is compatible with Python 2.4+ and Python 3. (For Python
<2.6 the packages *stringformat* and *argparse* are needed and
included.)
.. _END_OF_HELP:
.. |=NUM| replace:: ``[=NUM]``
Script Examples
===============
Templates
---------
Sections marked by |adhoc_template| can be retrieved as templates on
standard output.
Additionally, all other files compiled into an adhoc file with one of
================ ======================
|adhoc| ==> |adhoc_import|
|adhoc_verbatim| ==> |adhoc_template_v|
|adhoc_include| ==> |adhoc_unpack|
================ ======================
are accessible as templates.
``python adhoc.py --template list`` provides a list of templates:
>>> ign = main('adhoc.py --template list'.split())
================================================= ================================ ================
Command Template Type
================================================= ================================ ================
adhoc.py --template adhoc_test # !adhoc_test adhoc_import
adhoc.py --template adhoc_test.sub # !adhoc_test.sub adhoc_import
adhoc.py --template argparse_local # !argparse_local adhoc_import
adhoc.py --template namespace_dict # !namespace_dict adhoc_import
adhoc.py --template stringformat_local # !stringformat_local adhoc_import
adhoc.py --template use_case_000_ # !use_case_000_ adhoc_import
adhoc.py --template use_case_001_templates_ # !use_case_001_templates_ adhoc_import
adhoc.py --template use_case_002_include_ # !use_case_002_include_ adhoc_import
adhoc.py --template use_case_003_import_ # !use_case_003_import_ adhoc_import
adhoc.py --template use_case_005_nested_ # !use_case_005_nested_ adhoc_import
adhoc.py --template docutils.conf # docutils.conf adhoc_template_v
adhoc.py --template # - adhoc_template
adhoc.py --template README.txt # README.txt adhoc_template
adhoc.py --template col-param-closure # -col-param-closure adhoc_template
adhoc.py --template doc/USE_CASES.txt # doc/USE_CASES.txt adhoc_template
adhoc.py --template doc/index.rst # doc/index.rst adhoc_template
adhoc.py --template max-width-class # -max-width-class adhoc_template
adhoc.py --template rst-to-ascii # -rst-to-ascii adhoc_template
adhoc.py --template test # -test adhoc_template
adhoc.py --template MANIFEST.in # !MANIFEST.in adhoc_unpack
adhoc.py --template Makefile # !Makefile adhoc_unpack
adhoc.py --template README.css # !README.css adhoc_unpack
adhoc.py --template doc/Makefile # !doc/Makefile adhoc_unpack
adhoc.py --template doc/_static/adhoc-logo-32.ico # !doc/_static/adhoc-logo-32.ico adhoc_unpack
adhoc.py --template doc/adhoc-logo.svg # !doc/adhoc-logo.svg adhoc_unpack
adhoc.py --template doc/conf.py # !doc/conf.py adhoc_unpack
adhoc.py --template doc/make.bat # !doc/make.bat adhoc_unpack
adhoc.py --template doc/z-massage-index.sh # !doc/z-massage-index.sh adhoc_unpack
adhoc.py --template setup.py # !setup.py adhoc_unpack
================================================= ================================ ================
``python adhoc.py --template`` prints the standard template ``-``
(closing delimiter replaced by ellipsis):
>>> ign = main('./adhoc.py --template'.split()) #doctest: +ELLIPSIS
# @:adhoc_disable... allow modification of exploded sources in original place
sys.path.append('__adhoc__')
# @:adhoc_disable...
<BLANKLINE>
# @:adhoc_run_time... The run-time class goes here
# @:adhoc_run_time_engine... settings enabled at run-time
# @:adhoc_enable...
# RtAdHoc.flat = False
# @:adhoc_enable...
# @:adhoc_run_time_engine...
<BLANKLINE>
#import adhoc # @:adhoc...
``python adhoc.py --template test`` prints the template named ``-test``.
the leading ``-`` signifies disposition to standard output:
>>> ign = main('./adhoc.py --template test'.split())
Test template.
Extract
-------
The default destination for extracting files is the current working
directory.
Files extracted consist of
- packed files generated by |adhoc_include|
- templates generated by |adhoc_verbatim|
- templates with a file destination other than standard output
``python adhoc.py --extract __adhoc_extract__`` unpacks the following files into
directory ``__adhoc_extract__``:
>>> import shutil
>>> ign = main('./adhoc.py --extract __adhoc_extract__'.split())
>>> file_list = []
>>> for dir, subdirs, files in os.walk('__adhoc_extract__'):
... file_list.extend([os.path.join(dir, file_) for file_ in files])
>>> for file_ in sorted(file_list):
... printf(file_)
__adhoc_extract__/MANIFEST.in
__adhoc_extract__/Makefile
__adhoc_extract__/README.css
__adhoc_extract__/README.txt
__adhoc_extract__/doc/Makefile
__adhoc_extract__/doc/USE_CASES.txt
__adhoc_extract__/doc/_static/adhoc-logo-32.ico
__adhoc_extract__/doc/adhoc-logo.svg
__adhoc_extract__/doc/conf.py
__adhoc_extract__/doc/index.rst
__adhoc_extract__/doc/make.bat
__adhoc_extract__/doc/z-massage-index.sh
__adhoc_extract__/docutils.conf
__adhoc_extract__/setup.py
__adhoc_extract__/use_case_000_.py
__adhoc_extract__/use_case_001_templates_.py
__adhoc_extract__/use_case_002_include_.py
__adhoc_extract__/use_case_003_import_.py
__adhoc_extract__/use_case_005_nested_.py
>>> shutil.rmtree('__adhoc_extract__')
Export
------
The default destination for exporting files is the
subdirectory ``__adhoc__``.
Files exported consist of
- imported modules generated by |adhoc|
- all files covered in section `Extract`_
``python adhoc.py --explode __adhoc_explode__`` unpacks the following files into
directory ``__adhoc_explode__``:
>>> import shutil
>>> ign = main('./adhoc.py --explode __adhoc_explode__'.split())
>>> file_list = []
>>> for dir, subdirs, files in os.walk('__adhoc_explode__'):
... file_list.extend([os.path.join(dir, file_) for file_ in files])
>>> for file_ in sorted(file_list):
... printf(file_)
__adhoc_explode__/MANIFEST.in
__adhoc_explode__/Makefile
__adhoc_explode__/README.css
__adhoc_explode__/README.txt
__adhoc_explode__/adhoc.py
__adhoc_explode__/adhoc_test/__init__.py
__adhoc_explode__/adhoc_test/sub/__init__.py
__adhoc_explode__/argparse_local.py
__adhoc_explode__/doc/Makefile
__adhoc_explode__/doc/USE_CASES.txt
__adhoc_explode__/doc/_static/adhoc-logo-32.ico
__adhoc_explode__/doc/adhoc-logo.svg
__adhoc_explode__/doc/conf.py
__adhoc_explode__/doc/index.rst
__adhoc_explode__/doc/make.bat
__adhoc_explode__/doc/z-massage-index.sh
__adhoc_explode__/docutils.conf
__adhoc_explode__/namespace_dict.py
__adhoc_explode__/rt_adhoc.py
__adhoc_explode__/setup.py
__adhoc_explode__/stringformat_local.py
__adhoc_explode__/use_case_000_.py
__adhoc_explode__/use_case_001_templates_.py
__adhoc_explode__/use_case_002_include_.py
__adhoc_explode__/use_case_003_import_.py
__adhoc_explode__/use_case_005_nested_.py
>>> shutil.rmtree('__adhoc_explode__')
File Permissions
================
- File mode is restored.
- File ownership is not restored.
- File modification times are restored.
Since only naive datetimes are recorded, this only works correctly
within the same timezone.
.. @:adhoc_index_only:@
AdHoc Module
============
.. @:adhoc_index_only:@
"""
# @:adhoc_uncomment:@
# @:adhoc_template:@ doc/index.rst
#
# Purpose
# =======
#
# *AdHoc* provides python scripts with
#
# - template facilities
# - default file generation
# - standalone module inclusion
#
# @:adhoc_index_only:@
# See also `Use Cases`_.
#
# @:adhoc_index_only:@
# *AdHoc* has been designed to provide an implode/explode cycle:
#
# ======== ======= ========= ======= =========
# source_0 xsource_0
# source_1 implode explode xsource_1
# ... ------> script.py ------> ...
# source_n xsource_n
# ======== ======= ========= ======= =========
#
# where ``xsource_i === source_i``. I.e., ``diff source_i xsource_i``
# does not produce any output.
#
# Quickstart
# ==========
#
# module.py:
#
# | # -\*- coding: utf-8 -\*-
# | mvar = 'value'
#
# script.py:
#
# | # -\*- coding: utf-8 -\*-
# | # |adhoc_run_time|
# | import module # |adhoc|
# | print('mvar: ' + module.mvar)
#
# Compilation::
#
# adhoc.py --compile script.py >/tmp/script-compiled.py
#
# Execution outside source directory::
#
# cd /tmp && python script-compiled.py
#
# shows::
#
# mvar: value
#
# Decompilation::
#
# cd /tmp && \
# mkdir -p __adhoc__ && \
# adhoc.py --decompile <script-compiled.py >__adhoc__/script.py
#
# .. |@:| replace:: ``@:``
# .. |:@| replace:: ``:@``
# .. |adhoc_run_time| replace:: |@:|\ ``adhoc_run_time``\ |:@|
# .. |adhoc| replace:: |@:|\ ``adhoc``\ |:@|
#
# Description
# ===========
#
# The *AdHoc* compiler/decompiler parses text for tagged lines and
# processes them as instructions.
#
# The minimal parsed entity is a tagged line, which is any line
# containing a recognized *AdHoc* tag.
#
# All *AdHoc* tags are enclosed in delimiters (default: |@:| and |:@|). E.g:
#
# |@:|\ adhoc\ |:@|
#
# Delimiters come in several flavors, namely line and section
# delimiters and a set of macro delimiters. By default, line and
# section delimiters are the same, but they can be defined separately.
#
# `Flags`_ are tagged lines, which denote a single option or
# command. E.g.:
#
# | import module # |@:|\ adhoc\ |:@|
# | # |@:|\ adhoc_self\ |:@| my_module_name
#
# `Sections`_ are tagged line pairs, which delimit a block of
# text. The first tagged line opens the section, the second tagged
# line closes the section. E.g.:
#
# | # |@:|\ adhoc_enable\ |:@|
# | # disabled_command()
# | # |@:|\ adhoc_enable\ |:@|
#
# `Macros`_ have their own delimiters (default: |@m| and |m>|). E.g.:
#
# | # |@m|\ MACRO_NAME\ |m>|
#
# The implementation is realized as class :class:`adhoc.AdHoc` which
# is mainly used as a namespace. The run-time part of
# :class:`adhoc.AdHoc` -- which handles module import and file export
# -- is included verbatim as class :class:`RtAdHoc` in the generated
# output.
#
# Flags
# -----
#
# :|adhoc_run_time|:
# The place where the *AdHoc* run-time code is added. This flag must
# be present in files, which use the |adhoc| import feature. It
# is not needed for the enable/disable features.
#
# This flag is ignored, if double commented. E.g.:
#
# | # # |adhoc_run_time|
#
# :|adhoc| [force] [flat | full]:
# Mark import line for run-time compilation.
#
# If ``force`` is specified, the module is imported, even if it
# was imported before.
#
# If ``flat`` is specified, the module is not recursively
# exported.
#
# If ``full`` is specified, the module is recursively
# exported. (This parameter takes priority over ``flat``).
#
# If neither ``flat`` nor ``full`` are specified,
# :attr:`adhoc.AdHoc.flat` determines the export scope.
#
# This flag is ignored, if the line is commented out. E.g.:
#
# | # import module # |adhoc|
#
# .. _adhoc_include:
#
# :|adhoc_include| file_spec, ...:
# Include files for unpacking. ``file_spec`` is one of
#
# :file:
# ``file`` is used for both input and output.
#
# :file ``from`` default-file:
# ``file`` is used for input and output. if ``file`` does not
# exist, ``default-file`` is used for input.
#
# :source-file ``as`` output-file:
# ``source-file`` is used for input. ``output-file`` is used for
# output. If ``source-file`` does not exist, ``output-file`` is
# used for input also.
#
# This flag is ignored, if double commented. E.g.:
#
# | # # |adhoc_include| file
#
# :|adhoc_verbatim| [flags] file_spec, ...:
# Include files for verbatim extraction. See adhoc_include_ for
# ``file_spec``.
#
# The files are included as |adhoc_template_v| sections. *file* is used
# as *export_file* mark. If *file* is ``--``, the template disposition
# becomes standard output.
#
# Optional flags can be any combination of ``[+|-]NUM`` for
# indentation and ``#`` for commenting. E.g.:
#
# | # |adhoc_verbatim| +4# my_file from /dev/null
#
# *my_file* (or ``/dev/null``) is read, commented and indented 4
# spaces.
#
# If the |adhoc_verbatim| tag is already indented, the specified
# indentation is subtracted.
#
# This flag is ignored, if double commented. E.g.:
#
# | # # |adhoc_verbatim| file
#
# :|adhoc_self| name ...:
# Mark name(s) as currently compiling. This is useful, if
# ``__init__.py`` imports other module parts. E.g:
#
# | import pyjsmo # |@:|\ adhoc\ |:@|
#
# where ``pyjsmo/__init__.py`` contains:
#
# | # |@:|\ adhoc_self\ |:@| pyjsmo
# | from pyjsmo.base import * # |@:|\ adhoc\ |:@|
#
# :|adhoc_compiled|:
# If present, no compilation is done on this file. This flag is
# added by the compiler to the run-time version.
#
# Sections
# --------
#
# :|adhoc_enable|:
# Leading comment char and exactly one space are removed from lines
# in these sections.
#
# :|adhoc_disable|:
# A comment char and exactly one space are added to non-blank
# lines in these sections.
#
# :|adhoc_template| -mark | export_file:
# If mark starts with ``-``, the output disposition is standard output
# and the template is ignored, when exporting.
#
# Otherwise, the template is written to output_file during export.
#
# All template parts with the same mark/export_file are concatenated
# to a single string.
#
# :|adhoc_template_v| export_file:
# Variation of |adhoc_template|. Automatically generated by |adhoc_verbatim|.
#
# :|adhoc_uncomment|:
# Treated like |adhoc_enable| before template output.
#
# :|adhoc_indent| [+|-]NUM:
# Add or remove indentation before template output.
#
# :|adhoc_import|:
# Imported files are marked as such by the compiler. There is no
# effect during compilation.
#
# :|adhoc_unpack|:
# Included files are marked as such by the compiler. There is no
# effect during compilation.
#
# :|adhoc_remove|:
# Added sections are marked as such by the compiler. Removal is
# done when exporting.
#
# Before compilation, existing |adhoc_remove| tags are renamed to
# |adhoc_remove_|.
#
# After automatically added |adhoc_remove| sections have been
# removed during export, remaining |adhoc_remove_| tags are
# renamed to |adhoc_remove| again.
#
# .. note:: Think twice, before removing material from original
# sources at compile time. It will violate the condition
# ``xsource_i === source_i``.
#
# :|adhoc_run_time_engine|:
# The run-time class :class:`RtAdHoc` is enclosed in this special
# template section.
#
# It is exported as ``rt_adhoc.py`` during export.
#
# Macros
# ------
#
# Macros are defined programmatically::
#
# AdHoc.macros[MACRO_NAME] = EXPANSION_STRING
#
# A macro is invoked by enclosing a MACRO_NAME in
# :attr:`adhoc.AdHoc.macro_call_delimiters`. (Default: |@m|, |m>|).
#
# :|MACRO_NAME|:
# Macro call.
#
# Internal
# --------
#
# :|adhoc_run_time_class|:
# Marks the beginning of the run-time class. This is only
# recognized in the *AdHoc* programm/module.
#
# :|adhoc_run_time_section|:
# All sections are concatenated and used as run-time code. This is
# only recognized in the *AdHoc* programm/module.
#
# In order to preserve the ``xsource_i === source_i`` bijective
# condition, macros are expanded/collapsed with special macro
# definition sections. (See :attr:`adhoc.AdHoc.macro_xdef_delimiters`;
# Default: |<m|, |m@|).
#
# :|adhoc_macro_call|:
# Macro call section.
#
# :|adhoc_macro_expansion|:
# Macro expansion section.
#
# @:adhoc_template:@ doc/index.rst # off
# @:adhoc_uncomment:@
# @:adhoc_uncomment:@
# @:adhoc_template:@ doc/index.rst
# @:adhoc_index_only:@
#
# .. include:: USE_CASES.txt
# @:adhoc_index_only:@
#
# AdHoc Script
# ============
# @:adhoc_index_only:@
#
# .. automodule:: adhoc
# :members:
# :show-inheritance:
#
# .. _namespace_dict:
#
# NameSpace/NameSpaceDict
# =======================
#
# .. automodule:: namespace_dict
# :members:
# :show-inheritance:
#
# @:adhoc_index_only:@
# @:adhoc_template:@ doc/index.rst # off
# @:adhoc_uncomment:@
# @:adhoc_uncomment:@
# @:adhoc_template:@ doc/index.rst
#
# .. |adhoc_self| replace:: |@:|\ ``adhoc_self``\ |:@|
# .. |adhoc_include| replace:: |@:|\ ``adhoc_include``\ |:@|
# .. |adhoc_verbatim| replace:: |@:|\ ``adhoc_verbatim``\ |:@|
# .. |adhoc_compiled| replace:: |@:|\ ``adhoc_compiled``\ |:@|
# .. |adhoc_enable| replace:: |@:|\ ``adhoc_enable``\ |:@|
# .. |adhoc_disable| replace:: |@:|\ ``adhoc_disable``\ |:@|
# .. |adhoc_template| replace:: |@:|\ ``adhoc_template``\ |:@|
# .. |adhoc_template_v| replace:: |@:|\ ``adhoc_template_v``\ |:@|
# .. |adhoc_uncomment| replace:: |@:|\ ``adhoc_uncomment``\ |:@|
# .. |adhoc_indent| replace:: |@:|\ ``adhoc_indent``\ |:@|
# .. |adhoc_import| replace:: |@:|\ ``adhoc_import``\ |:@|
# .. |adhoc_unpack| replace:: |@:|\ ``adhoc_unpack``\ |:@|
# .. |adhoc_remove| replace:: |@:|\ ``adhoc_remove``\ |:@|
# .. |adhoc_remove_| replace:: |@:|\ ``adhoc_remove_``\ |:@|
# .. |adhoc_run_time_class| replace:: |@:|\ ``adhoc_run_time_class``\ |:@|
# .. |adhoc_run_time_section| replace:: |@:|\ ``adhoc_run_time_section``\ |:@|
# .. |adhoc_run_time_engine| replace:: |@:|\ ``adhoc_run_time_engine``\ |:@|
# .. |@m| replace:: ``@|:``
# .. |m>| replace:: ``:|>``
# .. |<m| replace:: ``<|:``
# .. |m@| replace:: ``:|@``
# .. |MACRO_NAME| replace:: |@m|\ ``MACRO_NAME``\ |m>|
# .. |adhoc_macro_call| replace:: |<m|\ ``adhoc_macro_call``\ |m@|
# .. |adhoc_macro_expansion| replace:: |<m|\ ``adhoc_macro_expansion``\ |m@|
#
# @:adhoc_template:@ doc/index.rst # off
# @:adhoc_uncomment:@
# --------------------------------------------------
# |||:sec:||| COMPATIBILITY
# --------------------------------------------------
import sys
# (progn (forward-line 1) (snip-insert-mode "py.b.printf" t) (insert "\n"))
# adapted from http://www.daniweb.com/software-development/python/code/217214
try:
printf = eval("print") # python 3.0 case
except SyntaxError:
printf_dict = dict()
try:
exec("from __future__ import print_function\nprintf=print", printf_dict)
printf = printf_dict["printf"] # 2.6 case
except SyntaxError:
def printf(*args, **kwd): # 2.4, 2.5, define our own Print function
fout = kwd.get("file", sys.stdout)
w = fout.write
if args:
w(str(args[0]))
sep = kwd.get("sep", " ")
for a in args[1:]:
w(sep)
w(str(a))
w(kwd.get("end", "\n"))
del printf_dict
# (progn (forward-line 1) (snip-insert-mode "py.f.isstring" t) (insert "\n"))
# hide from 2to3
exec('''
def isstring(obj):
return isinstance(obj, basestring)
''')
try:
isstring("")
except NameError:
def isstring(obj):
return isinstance(obj, str) or isinstance(obj, bytes)
# (progn (forward-line 1) (snip-insert-mode "py.b.dict_items" t) (insert "\n"))
try:
getattr(dict(), 'iteritems')
ditems = lambda d: getattr(d, 'iteritems')()
dkeys = lambda d: getattr(d, 'iterkeys')()
dvalues = lambda d: getattr(d, 'itervalues')()
except AttributeError:
ditems = lambda d: getattr(d, 'items')()
dkeys = lambda d: getattr(d, 'keys')()
dvalues = lambda d: getattr(d, 'values')()
import os
import re
# --------------------------------------------------
# |||:sec:||| CONFIGURATION
# --------------------------------------------------
dbg_comm = ((('dbg_comm' in globals()) and (globals()['dbg_comm'])) or ('# '))
dbg_twid = ((('dbg_twid' in globals()) and (globals()['dbg_twid'])) or (9))
dbg_fwid = ((('dbg_fwid' in globals()) and (globals()['dbg_fwid'])) or (23))
# (progn (forward-line 1) (snip-insert-mode "py.b.dbg.setup" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.b.strings" t) (insert "\n"))
def _uc(string): # ||:fnc:||
return unicode(string, 'utf-8')
try:
_uc("")
except NameError:
_uc = lambda x: x
uc_type = type(_uc(""))
def uc(value): # ||:fnc:||
if isstring(value) and not isinstance(value, uc_type):
return _uc(value)
return value
def _utf8str(string): # ||:fnc:||
if isinstance(string, uc_type):
return string.encode('utf-8')
return string
def utf8str(value): # ||:fnc:||
if isstring(value):
return _utf8str(value)
return value
def _nativestr(string): # ||:fnc:||
# for python3, unicode strings have type str
if isinstance(string, str):
return string
# for python2, encode unicode strings to utf-8 strings
if isinstance(string, uc_type):
return string.encode('utf-8')
try:
return str(string.decode('utf-8'))
except UnicodeDecodeError:
return string
def nativestr(value): # ||:fnc:||
if isstring(value):
return _nativestr(value)
return value
# (progn (forward-line 1) (snip-insert-mode "py.f.strclean" t) (insert "\n"))
[docs]def strclean(value):
'''Make a copy of any structure with all strings converted to
native strings.
:func:`strclean` is good for :meth:`__str__` methods.
It is needed for doctest output that should be compatible with
both python2 and python3.
The output structure is not necessarily an exact copy of the input
structure, since objects providing iterator or item interfaces are
only copied through those!
'''
if isstring(value):
return _nativestr(value)
if hasattr(value, 'items'):
try:
out = type(value)()
except:
(t, e, tb) = sys.exc_info() # |:debug:|
printf(''.join(traceback.format_tb(tb)), file=sys.stderr)
printe('OOPS: ' + t.__name__ + ': ' + str(e) + ' [' + str(value.__class__.__name__) + '] [' + str(value) + ']')
for k, v in value.items():
out[strclean(k)] = strclean(v)
return out
if hasattr(value, '__iter__') or hasattr(value, 'iter'):
if isinstance(value, tuple):
out = []
else:
out = type(value)()
for e in value:
out.append(strclean(e))
if isinstance(value, tuple):
out = type(value)(out)
return out
return value
# (progn (forward-line 1) (snip-insert-mode "py.f.issequence" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.b.logging" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.b.ordereddict" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.main.pyramid.activate" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.main.project.libdir" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.main.sql.alchemy" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.main.sql.ws" t) (insert "\n"))
# The standard template should be something useful
# @:adhoc_uncomment:@
# @:adhoc_template:@ -
# # @:adhoc_disable:@ allow modification of exploded sources in original place
sys.path.append('__adhoc__')
# # @:adhoc_disable:@
# @:adhoc_template:@
# @:adhoc_uncomment:@
# @:adhoc_run_time:@
# @:adhoc_template:@ -
# @:adhoc_run_time:@ The run-time class goes here
# @:adhoc_run_time_engine:@ settings enabled at run-time
# @:adhoc_enable:@
# # RtAdHoc.flat = False
# # @:adhoc_template:@
# RtAdHoc.flat = False
# # @:adhoc_template:@ -
# @:adhoc_enable:@
# @:adhoc_run_time_engine:@
#import adhoc # @:adhoc:@
# @:adhoc_template:@
# (progn (forward-line 1) (snip-insert-mode "py.b.sformat" t) (insert "\n"))
try:
('{0}').format(0)
def sformat (fmtspec, *args, **kwargs):
return fmtspec.format(*args, **kwargs)
except AttributeError:
try:
import stringformat
except ImportError:
try:
import stringformat_local as stringformat # @:adhoc:@
except ImportError:
printf('error: (adhoc) stringformat missing.'
' Try *easy_install stringformat*.', file=sys.stderr)
exit(1)
def sformat (fmtspec, *args, **kwargs):
return stringformat.FormattableString(fmtspec).format(
*args, **kwargs)
import base64
import urllib
#import something.non.existent # @:adhoc:@
try:
import namespace_dict
except ImportError:
import namespace_dict # @:adhoc:@
# copy of ws_prop_dict.dict_dump
[docs]def dict_dump(dict_, wid=0, trunc=0, commstr=None, tag=None, out=None): # ||:fnc:||
'''Dump a dictionary.'''
if out is None:
out = sys.stderr
if commstr is None:
commstr = ((('dbg_comm' in globals()) and (globals()['dbg_comm'])) or ('# '))
dbg_twid = ((('dbg_twid' in globals()) and (globals()['dbg_twid'])) or (9))
if tag is None:
tag = ':DBG:'
max_wid = 0
for key in dict_.keys():
_wid = len(key)
if max_wid < _wid:
max_wid = _wid
dbg_fwid = ((('dbg_fwid' in globals()) and (globals()['dbg_fwid'])) or (max_wid))
if dbg_fwid < max_wid:
dbg_fwid = max_wid
printf(sformat('{0}{1}', commstr, '-' * 30), file=out)
indent = (sformat("{0}{3:^{1}} {4:<{2}s}: ",
commstr, dbg_twid, dbg_fwid,
'', ''))
for key, value in sorted(dict_.items()):
value = str(value)
value = value.replace('\n', '\\n')
value = value.replace('\r', '\\r')
value = value.replace('\t', '\\t')
value = value.replace('\f', '\\f')
if wid == 0:
wid = 78 - len(indent) - 1
if wid < 50:
wid = 50
start = 0
limit = len(value)
value_lines = []
while start < limit:
line = value[start:start+wid]
space_pos = wid - 1
if len(line) == wid:
space_pos = line.rfind(' ')
if space_pos > 0:
line = line[:space_pos + 1]
else:
space_pos = wid - 1
value_lines.append(line)
start += space_pos + 1
if trunc > 0:
value_lines = value_lines[:trunc]
value_lines[-1] = sformat('{0}[', value_lines[-1])
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}",
commstr, dbg_twid, dbg_fwid,
tag, key, value_lines[0]), file=out)
for line in value_lines[1:]:
printf(sformat('{0}{1}',indent, line), file=out)
def dump_attr(obj, wid=0, trunc=0, commstr=None, # ||:fnc:||
tag=None, out=None):
if out is None:
out = sys.stdout
dict_dump(
vars(obj), wid=wid, trunc=trunc, commstr=commstr, tag=tag, out=out)
printe = printf
# (progn (forward-line 1) (snip-insert-mode "py.b.posix" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.b.os.system.sh" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.b.prog.path" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.b.line.loop" t) (insert "\n"))
# --------------------------------------------------
# |||:sec:||| CLASSES
# --------------------------------------------------
# (progn (forward-line 1) (snip-insert-mode "py.c.placeholder.template" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.c.key.hash.ordered.dict" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.c.progress" t) (insert "\n"))
# --------------------------------------------------
# |||:sec:||| EXCEPTION
# --------------------------------------------------
class AdHocError(Exception): # ||:cls:||
pass
# --------------------------------------------------
# |||:sec:||| ADHOC
# --------------------------------------------------
# @:adhoc_run_time_section:@ START
import sys
import os
import re
try:
from cStringIO import StringIO as _AdHocBytesIO, StringIO as _AdHocStringIO
except ImportError:
from io import BytesIO as _AdHocBytesIO, StringIO as _AdHocStringIO
# @:adhoc_run_time_section:@ off
if not hasattr(os.path, 'relpath'):
def relpath(path, start=os.curdir):
"""Return a relative version of a path"""
if not path:
raise ValueError("no path specified")
start_list = os.path.abspath(start).split(os.sep)
path_list = os.path.abspath(path).split(os.sep)
# Work out how much of the filepath is shared by start and path.
i = len(os.path.commonprefix([start_list, path_list]))
rel_list = [os.pardir] * (len(start_list)-i) + path_list[i:]
if not rel_list:
return os.curdir
return os.path.join(*rel_list)
os.path.relpath = relpath
del relpath
AH_CHECK_SOURCE = '''\
not in section
# >:cmd:< arg0 arg1 # comment
# <:tag:> on
in section
# >:cmd:< arg2 arg3 # comment
in section
# <:tag:> off
not in section
# <:tag2:> on
in section
in section
# <:tag2:> off
not in section
'''
# @:adhoc_run_time_section:@ on
# @:adhoc_run_time_class:@
[docs]class AdHoc(object): # |||:cls:|||
# @:adhoc_run_time_section:@ off
"""
:class:`AdHoc` is mainly used as a namespace, which is partially
included verbatim as :class:`RtAdHoc` in the generated output.
It is only instantiated for compiling adhoc output
(:meth:`compileFile`, :meth:`compile`).
**Attributes**
The following class attrbutes determine the operation of AdHoc:
- :attr:`line_delimiters`
- :attr:`section_delimiters`
- :attr:`template_process_hooks`
- :attr:`extra_templates`
- :attr:`export_dir`
- :attr:`extract_dir`
- :attr:`flat`
- :attr:`frozen`
- :attr:`quiet`
- :attr:`verbose`
- :attr:`debug`
Run-time class attributes can be set like this:
| # |adhoc_run_time|
| # |adhoc_enable|
| # RtAdHoc.flat = False
| # RtAdHoc.frozen = True
| # |adhoc_enable|
or like this:
| # |adhoc_run_time|
| if 'RtAdHoc' in globals():
| RtAdHoc.flat = False
| RtAdHoc.frozen = True
**Low-Level Functions**
:meth:`adhoc_tag` constructs a delimited tag or tag regular
expression:
>>> adhoc_tag = AdHoc.adhoc_tag
>>> delimiters = ('<:', ':>')
>>> tag_sym = 'my_tag'
>>> adhoc_tag(tag_sym, delimiters)
'<:my_tag:>'
>>> tag_rx = 'my_[^:]+'
>>> adhoc_tag(tag_rx, delimiters, is_re=True)
'\\\\<\\\\:my_[^:]+\\\\:\\\\>'
:meth:`tag_split` splits a string into tagged line parts and
untagged parts.
:meth:`adhoc_parse_line` splits a tagged line into a tag symbol and
additional arguments:
>>> adhoc_parse_line = AdHoc.adhoc_parse_line
>>> tagged_line = 'anything # <:my_tag:> additonal arguments # end comment'
>>> adhoc_parse_line(tagged_line, tag_sym, delimiters)
('my_tag', 'additonal arguments # end comment')
>>> adhoc_parse_line(tagged_line, tag_rx, delimiters, is_re=True)
('my_tag', 'additonal arguments # end comment')
>>> adhoc_parse_line(tagged_line, tag_rx, delimiters, is_re=True, strip_comment=True)
('my_tag', 'additonal arguments')
**Low-Level Convenience Functions**
*Tag Generation*
:meth:`line_tag`, :meth:`section_tag`
>>> class ah(AdHoc):
... line_delimiters = ('>:', ':<')
... section_delimiters = ('<:', ':>')
>>> ah.line_tag('tag-symbol')
'>:tag-symbol:<'
>>> ah.line_tag('tag.?rx', True)
'\\\\>\\\\:tag.?rx\\\\:\\\\<'
>>> ah.section_tag('tag-symbol')
'<:tag-symbol:>'
>>> ah.section_tag('tag.?rx', True)
'\\\\<\\\\:tag.?rx\\\\:\\\\>'
*Tagged Line/Section Retrieval*
:meth:`tag_lines`, :meth:`tag_partition`, :meth:`tag_sections`
>>> source = AH_CHECK_SOURCE
>>> line_tag = ah.line_tag('cmd')
>>> tagged_lines = ah.tag_lines(source, line_tag)
>>> adhoc_dump_list(tagged_lines, 40)
# :DBG: elt[0] : ]'# >:cmd:< arg0 arg1 # comment\\n'[
# :DBG: elt[1] : ]'# >:cmd:< arg2 arg3 # comment\\n'[
>>> is_re = True
>>> section_tag_rx = ah.section_tag('tag.?', is_re=is_re)
>>> body, sections = ah.tag_partition(source, section_tag_rx, is_re=is_re)
>>> adhoc_dump_list(body, 40)
# :DBG: elt[0] : ]'not in section\\n# >:cmd:< arg0 arg1 # ...'[
# :DBG: elt[1] : ]'not in section\\n'[
# :DBG: elt[2] : ]'not in section\\n'[
>>> adhoc_dump_list(sections, 40)
# :DBG: elt[0] : ]'in section\\n# >:cmd:< arg2 arg3 # comm ...'[
# :DBG: elt[1] : ]'in section\\nin section\\n'[
>>> body, sections = ah.tag_partition(source, section_tag_rx, is_re=is_re, headline=True)
>>> adhoc_dump_sections(sections, 40)
# :DBG: section[0] : ]['# <:tag:> on\\n', 'in section\\n# >:cmd:< arg2 arg3 # comm ...'][
# :DBG: section[1] : ]['# <:tag2:> on\\n', 'in section\\nin section\\n'][
>>> sections = ah.tag_sections(source, section_tag_rx, is_re=is_re, headline=True)
>>> adhoc_dump_sections(sections, 40)
# :DBG: section[0] : ]['# <:tag:> on\\n', 'in section\\n# >:cmd:< arg2 arg3 # comm ...'][
# :DBG: section[1] : ]['# <:tag2:> on\\n', 'in section\\nin section\\n'][
*Tagged Line Parsing*
- :meth:`line_tag_parse`, :meth:`line_tag_strip`
- :meth:`section_tag_parse`, :meth:`section_tag_strip`
>>> strclean(ah.line_tag_parse(tagged_lines[0], 'cmd'))
('cmd', 'arg0 arg1 # comment')
>>> strclean(ah.line_tag_strip(tagged_lines[0], 'cmd', strip_comment=True))
'arg0 arg1'
>>> strclean(ah.section_tag_parse(sections[1][0], 'tag.?', is_re=True))
('tag2', 'on')
>>> strclean(ah.section_tag_strip(sections[1][0], 'tag.?', is_re=True))
'on'
**Tagged Line/Section Transformations**
- :meth:`transform_lines`, :meth:`transform_sections`
- :meth:`line_tag_rename`, :meth:`line_tag_remove`
- :meth:`section_tag_rename`, :meth:`section_tag_remove`
- :meth:`indent_sections`
- :meth:`enable_sections`, :meth:`disable_transform`, :meth:`disable_sections`
- :meth:`remove_sections`
**IO Functions**
- :meth:`check_coding`
- :meth:`decode_source`, :meth:`encode_source`
- :meth:`read_source`, :meth:`write_source`
- :meth:`check_xfile`
- :meth:`pack_file`, :meth:`unpack_file`
**Run-Time Unpack/Import Interface**
- :meth:`unpack_`
- :meth:`import_`, :meth:`module_setup`
**Export Tools**
- :meth:`std_source_param`
- :meth:`export_source`
**Extract Interface**
- :meth:`unpack`
- :meth:`extract`
**Export Interface**
- :meth:`export__`, :meth:`export_`, :meth:`export`
**Dump Interface (Import/Unpack Substitute)**
- :meth:`dump__`, :meth:`dump_`, :meth:`dump_file`
**Macro Interface**
Naive macro expansion would violate the condition
``xsource_i === source_i``.
Here is a simple macro system which preserves the bijectivity
condition. It is quite useful for conditional templating. (See
`Use Cases`_ generator scripts).
*Limitations*
- Macro expansions are not prefixed with the current indentation
- Macros cannot be nested
*Attributes*
- :attr:`macro_call_delimiters`
Delimiters for macros, e.g.: ``@|:MACRO_NAME:|>``
- :attr:`macro_xdef_delimiters`
Delimiters for macro expansion, e.g.::
# <|:adhoc_macro_call\x3a|@
# @|:MACRO_NAME:|>
# <|:adhoc_macro_call\x3a|@
# <|:adhoc_macro_expansion\x3a|@
The macro definition ...
The macro definition ...
# <|:adhoc_macro_expansion\x3a|@
- :attr:`macros`
Macro definitions.
*Methods*
- :meth:`expand_macros`
- :meth:`has_expanded_macros`
- :meth:`activate_macros`
- :meth:`collapse_macros`
**Template Interface**
- :meth:`std_template_param`
- :meth:`get_templates`
- :meth:`template_list`, :meth:`col_param_closure`, :meth:`template_table`
- :meth:`get_named_template`
- :meth:`extract_templates`
**Template Extraction (uncompiled)**
- Expand and activate macros for uncompiled source
- Activate macros on compiled source
**Compile**
- Expand macros before compilation
**Export**
- Collapse macros on export of compiled source.
**Compilation Attributes**
- :attr:`include_path`
**Compilation Interface**
- :meth:`setup_tags`
- :meth:`strquote`
- :meth:`adhoc_run_time_sections_from_string`
- :meth:`adhoc_run_time_section_from_file`
- :meth:`adhoc_get_run_time_section`
- :meth:`prepare_run_time_section`
- :meth:`verbatim_`
- :meth:`include_`
- :meth:`encode_module_`
- :meth:`compile_`
**User API**
- :meth:`encode_include`
- :meth:`encode_module`
- :meth:`compile`
- :meth:`compileFile`
.. \\|:here:|
"""
# @:adhoc_run_time_section:@ on
# @:adhoc_run_time_section:@ off
# --------------------------------------------------
# ||:sec:|| Attributes
# --------------------------------------------------
# @:adhoc_run_time_section:@ on
line_delimiters = ('@:', ':@')
# @:adhoc_run_time_section:@ off
'''Tag delimiters for lines.'''
# @:adhoc_run_time_section:@ on
section_delimiters = ('@:', ':@')
# @:adhoc_run_time_section:@ off
'''Tag delimiters for sections.'''
# @:adhoc_run_time_section:@ on
template_process_hooks = {}
# @:adhoc_run_time_section:@ off
'''Dictionary of ``template-name, hook-function`` items.
If the name of a template section matches an item in this
dictionary, the ``hook-function`` is called::
section = hook-function(cls, section, tag, template_name)
'''
# @:adhoc_run_time_section:@ on
extra_templates = []
# @:adhoc_run_time_section:@ off
'''List of additional templates::
[(name, type), ...]
'''
# @:adhoc_run_time_section:@ on
export_dir = '__adhoc__'
# @:adhoc_run_time_section:@ off
'''Export directory (for :meth:`export`, ``--explode``).'''
# @:adhoc_run_time_section:@ on
extract_dir = '.'
# @:adhoc_run_time_section:@ off
'''Export directory (for :meth:`extract`, ``--extract``).'''
# @:adhoc_run_time_section:@ on
flat = True
# @:adhoc_run_time_section:@ off
'''If True, do not export files recursively.'''
# @:adhoc_run_time_section:@ on
forced = False
# @:adhoc_run_time_section:@ off
'''If True, allow duplicate imports.'''
# @:adhoc_run_time_section:@ on
frozen = False
# @:adhoc_run_time_section:@ off
'''If True, do not attempt to load modules from external
sources (\\|:todo:| not implemented).'''
# @:adhoc_run_time_section:@ on
quiet = False
# @:adhoc_run_time_section:@ off
'''If True, suppress warnings.'''
# @:adhoc_run_time_section:@ on
verbose = False
# @:adhoc_run_time_section:@ off
'''If True, display messages.'''
# @:adhoc_run_time_section:@ on
debug = False
# @:adhoc_run_time_section:@ off
'''If True, display debug messages.'''
# @:adhoc_run_time_section:@ on
include_path = []
# @:adhoc_run_time_section:@ off
'''Search path for include files. Only relevant during compilation.'''
# @:adhoc_run_time_section:@ on
export_need_init = {}
export_have_init = {}
extract_warn = False
# @:adhoc_run_time_section:@ off
# --------------------------------------------------
# ||:sec:|| Low-Level Functions
# --------------------------------------------------
# @:adhoc_run_time_section:@ on
def _adhoc_string_util():
# @:adhoc_run_time_section:@ off
'''Define string utilities.
- static method :meth:`isstring`
- unicode type :attr:`uc_type`
- static method :meth:`uc`
'''
# @:adhoc_run_time_section:@ on
def isstring(obj):
return isinstance(obj, basestring)
try:
isstring("")
except NameError:
def isstring(obj):
return isinstance(obj, str) or isinstance(obj, bytes)
def _uc(string):
return unicode(string, 'utf-8')
try:
_uc("")
except NameError:
_uc = lambda x: x
uc_type = type(_uc(""))
def uc(value):
if isstring(value) and not isinstance(value, uc_type):
return _uc(value)
return value
return staticmethod(isstring), uc_type, staticmethod(uc)
isstring, uc_type, uc = _adhoc_string_util()
@staticmethod
[docs] def adhoc_tag(symbol_or_re, delimiters, is_re=False): # |:fnc:|
# @:adhoc_run_time_section:@ off
'''Make a tag from symbol_or_re and delimiters.
:param symbol_or_re: symbol string or regular expresssion.
:param delimiters: tuple of delimiter strings
``(prefix, suffix)``.
:param is_re: if True, escape the delimiters for regular
expressions.
'''
# @:adhoc_run_time_section:@ on
ldlm = delimiters[0]
rdlm = delimiters[1]
if is_re:
ldlm = re.escape(ldlm)
rdlm = re.escape(rdlm)
return ''.join((ldlm, symbol_or_re, rdlm))
@classmethod
[docs] def tag_split(cls, string, tag, is_re=False): # |:fnc:|
# @:adhoc_run_time_section:@ off
"""Split string with tag line.
:returns:
a list of tuples with a flag and a section::
[(is_tag, section), ... ]
**Example**
>>> source = AH_CHECK_SOURCE
>>> printf(str(source), end='')
not in section
# >:cmd:< arg0 arg1 # comment
# <:tag:> on
in section
# >:cmd:< arg2 arg3 # comment
in section
# <:tag:> off
not in section
# <:tag2:> on
in section
in section
# <:tag2:> off
not in section
**Split on literal tag**
>>> is_re = False
>>> tag = AdHoc.adhoc_tag('tag', ('<:', ':>'), is_re)
>>> parts = AdHoc.tag_split(source, tag, is_re)
>>> adhoc_dump_sections(parts, 40)
# :DBG: section[0] : ][False, 'not in section\\n# >:cmd:< arg0 arg1 # ...'][
# :DBG: section[1] : ][True, '# <:tag:> on\\n'][
# :DBG: section[2] : ][False, 'in section\\n# >:cmd:< arg2 arg3 # comm ...'][
# :DBG: section[3] : ][True, '# <:tag:> off\\n'][
# :DBG: section[4] : ][False, 'not in section\\n# <:tag2:> on\\nin secti ...'][
**Split on tag regexp**
>>> is_re = True
>>> tag = AdHoc.adhoc_tag('tag.?', ('<:', ':>'), is_re)
>>> parts = AdHoc.tag_split(source, tag, is_re)
>>> adhoc_dump_sections(parts, 40)
# :DBG: section[0] : ][False, 'not in section\\n# >:cmd:< arg0 arg1 # ...'][
# :DBG: section[1] : ][True, '# <:tag:> on\\n'][
# :DBG: section[2] : ][False, 'in section\\n# >:cmd:< arg2 arg3 # comm ...'][
# :DBG: section[3] : ][True, '# <:tag:> off\\n'][
# :DBG: section[4] : ][False, 'not in section\\n'][
# :DBG: section[5] : ][True, '# <:tag2:> on\\n'][
# :DBG: section[6] : ][False, 'in section\\nin section\\n'][
# :DBG: section[7] : ][True, '# <:tag2:> off\\n'][
# :DBG: section[8] : ][False, 'not in section\\n'][
**Assemble section**
>>> section = []
>>> in_section = False
>>> for part in parts:
... if part[0]:
... in_section = not in_section
... continue
... if in_section:
... section.append(part[1])
>>> section = ''.join(section)
>>> printf(str(section), end='')
in section
# >:cmd:< arg2 arg3 # comment
in section
in section
in section
"""
# @:adhoc_run_time_section:@ on
if not is_re:
tag = re.escape(tag)
ro = re.compile(''.join(('^[^\n]*(', tag, ')[^\n]*$')), re.M)
result = []
last_end = 0
string = cls.decode_source(string)
for mo in re.finditer(ro, string):
start = mo.start(0)
end = mo.end(0)
result.append((False, string[last_end:start]))
result.append((True, string[start:end+1]))
last_end = end+1
result.append((False, string[last_end:]))
return result
@classmethod
[docs] def adhoc_parse_line(cls, tagged_line, symbol_or_re=None, # |:clm:|
delimiters=None, is_re=False, strip_comment=None):
# @:adhoc_run_time_section:@ off
"""Parse a tagged line into tag-symbol and argument parts.
:returns: a tuple ``(tag-symbol, tag-arguments)``.
:param tagged_line: string to be parsed.
:param symbol_or_re: symbol string or regular expresssion to
be parsed, default is any sequence of characters except the
first character of the suffix delimiter.
:param delimiters: tuple of delimiter strings
``(prefix, suffix)``. Default is :attr:`line_delimiters`.
:param strip_comment: If True, remove trailing ``#`` comment
from arguments. Default: False.
>>> tagged_line = ' # @:' 'adhoc_test' ':@ arg1 arg2 # comment'
>>> AdHoc.adhoc_parse_line(tagged_line)
('adhoc_test', 'arg1 arg2 # comment')
>>> AdHoc.adhoc_parse_line(tagged_line, 'adhoc_.*', is_re=True)
('adhoc_test', 'arg1 arg2 # comment')
>>> AdHoc.adhoc_parse_line(tagged_line, strip_comment=True)
('adhoc_test', 'arg1 arg2')
>>> AdHoc.adhoc_parse_line(tagged_line.replace('@', '<'))
('', '# <:adhoc_test:< arg1 arg2 # comment')
>>> AdHoc.adhoc_parse_line(tagged_line.replace('@', '|'), delimiters=('|:', ':|'))
('adhoc_test', 'arg1 arg2 # comment')
"""
# @:adhoc_run_time_section:@ on
if delimiters is None:
delimiters = cls.line_delimiters
if symbol_or_re is None:
dlm = delimiters[1]
if dlm:
symbol_or_re = ''.join(('[^', dlm[0], ']+'))
else:
symbol_or_re = ''.join(('[^\\s]+'))
is_re = True
if not is_re:
symbol_or_re = re.escape(symbol_or_re)
tag_rx = cls.adhoc_tag(''.join(('(', symbol_or_re, ')')), delimiters, is_re=True)
mo = re.search(tag_rx, tagged_line)
if mo:
ptag = mo.group(1)
else:
ptag = ''
strip_rx = ''.join(('^.*', tag_rx, '\\s*'))
tag_arg = re.sub(strip_rx, '', tagged_line).strip()
if strip_comment:
tag_arg = re.sub('\\s*#.*', '', tag_arg)
return (ptag, tag_arg)
# @:adhoc_run_time_section:@ off
# --------------------------------------------------
# ||:sec:|| Low-Level Convenience Functions
# --------------------------------------------------
# @:adhoc_run_time_section:@ on
@classmethod
[docs] def set_delimiters(cls, line_delimiters=None, section_delimiters=None): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Set line/section delimiters.
:returns: saved delimiter state suitable for
:meth:`reset_delimiters`.
:param line_delimiters: the line delimiters. If None, line
delimiters are not changed.
:param section_delimiters: the section delimiters. If None,
`line_delimiters` is used.
If both `line_delimiters` and `section_delimiters` are None,
the delimiter state is returned without any modification to
the current delimiters.
>>> AdHoc.set_delimiters()
(('@:', ':@'), ('@:', ':@'))
>>> sv = AdHoc.inc_delimiters()
>>> sv
(('@:', ':@'), ('@:', ':@'))
>>> AdHoc.set_delimiters()
(('@@:', ':@@'), ('@@:', ':@@'))
>>> AdHoc.reset_delimiters(sv)
>>> AdHoc.set_delimiters()
(('@:', ':@'), ('@:', ':@'))
>>> AdHoc.set_delimiters(('<:', ':>'))
(('@:', ':@'), ('@:', ':@'))
>>> AdHoc.set_delimiters()
(('<:', ':>'), ('<:', ':>'))
>>> AdHoc.reset_delimiters(sv)
>>> AdHoc.set_delimiters()
(('@:', ':@'), ('@:', ':@'))
'''
# @:adhoc_run_time_section:@ on
delimiter_state = (cls.line_delimiters, cls.section_delimiters)
if line_delimiters is None:
line_delimiters = delimiter_state[0]
if section_delimiters is None:
section_delimiters = delimiter_state[1]
elif section_delimiters is None:
section_delimiters = line_delimiters
cls.line_delimiters, cls.section_delimiters = (
line_delimiters, section_delimiters)
return delimiter_state
@classmethod
[docs] def reset_delimiters(cls, delimiter_state): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Reset line/section delimiters from saved state.
:param delimiter_state: delimiter state as returned by
:meth:`set_delimiters`.
'''
# @:adhoc_run_time_section:@ on
cls.line_delimiters, cls.section_delimiters = delimiter_state
@classmethod
[docs] def inc_delimiters(cls): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Duplicate outer delimiter characters.
:returns: saved delimiter state suitable for
:meth:`reset_delimiters`.
E.g.::
"@:", ":@" => "@@:", ":@@"
See :meth:`set_delimiters` for doctest example.
'''
# @:adhoc_run_time_section:@ on
inc_first = lambda dlm: (((not dlm) and ('')) or (dlm[0] + dlm))
inc_last = lambda dlm: (((not dlm) and ('')) or (dlm + dlm[-1]))
outer_delimiters = [(inc_first(dlm[0]), inc_last(dlm[1]))
for dlm in (cls.line_delimiters,
cls.section_delimiters)]
return cls.set_delimiters(*outer_delimiters)
@classmethod
[docs] def line_tag(cls, symbol_or_re, is_re=False): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Make a line tag from symbol or regular expression.
:returns: unicode string.
:param symbol_or_re: symbol string or regular expresssion.
:param is_re: if True, escape the delimiters for regular
expressions.
'''
# @:adhoc_run_time_section:@ on
return cls.adhoc_tag(symbol_or_re, cls.line_delimiters, is_re)
@classmethod
[docs] def section_tag(cls, symbol_or_re, is_re=False): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Make a section tag from symbol or regular expression.
:returns: unicode string.
:param symbol_or_re: symbol string or regular expresssion.
:param is_re: if True, escape the delimiters for regular
expressions.
'''
# @:adhoc_run_time_section:@ on
return cls.adhoc_tag(symbol_or_re, cls.section_delimiters, is_re)
@classmethod
[docs] def tag_lines(cls, string, tag, is_re=False): # |:clm:|
# @:adhoc_run_time_section:@ off
"""Get lines matching tag.
:returns: list of tag lines.
See :meth:`tag_split`.
"""
# @:adhoc_run_time_section:@ on
result = []
for section in cls.tag_split(string, tag, is_re):
if section[0]:
result.append(section[1])
return result
@classmethod
[docs] def tag_partition(cls, string, tag, is_re=False, headline=False): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Split the string into body parts and sections.
If `headline` is True, the starting tag line is included for
sections.'''
# @:adhoc_run_time_section:@ on
in_section = False
body_parts = []
sections = []
tagged_line = ''
for section in cls.tag_split(string, tag, is_re):
if section[0]:
in_section = not in_section
tagged_line = section[1]
continue
if in_section:
if headline:
sections.append((tagged_line, section[1]))
else:
sections.append(section[1])
else:
body_parts.append(section[1])
return body_parts, sections
@classmethod
[docs] def tag_sections(cls, string, tag, is_re=False, headline=False): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Split the string into sections.
If `headline` is True, the starting tag line is included.
See :meth:`tag_partition`.
'''
# @:adhoc_run_time_section:@ on
body_parts, sections = cls.tag_partition(string, tag, is_re, headline)
return sections
@classmethod
[docs] def line_tag_parse(cls, tagged_line, symbol_or_re=None, is_re=False, # |:clm:|
strip_comment=None):
# @:adhoc_run_time_section:@ off
"""Parse a line tag line into tag-symbol and argument parts.
:returns: a tuple ``(tag-symbol, tag-arguments)``.
See :meth:`adhoc_parse_line`.
"""
# @:adhoc_run_time_section:@ on
return cls.adhoc_parse_line(tagged_line, symbol_or_re, cls.line_delimiters,
is_re, strip_comment=strip_comment)
@classmethod
[docs] def line_tag_strip(cls, tagged_line, symbol_or_re=None, is_re=False, # |:clm:|
strip_comment=None):
# @:adhoc_run_time_section:@ off
"""Remove tag and optionally comment from line tag line.
:returns: tag arguments.
See :meth:`adhoc_parse_line`.
"""
# @:adhoc_run_time_section:@ on
return cls.line_tag_parse(tagged_line, symbol_or_re, is_re, strip_comment)[1]
@classmethod
[docs] def section_tag_parse(cls, tagged_line, symbol_or_re=None, is_re=False, # |:clm:|
strip_comment=None):
# @:adhoc_run_time_section:@ off
"""Parse a section tag line into tag-symbol and argument parts.
:returns: a tuple ``(tag-symbol, tag-arguments)``.
See :meth:`adhoc_parse_line`.
"""
# @:adhoc_run_time_section:@ on
return cls.adhoc_parse_line(tagged_line, symbol_or_re, cls.section_delimiters,
is_re, strip_comment=strip_comment)
@classmethod
[docs] def section_tag_strip(cls, tagged_line, symbol_or_re=None, is_re=False, # |:clm:|
strip_comment=None):
# @:adhoc_run_time_section:@ off
"""Remove tag and optionally comment from section tag line.
:returns: tag arguments.
See :meth:`adhoc_parse_line`.
"""
# @:adhoc_run_time_section:@ on
return cls.section_tag_parse(tagged_line, symbol_or_re, is_re, strip_comment)[1]
# @:adhoc_run_time_section:@ off
# --------------------------------------------------
# ||:sec:|| Tagged Line/Section Transformations
# --------------------------------------------------
# @:adhoc_run_time_section:@ on
@classmethod
@classmethod
@classmethod
[docs] def line_tag_rename(cls, string, symbol_or_re, renamed, is_re=False, delimiters=None): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Rename tag-symbol.
Default tag delimiters are :attr:`line_delimiters`.
>>> tpl = AdHoc.get_named_template("col-param-closure")
.. >>> printf(str(AdHoc.line_tag_rename(tpl, "adhoc_run_time_section", "should_be_kept")))
'''
# @:adhoc_run_time_section:@ on
if is_re:
transform = lambda blob: re.sub(symbol_or_re, renamed, blob)
else:
transform = lambda blob: blob.replace(symbol_or_re, renamed)
return cls.transform_lines(transform, string, symbol_or_re, is_re, delimiters)
@classmethod
[docs] def line_tag_remove(cls, string, symbol_or_re, is_re=False, delimiters=None): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Remove tagged lines.
Default tag delimiters are :attr:`line_delimiters`.
>>> tpl = AdHoc.get_named_template("col-param-closure")
.. >>> printf(str(AdHoc.line_tag_remove(tpl, "adhoc_run_time_section")))
'''
# @:adhoc_run_time_section:@ on
transform = lambda blob: ''
return cls.transform_lines(transform, string, symbol_or_re, is_re, delimiters)
@classmethod
[docs] def section_tag_rename(cls, string, symbol_or_re, renamed, is_re=False): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Rename tag-symbol of lines tagged with :attr:`section_delimiters`.
>>> tpl = AdHoc.get_named_template("col-param-closure")
>>> res = AdHoc.section_tag_rename(tpl, "adhoc_run_time_section", "should_be_kept")
>>> res = '\\n'.join(res.splitlines()[:4])
>>> printf(str(res)) #doctest: +ELLIPSIS
# @:should_be_kept:@ on
@classmethod
def col_param_closure(cls):...
# @:should_be_kept:@ off
'''
# @:adhoc_run_time_section:@ on
if is_re:
transform = lambda blob: re.sub(symbol_or_re, renamed, blob)
else:
transform = lambda blob: blob.replace(symbol_or_re, renamed)
return cls.transform_lines(transform, string, symbol_or_re, is_re, cls.section_delimiters)
@classmethod
[docs] def section_tag_remove(cls, string, symbol_or_re, is_re=False): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Remove lines tagged with :attr:`section_delimiters`.
>>> tpl = AdHoc.get_named_template("col-param-closure")
>>> res = AdHoc.section_tag_remove(tpl, "adhoc_run_time_section")
>>> res = '\\n'.join(res.splitlines()[:4])
>>> printf(str(res)) #doctest: +ELLIPSIS
@classmethod
def col_param_closure(cls):...
...Closure for setting up maximum width, padding and separator
for table columns.
'''
# @:adhoc_run_time_section:@ on
transform = lambda blob: ''
return cls.transform_lines(transform, string, symbol_or_re, is_re, cls.section_delimiters)
@classmethod
[docs] def indent_sections(cls, string, symbol_or_re, is_re=False): # |:clm:|
# @:adhoc_run_time_section:@ off
'''
>>> section = """\\
... # prefix
... # @:adhoc_indent_check:@ +4
... #line 1
... # line 2
... #
... # line 3
... # @:adhoc_indent_check:@
... # suffix\\
... """
>>> printf(AdHoc.indent_sections(section, "adhoc_indent_check"))
# prefix
# @:adhoc_indent_check:@ +4
#line 1
# line 2
#
# line 3
# @:adhoc_indent_check:@
# suffix
>>> printf(AdHoc.indent_sections(section.replace("+4", "-1"),
... "adhoc_indent_check"))
# prefix
# @:adhoc_indent_check:@ -1
#line 1
# line 2
#
# line 3
# @:adhoc_indent_check:@
# suffix
'''
# @:adhoc_run_time_section:@ on
result = []
in_section = False
indent = 0
for section in cls.tag_split(
string, cls.section_tag(symbol_or_re, is_re), is_re):
blob = section[1]
if section[0]:
in_section = not in_section
if in_section:
tag_arg = cls.section_tag_strip(blob)
if tag_arg:
indent = int(tag_arg)
else:
indent = -4
else:
if in_section and indent:
if indent < 0:
rx = re.compile(''.join(('^', ' ' * (-indent))), re.M)
blob = rx.sub('', blob)
elif indent > 0:
rx = re.compile('^', re.M)
blob = rx.sub(' ' * indent, blob)
indent = 0
result.append(blob)
string = ''.join(result)
return string
@classmethod
[docs] def enable_sections(cls, string, symbol_or_re, is_re=False): # |:clm:|
# @:adhoc_run_time_section:@ off
'''
>>> section = """\\
... # prefix
... # @:adhoc_enable_check:@
... #line 1
... # line 2
... #
... # line 3
... # @:adhoc_enable_check:@
... # suffix\\
... """
>>> printf(AdHoc.enable_sections(section, "adhoc_enable_check"))
# prefix
# @:adhoc_enable_check:@
line 1
line 2
<BLANKLINE>
line 3
# @:adhoc_enable_check:@
# suffix
'''
# @:adhoc_run_time_section:@ on
enable_ro = re.compile('^([ \t\r]*)(# ?)', re.M)
enable_sub = '\\1'
transform = lambda blob, hl: (enable_ro.sub(enable_sub, blob), hl)
return cls.transform_sections(transform, string, symbol_or_re, is_re)
adhoc_rx_tab_check = re.compile('^([ ]*\t)', re.M)
adhoc_rx_disable_simple = re.compile('^', re.M)
adhoc_rx_min_indent_check = re.compile('^([ ]*)([^ \t\r\n]|$)', re.M)
@classmethod
@classmethod
[docs] def disable_sections(cls, string, symbol_or_re, is_re=False): # |:clm:|
# @:adhoc_run_time_section:@ off
'''
>>> section = """\\
... prefix
... @:adhoc_disable_check:@
... line 1
... line 2
...
... line 3
... @:adhoc_disable_check:@
... suffix\\
... """
>>> printf(AdHoc.disable_sections(section, "adhoc_disable_check"))
prefix
@:adhoc_disable_check:@
# line 1
# line 2
<BLANKLINE>
# line 3
@:adhoc_disable_check:@
suffix
'''
# @:adhoc_run_time_section:@ on
return cls.transform_sections(
cls.disable_transform, string, symbol_or_re, is_re)
@classmethod
[docs] def remove_sections(cls, string, symbol_or_re, is_re=False): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Remove sections.'''
# @:adhoc_run_time_section:@ on
ah_retained, ah_removed = cls.tag_partition(
string, cls.section_tag(symbol_or_re, is_re), is_re)
return ''.join(ah_retained)
# @:adhoc_run_time_section:@ off
# --------------------------------------------------
# ||:sec:|| IO Functions
# --------------------------------------------------
# @:adhoc_run_time_section:@ on
@staticmethod
[docs] def check_coding(source): # |:fnc:|
# @:adhoc_run_time_section:@ off
'''Determine coding for source.
:returns: coding type for string.
:param source: source string/unicode.
If the ``source`` string contains a coding specification
within the first two lines, the specified coding is used,
otherwise, ``UTF-8`` is returned.
'''
# @:adhoc_run_time_section:@ on
if source:
eol_seen = 0
for c in source:
if isinstance(c, int):
lt_ = lambda a, b: a < b
chr_ = lambda a: chr(a)
else:
lt_ = lambda a, b: True
chr_ = lambda a: a
break
check = []
for c in source:
if lt_(c, 127):
check.append(chr_(c))
if c == '\n':
eol_seen += 1
if eol_seen == 2:
break
check = ''.join(check)
mo = re.search('-[*]-.*coding:\\s*([^;\\s]+).*-[*]-', check)
else:
mo = None
if mo:
coding = mo.group(1)
else:
coding = 'utf-8'
return coding
@classmethod
[docs] def decode_source(cls, source): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Decode source to unicode.
:param source: source string (may already be unicode).
If the ``source`` string contains a coding specification
within the first two lines, the specified coding is used,
otherwise, ``UTF-8`` is applied.
'''
# @:adhoc_run_time_section:@ on
if not source:
return cls.uc('')
if not isinstance(source, cls.uc_type) and hasattr(source, 'decode'):
source = source.decode(cls.check_coding(source))
return source
@classmethod
[docs] def encode_source(cls, source): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Encode source from unicode.
:param source: source string (may already be encoded).
If the ``source`` string contains a coding specification
within the first two lines, the specified coding is used,
otherwise, ``UTF-8`` is applied.
'''
# @:adhoc_run_time_section:@ on
if not source:
return ''.encode('utf-8')
if isinstance(source, cls.uc_type) and hasattr(source, 'encode'):
source = source.encode(cls.check_coding(source))
return source
@classmethod
[docs] def read_source(cls, file_, decode=True): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Read source from file.
:returns: unicode string.
:param file_: If None, empty or ``-``, sys.stdin is used,
otherwise the file is read from ``file_`` and decoded with
:meth:`decode_source`.
'''
# @:adhoc_run_time_section:@ on
source = None
if not file_ or file_ == '-':
# Python3 has a buffer attribute for binary input.
if hasattr(sys.stdin, 'buffer'):
source = sys.stdin.buffer.read()
else:
source = sys.stdin.read()
else:
try:
sf = open(file_, 'rb')
source = sf.read()
sf.close()
except IOError:
for module in sys.modules.values():
if (module
and hasattr(module, '__file__')
and module.__file__ == file_):
if (hasattr(module, '__adhoc__')
and hasattr(module.__adhoc__, 'source')):
source = module.__adhoc__.source
break
if source is None:
raise IOError('source not found for `' + str(file_) + '`')
if decode:
return cls.decode_source(source)
return source
@classmethod
[docs] def write_source(cls, file_, source, mtime=None, mode=None): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Write source to file.
:param file_: If None, empty or ``-``, sys.stdout is used,
otherwise the file is written to ``file_`` after encoding
with :meth:`encode_source`.
'''
# @:adhoc_run_time_section:@ on
esource = cls.encode_source(source)
if not file_ or file_ == '-':
# @:adhoc_run_time_section:@ off
# For Python2, sys.stdout is effectively binary, so source
# can be pre-encoded.
#
# With Python3 sys.stdout does automatic encoding (which
# is unwanted).
# Normal sys.stdout has a buffer member which allows
# binary output, but not during doctest.
# @:adhoc_run_time_section:@ on
if hasattr(sys.stdout, 'buffer'):
sys.stdout.buffer.write(esource)
else:
try:
sys.stdout.write(esource)
except TypeError:
sys.stdout.write(source)
else:
sf = open(file_, 'wb')
sf.write(esource)
sf.close()
if mode is not None:
os.chmod(file_, mode)
if mtime is not None:
import datetime
if cls.isstring(mtime):
try:
date, ms = mtime.split('.')
except ValueError:
date = mtime
ms = 0
mtime = cls.strptime(date, '%Y-%m-%dT%H:%M:%S')
mtime += datetime.timedelta(microseconds=int(ms))
if isinstance(mtime, datetime.datetime):
# @:adhoc_run_time_section:@ off
# import calendar
# if mtime.utcoffset() is not None:
# mtime = mtime - mtime.utcoffset()
# millis = int(calendar.timegm(mtime.timetuple()) * 1000 +
# mtime.microsecond / 1000)
# ts = float(millis) / 1000
# @:adhoc_run_time_section:@ on
ts = int(mtime.strftime("%s"))
else:
ts = mtime
os.utime(file_, (ts, ts))
@classmethod
[docs] def check_xfile(cls, file_, xdir=None): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Prepare extraction of a file.
:returns: None, if the file already exists. Otherwise, the
file directory is created and the absolute path name of the
file is returned.
:param file_: filename.
:param xdir: extraction directory. If it is `None`,
:attr:`extract_dir` is used.
If ``file_`` is `None`, empty or ``-``, the filename ``-`` is
returned.
If ``file_`` starts with a slash ``/``, ``xdir`` is ignored,
otherwise, ``xdir`` is prepended to ``file_``.
'''
# @:adhoc_run_time_section:@ on
if xdir is None:
xdir = cls.extract_dir
if not file_:
file_ = '-'
if file_ == '-':
return file_
file_ = os.path.expanduser(file_)
if os.path.isabs(file_):
xfile = file_
else:
xfile = os.path.join(xdir, file_)
xfile = os.path.abspath(xfile)
if os.path.exists(xfile):
# do not overwrite files
if (cls.extract_warn or (cls.verbose)) and not cls.quiet:
list(map(sys.stderr.write, (
"# xf: ", cls.__name__, ": warning file `", file_,
"` exists. skipping ...\n")))
return None
xdir = os.path.dirname(xfile)
if not os.path.exists(xdir):
os.makedirs(xdir)
return xfile
@classmethod
[docs] def pack_file(cls, source, zipped=True): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Optionally gzip a file and base64-encode it.
:returns: base64-encoded unicode string.
:param source: string to be packed.
:param zipped: if True, gzip ``source`` before
base64-encoding. (Default: True).
'''
# @:adhoc_run_time_section:@ on
import base64, gzip
if zipped:
sio = _AdHocBytesIO()
gzf = gzip.GzipFile('', 'wb', 9, sio)
gzf.write(cls.encode_source(source))
gzf.close()
source = sio.getvalue()
sio.close()
else:
source = cls.encode_source(source)
source = base64.b64encode(source)
source = source.decode('ascii')
return source
@classmethod
[docs] def unpack_file(cls, source64, zipped=True, decode=True): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Base64-decode a file and optionally ungzip it.
:returns: unicode string if ``decode`` is True.
:param source64: base64 encoded unicode string to be unpacked.
:param zipped: if True, ungzip ``source`` after
base64-decoding. (Default: True).
'''
# @:adhoc_run_time_section:@ on
import base64, gzip
# @:adhoc_run_time_section:@ off
if cls.debug:
printf(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5:>7d}[ ]{6!s}[ {7}",
dbg_comm, dbg_twid, dbg_fwid,
':DBG:', 'source64', len(source64), source64[:80],
'b64decode ...'))
# @:adhoc_run_time_section:@ on
source = source64.encode('ascii')
source = base64.b64decode(source)
if zipped:
# @:adhoc_run_time_section:@ off
if cls.debug:
printf(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5:>7d}[ ]{6!s}[ {7}",
dbg_comm, dbg_twid, dbg_fwid,
':DBG:', 'source (zip)', len(source), repr(source)[:80],
'unzipping ...'))
# @:adhoc_run_time_section:@ on
sio = _AdHocBytesIO(source)
gzf = gzip.GzipFile('', 'rb', 9, sio)
source = gzf.read()
gzf.close()
sio.close()
if decode:
source = cls.decode_source(source)
# @:adhoc_run_time_section:@ off
if cls.debug:
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5:>7d}[ ]{6!s}[",
dbg_comm, dbg_twid, dbg_fwid,
':DBG:', 'source', len(source), repr(source)[:80]))
# @:adhoc_run_time_section:@ on
return source
# @:adhoc_run_time_section:@ off
# --------------------------------------------------
# ||:sec:|| Run-Time Unpack/Import Interface
# --------------------------------------------------
# @:adhoc_run_time_section:@ on
@classmethod
[docs] def unpack_(cls, mod_name=None, file_=None, mtime=None, # |:clm:||:api_fi:|
mode=None, zipped=True, flat=None, source64=None):
# @:adhoc_run_time_section:@ off
"""Unpack adhoc'ed file, if it does not exist."""
# @:adhoc_run_time_section:@ on
xfile = cls.check_xfile(file_, cls.extract_dir)
if xfile is None:
return
if cls.verbose:
list(map(sys.stderr.write,
("# xf: ", cls.__name__, ": unpacking `", file_, "`\n")))
source = cls.unpack_file(source64, zipped=zipped, decode=False)
cls.write_source(xfile, source, mtime, mode)
@classmethod
[docs] def strptime(cls, date_string, format_): # |:clm:|
# @:adhoc_run_time_section:@ off
"""Python 2.4 compatible"""
# @:adhoc_run_time_section:@ on
import datetime
if hasattr(datetime.datetime, 'strptime'):
strptime_ = datetime.datetime.strptime
else:
import time
strptime_ = lambda date_string, format_: (
datetime.datetime(*(time.strptime(date_string, format_)[0:6])))
return strptime_(date_string, format_)
@classmethod
[docs] def import_(cls, mod_name=None, file_=None, mtime=None, # |:clm:||:api_fi:|
mode=None, zipped=True, flat=None, source64=None):
# @:adhoc_run_time_section:@ off
"""Import adhoc'ed module."""
# @:adhoc_run_time_section:@ on
import datetime
import time
module = cls.module_setup(mod_name)
if mtime is None:
mtime = datetime.datetime.fromtimestamp(0)
else:
# mtime=2011-11-23T18:04:26[.218506], zipped=True, flat=None, source64=
try:
date, ms = mtime.split('.')
except ValueError:
date = mtime
ms = 0
mtime = cls.strptime(date, '%Y-%m-%dT%H:%M:%S')
mtime += datetime.timedelta(microseconds=int(ms))
source = cls.unpack_file(source64, zipped=zipped, decode=False)
# @:adhoc_run_time_section:@ off
# |:todo:| add to parent module
# @:adhoc_run_time_section:@ on
mod_parts = mod_name.split('.')
mod_child = mod_parts[-1]
parent = '.'.join(mod_parts[:-1])
# @:adhoc_run_time_section:@ off
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'parent', parent))
# @:adhoc_run_time_section:@ on
old_mtime = module.__adhoc__.mtime
module = cls.module_setup(mod_name, file_, mtime, source, mode)
if len(parent) > 0:
setattr(sys.modules[parent], mod_child, module)
if module.__adhoc__.mtime != old_mtime:
# @:adhoc_run_time_section:@ off
printf(sformat('{0}Executing source', dbg_comm))
# @:adhoc_run_time_section:@ on
source = cls.encode_source(module.__adhoc__.source)
exec(source, module.__dict__)
# @:adhoc_run_time_section:@ off
msg = (((mod_name in sys.modules) and ('YES')) or ('NO'))
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
mod_name + ' imported', msg))
module_name = module.__name__
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'module_name', module_name))
dump_attr(module, wid=80, trunc=5)
# @:adhoc_run_time_section:@ on
@classmethod
[docs] def module_setup(cls, module=None, file_=None, mtime=None, # |:clm:||:api_fi:|
source=None, mode=None):
# @:adhoc_run_time_section:@ off
'''Setup module for `AdHoc`.
\\|:todo:| various modes are possible:
- always use newest version (development) (currently implemented)
- always use adhoc\'ed version (freeze) (not implemented)
'''
# @:adhoc_run_time_section:@ on
m = 'ms: '
class Attr: # |:cls:|
pass
import types, datetime, os
if not isinstance(module, types.ModuleType):
mod_name = module
if mod_name is None:
mod_name = __name__
try:
if mod_name not in sys.modules:
# @:adhoc_run_time_section:@ off
if cls.verbose:
printe(sformat('{0}{1}__import__({2})',
dbg_comm, m, mod_name))
# @:adhoc_run_time_section:@ on
__import__(mod_name)
module = sys.modules[mod_name]
except (ImportError, KeyError):
# @:adhoc_run_time_section:@ off
if cls.verbose:
printe(sformat('{0}{1}imp.new_module({2})',
dbg_comm, m, mod_name))
# @:adhoc_run_time_section:@ on
import imp
module = imp.new_module(mod_name)
sys.modules[mod_name] = module
else:
mod_name = module.__name__
if mtime is None:
if (file_ is not None
or source is not None):
# the info is marked as outdated
mtime = datetime.datetime.fromtimestamp(1)
else:
# the info is marked as very outdated
mtime = datetime.datetime.fromtimestamp(0)
if not hasattr(module, '__adhoc__'):
adhoc = Attr()
setattr(module, '__adhoc__', adhoc)
setattr(adhoc, '__module__', module)
mtime_set = None
mode_set = mode
if hasattr(module, '__file__'):
module_file = module.__file__
if module_file.endswith('.pyc'):
module_file = module_file[:-1]
if os.access(module_file, os.R_OK):
stat = os.stat(module_file)
mtime_set = datetime.datetime.fromtimestamp(
stat.st_mtime)
mode_set = stat.st_mode
if mtime_set is None:
# the info is marked as very outdated
mtime_set = datetime.datetime.fromtimestamp(0)
adhoc.mtime = mtime_set
adhoc.mode = mode_set
else:
adhoc = module.__adhoc__
if (mtime > adhoc.mtime
or not hasattr(module, '__file__')):
if file_ is not None:
setattr(module, '__file__', file_)
if os.access(file_, os.R_OK): # |:api_fi:|
stat = os.stat(file_)
adhoc.mtime = datetime.datetime.fromtimestamp(
stat.st_mtime)
adhoc.mode = stat.st_mode
if adhoc.mtime > mtime:
# the file on disk is newer than the adhoc'ed source
try:
delattr(adhoc, 'source')
except AttributeError:
pass
source = None
if (mtime > adhoc.mtime
or not hasattr(adhoc, 'source')):
if source is not None:
adhoc.source = source
adhoc.mtime = mtime
adhoc.mode = mode
if not hasattr(adhoc, 'source'):
try:
file_ = module.__file__
file_, source = cls.std_source_param(file_, source)
adhoc.source = source
except (AttributeError, IOError):
# @:adhoc_run_time_section:@ off
# if hasattr(module, '__path__'): # |:debug:|
# list(map(sys.stderr.write,
# ('module path: ', module.__path__, '\n')))
# else:
# sys.stderr.write('no module.__path__\n')
# list(map(sys.stderr.write,
# [''.join((attr, str(value), "\n")) for attr, value in
# filter(lambda i: i[0] != '__builtins__',
# sorted(vars(module).items()))]))
if cls.verbose:
(t, e, tb) = sys.exc_info()
import traceback
printe(''.join(traceback.format_tb(tb)), end='')
printe(sformat('{0}: {1}', t.__name__, e))
del(tb)
# @:adhoc_run_time_section:@ on
pass
return module
# @:adhoc_run_time_section:@ off
# --------------------------------------------------
# ||:sec:|| Export Tools
# --------------------------------------------------
# @:adhoc_run_time_section:@ on
@classmethod
[docs] def std_source_param(cls, file_=None, source=None): # |:clm:||:api_fi:|
# @:adhoc_run_time_section:@ off
'''Setup standard source parameters.
:returns: tuple ``( file_, source )``
:param file_: If None, `__file__` is used. If it ends with
``.pyc``, it is transformed to ``.py``.
:param source: If None, the result of :meth:`read_source` is
used.
'''
# @:adhoc_run_time_section:@ on
if file_ is None:
file_ = __file__
if file_.endswith('.pyc'):
file_ = file_[:-1]
if source is None:
source = cls.read_source(file_)
return (file_, source)
@classmethod
[docs] def export_source(cls, string, no_remove=False, no_disable=False): # |:clm:|
# @:adhoc_run_time_section:@ off
'''
============================ =========================
check for |adhoc_remove| sections and remove them!
check for |adhoc_import| sections and remove them!
check for |adhoc_unpack| sections and remove them!
check for |adhoc_template_v| sections and remove them!
check for |adhoc_disable| sections and enable them!
check for |adhoc_enable| sections and disable them!
check for |adhoc_remove_| section markers and rename them!
============================ =========================
'''
# @:adhoc_run_time_section:@ on
string = cls.collapse_macros(string)
if not no_remove:
string = cls.remove_sections(string, 'adhoc_remove')
string = cls.remove_sections(string, 'adhoc_import')
string = cls.remove_sections(string, 'adhoc_unpack')
string = cls.remove_sections(string, 'adhoc_template_v')
if not no_disable:
string = cls.enable_sections(string, 'adhoc_disable')
string = cls.disable_sections(string, 'adhoc_enable')
if not no_remove:
string = cls.section_tag_rename(string, 'adhoc_remove_', 'adhoc_remove')
return string
# @:adhoc_run_time_section:@ off
# --------------------------------------------------
# ||:sec:|| Extract Interface
# --------------------------------------------------
# @:adhoc_run_time_section:@ on
@classmethod
[docs] def unpack(cls, file_=None, source=None): # |:clm:|
# @:adhoc_run_time_section:@ off
"""Unpack all adhoc'ed files in |adhoc_unpack| sections."""
# @:adhoc_run_time_section:@ on
file_, source = cls.std_source_param(file_, source)
source_sections, unpack_sections = cls.tag_partition(
source, cls.section_tag('adhoc_unpack'))
sv_extract_warn = cls.extract_warn
cls.extract_warn = True
unpack_call = ''.join((cls.__name__, '.unpack_'))
for unpack_section in unpack_sections:
unpack_section = re.sub('^\\s+', '', unpack_section)
unpack_section = re.sub(
'^[^(]*(?s)', unpack_call, unpack_section)
try:
#RtAdHoc = cls # unpack_call takes care of this
exec(unpack_section.lstrip(), globals(), locals())
except IndentationError:
sys.stderr.write("!!! IndentationError !!!\n")
# @:adhoc_run_time_section:@ off
sys.stderr.write(''.join((unpack_section, "\n")))
# @:adhoc_run_time_section:@ on
cls.extract_warn = sv_extract_warn
@classmethod
@classmethod
def export__(cls, mod_name=None, file_=None, mtime=None, # |:clm:||:api_fi:|
mode=None, zipped=True, flat=None, source64=None):
source = cls.unpack_file(source64, zipped=zipped, decode=False)
# @:adhoc_run_time_section:@ off
if cls.debug:
sys.stderr.write(
''.join(("# xp: ", cls.__name__, ".export__ for `",
file_, "`\n")))
# @:adhoc_run_time_section:@ on
if file_ is None:
return
file_base = os.path.basename(file_)
if file_base.startswith('__init__.py'):
is_init = True
else:
is_init = False
parts = mod_name.split('.')
base = parts.pop()
if parts:
module_dir = os.path.join(*parts)
cls.export_need_init[module_dir] = True
else:
module_dir = ''
if is_init:
module_dir = os.path.join(module_dir, base)
cls.export_have_init[module_dir] = True
module_file = os.path.join(module_dir, file_base)
cls.export_(source, module_file, mtime, mode, flat)
@classmethod
def export_(cls, source, file_, mtime, mode, flat=None): # |:clm:|
cflat = cls.flat
if flat is None:
flat = cflat
cls.flat = flat
if not flat:
# extract to export directory
sv_extract_dir = cls.extract_dir
cls.extract_dir = cls.export_dir
cls.extract(file_, source)
cls.extract_dir = sv_extract_dir
source_sections, import_sections = cls.tag_partition(
source, cls.section_tag('adhoc_import'))
source = cls.export_source(''.join(source_sections))
export_call = ''.join((cls.__name__, '.export__'))
xfile = cls.check_xfile(file_, cls.export_dir)
if xfile is not None:
cls.write_source(xfile, source, mtime, mode)
if cls.verbose:
list(map(sys.stderr.write,
("# xp: ", cls.__name__, ".export_ for `", file_,
"` using `", export_call,"`\n")))
for import_section in import_sections:
# this calls RtAdHoc.export__
import_section = re.sub('^\\s+', '', import_section)
import_section = re.sub(
'^[^(]*(?s)', export_call, import_section)
try:
#RtAdHoc = cls # export_call takes care of this
exec(import_section, globals(), locals())
except IndentationError:
sys.stderr.write("!!! IndentationError !!!\n")
# @:adhoc_run_time_section:@ off
sys.stderr.write(''.join((import_section, "\n")))
# @:adhoc_run_time_section:@ on
else:
xfile = cls.check_xfile(file_, cls.export_dir)
if xfile is not None:
cls.write_source(xfile, source, mtime, mode)
if cls.verbose:
list(map(sys.stderr.write,
("# xp: ", cls.__name__, ".export_ for `", file_,
"` using `", export_call,"`\n")))
cls.flat = cflat
# @:adhoc_run_time_section:@ off
default_engine = False
# @:adhoc_run_time_section:@ on
@classmethod
def export(cls, file_=None, source=None): # |:clm:|
file_, source = cls.std_source_param(file_, source)
# @:adhoc_run_time_section:@ off
# |:todo:| this chaos needs cleanup (cls.import_/cls.export__)
# @:adhoc_run_time_section:@ on
sv_import = cls.import_
cls.import_ = cls.export__
file_ = os.path.basename(file_)
# @:adhoc_run_time_section:@ off
if cls.verbose:
list(map(sys.stderr.write,
("# xp: ", cls.__name__, ".export for `", file_, "`\n")))
# @:adhoc_run_time_section:@ on
cls.export_(source, file_, None, None, False)
sv_extract_dir = cls.extract_dir
cls.extract_dir = cls.export_dir
engine_tag = cls.section_tag('adhoc_run_time_engine')
engine_source = cls.export_source(
source, no_remove=True, no_disable=True)
engine_source = cls.get_named_template(
None, file_, engine_source, tag=engine_tag, ignore_mark=True)
# @:adhoc_run_time_section:@ off
if cls.default_engine and not engine_source:
state = cls.set_delimiters(('@:', ':@'))
ah = cls()
engine_source = ah.prepare_run_time_section()
engine_source = cls.get_named_template(
None, file_, engine_source, tag=engine_tag, ignore_mark=True)
cls.reset_delimiters(state)
# @:adhoc_run_time_section:@ on
if engine_source:
efile = cls.check_xfile('rt_adhoc.py')
if efile is not None:
cls.write_source(efile, engine_source)
cls.extract_dir = sv_extract_dir
for init_dir in cls.export_need_init:
if not cls.export_have_init[init_dir]:
if cls.verbose:
list(map(sys.stderr.write,
("# xp: create __init__.py in `", init_dir, "`\n")))
inf = open(os.path.join(
cls.export_dir, init_dir, '__init__.py'), 'w')
inf.write('')
inf.close()
cls.import_ = sv_import
# @:adhoc_run_time_section:@ off
# --------------------------------------------------
# ||:sec:|| Dump Interface (Import/Unpack Substitute)
# --------------------------------------------------
# @:adhoc_run_time_section:@ on
@classmethod
def dump__(cls, mod_name=None, file_=None, mtime=None, # |:clm:||:api_fi:|
mode=None, zipped=True, flat=None, source64=None):
if cls.verbose:
list(map(sys.stderr.write,
("# xf: ", cls.__name__, ": dumping `", file_, "`\n")))
source = cls.unpack_file(source64, zipped=zipped, decode=False)
return source
@classmethod
def dump_(cls, dump_section, dump_type=None): # |:clm:|
if dump_type is None:
dump_type = 'adhoc_import'
if not dump_section:
return ''
dump_call = ''.join(('unpacked = ', cls.__name__, '.dump__'))
dump_section = re.sub('^\\s+', '', dump_section)
dump_section = re.sub(
'^[^(]*(?s)', dump_call, dump_section)
dump_dict = {'unpacked': ''}
try:
#RtAdHoc = cls # dump_call takes care of this
exec(dump_section.lstrip(), globals(), dump_dict)
except IndentationError:
sys.stderr.write("!!! IndentationError !!!\n")
# @:adhoc_run_time_section:@ off
sys.stderr.write(''.join((dump_section, "\n")))
# @:adhoc_run_time_section:@ on
return dump_dict['unpacked']
@classmethod
def dump_file(cls, match, file_=None, source=None, tag=None, # |:clm:|
is_re=False):
file_, source = cls.std_source_param(file_, source)
if tag is None:
tag = cls.section_tag('(adhoc_import|adhoc_update)', is_re=True)
is_re = True
source_sections, dump_sections = cls.tag_partition(
source, tag, is_re, headline=True)
dump_call = ''.join((cls.__name__, '.dump_'))
for dump_section in dump_sections:
tagged_line = dump_section[0]
dump_section = dump_section[1]
tag_arg = cls.section_tag_strip(tagged_line)
check_match = match
if tag_arg != match and not match.startswith('-'):
check_match = ''.join(('-', match))
if tag_arg != match and not match.startswith('!'):
check_match = ''.join(('!', match))
if tag_arg != match:
continue
dump_section = re.sub('^\\s+', '', dump_section)
dump_section = re.sub(
'^[^(]*(?s)', dump_call, dump_section)
try:
#RtAdHoc = cls # dump_call takes care of this
exec(dump_section.lstrip(), globals(), locals())
except IndentationError:
sys.stderr.write("!!! IndentationError !!!\n")
# @:adhoc_run_time_section:@ off
sys.stderr.write(''.join((dump_section, "\n")))
# @:adhoc_run_time_section:@ on
# @:adhoc_run_time_section:@ off
# --------------------------------------------------
# ||:sec:|| Macros
# --------------------------------------------------
# @:adhoc_run_time_section:@ on
macro_call_delimiters = ('@|:', ':|>')
# @:adhoc_run_time_section:@ off
"""Macro delimiters"""
# @:adhoc_run_time_section:@ on
macro_xdef_delimiters = ('<|:', ':|@')
# @:adhoc_run_time_section:@ off
"""Macro expansion delimiters"""
# @:adhoc_run_time_section:@ on
macros = {}
# @:adhoc_run_time_section:@ off
"""Macros"""
# @:adhoc_run_time_section:@ on
@classmethod
[docs] def expand_macros(cls, source, macro_call_dlm=None, macro_xdef_dlm=None): # |:clm:|
# @:adhoc_run_time_section:@ off
"""
>>> AdHoc.macros['uc_descr_end'] = (
... '# o:' 'adhoc_template:>\\n'
... '# <:' 'adhoc_uncomment:>\\n'
... )
>>> macro_source = '# ' + AdHoc.adhoc_tag('uc_descr_end', AdHoc.macro_call_delimiters) + '\\n'
>>> ign = sys.stdout.write(macro_source) #doctest: +ELLIPSIS
# @|:uc_descr_end...:|>
>>> ign = sys.stdout.write(AdHoc.expand_macros(macro_source)) #doctest: +ELLIPSIS
# <|:adhoc_macro_call...:|@
# @|:uc_descr_end...:|>
# <|:adhoc_macro_call...:|@
# <|:adhoc_macro_expansion...:|@
# o:adhoc_template...:>
# <:adhoc_uncomment...:>
# <|:adhoc_macro_expansion...:|@
"""
# @:adhoc_run_time_section:@ on
if macro_call_dlm is None:
macro_call_dlm = cls.macro_call_delimiters
if macro_xdef_dlm is None:
macro_xdef_dlm = cls.macro_xdef_delimiters
import re
for macro_name, macro_expansion in cls.macros.items():
macro_tag = cls.adhoc_tag(macro_name, macro_call_dlm, False)
macro_tag_rx = cls.adhoc_tag(macro_name, macro_call_dlm, True)
macro_call = ''.join(('# ', macro_tag, '\n'))
macro_call_rx = ''.join(('^[^\n]*', macro_tag_rx, '[^\n]*\n'))
mc_tag = ''.join(('# ', cls.adhoc_tag('adhoc_macro_call', macro_xdef_dlm, False), "\n"))
mx_tag = ''.join(('# ', cls.adhoc_tag('adhoc_macro_expansion', macro_xdef_dlm, False), "\n"))
xdef = ''.join((
mc_tag,
macro_call,
mc_tag,
mx_tag,
macro_expansion,
mx_tag,
))
rx = re.compile(macro_call_rx, re.M)
source = rx.sub(xdef, source)
return source
@classmethod
[docs] def has_expanded_macros(cls, source, macro_xdef_dlm=None): # |:clm:|
# @:adhoc_run_time_section:@ off
"""
"""
# @:adhoc_run_time_section:@ on
if macro_xdef_dlm is None:
macro_xdef_dlm = cls.macro_xdef_delimiters
mx_tag = cls.adhoc_tag('adhoc_macro_expansion', macro_xdef_dlm, False)
me_count = len(cls.tag_lines(source, mx_tag))
return me_count > 0
@classmethod
[docs] def activate_macros(cls, source, macro_call_dlm=None, macro_xdef_dlm=None): # |:clm:|
# @:adhoc_run_time_section:@ off
"""
"""
# @:adhoc_run_time_section:@ on
if macro_xdef_dlm is None:
macro_xdef_dlm = cls.macro_xdef_delimiters
if not cls.has_expanded_macros(source, macro_xdef_dlm):
source = cls.expand_macros(source, macro_call_dlm, macro_xdef_dlm)
sv = cls.set_delimiters (macro_xdef_dlm)
source = cls.remove_sections(source, 'adhoc_macro_call')
source = cls.section_tag_remove(source, 'adhoc_macro_expansion')
cls.reset_delimiters(sv)
return source
@classmethod
[docs] def collapse_macros(cls, source, macro_xdef_dlm=None): # |:clm:|
# @:adhoc_run_time_section:@ off
"""
"""
# @:adhoc_run_time_section:@ on
if macro_xdef_dlm is None:
macro_xdef_dlm = cls.macro_xdef_delimiters
if cls.has_expanded_macros(source, macro_xdef_dlm):
sv = cls.set_delimiters (macro_xdef_dlm)
source = cls.section_tag_remove(source, 'adhoc_macro_call')
source = cls.remove_sections(source, 'adhoc_macro_expansion')
cls.reset_delimiters(sv)
return source
# @:adhoc_run_time_section:@ off
# --------------------------------------------------
# ||:sec:|| Template Interface
# --------------------------------------------------
# @:adhoc_run_time_section:@ on
@classmethod
[docs] def std_template_param(cls, file_=None, source=None, # |:clm:|
tag=None, is_re=False, all_=False):
# @:adhoc_run_time_section:@ off
'''Setup standard template parameters.
:param tag: If None, section tag `adhoc_template(_v)?` is
used.
See :meth:`std_source_param` for `file_` and `source`.
'''
# @:adhoc_run_time_section:@ on
file_, source = cls.std_source_param(file_, source)
if tag is None:
is_re=True
if all_:
tag = cls.section_tag('adhoc_(template(_v)?|import|unpack)', is_re=is_re)
else:
tag = cls.section_tag('adhoc_template(_v)?', is_re=is_re)
source = cls.activate_macros(source)
return (file_, source, tag, is_re)
@classmethod
[docs] def get_templates(cls, file_=None, source=None, # |:clm:|
tag=None, is_re=False,
ignore_mark=False, all_=False):
# @:adhoc_run_time_section:@ off
'''Extract templates matching section tag.
:param ignore_mark: If True, all templates are mapped to
standard output name ``-``.
:param tag: If None, `adhoc_template` is used.
'''
# @:adhoc_run_time_section:@ on
file_, source, tag, is_re = cls.std_template_param(
file_, source, tag, is_re, all_)
source = cls.enable_sections(source, 'adhoc_uncomment')
source = cls.indent_sections(source, 'adhoc_indent')
source_sections, template_sections = cls.tag_partition(
source, tag, is_re=is_re, headline=True)
templates = {}
for template_section in template_sections:
tagged_line = template_section[0]
section = template_section[1]
tag, tag_arg = cls.section_tag_parse(tagged_line)
if not tag_arg:
tag_arg = '-'
if tag_arg in cls.template_process_hooks:
section = cls.template_process_hooks[tag_arg](cls, section, tag, tag_arg)
if ignore_mark:
tag_arg = '-'
if tag_arg not in templates:
templates[tag_arg] = [[section], tag]
else:
templates[tag_arg][0].append(section)
if all_:
result = dict([(m, (''.join(t[0]), t[1])) for m, t in templates.items()])
else:
result = dict([(m, ''.join(t[0])) for m, t in templates.items()])
return result
@classmethod
[docs] def template_list(cls, file_=None, source=None, # |:clm:|
tag=None, is_re=False, all_=False):
# @:adhoc_run_time_section:@ off
"""Sorted list of templates.
See :meth:`std_template_param` for `file_`, `source`, `tag`, `is_re`.
.. @:adhoc_disable:@
>>> for tpl in AdHoc.template_list():
... printf(tpl)
-
README.txt
-col-param-closure
doc/USE_CASES.txt
doc/index.rst
-max-width-class
-rst-to-ascii
-test
>>> for tpl in AdHoc.template_list(all_=True):
... printf(strclean(tpl))
('-', 'adhoc_template')
('README.txt', 'adhoc_template')
('-col-param-closure', 'adhoc_template')
('doc/USE_CASES.txt', 'adhoc_template')
('doc/index.rst', 'adhoc_template')
('-max-width-class', 'adhoc_template')
('-rst-to-ascii', 'adhoc_template')
('-test', 'adhoc_template')
.. @:adhoc_disable:@
"""
# @:adhoc_run_time_section:@ on
file_, source, tag, is_re = cls.std_template_param(
file_, source, tag, is_re, all_)
templates = cls.get_templates(file_, source, tag, is_re, all_=all_)
if all_:
templates.update([(k, ('', v)) for k, v in cls.extra_templates])
result = list(sorted(
[(k, v[1]) for k, v in templates.items()],
key=lambda kt: '||'.join((
kt[1],
(((not (kt[0].startswith('-') or kt[0].startswith('!')))
and (kt[0]))
or (kt[0][1:]))))))
else:
templates.update(filter(
lambda tdef: (tdef[1] == 'adhoc_template'
or tdef[1] == 'adhoc_template_v'),
cls.extra_templates))
result = list(sorted(
templates.keys(),
key=lambda kt: '||'.join((
(((not (kt.startswith('-') or kt.startswith('!')))
and (kt)) or (kt[1:]))))))
return result
# @:adhoc_run_time_section:@ off
# @:adhoc_template:@ -col-param-closure
# @:adhoc_run_time_section:@ on
@classmethod
[docs] def col_param_closure(cls): # |:clm:|
# @:adhoc_run_time_section:@ off
'''Closure for setting up maximum width, padding and separator
for table columns.
:returns: a setter and a getter function for calculating the
maximum width of a list of strings (e.g. a table column).
>>> set_, get_ = AdHoc.col_param_closure()
>>> i = set_("string")
>>> get_()
[6, ' ', '======']
>>> i = set_("str")
>>> get_()
[6, ' ', '======']
>>> i = set_("longer string")
>>> get_()
[13, ' ', '=============']
>>> table_in = """\\
... Column1 Column2
... some text text
... some-more-text text text
... something text
... less"""
A splitter and column parameters depending on column count:
>>> col_count = 2
>>> splitter = lambda line: line.split(' ', col_count-1)
>>> col_params = [AdHoc.col_param_closure() for i in range(col_count)]
Generic table processor:
>>> process_cols = lambda cols: [
... col_params[indx][0](col) for indx, col in enumerate(cols)]
>>> table = [process_cols(cols) for cols in
... [splitter(line) for line in table_in.splitlines()]]
Generic table output parameters/functions:
>>> mws = [cp[1]()[0] for cp in col_params]
>>> sep = ' '.join([cp[1]()[2] for cp in col_params])
>>> paddings = [cp[1]()[1] for cp in col_params]
>>> pad_cols_c = lambda cols: [
... (((paddings[indx] is None) and (col))
... or ((paddings[indx][:int((mws[indx]-len(col))/2)]
... + col + paddings[indx])[:mws[indx]]))
... for indx, col in enumerate(cols)]
>>> pad_cols = lambda cols: [
... (((paddings[indx] is None) and (col))
... or ((col + paddings[indx])[:mws[indx]]))
... for indx, col in enumerate(cols)]
Generic table output generator:
>>> output = []
>>> if table:
... output.append(sep)
... output.append(' '.join(pad_cols_c(table.pop(0))).rstrip())
... if table: output.append(sep)
... output.extend([' '.join(pad_cols(cols)).rstrip()
... for cols in table])
... output.append(sep)
>>> i = sys.stdout.write("\\n".join(output))
============== =========
Column1 Column2
============== =========
some text text
some-more-text text text
something text
less
============== =========
'''
# @:adhoc_run_time_section:@ on
mw = [0, "", ""]
def set_(col): # |:clo:|
lc = len(col)
if mw[0] < lc:
mw[0] = lc
mw[1] = " " * lc
mw[2] = "=" * lc
return col
def get_(): # |:clo:|
return mw
return set_, get_
# @:adhoc_run_time_section:@ off
# @:adhoc_template:@ -col-param-closure
# @:adhoc_run_time_section:@ on
@classmethod
[docs] def template_table(cls, file_=None, source=None, # |:clm:|
tag=None, is_re=False):
# @:adhoc_run_time_section:@ off
'''Table of template commands.
See :meth:`std_template_param` for `file_`, `source`, `tag`, `is_re`.
'''
# @:adhoc_run_time_section:@ on
file_, source, tag, is_re = cls.std_template_param(
file_, source, tag, is_re, all_=True)
# Parse table
table = []
tpl_arg_name = (lambda t: (((not (t.startswith('-') or t.startswith('!'))) and (t)) or (t[1:])))
col_param = [cls.col_param_closure() for i in range(3)]
table.append((col_param[0][0]('Command'), col_param[1][0]('Template'), col_param[2][0]('Type')))
table.extend([(col_param[0][0](''.join((
os.path.basename(file_), ' --template ',
tpl_arg_name(t[0]))).rstrip()),
col_param[1][0](''.join(('# ', t[0])).rstrip()),
col_param[2][0](''.join((t[1])).rstrip()),
)
for t in cls.template_list(file_, source, tag, is_re, all_=True)])
# Setup table output
mw, padding = (col_param[0][1]()[0], col_param[0][1]()[1])
mw1, padding1 = (col_param[1][1]()[0], col_param[1][1]()[1])
mw2, padding2 = (col_param[2][1]()[0], col_param[2][1]()[1])
sep = ' '.join([cp[1]()[2] for cp in col_param])
make_row_c = lambda row: ''.join((
''.join((padding[:int((mw-len(row[0]))/2)], row[0], padding))[:mw],
' ', ''.join((padding1[:int((mw1-len(row[1]))/2)],
row[1], padding1))[:mw1],
' ', ''.join((padding2[:int((mw2-len(row[2]))/2)],
row[2], padding2))[:mw2].rstrip()))
make_row = lambda row: ''.join((''.join((row[0], padding))[:mw],
' ', ''.join((row[1], padding))[:mw1],
' ', row[2])).rstrip()
# Generate table
output = []
output.append(sep)
output.append(make_row_c(table.pop(0)))
if table:
output.append(sep)
output.extend([make_row(row) for row in table])
output.append(sep)
return output
@classmethod
[docs] def get_named_template(cls, name=None, file_=None, source=None, # |:clm:|
tag=None, is_re=False, ignore_mark=False):
# @:adhoc_run_time_section:@ off
'''Extract templates matching section tag and name.
:param name: Template name. If None, standard output name ``-`` is used.
:param tag: If None, `adhoc_template(_v)?` is used.
:param ignore_mark: If True, all templates are mapped to
standard output name ``-``.
If a named template cannot be found and `name` does not start
with ``-``, the template name `-name` is tried.
>>> ign = main("adhoc.py --template adhoc_test.sub".split())
# -*- coding: utf-8 -*-
<BLANKLINE>
ADHOC_TEST_SUB_IMPORTED = True
'''
# @:adhoc_run_time_section:@ on
if name is None:
name = '-'
file_, source, tag, is_re = cls.std_template_param(
file_, source, tag, is_re, all_=True)
templates = cls.get_templates(
file_, source, tag, is_re=is_re, ignore_mark=ignore_mark, all_=True)
check_name = name
if check_name not in templates and not name.startswith('-'):
check_name = ''.join(('-', name))
if check_name not in templates and not name.startswith('!'):
check_name = ''.join(('!', name))
if check_name in templates:
template_set = templates[check_name]
else:
template_set = ['', 'adhoc_template']
template = template_set[0]
template_type = template_set[1]
if check_name.startswith('!'):
template = cls.dump_(template, template_type)
return template
@classmethod
run_time_flag = None # line
import_flag = None # line
include_flag = None # line
verbatim_flag = None # line
compiled_flag = None # line
run_time_class_flag = None # line
rt_engine_section_tag = None # section
indent_section_tag = None # section
uncomment_section_tag = None # section
enable_section_tag = None # section
disable_section_tag = None # section
remove_section_tag = None # section
import_section_tag = None # section
unpack_section_tag = None # section
template_v_section_tag = None # section
template_section_tag = None # section
run_time_section_tag = None # section
run_time_section = None
run_time_flag_symbol = 'adhoc_run_time' # line
import_flag_symbol = 'adhoc' # line
include_flag_symbol = 'adhoc_include' # line
verbatim_flag_symbol = 'adhoc_verbatim' # line
compiled_flag_symbol = 'adhoc_compiled' # line
run_time_class_symbol = 'adhoc_run_time_class' # line
rt_engine_section_symbol = 'adhoc_run_time_engine' # section
indent_section_symbol = 'adhoc_indent' # section
uncomment_section_symbol = 'adhoc_uncomment' # section
enable_section_symbol = 'adhoc_enable' # section
disable_section_symbol = 'adhoc_disable' # section
remove_section_symbol = 'adhoc_remove' # section
import_section_symbol = 'adhoc_import' # section
unpack_section_symbol = 'adhoc_unpack' # section
template_v_section_symbol = 'adhoc_template_v' # section
template_section_symbol = 'adhoc_template' # section
run_time_section_symbol = 'adhoc_run_time_section' # section
run_time_class_prefix = 'Rt'
import_function = 'AdHoc.import_'
modules = {}
compiling = []
file_include_template = ( # |:api_fi:|
"{ind}"
"# {stg}\n{ind}"
"{rtp}{ahc}("
"{mod},"
" file_={fnm},\n{ina}"
" mtime={mtm},"
" mode={fmd},\n{ina}"
" zipped={zip},"
" flat={flt},"
" source64=\n"
"{src}"
")\n{ind}"
"# {etg}\n"
)
# --------------------------------------------------
# ||:sec:|| Setup
# --------------------------------------------------
def __init__(self): # |:mth:|
self.modules = {}
self.compiling = []
self.setup_tags()
self.run_time_section = self.prepare_run_time_section().rstrip() + '\n'
@classmethod
def setup_tags(cls): # |:mth:|
cls.run_time_flag = cls.line_tag(cls.run_time_flag_symbol)
cls.import_flag = cls.line_tag(cls.import_flag_symbol)
cls.verbatim_flag = cls.line_tag(cls.verbatim_flag_symbol)
cls.include_flag = cls.line_tag(cls.include_flag_symbol)
cls.compiled_flag = cls.line_tag(cls.compiled_flag_symbol)
cls.run_time_class_flag = cls.line_tag(cls.run_time_class_symbol)
cls.rt_engine_section_tag = cls.section_tag(cls.rt_engine_section_symbol)
cls.indent_section_tag = cls.section_tag(cls.indent_section_symbol)
cls.uncomment_section_tag = cls.section_tag(cls.uncomment_section_symbol)
cls.enable_section_tag = cls.section_tag(cls.enable_section_symbol)
cls.disable_section_tag = cls.section_tag(cls.disable_section_symbol)
cls.remove_section_tag = cls.section_tag(cls.remove_section_symbol)
cls.import_section_tag = cls.section_tag(cls.import_section_symbol)
cls.unpack_section_tag = cls.section_tag(cls.unpack_section_symbol)
cls.template_v_section_tag = cls.section_tag(cls.template_v_section_symbol)
cls.template_section_tag = cls.section_tag(cls.template_section_symbol)
cls.run_time_section_tag = cls.section_tag(
cls.run_time_section_symbol)
# --------------------------------------------------
# ||:sec:|| Tools
# --------------------------------------------------
@staticmethod
def strquote(source, indent=(' ' * 4)): # |:fnc:|
source = source.replace("'", "\\'")
length = 78 - 2 - 4 - len(indent)
if length < 50:
length = 50
output_parts = []
indx = 0
limit = len(source)
while indx < limit:
output_parts.extend((
indent, " '", source[indx:indx+length], "'\n"))
indx += length
return ''.join(output_parts)
# --------------------------------------------------
# ||:sec:|| Run-Time Section
# --------------------------------------------------
@classmethod
def adhoc_run_time_sections_from_string(cls, string, symbol): # |:clm:|
tag = sformat('(#[ \t\r]*)?{0}', cls.section_tag(symbol, is_re=True))
def_sections = cls.tag_sections(string, tag, is_re=True)
return def_sections
@classmethod
def adhoc_run_time_section_from_file(cls, file_, symbol): # |:clm:|
if file_.endswith('.pyc'):
file_ = file_[:-1]
string = cls.read_source(file_)
def_sections = cls.adhoc_run_time_sections_from_string(
string, symbol)
return def_sections
@classmethod
def adhoc_get_run_time_section( # |:clm:|
cls, symbol, prolog='', epilog=''):
import datetime
adhoc_module_places = []
# try __file__
adhoc_module_places.append(__file__)
def_sections = cls.adhoc_run_time_section_from_file(
__file__, symbol)
if len(def_sections) == 0:
# try adhoc.__file__
try:
import adhoc
adhoc_module_places.append(adhoc.__file__)
def_sections = cls.adhoc_run_time_section_from_file(
adhoc.__file__, symbol)
except:
pass
if len(def_sections) == 0:
# try adhoc.__adhoc__.source
try:
adhoc_module_places.append('adhoc.__adhoc__.source')
def_sections = cls.adhoc_run_time_sections_from_string(
adhoc.__adhoc__.source, symbol)
except:
pass
if len(def_sections) == 0:
adhoc_dump_list(def_sections)
raise AdHocError(sformat('{0} not found in {1}',
cls.section_tag(symbol),
', '.join(adhoc_module_places)))
def_ = ''.join((
sformat('# {0}\n', cls.remove_section_tag),
sformat('# {0}\n', cls.rt_engine_section_tag),
sformat('# -*- coding: utf-8 -*-\n'),
sformat('# {0} {1}\n', cls.compiled_flag,
datetime.datetime.now(),
# |:todo:| add input filename
),
prolog,
''.join(def_sections),
epilog,
sformat('# {0}\n', cls.rt_engine_section_tag),
sformat('# {0}\n', cls.remove_section_tag),
))
return def_
@classmethod
def prepare_run_time_section(cls): # |:mth:|
rts = cls.adhoc_get_run_time_section(
cls.run_time_section_symbol)
rtc_sections = cls.tag_split(
rts, cls.run_time_class_flag)
transform = []
done = False
use_next = False
for section in rtc_sections:
blob = section[1]
if section[0]:
use_next = blob
continue
if use_next:
if not done:
mo = re.search('class[ \t\r]+', blob)
if mo:
blob = (blob[:mo.end(0)]
+ cls.run_time_class_prefix
+ blob[mo.end(0):])
done = True
else:
#transform.append(use_next)
pass
use_next = False
transform.append(blob)
transform.append(sformat('# {0}\n', cls.remove_section_tag))
transform.append(sformat('# {0}\n', cls.rt_engine_section_tag))
transform.append(sformat('# {0}\n', cls.rt_engine_section_tag))
transform.append(sformat('# {0}\n', cls.remove_section_tag))
rts = ''.join(transform)
if not done:
raise AdHocError(
sformat('run-time class(tag) `{0}` not found in:\n{1}',
cls.run_time_class_flag, rts))
return rts
# --------------------------------------------------
# ||:sec:|| Internal Includer (verbatim)
# --------------------------------------------------
[docs] def verbatim_(self, string, name=None): # |:mth:|
'''Entry point for verbatim inclusion.
:returns: string with verbatim included files.
:param string: input string, with |adhoc_verbatim| flags.
:param name: ignored. (API compatibility with
:meth:`AdHoc.compile_`).
.. note:: double commented flags, e.g. ``##``
|adhoc_verbatim|, are ignored.
.. \\|:here:|
>>> section = """\\
... some
... @:""" """adhoc_verbatim:@ {flags} my_verbatim{from_}
... text\\
... """
>>> adhoc = AdHoc()
**Non-existent File**
>>> sv_quiet = AdHoc.quiet
>>> AdHoc.quiet = True
>>> source = adhoc.verbatim_(sformat(section, flags="-2#", from_=""))
>>> printf(source) #doctest: +ELLIPSIS
some
@:adhoc_verbatim... -2# my_verbatim
text
>>> AdHoc.quiet = sv_quiet
**Empty File**
>>> source = adhoc.verbatim_(sformat(section, flags="", from_=" from /dev/null"))
>>> printf(source) #doctest: +ELLIPSIS
some
@:adhoc_verbatim... my_verbatim from /dev/null
# @:adhoc_remove...
# @:adhoc_indent... -4
# @:adhoc_template_v... my_verbatim
# @:adhoc_template_v...
# @:adhoc_indent...
# @:adhoc_remove...
text
**Empty file, with negative indent, commented**
>>> source = adhoc.verbatim_(sformat(section, flags="-2#", from_=" from /dev/null"))
>>> printf(source) #doctest: +ELLIPSIS
some
@:adhoc_verbatim... -2# my_verbatim from /dev/null
# @:adhoc_remove...
# @:adhoc_uncomment...
# @:adhoc_indent... -2
# @:adhoc_template_v... my_verbatim
# @:adhoc_template_v...
# @:adhoc_indent...
# @:adhoc_uncomment...
# @:adhoc_remove...
text
**Empty file, with overflowing negative indent, commented**
>>> source = adhoc.verbatim_(sformat(section, flags="-8#", from_=" from /dev/null"))
>>> printf(source) #doctest: +ELLIPSIS
some
@:adhoc_verbatim... -8# my_verbatim from /dev/null
# @:adhoc_remove...
# @:adhoc_uncomment...
# @:adhoc_template_v... my_verbatim
# @:adhoc_template_v...
# @:adhoc_uncomment...
# @:adhoc_remove...
text
**Existing file, without newline at end of file, commented.**
>>> mvf = open("my_verbatim", "w")
>>> ign = mvf.write("no end of line")
>>> mvf.close()
>>> source = adhoc.verbatim_(sformat(section, flags="-4#", from_=""))
>>> printf(source) #doctest: +ELLIPSIS
some
@:adhoc_verbatim... -4# my_verbatim
# @:adhoc_remove...
# @:adhoc_uncomment...
# @:adhoc_template_v... my_verbatim
# no end of line
# @:adhoc_template_v...
# @:adhoc_uncomment...
# @:adhoc_remove...
text
**Existing file, with extra newline at end of file, commented.**
>>> mvf = open("my_verbatim", "w")
>>> ign = mvf.write("extra end of line\\n\\n")
>>> mvf.close()
>>> source = adhoc.verbatim_(sformat(section, flags="-4#", from_=""))
>>> printf(source) #doctest: +ELLIPSIS
some
@:adhoc_verbatim... -4# my_verbatim
# @:adhoc_remove...
# @:adhoc_uncomment...
# @:adhoc_template_v... my_verbatim
# extra end of line
<BLANKLINE>
# @:adhoc_template_v...
# @:adhoc_uncomment...
# @:adhoc_remove...
text
**Existing file, without newline at end of file, not commented.**
>>> mvf = open("my_verbatim", "w")
>>> ign = mvf.write("no end of line")
>>> mvf.close()
>>> source = adhoc.verbatim_(sformat(section, flags="-4", from_=""))
>>> printf(source) #doctest: +ELLIPSIS
some
@:adhoc_verbatim... -4 my_verbatim
# @:adhoc_remove...
# @:adhoc_template_v... my_verbatim
no end of line
# @:adhoc_template_v...
# @:adhoc_remove...
text
**Existing file, with extra newline at end of file, not commented.**
>>> mvf = open("my_verbatim", "w")
>>> ign = mvf.write("extra end of line\\n\\n")
>>> mvf.close()
>>> source = adhoc.verbatim_(sformat(section, flags="", from_=""))
>>> printf(source) #doctest: +ELLIPSIS
some
@:adhoc_verbatim... my_verbatim
# @:adhoc_remove...
# @:adhoc_indent:@ -4
# @:adhoc_template_v... my_verbatim
extra end of line
<BLANKLINE>
# @:adhoc_template_v...
# @:adhoc_indent:@
# @:adhoc_remove...
text
**Existing file, but override with source /dev/null.**
>>> source = adhoc.verbatim_(sformat(section, flags="/dev/null as", from_=""))
>>> printf(source) #doctest: +ELLIPSIS
some
@:adhoc_verbatim... /dev/null as my_verbatim
# @:adhoc_remove...
# @:adhoc_indent... -4
# @:adhoc_template_v... my_verbatim
# @:adhoc_template_v...
# @:adhoc_indent...
# @:adhoc_remove...
text
**Existing file, override with non-existing source /not-here/.**
>>> if os.path.exists("not-here"):
... os.unlink("not-here")
>>> source = adhoc.verbatim_(sformat(section, flags="not-here as", from_=""))
>>> printf(source) #doctest: +ELLIPSIS
some
@:adhoc_verbatim... not-here as my_verbatim
# @:adhoc_remove...
# @:adhoc_indent... -4
# @:adhoc_template_v... my_verbatim
extra end of line
<BLANKLINE>
# @:adhoc_template_v...
# @:adhoc_indent...
# @:adhoc_remove...
text
>>> os.unlink("my_verbatim")
'''
m = 'is: '
import datetime
# # check for @: adhoc_compiled :@
# adhoc_compiled_lines = self.tag_lines(
# string, self.line_tag('adhoc_compiled'))
# if len(adhoc_compiled_lines) > 0:
# sys.stderr.write(sformat(
# '{0}{1}' 'warning: {2} already AdHoc\'ed `{3}`\n',
# dbg_comm, m, name, adhoc_compiled_lines[0].rstrip()))
# return string
# handle @: adhoc_verbatim :@
result = []
verbatim_cmd_parts = self.tag_split(string, self.verbatim_flag)
for part in verbatim_cmd_parts:
verbatim_def = part[1]
result.append(verbatim_def)
if part[0]:
# skip commented verbatim includes
if re.match('\\s*#\\s*#', verbatim_def):
if self.verbose:
printe(sformat(
'{0}{1}Skipping disabled verbatim `{2}`',
dbg_comm, m, verbatim_def.rstrip()))
continue
indent = ''
mo = re.match('\\s*', verbatim_def)
if mo:
indent = mo.group(0)
verbatim_def = self.line_tag_strip(
verbatim_def, self.verbatim_flag_symbol)
verbatim_specs = []
for verbatim_spec in re.split('\\s*,\\s*', verbatim_def):
verbatim_spec1 = re.split('\\s+from\\s+', verbatim_spec)
verbatim_spec2 = re.split('\\s+as\\s+', verbatim_spec)
default = None
source = None
output = None
flags = None
if len(verbatim_spec1) > 1:
output = verbatim_spec1[0]
default = verbatim_spec1[1]
fields = re.split('\\s+', output, 1)
if len(fields) > 1:
flags = fields[0]
output = fields[1]
else:
flags = ''
source = output
if len(verbatim_spec2) > 1:
source = verbatim_spec2[0]
output = verbatim_spec2[1]
fields = re.split('\\s+', source, 1)
if len(fields) > 1:
flags = fields[0]
source = fields[1]
else:
flags = ''
default = output
if flags is None:
source = verbatim_spec
fields = re.split('\\s+', source, 1)
if len(fields) > 1:
flags = fields[0]
source = fields[1]
else:
flags = ''
source = fields[0]
default = source
output = source
verbatim_specs.append([flags, source, default, output])
for verbatim_spec in verbatim_specs:
vflags = verbatim_spec.pop(0)
ifile = verbatim_spec.pop()
found = False
for lfile in verbatim_spec:
lfile = os.path.expanduser(lfile)
blfile = lfile
for include_dir in self.include_path:
if not os.path.exists(lfile):
if not (os.path.isabs(blfile)):
lfile = os.path.join(include_dir, blfile)
continue
break
if os.path.exists(lfile):
stat = os.stat(lfile)
mtime = datetime.datetime.fromtimestamp(
stat.st_mtime)
mode = stat.st_mode
exp_source = self.read_source(lfile)
source_len = len(exp_source)
start_tags = []
end_tags = []
prefix = []
tag_prefix = ['# ']
mo = re.search('[-+]?[0-9]+', vflags)
if mo:
uindent = int(mo.group(0))
else:
uindent = 0
tindent = (len(indent) + uindent)
if tindent < 0:
tindent = 0
if tindent:
tag = self.indent_section_tag
start_tags.insert(
0, ''.join((tag, ' ', str(-tindent))))
end_tags.append(tag)
prefix.insert(0, ' ' * tindent)
tag_prefix.insert(0, ' ' * tindent)
if '#' in vflags:
tag = self.uncomment_section_tag
start_tags.insert(0, tag)
end_tags.append(tag)
exp_source, hl = self.disable_transform(exp_source)
tag = self.remove_section_tag
start_tags.insert(0, tag)
end_tags.append(tag)
tag = self.section_tag('adhoc_template_v')
start_tags.append(''.join((tag, ' ', ifile)))
end_tags.insert(0,tag)
prefix = ''.join(prefix)
tag_prefix = ''.join(tag_prefix)
if prefix and exp_source:
if exp_source.endswith('\n'):
exp_source = exp_source[:-1]
exp_source = re.sub('^(?m)', prefix, exp_source)
if exp_source and not exp_source.endswith('\n'):
exp_source = ''.join((exp_source, '\n'))
output = []
output.extend([''.join((
tag_prefix, tag, '\n')) for tag in start_tags])
output.append(exp_source)
output.extend([''.join((
tag_prefix, tag, '\n')) for tag in end_tags])
result.append(''.join(output))
found = True
# |:debug:|
if self.verbose:
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]len: {5:>6d}"
" exp: {6:>6d} ]{9}[",
dbg_comm, dbg_twid, dbg_fwid, ':INF:',
'source stats', source_len, len(exp_source),
0, 0, ifile))
# |:debug:|
break
if not found and not self.quiet:
list(map(sys.stderr.write,
("# if: ", self.__class__.__name__,
": warning verbatim file `", ifile,
"` not found from `",
', '.join(verbatim_spec), "`\n")))
#adhoc_dump_list(result)
return ''.join(result)
# --------------------------------------------------
# ||:sec:|| Internal Includer (packed)
# --------------------------------------------------
[docs] def include_(self, string, name=None, zipped=True, flat=None): # |:mth:|
'''Entry point for inclusion.
:returns: string with packed included files.
:param string: input string, with |adhoc_include| flags.
:param name: ignored. (API compatibility with
:meth:`AdHoc.compile_`).
:param zipped: if True, :mod:`gzip` included files.
.. note:: double commented flags, e.g. ``##``
|adhoc_include|, are ignored.
.. \\|:here:|
>>> section = """\\
... some
... @:""" """adhoc_include:@ Makefile
... text\\
... """
.. @:adhoc_disable:@
>>> adhoc = AdHoc()
>>> source = adhoc.include_(section)
>>> printf(source) #doctest: +ELLIPSIS
some
@:adhoc_include... Makefile
# @:adhoc_unpack...
RtAdHoc.unpack_(None, file_='Makefile',
mtime='...', mode=...,
zipped=True, flat=None, source64=
...
# @:adhoc_unpack...
text
.. @:adhoc_disable:@
'''
m = 'is: '
import datetime
# # check for @: adhoc_compiled :@
# adhoc_compiled_lines = self.tag_lines(
# string, self.line_tag('adhoc_compiled'))
# if len(adhoc_compiled_lines) > 0:
# sys.stderr.write(sformat(
# '{0}{1}' 'warning: {2} already AdHoc\'ed `{3}`\n',
# dbg_comm, m, name, adhoc_compiled_lines[0].rstrip()))
# return string
# handle @: adhoc_include :@
result = []
include_cmd_sections = self.tag_split(string, self.include_flag)
for section in include_cmd_sections:
include_def = section[1]
result.append(include_def)
if section[0]:
# skip commented includes
if re.match('\\s*#\\s*#', include_def):
if self.verbose:
printe(sformat(
'{0}{1}Skipping disabled include `{2}`',
dbg_comm, m, include_def.rstrip()))
continue
indent = ''
mo = re.match('\\s*', include_def)
if mo:
indent = mo.group(0)
include_def = self.line_tag_strip(
include_def, self.include_flag_symbol)
include_specs = []
for include_spec in re.split('\\s*,\\s*', include_def):
include_spec1 = re.split('\\s+from\\s+', include_spec)
include_spec2 = re.split('\\s+as\\s+', include_spec)
default = None
source = None
output = None
if len(include_spec1) > 1:
output = include_spec1[0]
default = include_spec1[1]
source = output
if len(include_spec2) > 1:
source = include_spec2[0]
output = include_spec2[1]
default = output
if source is None:
source = include_spec
output = source
default = source
include_specs.append([source, default, output])
for include_spec in include_specs:
ifile = include_spec.pop()
found = False
for lfile in include_spec:
lfile = os.path.expanduser(lfile)
blfile = lfile
for include_dir in self.include_path:
if not os.path.exists(lfile):
if not (os.path.isabs(blfile)):
lfile = os.path.join(include_dir, blfile)
continue
break
if os.path.exists(lfile):
stat = os.stat(lfile)
mtime = datetime.datetime.fromtimestamp(
stat.st_mtime)
mode = stat.st_mode
exp_source = self.read_source(lfile, decode=False)
source64 = self.pack_file(exp_source, zipped)
output = self.strquote(source64, indent)
file_include_args = dict([ # |:api_fi:|
('ind', indent),
('ina', ''.join((indent, " "))),
('stg', ''.join((self.unpack_section_tag, ' !', ifile))),
('etg', self.unpack_section_tag),
('rtp', self.run_time_class_prefix),
('ahc', 'AdHoc.unpack_'),
('mod', 'None'),
('fnm', repr(str(ifile))),
('mtm', (((mtime is not None)
and repr(mtime.isoformat()))
or repr(mtime))),
('fmd', (mode is not None and sformat('int("{0:o}", 8)', mode)) or mode),
('zip', zipped),
('flt', flat),
('src', output.rstrip()),
])
output = sformat(
self.file_include_template,
**file_include_args
)
result.append(output)
found = True
# |:debug:|
if self.verbose:
source_len = len(exp_source)
exp_source_len = len(exp_source)
source64_len = len(source64)
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]len: {5:>6d}"
" exp: {6:>6d} b64: {8:>6d}[ ]{9}[",
dbg_comm, dbg_twid, dbg_fwid, ':INF:',
'source stats', source_len, exp_source_len,
0, source64_len, ifile))
# |:debug:|
break
if not found and not self.quiet:
list(map(sys.stderr.write,
("# if: ", self.__class__.__name__,
": warning include file `",
ifile, "` not found from `",
', '.join(include_spec), "`\n")))
#adhoc_dump_list(result)
return ''.join(result)
# --------------------------------------------------
# ||:sec:|| Internal Compiler
# --------------------------------------------------
def encode_module_( # |:mth:|
self, module, for_=None, indent='', zipped=True, flat=None, forced=None):
m = 'gm: '
if for_ is None:
for_ = self.import_function
if forced is None:
forced = self.forced
module = self.module_setup(module)
module_name = module.__name__
# no multiple occurences
if (not forced
and (module_name in self.modules
or module_name in self.compiling)):
if self.verbose:
# |:check:| what, if the previous import was never
# executed?
sys.stderr.write(sformat(
'{0}{1}`{2}` already seen. skipping ...\n',
dbg_comm, m, module_name))
return ''
self.compiling.append(module_name)
result = []
# |:todo:| parent modules
parts = module_name.split('.')
parent_modules = parts[:-1]
if self.verbose and len(parent_modules) > 0:
sys.stderr.write(sformat(
'{0}{1}Handle parent module(s) `{2}`\n',
dbg_comm, m, parent_modules))
for parent_module in parent_modules:
result.append(self.encode_module_(
parent_module, for_, indent, zipped, flat, forced))
if (module_name in self.modules):
if self.verbose:
sys.stderr.write(sformat(
'{0}{1}{1} already seen after parent import\n',
dbg_comm, m, module_name))
return ''.join(result)
if hasattr(module, '__file__'):
module_file = module.__file__
if module_file.endswith('.pyc'):
module_file = module_file[:-1]
else:
module_file = None
if hasattr(module.__adhoc__, 'source'):
source = module.__adhoc__.source
else:
if not self.quiet:
printf(sformat(
'{0}{1}|' 'warning: `{2}` does not have any source code.',
dbg_comm, m, module_name), file=sys.stderr)
source = ''
return ''.join(result)
# recursive!
exp_source = self.compile_(source, module_file, for_, zipped, forced)
source64 = self.pack_file(exp_source, zipped)
output = self.strquote(source64, indent)
mtime = module.__adhoc__.mtime
mode = module.__adhoc__.mode
# |:todo:| make Rt prefix configurable
file_include_args = dict([ # |:api_fi:|
('ind', indent),
('ina', ''.join((indent, " "))),
('stg', ''.join((self.import_section_tag, ' !', module_name))),
('etg', self.import_section_tag),
('rtp', self.run_time_class_prefix),
('ahc', for_),
('mod', repr(module.__name__)),
('fnm', (((module_file is not None)
and repr(str(os.path.relpath(module_file))))
or module_file)),
('mtm', (((mtime is not None)
and repr(mtime.isoformat()))
or repr(mtime))),
('fmd', (mode is not None and sformat('int("{0:o}", 8)', mode)) or mode),
('zip', zipped),
('src', output.rstrip()),
('flt', flat),
])
output = sformat(
self.file_include_template,
**file_include_args
)
result.append(output)
# |:debug:|
if self.verbose:
source_len = len(source)
exp_source_len = len(exp_source)
source64_len = len(source64)
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]len: {5:>6d} exp: {6:>6d}"
" b64: {8:>6d}[ ]{9}[",
dbg_comm, dbg_twid, dbg_fwid, ':INF:',
'source stats', source_len, exp_source_len, 0,
source64_len, module_file))
# |:debug:|
return ''.join(result)
[docs] def compile_(self, string, name=None, for_=None, # |:mth:|
zipped=True, forced=None):
'''Entry point for compilation.
:returns: string with fully compiled adhoc source. Includes
run-time class, imports, packed includes, verbatim includes,
enabled/disabled sections.
:param string: input string, with |adhoc| flags.
:param name: for messages.
:param for_: :class:`RtAdHoc` method call.
:param zipped: if True, :mod:`gzip` included files.
.. note:: for |adhoc|, commented lines, e.g.
``# import module # @:``\\ ``adhoc:@``, are ignored.
.. \\|:here:|
'''
m = 'cs: '
if name is None:
name = repr(string[:50])
# check for @: adhoc_compiled :@
string = self.expand_macros(string)
adhoc_compiled_lines = self.tag_lines(
string, self.line_tag('adhoc_compiled'))
if len(adhoc_compiled_lines) > 0:
if not self.quiet:
list(map(sys.stderr.write,
('# ', m, 'warning: ', name, ' already AdHoc\'ed `',
adhoc_compiled_lines[0].rstrip(), '`\n',)))
return string
# check for @: adhoc_self :@ (should not be taken from any templates)
adhoc_self_tag = self.line_tag('adhoc_self')
adhoc_self_lines = self.tag_lines(
string, adhoc_self_tag)
if len(adhoc_self_lines) > 0:
for line in adhoc_self_lines:
line = re.sub(''.join(('^.*', adhoc_self_tag)), '', line)
line = line.strip()
selfs = line.split()
if self.verbose:
printe(sformat(
'{0}{1}|' ':INF:| {2} found self: `{3}`',
dbg_comm, m, name, ', '.join(selfs)))
self.compiling.extend(selfs)
# check for @: adhoc_remove :@
string = self.section_tag_rename(string, 'adhoc_remove', 'adhoc_remove_')
# check for @: adhoc_verbatim :@ (templates can define the run-time flag, includes, imports)
string = self.verbatim_(string, name)
# search for @: adhoc_run_time :@ and put run-time section there!
result = []
ah_run_time_sections = self.tag_split(
string, self.line_tag(self.run_time_flag_symbol))
good = False
for section in ah_run_time_sections:
config_def = section[1]
if not good and section[0]:
# ignore double commented tagged lines
if not re.match('\\s*#\\s*#', config_def):
config_def = sformat('{0}{1}',
config_def, self.run_time_section)
good = True
result.append(config_def)
string = ''.join(result)
# check for @: adhoc_include :@
string = self.include_(string, name, zipped)
# handle @: adhoc :@ imports
result = []
import_cmd_sections = self.tag_split(string, self.import_flag)
if not good and len(import_cmd_sections) > 1:
adhoc_dump_sections(import_cmd_sections)
raise AdHocError(sformat('{0} not found',
self.line_tag(self.run_time_flag_symbol)))
for section in import_cmd_sections:
import_def = section[1]
if section[0]:
# skip commented imports
if re.match('\\s*#', import_def):
if self.verbose:
printe(sformat(
'{0}{1}Skipping disabled `{2}`',
dbg_comm, m, import_def.rstrip()))
result.append(import_def)
continue
import_args = self.line_tag_strip(import_def, self.import_flag_symbol)
module = ''
mo = re.match(
'(\\s*)from\\s+([a-zA-Z_][.0-9a-zA-Z_]*)\\s+'
'import', import_def)
if mo:
indent = mo.group(1)
module = mo.group(2)
else:
mo = re.match(
'([ \t\r]*)import[ \t\r]+([a-zA-Z_][.0-9a-zA-Z_]*)',
import_def)
if mo:
indent = mo.group(1)
module = mo.group(2)
if len(module) > 0:
module_flat = ((('flat' in import_args.lower().split()) and (True)) or (None))
module_flat = ((('full' in import_args.lower().split()) and (False)) or (module_flat))
module_forced = ((('force' in import_args.lower().split()) and (True)) or (forced))
source = self.encode_module_(module, for_, indent, zipped, module_flat, module_forced)
import_def = sformat('{0}{1}',source, import_def)
else:
if self.verbose:
list(map(sys.stderr.write,
('# ', m, 'warning: no import found! `',
import_def.rstrip(), '`\n')))
result.append(import_def)
string = ''.join(result)
# These are last, to avoid enabling/disabling the wrong imports etc.
# check for @: adhoc_enable :@
string = self.enable_sections(string, 'adhoc_enable')
# check for @: adhoc_disable :@
string = self.disable_sections(string, 'adhoc_disable')
#adhoc_dump_list(result)
return string
# --------------------------------------------------
# ||:sec:|| User API
# --------------------------------------------------
def encode_include( # |:mth:|
self, file_, as_=None, indent='', zipped=True):
m = 'if: '
def encode_module( # |:mth:|
self, module, for_=None, indent='', zipped=True, flat=None, forced=None):
if hasattr(module, __name__):
name = module.__name__
else:
name = module
if self.verbose:
sys.stderr.write(sformat(
'{0}--------------------------------------------------\n',
dbg_comm))
sys.stderr.write(sformat(
'{0}Get module `{1}`\n',
dbg_comm, name))
sys.stderr.write(sformat(
'{0}--------------------------------------------------\n',
dbg_comm))
return self.encode_module_(module, for_, indent, zipped, flat, forced)
[docs] def compile(self, string, name=None, for_=None, # |:mth:|
zipped=True, forced=None):
'''Compile a string into adhoc output.'''
if self.verbose:
if name is None:
name = repr(string[:50])
sys.stderr.write(sformat(
'{0}--------------------------------------------------\n',
dbg_comm))
sys.stderr.write(sformat(
'{0}Compiling string `{1}`\n',
dbg_comm, name))
sys.stderr.write(sformat(
'{0}--------------------------------------------------\n',
dbg_comm))
return self.compile_(string, name, for_, zipped, forced)
# @:adhoc_run_time_section:@ on
[docs] def compileFile(self, file_name, for_=None, zipped=True, forced=None): # |:mth:|
# @:adhoc_run_time_section:@ off
"""Compile a file into adhoc output.
Since a module that has RtAdHoc defined is already adhoc'ed,
the run-time RtAdHoc method returns the file source as is.
"""
# @:adhoc_run_time_section:@ on
# @:adhoc_run_time_section:@ off
if self.verbose:
sys.stderr.write(sformat(
'{0}--------------------------------------------------\n',
dbg_comm))
sys.stderr.write(
sformat('{0}Compiling {1}\n',dbg_comm, file_name))
sys.stderr.write(sformat(
'{0}--------------------------------------------------\n',
dbg_comm))
# @:adhoc_run_time_section:@ on
file_name, source = self.std_source_param(file_name, None)
# @:adhoc_run_time_section:@ off
source = self.compile_(source, file_name, for_, zipped, forced)
# @:adhoc_run_time_section:@ on
return source
# @:adhoc_run_time_section:@ END
# (progn (forward-line -1) (insert "\n") (snip-insert-mode "py.s.class" t) (backward-symbol-tag 2 "fillme" "::"))
# --------------------------------------------------
# |||:sec:||| FUNCTIONS
# --------------------------------------------------
# (progn (forward-line 1) (snip-insert-mode "py.f.hl" t) (insert "\n"))
hlr = None
def hlcr(title=None, tag='|||' ':CHP:|||', rule_width=50, **kwargs): # ||:fnc:||
comm = ((('dbg_comm' in globals()) and (globals()['dbg_comm'])) or ('# '))
dstr = []
dstr.append(''.join((comm, '-' * rule_width)))
if title:
dstr.append(sformat('{0}{2:^{1}} {3!s}',
comm, ((('dbg_twid' in globals()) and (globals()['dbg_twid'])) or (9)),
tag, title))
dstr.append(''.join((comm, '-' * rule_width)))
return '\n'.join(dstr)
def hlsr(title=None, tag='||' ':SEC:||', rule_width=35, **kwargs): # |:fnc:|
return hlcr(title, tag, rule_width)
def hlssr(title=None, tag='|' ':INF:|', rule_width=20, **kwargs): # |:fnc:|
return hlcr(title, tag, rule_width)
def hlc(*args, **kwargs): # |:fnc:|
for line in hlcr(*args, **kwargs).splitlines():
printf(line, **kwargs)
def hls(*args, **kwargs): # |:fnc:|
for line in hlsr(*args, **kwargs).splitlines():
printf(line, **kwargs)
def hlss(*args, **kwargs): # |:fnc:|
for line in hlssr(*args, **kwargs).splitlines():
printf(line, **kwargs)
def hl(*args, **kwargs): # |:fnc:|
for line in hlr(*args, **kwargs).splitlines():
printf(line, **kwargs)
def hl_lvl(level=0): # |:fnc:|
global hlr
if level == 0:
hlr = hlssr
elif level == 1:
hlr = hlsr
else:
hlr = hlcr
hl_lvl(0)
# (progn (forward-line 1) (snip-insert-mode "py.f.single.quote" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.f.remove.match" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.f.printenv" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.f.uname-s" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.f.printe" t) (insert "\n"))
def printe(*args, **kwargs): # ||:fnc:||
kwargs['file'] = kwargs.get('file', sys.stderr)
printf(*args, **kwargs)
# (progn (forward-line 1) (snip-insert-mode "py.f.dbg.squeeze" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.f.dbg.indent" t) (insert "\n"))
# (progn (forward-line -1) (insert "\n") (snip-insert-mode "py.s.func" t) (backward-symbol-tag 2 "fillme" "::"))
# --------------------------------------------------
# |||:sec:||| UTILTIES
# --------------------------------------------------
def adhoc_dump_list(list_, max_wid=None): # ||:fnc:||
if max_wid is None:
max_wid = 78
for indx, elt in enumerate(list_):
elt = str(elt)
if len(elt) > max_wid:
elt = elt[:max_wid-3] + ' ...'
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', sformat('elt[{0}]', indx), repr(elt)))
def adhoc_dump_sections(sections, max_wid=None): # ||:fnc:||
if max_wid is None:
max_wid = 78
for indx, section in enumerate(sections):
cut_section = list(section)
if len(cut_section[1]) > max_wid:
cut_section[1] = cut_section[1][:max_wid-3] + ' ...'
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', sformat('section[{0}]', indx), strclean(cut_section)))
[docs]def catch_stdout(): # ||:fnc:||
"""Install a string IO as `sys.stdout`.
:returns: a state variable that is needed by
:func:`restore_stdout` to retrieve the output as string.
"""
output_sio = _AdHocStringIO()
sv_stdout = sys.stdout
sys.stdout = output_sio
return (sv_stdout, output_sio)
[docs]def restore_stdout(state): # ||:fnc:||
"""Restore capturing `sys.stdout` and get captured output.
:returns: captured output as string.
:param state: state variable obtained from :func:`catch_stdout`.
"""
sys.stdout, output_sio = state
output = output_sio.getvalue()
output_sio.close()
return output
# @:adhoc_uncomment:@
# @:adhoc_template:@ -max-width-class
class mw_(object):
mw = 0
def __call__(self, col):
if self.mw < len(col):
self.mw = len(col)
return col
class mwg_(object):
def __init__(self, mwo):
self.mwo = mwo
def __call__(self):
return self.mwo.mw
# mws = [mw_(), mw_()]
# mwg = [mwg_(mwo) for mwo in mws]
# @:adhoc_template:@
# @:adhoc_uncomment:@
# @:adhoc_template:@ -rst-to-ascii
RST_HEADER = '''\
.. -*- mode: rst; coding: utf-8 -*-
.. role:: mod(strong)
.. role:: func(strong)
.. role:: class(strong)
.. role:: attr(strong)
.. role:: meth(strong)
'''
RST_FOOTER = '''
.. :ide: COMPILE: render reST as HTML
.. . (let* ((fp (buffer-file-name)) (fn (file-name-nondirectory fp))) (save-match-data (if (string-match-t "[.][^.]*$" fn) (setq fn (replace-match "" nil t fn)))) (let ((args (concat " " fp " | ws_rst2html.py --traceback --cloak-email-addresses | tee " fn ".html "))) (save-buffer) (compile (concat "PATH=\\".:$PATH\\"; cat " args))))
..
.. Local Variables:
.. mode: rst
.. snip-mode: rst
.. truncate-lines: t
.. symbol-tag-symbol-regexp: "[-0-9A-Za-z_#]\\\\([-0-9A-Za-z_. ]*[-0-9A-Za-z_]\\\\|\\\\)"
.. symbol-tag-auto-comment-mode: nil
.. symbol-tag-srx-is-safe-with-nil-delimiters: nil
.. End:
'''
[docs]def rst_to_ascii(string, header_footer=False): # ||:fnc:||
'''Convert ReST documentation to ASCII.'''
string = re.sub(
'^\\s*[.][.]\\s*(note|warning|attention)::(?im)', '\\1:', string)
string = re.sub(
'^\\s*[.][.]\\s*automodule::[^\\n]*\\n(\\s[^\\n]+\\n)*\\n(?m)',
'', string + '\n\n')
string = re.sub('^\\s*[.][.]([^.][^\\n]*|)\\n(?m)', '', string)
string = re.sub('\\\\\\*', '*', string)
string = re.sub('^(\\s*)\\|(\\s|$)(?m)', '\\1', string)
if header_footer:
string = ''.join((RST_HEADER, string, RST_FOOTER))
string = re.sub('\\n\\n\\n+', '\\n\\n', string)
return string
# @:adhoc_template:@
# --------------------------------------------------
# |||:sec:||| SYMBOL-TAG TOOLS
# --------------------------------------------------
[docs]def compile_(files=None): # ||:fnc:||
'''Compile files or standard input.'''
if files is None:
files = []
if len(files) == 0:
files.append('-')
compiled_files = []
for file_ in files:
sys_path = sys.path
file_dir = os.path.abspath(os.path.dirname(file_))
sys.path.insert(0, file_dir)
ah = AdHoc()
compiled = ah.compileFile(file_)
compiled_files.append(compiled)
sys.path = sys_path
return ''.join(map(lambda c:
(((c.endswith('\n')) and (c)) or (''.join((c, '\n')))),
compiled_files))
# --------------------------------------------------
# |||:sec:||| TEST
# --------------------------------------------------
doc_index_rst_tag_symbols = ('adhoc_index_only',)
def tpl_hook_doc_index_rst(cls, section, tag, tag_arg): # ||:fnc:||
tag_sym_rx = '|'.join([re.escape(tag_sym) for tag_sym in doc_index_rst_tag_symbols])
return cls.section_tag_remove(section, tag_sym_rx, is_re=True)
def tpl_hook_readme(cls, section, tag, tag_arg): # ||:fnc:||
section = section.replace('@@contents@@', 'contents::')
tag_sym_rx = '|'.join([re.escape(tag_sym) for tag_sym in doc_index_rst_tag_symbols])
return cls.remove_sections(section, tag_sym_rx, is_re=True)
[docs]def adhoc_rst_to_ascii(string): # ||:fnc:||
'''Transform ReST documentation to ASCII.'''
string = rst_to_ascii(string)
string = string.replace('|@:|\\\\? ', '@:')
string = string.replace('\\\\? |:@|', ':@')
string = string.replace('|@:|', '`@:`')
string = string.replace('|:@|', '`:@`')
string = re.sub('^:[|]_?(adhoc[^|]*)_?[|]([^:]*):(?m)', '@:\\1:@\\2', string)
string = re.sub('[|]_?(adhoc[^|]*)_?[|]', '@:\\1:@', string)
return string
def inc_template_marker(cls, as_template=False): # ||:fnc:||
sv = AdHoc.inc_delimiters()
template_tag = ''.join((
'# ', AdHoc.section_tag('adhoc_template_v'),
' ', as_template, '\n'))
AdHoc.reset_delimiters(sv)
return template_tag
def get_readme(file_=None, source=None, as_template=False, transform=True): # ||:fnc:||
file_, source = AdHoc.std_source_param(file_, source)
template_name = 'doc/index.rst'
tpl_hooks = AdHoc.template_process_hooks
AdHoc.template_process_hooks = {template_name: tpl_hook_readme}
template = AdHoc.get_named_template(template_name, file_, source)
AdHoc.template_process_hooks = tpl_hooks
template = template + '\n\n' + __doc__ + '\n'
template = AdHoc.remove_sections(template, 'adhoc_index_only')
if transform:
template = adhoc_rst_to_ascii(template).strip() + '\n'
if as_template:
template_tag = inc_template_marker(AdHoc, as_template)
output = []
output.append(template_tag)
output.append(RST_HEADER)
output.append(template)
output.append(RST_FOOTER)
output.append(template_tag)
template = ''.join(output)
return template
def get_use_cases(as_template=None): # ||:fnc:||
output = []
if as_template is not None:
template_tag = inc_template_marker(AdHoc, as_template)
else:
template_tag = ''
output.append(template_tag)
import use_case_000_ as use_case # @:adhoc:@
state = catch_stdout()
use_case.main('script --docu'.split())
output.append(restore_stdout(state))
import use_case_001_templates_ as use_case # @:adhoc:@
state = catch_stdout()
use_case.main('script --docu'.split())
output.append(restore_stdout(state))
import use_case_002_include_ as use_case # @:adhoc:@
state = catch_stdout()
use_case.main('script --docu'.split())
output.append(restore_stdout(state))
import use_case_003_import_ as use_case # @:adhoc:@
state = catch_stdout()
use_case.main('script --docu'.split())
output.append(restore_stdout(state))
import use_case_005_nested_ as use_case # @:adhoc:@
state = catch_stdout()
use_case.main('script --docu'.split())
output.append(restore_stdout(state))
output.append(template_tag)
output = ''.join(output)
return output
# --------------------------------------------------
# |||:sec:||| TEST
# --------------------------------------------------
def adhoc_run_time_module(): # ||:fnc:|| |:todo:| experimental
import imp
if 'adhoc.rt' in sys.modules:
return
file_ = __file__
source = None
exec_ = False
if file_.endswith('.pyc'):
file_ = file_[:-1]
if 'adhoc' in sys.modules:
adhoc = sys.modules['adhoc']
else:
adhoc = imp.new_module('adhoc')
setattr(adhoc, '__file__', file_)
sys.modules['adhoc'] = adhoc
exec_ = True
if not hasattr(adhoc, '__adhoc__'):
__adhoc__ = {}
adhoc.__adhoc__ = __adhoc__
if 'source' not in adhoc.__adhoc__:
adhoc.__adhoc__['source'] = AdHoc.read_source(file_)
if exec_:
source = AdHoc.encode_source(adhoc.__adhoc__['source'])
exec(source, adhoc)
RT = imp.new_module('adhoc.rt')
setattr(adhoc, 'rt', RT)
import adhoc_test.sub # @:adhoc:@ force
def adhoc_check_modules(): # ||:fnc:||
hl_lvl(0)
hlc('adhoc_check_modules')
printf(sformat('{0}--------------------------------------------------',
dbg_comm))
msg = ((('adhoc_test' in sys.modules) and ('SEEN')) or ('NOT SEEN'))
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'PRE sub import', 'adhoc_test ' + msg))
msg = ((('adhoc_test' in sys.modules) and ('SEEN')) or ('NOT SEEN'))
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'POST sub import', 'adhoc_test ' + msg))
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'dir(adhoc_test.sub)', dir(adhoc_test.sub)))
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'adhoc_test.sub.__file__', adhoc_test.sub.__file__))
if 'adhoc_test' in sys.modules:
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'dir(adhoc_test)[auto]', dir(adhoc_test)))
printf(sformat('{0}--------------------------------------------------',
dbg_comm))
import adhoc_test # @:adhoc:@
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'dir(adhoc_test)', dir(adhoc_test)))
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'adhoc_test.__file__', adhoc_test.__file__))
if hasattr(adhoc_test, '__path__'):
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'adhoc_test.__path__', adhoc_test.__path__))
[docs]def adhoc_check_module_setup(): # ||:fnc:||
'''
>>> state = catch_stdout()
>>> adhoc_check_module_setup()
>>> contents = restore_stdout(state)
>>> contents = re.sub('(mtime.*\\])[^[]*(\\[)', r'\\1\\2', contents)
>>> contents = re.sub(' at 0x([0-9a-f]+)', '', contents)
>>> contents = re.sub(r'adhoc\\.pyc', 'adhoc.py', contents)
>>> contents = '\\n'.join([l.strip() for l in contents.splitlines()])
.. >>> ign = open('adhoc_check_module_setup.t', 'w').write(
.. ... re.sub('^(?m)', ' ', contents)
.. ... .replace('\\\\', '\\\\\\\\') + '\\n')
.. @:adhoc_expected:@ adhoc_check_module_setup.e
>>> printf(contents, end='') #doctest: +ELLIPSIS
# --------------------------------------------------
# |||:CHP:||| adhoc_check_module_setup
# --------------------------------------------------
# -----------------------------------
# ||:SEC:|| no:module:found
# -----------------------------------
# :DBG: module : ]['__adhoc__', '__doc__', '__name__'...][
# ------------------------------
# :DBG: __adhoc__ : ]...
# :DBG: __doc__ : ]None[
...
# --------------------
# |:INF:| no:module:found.__adhoc__
# --------------------
# :DBG: __adhoc__ : ]...
# ------------------------------
# :DBG: __module__ : ]<module 'no:module:found' (built-in)>[
# :DBG: mode : ]...[
# :DBG: mtime : ][
# -----------------------------------
# ||:SEC:|| adhoc_test.sub
# -----------------------------------
# :DBG: module : ]['ADHOC_TEST_SUB_IMPORTED',...
# ------------------------------
# :DBG: ADHOC_TEST_SUB_IMPORTED: ]True[
# :DBG: __adhoc__ : ]...
...
# :DBG: __doc__ : ]None[
# :DBG: __file__ : ]...adhoc_test/sub/__init__.py...[
...
# --------------------
# |:INF:| adhoc_test.sub.__adhoc__
# --------------------
# :DBG: __adhoc__ : ]...
# ------------------------------
# :DBG: __module__ : ]<module 'adhoc_test.sub' from...
...
# :DBG: source : ]...# -*- coding: utf-8 -*-\\n\\nADHOC_TEST_SUB_IMPORTED = True\\n...[
# -----------------------------------
# ||:SEC:|| adhoc
# -----------------------------------
# :DBG: adhoc : ]...
# ------------------------------
# :DBG: AH_CHECK_SOURCE : ]...
...
# :DBG: AdHoc : ]<class 'adhoc.AdHoc'>[
# :DBG: AdHocError : ]...adhoc.AdHocError...[
...
# :DBG: RST_HEADER : ]...
...
# :DBG: __adhoc__ : ]...
...
# :DBG: __file__ : ].../adhoc.py...[
# :DBG: __name__ : ]adhoc[
...
# :DBG: _nativestr : ]<function _nativestr>[
# :DBG: _quiet : ]False[
# :DBG: _uc : ]<function ...>[
# :DBG: _utf8str : ]<function _utf8str>[
# :DBG: _verbose : ]False[
# :DBG: adhoc_check_encode_module: ]<function adhoc_check_encode_module>[
# :DBG: adhoc_check_module_setup : ]<function adhoc_check_module_setup>[
# :DBG: adhoc_check_modules : ]<function adhoc_check_modules>[
# :DBG: adhoc_check_packing : ]<function adhoc_check_packing>[
# :DBG: adhoc_dump_list : ]<function adhoc_dump_list>[
# :DBG: adhoc_dump_sections : ]<function adhoc_dump_sections>[
# :DBG: adhoc_rst_to_ascii : ]<function adhoc_rst_to_ascii>[
# :DBG: adhoc_run_time_module : ]<function adhoc_run_time_module>[
# :DBG: adhoc_test : ]<module 'adhoc_test' from '...adhoc_test/__init__.py...'>[
# :DBG: base64 : ]<module 'base64' from '.../base64.py...'>[
# :DBG: catch_stdout : ]<function catch_stdout>[
# :DBG: compile_ : ]<function compile_>[
# :DBG: dbg_comm : ]# [
# :DBG: dbg_fwid : ]23[
# :DBG: dbg_twid : ]9[
# :DBG: dict_dump : ]<function dict_dump>[
# :DBG: ditems : ]<function <lambda>>[
# :DBG: dkeys : ]<function <lambda>>[
# :DBG: doc_index_rst_tag_symbols: ]('adhoc_index_only',)[
# :DBG: dump_attr : ]<function dump_attr>[
# :DBG: dvalues : ]<function <lambda>>[
# :DBG: file_encoding_is_clean : ]True[
# :DBG: get_readme : ]<function get_readme>[
# :DBG: get_use_cases : ]<function get_use_cases>[
# :DBG: hl : ]<function hl>[
# :DBG: hl_lvl : ]<function hl_lvl>[
# :DBG: hlc : ]<function hlc>[
# :DBG: hlcr : ]<function hlcr>[
# :DBG: hlr : ]<function hlssr>[
# :DBG: hls : ]<function hls>[
# :DBG: hlsr : ]<function hlsr>[
# :DBG: hlss : ]<function hlss>[
# :DBG: hlssr : ]<function hlssr>[
# :DBG: inc_template_marker : ]<function inc_template_marker>[
# :DBG: isstring : ]<function isstring>[
# :DBG: main : ]<function main>[
# :DBG: mw_ : ]<class 'adhoc.mw_'>[
# :DBG: mwg_ : ]<class 'adhoc.mwg_'>[
# :DBG: namespace_dict : ]<module 'namespace_dict' from '...namespace_dict.py...'>[
# :DBG: nativestr : ]<function nativestr>[
# :DBG: os : ]<module 'os' from '.../os.py...'>[
# :DBG: printe : ]<function printe>[
# :DBG: printf : ]<...function print...>[
# :DBG: re : ]<module 're' from '.../re.py...'>[
# :DBG: restore_stdout : ]<function restore_stdout>[
# :DBG: rst_to_ascii : ]<function rst_to_ascii>[
# :DBG: run : ]<function run>[
# :DBG: setdefaultencoding : ]<function setdefaultencoding>[
# :DBG: sformat : ]<function sformat>[
...
# :DBG: sys : ]<module 'sys' (built-in)>[
# :DBG: tpl_hook_doc_index_rst : ]<function tpl_hook_doc_index_rst>[
# :DBG: tpl_hook_readme : ]<function tpl_hook_readme>[
# :DBG: uc : ]<function uc>[
# :DBG: uc_type : ]<...>[
# :DBG: urllib : ]<module 'urllib' from '.../urllib...'>[
# :DBG: utf8str : ]<function utf8str>[
# --------------------
# |:INF:| adhoc.__adhoc__
# --------------------
# :DBG: __adhoc__ : ]...
# ------------------------------
# :DBG: __module__ : ]<module 'adhoc' from '.../adhoc.py...'>[
# :DBG: mode : ]...[
# :DBG: mtime : ][
# :DBG: source : ]#!/usr/bin/env python\\n# -*- coding: utf-8 -*-\\n# Copyright (C) 2011, 2012, Wolfgang Scherer,
...
.. @:adhoc_expected:@ adhoc_check_module_setup.e
.. \\|:here:|
'''
# :ide-menu: Emacs IDE Menu - Buffer @BUFFER@
# . M-x `eIDE-menu' ()(eIDE-menu "z")
# also remove __builtins__, _AdHocStringIO ...
# (progn
# (goto-char point-min) (replace-string "/home/ws/project/ws-util/adhoc" "..." nil (if (and transient-mark-mode mark-active) (region-beginning)) (if (and transient-mark-mode mark-active) (region-end)))
# (goto-char point-min) (replace-string "/home/ws/project/ws-util/lib/python" "..." nil (if (and transient-mark-mode mark-active) (region-beginning)) (if (and transient-mark-mode mark-active) (region-end)))
# (goto-char point-min) (replace-string "/home/ws/project/ws-util" "..." nil (if (and transient-mark-mode mark-active) (region-beginning)) (if (and transient-mark-mode mark-active) (region-end)))
# (goto-char point-min) (replace-string ".pyc" ".py" nil (if (and transient-mark-mode mark-active) (region-beginning)) (if (and transient-mark-mode mark-active) (region-end)))
# (goto-char point-min) (replace-string ".py" ".py..." nil (if (and transient-mark-mode mark-active) (region-beginning)) (if (and transient-mark-mode mark-active) (region-end)))
# (goto-char point-min) (replace-string ".../urllib.py..." ".../urllib..." nil (if (and transient-mark-mode mark-active) (region-beginning)) (if (and transient-mark-mode mark-active) (region-end)))
# (goto-char point-min) (replace-string "/usr/lib/python2.7" "..." nil (if (and transient-mark-mode mark-active) (region-beginning)) (if (and transient-mark-mode mark-active) (region-end)))
# (goto-char point-min) (replace-string-regexp "# :DBG: __adhoc__\\( *\\): \\].*" "# :DBG: __adhoc__\\1: ]..." nil (if (and transient-mark-mode mark-active) (region-beginning)) (if (and transient-mark-mode mark-active) (region-end)))
# (goto-char point-min) (replace-string-regexp "# :DBG: adhoc\\( *\\): \\].*" "# :DBG: adhoc\\1: ]..." nil (if (and transient-mark-mode mark-active) (region-beginning)) (if (and transient-mark-mode mark-active) (region-end)))
# (goto-char point-min) (replace-string-regexp "# :DBG: module : ..'ADHOC_TEST_SUB_IMPORTED',.*" "# :DBG: module : ]['ADHOC_TEST_SUB_IMPORTED',..." nil (if (and transient-mark-mode mark-active) (region-beginning)) (if (and transient-mark-mode mark-active) (region-end)))
# (goto-char point-min) (replace-string "<function _uc>" "<function ...>" nil (if (and transient-mark-mode mark-active) (region-beginning)) (if (and transient-mark-mode mark-active) (region-end)))
# (goto-char point-min) (replace-string "<type 'unicode'>" "<...>" nil (if (and transient-mark-mode mark-active) (region-beginning)) (if (and transient-mark-mode mark-active) (region-end)))
# (goto-char point-min)
# (goto-char point-min)
# (goto-char point-min)
# )
wid = 100
trunc = 10
hl_lvl(0)
hlc('adhoc_check_module_setup')
mod_name = 'no:module:found'
hls(mod_name)
module = AdHoc.module_setup('no:module:found')
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'module', str(dir(module))[:wid]))
dump_attr(module, wid=wid, trunc=trunc)
hl(sformat('{0}.__adhoc__',mod_name))
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'__adhoc__', str(dir(module.__adhoc__))[:wid]))
dump_attr(module.__adhoc__, wid=wid, trunc=trunc)
hls('adhoc_test.sub')
import adhoc_test.sub # @:adhoc:@
module = AdHoc.module_setup('adhoc_test.sub')
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'module', str(dir(module))[:wid]))
dump_attr(module, wid=wid, trunc=trunc)
hl('adhoc_test.sub.__adhoc__')
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'__adhoc__', str(dir(module.__adhoc__))[:wid]))
dump_attr(module.__adhoc__, wid=wid, trunc=trunc)
try:
import adhoc
hls('adhoc')
module = AdHoc.module_setup('adhoc')
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'adhoc', str(dir(module))[:wid]))
dump_attr(module, wid=wid, trunc=trunc)
hl('adhoc.__adhoc__')
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'__adhoc__', str(dir(module.__adhoc__))[:wid]))
dump_attr(module.__adhoc__, wid=wid, trunc=trunc)
except ImportError:
pass
def adhoc_check_encode_module(): # ||:fnc:||
wid = 100
trunc = 10
hl_lvl(0)
hlc('adhoc_check_encode_module')
module = AdHoc.module_setup('no:module:found')
hl('IMPORT SPEC')
ahc = AdHoc()
import_spec = '\n'.join(ahc.run_time_section.splitlines()[:5])
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'ahc.run_time_section', import_spec))
for_=None
module_name = 'no:module:found'
#hl(sformat('GET MODULE {0}',module_name))
module_import = ahc.encode_module(module_name, for_)
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'module_import',
'\n'.join(module_import.splitlines()[:5])))
module_name = 'ws_sql_tools'
#hl(sformat('GET MODULE {0}',module_name))
module_import = ahc.encode_module(module_name, for_)
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'module_import',
'\n'.join(module_import.splitlines()[:5])))
hl('EXECUTE')
exec(module_import)
[docs]def adhoc_check_packing(): # ||:fnc:||
"""
>>> source = AdHoc.read_source(__file__)
>>> AdHoc.write_source('write-check', source)
>>> rsource = AdHoc.read_source('write-check')
>>> os.unlink('write-check')
>>> (source == rsource)
True
>>> psource = AdHoc.pack_file(source, zipped=False)
>>> usource = AdHoc.unpack_file(psource, zipped=False)
>>> (source == usource)
True
>>> psource = AdHoc.pack_file(source, zipped=True)
>>> usource = AdHoc.unpack_file(psource, zipped=True)
>>> (source == usource)
True
"""
[docs]def run(parameters, pass_opts): # ||:fnc:||
"""Application runner, when called as __main__."""
# (progn (forward-line 1) (snip-insert-mode "py.bf.sql.ws" t) (insert "\n"))
# (progn (forward-line 1) (snip-insert-mode "py.bf.file.arg.loop" t) (insert "\n"))
# @: adhoc_enable:@
if not (parameters.compile or parameters.decompile):
parameters.compile = True
# @: adhoc_enable:@
if not parameters.args:
parameters.args = '-'
if _debug:
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'parameters.args', parameters.args))
# |:here:|
if parameters.compile:
output = parameters.output
if _verbose:
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':INF:', 'output', output))
if output is None:
output = '-'
compiled = compile_(parameters.args)
if _debug:
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'compiled', compiled))
AdHoc.write_source(output, compiled)
return
if parameters.decompile:
AdHoc.default_engine = True
export_dir = parameters.output
if export_dir is not None:
AdHoc.export_dir = export_dir
if _verbose:
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':INF:', 'export_dir', export_dir))
for file_ in parameters.args:
AdHoc.export(file_)
return
# |:here:|
# @:adhoc_disable:@ -development_tests
myfile = __file__
if myfile.endswith('.pyc'):
myfile = myfile[:-1]
myself = AdHoc.read_source(myfile)
if False:
adhoc_check_modules() # |:debug:|
adhoc_check_module_setup() # |:debug:|
# import ws_sql_tools
# ws_sql_tools.dbg_fwid = dbg_fwid
ws_sql_tools.check_file()
import_cmd_sections = AdHoc.tag_lines(
myself, AdHoc.line_tag('adhoc'))
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'import_cmd_sections', import_cmd_sections))
import_cmd_sections = AdHoc.tag_split(
myself, AdHoc.line_tag('adhoc'))
adhoc_dump_sections(import_cmd_sections)
pass
# |:here:|
# @:adhoc_disable:@
# @:adhoc_disable:@ -more_development_tests
# @:adhoc_remove:@
ah_retained, ah_removed = AdHoc.tag_partition(
myself, AdHoc.section_tag('adhoc_remove'))
hl('REMOVED')
adhoc_dump_list(ah_removed)
hl('RETAINED')
adhoc_dump_list(ah_retained)
# @:adhoc_remove:@
# |:debug:| def/class
ah = AdHoc()
ah_run_time_section = ah.prepare_run_time_section()
printf(sformat("{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:',
'ah_run_time_section', ah_run_time_section))
# adhoc_check_modules() # |:debug:|
# adhoc_check_module_setup() # |:debug:|
# adhoc_check_encode_module() # |:debug:|
# |:debug:| compiler
ah = AdHoc()
compiled = ah.compile(myself, 'myself')
printf(compiled, end='')
# @:adhoc_disable:@
# |:here:|
return
# --------------------------------------------------
# |||:sec:||| MAIN
# --------------------------------------------------
_quiet = False
_verbose = False
_debug = False
# (progn (forward-line 1) (snip-insert-mode "py.f.setdefaultencoding" t) (insert "\n"))
file_encoding_is_clean = True
def setdefaultencoding(encoding=None, quiet=False):
if file_encoding_is_clean:
return
if encoding is None:
encoding='utf-8'
try:
isinstance('', basestring)
if not hasattr(sys, '_setdefaultencoding'):
if not quiet:
printf('''\
Add this to /etc/python2.x/sitecustomize.py,
or put it in local sitecustomize.py and adjust PYTHONPATH=".:${PYTHONPATH}"::
try:
import sys
setattr(sys, '_setdefaultencoding', getattr(sys, 'setdefaultencoding'))
except AttributeError:
pass
Running with reload(sys) hack ...
''', file=sys.stderr)
reload(sys)
setattr(sys, '_setdefaultencoding',
getattr(sys, 'setdefaultencoding'))
sys._setdefaultencoding(encoding)
except NameError:
# python3 already has utf-8 default encoding ;-)
pass
def main(argv): # ||:fnc:||
global _quiet, _debug, _verbose
global RtAdHoc, AdHoc
global adhoc_rst_to_ascii
_parameters = None
_pass_opts = []
try:
# try system library first
import argparse
except ImportError:
# use canned version
try:
import argparse_local as argparse # @:adhoc:@
except ImportError:
printe('error: argparse missing. Try `easy_install argparse`.')
sys.exit(1)
parser = argparse.ArgumentParser(add_help=False)
# parser.add_argument('--sum', dest='accumulate', action='store_const',
# const=sum, default=max,
# help='sum the integers (default: find the max)')
# |:opt:| add options
# |:special:|
class AdHocAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
list(map(lambda opt: setattr(namespace, opt, False),
('implode', 'explode', 'extract', 'template', 'compile', 'decompile')))
setattr(namespace, option_string[2:], True)
setattr(namespace, 'adhoc_arg', values)
parser.add_argument(
'-c', '--compile', nargs=0, action=AdHocAction, default=False,
help='compile file(s) or standard input into file OUT (default standard output).')
parser.add_argument(
'-d', '--decompile', nargs=0, action=AdHocAction, default=False,
help='decompile file(s) or standard input into DIR (default __adhoc__).')
parser.add_argument(
'-o', '--output', action='store', type=str, default=None,
help='output file/directory for --compile/--decompile.')
# |:special:|
parser.add_argument(
'-q', '--quiet', action='store_const', const=-2,
dest='debug', default=0, help='suppress warnings')
parser.add_argument(
'-v', '--verbose', action='store_const', const=-1,
dest='debug', default=0, help='verbose test output')
parser.add_argument(
'--debug', nargs='?', action='store', type=int, metavar='NUM',
default = 0, const = 1,
help='show debug information')
parser.add_argument(
'-t', '--test', action='store_true',
help='run doc tests')
parser.add_argument(
'--implode', nargs=0, action=AdHocAction, default=False,
help='implode script with adhoc')
parser.add_argument(
'--explode', nargs='?', action=AdHocAction, type=str, metavar='DIR',
default=False, const='__adhoc__',
help='explode script with adhoc in directory DIR'
' (default: `__adhoc__`)')
parser.add_argument(
'--extract', nargs='?', action=AdHocAction, type=str, metavar='DIR',
default=False, const = '.',
help='extract files to directory DIR (default: `.`)')
parser.add_argument(
'--template', nargs='?', action=AdHocAction, type=str, metavar='NAME',
default=False, const = '-',
help='extract named template to standard output. default NAME is ``-``')
parser.add_argument(
'--expected', nargs='?', action=AdHocAction, type=str, metavar='DIR',
default=False, const = '.',
help='extract expected output to directory DIR (default: `.`)')
parser.add_argument(
'-h', '--help', action='store_true',
help="display this help message")
# |:special:|
parser.add_argument(
'--documentation', action='store_true',
help="display module documentation.")
parser.add_argument(
'--install', action='store_true',
help="install adhoc.py script.")
# |:special:|
parser.add_argument(
'--ap-help', action='store_true',
help="internal help message")
parser.add_argument(
'args', nargs='*', metavar='arg',
#'args', nargs='+', metavar='arg',
#type=argparse.FileType('r'), default=sys.stdin,
help='a series of arguments')
#_parameters = parser.parse_args()
(_parameters, _pass_opts) = parser.parse_known_args(argv[1:])
# generate argparse help
if _parameters.ap_help:
parser.print_help()
return 0
# standard help
if _parameters.help:
# |:special:|
help_msg = __doc__
help_msg = re.sub(
'^\\s*[.][.]\\s+_END_OF_HELP:\\s*\n.*(?ms)', '', help_msg)
sys.stdout.write(adhoc_rst_to_ascii(help_msg).strip() + '\n')
# |:special:|
return 0
_debug = _parameters.debug
if _debug > 0:
_verbose = True
_quiet = False
elif _debug < 0:
_verbose = (_debug == -1)
_quiet = not(_verbose)
_debug = 0
_parameters.debug = _debug
_parameters.verbose = _verbose
_parameters.quiet = _quiet
if _debug:
cmd_line = argv
sys.stderr.write(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[\n",
((('dbg_comm' in globals()) and (globals()['dbg_comm'])) or ('# ')),
((('dbg_twid' in globals()) and (globals()['dbg_twid'])) or (9)),
((('dbg_fwid' in globals()) and (globals()['dbg_fwid'])) or (15)),
':DBG:', 'cmd_line', cmd_line))
# at least use `quiet` to suppress the setdefaultencoding warning
setdefaultencoding(quiet=_quiet or _parameters.test)
# |:opt:| handle options
# adhoc: implode/explode/extract
adhoc_export = (_parameters.explode or _parameters.extract)
adhoc_op = (_parameters.implode or adhoc_export or _parameters.template
# |:special:|
or _parameters.documentation
or _parameters.install
or _parameters.expected
# |:special:|
)
if adhoc_op:
# |:special:|
# compiled AdHoc RtAdHoc
# compiled v
# implode req req
# explode req req
# extract req req
# template req(v) req
#
# uncompiled --- AdHoc ---> implode --> (compiled)
# compiled -- RtAdHoc --> explode --> __adhoc__
# compiled -- RtAdHoc --> extracted --> .
# compiled -- RtAdHoc --> template --> stdout
# |:special:|
file_ = __file__
source = None
have_adhoc = 'AdHoc' in globals()
have_rt_adhoc = 'RtAdHoc' in globals()
# shall adhoc be imported
if _parameters.implode or not have_rt_adhoc:
# shall this file be compiled
adhoc_compile = not (have_rt_adhoc
# |:special:|
or _parameters.documentation
# |:special:|
)
os_path = os.defpath
for pv in ('PATH', 'path'):
try:
os_path = os.environ[pv]
break
except KeyError:
pass
os_path = os_path.split(os.pathsep)
for path_dir in os_path:
if not path_dir:
continue
if path_dir not in sys.path:
sys.path.append(path_dir)
if not have_adhoc:
try:
import adhoc
AdHoc = adhoc.AdHoc
except ImportError:
adhoc_compile = False
try:
from rt_adhoc import RtAdHoc as Adhoc
except ImportError:
pass
# |:special:|
AdHoc.flat = False
# |:special:|
else:
adhoc_compile = False
AdHoc = RtAdHoc
AdHoc.quiet = _quiet
AdHoc.verbose = _verbose
AdHoc.debug = _debug
AdHoc.include_path.append(os.path.dirname(file_))
AdHoc.extra_templates = [
('README.txt', 'adhoc_template'),
('doc/USE_CASES.txt', 'adhoc_template'),
]
AdHoc.template_process_hooks = {'doc/index.rst': tpl_hook_doc_index_rst}
if adhoc_compile:
ah = AdHoc()
source = ah.compileFile(file_)
else:
file_, source = AdHoc.std_source_param(file_)
# implode
if _parameters.implode:
# @:adhoc_enable:@
# if not _quiet:
# list(map(sys.stderr.write,
# ["warning: ", os.path.basename(file_),
# " already imploded!\n"]))
# @:adhoc_enable:@
AdHoc.write_source('-', source)
# explode
elif (_parameters.explode
# |:special:|
or _parameters.install
# |:special:|
):
# |:special:|
if _parameters.install:
_parameters.adhoc_arg = '__adhoc_install__'
# |:special:|
AdHoc.export_dir = _parameters.adhoc_arg
AdHoc.export(file_, source)
# |:special:|
README = get_readme(file_, source, as_template='README.txt', transform=False)
USE_CASES = get_use_cases(as_template='doc/USE_CASES.txt')
sv = AdHoc.inc_delimiters()
AdHoc.export(file_, README)
AdHoc.export(file_, USE_CASES)
AdHoc.reset_delimiters(sv)
# |:special:|
# extract
elif _parameters.extract:
AdHoc.extract_dir = _parameters.adhoc_arg
AdHoc.extract(file_, source)
# |:special:|
# imports, that should be extracted
for imported in (
'use_case_000_',
'use_case_001_templates_',
'use_case_002_include_',
'use_case_003_import_',
'use_case_005_nested_',
):
ximported = ''.join((imported, '.py'))
ximported = AdHoc.check_xfile(ximported)
if ximported:
simported = AdHoc.get_named_template(imported, file_)
AdHoc.write_source(ximported, simported)
README = get_readme(file_, source, as_template='README.txt', transform=False)
USE_CASES = get_use_cases(as_template='doc/USE_CASES.txt')
sv = AdHoc.inc_delimiters()
AdHoc.extract(file_, README)
AdHoc.extract(file_, USE_CASES)
AdHoc.reset_delimiters(sv)
# |:special:|
# template
elif _parameters.template:
template_name = _parameters.adhoc_arg
if not template_name:
template_name = '-'
if template_name == 'list':
sys.stdout.write(
'\n'.join(AdHoc.template_table(file_, source)) + '\n')
# |:special:|
elif template_name == 'README.txt':
README = get_readme(file_, source, as_template=template_name, transform=False)
sv = AdHoc.inc_delimiters()
AdHoc.write_source('-', AdHoc.get_named_template(template_name, file_, README))
AdHoc.reset_delimiters(sv)
elif template_name == 'doc/USE_CASES.txt':
USE_CASES = get_use_cases()
AdHoc.write_source('-', USE_CASES)
# |:special:|
else:
template = AdHoc.get_named_template(
template_name, file_, source)
# |:special:|
template = AdHoc.section_tag_remove(template, "adhoc_run_time_section")
# |:special:|
AdHoc.write_source('-', template)
# |:special:|
# expected
elif _parameters.expected:
AdHoc.extract_dir = _parameters.adhoc_arg
AdHoc.extract_templates(file_, source, AdHoc.section_tag('adhoc_expected'))
# documentation
elif _parameters.documentation:
sys.stdout.write(get_readme(file_, source))
# install
if _parameters.install:
here = os.path.abspath(os.getcwd())
os.chdir(AdHoc.export_dir)
os.system(''.join((sys.executable, " setup.py install")))
os.chdir(here)
import shutil
shutil.rmtree(AdHoc.export_dir, True)
# |:special:|
# restore for subsequent calls to main
if not have_adhoc:
del(AdHoc)
return 0
# run doc tests
if _parameters.test:
import doctest
doctest.testmod(verbose = _verbose)
return 0
# |:opt:| handle options
run(_parameters, _pass_opts)
if __name__ == "__main__":
#sys.argv.insert(1, '--debug') # |:debug:|
result = main(sys.argv)
sys.exit(result)
# |:here:|
# @:adhoc_uncomment:@
# @:adhoc_template:@ -test
# Test template.
# @:adhoc_template:@
# @:adhoc_uncomment:@
if False:
pass
# @:adhoc_verbatim:@ # docutils.conf
# @:adhoc_include:@ Makefile, MANIFEST.in, README.css, setup.py
# @:adhoc_include:@ doc/conf.py, doc/make.bat, doc/Makefile, doc/z-massage-index.sh, doc/adhoc-logo.svg, doc/_static/adhoc-logo-32.ico
# |:here:|
# (progn (forward-line 1) (snip-insert-mode "py.t.ide" t) (insert "\n"))
#
# :ide-menu: Emacs IDE Main Menu - Buffer @BUFFER@
# . M-x `eIDE-menu' (eIDE-menu "z")
# :ide: CSCOPE ON
# . (cscope-minor-mode)
# :ide: CSCOPE OFF
# . (cscope-minor-mode (quote ( nil )))
# :ide: TAGS: forced update
# . (compile (concat "cd /home/ws/project/ws-rfid && make -k FORCED=1 tags"))
# :ide: TAGS: update
# . (compile (concat "cd /home/ws/project/ws-rfid && make -k tags"))
# :ide: +-#+
# . Utilities ()
# :ide: TOC: Generate TOC with py-toc.py
# . (progn (save-buffer) (compile (concat "py-toc.py ./" (file-name-nondirectory (buffer-file-name)) " ")))
# :ide: CMD: Fold region with line continuation
# . (shell-command-on-region (region-beginning) (region-end) "fold --spaces -width 79 | sed 's, $,,;1!s,^, ,;$!s,$,\\\\,'" nil nil nil t)
# :ide: CMD: Fold region and replace with line continuation
# . (shell-command-on-region (region-beginning) (region-end) "fold --spaces --width 79 | sed 's, $,,;1!s,^, ,;$!s,$,\\\\,'" t nil nil t)
# :ide: +-#+
# . Fold ()
# :ide: CMD: Remove 8 spaces and add `>>> ' to region
# . (shell-command-on-region (region-beginning) (region-end) "sed 's,^ ,,;/^[ ]*##/d;/^[ ]*#/{;s,^ *# *,,p;d;};/^[ ]*$/!s,^,>>> ,'" nil nil nil t)
# :ide: CMD: Remove 4 spaces and add `>>> ' to region
# . (shell-command-on-region (region-beginning) (region-end) "sed 's,^ ,,;/^[ ]*##/d;/^[ ]*#/{;s,^ *# *,,p;d;};/^[ ]*$/!s,^,>>> ,'" nil nil nil t)
# :ide: +-#+
# . Doctest ()
# :ide: LINT: Check 80 column width ignoring IDE Menus
# . (let ((args " | /srv/ftp/pub/check-80-col.sh -")) (compile (concat "sed 's,^\\(\\|. \\|.. \\|... \\)\\(:ide\\|[.] \\).*,,;s,^ *. (progn (forward-line.*,,' " (buffer-file-name) " " args " | sed 's,^-," (buffer-file-name) ",'")))
# :ide: LINT: Check 80 column width
# . (let ((args "")) (compile (concat "/srv/ftp/pub/check-80-col.sh " (buffer-file-name) " " args)))
# :ide: +-#+
# . Lint Tools ()
# :ide: DELIM: |: SYM :| |:tag:| standard symbol-tag!
# . (symbol-tag-normalize-delimiter (cons (cons nil "|:") (cons ":|" nil)) t)
# :ide: DELIM: :: SYM :: ::fillme:: future standard fill-me tag
# . (symbol-tag-normalize-delimiter (cons (cons nil "::") (cons "::" nil)) t)
# :ide: DELIM: @: SYM :@ @:fillme:@ adhoc tag
# . (symbol-tag-normalize-delimiter (cons (cons nil "@:") (cons ":@" nil)) t)
# :ide: +-#+
# . Delimiters ()
# :ide: COMPILE: Run with --ap-help
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --ap-help")))
# :ide: COMPILE: Run with --help
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --help")))
# :ide: COMPILE: Run with --test
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --test")))
# :ide: COMPILE: Run with --test --verbose
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --test --verbose")))
# :ide: COMPILE: Run with --debug
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --debug")))
# :ide: +-#+
# . Compile with standard arguments ()
# :ide: OCCUR-OUTLINE: Python Source Code
# . (x-symbol-tag-occur-outline "sec" '("||:" ":||") (cons (cons "^\\([ \t\r]*\\(def\\|class\\)[ ]+\\|[A-Za-z_]?\\)" nil) (cons nil "\\([ \t\r]*(\\|[ \t]*=\\)")))
# :ide: MENU-OUTLINE: Python Source Code
# . (x-eIDE-menu-outline "sec" '("|||:" ":|||") (cons (cons "^\\([ \t\r]*\\(def\\|class\\)[ ]+\\|[A-Za-z_]?\\)" nil) (cons nil "\\([ \t\r]*(\\|[ \t]*=\\)")))
# :ide: +-#+
# . Outline ()
# :ide: INFO: SQLAlchemy - SQL Expression Language - Reference
# . (let ((ref-buffer "*sqa-expr-ref*")) (if (not (get-buffer ref-buffer)) (shell-command (concat "w3m -dump -cols " (number-to-string (1- (window-width))) " 'http://www.sqlalchemy.org/docs/05/reference/sqlalchemy/expressions.html'") ref-buffer) (display-buffer ref-buffer t)))
# :ide: INFO: SQLAlchemy - SQL Expression Language - Tutorial
# . (let ((ref-buffer "*sqa-expr-tutor*")) (if (not (get-buffer ref-buffer)) (shell-command (concat "w3m -dump -cols " (number-to-string (1- (window-width))) " 'http://www.sqlalchemy.org/docs/05/sqlexpression.html'") ref-buffer) (display-buffer ref-buffer t)))
# :ide: INFO: SQLAlchemy - Query
# . (let ((ref-buffer "*sqa-query*")) (if (not (get-buffer ref-buffer)) (shell-command (concat "w3m -dump -cols " (number-to-string (1- (window-width))) " 'http://www.sqlalchemy.org/docs/orm/query.html'") ref-buffer) (display-buffer ref-buffer t)))
# :ide: +-#+
# . SQLAlchemy Reference ()
# :ide: INFO: Python - argparse
# . (let ((ref-buffer "*python-argparse*")) (if (not (get-buffer ref-buffer)) (shell-command (concat "w3m -dump -cols " (number-to-string (1- (window-width))) " 'http://docs.python.org/library/argparse.html'") ref-buffer) (display-buffer ref-buffer t)))
# :ide: INFO: Python Documentation
# . (let ((ref-buffer "*w3m*")) (if (get-buffer ref-buffer) (display-buffer ref-buffer t)) (other-window 1) (w3m-goto-url "http://docs.python.org/index.html" nil nil))
# :ide: INFO: Python Reference
# . (let* ((ref-buffer "*python-ref*") (local "/home/ws/project/ws-util/python/reference/PQR2.7.html") (url (or (and (file-exists-p local) local) "'http://rgruet.free.fr/PQR27/PQR2.7.html'"))) (unless (get-buffer ref-buffer) (get-buffer-create ref-buffer) (with-current-buffer ref-buffer (shell-command (concat "snc txt.py.reference 2>/dev/null") ref-buffer) (goto-char (point-min)) (if (eobp) (shell-command (concat "w3m -dump -cols " (number-to-string (1- (window-width))) " " url) ref-buffer)))) (display-buffer ref-buffer t))
# :ide: +-#+
# . Python Reference ()
# :ide: COMPILE: Run with --decompile dist/xx_adhoc.py
# . (progn (save-buffer) (compile (concat "rm -rf __adhoc__; cp -p dist/adhoc.py dist/xx_adhoc.py; python ./" (file-name-nondirectory (buffer-file-name)) " --decompile dist/xx_adhoc.py")))
# :ide: COMPILE: Run with cat dist/adhoc.py | --decompile
# . (progn (save-buffer) (compile (concat "rm -rf __adhoc__; cat dist/adhoc.py | python ./" (file-name-nondirectory (buffer-file-name)) " --decompile")))
# :ide: COMPILE: Run with cat /dev/null | --decompile
# . (progn (save-buffer) (compile (concat "rm -rf __adhoc__; cat /dev/null | python ./" (file-name-nondirectory (buffer-file-name)) " --decompile")))
# :ide: COMPILE: Run with cat /dev/null | --compile
# . (progn (save-buffer) (compile (concat "cat /dev/null | python ./" (file-name-nondirectory (buffer-file-name)) " --compile")))
# :ide: COMPILE: Run with cat /dev/null |
# . (progn (save-buffer) (compile (concat "cat /dev/null | python ./" (file-name-nondirectory (buffer-file-name)) " ")))
# :ide: COMPILE: Run with --help
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --help")))
# :ide: COMPILE: Run with --template doc/index.rst
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --template doc/index.rst")))
# :ide: COMPILE: Run with --template test
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --template test")))
# :ide: COMPILE: Run with --template
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --template")))
# :ide: COMPILE: Run with python3 with --template list
# . (progn (save-buffer) (compile (concat "python3 ./" (file-name-nondirectory (buffer-file-name)) " --template list")))
# :ide: COMPILE: Run with --verbose --implode
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --verbose --implode")))
# :ide: COMPILE: Run with --documentation
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --documentation")))
# :ide: COMPILE: make ftp
# . (progn (save-buffer) (compile (concat "make -k ftp")))
# :ide: COMPILE: Run with --verbose --extract
# . (progn (save-buffer) (shell-command "rm -f README.txt doc/index.rst") (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --verbose --extract")))
# :ide: COMPILE: Run with --verbose --template README.txt
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --verbose --template README.txt")))
# :ide: COMPILE: make doc
# . (progn (save-buffer) (compile (concat "make doc")))
# :ide: COMPILE: Run with --template list
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --template list")))
# :ide: COMPILE: Run with python3 with --test
# . (progn (save-buffer) (compile (concat "python3 ./" (file-name-nondirectory (buffer-file-name)) " --test")))
# :ide: COMPILE: Run with python3 w/o args
# . (progn (save-buffer) (compile (concat "python3 ./" (file-name-nondirectory (buffer-file-name)) " ")))
# :ide: COMPILE: Run with --expected
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --expected")))
# :ide: COMPILE: Run with --test
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --test")))
# :ide: COMPILE: Run with --verbose
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --verbose")))
# :ide: +-#+
# . Compile ()
#
# Local Variables:
# mode: python
# comment-start: "#"
# comment-start-skip: "#+"
# comment-column: 0
# truncate-lines: t
# End: