GithubHelp home page GithubHelp logo

erikrose / nose-progressive Goto Github PK

View Code? Open in Web Editor NEW
112.0 7.0 39.0 442 KB

A nosetests plugin with a progress bar and an emphasis on showing what's important

Home Page: http://pypi.python.org/pypi/nose-progressive/

License: MIT License

Python 100.00%

nose-progressive's Introduction

nose-progressive

Give your tests a progress bar and smarter tracebacks in 3 lines:

pip install nose-progressive
cd your_project
nosetests --with-progressive

https://github.com/erikrose/nose-progressive/raw/master/in_progress.png

nose-progressive is a nose plugin which displays progress in a stationary bar, freeing the rest of the screen (as well as the scrollback buffer) for the compact display of test failures, which it formats beautifully and usefully. It displays failures and errors as soon as they occur and avoids scrolling them off the screen in favor of less useful output. It also offers a number of other human-centric features to speed the debugging process.

The governing philosophy of nose-progressive is to get useful information onto the screen as soon as possible and keep it there as long as possible while still indicating progress.

Features

Progress Bar

nose-progressive indicates progress in a stationary progress bar at the bottom of the screen. It supports a wide variety of terminal types and reacts to terminal resizing with all the grace it can muster. And unlike with the standard dot-strewing testrunner, you can always see what test is running.

Tracebacks: Prompt, Pretty, and Practical

nose, like most testrunners, typically waits until the bitter end to show error and failure tracebacks, which wastes a lot of time in large tests suites that take many minutes to complete. We show tracebacks as soon as they occur so you can start chasing them immediately, and we format them much better:

  • Judicious use of color and other formatting makes the traceback easy to scan. It's especially easy to slide down the list of function names to keep your place while debugging.

  • Omitting the Traceback (most recent call last) line and using relative paths (optional), along with many other tweaks, fits much more in limited screen space.

  • Identifying failed tests in a format that can be fed back to nose makes it easy to re-run them:

    FAIL: kitsune.apps.wiki.tests.test_parser:TestWikiVideo.test_video_english
    

    To re-run the above, do this:

    nosetests --with-progressive kitsune.apps.wiki.tests.test_parser:TestWikiVideo.test_video_english
    
  • The frame of the test itself always comes first; we skip any setup frames from test harnesses and such. This keeps your concentration where it counts. Also, like unittest itself, we hide any frames that descend into trivial comparison helpers like assertEquals() or assertRaises().

    (We're actually better at it than unittest. We don't just start hiding frames at the first unittest one after the test; we snip off only the last contiguous run of unittest frames. This lets you wrap your tests in the decorators from the mock library, which masquerades as unittest, and still see your tracebacks.)

  • Editor shortcuts (see below) let you jump right to any problem line in your editor.

Editor Shortcuts

For each frame of a traceback, nose-progressive provides an editor shortcut. This is a combination of a filesystem path and line number in a format understood by vi, emacs, the BBEdit command-line tool, and a number of other editors:

vi +361 apps/notifications/tests.py  # test_notification_completeness

Just triple-click (or what have you) to select the line, and copy and paste it onto the command line. You'll land right at the offending line in your editor of choice. As a bonus, the editor shortcut is more compact than the stock traceback formatting.

You can set which editor to use by setting any of these, which nose-progressive checks in order:

  • The --progressive-editor commandline option
  • The NOSE_PROGRESSIVE_EDITOR environment variable
  • The $EDITOR environment variable

Custom Error Classes

nose-progressive fully supports custom error classes like Skip and Deprecated. We note the tests that raise them in realtime, just like normal errors and failures:

TODO: kitsune.apps.sumo.tests.test_readonly:ReadOnlyModeTest.test_login_error

However, when an error class is not considered a failure, we don't show it unless the --progressive-advisories option is used, and, even in that case, we don't show a traceback (since usually the important bit of information is that the test was skipped, not the line it was skipped on). This stems from our philosophy of prioritizing useful information.

Custom error classes are summarized in the counts after the run, along with failures and errors:

4 tests, 1 failure, 1 error, 1 skip in 0.0s
         ^^^^^^ Bold ^^^^^^

The non-zero counts of error classes that represent failures are bold to draw the eye and to correspond with the bold details up in the scrollback. Just follow the bold, and you'll find your bugs.

Django Support

nose-progressive can run your Django tests via django-nose. Just install django-nose, then run your tests like so:

./manage.py test --with-progressive --logging-clear-handlers

Installation

pip install nose-progressive

Or, get the bleeding-edge, unreleased version:

pip install -e git://github.com/erikrose/nose-progressive.git#egg=nose-progressive

Upgrading

To upgrade from an older version of nose-progressive, assuming you didn't install it from git:

pip install --upgrade nose-progressive

Use

The simple way:

nosetests --with-progressive

My favorite way, which suppresses any noisy log messages thrown by tests unless they fail:

nosetests --with-progressive --logging-clear-handlers

To use nose-progressive by default, add with-progressive=1 to .noserc.

Options

General Options

--progressive-editor
The editor to use for the shortcuts in tracebacks. Defaults to the value of $EDITOR and then "vi". Equivalent environment variable: NOSE_PROGRESSIVE_EDITOR.
--progressive-abs
Display paths in traceback as absolute, rather than relative to the current working directory. This lets you copy and paste it to a shell in a different cwd or to another program entirely. Equivalent environment variable: NOSE_PROGRESSIVE_ABSOLUTE_PATHS.
--progressive-advisories
Show even non-failure custom errors, like Skip and Deprecated, during test runs. Equivalent environment variable: NOSE_PROGRESSIVE_ADVISORIES.
--progressive-with-styling
nose-progressive automatically omits bold and color formatting when its output is directed to a non- terminal. Specifying --progressive-with-styling forces such styling to be output regardless. Equivalent environment variable: NOSE_PROGRESSIVE_WITH_STYLING.
--progressive-with-bar
nose-progressive automatically omits the progress bar when its output is directed to a non-terminal. Specifying --progressive-with-bar forces the bar to be output regardless. This option implies --progressive-with-styling. Equivalent environment variable: NOSE_PROGRESSIVE_WITH_BAR.

Color Options

Each of these takes an ANSI color expressed as a number from 0 to 15.

--progressive-function-color=<0..15>
Color of function names in tracebacks. Equivalent environment variable: NOSE_PROGRESSIVE_FUNCTION_COLOR.
--progressive-dim-color=<0..15>
Color of de-emphasized text (like editor shortcuts) in tracebacks. Equivalent environment variable: NOSE_PROGRESSIVE_DIM_COLOR.
--progressive-bar-filled=<0..15>
Color of the progress bar's filled portion. Equivalent environment variable: NOSE_PROGRESSIVE_BAR_FILLED_COLOR.
--progressive-bar-empty=<0..15>
Color of the progress bar's empty portion. Equivalent environment variable: NOSE_PROGRESSIVE_BAR_EMPTY_COLOR.

Advanced Formatting

If you can't get what you want with the above options—for example, if your editor needs a different line number syntax—you can replace the entire template that controls the editor shortcut lines of the traceback. You can even rig clickable URLs in most terminals that take you straight to the right line in your editor, without even the bother of copy and paste.

--progressive-editor-shortcut-template='<template>'
<template> is a format string as accepted by str.format(). Equivalent environment variable: NOSE_PROGRESSIVE_EDITOR_SHORTCUT_TEMPLATE.

The default template is...

'  {dim_format}{editor} +{line_number:<{line_number_max_width}} {path}{normal}{function_format}{hash_if_function}{function}{normal}'

Here are the available keys:

dim_format A terminal formatting sequence for de-emphasized text. Affected by --progressive-dim-color.
editor Your editor, set through --progressive-editor and $EDITOR
function The name of the function referenced by this stack frame
function_format A terminal formatting sequence for the function name. Affected by --progressive-function-color.
hash_if_function ' # ' if this frame has a function with a name; empty otherwise. Useful for commenting out the function name at the end of a line.
line_number The line number of the instruction this stack frame references
line_number_max_width The maximum width, in characters, of the line numbers in the traceback currently being formatted. Useful for aligning columns.
normal A terminal escape sequence that turns off all special formatting. A shortcut for term.normal.
path The path to the file this stack frame references. Affected by --progressive-abs.
term A blessings Terminal object, through which you can access any terminal capability, even compound ones such as term.bold_blue_on_bright_red. This is your escape hatch to wild and crazy things beyond mere colors.

Caveats and Known Bugs

  • Makes a cosmetic mess when used with ipdb. Consider pdbpp instead.
  • Some logging handlers will smear bits of the progress bar upward if they don't print complete lines. I hope to fix this with some monkeypatching, but in the meantime, passing --logging-clear-handlers works around this.

Having trouble? Pop over to the issue tracker.

Kudos

Thanks to Kumar McMillan for his nose-nicedots plugin, which provided inspiration and starting points for the path formatting. Thanks to my support.mozilla.com teammates for writing so many tests that this became necessary. Thanks to Jeff Balogh for django-nose, without which I would have had little motivation to write this.

Author

Erik Rose, while waiting for tests to complete ;-)

Version History

1.5.2
  • Handle KeyboardInterrupt more gracefully. (Alexander Artemenko)
  • Look up exception messages more compatibly with Python 3.4. (Paul Weaver)
  • Gracefully handle proxied SyntaxErrors when using the logcapture plugin. (Lucas Taylor)
  • Add LICENSE to MANIFEST.in. (Sanny Kumar)
1.5.1
  • Avoid a TypeError when running nose-progressive from within invoke, which obscures the terminal size.
  • Fix a Unicode error when running setup.py inside Fedora's mock tool.
1.5
  • Add the --progressive-editor-shortcut-template option, letting you completely customize the editor shortcuts. Now we support any text editor that has a go-to-line option, no matter how it's spelled.
  • Drop support for Python 2.5. We needed modern string formatting.
  • Add first-class support for Python 3.2.3 and higher. It turned out my tox config was just wrong.
  • Tolerate Nones in traceback components: file names and code extracts particularly. (Kyle Gibson)
1.4.3
  • Fix bar not showing up in Python 3.
  • Add honest-to-goodness, tox-tested support for Python 3.3. 3.2 may come later. 3.1 and earlier won't, because its stdlib hadn't got its curses act together yet.
1.4.2
  • Clear the TestLoader's path cache (new in nose 1.3.0) after counting the tests. This solves the problem of finding 0 tests to run under nose 1.3.0.
  • Make progress bar tests less brittle so they don't falsely fail on OS X 10.8 or other platforms where the terminfo isn't exactly what I wrote the test under.
1.4.1
  • Fix the "AttributeError: 'dict' object has no attribute 'raw_input'" error that sometimes occurred at pdb breakpoints. Thanks to David Baumgold for finding the cause!
1.4
  • Make the final "OK!" green and bold. This helps me pick it out faster.
  • Warn when using --with-id and --verbosity=2 or higher. (Jason Ward)
  • Add experimental Python 3 support. Functionality might work, but tests need to be ported to pass.
  • Allow other nose plugins to process the test loader. (Ratnadeep Debnath)
  • Show parameter values in the names of generated tests. (Bruno Binet)
  • Tolerate a corner case in skipped tests without crashing. (Will Kahn-Greene)
  • Swallow chars that don't decode with UTF-8 when printing tracebacks: both in filenames and source code. (Thanks to Bruno Binet for some patches inspiring a rethink here.)
1.3
  • Redo progress bar. Now it is made of beautiful terminal magic instead of equal signs. It looks best when your terminal supports at least 16 colors, but there's a monochrome fallback for fewer. Or, you can customize the colors using several new command-line options.
  • Fix a Unicode encoding error that happened when non-ASCII chars appeared in traceback text. (Naoya INADA)
1.2.1
  • Tolerate empty tracebacks in the formatter. This avoids exacerbating crashes that occur before any test frames.
1.2
  • Fix Python 2.5 support. (David Warde-Farley)
  • Fix display of skipped tests in Python 2.7.
  • Require nose 0.11.0 or greater. Before that, test counting didn't work sometimes when test generators were involved. (David Warde-Farley)
  • Hide the progress bar by default when not outputting to a terminal. This lets you redirect nose-progressive's output to a file or another process and get a nice list of tracebacks.
  • Add an option for forcing the display of terminal formatting, even when redirecting the output to a non-terminal.
  • Factor out the terminal formatting library into its own package.
  • Start using tox for testing under multiple versions of Python.
1.1.1
  • Fix a bug that would cause the formatter to crash on many SyntaxErrors. This also improves the heuristics for identifying the test frame when there's a SyntaxError: we can now find it as long as the error happens at a frame below that of the test.
1.1
  • You can now set the editor nose-progressive uses separately from the $EDITOR shell variable.
1.0
  • Every stack frame is now an editor shortcut. Not only does this make it easier to navigate, but it's shorter in both height and width.
  • Reformat tracebacks for great justice. Subtle coloring guides the eye down the list of function names.
  • Hide unittest-internal and other pre-test stack frames when printing tracebacks. Fewer frames = less noise onscreen = less thinking = win!
  • Add an option to use absolute paths in tracebacks.
0.7
  • Pick the correct stack frame for editor shortcuts to syntax errors. Had to handle syntax errors specially, since they don't make it into the traceback proper.
  • Show the actual value of the $EDITOR env var rather than just "$EDITOR". I'm hoping it makes it a little more obvious what to do with it, plus it gives a working default if $EDITOR is not set. Plus plus it doesn't explode if you have flags in your $EDITOR, e.g. bbedit -w.
0.6.1
  • Fix a crash triggered by a test having no defined module. --failed should always work now.
0.6
  • Major refactoring. nose-progressive now has its own testrunner and test result class. This makes it fully compatible with the capture plugin and other plugins that make output.
  • Fully support custom error classes, like Skips and Deprecations. They are printed during the test run, bolded if they represent failure, and summarized in the counts after the run.
  • Tests which write directly to stderr or stdout no longer smear the progress bar.
  • Add $EDITOR to editor shortcut: no more typing!
  • Work with tests that don't have an address() method.
  • Work with tests that return a null filename from test_address().
  • Don't pave over pdb prompts (anymore?).
  • Don't obscure the traceback when the @with_setup decorator on a test generator fails.
0.5.1
  • Fix a crash on error when file of a stack frame or function of a test are None.
0.5
  • Guess the frame of the test, and spit that out as the editor shortcut. No more pointers to eq_()!
  • More reliably determine the editor shortcut pathname, e.g. when running tests from an egg distribution directory.
  • Embolden bits of the summary that indicate errors or failures.
0.4
  • Add time elapsed to the final summary.
  • Print "OK!" if no tests went ill. I seem to need this explicit affirmation in order to avoid thinking after a test run.
  • In the test failure output, switch the order of the line number and file name. This makes it work with the BBEdit command-line tool in addition to emacs and vi.
0.3.1
  • Cowboy attempt to fix a crasher on error by changing the entry_point to nose.plugin.0.10
0.3
  • Progress bar now works with plain old nosetests, not just django-nose. Sorry about that!
  • Stop printing the test name twice in the progress bar.
  • Add basic terminal resizing (SIGWINCH) support. Expanding is great, but contracting is still a little ugly. Suggestions welcome.
0.2
  • Real progress bar!
  • Don't crash at the end when --no-skips is passed.
  • Print the exception, not just the traceback. That's kind of important. :-)
  • Don't crash when a requested test doesn't exist.
0.1.2
  • More documentation tweaks. Package long_description now contains README.
0.1.1
  • Add instructions for installing without git.
  • Change package name in readme to the hypenated one. No behavior changes.
0.1
  • Initial release

nose-progressive's People

Contributors

bbinet avatar danc86 avatar dwf avatar erikrose avatar hfaran avatar ltvolks avatar msabramo avatar naoina avatar sannykr avatar svetlyak40wt avatar willkg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

nose-progressive's Issues

Don't print the bar a million times if nose crashes

If you control-C a test run in the middle, a traceback prints. However, stdout is still wrapped in the bar-dodging, so you get a new progress bar after ever line of the traceback. Unwrap it or something.

add ability to not show the test name

I often appreciate that nose-progressive is showing me the test name, however when testing even modestly sized numpy arrays using test generators i have to go back to using regular old ugly nose since there's now a huge amount test name garbage. it would be great to be able to turn off showing the name or just limit its output to some small number of characters

progressive don't play well with nose.plugin.multiprocess

progressive can only run test sequentially, it seems.

--processes=8--with-progressive
50 tests [...] in 53.6s

--processes=8
[...] 50 tests in 13.544s

I am using nose 1.1.2 and nose-progressive 0.7, tests are run with django-nose.

When there are no non-unittest frames, deal.

Sometimes, stuff crashes before we even get to the test. pdbpp has been doing this a lot to me lately. When that happens, this does too:

  bbedit +53  /Users/erose/Checkouts/nose-progress/noseprogressive/tracebacks.py  # format_traceback
    line_width = len(str(max(the_line for _, the_line, _, _ in extracted_tb)))
ValueError: max() arg is an empty sequence

Don't do that.

Enable progressive with environment variable

I get tired of remembering to use --with-progress, and the fact that I want to use the progressive runner is based on my user preferences (and possibly my OS), so specifying it in each project's .nosecfg seems wrong to me.

So can we add environment-variable activation that I can set in my user profile? e.g. NOSE_USE_PROGRESSIVE=1

(or maybe NODE_PROGRESSIVE_ENABLE=1 to keep the same format as other vars)

Discovery breaks when excluding tests

We have a modified version of django-nose, and we override things like "wantMethod", and sometimes return False. If that statement is hit, it causes progressive to discover no tests. Removing the return False statements allows progressive to work correctly.

e.g. we have code like this in our plugin:

    def wantClass(self, cls):
        if issubclass(cls, TransactionTestCase):
            self.needs_db = True

        if cls in self._registry:
            return False
        self._registry.add(cls)

    def wantMethod(self, method):
        if issubclass(method.im_class, TransactionTestCase):
            self.needs_db = True

        if method in self._registry:
            return False
        self._registry.add(method)

    def wantFunction(self, function):
        if function in self._registry:
            return False
        self._registry.add(function)

Change bar colour on failure

In the spirit of red-green-refactor, I'd like to get a clear visual indicator that there's been a failure.

It would be good if the entire progress bar could change red (or, presumably, a colour of my choosing) when a failure/error occurs during the run.

(P.S. I love nose-progressive, keep up the great work!)

add --progressive-without-bar flag

for whatever reason, nose-progressive isn't identifying my environment as one that it should automatically turn off the progress bar. i would like to be able to keep the failures / exceptions during the run and force the progress bar to be turned off.

Test path wrong for some functions

For a module-level function within a module in a tests package, nose-progressive reports a test path of tests.test_scope.test_other_modules, where it should be tests.test_scope:test_other_modules (with a colon).

Running tests --with-progressive results in no tests

When I run the tests normally:

$ nosetests
......................
----------------------------------------------------------------------
Ran 22 tests in 0.139s

OK

Then when I run it with the plugin:

$ nosetests --with-progressive

0 tests, 0 failures, 0 errors, 0 skips

This was with version 0.2

Move AtLine to terminal.py

Before breaking off terminal.py into its own package, put AtLine and any other useful context managers in there. And make AtLine take a horizontal position, too, not just a line number. Call it At or something.

--progressive-with-bar shits itself when run through invoke

I'm starting to use invoke now for
running oft-repeated tasks, rather than using make, rake, or shell scripts.
Right now, I've got a pretty basic file - it just runs my tests:

[$]> cat tasks.py
from invoke import run, task

@task
def test():
   run("nosetests --with-progressive --progressive-with-bar tests")

When I run it like this, I get some ugly errors:

[$]> invoke test

ERROR: tests.test_category:CategoryTest.test_categories
  /usr/bin/vim +133 env/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  /usr/bin/vim +151 env/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  /usr/bin/vim +376 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  /usr/bin/vim +295 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # run
    result.startTest(self)
  /usr/bin/vim +170 env/lib/python2.7/site-packages/nose/proxy.py  # startTest
    self.result.startTest(self.test)
  /usr/bin/vim +44  env/lib/python2.7/site-packages/noseprogressive/result.py  # startTest
    self.bar.update(nose_selector(test), self.testsRun)
  /usr/bin/vim +61  env/lib/python2.7/site-packages/noseprogressive/bar.py  # update
    cols_for_path = self.cols - GRAPH_WIDTH - 2  # 2 spaces between path & graph
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

ERROR: tests.test_category:CategoryTest.test_description
  /usr/bin/vim +133 env/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  /usr/bin/vim +151 env/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  /usr/bin/vim +376 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  /usr/bin/vim +295 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # run
    result.startTest(self)
  /usr/bin/vim +170 env/lib/python2.7/site-packages/nose/proxy.py  # startTest
    self.result.startTest(self.test)
  /usr/bin/vim +44  env/lib/python2.7/site-packages/noseprogressive/result.py  # startTest
    self.bar.update(nose_selector(test), self.testsRun)
  /usr/bin/vim +61  env/lib/python2.7/site-packages/noseprogressive/bar.py  # update
    cols_for_path = self.cols - GRAPH_WIDTH - 2  # 2 spaces between path & graph
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

ERROR: tests.test_category:CategoryTest.test_locale
  /usr/bin/vim +133 env/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  /usr/bin/vim +151 env/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  /usr/bin/vim +376 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  /usr/bin/vim +295 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # run
    result.startTest(self)
  /usr/bin/vim +170 env/lib/python2.7/site-packages/nose/proxy.py  # startTest
    self.result.startTest(self.test)
  /usr/bin/vim +44  env/lib/python2.7/site-packages/noseprogressive/result.py  # startTest
    self.bar.update(nose_selector(test), self.testsRun)
  /usr/bin/vim +61  env/lib/python2.7/site-packages/noseprogressive/bar.py  # update
    cols_for_path = self.cols - GRAPH_WIDTH - 2  # 2 spaces between path & graph
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

ERROR: tests.test_category:CategoryTest.test_name
  /usr/bin/vim +133 env/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  /usr/bin/vim +151 env/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  /usr/bin/vim +376 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  /usr/bin/vim +295 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # run
    result.startTest(self)
  /usr/bin/vim +170 env/lib/python2.7/site-packages/nose/proxy.py  # startTest
    self.result.startTest(self.test)
  /usr/bin/vim +44  env/lib/python2.7/site-packages/noseprogressive/result.py  # startTest
    self.bar.update(nose_selector(test), self.testsRun)
  /usr/bin/vim +61  env/lib/python2.7/site-packages/noseprogressive/bar.py  # update
    cols_for_path = self.cols - GRAPH_WIDTH - 2  # 2 spaces between path & graph
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

ERROR: tests.test_category:CategoryTest.test_title
  /usr/bin/vim +133 env/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  /usr/bin/vim +151 env/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  /usr/bin/vim +376 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  /usr/bin/vim +295 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # run
    result.startTest(self)
  /usr/bin/vim +170 env/lib/python2.7/site-packages/nose/proxy.py  # startTest
    self.result.startTest(self.test)
  /usr/bin/vim +44  env/lib/python2.7/site-packages/noseprogressive/result.py  # startTest
    self.bar.update(nose_selector(test), self.testsRun)
  /usr/bin/vim +61  env/lib/python2.7/site-packages/noseprogressive/bar.py  # update
    cols_for_path = self.cols - GRAPH_WIDTH - 2  # 2 spaces between path & graph
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

ERROR: tests.test_guide:GuideTest.test_category
  /usr/bin/vim +133 env/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  /usr/bin/vim +151 env/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  /usr/bin/vim +376 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  /usr/bin/vim +295 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # run
    result.startTest(self)
  /usr/bin/vim +170 env/lib/python2.7/site-packages/nose/proxy.py  # startTest
    self.result.startTest(self.test)
  /usr/bin/vim +44  env/lib/python2.7/site-packages/noseprogressive/result.py  # startTest
    self.bar.update(nose_selector(test), self.testsRun)
  /usr/bin/vim +61  env/lib/python2.7/site-packages/noseprogressive/bar.py  # update
    cols_for_path = self.cols - GRAPH_WIDTH - 2  # 2 spaces between path & graph
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

ERROR: tests.test_guide:GuideTest.test_difficulty
  /usr/bin/vim +133 env/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  /usr/bin/vim +151 env/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  /usr/bin/vim +376 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  /usr/bin/vim +295 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # run
    result.startTest(self)
  /usr/bin/vim +170 env/lib/python2.7/site-packages/nose/proxy.py  # startTest
    self.result.startTest(self.test)
  /usr/bin/vim +44  env/lib/python2.7/site-packages/noseprogressive/result.py  # startTest
    self.bar.update(nose_selector(test), self.testsRun)
  /usr/bin/vim +61  env/lib/python2.7/site-packages/noseprogressive/bar.py  # update
    cols_for_path = self.cols - GRAPH_WIDTH - 2  # 2 spaces between path & graph
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

ERROR: tests.test_guide:GuideTest.test_locale
  /usr/bin/vim +133 env/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  /usr/bin/vim +151 env/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  /usr/bin/vim +376 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  /usr/bin/vim +295 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # run
    result.startTest(self)
  /usr/bin/vim +170 env/lib/python2.7/site-packages/nose/proxy.py  # startTest
    self.result.startTest(self.test)
  /usr/bin/vim +44  env/lib/python2.7/site-packages/noseprogressive/result.py  # startTest
    self.bar.update(nose_selector(test), self.testsRun)
  /usr/bin/vim +61  env/lib/python2.7/site-packages/noseprogressive/bar.py  # update
    cols_for_path = self.cols - GRAPH_WIDTH - 2  # 2 spaces between path & graph
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

ERROR: tests.test_guide:GuideTest.test_public
  /usr/bin/vim +133 env/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  /usr/bin/vim +151 env/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  /usr/bin/vim +376 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  /usr/bin/vim +295 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # run
    result.startTest(self)
  /usr/bin/vim +170 env/lib/python2.7/site-packages/nose/proxy.py  # startTest
    self.result.startTest(self.test)
  /usr/bin/vim +44  env/lib/python2.7/site-packages/noseprogressive/result.py  # startTest
    self.bar.update(nose_selector(test), self.testsRun)
  /usr/bin/vim +61  env/lib/python2.7/site-packages/noseprogressive/bar.py  # update
    cols_for_path = self.cols - GRAPH_WIDTH - 2  # 2 spaces between path & graph
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

ERROR: tests.test_guide:GuideTest.test_revision
  /usr/bin/vim +133 env/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  /usr/bin/vim +151 env/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  /usr/bin/vim +376 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  /usr/bin/vim +295 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # run
    result.startTest(self)
  /usr/bin/vim +170 env/lib/python2.7/site-packages/nose/proxy.py  # startTest
    self.result.startTest(self.test)
  /usr/bin/vim +44  env/lib/python2.7/site-packages/noseprogressive/result.py  # startTest
    self.bar.update(nose_selector(test), self.testsRun)
  /usr/bin/vim +61  env/lib/python2.7/site-packages/noseprogressive/bar.py  # update
    cols_for_path = self.cols - GRAPH_WIDTH - 2  # 2 spaces between path & graph
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

ERROR: tests.test_guide:GuideTest.test_subject
  /usr/bin/vim +133 env/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  /usr/bin/vim +151 env/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  /usr/bin/vim +376 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  /usr/bin/vim +295 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # run
    result.startTest(self)
  /usr/bin/vim +170 env/lib/python2.7/site-packages/nose/proxy.py  # startTest
    self.result.startTest(self.test)
  /usr/bin/vim +44  env/lib/python2.7/site-packages/noseprogressive/result.py  # startTest
    self.bar.update(nose_selector(test), self.testsRun)
  /usr/bin/vim +61  env/lib/python2.7/site-packages/noseprogressive/bar.py  # update
    cols_for_path = self.cols - GRAPH_WIDTH - 2  # 2 spaces between path & graph
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

ERROR: tests.test_guide:GuideTest.test_title
  /usr/bin/vim +133 env/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  /usr/bin/vim +151 env/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  /usr/bin/vim +376 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  /usr/bin/vim +295 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # run
    result.startTest(self)
  /usr/bin/vim +170 env/lib/python2.7/site-packages/nose/proxy.py  # startTest
    self.result.startTest(self.test)
  /usr/bin/vim +44  env/lib/python2.7/site-packages/noseprogressive/result.py  # startTest
    self.bar.update(nose_selector(test), self.testsRun)
  /usr/bin/vim +61  env/lib/python2.7/site-packages/noseprogressive/bar.py  # update
    cols_for_path = self.cols - GRAPH_WIDTH - 2  # 2 spaces between path & graph
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

ERROR: tests.test_guide:GuideTest.test_type
  /usr/bin/vim +133 env/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  /usr/bin/vim +151 env/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  /usr/bin/vim +376 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  /usr/bin/vim +295 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # run
    result.startTest(self)
  /usr/bin/vim +170 env/lib/python2.7/site-packages/nose/proxy.py  # startTest
    self.result.startTest(self.test)
  /usr/bin/vim +44  env/lib/python2.7/site-packages/noseprogressive/result.py  # startTest
    self.bar.update(nose_selector(test), self.testsRun)
  /usr/bin/vim +61  env/lib/python2.7/site-packages/noseprogressive/bar.py  # update
    cols_for_path = self.cols - GRAPH_WIDTH - 2  # 2 spaces between path & graph
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

ERROR: tests.test_guide:GuideTest.test_url
  /usr/bin/vim +133 env/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  /usr/bin/vim +151 env/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  /usr/bin/vim +376 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  /usr/bin/vim +295 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py  # run
    result.startTest(self)
  /usr/bin/vim +170 env/lib/python2.7/site-packages/nose/proxy.py  # startTest
    self.result.startTest(self.test)
  /usr/bin/vim +44  env/lib/python2.7/site-packages/noseprogressive/result.py  # startTest
    self.bar.update(nose_selector(test), self.testsRun)
  /usr/bin/vim +61  env/lib/python2.7/site-packages/noseprogressive/bar.py  # update
    cols_for_path = self.cols - GRAPH_WIDTH - 2  # 2 spaces between path & graph
TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

14 tests, 0 failures, 14 errors in 0.1s

Running that same command directly in my terminal works as expected. Running
without --progress-with-bar has no errors, but also no progress bar.

Here's what I've got installed:

[$]> pip freeze
blessings==1.5
distribute==0.6.27
nose==1.3.0
nose-progressive==1.5
requests==1.2.0
[$]> python --version
Python 2.7.1
[$]> uname -a
Darwin geror 11.4.2 Darwin Kernel Version 11.4.2: Thu Aug 23 16:25:48 PDT 2012; root:xnu-1699.32.7~1/RELEASE_X86_64 x86_64

I don't know if this is a nose-progressive issue, or a nose issue, or an invoke
issue; if you can tell me it's not your fault and point me elsewhere, I'd be
glad to go report it to the responsible party.

AttributeError: 'dict' object has no attribute 'raw_input'

ERROR: mkt.api.tests.test_handlers:TestFeaturedHomeHandler.test_verbs
vim +816 mkt/api/tests/test_handlers.py # setUp
import pdb; pdb.set_trace()
vim +50 /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/bdb.py # trace_dispatch
return self.dispatch_return(frame, arg)
vim +83 /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/bdb.py # dispatch_return
self.user_return(frame, arg)
vim +178 /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/pdb.py # user_return
self.interaction(frame, None)
vim +198 /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/pdb.py # interaction
self.cmdloop()
vim +33 /Users/rob/.virtualenvs/zamboni/lib/python2.6/site-packages/noseprogressive/wrapping.py # cmdloop
builtins.raw_input = unwrapping_raw_input
AttributeError: 'dict' object has no attribute 'raw_input'

Make reduced functionality available on Windows

I would love to use nose-progressive to format tracebacks in a way that MS Visual Studio understands to allow jumping directly to the right line in the source file.

My problem is that nose-progressive requires imports that are not available on Windows:
curses can be found as a binary distribution but fcntl can really not be ported.

Any chance of putting these imports in a try statement and reducing functionality as required, e.g. to begin with to just formatting the editor shortcuts?

Editor shortcuts for every frame

Python's default traceback formatting is noisy. Why not provide an editor shortcut for each frame? It's actually shorter, plus it lends itself to columnization, which would make it easier to scan. We could eliminate the dedicated editor shortcut, saving a line, and indicate the suggested frame with bold:

FAIL: dashboards.tests.test_readouts:MostVisitedTranslationsTests.test_unreviewed
  bbedit +279  /opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py  # run
    testMethod()
  bbedit  +75  /Users/erose/Checkouts/kitsune/apps/dashboards/tests/test_readouts.py  # test_unreviewed
  ^^^^^^^^^^^^^^^^^^^^^^^^^^BOLD^^^^^^^^^^^^^^^^^^^
    eq_(row['status'], "smoo")
  bbedit  +31  /Users/erose/Checkouts/kitsune/vendor/packages/nose/nose/tools.py      # eq_
    assert a == b, msg or "%r != %r" % (a, b)
AssertionError: u'' != 'smoo'

test_skip fails under Python 2.7

FAIL: noseprogressive.tests.test_integration:AdvisoryShowingTests.test_skip
  bbedit +72 tests/test_integration.py  # test_skip
    self._count_eq('SKIP: ', 1)
  bbedit +17 tests/test_integration.py  # _count_eq
    eq_(str(self.output).count(text), count)
  bbedit +31 /Users/erose/Virtualenvs/noseprogressive/lib/python2.7/site-packages/nose/tools.py  # eq_
    assert a == b, msg or "%r != %r" % (a, b)
AssertionError: 0 != 1

Hide leading nose stack frames

Like the unittest ones, hide the nose ones. They appear when you have top-level functions that are tests, like this:

FAIL: tests.tests:test_querying_fields
  bbedit +197 /Users/erose/Virtualenvs/elasticutils/lib/python2.6/site-packages/nose/case.py  # runTest
    self.test(*self.arg)
  bbedit +118 tests/tests.py  # test_querying_fields
    eq_(implicit._build_query(), explicit._build_query())
  bbedit +31  /Users/erose/Virtualenvs/elasticutils/lib/python2.6/site-packages/nose/tools.py  # eq_
    assert a == b, msg or "%r != %r" % (a, b)

We're smart enough to find the test frame to highlight it, so let's just skip everything before that and save screen space and reading. We should make the frame guesser more conservative, as right now it defaults to the last frame.

"TypeError: expected a character buffer object" on skipped tests

I enabled --progressive-advisories and I was expecting to see the Skip reasons being logged. Instead I'm getting a different kind of exception for each skipped test:

DEPRECATED: tests.embvt.integration.icontrol.icproxy:Tests.test_12_node_create

ERROR: tests.embvt.integration.icontrol.icproxy:Tests.test_12_node_create
  /bin/nano +133 develop-eggs/nose-1.1.2-py2.7.egg/nose/case.py  # run
    self.runTest(result, blocked)
  /bin/nano +156 develop-eggs/nose-1.1.2-py2.7.egg/nose/case.py  # runTest
    test(result)
  /bin/nano +398 eggs/unittest2-0.5.1-py2.7.egg/unittest2/case.py  # __call__
    return self.run(*args, **kwds)
  /bin/nano +360 eggs/unittest2-0.5.1-py2.7.egg/unittest2/case.py  # run
    self._addSkip(result, str(e))
  /bin/nano +301 eggs/unittest2-0.5.1-py2.7.egg/unittest2/case.py  # _addSkip
    addSkip(self, reason)
  /bin/nano +163 develop-eggs/nose-1.1.2-py2.7.egg/nose/proxy.py  # addSkip
    self.result.addSkip(self.test, reason)
  /bin/nano +143 eggs/nose_progressive-1.3-py2.7.egg/noseprogressive/result.py  # addSkip
    self.stream.writeln(reason)
  /bin/nano +24  /usr/lib64/python2.7/unittest/runner.py  # writeln
    self.write(arg)
TypeError: expected a character buffer object

Hide progress bar in ipdb

ipdb must bring its own cmdloop or something, because the progress bar prints over the prompt. (If you're using ipdb, I humbly recommend pdbpp, which has a superset of its functionality and doesn't crash into the progress bar.)

Option to disable terminal formatting

Things like bold and colors don't always survive in all terminal types or behave nicely through pipes. An option to disable those would not go amiss

Use tox

…to test under multiple versions of Python. It would have caught the 2.5 and the 2.7 bugs that were just discovered.

Clarify license

Hi Erik,

From what I can see at the moment, nose-progressive's license is limited the single mention of "GPL" here. This makes legitimately reusing your code difficult as GPL version isn't specified (whether it is v2 or v3), nor is the license distributed with nose-progressive.

Unless you are adamant you would like this released under GPL, I would implore you to switch to the MIT License for the same reasons you discussed in blessings.

If you would like, I would be more than happy to make the pull request for you (for either MIT, GPL v2/v3, or whatever license you would like).

Look forward to hearing from you on this,
Thanks!

Yet another None in test path

...most likely.

How it's supposed to be:

(kitsune)[paulc (upgrade-django-634345) kitsune]$ ./manage.py test gallery.tests.test_views
nosetests --verbosity 1 gallery.tests.test_views
Creating test database 'default'...
...Skipping setup of test_k_01_11!
...Try FORCE_DB=true if you need fresh databases.
No fixtures found.
E
======================================================================
ERROR: Failure: AttributeError ('tuple' object has no attribute '_meta')
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/paulc/Sites/kitsune/vendor/packages/nose/nose/loader.py", line 368, in loadTestsFromName
    module = resolve_name(addr.module)
  File "/Users/paulc/Sites/kitsune/vendor/packages/nose/nose/util.py", line 334, in resolve_name
    module = __import__('.'.join(parts_copy))
  File "/Users/paulc/Sites/kitsune/../kitsune/apps/gallery/tests/test_views.py", line 9, in <module>
    from gallery import forms
  File "/Users/paulc/Sites/kitsune/apps/gallery/forms.py", line 97, in <module>
    class VideoUploadFormAsync(forms.ModelForm):
  File "/Users/paulc/Sites/kitsune/vendor/src/django/django/forms/models.py", line 226, in __new__
    opts.exclude, opts.widgets, formfield_callback)
  File "/Users/paulc/Sites/kitsune/vendor/src/django/django/forms/models.py", line 166, in fields_for_model
    opts = model._meta
AttributeError: 'tuple' object has no attribute '_meta'

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (errors=1)

How it is:

(kitsune)[paulc (upgrade-django-634345) kitsune]$ tg gallery.tests.test_viewsnosetests --verbosity 1 gallery.tests.test_views -s --logging-clear-handlers --with-progressive
Creating test database 'default'...
...Skipping setup of test_k_01_11!
...Try FORCE_DB=true if you need fresh databases.
No fixtures found.

ERROR: gallery.tests.test_views

ERROR: gallery.tests.test_views
Traceback (most recent call last):
  File "manage.py", line 49, in <module>
    execute_manager(settings)
  File "/Users/paulc/Sites/kitsune/vendor/src/django/django/core/management/__init__.py", line 438, in execute_manager
    utility.execute()
  File "/Users/paulc/Sites/kitsune/vendor/src/django/django/core/management/__init__.py", line 379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/paulc/Sites/kitsune/vendor/src/django/django/core/management/base.py", line 191, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/Users/paulc/Sites/kitsune/vendor/src/django/django/core/management/base.py", line 220, in execute
    output = self.handle(*args, **options)
  File "/Users/paulc/Sites/kitsune/vendor/src/django/django/core/management/commands/test.py", line 37, in handle
    failures = test_runner.run_tests(test_labels)
  File "/Users/paulc/Sites/kitsune/vendor/src/django-nose/django_nose/runner.py", line 85, in run_tests
    result = self.run_suite(nose_argv)
  File "/Users/paulc/Sites/kitsune/vendor/src/django-nose/django_nose/runner.py", line 49, in run_suite
    addplugins=plugins_to_add)
  File "/Users/paulc/Sites/kitsune/vendor/packages/nose/nose/core.py", line 113, in __init__
    argv=argv, testRunner=testRunner, testLoader=testLoader)
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/unittest.py", line 817, in __init__
    self.runTests()
  File "/Users/paulc/Sites/kitsune/vendor/packages/nose/nose/core.py", line 192, in runTests
    result = self.testRunner.run(self.test)
  File "/Users/paulc/.virtualenvs/kitsune/src/nose-progressive/noseprogressive/runner.py", line 44, in run
    test(result)
  File "/Users/paulc/Sites/kitsune/vendor/packages/nose/nose/suite.py", line 154, in __call__
    return self.run(*arg, **kw)
  File "/Users/paulc/Sites/kitsune/vendor/packages/nose/nose/suite.py", line 197, in run
    test(orig)
  File "/Users/paulc/Sites/kitsune/vendor/packages/nose/nose/suite.py", line 154, in __call__
    return self.run(*arg, **kw)
  File "/Users/paulc/Sites/kitsune/vendor/packages/nose/nose/suite.py", line 197, in run
    test(orig)
  File "/Users/paulc/Sites/kitsune/vendor/packages/nose/nose/case.py", line 44, in __call__
    return self.run(*arg, **kwarg)
  File "/Users/paulc/Sites/kitsune/vendor/packages/nose/nose/case.py", line 137, in run
    result.addError(self, err)
  File "/Users/paulc/Sites/kitsune/vendor/packages/nose/nose/proxy.py", line 122, in addError
    self.result.addError(self.test, err)
  File "/Users/paulc/.virtualenvs/kitsune/src/nose-progressive/noseprogressive/result.py", line 131, in addError
    isFailure=not isErrorClass or isFailure)
  File "/Users/paulc/.virtualenvs/kitsune/src/nose-progressive/noseprogressive/result.py", line 91, in _printError
    file, line = frame_of_test(address, extracted_tb)[:2]
  File "/Users/paulc/.virtualenvs/kitsune/src/nose-progressive/noseprogressive/utils.py", line 63, in frame_of_test
    test_file_path = realpath(test_file)
  File "/Users/paulc/.virtualenvs/kitsune/bin/../lib/python2.6/posixpath.py", line 347, in realpath
    if isabs(filename):
  File "/Users/paulc/.virtualenvs/kitsune/bin/../lib/python2.6/posixpath.py", line 52, in isabs
    return s.startswith('/')

Ugly progress bar when running with TERM=xterm

If the TERM environment variable is "xterm", then the progress bar is "ugly". Instead of using full blocks with the configured colors, it uses white full blocks for the progress and "-" chars for the remaining bar.

Running with TERM="screen-256color" the bar works as desired.

(tested in gnome-terminal under ubuntu 12.04 and 12.10)

Use as much room as possible for progress bar

Aside from having an option to set the progress bar as wide as you want, the bar should take up all the empty width that exists when the longest of test paths is displayed. (Recalculate when the terminal is resized.)

Include license

After preparing my patch I was surprised to find no license in the project (I looked it up on pypi). It's probably a good idea to mention it in the README.

Display progress bar in terminal, redirect test output to file

Hey,

Is there a way to display the progress bar in the terminal while redirection the test output to a file?

Obviously this does not display anything in the terminal:

nosetests --with-progressive &> tests.log

And this fails:

nosetests --with-progressive --progressive-with-bar &> tests.log

I'd love to be able to follow the progress while getting all the tests results in a file (ideally as soon as they arrive so that I can begin working on them while the tests are running).

Thanks!

nose-progressive causes issue with generator methods/setup_class

See the following example:

class TestDemo(object):
    @classmethod
    def setup_class(cls):
        cls.list_of_things = range(2)

    @classmethod 
    def teardown_class(cls): 
        del cls.list_of_things 

    def checker(self, index): 
        assert True 

    def test_driver(self):
        for index in range(len(self.list_of_things)): 
            yield self.checker, index 

Output of just nosetests vs nosetests --with-progressive:

wardefar@atchoum:~$ nosetests test.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK
wardefar@atchoum:~$ nosetests --with-progressive test.py
Traceback (most recent call last):
  File "/usr/bin/nosetests", line 8, in <module>
    load_entry_point('nose==0.10.3', 'console_scripts', 'nosetests')()
  File "/usr/lib/python2.5/site-packages/nose/core.py", line 219, in __init__
    argv=argv, testRunner=testRunner, testLoader=testLoader)
  File "/usr/lib64/python2.5/unittest.py", line 767, in __init__
    self.parseArgs(argv)
  File "/usr/lib/python2.5/site-packages/nose/core.py", line 270, in parseArgs
    self.createTests()
  File "/usr/lib/python2.5/site-packages/nose/core.py", line 284, in createTests
    self.test = self.testLoader.loadTestsFromNames(self.testNames)
  File "/u/wardefar/src/nose-progressive/noseprogressive/plugin.py", line 120, in capture_suite
    self._totalTests += orig_method(*args, **kwargs).countTestCases()
  File "/usr/lib64/python2.5/unittest.py", line 410, in countTestCases
    cases += test.countTestCases()
  File "/usr/lib64/python2.5/unittest.py", line 410, in countTestCases
    cases += test.countTestCases()
  File "/usr/lib64/python2.5/unittest.py", line 410, in countTestCases
    cases += test.countTestCases()
  File "/usr/lib64/python2.5/unittest.py", line 409, in countTestCases
    for test in self._tests:
  File "/usr/lib/python2.5/site-packages/nose/suite.py", line 277, in _get_wrapped_tests
    for test in self._get_tests():
  File "/usr/lib/python2.5/site-packages/nose/suite.py", line 76, in _get_tests
    for test in self.test_generator:
  File "/usr/lib/python2.5/site-packages/nose/loader.py", line 249, in generate
    for test in g():
  File "/u/wardefar/test.py", line 14, in test_driver
    for index in range(len(self.list_of_things)):
AttributeError: 'TestDemo' object has no attribute 'list_of_things'

Hide cursor while running tests

If it's a block cursor, it kind of blots out the first char of the test path. printing term.civis will do it, but somehow trap exit (like with the atexit stdlib module) so we're sure to restore it.

Make editor shortcut line number customizable

I would like to use TextMate whose mate cli command uses -l <number> or --line <number> instead of +<number> to specify the line numer. It could be great if one could specify a format string for the editor setting.

SyntaxError masked by nose-progressive

We had mismatched brackets in a test and received the following in the nose-progressive output:

ERROR: portal.zonza.ingest.tests.test_supporting_files
  vi +133 /opt/hogarth/envs/zonza/current/local/lib/python2.7/site-packages/nose/case.py  # run
    self.runTest(result)
  vi +151 /opt/hogarth/envs/zonza/current/local/lib/python2.7/site-packages/nose/case.py  # runTest
    test(result)
  vi +391 /usr/lib/python2.7/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  vi +351 /usr/lib/python2.7/unittest/case.py  # run
    result.addError(self, sys.exc_info())
  vi +132 /opt/hogarth/envs/zonza/current/local/lib/python2.7/site-packages/nose/proxy.py  # addError
    self.result.addError(self.test, self._prepareErr(err))
  vi +162 /opt/hogarth/envs/zonza/current/local/lib/python2.7/site-packages/noseprogressive/result.py  # addError
    self._printTraceback(test, err)
  vi +91  /opt/hogarth/envs/zonza/current/local/lib/python2.7/site-packages/noseprogressive/result.py  # _printTraceback
    self._options.editor_shortcut_template)))
  vi +82  /opt/hogarth/envs/zonza/current/local/lib/python2.7/site-packages/noseprogressive/tracebacks.py  # format_traceback
    exc_lines = [format_shortcut(editor, exc_value.filename, exc_value.lineno)]
AttributeError: 'SyntaxError' object has no attribute 'filename'
-------------------- >> begin captured logging << --------------------
django.db.backends: DEBUG: (0.016) SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login", "auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user"; args=()
--------------------- >> end captured logging << ---------------------

UnicodeDecodeError when using logging, different case of #29

Consider the following script:

# -*- coding: utf-8 -*-

import logging

logging.basicConfig()

def test_unicode_output():
    logger = logging.getLogger('root')

    logger.warning(u"Foo·····")
    print u"This is something “weird”"
    assert False, u"This too …"

Without progressive, I get:

F
======================================================================
FAIL: test.test_unicode_output
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/tp/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/tmp/tp/wip/test.py", line 12, in test_unicode_output
    assert False, u"This too …"
AssertionError: This too …
-------------------- >> begin captured stdout << ---------------------
This is something “weird”

--------------------- >> end captured stdout << ----------------------
-------------------- >> begin captured logging << --------------------
root: WARNING: Foo·····
--------------------- >> end captured logging << ---------------------

----------------------------------------------------------------------
Ran 1 test in 0.008s

FAILED (failures=1)

while --with-progressive emits a bad looking tb:


FAIL: test:test_unicode_output

ERROR: test:test_unicode_output
Traceback (most recent call last):
  File "/tmp/tp/bin/nosetests", line 9, in <module>
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     load_entry_point('nose==1.1.2', 'console_scripts', 'nosetests')()
  File "/tmp/tp/local/lib/python2.7/site-packages/nose/core.py", line 118, in __init__
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     **extra_args)
  File "/usr/lib/python2.7/unittest/main.py", line 95, in __init__
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     self.runTests()
  File "/tmp/tp/local/lib/python2.7/site-packages/nose/core.py", line 197, in runTests
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     result = self.testRunner.run(self.test)
  File "/tmp/tp/nose-progressive/noseprogressive/runner.py", line 42, in run
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     test(result)
  File "/tmp/tp/local/lib/python2.7/site-packages/nose/suite.py", line 176, in __call__
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     return self.run(*arg, **kw)
  File "/tmp/tp/local/lib/python2.7/site-packages/nose/suite.py", line 223, in run
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     test(orig)
  File "/usr/lib/python2.7/unittest/suite.py", line 70, in __call__
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     return self.run(*args, **kwds)
  File "/tmp/tp/local/lib/python2.7/site-packages/nose/suite.py", line 74, in run
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     test(result)
  File "/tmp/tp/local/lib/python2.7/site-packages/nose/suite.py", line 176, in __call__
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     return self.run(*arg, **kw)
  File "/tmp/tp/local/lib/python2.7/site-packages/nose/suite.py", line 223, in run
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     test(orig)
  File "/tmp/tp/local/lib/python2.7/site-packages/nose/case.py", line 45, in __call__
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     return self.run(*arg, **kwarg)
  File "/tmp/tp/local/lib/python2.7/site-packages/nose/case.py", line 138, in run
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     result.addError(self, err)
  File "/tmp/tp/local/lib/python2.7/site-packages/nose/proxy.py", line 135, in addError
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     self.result.addError(self.test, self._prepareErr(err))
  File "/tmp/tp/nose-progressive/noseprogressive/result.py", line 151, in addError
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     self._printTraceback(test, err)
  File "/tmp/tp/nose-progressive/noseprogressive/result.py", line 82, in _printTraceback
    test:test_unicode_output                                                                                                                                                                                                                                                                                                     self._options.editor)))
UnicodeDecodeErrortest:test_unicode_output                                                                                                                                                                                                                                                                                                     : test:test_unicode_output                                                                                                                                                                                                                                                                                                     'ascii' codec can't decode byte 0xc2 in position 188: ordinal not in range(128)test:test_unicode_output                                                                                                                                                                                                                                                                                                     

The logger output really makes the difference, commenting it out I get:

FAIL: test:test_unicode_output
  vi +12 test.py  # test_unicode_output
    assert False, u"This too …"
AssertionError: This too \u2026
-------------------- >> begin captured stdout << ---------------------
This is something \u201cwierd\u201d

--------------------- >> end captured stdout << ----------------------

1 test, 1 failure, 0 errors in 0.0s

Test case failures on Python 2.7

$ python -V
Python 2.7.3
$ python setup.py test
running test
running egg_info
writing requirements to nose_progressive.egg-info/requires.txt
writing nose_progressive.egg-info/PKG-INFO
writing top-level names to nose_progressive.egg-info/top_level.txt
writing dependency_links to nose_progressive.egg-info/dependency_links.txt
writing entry points to nose_progressive.egg-info/entry_points.txt
reading manifest file 'nose_progressive.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
writing manifest file 'nose_progressive.egg-info/SOURCES.txt'
running build_ext
noseprogressive.tests.test_bar.test_color_bar_half
Assert that a half-filled 16-color bar draws properly. ... FAIL
noseprogressive.tests.test_bar.test_color_bar_full
Assert that a complete 16-color bar draws properly. ... FAIL
noseprogressive.tests.test_bar.test_monochrome_bar
Assert that the black-and-white bar draws properly when < 16 colors are available. ... FAIL
test_skip (noseprogressive.tests.test_integration.AdvisoryShowingTests)
Make sure skipped tests print a line. ... ok
test_summary (noseprogressive.tests.test_integration.AdvisoryShowingTests)
Make sure summary prints. ... ok
test_error (noseprogressive.tests.test_integration.HookTests)
Make sure uncaught errors print a line. ... ok
test_fail (noseprogressive.tests.test_integration.HookTests)
Make sure failed tests print a line. ... ok
test_summary (noseprogressive.tests.test_integration.HookTests)
Make sure summary prints. ... ok
test_skip_invisible (noseprogressive.tests.test_integration.SkipHidingTests)
Make sure skipped tests don't show up in the output. ... ok
test_skipping (noseprogressive.tests.test_integration.UnitTestFrameSkippingTests)
Make sure no unittest frames make it into the traceback. ... ok
noseprogressive.tests.test_tracebacks.test_syntax_error
Exercise special handling of syntax errors to show it doesn't crash. ... ok
noseprogressive.tests.test_tracebacks.test_non_syntax_error
Exercise typical error formatting to show it doesn't crash. ... ok
noseprogressive.tests.test_tracebacks.test_empty_tracebacks
Make sure we don't crash on empty tracebacks. ... ok
noseprogressive.tests.test_tracebacks.test_unicode
Don't have encoding explosions when a line of code contains non-ASCII. ... ok
runTest (noseprogressive.tests.test_utils.DummyCase) ... ok
noseprogressive.tests.test_utils.test_human_path ... ok
noseprogressive.tests.test_utils.test_index_when_syntax_error_in_test_frame
Make sure ``index_of_test_frame()`` returns None for SyntaxErrors in the test frame. ... ok
noseprogressive.tests.test_utils.test_index_when_syntax_error_below_test_frame
Make sure we manage to find the test frame if there's a SyntaxError below it. ... ok

======================================================================
FAIL: noseprogressive.tests.test_bar.test_color_bar_half
Assert that a half-filled 16-color bar draws properly.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/Users/singingwolfboy/clones/nose-progressive/noseprogressive/tests/test_bar.py", line 36, in test_color_bar_half
    eq_(out.getvalue(), u'\x1b7\x1b[25d\x1b[1mHI                                '
AssertionError: u'\x1b7\x1b[25;1H\x1b[1mHI                                \x1b(B\x1b[m  \x1b[100m       \x1b(B\x1b[m\x1b[47m       \x1b(B\x1b[m\x1b8' != u'\x1b7\x1b[25d\x1b[1mHI                                \x1b(B\x1b[m  \x1b[100m       \x1b(B\x1b[m\x1b[47m       \x1b(B\x1b[m\x1b8'

======================================================================
FAIL: noseprogressive.tests.test_bar.test_color_bar_full
Assert that a complete 16-color bar draws properly.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/Users/singingwolfboy/clones/nose-progressive/noseprogressive/tests/test_bar.py", line 48, in test_color_bar_full
    eq_(out.getvalue(), u'\x1b7\x1b[25d\x1b[1mHI                                '
AssertionError: u'\x1b7\x1b[25;1H\x1b[1mHI                                \x1b(B\x1b[m  \x1b[100m              \x1b(B\x1b[m\x1b[47m\x1b(B\x1b[m\x1b8' != u'\x1b7\x1b[25d\x1b[1mHI                                \x1b(B\x1b[m  \x1b[100m              \x1b(B\x1b[m\x1b[47m\x1b(B\x1b[m\x1b8'

======================================================================
FAIL: noseprogressive.tests.test_bar.test_monochrome_bar
Assert that the black-and-white bar draws properly when < 16 colors are available.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/Users/singingwolfboy/clones/nose-progressive/noseprogressive/tests/test_bar.py", line 61, in test_monochrome_bar
    eq_(out.getvalue(), u'\x1b7\x1b[25d\x1b[1mHI                                '
AssertionError: u'\x1b7\x1b[25;1H\x1b[1mHI                                \x1b(B\x1b[m  \x1b[7m       \x1b(B\x1b[m_______\x1b8' != u'\x1b7\x1b[25d\x1b[1mHI                                \x1b(B\x1b[m  \x1b[7m       \x1b(B\x1b[m_______\x1b8'

----------------------------------------------------------------------
Ran 18 tests in 0.176s

FAILED (failures=3)

This seems both embarrassing and problematic for a unit testing tool.

Don't be so hostile to other outputters

Right now, we condemn other plugins to the oblivion of DummyStream(). Let their output through after dodging the progress bar around it. Make TextTestRunner shut up (by patching or replacing) to make this possible.

Unicode error in self.stream.write()

This might be the same as #52.

Rob Hudson ran across an encode error:

ERROR: mkt.search.tests.test_filters:TestFlaggedUsersPremiumApps.test_no_premium_on_android_flagged
  vim +133 /Users/rob/.virtualenvs/zamboni/lib/python2.6/site-packages/nose/case.py  # run
    self.runTest(result)
  vim +151 /Users/rob/.virtualenvs/zamboni/lib/python2.6/site-packages/nose/case.py  # runTest
    test(result)
  vim +508 /Users/rob/.virtualenvs/zamboni/lib/python2.6/site-packages/django/test/testcases.py  # __call__
    super(TransactionTestCase, self).__call__(result)
  vim +391 /Users/rob/.virtualenvs/zamboni/lib/python2.6/site-packages/django/utils/unittest/case.py  # __call__
    return self.run(*args, **kwds)
  vim +355 /Users/rob/.virtualenvs/zamboni/lib/python2.6/site-packages/django/utils/unittest/case.py  # run
    result.addError(self, sys.exc_info())
  vim +132 /Users/rob/.virtualenvs/zamboni/lib/python2.6/site-packages/nose/proxy.py  # addError
    self.result.addError(self.test, self._prepareErr(err))
  vim +164 /Users/rob/.virtualenvs/zamboni/lib/python2.6/site-packages/noseprogressive/result.py  # addError
    self._printTraceback(test, err)
  vim +93  /Users/rob/.virtualenvs/zamboni/lib/python2.6/site-packages/noseprogressive/result.py  # _printTraceback
    self.stream.write(v)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 663-667: ordinal not in range(128)

I fixed it by calling .encode('utf-8') on the unicode returned from format_traceback around line 91 of result.py before passing it to self.stream.write. write() was trying to encode it as ASCII, which didn't work because there's some Arabic in there. This might not be a general enough solution.

Use of deprecated Exception.message attribute

  vi +134 /home/vagrant/.py3/lib/python3.4/site-packages/nose/case.py  # run
    self.runTest(result)
  vi +152 /home/vagrant/.py3/lib/python3.4/site-packages/nose/case.py  # runTest
    test(result)
  vi +184 /home/vagrant/.py3/lib/python3.4/site-packages/django/test/testcases.py  # __call__
    super(SimpleTestCase, self).__call__(result)
  vi +410 /home/vagrant/.py3/lib/python3.4/site-packages/unittest2/case.py  # __call__
    return self.run(*args, **kwds)
  vi +338 /home/vagrant/.py3/lib/python3.4/site-packages/unittest2/case.py  # run
    self._addSkip(result, skip_why)
  vi +314 /home/vagrant/.py3/lib/python3.4/site-packages/unittest2/case.py  # _addSkip
    addSkip(self, reason)
  vi +160 /home/vagrant/.py3/lib/python3.4/site-packages/nose/proxy.py  # addSkip
    self.result.addSkip(self.test, reason)
  vi +151 /home/vagrant/.py3/lib/python3.4/site-packages/noseprogressive/result.py  # addSkip
    reason = reason.message
AttributeError: 'Exception' object has no attribute 'message'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.