Thread: [Pyunit-interest] ANN: PyUnitTestBrowser
Brought to you by:
purcell
From: Phlip <ppl...@om...> - 2002-05-31 14:28:58
|
PyUnit Interest: This is a graphical test browser; an alternative to GuiTestRunner: http://www.c2.com/cgi/wiki?PyUnitTestBrowser http://flea.sourceforge.net/browser002.zip It triggers tests when you change your source or test file. Therefor it provides One Button Testing for any editor. If an error occurs, you can surf to the error point automatically with Vim. I'm currently adding support for Idle; this is new, but the first scratch appears in that zip file. I wrote this because... A> at work we have a hand-made proprietary test runner with no GUI that philosophically diverges from PyUnit, and... B> after hearing about the miracle of TestFirst for years and only using CppUnit once, I developed a (glowing) mental image of what graphic test runners presented that in no way paralleled the actual (dim) reality. So to put them together, I allocated resources at work (me), to write a greenfield GUI test browser for our rig. Then I ported all of the relevant features back to PyUnit, out to LGPL instead of Private, creating PyUnitTestBrowser. Also, I discovered another missing feature about PyUnit (and the other *Units I have interviewed). All of them seem to have neglected to include their own unit tests in their distributions. This sentence refers to itself. >sigh< -- Phlip http://www.greencheese.org/LucidScheming -- Who needs a degree when we have Web e-search engines? -- |
From: Phlip <ppl...@om...> - 2002-05-31 16:39:11
|
Phlip sez: > This is a graphical test browser; an alternative to GuiTestRunner: > > http://www.c2.com/cgi/wiki?PyUnitTestBrowser > http://flea.sourceforge.net/browser002.zip I just uploaded a tweak (to the same file name ;-) that fixes a hairy-arm \ / path separator insect for MS Windows. Tell me what y'all think! -- Phlip http://www.greencheese.org/HatTrick "The man who sets out to carry a cat by its tail learns something that will always be useful and which never will grow dim or doubtful." -- Mark Twain |
From: Phlip <ppl...@om...> - 2002-05-31 21:19:35
|
Alexander Garden sez: > It ran away and was killed by the VOOM just a few minutes ago, so > something is leaking. Voom is the thing under the Y-cat's hat in /The Cat in the Hat Comes Back/, right? Apologies for running away, but if you disable the timer (grep def\ timer browser.py) will it stop leaking? And do you have a link for Voom so I can release it from under my hat too? > But very cool. It might even persuade me to crawl > out of my console cave and use X for development. Ah, but it explicitly supports the console, too! ;-) > My development box is running Linux with Python 2.0, fyi. I tried it on > my Win'98, Python 2.2 machine but it didn't work. TreeBox throws an > exception. In the process I fixed some path stuff, which fix is included > in the patch at the end of this email. (Come to think of it, I'll bet > that's the same one that you mention as being fixed above. I downloaded > after the first email.) Nnnnot TreeBox. You did hit the bug I fixed, and (because we are totally OO) at crash time the traceback will show TreeBox calling into the browser. But your patch here is proper. I will apply your patch just as soon as I can figure out the interface to the patch command. Do you know if Win95 supports / path delimiters? -- Phlip http://www.c2.com/cgi/wiki?PhlIp "When a true genius appears in the world you may know him by this sign: that all the dunces are in confederacy against him." -- Jonathan Swift |
From: Syver E. <syv...@on...> - 2002-06-02 01:26:07
|
Phlip <ppl...@om...> writes: > > Do you know if Win95 supports / path delimiters? > All win32 os'es that I've tried support / for most all api functions (the volume mountpoint functions are an exception, there might be more), they don't support it in the shell (cmd.exe or command.com) though, so os.system with forward slashes won't work. -- Vennlig hilsen Syver Enstad |
From: Alexander G. <al...@in...> - 2002-05-31 23:24:16
|
On Fri, May 31, 2002 at 02:18:20PM -0700, Phlip wrote: > Alexander Garden sez: > > > It ran away and was killed by the VOOM just a few minutes ago, so > > something is leaking. > > Voom is the thing under the Y-cat's hat in /The Cat in the Hat Comes Back/, > right? Oops, that should have been OOM killer. But you got it right anyway. Some people say it stands for 'Out Of Memory' killer, but I know better. They also say it's a Linux kernel process that takes upon itself to violently end the life of runaway processes. Yeah, right. > Apologies for running away, but if you disable the timer (grep def\ timer > browser.py) will it stop leaking? I'll look into it. It only happened once, so I'm not sure if I can make it repeat. > And do you have a link for Voom so I can release it from under my hat too? > > > But very cool. It might even persuade me to crawl > > out of my console cave and use X for development. > > Ah, but it explicitly supports the console, too! ;-) In an xterm. Which is quite cool. But I meant where real gurus spend their time, without the aid of such frivolities as point and click, drag and drop, toolbars, menus, or pretty icons. F1-F6, X free. >;-| > Do you know if Win95 supports / path delimiters? I think it does. So it surprised me when Python complained about the code I patched. Maybe I missed the cause of the error altogether and just managed to eliminate it by happenstance. Could well be, seeing as how my patch was badly broken on this point. But I'm told the Mac is the real issue. Only colons suffice over there. Alexander |
From: Alexander G. <al...@in...> - 2002-06-03 23:17:45
|
On Fri, May 31, 2002 at 06:24:08PM -0500, Alexander Garden wrote: > On Fri, May 31, 2002 at 02:18:20PM -0700, Phlip wrote: > > Alexander Garden sez: > > > > > It ran away and was killed by the VOOM just a few minutes ago, so > > > something is leaking. > > > > Voom is the thing under the Y-cat's hat in /The Cat in the Hat Comes Back/, > > right? > > Oops, that should have been OOM killer. But you got it right anyway. > > Some people say it stands for 'Out Of Memory' killer, but I know better. > They also say it's a Linux kernel process that takes upon itself to > violently end the life of runaway processes. Yeah, right. > > > Apologies for running away, but if you disable the timer (grep def\ timer > > browser.py) will it stop leaking? > > I'll look into it. It only happened once, so I'm not sure if I can make > it repeat. It was leaking every time I ran it. Here's what I did to fix it: =========================================================== --- 002.browser/Debug.py Tue May 28 21:44:12 2002 +++ mybrowser/Debug.py Mon Jun 3 17:39:33 2002 @@ -93,10 +93,12 @@ try: raise None except: # TODO is there an inspect.py frame thing we could use here? - try: + #try: info = sys.exc_info() tb = info[2] frame = tb.tb_frame.f_back + del info + del tb code = frame.f_code file = [None, None] @@ -155,18 +157,20 @@ if len(expr) > 1: stringThing = "(" + stringThing + ")" report = '%s:%i: %s' % (file[0], frame.f_lineno, output) + del file if count (stringThing, "\n") > 0: - report += " =\n", + report += " =\n" else: - report += " = ", + report += " = " report += stringThing - sys.stderr(report) + sys.stderr.write(report) print report - except: - pass + #except: + #print "We're here" + #pass def tolerance(a, b): =========================================================== Of course, you don't want to apply that. The three added del statements fixed the problem, the rest is included because I want to ask questions. First, why is the whole thing wrapped up in a catch-all try/except that does nothing when an exception is raised? I commented this out because an exception was being raised every time. Second, the exception being raised was a TypeError because of the 'report += "...",' lines. Why the comma at the end? This makes the thing a tuple, which, to quote from the exception message, cannot be concatenated with a string object. (I tested this in 2.2 and got the same message.) Thirdly, the sys.stderr line raised an exception. I strongly suspect that's just because this way of invoking stderr was introduced in 2.1 or 2.2. Recall that I'm running 2.0. So you might want to change this for backwards compatibility. Or you might not. Whatever. And if you or someone else could clue me in as to why adding the explicit del statements could fix a memory leak here, I'd appreciate it. Maybe a 2.0 bug? Alexander |
From: Phlip <ppl...@om...> - 2002-06-02 08:10:25
|
Syver Enstad sez: > Phlip <ppl...@om...> writes: > > Do you know if Win95 supports / path delimiters? > > All win32 os'es that I've tried support / for most all api functions > (the volume mountpoint functions are an exception, there might be > more), they don't support it in the shell (cmd.exe or command.com) > though, so os.system with forward slashes won't work. So I hope y'all can understand the pressure on me to write os.system("rm -f " + tempFileOrDirectory) instead of the current blob of portable crap to do it. Come to think of it, I could write a "removeForced()" function over "glob.glob" and "os.path.isfile". I think I'l do that first before reading this evening's bug reports (if any ;). -- Phlip http://www.greencheese.org/YaAw -- Please state the nature of the programming emergency -- |
From: Fred L. D. Jr. <fd...@ac...> - 2002-06-06 13:52:34
|
Phlip writes: > So I hope y'all can understand the pressure on me to write > os.system("rm -f " + tempFileOrDirectory) instead of the current > blob of portable crap to do it. > > Come to think of it, I could write a "removeForced()" function over > "glob.glob" and "os.path.isfile". I think I'l do that first before > reading this evening's bug reports (if any ;). What's wrong with shutil.rmtree() ? -Fred -- Fred L. Drake, Jr. <fdrake at acm.org> PythonLabs at Zope Corporation |
From: Phlip <ppl...@om...> - 2002-06-06 15:49:41
|
Fred L. Drake, Jr. sez: > What's wrong with shutil.rmtree() ? What's wrong with it is I never heard of it. I'l work on this issue for a while and see if I eventually hear of it. > > The bug is 'reload(module)' often does not work. > > We need more information than this! What do you mean? Do you have a > reproducible test case? It's a general request for help, that Steve answered very specifically. If I need to reload the same way other test runners reload, then I need to ask the question in general to someone who has already covered that area. His answer was to take a snapshot of all the modules loaded before the test runner starts testing, and then to return to this state at reload time by whacking every module not in the snapshot. No further request for assistance implied. > > When a file changes I whack its self.myModule handle, and all the > > children below it in the tree and build them again. But Python's > > infamous > > Did you leave something off here? ...module import ability leaves bits of the old modules strewn around memory, as does its infamous garbage collection system. Objects created from old modules with positive reference counts remain, figuratively "next to" the ones created from new modules. -- Phlip http://www.greencheese.org/PhilosophyBrethrenThree "Nothing is more despicable than respect based on fear." -- Albert Camus |
From: Phlip <ppl...@om...> - 2002-06-04 00:15:20
|
Alexander Garden sez: > Of course, you don't want to apply that. The three added del > statements fixed the problem, the rest is included because I want to ask > questions. Thank you thank you. I will reduce the strength of db() soonest. > First, why is the whole thing wrapped up in a catch-all try/except that > does nothing when an exception is raised? I commented this out because > an exception was being raised every time. Because this code is crufty and via a colleague, a post on comp.lang.python, and the code in our private test runner that parallels the catch after the Official UnitTest.py. The throw-catch-pass was to prevent us from ever debugging this dumb code. The intent, in the testrunner, is to prevent an error-in-an-error from whacking the entire process. I vote to whack it. It simulates this in C++: #define db(x) std::cerr << __FILE__ << ':' << __LINE__ << \ ": " #x << x << std::endl You can see the C++ version has just a little bit less lines! Thanks for debugging the rest of this crud, but I un-crudded it for version 003. Please try http://flea.sourceforge.net/browser003.zip if you still have any enthusiasm left, but I should take a shift this evening. > And if you or someone else could clue me in as to why adding the > explicit del statements could fix a memory leak here, I'd appreciate it. > Maybe a 2.0 bug? I don't know why the legacy code said code.something in it. I will investigate via elimination! -- Phlip http://www.greencheese.org/SkeletonCrew "Men never do evil so completely and cheerfully as when they do it from religious conviction." -- Blaise Pascal |
From: Alexander G. <al...@in...> - 2002-06-04 02:33:22
|
On Mon, Jun 03, 2002 at 05:14:03PM -0700, Phlip wrote: > Thanks for debugging the rest of this crud, but I un-crudded it for version > 003. Please try http://flea.sourceforge.net/browser003.zip if you still have > any enthusiasm left, but I should take a shift this evening. I knew I should have gotten the latest code before debugging! But, then I wouldn't have had the fun and education of The Hunt. :) This version seems to work fine. Memory usage doubled from 6 megs to 13, but it doesn't seem to leak. One complaint: @@ -463,7 +490,7 @@ def __init__(self, folder): FolderNode.__init__(self, folder) - listage = glob.glob(os.path.join(folder, '*test*.py')) + listage = glob.glob(os.path.join(folder, '*.py')) listage.sort() I like the old line better. I commonly have a handful of helper scripts lying around in my code directory, which, because of their temporary and simple nature, don't have the body of the code wrapped up in a __name__ == '__main__' if clause. So when I ran the new browser.py, it died when importing these because sys.argv[1] was outside the range of the list. And if one of these things didn't depend on something which would break when imported, as is sometimes the case, Bad Things could happen. Also I commonly rename old files something like old.program.py, which also breaks on import because the module old.program doesn't exist. Or even better, + listage = sys.argv[1:] and let the user choose the pattern and the shell the expansion. Alexander |
From: Phlip <ppl...@om...> - 2002-06-04 02:45:24
|
Alexander Garden sez: > Phlip wrote: > > Thanks for debugging the rest of this crud, but I un-crudded it for > > version 003. Please try http://flea.sourceforge.net/browser003.zip if you > > still have any enthusiasm left, but I should take a shift this evening. > > I knew I should have gotten the latest code before debugging! But, then I > wouldn't have had the fun and education of The Hunt. :) Not at all - I'm totally indebted to you for confirming the leak was in the area that I fixed, and that I should fix it again. (Funny how these programming bug hunts can always find meaning.) > This version seems to work fine. Memory usage doubled from 6 megs to 13, > but it doesn't seem to leak. Mem pumps when we call 'reload', and we now have a test for Debug.py. So the testor is in memory, and its copy of the testee, etc. > One complaint: > @@ -463,7 +490,7 @@ > def __init__(self, folder): > FolderNode.__init__(self, folder) > > - listage = glob.glob(os.path.join(folder, '*test*.py')) > + listage = glob.glob(os.path.join(folder, '*.py')) > listage.sort() > > I like the old line better. Sorry - that one was a request by an audience member. At work, our custom testrunner enforces a totally strict naming convention. But to appeal to a mass market I have to be less narrow. I envision a browserConfig.py where one tweaks such constants by applying or removing well-commented commented code. As this is my first foray into authoring a tool others must use and patch, I note with wry amusement how you take for granted the ability to "speak in diffs". ;-) > I commonly have a handful of helper scripts > lying around in my code directory, which, because of their temporary and > simple nature, don't have the body of the code wrapped up in a __name__ > == '__main__' if clause. So when I ran the new browser.py, it died when > importing these because sys.argv[1] was outside the range of the list. A colleague stumbled over this one, and so did I when I tossed all of idlefork into a sub directory. > Or even better, > + listage = sys.argv[1:] > and let the user choose the pattern and the shell the expansion. Oookay. Now make them enter this: $ ./browser.py test\*.py The slash is not optional because we don't want your BASH or whatever to expand the *. We need to expand it for you, recursively in each sub directory. Like 'find'. I will add this last suggestion to the do-list because it subsumes all the others. -- Phlip http://www.greencheese.org/ParodyMode -- The first few lines of code must "hook" the computer, and make it "care" about the program -- |
From: Alexander G. <al...@in...> - 2002-06-04 03:40:23
|
On Mon, Jun 03, 2002 at 07:35:51PM -0700, Phlip wrote: > Alexander Garden sez: > > One complaint: > > - listage = glob.glob(os.path.join(folder, '*test*.py')) > > + listage = glob.glob(os.path.join(folder, '*.py')) > > > > I like the old line better. > > Sorry - that one was a request by an audience member. > > At work, our custom testrunner enforces a totally strict naming convention. > But to appeal to a mass market I have to be less narrow. > > I envision a browserConfig.py where one tweaks such constants by applying or > removing well-commented commented code. That would work, but it seems unobvious and cumbersome to me. Would I have to edit the file to change the pattern from the one I use to the one a colleague uses to the one some open source project uses? Ugh. That would be fine for a default, but not as the primary way. And I would like to press the point that a loose default could do damage. If I ran the latest code in some of my directories, stuff would get overwritten that I would *not* want overwritten. That would be bad. But one could blame me for that. :) It's probably a left over from my Perl habits. > As this is my first foray into authoring a tool others must use and patch, I > note with wry amusement how you take for granted the ability to "speak in > diffs". ;-) Can't imagine living without them. > > Or even better, > > + listage = sys.argv[1:] (Make that: listage = filter(lambda x: x[0] != '-', sys.argv[1:]) > > and let the user choose the pattern and the shell the expansion. > > Oookay. Now make them enter this: > > $ ./browser.py test\*.py > > The slash is not optional because we don't want your BASH or whatever to > expand the *. We need to expand it for you, recursively in each sub > directory. Like 'find'. Being a Unix guy, I'd much, much rather have the shell do the work of finding files for me. That's what it's good at. That's what it's there for, among other things. If I needed to recursively find files, I'd do $ ./browser.py `find . -name 'test*.py'` which is admittedly rather clumsy if one must type it often, but one shouldn't have to, right? :) And it is easily bound up into a shell script or alias anyway. Of course, that wouldn't work on Windows. A python wrapper script would work well enough over there, I suppose. It could work exactly as the current implementation works. It seems more flexible and cleaner to me to have the internals think in terms of a list of files and have an outer layer optionally do the conversion from directories and patterns to a file list than to build a pattern/directory thought structure into the core. If you decide to go this way, I'd be happy to help out with the refactoring. Alexander |
From: Phlip <ppl...@om...> - 2002-06-04 04:21:17
|
Alexander Garden sez: > > $ ./browser.py test\*.py > > > > The slash is not optional because we don't want your BASH or whatever to > > expand the *. We need to expand it for you, recursively in each sub > > directory. Like 'find'. > > Being a Unix guy, I'd much, much rather have the shell do the work of > finding files for me. That's what it's good at. It don't recurse. The entire point of the tree structure was to recurse; to make very large Python projects in a stack of folders testable. Deal: I will detect * on the command line (meaning you escape it so the shell did not leap at it, and meaning you didn't name your test program *.py out of perversity), and then I will accept everything on the command line and treat stars as requests to recurse and expand the stars as file globs. > That's what it's there > for, among other things. If I needed to recursively find files, I'd do > $ ./browser.py `find . -name 'test*.py'` > which is admittedly rather clumsy if one must type it often, but one > shouldn't have to, right? :) And it is easily bound up into a shell > script or alias anyway. That would not work, directly, because browser.py would prefer to find the folders itself so it can construct its tree; with the '.' node to mean "test this folder but not the sub-folders." But it would work with my proposed tweak because the sought files would go in as individual files in a long list at the root level. > It seems more flexible and cleaner to me to have the internals think in > terms of a list of files and have an outer layer optionally do the > conversion from directories and patterns to a file list than to build a > pattern/directory thought structure into the core. If you decide to go > this way, I'd be happy to help out with the refactoring. Let me catch up first! ;-) Then I will refactor the long list at the root level into a merged folder structure. -- Phlip http://www.greencheese.org/PhilosophyBrethrenThree -- Appears that VIM is internationalized... May I ask what's the point? -- |
From: Steve P. <ste...@ya...> - 2002-06-04 06:11:11
|
Alexander Garden wrote: > > The slash is not optional because we don't want your BASH or whatever to > > expand the *. We need to expand it for you, recursively in each sub > > directory. Like 'find'. > > Being a Unix guy, I'd much, much rather have the shell do the work of > finding files for me. That's what it's good at. That's what it's there > for, among other things. If I needed to recursively find files, I'd do > $ ./browser.py `find . -name 'test*.py'` > which is admittedly rather clumsy if one must type it often, but one > shouldn't have to, right? :) And it is easily bound up into a shell > script or alias anyway. I second that. On UNIX, scripts shouldn't be doing any globbing themselves. Better explicit than implicit, etc. etc. And on a practical note, the more magic is in a script, the more bugs and maintenance issues appear later. (Perl, anyone? :-) -Steve |