#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2018, Wolfgang Scherer, <Wolfgang.Scherer at gmx.de>
#
# This file is part of Documentation Standard.
#
# 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/>.
## |||:sec:||| Extract UML Diagrams #a2
## start #a2
## floating note right #a2
r"""line_diversion.py - extract UML diagram from source code
.. role:: rem(comment)
====== ====================
usage: line_diversion.py [OPTIONS] [file ..] :rem:`a2`
or import line_diversion
====== ====================
Options
=======
.. :rem:`a2`
===================== ==================================================
-m, --match RX only extract diagrams matching RX :rem:`a2`
-b, --file-base=BASE Write output to files: `BASE` + `ID` + ".puml". :rem:`a2`
E.g. --file-base="file-base-" => file-base-a0.puml
--show-bases show base classes for class diagrams (default) :rem:`a2`
--hide-bases hide base classes for class diagrams :rem:`a2`
--ignore-bases CLASS ignore base class for class diagrams :rem:`a2`
(can be specified multiple times) (default: object, PyJsMo)
-r, --replace REP register replacement REP. REP is a symbol and :rem:`a2`
a replacement separated by whitespace. :rem:`a2`
--verbatim do not perform standard replacements :rem:`a2`
-q, --quiet suppress warnings
-v, --verbose verbose test output
-d, --debug[=NUM] show debug information
-h, --help display this help message
--template list show available templates.
--eide[=COMM] Emacs IDE template list (implies --template list).
--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__``)
--setup[=install] explode script into temporary directory and call
`python setup.py install`
--implode implode script with adhoc
-t, --test run doc tests
===================== ==================================================
Module
======
These are the `UML diagrams`_ and type codes supported by `PlantUML`_
.. :rem:`a2`
============ ======================= ==========
| **Marker** | **Diagram** | :rem:`a2`
============ ======================= ==========
| #c[0-9]+ | class diagram | :rem:`a2`
| #o[0-9]+ | object diagram | :rem:`a2`
| #p[0-9]+ | component diagram | :rem:`a2`
| #d[0-9]+ | deployment diagram | :rem:`a2`
| #u[0-9]+ | use case diagram | :rem:`a2`
| #a[0-9]+ | activity diagram | :rem:`a2`
| #s[0-9]+ | state machine diagram | :rem:`a2`
| #m[0-9]+ | sequence diagram | :rem:`a2`
| #t[0-9]+ | timing diagram | :rem:`a2`
============ ======================= ==========
+-------------------------+------+-------------------------------+------+
| - `Structure Diagrams`_ | Type | - `Behavior Diagrams`_ | Type |
+=========================+======+===============================+======+
| - `Class Diagram`_ | c | - `Use Case Diagram`_ | u |
+-------------------------+------+-------------------------------+------+
| - `Object Diagram`_ | o | - `Activity Diagram`_ | a |
+-------------------------+------+-------------------------------+------+
| - `Component Diagram`_ | p | - `State Machine Diagram`_ | s |
+-------------------------+------+-------------------------------+------+
| - `Deployment Diagram`_ | d | - `Message Sequence Diagram`_ | m |
+-------------------------+------+-------------------------------+------+
| | | - `Timing Diagram`_ | t |
+-------------------------+------+-------------------------------+------+
This is the inheritance hierarchy of `UML diagrams`_ supported by
PlantUML (clickable in HTML):
.. uml:: _static/uml-diagram-hierarchy.puml
.. _`UML Diagrams`: https://www.uml-diagrams.org/uml-25-diagrams.html
.. _`PlantUML`: http://plantuml.com
Automatic Exports
=================
>>> for ex in __all__: printf(sformat('from {0} import {1}', __name__, ex))
from line_diversion import check_line_parse
from line_diversion import LineParser
from line_diversion import DiagramTiming
from line_diversion import DiagramMessageSequence
from line_diversion import DiagramInteraction
from line_diversion import DiagramStateMachine
from line_diversion import DiagramActivity
from line_diversion import DiagramUseCase
from line_diversion import DiagramBehavior
from line_diversion import DiagramDeployment
from line_diversion import DiagramComponent
from line_diversion import DiagramObject
from line_diversion import DiagramClass
from line_diversion import DiagramStructure
from line_diversion import Diagram
from line_diversion import LineDiversion
Explicit Exports
================
>>> if '__all_internal__' in globals():
... for ex in __all_internal__:
... printf(sformat('from {0} import {1}', __name__, ex))
.. _END_OF_HELP_line_diversion:
Details
=======
See :func:`check_line_parse` for comprehensive list of line matchers.
Prefix Match
------------
>>> printf(PREFIX_LP)
{
"rx": [
"^(\\s*)(?://+|/\\*+|;+|@:u?[bl]?comm_?@|--|#+|@[bl]?comm_?@|[.][.])([copduasmt][0-9]+)(?:\\s|$)",
"0"
],
"groups": {
"whitespace": 1,
"id": 2,
"text": null,
"keyword": null,
"condition": null
}
}
>>> mo, _id = PREFIX_LP.match('#''a3 if (test) then (yes)')
>>> printf(mo.groups())
('', 'a3')
Condition Match
---------------
>>> printf(COND_LP)
{
"rx": [
"^(\\s*)(break|class|def|done|elif|else|elseif|elsif|fi|for|if|while|\\})(?::?|\\s)\\s*(.*)\\s*(?://+|/\\*+|;+|@:u?[bl]?comm_?@|--|#+|@[bl]?comm_?@|[.][.])([copduasmt][0-9]+)(?:\\s(.*)|\\s*)$",
"0"
],
"groups": {
"whitespace": 1,
"id": 4,
"text": 5,
"keyword": 2,
"condition": 3
}
}
>>> mo, _id = COND_LP.match(' if remove_count: #''a1 then (yeah)')
>>> printf(mo.groups())
(' ', 'if', 'remove_count: ', 'a1', 'then (yeah)')
>>> mo, _id = COND_LP.match('} #''a1')
>>> printf(mo.groups())
('', '}', '', 'a1', None)
Action Match
------------
>>> printf(ACT_LP)
{
"rx": [
"^(\\s*)(?:(?://+|/\\*+|;+|@:u?[bl]?comm_?@|--|#+|@[bl]?comm_?@|[.][.]) )?(.*)\\s*(?://+|/\\*+|;+|@:u?[bl]?comm_?@|--|#+|@[bl]?comm_?@|[.][.])([copduasmt][0-9]+) (:[];|<>/}]?|[];|<>/}.-])\\s*(?:(#[0-9A-Za-z]+|backwards)(?:\\s+|$))?(?:\\s(.*)|\\s*)$",
"0"
],
"groups": {
"whitespace": 1,
"id": 3,
"text": 6,
"keyword": 4,
"condition": 2,
"cond_pfx": 5
}
}
>>> mo, _id = ACT_LP.match('# * call `process_parts #''a3 :| #red')
>>> printf(mo.groups())
('', '* call `process_parts ', 'a3', ':|', '#red', None)
>>> mo, _id = ACT_LP.match(' something = more #''a1 :')
>>> printf(mo.groups())
(' ', 'something = more ', 'a1', ':', None, None)
>>> mo, _id = ACT_LP.match(' something = more #''a1 ::')
>>> if mo: printf(mo.groups())
>>> mo, _id = ACT_LP.match(' something = more #''a1 :-')
>>> if mo: printf(mo.groups())
>>> mo, _id = ACT_LP.match(' something = more #''a1 :;')
>>> printf(mo.groups())
(' ', 'something = more ', 'a1', ':;', None, None)
>>> mo, _id = ACT_LP.match('rm -f "${top_dir}/.hgignore.new" #''a1 :')
>>> printf(mo.groups())
('', 'rm -f "${top_dir}/.hgignore.new" ', 'a1', ':', None, None)
.. \|:here:|
>>> printf(ACT_RX.pattern)
^(\s*)(?:(?://+|/\*+|;+|@:u?[bl]?comm_?@|--|#+|@[bl]?comm_?@|[.][.]) )?(.*)\s*(?://+|/\*+|;+|@:u?[bl]?comm_?@|--|#+|@[bl]?comm_?@|[.][.])([copduasmt][0-9]+) (:[];|<>/}]?|[];|<>/}.-])\s*(?:(#[0-9A-Za-z]+|backwards)(?:\s+|$))?(?:\s(.*)|\s*)$
>>> printf(ACT_LP.groups)
OrderedDict([('whitespace', 1), ('id', 3), ('text', 6), ('keyword', 4), ('condition', 2), ('cond_pfx', 5)])
.. _`UML 2.5 Diagram`: https://www.uml-diagrams.org/uml-25-diagrams.html
.. _`Structure Diagram`: https://www.uml-diagrams.org/uml-25-diagrams.html#structure-diagram
.. _`Structure Diagrams`: https://www.uml-diagrams.org/uml-25-diagrams.html#structure-diagram
.. _`Class Diagram`: https://www.uml-diagrams.org/class-diagrams-overview.html
.. _`Object Diagram`: https://www.uml-diagrams.org/class-diagrams-overview.html#object-diagram
.. _`Component Diagram`: https://www.uml-diagrams.org/component-diagrams.html
.. _`Deployment Diagram`: https://www.uml-diagrams.org/deployment-diagrams-overview.html
.. _`Behavior Diagram`: https://www.uml-diagrams.org/uml-25-diagrams.html#behavior-diagram
.. _`Behavior Diagrams`: https://www.uml-diagrams.org/uml-25-diagrams.html#behavior-diagram
.. _`Use Case Diagram`: https://www.uml-diagrams.org/use-case-diagrams.html
.. _`Activity Diagram`: https://www.uml-diagrams.org/activity-diagrams.html
.. _`State Machine Diagram`: https://www.uml-diagrams.org/state-machine-diagrams.html
.. _`Interaction diagram`: https://www.uml-diagrams.org/uml-25-diagrams.html#interaction-diagram
.. _`Message Sequence Diagram`: https://www.uml-diagrams.org/sequence-diagrams.html
.. _`Timing Diagram`: https://www.uml-diagrams.org/timing-diagrams.html
"""
# end note #a2
# (progn (forward-line 1) (snip-insert "py.b.future.with" t t "python") (insert "\n"))
# for python 2.5
from __future__ import with_statement
# (progn (forward-line 1) (snip-insert "py.main.pyramid.activate" t t "py") (insert ""))
# --------------------------------------------------
# |||:sec:||| COMPATIBILITY
# --------------------------------------------------
import sys
# (progn (forward-line 1) (snip-insert "py.b.printf" t t "py") (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 "py.b.sformat" t t "py") (insert "\n"))
try:
('{0}').format(0)
def sformat (fmtspec, *args, **kwargs):
return fmtspec.format(*args, **kwargs)
except AttributeError:
try:
import stringformat
def sformat (fmtspec, *args, **kwargs):
return stringformat.FormattableString(fmtspec).format(
*args, **kwargs)
except ImportError:
printf('error: stringformat missing. Try `easy_install stringformat`.', file=sys.stderr)
# (progn (forward-line 1) (snip-insert "py.b.isstring" t t "python") (insert "\n"))
try:
from ws_seq_type import isstring, issequence, sequence_type, UCHAR_FMT
except ImportError:
# (progn (forward-line 1) (snip-insert "py.f.isstring" t t "py") (insert "\n"))
exec('''
def isstring(obj):
return isinstance(obj, basestring)
'''.strip())
try:
isstring("")
UCHAR_FMT = 'u"{0}u{1:04x}"'
except NameError:
def isstring(obj):
return isinstance(obj, str) or isinstance(obj, bytes)
UCHAR_FMT = '"{0}u{1:04x}"'
# (progn (forward-line 1) (snip-insert "py.f.issequence" t t "py") (insert "\n"))
def issequence(arg, or_dict=False, or_seq=True): # ||:fnc:||
if not isstring(arg):
if hasattr(arg, 'items'):
return or_dict
if hasattr(arg, '__getitem__'):
return True
if hasattr(arg, '__iter__'):
return or_seq
return False
# (progn (forward-line 1) (snip-insert-mode "py.f.sequence_type" t) (insert "\n"))
_st_strg = (True, False, False, False)
_st_list = (False, True, False, False)
_st_dict = (False, False, True, False)
_st_seq = (False, False, False, True)
_st_none = (False, False, False, False)
def sequence_type(value): # ||:fnc:||
if isstring(value):
return _st_strg
if hasattr(value, 'items'):
return _st_dict
if hasattr(value, '__getitem__'):
return _st_list
if hasattr(value, '__iter__'):
return _st_seq
return _st_none
# (progn (forward-line 1) (snip-insert-mode "py.f.uchar" t) (insert "\n"))
def uchar(num):
'''Make UNICODE character.'''
return eval(sformat(UCHAR_FMT,'\\', num))
# (progn (forward-line 1) (snip-insert "py.b.dict.items" t t "py") (insert "\n"))
try:
getattr(dict(), 'iteritems')
except AttributeError:
ditems = lambda d: getattr(d, 'items')()
dkeys = lambda d: getattr(d, 'keys')()
dvalues = lambda d: getattr(d, 'values')()
else:
ditems = lambda d: getattr(d, 'iteritems')()
dkeys = lambda d: getattr(d, 'iterkeys')()
dvalues = lambda d: getattr(d, 'itervalues')()
# (progn (forward-line 1) (snip-insert "py.b.xrange" t t "py") (insert "\n"))
# `xrange` returns a generator, which `range` already does for python3
# note: use l.. and g.. to get list/generator versions
try:
xrange(0)
lrange = lambda *args, **kwargs: range(*args, **kwargs)
except NameError:
xrange = range
lrange = lambda *args, **kwargs: list(range(*args, **kwargs))
grange = xrange
# `xfilter` returns a list, `filter` may return a generator. This is
# different from the range/xrange semantics!
if isinstance(filter(str, []), list):
xfilter = filter
gfilter = lambda _f, _s, *args, **kwargs: (_e for _e in _s if _f(_e))
else:
xfilter = lambda *args, **kwargs: list(filter(*args, **kwargs))
gfilter = filter
lfilter = xfilter
# `xmap` returns a list, `map` may return a generator. This is
# different from the range/xrange semantics!
if isinstance(map(str, []), list):
xmap = map
gmap = lambda _f, _s, *args, **kwargs: (_f(_e) for _e in _s)
else:
xmap = lambda *args, **kwargs: list(map(*args, **kwargs))
gmap = map
lmap = xmap
# `long` is gone in python3
try:
isinstance(int, long)
except NameError:
long = int
# (progn (forward-line 1) (snip-insert "py_f.lfind" t t "python") (insert "\n"))
def lfind(l, elt):
try:
return l.index(elt)
except ValueError:
return -1
import os
import re
# --------------------------------------------------
# |||:sec:||| CONFIGURATION
# --------------------------------------------------
__all__ = []
__all_internal__ = []
# (progn (forward-line 1) (snip-insert "py.b.dbg.def" t t "python") (insert ""))
dbg_fwid = globals().get('dbg_fwid', 15)
# (progn (forward-line 1) (snip-insert "py.b.canonize.module" t t "python") (insert ""))
def _canonize_module_(module_or_name, full=None, drop=None):
if isstring(module_or_name):
module = sys.modules[module_or_name]
else:
module = module_or_name
module_name = module.__name__
# flag for __main__
_is_main_ = (module_name == '__main__')
if not hasattr(module, '_is_main_'):
module._is_main_ = _is_main_
if not full:
return _is_main_
# module file name -> canonical name
try:
mfile = module.__file__
except AttributeError:
return
canon_name_ = mfile
canon_name_ = os.path.basename(canon_name_)
canon_name_, _ext = os.path.splitext(canon_name_)
# adhoc compiliation xx_.py -> xx.py
if canon_name_.endswith('_') and not canon_name_.endswith('__'):
canon_name_ = canon_name_[:-1]
canon_name_ = re.sub('[^0-9A-Za-z_]+', '_', canon_name_)
# find parent module |:check:| distutils/pkg_resources?
mdir = os.path.abspath(os.path.dirname(mfile))
mparts = []
while mdir and os.path.exists(os.path.join(mdir, '__init__.py')):
mdir, pfx = os.path.split(mdir)
mparts.insert(0, pfx)
parent = '.'.join(mparts)
if canon_name_ != '__init__':
mparts.append(canon_name_)
if drop:
mparts = mparts[:-drop]
canon_name = '.'.join(mparts)
if module_name != canon_name:
if parent != canon_name or drop: # |:check:| why?
if parent:
# fix parent module
exec('import ' + parent)
if parent in (sys.modules):
setattr(sys.modules[parent], canon_name_, module)
sys.modules[canon_name] = module
module.__name__ = canon_name
# adjust module members
for t in dvalues(vars(module)):
try:
if '__module__' in vars(t) and t.__module__ == module_name:
t.__module__ = canon_name
except TypeError:
pass
return _is_main_
#_canonize_module_(__name__, __name__ == '__main__')
# (progn (forward-line 1) (snip-insert "py.b.strings" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.strclean" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.b.logging" t t "python") (insert ""))
# (progn (forward-line 1) (snip-insert "py.b.ordereddict" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.b.dbg.setup" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.main.project.libdir" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.main.sql.alchemy" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.main.sql.ws" t t "py") (insert "\n"))
# @:adhoc_run_time:@
import pyjsmo # @:adhoc:@
# (progn (forward-line 1) (snip-insert "py.b.posix" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.b.os.system.sh" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.b.prog.path" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_b.line-loop" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_b.table_standalone" t t "python") (insert ""))
# (progn (forward-line 1) (snip-insert "py.wsrfid.pylons.imports" t t "python") (insert ""))
# (progn (forward-line 1) (snip-insert "py.main.wsgi.get.app" t t "python") (insert ""))
# (progn (forward-line 1) (snip-insert "py_wsrfid.config_delayed" t t "python") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_b.wsrfid.config_translate_shortcuts" t t "python") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_b.dba_imports" t t "python") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_b.dba_datainit" t t "python") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_jsmo.imports" t t "python") (insert "\n"))
from pyjsmo.result import *
from pyjsmo.translate import trans_list_comma
# |:here:|
# --------------------------------------------------
# |||:sec:||| DATA
# --------------------------------------------------
DIAGRAM_HEADER = '''
@startuml /' @ld-id@ '/
skinparam padding 1
'''.strip()
DIAGRAM_FOOTER = '''
@enduml
'''.strip()
DELIMITERS = dict(((_d, _d) for _d in ('"', "'")))
IGNORE_BASES = ['object', 'pyjsmo.PyJsMo', 'PyJsMo']
REPLACEMENTS = dict()
REPLACEMENTS_STD = dict()
# left to right direction #c0
# --------------------------------------------------
# |||:sec:||| CLASSES #c0
# --------------------------------------------------
__all__.append('LineDiversion')
[docs]class LineDiversion(list): #c0 ||:cls:||
r"""
.. \|:here:|
"""
type = None #c0
id_ = None #c0
header = '' #c0
footer = '' #c0
def __init__(self, *args, **kwargs): # |:mth:|
super(LineDiversion, self).__init__(*args, **kwargs)
[docs] def open_partition(self, text): #c0 |:mth:|
r"""
:returns: self for chaining.
"""
self.close_partition()
return self
[docs] def close_partition(self): #c0 |:mth:|
r"""
:returns: self for chaining.
"""
return self
[docs] def finish(self): #c0 |:mth:|
r"""
:returns: self for chaining.
"""
return self.close_partition()
# --------------------------------------------------
# |||:sec:||| DIAGRAM CLASSES
# --------------------------------------------------
DIAGRAM_LINE_PARTS = (
'indent',
'text',
'sformat',
'kw',
'cond_pfx',
'condr',
'rest',
'mapped_kw',
'kw_sep',
'cond',
'kw_cont_sep',
'mapped_kw_cont',
)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
__all__.append('Diagram')
[docs]class Diagram(LineDiversion): #c0 ||:cls:||
r"""
.. \|:here:|
"""
opt_show_bases = True
opt_ignore_bases = IGNORE_BASES
kw_map = dict(( #c0
(':;' , ('', '') ),
(':|' , ('', '') ),
(':<' , ('', '') ),
(':>' , ('', '') ),
(':/' , ('', '') ),
(':]' , ('', '') ),
(':}' , ('', '') ),
(':' , ('', '') ),
('-' , ('', '') ),
('.' , ('', '') ),
(';' , ('', '') ),
('|' , ('', '') ),
('<' , ('', '') ),
('>' , ('', '') ),
('/' , ('', '') ),
(']' , ('', '') ),
('}' , ('', '') ),
('class' , ('class', ' "') ),
('def' , ('', '') ),
('done' , ('endwhile', ' ')),
('elif' , ('elseif', ' (') ),
('else' , ('else', ' ') ),
('elseif', ('elseif', ' (') ),
('elsif' , ('elseif', ' (') ),
('fi' , ('endif', ' ') ),
('for' , ('while', ' (for ') ),
('if' , ('if', ' (') ),
('while' , ('while', ' (') ),
('break' , ('break', ' ') ),
))
kw_cont_map = dict(( #c0
(':;' , ('', '') ),
(':|' , ('', '') ),
(':<' , ('', '') ),
(':>' , ('', '') ),
(':/' , ('', '') ),
(':]' , ('', '') ),
(':}' , ('', '') ),
(':' , ('', '') ),
('-' , ('', '') ),
('.' , ('', '') ),
(';' , ('', '') ),
('|' , ('', '') ),
('<' , ('', '') ),
('>' , ('', '') ),
('/' , ('', '') ),
(']' , ('', '') ),
('}' , ('', '') ),
('class' , ('', '" {') ),
('def' , ('', '') ),
('done' , ('', '') ),
('elif' , (') then', '')),
('elseif', (') then', '')),
('elsif' , (') then', '')),
('for' , (')', '') ),
('if' , (') then', '')),
('while' , (')', '') ),
('break' , ('', '') ),
))
header = ''.join(( #c0
DIAGRAM_HEADER,
'''
''')).strip()
footer = ''.join(( #c0
DIAGRAM_FOOTER,
'''
''')).strip()
in_partition = False #c0
partition_format = 'partition "{0}" {1} {{' #c0
association = [] #c0
inheritance = [] #c0
def __init__(self, *args, **kwargs): # |:mth:|
super(Diagram, self).__init__(*args, **kwargs)
self.associations = []
self.inheritance = []
[docs] def open_partition(self, text): #c0 |:mth:|
r"""
:returns: self for chaining.
"""
super(Diagram, self).open_partition(text)
text = text.strip()
color = ''
_mo = re.search('(.*)(#[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]([0-9a-f][0-9a-f])?)(?i)', text)
if _mo:
text = _mo.group(1).strip()
color = _mo.group(2)
self.append(sformat(self.partition_format, text, color))
self.in_partition = True
return self
[docs] def close_partition(self): #c0 |:mth:|
r"""
:returns: self for chaining.
"""
super(Diagram, self).close_partition()
if self.inheritance:
self.extend((' '.join(_i) for _i in self.inheritance))
del(self.inheritance[:])
if self.in_partition:
self.append('}')
self.in_partition = False
return self
[docs] def process_parts(self, part_map): # |:mth:| #c0
r"""
:returns: new/altered part_map.
>>> check_def = 'SomeClass ( with,multiple, inheritance )'
>>> mo = re.match(CLASS_DEF_RX, check_def)
>>> if mo: printf(sformat("{0}//{1}//", mo.groups(), check_def[mo.end(0):]))
('SomeClass', 'with,multiple, inheritance ')////
>>> class Check():
... pass
>>> check_def = 'SomeClass ()'
>>> mo = re.match(CLASS_DEF_RX, check_def)
>>> if mo: printf(sformat("{0}//{1}//", mo.groups(), check_def[mo.end(0):]))
('SomeClass', '')////
>>> check_def = 'SomeClass'
>>> mo = re.match(CLASS_DEF_RX, check_def)
>>> if mo: printf(sformat("{0}//{1}//", mo.groups(), check_def[mo.end(0):]))
('SomeClass', None)////
"""
if part_map.get('mapped_kw') == 'class':
class_def = part_map.get('cond')
mo = re.match(CLASS_DEF_RX, class_def)
if mo:
name = mo.group(1)
if self.opt_show_bases:
bases = (mo.group(2) or '').strip().replace(' ', '').split(',')
self.inheritance.extend(((_b, '<|--', name) for _b in bases if _b and _b not in self.opt_ignore_bases))
else:
name = class_def
cond = []
text = TAG_RX.sub('', part_map.get('text') or '')
part_map['text'] = ''
mo = re.search('"[^"]+"', text)
if mo:
_pre = text[:mo.start(0)].strip()
_post = text[mo.end(0):].strip()
cond.extend((mo.group(0), 'as', name, _pre, _post))
else:
cond.extend((name, text))
part_map['cond'] = ' '.join((_p for _p in cond if _p))
part_map['kw_sep'] = ' '
part_map['kw_cont_sep'] = ' {'
elif part_map.get('kw') == 'def':
_text_list = []
_condr = part_map.get('condr')
_mo = re.match('([^#]*)#+(.*)', _condr)
if _mo:
_condr = _mo.group(1).strip()
part_map['condr'] = _condr
_text_list.append(_mo.group(2).strip())
_text = ' '.join((_t for _t in (_text_list[0], part_map.get('text')) if _t))
part_map['text'] = _text
# - remove trailing colon, semicolon
_cond = re.sub('\\s*[:;]$', '', _condr)
part_map['cond'] = _cond
# |||:here:||||:todo:| more intelligent attribute handling
return part_map
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
__all__.append('DiagramStructure')
[docs]class DiagramStructure(Diagram): #c0 ||:cls:||
r"""LineDiversion for Structure Diagram.
.. \|:here:|
"""
header = ''.join(( #c0
Diagram.header,
'''
''')).strip()
footer = ''.join(( #c0
Diagram.footer,
'''
''')).strip()
def __init__(self, *args, **kwargs): # |:mth:|
super(DiagramStructure, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
__all__.append('DiagramClass')
[docs]class DiagramClass(DiagramStructure): #c0 ||:cls:||
r"""LineDiversion for Class Diagram.
.. \|:here:|
"""
type = 'c' #c0 c
header = ''.join(( #c0
DiagramStructure.header,
'''
''')).strip()
footer = ''.join(( #c0
DiagramStructure.footer,
'''
''')).strip()
partition_format = 'frame "{0}" {1} {{' #c0
def __init__(self, *args, **kwargs): # |:mth:|
super(DiagramClass, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
__all__.append('DiagramObject')
[docs]class DiagramObject(DiagramStructure): #c0 ||:cls:||
r"""LineDiversion for Object Diagram.
.. \|:here:|
"""
type = 'o' #c0
header = ''.join((
DiagramStructure.header,
'''
''')).strip()
footer = ''.join((
DiagramStructure.footer,
'''
''')).strip()
def __init__(self, *args, **kwargs): # |:mth:|
super(DiagramObject, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
__all__.append('DiagramComponent')
[docs]class DiagramComponent(DiagramStructure): #c0 ||:cls:||
r"""LineDiversion for Component Diagram.
.. \|:here:|
"""
type = 'p' #c0
header = ''.join((
DiagramStructure.header,
'''
''')).strip()
footer = ''.join((
DiagramStructure.footer,
'''
''')).strip()
def __init__(self, *args, **kwargs): # |:mth:|
super(DiagramComponent, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
__all__.append('DiagramDeployment')
[docs]class DiagramDeployment(DiagramStructure): #c0 ||:cls:||
r"""LineDiversion for Deployment Diagram.
.. \|:here:|
"""
type = 'd' #c0
header = ''.join((
DiagramStructure.header,
'''
''')).strip()
footer = ''.join((
DiagramStructure.footer,
'''
''')).strip()
def __init__(self, *args, **kwargs): # |:mth:|
super(DiagramDeployment, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
__all__.append('DiagramBehavior')
[docs]class DiagramBehavior(Diagram): #c0 ||:cls:||
r"""LineDiversion for Behavior Diagram.
.. \|:here:|
"""
header = ''.join((
Diagram.header,
'''
''')).strip()
footer = ''.join((
Diagram.footer,
'''
''')).strip()
def __init__(self, *args, **kwargs): # |:mth:|
super(DiagramBehavior, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
__all__.append('DiagramUseCase')
[docs]class DiagramUseCase(DiagramBehavior): #c0 ||:cls:||
r"""LineDiversion for Use Case Diagram.
.. \|:here:|
"""
type = 'u' #c0
header = ''.join((
DiagramBehavior.header,
'''
''')).strip()
footer = ''.join((
DiagramBehavior.footer,
'''
''')).strip()
def __init__(self, *args, **kwargs): # |:mth:|
super(DiagramUseCase, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
__all__.append('DiagramActivity')
[docs]class DiagramActivity(DiagramBehavior): #c0 ||:cls:||
r"""LineDiversion for Activity Diagram.
.. \|:here:|
"""
type = 'a' #c0
kw_map = dict((
(':;', (':', '')),
(':|', (':', '')),
(':<', (':', '')),
(':>', (':', '')),
(':/', (':', '')),
(':]', (':', '')),
(':}', (':', '')),
(':' , (':', '')),
('-' , ('', '') ),
('.' , ('', '') ),
(';' , ('', '') ),
('|' , ('', '') ),
('<' , ('', '') ),
('>' , ('', '') ),
('/' , ('', '') ),
(']' , ('', '') ),
('}' , ('', '') ),
))
kw_cont_map = dict((
(':;', (';', '')),
(':|', ('|', '')),
(':<', ('<', '')),
(':>', ('>', '')),
(':/', ('/', '')),
(':]', (']', '')),
(':}', ('}', '')),
(':' , ('', '') ),
('-' , ('', '') ),
('.' , ('', '') ),
(';' , (';', '')),
('|' , ('|', '')),
('<' , ('<', '')),
('>' , ('>', '')),
('/' , ('/', '')),
(']' , (']', '')),
('}' , ('}', '')),
))
header = ''.join((
DiagramBehavior.header,
'''
''')).strip()
footer = ''.join((
DiagramBehavior.footer,
'''
''')).strip()
def __init__(self, *args, **kwargs): # |:mth:|
super(DiagramActivity, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
__all__.append('DiagramStateMachine')
[docs]class DiagramStateMachine(DiagramBehavior): #c0 ||:cls:||
r"""LineDiversion for State Machine Diagram.
.. \|:here:|
"""
type = 's' #c0
header = ''.join((
DiagramBehavior.header,
'''
''')).strip()
footer = ''.join((
DiagramBehavior.footer,
'''
''')).strip()
def __init__(self, *args, **kwargs): # |:mth:|
super(DiagramStateMachine, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
__all__.append('DiagramInteraction')
[docs]class DiagramInteraction(DiagramBehavior): #c0 ||:cls:||
r"""LineDiversion for Interaction Diagram.
.. \|:here:|
"""
header = ''.join((
DiagramBehavior.header,
'''
''')).strip()
footer = ''.join((
DiagramBehavior.footer,
'''
''')).strip()
def __init__(self, *args, **kwargs): # |:mth:|
super(DiagramInteraction, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
__all__.append('DiagramMessageSequence')
[docs]class DiagramMessageSequence(DiagramInteraction): #c0 ||:cls:||
r"""LineDiversion for Message Sequence Diagram.
.. \|:here:|
"""
type = 'm' #c0
header = ''.join((
DiagramInteraction.header,
'''
''')).strip()
footer = ''.join((
DiagramInteraction.footer,
'''
''')).strip()
def __init__(self, *args, **kwargs): # |:mth:|
super(DiagramMessageSequence, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
__all__.append('DiagramTiming')
[docs]class DiagramTiming(DiagramInteraction): #c0 ||:cls:||
r"""LineDiversion for Timing Diagram.
.. \|:here:|
"""
type = 't' #c0
header = ''.join((
DiagramInteraction.header,
'''
''')).strip()
footer = ''.join((
DiagramInteraction.footer,
'''
''')).strip()
def __init__(self, *args, **kwargs): # |:mth:|
super(DiagramTiming, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
DIAGRAMS = dict(
((_obj.type, _obj)
for _name, _obj in ditems(globals())
if _name.startswith('Diagram')
and getattr(_obj, 'type', None)
))
# printe=printf
# printe(sformat("# "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "DIAGRAMS", (DIAGRAMS)))
# exit(0)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.class" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# --------------------------------------------------
# |||:sec:||| REGULAR EXPRESSIONS (SNIAP)
# --------------------------------------------------
# (progn (forward-line 1) (snip-insert "py_snip.rx" t t "py") (insert "\n"))
# All snippet tags
SNIAP_RX='\\|\\|<-sn([ia])p->\\|\\|'
# Command tags at beginning of line preceeded at most by one word
SNIAP_PFX_RX='^(([^ @][^ ]*|@:[^ ]*|\\.\\. \\\\)[ ]*|)' + SNIAP_RX
# Command tags at beginning of line preceeded at most by one word,
# which cannot begin with an alpha-numeric character
SNIAP_PFX_RX1='^(([^ @0-9A-Za-z][^ ]*|@:[^ ]*|\\.\\. \\\\)[ ]*|)' + SNIAP_RX
# The regular expression used on 2012-01-11 03:11:54 (which may have
# changed since then). This Regexp is automatically generated from all
# defined comment start skips.
# Perl: '//+|/\*+|;+|\.\. |\.\. \\|\@:[bl]?comm_?\@|--|<!--|#+|\@[bl]?comm_?\@'
SNIAP_PFX_RXX='^((//+|/\\*+|;+|\\.\\. |\\.\\. \\\\|@:[bl]?comm_?@|--|<!--|#+|@[bl]?comm_?@) *|)' + SNIAP_RX
# Catch indented command tags (especially for beg/end tags, but --no-indent is better in this case)
SNIAP_PFX_RXI='^(([ ]*[^ ]*|\\.\\. \\\\)[ ]*|)' + SNIAP_RX
# Snippet command and arguments (remove comment end before matching
# for arguments)
SNIP_CMD_RX=' *([A-Za-z_][-0-9A-Za-z_]*) *(.*)'
# --------------------------------------------------
# |||:sec:||| REGULAR EXPRESSIONS
# --------------------------------------------------
# Generic comment end with PUML and HTML comments
COMMENT_RX ='(?://+|/[*\']+|;+|@:u?[bl]?comm_?@|--|<!--|#+|@[bl]?comm_?@|\\.\\. |\\.\\. \\\\)'
COMMENT_TYPE_RX='(?://+|/[*\']+|;+|@:u?[bl]?comm_?@|--|<!--|#+|@[bl]?comm_?@|[.][.])'
COMMENT_END_RX_='@:(((_|)(b|)comm)|((b|)comme))@|[*\']/|-->|`'
# Generic comment end with HTML comments
COMMENT_RX ='(?://+|/\\*+|;+|@:u?[bl]?comm_?@|--|<!--|#+|@[bl]?comm_?@|\\.\\. |\\.\\. \\\\)'
COMMENT_TYPE_RX='(?://+|/\\*+|;+|@:u?[bl]?comm_?@|--|<!--|#+|@[bl]?comm_?@|[.][.])'
COMMENT_END_RX_='@:(((_|)(b|)comm)|((b|)comme))@|[*]/|-->|`'
# generic comment RXs with PUML, w/o HTML comments
COMMENT_RX ='(?://+|/[*\']+|;+|@:u?[bl]?comm_?@|--|#+|@[bl]?comm_?@|\\.\\. |\\.\\. \\\\)'
COMMENT_TYPE_RX='(?://+|/[*\']+|;+|@:u?[bl]?comm_?@|--|#+|@[bl]?comm_?@|[.][.])'
COMMENT_END_RX_='@:(((_|)(b|)comm)|((b|)comme))@|[*\']/|`'
# generic comment RXs w/o PUML and HTML comments
# since a HTML comment end is also a valid association `-->`. Diagrams
# embedded in HTML documents can also be annotated with a hash `#`
# comment start.
COMMENT_RX ='(?://+|/\\*+|;+|@:u?[bl]?comm_?@|--|#+|@[bl]?comm_?@|\\.\\. |\\.\\. \\\\)'
COMMENT_TYPE_RX='(?://+|/\\*+|;+|@:u?[bl]?comm_?@|--|#+|@[bl]?comm_?@|[.][.])'
COMMENT_END_RX_='@:(((_|)(b|)comm)|((b|)comme))@|[*]/|`'
COMMENT_END_RX=re.compile("\\s*" + COMMENT_END_RX_ + "\\s*$")
COMMENT_TRAIL_RX = re.compile(COMMENT_TYPE_RX + '+$')
SYMBOL_RX = '[A-Za-z_][0-9A-Za-z_]*'
XSYMBOL_RX = '[-A-Za-z_][-0-9A-Za-z_]*'
DOT_SYMBOL_RX = '[A-Za-z_][0-9A-Za-z_.]*'
SECTION_RX = re.compile('(\\s*)\|\|*:sec:\|\|*\\s*')
TAG_RX = re.compile('\\s*\|\|*:[^:]*:\|\|*\\s*')
DIAGRAM_TYPE_RX = '[copduasmt]'
OPT_TRAILER_RX = '(?:\\s(.*)|\\s*)$'
OPT_TRAILER_TAG_RX = '(?:' + TAG_RX.pattern + ')*$'
CLASS_DEF_RX = '(' + SYMBOL_RX + ')\\s*(?:[(]\\s*(?:(' + SYMBOL_RX + ')\\s*(?:,\\s*(' + SYMBOL_RX + ')\\s*)*)?[)])?'
CLASS_DEF_RX = '(' + SYMBOL_RX + ')\\s*(?:[(]\\s*((?:' + DOT_SYMBOL_RX + '|[,]|\\s)*)[)])?'
REST_COMMENT_START_RX = re.compile('^\\s*[.][.]\\s?')
REST_INLINE_COMMENT_RX = re.compile(':rem:`([^`]*)`')
# --------------------------------------------------
# |||:sec:||| LINE PARSERS
# --------------------------------------------------
from pyjsmo.translate import trans_re_flags
from pyjsmo.translate import trans_rx_repr
STD_GROUPS = pyjsmo.OrderedDict((
(_k, None) for _k in (
'whitespace',
'id',
'text',
'keyword',
'condition',)
))
__all__.append('LineParser')
[docs]class LineParser(pyjsmo.PyJsMo): #c0 ||:cls:||
r"""
>>> lp = LineParser()
>>> printf(lp)
{
"rx": [
null,
"0"
],
"groups": {
"whitespace": null,
"id": null,
"text": null,
"keyword": null,
"condition": null
}
}
>>> printf(lp._pyjsmo_x_rx)
None
>>> lp.rx = re.compile('some', re.I | re.M | re.U)
>>> printf(lp)
{
"rx": [
"some",
"re.IGNORECASE|re.MULTILINE|re.UNICODE"
],
"groups": {
"whitespace": null,
"id": null,
"text": null,
"keyword": null,
"condition": null
}
}
>>> printf(trans_rx_repr(lp._pyjsmo_x_rx)) #doctest: +ELLIPSIS
re.compile('some', re.IGNORECASE|re.MULTILINE|re.UNICODE)
>>> lp.rx = ("some where", "re.IGNORECASE|re.UNICODE")
>>> printf(lp)
{
"rx": [
"some where",
"re.IGNORECASE|re.UNICODE"
],
"groups": {
"whitespace": null,
"id": null,
"text": null,
"keyword": null,
"condition": null
}
}
>>> printf(trans_rx_repr(lp._pyjsmo_x_rx)) #doctest: +ELLIPSIS
re.compile('some where', re.IGNORECASE|re.UNICODE)
"""
_pyjsmo_versions = [
(1, {'bases': [0],
'order': [
'rx', #c0
'groups', #c0
],
'defaults': pyjsmo.OrderedDict((
('rx', None),
('groups', None),
)),
'amap': [],
'expand': None,
}),
]
def __init__(self, *args, **kwargs): # |:mth:|
super(LineParser, self).__init__(*args, **kwargs)
if self.groups is None:
self.groups = pyjsmo.OrderedDict(STD_GROUPS)
# http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/
_pyjsmo_x_rx = None
def _get_rx(self): # |:mth:|
r"""Programmatic property."""
value = self._pyjsmo_x_rx
return (
getattr(value, 'pattern', value),
trans_re_flags(getattr(value, 'flags', None))
)
def _set_rx(self, value): # |:mth:|
flags = None
if issequence(value):
flags = value[1]
if isstring(flags):
flags = eval(flags)
value = value[0]
if isstring(value):
value = re.compile(value, flags)
self._pyjsmo_x_rx = value
rx = property(_get_rx, _set_rx, None, _get_rx.__doc__)
[docs] def init(self, rx, groups): #c0 |:mth:|
r"""
:returns: self for chaining.
"""
self.rx = rx
_groups = pyjsmo.OrderedDict(STD_GROUPS)
if groups:
_groups.update(groups)
self.groups = _groups
return self
[docs] def match(self, line): #c0 |:mth:|
r"""Match against line.
:returns: match object or None.
"""
rx = self._pyjsmo_x_rx
if not rx:
return None
mo = rx.search(line)
if mo:
id_ = mo.group(self.groups['id'])
else:
id_ = None
return mo, id_
[docs] def split_(self, line, mo, diagram): # |:mth:|
r"""
:returns: part map
"""
# |:sec:| Split Line Into Parts #a4
# start #a4
# * split line into parts #a4 :
# indent, text, keyword, condition, rest
indent = line[:mo.end(self.groups.get('whitespace'))]
_gtext = self.groups.get('text')
text = COMMENT_TRAIL_RX.sub(
'', ((_gtext and mo.group(_gtext)) or '')).strip()
_gkeyword = self.groups.get('keyword')
kw = ((_gkeyword and mo.group(_gkeyword)) or '').strip()
_gcond_pfx = self.groups.get('cond_pfx')
cond_pfx = ((_gcond_pfx and mo.group(_gcond_pfx)) or '').strip()
_gcondition = self.groups.get('condition')
cond = condr = COMMENT_TRAIL_RX.sub(
'', ((_gcondition and mo.group(_gcondition)) or '')).rstrip()
_gsformat = self.groups.get('sformat')
sformat_ = ((_gsformat and mo.group(_gsformat)) or '').strip()
if sformat_:
_fmt = []
_rest = sformat_
while True:
if _rest:
_delimiter = DELIMITERS.get(_rest[0])
if _delimiter:
_rest = _rest[1:]
else:
break
_pos = _rest.find(_delimiter)
if _pos >= 0:
_fmt.append(_rest[:_pos])
_rest = _rest[_pos+1:]
continue
_fmt.append(_rest)
break
_fmt = ''.join(_fmt)
_fmt = re.sub('^\\s*#\\s*', '', _fmt)
_rest = re.sub('^\\s*,\\s*', '', _rest)
_args = [re.sub('^\\s*([\'"])(.*)\\1\\s*$', '\\2', _a) for _a in trans_list_comma(_rest)]
_args.extend(('' for _i in xrange(20)))
sformat_ = sformat(_fmt, *_args)
if kw:
cond = sformat_
sformat_ = ''
# remove tags from action header
cond = TAG_RX.sub('', cond)
cond = cond.rstrip()
rest = line[mo.end(0):]
# * identify condition parts #a4 -
mapped_kw, kw_sep = diagram.kw_map.get(
kw, KW_PLANT_MAP.get(kw, (kw, ' ')))
mapped_kw_cont, kw_cont_sep = diagram.kw_cont_map.get(
kw, KW_PLANT_CONT_MAP.get(kw, ('', '')))
# - remove trailing colon, semicolon #a4 -
# - remove paired parentheses #a4 ;
if cond:
cond = re.sub('\\s*[:;]$', '', cond)
cond = re.sub('^(\\s*)[(](.*)[)]\\s*$', '\\1\\2', cond)
_loc = locals()
part_map = pyjsmo.OrderedDict(zip(DIAGRAM_LINE_PARTS, (_loc.get(_p.replace('sformat', 'sformat_')) for _p in DIAGRAM_LINE_PARTS)))
if _debug:
printe("# --------------------------------------------------")
printe(sformat("# "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "rx", (self.rx)))
printe(sformat("# "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "line", (line)))
printe(sformat("# "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "mo.groups", (mo.groups())))
printe(sformat("# "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "part_map", list(ditems(part_map))))
return part_map
[docs] def split(self, line, mo, diagram): #c0 |:mth:|
r"""
:returns: part map
- indent
- text
- kw
- cond_pfx
- condr
- rest
- mapped_kw
- kw_sep
- cond
- kw_cont_sep
- mapped_kw_cont
"""
part_map = self.split_(line, mo, diagram)
# * call `process_parts` method of `Diagram` #a4 :|
part_map = diagram.process_parts(part_map)
# stop #a4
return part_map
[docs] def assemble(self, part_map, diagram): #c0 |:mth:|
r"""
:returns: assembled line.
"""
# |:sec:| Assemble Line Parts #a5
# start #a5
# * assemble condition #a5 :
_cond_parts = []
_cond_pfx = part_map.get('cond_pfx') or ''
if _cond_pfx:
_cond_parts.append(_cond_pfx)
_mapped_kw = part_map.get('mapped_kw') or ''
if _mapped_kw:
_cond_parts.append(_mapped_kw)
_cond_parts.append(part_map.get('kw_sep') or '')
_cond = part_map.get('cond') or ''
if _cond:
_cond_parts.append(_cond)
_cond_parts.append(part_map.get('kw_cont_sep') or '')
_cond_parts.append(part_map.get('mapped_kw_cont') or '')
_cond_text = ''.join(_cond_parts)
# * assemble all parts of line #a5 ;
_parts = [
part_map.get('indent') or '',
_cond_text
]
text = part_map.get('text') or ''
if text and _cond_text:
_parts.append(' ')
_parts.append(text)
sformat_ = part_map.get('sformat') or ''
if sformat_ and (text or _cond_text):
_parts.append(' ')
_parts.append(sformat_)
_parts.append(part_map.get('rest') or '')
if _debug:
printe(sformat("# "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "cond_parts", (_cond_parts)))
printe(sformat("# "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "parts", (_parts)))
line = ''.join(_parts)
# stop #a5
return line
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# } #c0
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.class" t t "py") (backward-symbol-tag 1 "fillme" "::"))
LINE_PARSERS = []
PREFIX_RX = re.compile('^(\\s*)' + COMMENT_TYPE_RX + '(' + DIAGRAM_TYPE_RX + '[0-9]+)(?:\\s|$)')
PREFIX_LP = LineParser().init(
PREFIX_RX,
(('whitespace', 1 ),
('id' , 2 ),
('text' , None),
('keyword' , None),
('condition' , None),
))
LINE_PARSERS.append(PREFIX_LP)
SUFFIX_RX = re.compile('^(\\s*)' + COMMENT_TYPE_RX + ' (.*)\\s*' + COMMENT_TYPE_RX + '(' + DIAGRAM_TYPE_RX + '[0-9]+)' + OPT_TRAILER_TAG_RX)
SUFFIX_LP = LineParser().init(
SUFFIX_RX,
(('whitespace', 1 ),
('id' , 3 ),
('text' , 2 ),
('keyword' , None),
('condition' , None),
))
LINE_PARSERS.append(SUFFIX_LP)
KW_PLANT_MAP = Diagram.kw_map
KW_PLANT_CONT_MAP = Diagram.kw_cont_map
#printf(pyjsmo.formatv.tuple_def(sorted(ditems(KW_PLANT_MAP))))
#printf()
#printf(pyjsmo.formatv.tuple_def(sorted(ditems(KW_PLANT_CONT_MAP))))
KEYWORDS = [_k for _k in sorted(dkeys(KW_PLANT_MAP)) if re.match('[a-z}](?i)', _k)]
KEYWORDS_RX = '|'.join((re.escape(_k) for _k in KEYWORDS))
ACTION_RX = '(:[];|<>/}]?|[];|<>/}.-])'
# printe(sformat("# ||"":sec:|| some section header{0}", "")) #a1
PRINTE_SFORMAT_RX = re.compile("^(\\s*)printe\\s*[(]\\s*sformat\\s*[(]\\s*(.*)\\s*(?:[)][)]|,)\\s*" + COMMENT_TYPE_RX + '(' + DIAGRAM_TYPE_RX + '[0-9]+)\\s*' + ACTION_RX + '?' + OPT_TRAILER_RX)
PRINTE_SFORMAT_LP = LineParser().init(
PRINTE_SFORMAT_RX,
(('whitespace', 1 ),
('sformat' , 2 ),
('id' , 3 ),
('keyword' , 4 ),
('condition' , None),
))
LINE_PARSERS.append(PRINTE_SFORMAT_LP)
COND_RX = re.compile('^(\\s*)(' + KEYWORDS_RX + ')(?::?|\\s)\\s*(.*)\\s*' + COMMENT_TYPE_RX + '(' + DIAGRAM_TYPE_RX + '[0-9]+)' + OPT_TRAILER_RX)
COND_LP = LineParser().init(
COND_RX,
(('whitespace', 1),
('id' , 4),
('text' , 5),
('keyword' , 2),
('condition' , 3),
))
LINE_PARSERS.append(COND_LP)
ACT_RX = re.compile('^(\\s*)(?:' + COMMENT_TYPE_RX + ' )?(.*)\\s*' + COMMENT_TYPE_RX + '(' + DIAGRAM_TYPE_RX + '[0-9]+) ' + ACTION_RX + '\\s*(?:(#[0-9A-Za-z]+|backwards)(?:\\s+|$))?' + OPT_TRAILER_RX)
ACT_LP = LineParser().init(
ACT_RX,
(('whitespace', 1),
('id' , 3),
('text' , 6),
('cond_pfx' , 5),
('keyword' , 4),
('condition' , 2),
))
LINE_PARSERS.append(ACT_LP)
ATTRIB_RX = re.compile('^(\\s*)(' + SYMBOL_RX + ')\\s*=\\s*(.*)\\s*' + COMMENT_TYPE_RX + '(' + DIAGRAM_TYPE_RX + '[0-9]+)' + OPT_TRAILER_RX)
ATTRIB_LP = LineParser().init(
ATTRIB_RX,
(('whitespace', 1 ),
('id' , 4 ),
('text' , 2 ),
('keyword' , None),
('condition' , None),
))
LINE_PARSERS.append(ATTRIB_LP)
PYJSMO_ATTRIB_RX = re.compile("^(\\s*)['](" + SYMBOL_RX + ")['],?"'\\s*' + COMMENT_TYPE_RX + '(' + DIAGRAM_TYPE_RX + '[0-9]+)' + OPT_TRAILER_RX)
PYJSMO_ATTRIB_LP = LineParser().init(
PYJSMO_ATTRIB_RX,
(('whitespace', 1 ),
('id' , 3 ),
('text' , 2 ),
('keyword' , None),
('condition' , None),
))
LINE_PARSERS.append(PYJSMO_ATTRIB_LP)
# --------------------------------------------------
# |||:sec:||| FUNCTIONS
# --------------------------------------------------
__all__.append('check_line_parse')
[docs]def check_line_parse(*exprs): # ||:fnc:||
r"""
:returns:
prints
>>> check_line_parse('# s/^+//''p') #doctest: +ELLIPSIS
# --------------------------------------------------
# ||:exp:|| # s/^+//p
# --------------------------------------------------
# :DBG: ACT_LP : ]--[ ]()[
# :DBG: ATTRIB_LP : ]--[ ]()[
# :DBG: COND_LP : ]--[ ]()[
# :DBG: PREFIX_LP : ]--[ ]()[
# :DBG: PRINTE_SFORMAT_LP: ]--[ ]()[
# :DBG: PYJSMO_ATTRIB_LP : ]--[ ]()[
# :DBG: SUFFIX_LP : ]--[ ]()[
>>> check_line_parse('# start #''a99') #doctest: +ELLIPSIS
# --------------------------------------------------
# ||:exp:|| # start #a...99
# --------------------------------------------------
# :DBG: ACT_LP : ]--[ ]()[
# :DBG: ATTRIB_LP : ]--[ ]()[
# :DBG: COND_LP : ]--[ ]()[
# :DBG: PREFIX_LP : ]--[ ]()[
# :DBG: PRINTE_SFORMAT_LP: ]--[ ]()[
# :DBG: PYJSMO_ATTRIB_LP : ]--[ ]()[
# :DBG: SUFFIX_LP : ]a99[ ]('', 'start ', 'a99')[
>>> check_line_parse('.. start ..''a99') #doctest: +ELLIPSIS
# --------------------------------------------------
# ||:exp:|| .. start ..a...99
# --------------------------------------------------
# :DBG: ACT_LP : ]--[ ]()[
# :DBG: ATTRIB_LP : ]--[ ]()[
# :DBG: COND_LP : ]--[ ]()[
# :DBG: PREFIX_LP : ]--[ ]()[
# :DBG: PRINTE_SFORMAT_LP: ]--[ ]()[
# :DBG: PYJSMO_ATTRIB_LP : ]--[ ]()[
# :DBG: SUFFIX_LP : ]a99[ ]('', 'start ', 'a99')[
>>> check_line_parse('start #''a99') #doctest: +ELLIPSIS
# --------------------------------------------------
# ||:exp:|| start #a...99
# --------------------------------------------------
# :DBG: ACT_LP : ]--[ ]()[
# :DBG: ATTRIB_LP : ]--[ ]()[
# :DBG: COND_LP : ]--[ ]()[
# :DBG: PREFIX_LP : ]--[ ]()[
# :DBG: PRINTE_SFORMAT_LP: ]--[ ]()[
# :DBG: PYJSMO_ATTRIB_LP : ]--[ ]()[
# :DBG: SUFFIX_LP : ]--[ ]()[
"""
_line_parsers = []
for _name, _obj in sorted(ditems(globals())):
if isinstance(_obj, LineParser):
_line_parsers.append((_name, _obj))
dbg_fwid = 17
for _expr in exprs:
printf("# --------------------------------------------------")
printf(sformat("# ||"":exp:|| {0}", _expr))
printf("# --------------------------------------------------")
for _name, _lp in _line_parsers:
mo, _id = _lp.match(_expr)
if mo:
_groups = mo.groups()
else:
_groups = ()
_id = '--'
printf(sformat("# "":DBG: {1:<{0}s}: ]{2!s}[ ]{3!s}[", dbg_fwid, _name, _id, _groups))
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.func" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line 1) (snip-insert "py_wsrfid.customization" t t "python" " --key cust_delayed_skipx") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_b.dba_setup_sql" t t "python") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_b.dba_id_maps" t t "python") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_b.dba_commands_init" t t "python") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.wsrfid.module.route" t t "py") (insert ""))
# --------------------------------------------------
# |||:sec:||| UTILITIES
# --------------------------------------------------
# (progn (forward-line 1) (snip-insert "py.wsrfid.dispatch.request" t t "py") (insert ""))
# (progn (forward-line 1) (snip-insert "py.f.findfile" t t "py") (insert ""))
# (progn (forward-line 1) (snip-insert "py_f.add_prefix_indent" t t "python") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.c.placeholder.template" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.c.key.hash.ordered.dict" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.c.progress" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.hl" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.single.quote" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.remove.match" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.printenv" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.uname.s" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_f.decoded_email_headers" t t "python") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_f.print_utf8" t t "python") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.printe" t t "py") (insert ""))
def printe_(*args, **kwargs):
kwargs['file'] = kwargs.get('file', sys.stderr)
printf(*args, **kwargs)
if 'printe' not in globals(): # or globals().get('_is_main_', (__name__ == '__main__')):
printe = printe_
printd = printe_
printw = printe_
printx = printe_
# (progn (forward-line 1) (snip-insert "py.f.dbg.squeeze" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.dbg.indent" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.quick.dump" t t "python") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_b.all.reverse" t t "python") (insert "\n"))
if '__all_internal__' in globals():
import sys
if 'sphinx.directives' in sys.modules:
__all__[:0] = __all_internal__
__all_internal__ = list(reversed(__all_internal__))
__all__ = list(reversed(__all__))
def run(parameters): # ||:fnc:||
"""Application runner, when called as __main__."""
# (progn (forward-line 1) (snip-insert "py.bf.sql.ws" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.bf.file.arg.loop" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.wsrfid.wsuvv.run" t t "py" " --key py_wsrfid.wsuvv_run --key skip_for_new") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_shell.run" t t "python") (insert "\n"))
# from pyjsmo.result import Result, IResult, ERR_NONE
result = IResult()
opt_match = parameters.match
opt_file_base = parameters.file_base
opt_replace = getattr(parameters, 'replace', None)
opt_verbatim = getattr(parameters, 'verbatim', None)
for _rep in (opt_replace or []):
_sym, _val = _rep.split(None, 1)
REPLACEMENTS[_sym] = _val
if opt_match:
opt_match_rx = re.compile(opt_match)
else:
opt_match_rx = None
Diagram.opt_show_bases = parameters.show_bases
if parameters.ignore_bases:
Diagram.opt_ignore_bases = list(Diagram.opt_ignore_bases)
Diagram.opt_ignore_bases.extend(parameters.ignore_bases)
# |:here:|
error = ERR_NONE
# |:todo:| class LineDiversionParser
diagrams = pyjsmo.OrderedDict()
# read from standard input, #a2 :
# if no arguments are given #a2 ;
if not parameters.args:
parameters.args.append('-')
for _file in parameters.args:
# setup replacement for @filepath@, @filedir@, @filename@
_filename = _file
if _filename == '-':
_filename = '{stdin}'
_filepath = _filename
else:
_filepath = os.path.abspath(_filename)
_filedir = os.path.dirname(_filepath)
_filebase = os.path.basename(_filepath)
REPLACEMENTS_STD['@filepath@'] = _filepath
REPLACEMENTS_STD['@filedir@'] = _filedir
REPLACEMENTS_STD['@filename@'] = _filebase
# get file contents #a2 :;
result.get_file_contents(_file)
if result.error > ERR_NONE: #a2 (yes)
error = result.error
result.error = ERR_NONE
continue
# else #a2
lines = result.output.splitlines()
cur_id = None
cur_diagram = Diagram()
# while (for each line) is (do) #a2
for _indx, _line in enumerate(lines):
# |:todo:| move to Diagram.process_line()
# * convert :rem: docstring comment #a2 :
# to regular comment #a2 .
if REST_INLINE_COMMENT_RX.search(_line):
_line = '# ' + REST_INLINE_COMMENT_RX.sub(
'#\\1', REST_COMMENT_START_RX.sub('', _line))
# * remove closing comment #a2 .
# at end of line #a2 ;
_line = COMMENT_END_RX.sub('', _line)
# perform registered replacements #a2 :;
for _sym, _val in ditems(REPLACEMENTS):
_line = _line.replace(_sym, _val)
# perform standard replacements #a2 :;
if not opt_verbatim:
for _sym, _val in ditems(REPLACEMENTS_STD):
_line = _line.replace(_sym, _val)
# while (for each registered line parser) is (do) #a2
for _lp in LINE_PARSERS:
# get match object and diagram ID #a2 :
# from LineParser.match() #a2 ;
# note right #a2
# the first matching LineParser is used: #a2
# * PREFIX_LP #a2
# * SUFFIX_LP #a2
# * COND_LP #a2
# * ACT_LP #a2
# * ATTRIB_LP #a2
# * PYJSMO_ATTRIB_LP #a2
# * PRINTE_SFORMAT_LP #a2
# end note #a2
# if (match found?) then (yes) #a2
mo, _id = _lp.match(_line)
if mo:
# if (ID satisfies `--match`) then (yes) #a2
if opt_match_rx and not opt_match_rx.search(_id):
continue
# Process matching line #a2 :| #lightgreen
# endif #a2
# ||:sec:|| Process Matching Line #a3
# start #a3
if _id != cur_id:
cur_id = _id
# find current diagram #a3 :
cur_diagram = diagrams.get(cur_id)
# create, if not found #a3 ;
if cur_diagram is None:
cur_diagram = DIAGRAMS.get(cur_id[0], Diagram)()
cur_diagram.id_ = cur_id
diagrams[cur_id] = cur_diagram
# split line into parts #a3 :|
_part_map = _lp.split(_line, mo, cur_diagram)
# assemble line parts #a3 :|
_line = _lp.assemble(_part_map, cur_diagram)
mo = SECTION_RX.search(_line)
_start_partition = mo
if _start_partition:
_line = _line[mo.end(0):]
# remove tags from line #a3 :
_line = TAG_RX.sub('', _line)
_line = _line.rstrip()
# escape line (creole does not like backticks) #a3 ;
_line = re.sub('`', '//', _line)
# if (line starts with ||<U+007C>:sec:|||) then (yes) #a3
if _start_partition:
# start partition #a3 :;
cur_diagram.open_partition(_line)
else: #a3
# append line to diagram #a3 :;
cur_diagram.append(_line)
# endif #a3
# stop #a3
# first match is sufficient, process next line
break #a2
# else (no) #a2
# endif #a2
# endwhile #a2
# endwhile #a2
# endif #a2
output = []
for _id, _diagram in ditems(diagrams):
# finish diagrams #a2 :;
_diagram.finish()
output.extend((
_p.replace('@ld-id@', _id) for _p in (
_diagram.header,
'\n'.join(_diagram),
_diagram.footer,
) if _p ))
output.append('')
if opt_file_base: #a2 (yes)
# write diagrams to\nseparate files #a2 :;
_fh = open(opt_file_base + _id + '.puml', 'w')
_fh.write('\n'.join(output))
_fh.close()
output = []
# else (no) #a2
# print diagrams on\nstandard output #a2 :;
if output:
output.pop()
if output:
printf('\n'.join(output))
# endif #a2
# stop #a2
# (progn (forward-line 1) (snip-insert "py_run.ws_rfid.dispatch_request" t t "python") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_shell.run" t t "python") (insert "\n"))
# |:here:|
return
# result.report()
# return max(result.error, ERR_NONE)
# --------------------------------------------------
# |||:sec:||| MAIN
# --------------------------------------------------
_quiet = False
_verbose = False
_debug = False
# (progn (forward-line 1) (snip-insert "py_f.argparse_callbacks" t t "python") (insert "\n"))
_argparse_have_sub_commands = False
def _argparse_begin(parser, context=None): # ||:fnc:||
r"""
:returns: parser
"""
if context is None:
context = globals()
parser.add_argument(
'-m', '--match', action='store', type=str, metavar='RX', default=None,
help='only extract diagrams matching RX')
parser.add_argument(
'-b', '--file-base', action='store', type=str, metavar='BASE', default=None,
help='Write output to files: `BASE` + `ID` + `INDEX` + ".puml"')
parser.add_argument(
'--show-bases', action='store_true', dest='show_bases', default=True,
help='show base classes for class diagrams (default)')
parser.add_argument(
'--hide-bases', action='store_false', dest='show_bases', default=True,
help='hide base classes for class diagrams')
parser.add_argument(
'--ignore-bases', action='append', metavar='CLASS',
help='ignore base classes for class diagrams')
parser.add_argument(
'-r', '--replace', action='append', metavar='REP',
help='register replacement REP = "SYM VAL"')
parser.add_argument(
'--verbatim', action='store_true', default=None,
help='do not perform standard replacements')
# |:here:|
return parser
def _argparse_end(parser, context=None): # ||:fnc:||
r"""
:returns: parser
"""
if context is None:
context = globals()
# |:here:|
return parser
# (progn (forward-line 1) (snip-insert "py_main.py" t t "python" " --key xpy_main_minimal") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.setdefaultencoding" t t "py") (insert "\n"))
#file_encoding_is_clean = True
def setdefaultencoding(encoding=None, quiet=False, context=None):
if context is None:
context = globals()
if context.get('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=None, context=None): # ||:fnc:||
if argv is None:
argv = sys.argv
if context is None:
context = globals()
context.get(
'setup_logger', globals().get(
'setup_logger', lambda *args: None))(context, True)
try:
import argparse
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
context.get('_argparse_begin', lambda _p, *_args: _p)(parser, context)
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(
'-d', '--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')
class AdHocAction(argparse.Action):
options = ('implode', 'setup', 'explode', 'extract', 'template', 'eide')
def __call__(self, parser, namespace, values, option_string=None):
for _opt in self.options:
setattr(namespace, 'adhoc_' + _opt, False)
setattr(namespace, 'adhoc_' + option_string[2:], True)
setattr(namespace, 'adhoc_arg', values)
parser.add_argument(
'--implode', nargs=0, action=AdHocAction, dest='adhoc_implode', default=False,
help='implode script with adhoc')
parser.add_argument(
'--setup', nargs='?', action=AdHocAction, type=str, metavar='install',
dest='adhoc_setup', default=False, const='install',
help='explode script into temporary directory and call'
' `python setup.py install`')
parser.add_argument(
'--explode', nargs='?', action=AdHocAction, type=str, metavar='DIR',
dest='adhoc_explode', 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',
dest='adhoc_extract', default=False, const = '.',
help='extract files to directory DIR (default: `.`)')
parser.add_argument(
'--template', nargs='?', action=AdHocAction, type=str, metavar='NAME',
dest='adhoc_template', default=False, const = '-',
help='extract named template to standard output. default NAME is ``-``')
parser.add_argument(
'--eide', nargs='?', action=AdHocAction, type=str, metavar='COMM',
dest='adhoc_eide', default=False, const = '',
help='Emacs IDE template list (implies --template list).')
parser.add_argument(
'-h', '--help', action='store_true',
help="display this help message")
parser.add_argument(
'--ap-help', action='store_true',
help="internal help message")
context.get('_argparse_end', lambda _p, *_args: _p)(parser, context)
if not context.get('_argparse_have_sub_commands'):
# all options and arguments are known
# all non-option arguments are consumed by `_parameters.args`
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(argv[1:])
else:
# (progn (forward-line 1) (snip-insert "py_f.args_split_range" t t "python") (insert "\n"))
def args_split_range(args):
next_range = []
for arg in args:
next_range.append(arg)
if not arg.startswith('-'):
break
if next_range and not next_range[0].startswith('-'):
next_range = []
return next_range, args[len(next_range):]
# for sub-commands with their own options: pre-parse to first
# non-option argument
_parameters = None
args = argv[1:]
while True:
next_range, args = args_split_range(args)
if not next_range and not _parameters is None:
break
_parameters, unknown_args = parser.parse_known_args(next_range, _parameters)
if unknown_args:
unknown_args.extend(args)
args = unknown_args
next_range = []
break
_parameters.args = args
# generate argparse help
if _parameters.ap_help:
parser.print_help()
return 0
# standard help
if _parameters.help:
help_ = re.sub('\n+[.][.] _END_OF_HELP.*(?s)', '', context['__doc__'])
sys.stdout.write(help_ + '\n')
return 0
context['_debug'] = _parameters.debug
if context['_debug'] > 0:
context['_verbose'] = True
context['_quiet'] = False
elif context['_debug'] < 0:
context['_verbose'] = (context['_debug'] == -1)
context['_quiet'] = not(context['_verbose'])
context['_debug'] = 0
_parameters.debug = context['_debug']
_parameters.verbose = context['_verbose']
_parameters.quiet = context['_quiet']
if context['_debug']:
cmd_line = argv
sys.stderr.write(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[\n",
context.get('dbg_comm', '# '),
context.get('dbg_twid', 11),
context.get('dbg_fwid', 15),
':DBG:', 'cmd_line', cmd_line))
# at least use `quiet` to suppress the setdefaultencoding warning
context.get('setdefaultencoding',
globals().get('setdefaultencoding', lambda *_a, **_k: None))(
quiet=context['_quiet'] or _parameters.test)
# |:opt:| handle options
# adhoc: implode/setup/explode/extract
adhoc_get_opt = lambda opt: getattr(
_parameters, 'adhoc_' + opt, None)
adhoc_op = sum(((adhoc_get_opt(_opt) and 1) or 0
for _opt in AdHocAction.options))
if adhoc_op:
for _opt in AdHocAction.options:
setattr(_parameters, _opt, adhoc_get_opt(_opt))
adhoc_export = (
_parameters.setup
or _parameters.explode
or _parameters.extract)
file_ = context['__file__']
source = None
have_adhoc = 'AdHoc' in context
have_rt_adhoc = 'RtAdHoc' in context
# shall adhoc be imported
if _parameters.implode or not have_rt_adhoc:
# shall this file be compiled
adhoc_compile = not (have_rt_adhoc)
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
context['AdHoc'] = adhoc.AdHoc
except ImportError:
adhoc_compile = False
try:
from rt_adhoc import RtAdHoc as Adhoc
context['AdHoc'] = AdHoc
except ImportError:
pass
else:
adhoc_compile = False
context['AdHoc'] = context['RtAdHoc']
AdHoc = context['AdHoc']
AdHoc.quiet = context['_quiet']
AdHoc.verbose = context['_verbose']
AdHoc.debug = context['_debug']
AdHoc.include_path.append(os.path.dirname(file_))
AdHoc.extra_templates = [
]
AdHoc.template_process_hooks = {
}
if _parameters.eide:
AdHoc.tt_ide = True
AdHoc.tt_comment = _parameters.adhoc_arg or ''
AdHoc.tt_prefix = '. (shell-command "'
AdHoc.tt_suffix = '")'
_parameters.template = True
_parameters.adhoc_arg = 'list'
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 context['_quiet']:
# map(sys.stderr.write,
# ["warning: ", os.path.basename(file_),
# " already imploded!\n"])
# @:adhoc_enable:@
AdHoc.write_source('-', source)
# explode
elif _parameters.setup or _parameters.explode:
_here = os.path.abspath('.')
_clean_dir = False
AdHoc.export_dir = _parameters.adhoc_arg
if _parameters.setup:
import tempfile
_clean_dir = True
AdHoc.export_dir = tempfile.mkdtemp('_setup', '__adhoc__')
try:
AdHoc.export(file_, source)
if _parameters.setup:
sq = lambda string: ''.join(("'", re.sub("'", """'\\''""", string), "'"))
os.chdir(AdHoc.export_dir)
os.system(sformat('{0} setup.py {1}', sq(sys.executable), sq(_parameters.adhoc_arg)))
finally:
if _clean_dir:
try:
os.chdir(_here)
except:
pass
import shutil
shutil.rmtree(AdHoc.export_dir)
# extract
elif _parameters.extract:
AdHoc.extract_dir = _parameters.adhoc_arg
AdHoc.extract(file_, source)
# 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')
else:
template = AdHoc.get_named_template(
template_name, file_, source)
AdHoc.write_source('-', template)
# restore for subsequent calls to main
if not have_adhoc:
del(AdHoc)
return 0
# run doc tests
if _parameters.test:
import warnings
warnings.simplefilter('default')
import doctest
# for :file:`__init__.py`, :func:`_canonize_module_` does not register the module in `sys.modules`.
_canon_name = _module_name = context['__name__']
context.get('_canonize_module_', globals().get(
'_canonize_module_',
lambda *args: context.__setitem__('__name__', _canon_name)))(context['__name__'], context['__name__'] == '__main__')
if context['__name__'] not in sys.modules:
sys.modules[context['__name__']] = sys.modules[_module_name]
try:
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
except NameError:
pass
context.get('_doctest_hook_', lambda *args, **kwargs: None)(context)
result = doctest.testmod(sys.modules[context['__name__']], verbose = context['_verbose'])
return result.failed
# run program
final = False
ecode = 0
try:
try:
ecode = context['run'](_parameters)
except IOError:
(t, e, tb) = sys.exc_info()
del(tb)
# ignore SIGPIPE
import errno
if e.errno != errno.EPIPE:
raise
except SystemExit:
raise
except:
# |:info:| this is used, since module cgitb does not work so well ...
(t, e, tb) = sys.exc_info()
if not final or context['_debug']:
import traceback
printf(''.join(traceback.format_tb(tb)), file=sys.stderr, end='')
printf(sformat('{0}: {1}', t.__name__, e), file=sys.stderr)
del(tb)
ecode = 1
return ecode
if globals().get('_is_main_', (__name__ == '__main__')):
#sys.argv.insert(1, '--debug') # |:debug:|
result = main(sys.argv, globals())
sys.exit(result)
# |:here:|
# (progn (forward-line 1) (snip-insert "py.t.ide" t t "py") (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\\|[.] \\).*,,' " (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 :@ @: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 --eide
# . (progn (save-buffer) (shell-command (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --eide") (concat "*templates: " (file-name-nondirectory (buffer-file-name)) "*")))
# :ide: COMPILE: Run with python3 --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 --debug self
# . (let ((fn (file-name-nondirectory (buffer-file-name)))) (save-buffer) (compile (concat "python ./" fn " --debug=1 " fn)))
# :ide: COMPILE: Run with --match '^a'
# . (let ((fn (file-name-nondirectory (buffer-file-name)))) (save-buffer) (compile (concat "python ./" fn " --match '^a' " fn)))
# :ide: COMPILE: Run with --match '^c'
# . (let ((fn (file-name-nondirectory (buffer-file-name)))) (save-buffer) (compile (concat "python ./" fn " --match '^c' " fn)))
# :ide: COMPILE: Run with --file-base line_diversion-check- self
# . (let ((fn (file-name-nondirectory (buffer-file-name)))) (save-buffer) (compile (concat "python ./" fn " --file-base line_diversion-check- " fn)))
# :ide: COMPILE: Run with self (>.t; diff .e .t)
# . (let ((fn (file-name-nondirectory (buffer-file-name)))) (save-buffer) (compile (concat "python ./" fn " " fn " | tee " fn ".t; echo '--------------------'; diff -u " fn ".e " fn ".t")))
# :ide: COMPILE: Run with /home/ws/project/ws_rfid/data/c_wiedenmann/modules/ws_rfid_cust/update_task_nos.py
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " /home/ws/project/ws_rfid/data/c_wiedenmann/modules/ws_rfid_cust/update_task_nos.py")))
# :ide: COMPILE: Run with --debug=1 /home/ws/project/ws_rfid/app/ws_rfid_app/models/dba_standard.py
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --debug=1 /home/ws/project/ws_rfid/app/ws_rfid_app/models/dba_standard.py")))
# :ide: COMPILE: Run with --debug=1 /home/ws/snippets/xx.py
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --debug=1 /home/ws/snippets/xx.py")))
# :ide: COMPILE: Run with --test
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --test")))
# :ide: COMPILE: Run with --debug=1 --match '^u0$' /home/ws/project/documentation/bin/sphinx-doc-admin.sh
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --debug=1 --match '^u0$' /home/ws/project/documentation/bin/sphinx-doc-admin.sh")))
# :ide: +-#+
# . Compile ()
#
# Local Variables:
# mode: python
# comment-start: "#"
# comment-start-skip: "#+"
# comment-column: 0
# truncate-lines: t
# End: