summaryrefslogtreecommitdiffstats
path: root/Demo/parser
diff options
context:
space:
mode:
Diffstat (limited to 'Demo/parser')
-rw-r--r--Demo/parser/Makefile6
-rw-r--r--Demo/parser/README17
-rw-r--r--Demo/parser/example.py133
-rw-r--r--Demo/parser/pprint.py97
-rw-r--r--Demo/parser/simple.py1
5 files changed, 150 insertions, 104 deletions
diff --git a/Demo/parser/Makefile b/Demo/parser/Makefile
index 648bf6e..d71e811 100644
--- a/Demo/parser/Makefile
+++ b/Demo/parser/Makefile
@@ -3,6 +3,10 @@ parser.dvi: parser.tex ../../Doc/libparser.tex
# Use a new name for this; the included file uses 'clean' already....
clean-parser:
- rm -f *.log *.aux *.dvi *.pyc
+ rm -f *.log *.aux *.dvi *.pyc *.ps
+
+dist:
+ (cd ../..; \
+ tar cf - `cat Demo/parser/FILES` | gzip >parsermodule-1.4.tar.gz)
include ../../Doc/Makefile
diff --git a/Demo/parser/README b/Demo/parser/README
index 03696c3..3d775aa 100644
--- a/Demo/parser/README
+++ b/Demo/parser/README
@@ -4,12 +4,29 @@ to the Python Library Reference for more information.
Files:
------
+ FILES -- list of files associated with the parser module.
+
+ README -- this file.
+
example.py -- module that uses the `parser' module to extract
information from the parse tree of Python source
code.
+ docstring.py -- sample source file containing only a module docstring.
+
+ simple.py -- sample source containing a "short form" definition.
+
source.py -- sample source code used to demonstrate ability to
handle nested constructs easily using the functions
and classes in example.py.
+ pprint.py -- function to pretty-print Python values.
+
+ test_parser.py program to put the parser module through it's paces.
+
+ parser.tex -- LaTex driver file for formatting the parser module
+ documentation separately from the library reference.
+
+ Makefile -- `make' rule set to format the parser module manual.
+
Enjoy!
diff --git a/Demo/parser/example.py b/Demo/parser/example.py
index c428aff..363f5bb 100644
--- a/Demo/parser/example.py
+++ b/Demo/parser/example.py
@@ -1,6 +1,8 @@
"""Simple code to extract class & function docstrings from a module.
-
+This code is used as an example in the library reference manual in the
+section on using the parser module. Refer to the manual for a thorough
+discussion of the operation of this code.
"""
import symbol
@@ -23,12 +25,35 @@ def get_docs(fileName):
return ModuleInfo(tup, basename)
-class DefnInfo:
+class SuiteInfoBase:
_docstring = ''
_name = ''
- def __init__(self, tree):
- self._name = tree[2][1]
+ def __init__(self, tree = None):
+ self._class_info = {}
+ self._function_info = {}
+ if tree:
+ self._extract_info(tree)
+
+ def _extract_info(self, tree):
+ # extract docstring
+ if len(tree) == 2:
+ found, vars = match(DOCSTRING_STMT_PATTERN[1], tree[1])
+ else:
+ found, vars = match(DOCSTRING_STMT_PATTERN, tree[3])
+ if found:
+ self._docstring = eval(vars['docstring'])
+ # discover inner definitions
+ for node in tree[1:]:
+ found, vars = match(COMPOUND_STMT_PATTERN, node)
+ if found:
+ cstmt = vars['compound']
+ if cstmt[0] == symbol.funcdef:
+ name = cstmt[2][1]
+ self._function_info[name] = FunctionInfo(cstmt)
+ elif cstmt[0] == symbol.classdef:
+ name = cstmt[2][1]
+ self._class_info[name] = ClassInfo(cstmt)
def get_docstring(self):
return self._docstring
@@ -36,38 +61,21 @@ class DefnInfo:
def get_name(self):
return self._name
-class SuiteInfoBase(DefnInfo):
- def __init__(self):
- self._class_info = {}
- self._function_info = {}
-
def get_class_names(self):
return self._class_info.keys()
def get_class_info(self, name):
return self._class_info[name]
- def _extract_info(self, tree):
- if len(tree) >= 4:
- found, vars = match(DOCSTRING_STMT_PATTERN, tree[3])
- if found:
- self._docstring = eval(vars['docstring'])
- for node in tree[1:]:
- if (node[0] == symbol.stmt
- and node[1][0] == symbol.compound_stmt):
- if node[1][1][0] == symbol.funcdef:
- name = node[1][1][2][1]
- self._function_info[name] = \
- FunctionInfo(node[1][1])
- elif node[1][1][0] == symbol.classdef:
- name = node[1][1][2][1]
- self._class_info[name] = ClassInfo(node[1][1])
-
-
-class SuiteInfo(SuiteInfoBase):
- def __init__(self, tree):
- SuiteInfoBase.__init__(self)
- self._extract_info(tree)
+ def __getitem__(self, name):
+ try:
+ return self._class_info[name]
+ except KeyError:
+ return self._function_info[name]
+
+
+class SuiteFuncInfo:
+ # Mixin class providing access to function names and info.
def get_function_names(self):
return self._function_info.keys()
@@ -76,23 +84,16 @@ class SuiteInfo(SuiteInfoBase):
return self._function_info[name]
-class FunctionInfo(SuiteInfo):
- def __init__(self, tree):
- DefnInfo.__init__(self, tree)
- suite = tree[-1]
- if len(suite) >= 4:
- found, vars = match(DOCSTRING_STMT_PATTERN, suite[3])
- if found:
- self._docstring = eval(vars['docstring'])
- SuiteInfoBase.__init__(self)
- self._extract_info(suite)
+class FunctionInfo(SuiteInfoBase, SuiteFuncInfo):
+ def __init__(self, tree = None):
+ self._name = tree[2][1]
+ SuiteInfoBase.__init__(self, tree and tree[-1] or None)
class ClassInfo(SuiteInfoBase):
- def __init__(self, tree):
- SuiteInfoBase.__init__(self)
- DefnInfo.__init__(self, tree)
- self._extract_info(tree[-1])
+ def __init__(self, tree = None):
+ self._name = tree[2][1]
+ SuiteInfoBase.__init__(self, tree and tree[-1] or None)
def get_method_names(self):
return self._function_info.keys()
@@ -101,19 +102,40 @@ class ClassInfo(SuiteInfoBase):
return self._function_info[name]
-class ModuleInfo(SuiteInfo):
- def __init__(self, tree, name="<string>"):
+class ModuleInfo(SuiteInfoBase, SuiteFuncInfo):
+ def __init__(self, tree = None, name = "<string>"):
self._name = name
- SuiteInfo.__init__(self, tree)
- found, vars = match(DOCSTRING_STMT_PATTERN, tree[1])
- if found:
- self._docstring = vars["docstring"]
+ SuiteInfoBase.__init__(self, tree)
+ if tree:
+ found, vars = match(DOCSTRING_STMT_PATTERN, tree[1])
+ if found:
+ self._docstring = vars["docstring"]
from types import ListType, TupleType
def match(pattern, data, vars=None):
- """
+ """Match `data' to `pattern', with variable extraction.
+
+ pattern
+ Pattern to match against, possibly containing variables.
+
+ data
+ Data to be checked and against which variables are extracted.
+
+ vars
+ Dictionary of variables which have already been found. If not
+ provided, an empty dictionary is created.
+
+ The `pattern' value may contain variables of the form ['varname'] which
+ are allowed to match anything. The value that is matched is returned as
+ part of a dictionary which maps 'varname' to the matched value. 'varname'
+ is not required to be a string object, but using strings makes patterns
+ and the code which uses them more readable.
+
+ This function returns two values: a boolean indicating whether a match
+ was found and a dictionary mapping variable names to their associated
+ values.
"""
if vars is None:
vars = {}
@@ -131,6 +153,15 @@ def match(pattern, data, vars=None):
return same, vars
+# This pattern identifies compound statements, allowing them to be readily
+# differentiated from simple statements.
+#
+COMPOUND_STMT_PATTERN = (
+ symbol.stmt,
+ (symbol.compound_stmt, ['compound'])
+ )
+
+
# This pattern will match a 'stmt' node which *might* represent a docstring;
# docstrings require that the statement which provides the docstring be the
# first statement in the class or function, which this pattern does not check.
diff --git a/Demo/parser/pprint.py b/Demo/parser/pprint.py
index c4b8158..36d1888 100644
--- a/Demo/parser/pprint.py
+++ b/Demo/parser/pprint.py
@@ -1,7 +1,7 @@
# pprint.py
#
# Author: Fred L. Drake, Jr.
-# fdrake@vt.edu
+# fdrake@cnri.reston.va.us, fdrake@intr.net
#
# This is a simple little module I wrote to make life easier. I didn't
# see anything quite like it in the library, though I may have overlooked
@@ -9,34 +9,28 @@
# tuples with fairly non-descriptive content. This is modelled very much
# after Lisp/Scheme - style pretty-printing of lists. If you find it
# useful, thank small children who sleep at night.
-#
"""Support to pretty-print lists, tuples, & dictionaries recursively.
-Very simple, but at least somewhat useful, especially in debugging
-data structures.
-
-INDENT_PER_LEVEL -- Amount of indentation to use for each new
- recursive level. The default is 1. This
- must be a non-negative integer, and may be
- set by the caller before calling pprint().
-
-MAX_WIDTH -- Maximum width of the display. This is only
- used if the representation *can* be kept
- less than MAX_WIDTH characters wide. May
- be set by the user before calling pprint().
-
-TAB_WIDTH -- The width represented by a single tab. This
- value is typically 8, but 4 is the default
- under MacOS. Can be changed by the user if
- desired, but is probably not a good idea.
-
-pprint(seq [, stream]) -- The pretty-printer. This takes a Python
- object (presumably a sequence, but that
- doesn't matter) and an optional output
- stream. See the function documentation
- for details.
-"""
+Very simple, but useful, especially in debugging data structures.
+
+Constants
+---------
+INDENT_PER_LEVEL
+ Amount of indentation to use for each new recursive level. The
+ default is 1. This must be a non-negative integer, and may be set
+ by the caller before calling pprint().
+
+MAX_WIDTH
+ Maximum width of the display. This is only used if the
+ representation *can* be kept less than MAX_WIDTH characters wide.
+ May be set by the user before calling pprint().
+
+TAB_WIDTH
+ The width represented by a single tab. This value is typically 8,
+ but 4 is the default under MacOS. Can be changed by the user if
+ desired, but is probably not a good idea.
+"""
INDENT_PER_LEVEL = 1
@@ -46,46 +40,45 @@ import os
TAB_WIDTH = (os.name == 'mac' and 4) or 8
del os
+from types import DictType, ListType, TupleType
def _indentation(cols):
- "Create tabbed indentation string COLS columns wide."
-
- # This is used to reduce the byte-count for the output, allowing
- # files created using this module to use as little external storage
- # as possible. This is primarily intended to minimize impact on
- # a user's quota when storing resource files, or for creating output
- # intended for transmission.
+ """Create tabbed indentation string.
+ cols
+ Width of the indentation, in columns.
+ """
return ((cols / TAB_WIDTH) * '\t') + ((cols % TAB_WIDTH) * ' ')
-
def pprint(seq, stream = None, indent = 0, allowance = 0):
"""Pretty-print a list, tuple, or dictionary.
- pprint(seq [, stream]) ==> None
-
- If STREAM is provided, output is written to that stream, otherwise
- sys.stdout is used. Indentation is done according to
- INDENT_PER_LEVEL, which may be set to any non-negative integer
- before calling this function. The output written on the stream is
- a perfectly valid representation of the Python object passed in,
- with indentation to suite human-readable interpretation. The
- output can be used as input without error, given readable
- representations of all sequence elements are available via repr().
- Output is restricted to MAX_WIDTH columns where possible. The
- STREAM parameter must support the write() method with a single
- parameter, which will always be a string. The output stream may be
- a StringIO.StringIO object if the result is needed as a string.
+ seq
+ List, tuple, or dictionary object to be pretty-printed. Other
+ object types are permitted by are not specially interpreted.
+
+ stream
+ Output stream. If not provided, `sys.stdout' is used. This
+ parameter must support the `write()' method with a single
+ parameter, which will always be a string. It may be a
+ `StringIO.StringIO' object if the result is needed as a
+ string.
+
+ Indentation is done according to `INDENT_PER_LEVEL', which may be
+ set to any non-negative integer before calling this function. The
+ output written on the stream is a perfectly valid representation
+ of the Python object passed in, with indentation to assist
+ human-readable interpretation. The output can be used as input
+ without error, given readable representations of all elements are
+ available via `repr()'. Output is restricted to `MAX_WIDTH'
+ columns where possible.
"""
-
if stream is None:
import sys
stream = sys.stdout
- from types import DictType, ListType, TupleType
-
rep = `seq`
typ = type(seq)
sepLines = len(rep) > (MAX_WIDTH - 1 - indent - allowance)
@@ -140,4 +133,4 @@ def pprint(seq, stream = None, indent = 0, allowance = 0):
#
-# end of pprint.py
+# end of file
diff --git a/Demo/parser/simple.py b/Demo/parser/simple.py
new file mode 100644
index 0000000..184e2fe
--- /dev/null
+++ b/Demo/parser/simple.py
@@ -0,0 +1 @@
+def f(): "maybe a docstring"