http://code.google.com/p/pycopia/source/detail?r=523
Modified:
/trunk/CLI/pycopia/UI.py
/trunk/QA/pycopia/QA/shellinterface.py
/trunk/debugger/pycopia/debugger.py
=======================================
--- /trunk/CLI/pycopia/UI.py Wed Aug 17 22:51:10 2011
+++ /trunk/CLI/pycopia/UI.py Tue Jan 3 22:19:21 2012
@@ -43,7 +43,7 @@
PROMPT_START_IGNORE = ''
PROMPT_END_IGNORE = ''
-from types import MethodType
+from types import MethodType, FunctionType
class UIError(Exception):
pass
@@ -240,14 +240,10 @@
self._io.flush()
def pprint(self, obj):
- self._format(obj, 0, 0, {}, 0)
+ self._format(obj, 0, 0, set(), 0)
self._io.write("\n")
self._io.flush()
- def printf(self, text):
- "Print text run through the expansion formatter."
- self.Print(self.format(text))
-
def print_obj(self, obj, nl=1):
if nl:
self._io.write("%s\n" % (obj,))
@@ -275,6 +271,10 @@
def write(self, text):
self._io.write(text)
+ def printf(self, text):
+ "Print text run through the expansion formatter."
+ self.Print(self.format(text))
+
def error(self, text):
self.printf("%%r%s%%N" % (text,))
@@ -376,16 +376,38 @@
else:
return None
- def register_expansion(self, key, func):
- """Register a percent-expansion function for the format method. The
+ def format_wrap(self, obj, formatstring):
+ return FormatWrapper(obj, self, formatstring)
+
+ def register_prompt_expansion(self, key, func):
+ """Register a percent-expansion function for the prompt format
method. The
function must take one argument, and return a string. The argument
is
- the character expanded on."""
+ the character expanded on.
+ """
key = str(key)[0]
if not key in self._PROMPT_EXPANSIONS:
self._PROMPT_EXPANSIONS[key] = func
else:
raise ValueError("expansion key %r already exists." % (key, ))
+ def register_format_expansion(self, key, func):
+ """Register a percent-expansion function for the format method. The
+ function must take one argument, and return a string. The argument
is
+ the character expanded on.
+ """
+ key = str(key)[0]
+ if key not in self._FORMAT_EXPANSIONS:
+ self._FORMAT_EXPANSIONS[key] = func
+ else:
+ raise ValueError("expansion key %r already exists." % (key, ))
+
+ def unregister_format_expansion(self, key):
+ key = str(key)[0]
+ try:
+ del self._FORMAT_EXPANSIONS[key]
+ except KeyError:
+ pass
+
# FSM for prompt expansion
def _initfsm(self):
# maps percent-expansion items to some value.
@@ -549,10 +571,10 @@
return
rep = self._repr(obj, context, level - 1)
typ = type(obj)
- sepLines = len(rep) > (self._termwidth - 1 - indent - allowance)
+ sep_lines = len(rep) > (self._termwidth - 1 - indent - allowance)
write = self._io.write
- if sepLines:
+ if sep_lines:
if typ is dict:
write('{\n ')
length = len(obj)
@@ -598,6 +620,48 @@
def _safe_repr(self, obj, context, maxlevels, level):
return _safe_repr(obj, context, maxlevels, level)
+
+class FormatWrapper(object):
+ """Wrap any object with a format.
+
+ The format string should have an '%O' component that will be expanded
to
+ the stringified object given here.
+ """
+ def __init__(self, obj, ui, format):
+ self.value = obj
+ self._ui = ui
+ self._format = format
+
+ def __str__(self):
+ self._ui.register_format_expansion("O", self._str_value)
+ try:
+ return self._ui.format(self._format)
+ finally:
+ self._ui.unregister_format_expansion("O")
+
+ def _str_value(self, c):
+ return str(self.value)
+
+ def __len__(self):
+ return len(str(self.value))
+
+ def __repr__(self):
+ return _safe_repr(self.value, set(), None, 0)
+
+ def __cmp__(self, other):
+ if type(other) is FormatWrapper:
+ return cmp(self.value, other.value)
+ else:
+ return cmp(self.value, other)
+
+
+def safe_repr(value):
+ """Return a representational string of the given object.
+
+ Large or recursive objects or detected and clipped.
+ """
+ return _safe_repr(value, set(), None, 0)
+
# Return repr_string
def _safe_repr(obj, context, maxlevels, level):
typ = type(obj)
@@ -669,19 +733,18 @@
if typ is MethodType:
return method_repr(obj)
- rep = repr(obj)
- return rep
+ if typ is FunctionType:
+ return function_repr(obj)
+
+ return repr(obj)
def _recursion(obj):
return ("<Recursion on %s with id=%s>" % (type(obj).__name__, id(obj)))
-def safe_repr(value):
- return _safe_repr(value, {}, None, 0)
-
def method_repr(method):
methname = method.im_func.func_name
# formal names
- varnames =
list(method.im_func.func_code.co_varnames)[1:method.im_func.func_code.co_argcount]
+ varnames =
list(method.im_func.func_code.co_varnames)[:method.im_func.func_code.co_argcount]
if method.im_func.func_defaults:
ld = len(method.im_func.func_defaults)
varlist = [", ".join(varnames[:-ld]),
@@ -690,6 +753,19 @@
else:
return "%s(%s)" % (methname, ", ".join(varnames))
+def function_repr(func):
+ methname = func.func_name
+ # formal names
+ argcount = func.func_code.co_argcount
+ varnames = list(func.func_code.co_varnames)[:argcount]
+ if func.func_defaults:
+ ld = len(func.func_defaults)
+ varlist = varnames[:-ld]
+ varlist.extend(["%s=%r" % (n, v) for n, v in zip(varnames[-ld:],
func.func_defaults)])
+ return "%s(%s)" % (methname, ", ".join(varlist))
+ else:
+ return "%s(%s)" % (methname, ", ".join(varnames))
+
def _get_object(name):
try:
@@ -740,6 +816,8 @@
ui.Print("Hello world!")
inp = ui.user_input("Type something> ")
ui.Print("You typed:", inp)
+ return ui
if __name__ == "__main__":
- _test(sys.argv)
+ ui = _test(sys.argv)
+
=======================================
--- /trunk/QA/pycopia/QA/shellinterface.py Tue Sep 13 00:17:31 2011
+++ /trunk/QA/pycopia/QA/shellinterface.py Tue Jan 3 22:19:21 2012
@@ -25,24 +25,18 @@
from pycopia import module
-def get_module_list():
- """Get list of test modules.
-
- Used by user interfaces to select a module to run. All automated test
- implementations are located in a base package called "testcases".
-
- Returns:
- A complete list of module names found in the "testcases" package,
as
- strings. This includes sub-packages.
- """
+def choose_tests():
try:
import testcases
except ImportError:
logging.warn("Cannot find 'testcases' base package.")
- return []
-
+ return None
+ from pycopia import UI
from pycopia.QA import core
+ ui = UI.get_userinterface(themename="ANSITheme")
+ ui.printf("Select any number of runnable objects. %n"
+ "You can select %wmodules%N, %gUseCase%N objects, or
single %yTest%N object.")
# callback for testdir walker
def filternames(flist, dirname, names):
for name in names:
@@ -50,23 +44,68 @@
flist.append(os.path.join(dirname, name[:-3]))
testhome = os.path.dirname(testcases.__file__)
modnames = []
+ runnables = []
os.path.walk(testhome, filternames, modnames)
testhome_index = len(os.path.dirname(testhome)) + 1
- names = map(lambda n: n[testhome_index:].replace("/", "."), modnames)
- for name in names[:]:
+ modnames = map(lambda n: n[testhome_index:].replace("/", "."),
modnames)
+ modnames.sort()
+ for modname in modnames:
try:
- mod = module.get_module(name)
+ mod = module.get_module(modname)
except module.ModuleImportError:
- names.remove(name)
+ ui.warning(" Warning: could not import '{}'".format(modname))
continue
+ if getattr(mod, "run", None) is not None:
+ runnables.append(FormatWrapper(ui, modname, None, "%w%U%N"))
for attrname in dir(mod):
obj = getattr(mod, attrname)
- if type(obj) is type and issubclass(obj, core.UseCase):
- names.append(".".join([obj.__module__, obj.__name__]))
- if getattr(mod, "run", None) is None:
- names.remove(name)
- names.sort()
- return names
+ if type(obj) is type:
+ if issubclass(obj, core.UseCase):
+ runnables.append(FormatWrapper(ui, modname,
obj.__name__, "%U.%g%O%N"))
+ if issubclass(obj, core.Test):
+ runnables.append(FormatWrapper(ui, modname,
obj.__name__, "%U.%y%O%N"))
+ return [o.fullname for o in ui.choose_multiple(runnables,
prompt="Select tests")]
+
+
+class FormatWrapper(object):
+ """Wrap module path object with a format.
+
+ The format string should have an '%O' component that will be expanded
to
+ the stringified object, and an '%U' component for the module name.
+ """
+ def __init__(self, ui, module, objname, format):
+ self._ui = ui
+ self.modname = module
+ self.name = objname
+ self._format = format
+
+ @property
+ def fullname(self):
+ if self.name:
+ return "{}.{}".format(self.modname, self.name)
+ else:
+ return self.modname
+
+ def __str__(self):
+ self._ui.register_format_expansion("O", self._str_name)
+ self._ui.register_format_expansion("U", self._str_module)
+ try:
+ return self._ui.format(self._format)
+ finally:
+ self._ui.unregister_format_expansion("O")
+ self._ui.unregister_format_expansion("U")
+
+ def _str_name(self, c):
+ return str(self.name)
+
+ def _str_module(self, c):
+ return str(self.modname)
+
+ def __len__(self):
+ return len(self.fullname)
+
+ def __cmp__(self, other):
+ return cmp(self.modname, other.modname)
# not in a docstring since docstrings don't exist in optimize mode.
@@ -138,13 +177,9 @@
self.runner.set_options(extraopts)
if not args:
- from pycopia import cliutils
- l = get_module_list()
- l.insert(0, None)
- arg = cliutils.choose(l, prompt="Select test")
- if arg is None:
- return
- args = [arg]
+ args = choose_tests()
+ if not args:
+ return
objects, errors = module.get_objects(args)
if errors:
logging.error("Errors found while loading test object:")
=======================================
--- /trunk/debugger/pycopia/debugger.py Thu Feb 10 23:22:29 2011
+++ /trunk/debugger/pycopia/debugger.py Tue Jan 3 22:19:21 2012
@@ -155,7 +155,7 @@
theme = DebuggerTheme("%GDebug%N> ")
io = IO.ConsoleIO()
self._ui = CLI.UserInterface(io, env=None, theme=theme)
- self._ui.register_expansion("S", self._expansions)
+ self._ui.register_prompt_expansion("S", self._expansions)
def _expansions(self, c):
if c == "S": # current frame over total frames in backtrace