Avoid deprecation warnings in the testrunner
Hello, I think we should provide a zope.testing package which does not emit deprecation warnings while running the testrunner on other packages, otherwise there is no way to really understand why the package you are working on is using a deprecated API. I propose the patch attached to this message to zope.testing. It tries to avoid importing zope.testing.doctest unless it is really needed. In this way, developers can see the DeprecationWarning with the path of *their* code, and fix it, instead of receiving the DeprecationWarning because the testrunner imports zope.testing.doctest itself. Before applying the patch, running the tests on another package produced this output: ----------------------------------------------------------------------- .../zope/testing/testrunner/debug.py:23: DeprecationWarning: zope.testing.doctest is deprecated in favour of the Python standard library doctest module from zope.testing import doctest Running zope.testing.testrunner.layer.UnitTests tests: ... ----------------------------------------------------------------------- After applying my patch, I get this: ----------------------------------------------------------------------- .../zope/interface/tests/test_adapter.py:405: DeprecationWarning: zope.testing.doctest is deprecated in favour of the Python standard library doctest module from zope.testing import doctest Running zope.testing.testrunner.layer.UnitTests tests: ... ----------------------------------------------------------------------- Comments? Thanks, Fabio
On Wed, Dec 23, 2009 at 01:36:33PM +0100, Fabio Tranchitella wrote:
I think we should provide a zope.testing package which does not emit deprecation warnings while running the testrunner on other packages, otherwise there is no way to really understand why the package you are working on is using a deprecated API.
+1
I propose the patch attached to this message to zope.testing.
It tries to avoid importing zope.testing.doctest unless it is really needed. In this way, developers can see the DeprecationWarning with the path of *their* code, and fix it, instead of receiving the DeprecationWarning because the testrunner imports zope.testing.doctest itself.
Before applying the patch, running the tests on another package produced this output:
----------------------------------------------------------------------- .../zope/testing/testrunner/debug.py:23: DeprecationWarning: zope.testing.doctest is deprecated in favour of the Python standard library doctest module from zope.testing import doctest Running zope.testing.testrunner.layer.UnitTests tests: ... -----------------------------------------------------------------------
After applying my patch, I get this:
----------------------------------------------------------------------- .../zope/interface/tests/test_adapter.py:405: DeprecationWarning: zope.testing.doctest is deprecated in favour of the Python standard library doctest module from zope.testing import doctest Running zope.testing.testrunner.layer.UnitTests tests: ... -----------------------------------------------------------------------
Comments?
Let's look at it:
Thanks, Fabio
Index: src/zope/testing/testrunner/formatter.py =================================================================== --- src/zope/testing/testrunner/formatter.py (revisione 106999) +++ src/zope/testing/testrunner/formatter.py (copia locale) @@ -19,10 +19,9 @@ import sys import re import traceback +import warnings
-from zope.testing import doctest
- doctest_template = """ File "%s", line %s, in %s
@@ -328,6 +327,9 @@ def format_traceback(self, exc_info): """Format the traceback.""" v = exc_info[1] + warnings.simplefilter('ignore') + from zope.testing import doctest + warnings.filters.pop()
I'm not thrilled. Can we 'import doctest' from the stdlib, and hope that these isinstance checks work fine? Specifically, can we make it so that zope.testing.doctest's exceptions _inherit_ from stdlib's doctest exceptions? Otherwise people who convert to stdlib's doctest to avoid deprecation warnings will lose all the nice doctest formatting and post-mortem debugging bits they're accustomed to.
if isinstance(v, doctest.DocTestFailureException): tb = v.args[0] elif isinstance(v, doctest.DocTestFailure): @@ -560,6 +562,9 @@ print print self.colorize('error', msg) v = exc_info[1] + warnings.simplefilter('ignore'); + from zope.testing import doctest + warnings.filters.pop() if isinstance(v, doctest.DocTestFailureException): self.print_doctest_failure(v.args[0]) elif isinstance(v, doctest.DocTestFailure): Index: src/zope/testing/testrunner/doctest.py =================================================================== --- src/zope/testing/testrunner/doctest.py (revisione 106999) +++ src/zope/testing/testrunner/doctest.py (copia locale) @@ -17,10 +17,11 @@ """
import sys -from zope.testing import doctest import zope.testing.testrunner.feature
+from zope.testing import doctest
+
Doesn't seem like much of a change ;) Suggest importing stdlib here as well.
class DocTest(zope.testing.testrunner.feature.Feature):
active = True Index: src/zope/testing/testrunner/runner.py =================================================================== --- src/zope/testing/testrunner/runner.py (revisione 106999) +++ src/zope/testing/testrunner/runner.py (copia locale) @@ -34,7 +34,6 @@ from zope.testing.testrunner.refcount import TrackRefs from zope.testing.testrunner.options import get_options import zope.testing.testrunner.coverage -import zope.testing.testrunner.doctest import zope.testing.testrunner.logsupport import zope.testing.testrunner.selftest import zope.testing.testrunner.profiling @@ -177,7 +176,10 @@ self.features.append(zope.testing.testrunner.selftest.SelfTest(self)) self.features.append(zope.testing.testrunner.logsupport.Logging(self)) self.features.append(zope.testing.testrunner.coverage.Coverage(self)) - self.features.append(zope.testing.testrunner.doctest.DocTest(self)) + if options.ndiff or options.udiff or options.cdiff or \ + options.report_only_first_failure is not None: + from zope.testing.testrunner.doctest import DocTest + self.features.append(DocTest(self))
A *strong* -1 for this bit.
self.features.append(zope.testing.testrunner.profiling.Profiling(self)) if is_jython: # Jython GC support is not yet implemented Index: src/zope/testing/testrunner/debug.py =================================================================== --- src/zope/testing/testrunner/debug.py (revisione 106999) +++ src/zope/testing/testrunner/debug.py (copia locale) @@ -20,12 +20,12 @@ import sys import pdb
-from zope.testing import doctest import zope.testing.testrunner.interfaces
def post_mortem(exc_info): err = exc_info[1] + from zope.testing import doctest
Same here: I'd like to use stdlib's doctest.
if isinstance(err, (doctest.UnexpectedException, doctest.DocTestFailure)):
if isinstance(err, doctest.UnexpectedException):
Cheers! Marius Gedminas -- http://pov.lt/ -- Zope 3 consulting and development
Hello, * 2009-12-23 14:33, Marius Gedminas wrote:
@@ -328,6 +327,9 @@ def format_traceback(self, exc_info): """Format the traceback.""" v = exc_info[1] + warnings.simplefilter('ignore') + from zope.testing import doctest + warnings.filters.pop()
I'm not thrilled.
Me neither, but if I don't do that, I will have a lot of test failures because the deprecation warning will be printed in the middle of the tests.
Can we 'import doctest' from the stdlib, and hope that these isinstance checks work fine?
No, it doesn't because the first if is about an exception which is zope.testing.doctest-specific.
Specifically, can we make it so that zope.testing.doctest's exceptions _inherit_ from stdlib's doctest exceptions?
I couldn't find the way to do it.
=================================================================== --- src/zope/testing/testrunner/doctest.py (revisione 106999) +++ src/zope/testing/testrunner/doctest.py (copia locale) @@ -17,10 +17,11 @@ """
import sys -from zope.testing import doctest import zope.testing.testrunner.feature
+from zope.testing import doctest
+
Doesn't seem like much of a change ;) Suggest importing stdlib here as well.
Same reason, we cannot use the standard doctest because it doesn't have the feature needed there.
- self.features.append(zope.testing.testrunner.doctest.DocTest(self)) + if options.ndiff or options.udiff or options.cdiff or \ + options.report_only_first_failure is not None: + from zope.testing.testrunner.doctest import DocTest + self.features.append(DocTest(self))
A *strong* -1 for this bit.
This is the only way I could avoid deprecation warnings for a test that doesn't need zope.testing-specific doctest features. Better ideas? Fabio
I was (finally) able to patch zope.testing to use the standard Python doctest module while still supporting zope.testing.doctest if a package is importing and using it. The tests of zope.testing are passing on Python 2.4, 2.5 and 2.6 and the output from running the tests of a package which does not make use of zope.testing.doctest doesn't contain any deprecation warning, yay! I committed my changes to the trunk. I'd appreciate if somebody would check the diff and, if nobody object, upload a new release of zope.testing (I don't have the rights on PyPI, my nickname is kobold). Best regards. Fabio * 2009-12-23 14:38, Fabio Tranchitella wrote:
...
Notice that replacing zope.testings use of it's own doctests module with stdlibs one is a major undertaking. I have done it as a part of the Python 3 branch, because I removed doctest.py from that branch. We could look into merging those changes without removing doctests.py, but I think we might even run into such simple problems as relative import paths clashing. -- Lennart Regebro: http://regebro.wordpress.com/ Python 3 Porting: http://python-incompatibility.googlecode.com/ +33 661 58 14 64
On Wed, Dec 23, 2009 at 22:40, Lennart Regebro <regebro@gmail.com> wrote:
Notice that replacing zope.testings use of it's own doctests module with stdlibs one is a major undertaking.
OK, I'm tired. It's only a major undertaking if you remove it completely. zope.testings tests are mostly a question of running tests. Those should obviously still use zope.testing.doctest, and then it's a much smaller problem. -- Lennart Regebro: http://regebro.wordpress.com/ Python 3 Porting: http://python-incompatibility.googlecode.com/ +33 661 58 14 64
* 2009-12-23 22:48, Lennart Regebro wrote:
OK, I'm tired. It's only a major undertaking if you remove it completely. zope.testings tests are mostly a question of running tests. Those should obviously still use zope.testing.doctest, and then it's a much smaller problem.
This is exactly what I did in the trunk: zope.testing.doctest is still there (so you can use it for declaring your doctests) it is not used directly by the testrunner anymore because it uses the stdlib doctest. Best regards, Fabio
On Wed, Dec 23, 2009 at 23:04, Fabio Tranchitella <kobold@kobold.it> wrote:
* 2009-12-23 22:48, Lennart Regebro wrote:
OK, I'm tired. It's only a major undertaking if you remove it completely. zope.testings tests are mostly a question of running tests. Those should obviously still use zope.testing.doctest, and then it's a much smaller problem.
This is exactly what I did in the trunk: zope.testing.doctest is still there (so you can use it for declaring your doctests) it is not used directly by the testrunner anymore because it uses the stdlib doctest.
Yeah, that's fine by me. I see you did some ugly hacks to make it work like making doctest.py into directory, but I don't have a problem with that personally. -- Lennart Regebro: http://regebro.wordpress.com/ Python 3 Porting: http://python-incompatibility.googlecode.com/ +33 661 58 14 64
* 2009-12-24 07:12, Lennart Regebro wrote:
Yeah, that's fine by me. I see you did some ugly hacks to make it work like making doctest.py into directory, but I don't have a problem with that personally.
I've tested the whole ZTK KGS using the current zope.testing's trunk and the only failing package was zope.minmax (already fixed in the trunk), because it imported zope.testing and used zope.testing.doctest, which fails now that doctest is a directory and not a file, as Lennnart pointed out. I think we should now make a new release for zope.testing and, obviously, zope.minmax. I don't have the rights on PyPI, can somebody help me (or add me, kobold)? Thanks, Fabio
On Thu, Dec 24, 2009 at 08:26, Fabio Tranchitella <kobold@kobold.it> wrote:
I've tested the whole ZTK KGS using the current zope.testing's trunk and the only failing package was zope.minmax (already fixed in the trunk), because it imported zope.testing and used zope.testing.doctest, which fails now that doctest is a directory and not a file, as Lennnart pointed out.
It does? But the code is moved to doctest/__init__.py. That should work... Or maybe we need to do an import doctest from zope/testing/__init__.py for it to show up, I don't remember. Can we avoid this error? The whole point with the deprecation is to NOT break code. ;) -- Lennart Regebro: http://regebro.wordpress.com/ Python 3 Porting: http://python-incompatibility.googlecode.com/ +33 661 58 14 64
* 2009-12-24 11:40, Lennart Regebro wrote:
On Thu, Dec 24, 2009 at 08:26, Fabio Tranchitella <kobold@kobold.it> wrote:
I've tested the whole ZTK KGS using the current zope.testing's trunk and the only failing package was zope.minmax (already fixed in the trunk), because it imported zope.testing and used zope.testing.doctest, which fails now that doctest is a directory and not a file, as Lennnart pointed out.
It does?
Yes, definitely.
But the code is moved to doctest/__init__.py. That should work...
No, it does not because now doctest is a package.
Or maybe we need to do an import doctest from zope/testing/__init__.py for it to show up, I don't remember.
Yes, you are right, but if I'd do that, the deprecation warning would be raised by the simple import of zope.testing, making it useless because it would mask the warnings related to the package you are running the tests for.
Can we avoid this error? The whole point with the deprecation is to NOT break code. ;)
I don't think we can avoid the error, and to be honest I consider the code in zope.minmax to be wrong. """ import zope.testing x = zope.testing.doctest.DocTestFile(... """ The import is wrong, it should be "zope.testing.doctest", and I fixed it in the trunk, and this was the only failure in the ZTK. Thanks for your support, Fabio
On Dec 24, 2009, at 8:50 AM, Fabio Tranchitella wrote:
I don't think we can avoid the error, and to be honest I consider the code in zope.minmax to be wrong.
""" import zope.testing x = zope.testing.doctest.DocTestFile(... """
The import is wrong, it should be "zope.testing.doctest", and I fixed it in the trunk, and this was the only failure in the ZTK.
I don't think you fixed it on the trunk. The code now looks like this import doctest ... zope.testing.doctest.DocFileSuite('minmax.txt'), ... You did not import zope.testing.doctest, but the reference to it remains. I don't think that's a fix. Zvezdan
On Thu, Dec 24, 2009 at 14:50, Fabio Tranchitella <kobold@kobold.it> wrote:
I don't think we can avoid the error, and to be honest I consider the code in zope.minmax to be wrong.
""" import zope.testing x = zope.testing.doctest.DocTestFile(... """
The import is wrong
No, that's perferctly correct code and not wrong in any way. What if we hide the warning during the __init__.py import. Will it show up the next time, then? or Maybe we can add deprecations only for the major names in doctest.py? That would still raise an error everytime you use it, but only when you import a name, not the module. -- Lennart Regebro: http://regebro.wordpress.com/ Python 3 Porting: http://python-incompatibility.googlecode.com/ +33 661 58 14 64
* 2009-12-25 07:32, Lennart Regebro wrote:
On Thu, Dec 24, 2009 at 14:50, Fabio Tranchitella <kobold@kobold.it> wrote:
I don't think we can avoid the error, and to be honest I consider the code in zope.minmax to be wrong.
""" import zope.testing x = zope.testing.doctest.DocTestFile(... """
The import is wrong
No, that's perferctly correct code and not wrong in any way.
It is not wrong from a syntax point of view, but it is wrong because it assumes doctest is a sub-module and not a sub-package. As said here: http://docs.python.org/tutorial/modules.html#packages It would have been perfect to write: import zope.testing.doctest ... avoiding the "embedded" design decision that doctest is a sub-module. Anyway, I'm happy with whatever fix we apply, as long as we find a way to not rise the deprecation warning just after an import of zope.testing or a run of the testrunner.
What if we hide the warning during the __init__.py import. Will it show up the next time, then?
No, because modules/packages are imported only once.
Maybe we can add deprecations only for the major names in doctest.py? That would still raise an error everytime you use it, but only when you import a name, not the module.
I thought we deprecated the whole zope.testing.doctest. Best regards, and Merry Christmas. Fabio
On Fri, Dec 25, 2009 at 07:49, Fabio Tranchitella <kobold@kobold.it> wrote:
No, that's perferctly correct code and not wrong in any way.
It is not wrong from a syntax point of view, but it is wrong because it assumes doctest is a sub-module and not a sub-package.
I understand the difference, but the fact is that up until yesterday it *was* a submodule, and hence it was correct and valid code. There are no PEP8 rules against doing this, hence it has to be viewed as valid code. Ugly yes, but you can't say it's wrong.
What if we hide the warning during the __init__.py import. Will it show up the next time, then?
No, because modules/packages are imported only once.
Right.
Maybe we can add deprecations only for the major names in doctest.py? That would still raise an error everytime you use it, but only when you import a name, not the module.
I thought we deprecated the whole zope.testing.doctest.
Yes, we did. But now we try to get the deprecation warnings to show up in the correct place. And we could warn for the usage of some of the names, but in the message explain that doctest.py is deprecated.
Best regards, and Merry Christmas.
The same! -- Lennart Regebro: Python, Zope, Plone, Grok http://regebro.wordpress.com/ +33 661 58 14 64
* 2009-12-25 10:23, Lennart Regebro wrote:
Yes, we did. But now we try to get the deprecation warnings to show up in the correct place. And we could warn for the usage of some of the names, but in the message explain that doctest.py is deprecated.
What do you think about the attached patch (applied to the current trunk)? It makes the tests quite noisy (each usage of DocTestSuite and DocFileSuite raises a warning), but I think matches with what you wrote in the quoted paragraph above. Thanks, Fabio
On Sun, Dec 27, 2009 at 10:44, Fabio Tranchitella <kobold@kobold.it> wrote:
* 2009-12-25 10:23, Lennart Regebro wrote:
Yes, we did. But now we try to get the deprecation warnings to show up in the correct place. And we could warn for the usage of some of the names, but in the message explain that doctest.py is deprecated.
What do you think about the attached patch (applied to the current trunk)? It makes the tests quite noisy (each usage of DocTestSuite and DocFileSuite raises a warning), but I think matches with what you wrote in the quoted paragraph above.
Yeah, I think that make sense. Seems a simple solution that works. -- Lennart Regebro: http://regebro.wordpress.com/ Python 3 Porting: http://python-incompatibility.googlecode.com/ +33 661 58 14 64
On Fri, Dec 25, 2009 at 07:49:38AM +0100, Fabio Tranchitella wrote:
* 2009-12-25 07:32, Lennart Regebro wrote:
On Thu, Dec 24, 2009 at 14:50, Fabio Tranchitella <kobold@kobold.it> wrote:
I don't think we can avoid the error, and to be honest I consider the code in zope.minmax to be wrong.
""" import zope.testing x = zope.testing.doctest.DocTestFile(... """
The import is wrong
No, that's perferctly correct code and not wrong in any way.
It is not wrong from a syntax point of view, but it is wrong because it assumes doctest is a sub-module and not a sub-package.
I think you mean "assumes doctest is imported in zope.testing's __init__.py". There's no difference between modules or packages for the import statement, witness mg@platonas:~ $ cd tmp mg@platonas:~/tmp $ mkdir a mg@platonas:~/tmp $ touch a/__init__.py mg@platonas:~/tmp $ mkdir a/b mg@platonas:~/tmp $ touch a/b/__init__.py mg@platonas:~/tmp $ touch a/c.py mg@platonas:~/tmp $ python Python 2.6.4 (r264:75706, Dec 7 2009, 18:45:15) [GCC 4.4.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import a >>> a.b Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'b' >>> a.c Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'c' >>> Marius Gedminas -- http://pov.lt/ -- Zope 3 consulting and development
* 2009-12-28 13:31, Marius Gedminas wrote:
I think you mean "assumes doctest is imported in zope.testing's __init__.py".
There's no difference between modules or packages for the import statement, witness
Yes, you are right; any comment on my patches though? I'd love to release a zope.testing which emits a single *useless* deprecation warning. Fabio
On Tue, Dec 29, 2009 at 07:38:16AM +0100, Fabio Tranchitella wrote:
* 2009-12-28 13:31, Marius Gedminas wrote:
I think you mean "assumes doctest is imported in zope.testing's __init__.py".
There's no difference between modules or packages for the import statement, witness
Yes, you are right; any comment on my patches though? I'd love to release a zope.testing which emits a single *useless* deprecation warning.
Uh, what? Don't you mean "doesn't"? Marius Gedminas -- http://pov.lt/ -- Zope 3 consulting and development
participants (4)
-
Fabio Tranchitella -
Lennart Regebro -
Marius Gedminas -
Zvezdan Petkovic