From b257ecb0bdcfae09d74ab95ad621bed19934b555 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 19 Oct 2013 20:56:31 -0400 Subject: Start on 4.0 --HG-- branch : 4.0 --- coverage/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coverage/version.py b/coverage/version.py index a43bde80..27c2f6b1 100644 --- a/coverage/version.py +++ b/coverage/version.py @@ -1,7 +1,7 @@ """The version and URL for coverage.py""" # This file is exec'ed in setup.py, don't import anything! -__version__ = "3.7.1" # see detailed history in CHANGES.txt +__version__ = "4.0a0" # see detailed history in CHANGES.txt __url__ = "http://nedbatchelder.com/code/coverage" if max(__version__).isalpha(): -- cgit v1.2.1 From 18ba48b6b119f07f5c738c7fd36c2d2ede04f67e Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 19 Oct 2013 21:21:10 -0400 Subject: We only run on 2.6, 2.7, 3.2, 3.3 now. --HG-- branch : 4.0 --- coverage/phystokens.py | 9 +- setup.py | 6 +- tests/farm/html/run_partial.py | 7 +- tests/osinfo.py | 2 +- tests/test_arcs.py | 117 +++++++-------- tests/test_config.py | 23 ++- tests/test_coverage.py | 332 ++++++++++++++++++++--------------------- tests/test_html.py | 31 ++-- tests/test_oddball.py | 73 +++++---- tests/test_phystokens.py | 9 +- tests/test_process.py | 29 ++-- tox.ini | 2 +- 12 files changed, 305 insertions(+), 335 deletions(-) diff --git a/coverage/phystokens.py b/coverage/phystokens.py index 2a91882d..58522413 100644 --- a/coverage/phystokens.py +++ b/coverage/phystokens.py @@ -141,13 +141,8 @@ def source_encoding(source): # invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found, # 'utf-8-sig' is returned. - # If no encoding is specified, then the default will be returned. The - # default varied with version. - - if sys.version_info <= (2, 4): - default = 'iso-8859-1' - else: - default = 'ascii' + # If no encoding is specified, then the default will be returned. + default = 'ascii' bom_found = False encoding = None diff --git a/setup.py b/setup.py index f0e83e67..e96bdb75 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ Coverage.py measures code coverage, typically during test execution. It uses the code analysis tools and tracing hooks provided in the Python standard library to determine which lines are executable, and which have been executed. -Coverage.py runs on Pythons 2.3 through 3.3, and PyPy 1.9. +Coverage.py runs on Pythons 2.6, 2.7, 3.2, 3.3, and PyPy 1.9. Documentation is at `nedbatchelder.com <%s>`_. Code repository and issue tracker are on `Bitbucket `_, with a @@ -118,8 +118,8 @@ ext_errors = ( errors.DistutilsExecError, errors.DistutilsPlatformError, ) -if sys.platform == 'win32' and sys.version_info > (2, 6): - # 2.6's distutils.msvc9compiler can raise an IOError when failing to +if sys.platform == 'win32': + # distutils.msvc9compiler can raise an IOError when failing to # find the compiler ext_errors += (IOError,) diff --git a/tests/farm/html/run_partial.py b/tests/farm/html/run_partial.py index 41e6ba96..eab14411 100644 --- a/tests/farm/html/run_partial.py +++ b/tests/farm/html/run_partial.py @@ -24,9 +24,8 @@ contains("html_partial/partial.html", contains("html_partial/index.html", "partial", ) -if sys.version_info >= (2, 4): - contains("html_partial/index.html", - "100%" - ) +contains("html_partial/index.html", + "100%" + ) clean("html_partial") diff --git a/tests/osinfo.py b/tests/osinfo.py index 25c3a7c6..acbec231 100644 --- a/tests/osinfo.py +++ b/tests/osinfo.py @@ -2,7 +2,7 @@ import sys -if sys.version_info >= (2, 5) and sys.platform == 'win32': +if sys.platform == 'win32': # Windows implementation def process_ram(): """How much RAM is this process using? (Windows)""" diff --git a/tests/test_arcs.py b/tests/test_arcs.py index 6268e289..80923f8d 100644 --- a/tests/test_arcs.py +++ b/tests/test_arcs.py @@ -88,12 +88,6 @@ class SimpleArcTest(CoverageTest): arcz=".1 14 45 5. .2 2. 23 3.", arcz_missing="23 3.") def test_multiline(self): - # The firstlineno of the a assignment below differs among Python - # versions. - if sys.version_info >= (2, 5): - arcz = ".1 15 5-2" - else: - arcz = ".1 15 5-1" self.check_coverage("""\ a = ( 2 + @@ -102,7 +96,7 @@ class SimpleArcTest(CoverageTest): b = \\ 6 """, - arcz=arcz, arcz_missing="") + arcz=".1 15 5-2", arcz_missing="") def test_if_return(self): self.check_coverage("""\ @@ -151,33 +145,32 @@ class SimpleArcTest(CoverageTest): ) -if sys.version_info >= (2, 6): - class WithTest(CoverageTest): - """Arc-measuring tests involving context managers.""" +class WithTest(CoverageTest): + """Arc-measuring tests involving context managers.""" - def test_with(self): - self.check_coverage("""\ - def example(): - with open("test", "w") as f: # exit - f.write("") - return 1 + def test_with(self): + self.check_coverage("""\ + def example(): + with open("test", "w") as f: # exit + f.write("") + return 1 - example() - """, - arcz=".1 .2 23 34 4. 16 6." - ) + example() + """, + arcz=".1 .2 23 34 4. 16 6." + ) - def test_bug_146(self): - # https://bitbucket.org/ned/coveragepy/issue/146 - self.check_coverage("""\ - for i in range(2): - with open("test", "w") as f: - print(3) - print(4) - print(5) - """, - arcz=".1 12 23 34 41 15 5." - ) + def test_bug_146(self): + # https://bitbucket.org/ned/coveragepy/issue/146 + self.check_coverage("""\ + for i in range(2): + with open("test", "w") as f: + print(3) + print(4) + print(5) + """, + arcz=".1 12 23 34 41 15 5." + ) class LoopArcTest(CoverageTest): @@ -509,9 +502,9 @@ class ExceptionArcTest(CoverageTest): arcz=".1 12 23 35 56 61 17 7.", arcz_missing="", arcz_unpredicted="") - # Run this test only on 2.6 and 2.7 for now. I hope to fix it on Py3 + # Run this test only on Py2 for now. I hope to fix it on Py3 # eventually... - if (2, 6) <= sys.version_info < (3,): + if sys.version_info < (3, 0): # "except Exception as e" is crucial here. def test_bug_212(self): self.check_coverage("""\ @@ -533,36 +526,34 @@ class ExceptionArcTest(CoverageTest): arcz=".1 .2 1A 23 34 56 67 68 8. AB BC C. DE E.", arcz_missing="C.", arcz_unpredicted="45 7. CD") - if sys.version_info >= (2, 5): - # Try-except-finally was new in 2.5 - def test_except_finally(self): - self.check_coverage("""\ - a, b, c = 1, 1, 1 - try: - a = 3 - except: - b = 5 - finally: - c = 7 - assert a == 3 and b == 1 and c == 7 - """, - arcz=".1 12 23 45 37 57 78 8.", arcz_missing="45 57") - self.check_coverage("""\ - a, b, c = 1, 1, 1 - def oops(x): - if x % 2: raise Exception("odd") - try: - a = 5 - oops(1) - a = 7 - except: - b = 9 - finally: - c = 11 - assert a == 5 and b == 9 and c == 11 - """, - arcz=".1 12 .3 3-2 24 45 56 67 7B 89 9B BC C.", - arcz_missing="67 7B", arcz_unpredicted="68") + def test_except_finally(self): + self.check_coverage("""\ + a, b, c = 1, 1, 1 + try: + a = 3 + except: + b = 5 + finally: + c = 7 + assert a == 3 and b == 1 and c == 7 + """, + arcz=".1 12 23 45 37 57 78 8.", arcz_missing="45 57") + self.check_coverage("""\ + a, b, c = 1, 1, 1 + def oops(x): + if x % 2: raise Exception("odd") + try: + a = 5 + oops(1) + a = 7 + except: + b = 9 + finally: + c = 11 + assert a == 5 and b == 9 and c == 11 + """, + arcz=".1 12 .3 3-2 24 45 56 67 7B 89 9B BC C.", + arcz_missing="67 7B", arcz_unpredicted="68") class MiscArcTest(CoverageTest): diff --git a/tests/test_config.py b/tests/test_config.py index 6d370255..c44fa80c 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -211,15 +211,14 @@ class ConfigFileTest(CoverageTest): 'other': ['other', '/home/ned/other', 'c:\\Ned\\etc'] }) - if sys.version_info[:2] != (3,1): - def test_one(self): - # This sample file tries to use lots of variation of syntax... - self.make_file(".coveragerc", """\ - [html] - title = tabblo & «ταБЬℓσ» # numbers - """) - cov = coverage.coverage() - - self.assertEqual(cov.config.html_title, - "tabblo & «ταБЬℓσ» # numbers" - ) + def test_one(self): + # This sample file tries to use lots of variation of syntax... + self.make_file(".coveragerc", """\ + [html] + title = tabblo & «ταБЬℓσ» # numbers + """) + cov = coverage.coverage() + + self.assertEqual(cov.config.html_title, + "tabblo & «ταБЬℓσ» # numbers" + ) diff --git a/tests/test_coverage.py b/tests/test_coverage.py index 6de4d0ea..078c66ca 100644 --- a/tests/test_coverage.py +++ b/tests/test_coverage.py @@ -839,15 +839,13 @@ class CompoundStatementTest(CoverageTest): """, [1,2,4,5,7,9,10], "4, 7") - if sys.version_info >= (2, 4): - # In 2.4 and up, constant if's were compiled away. - def test_constant_if(self): - self.check_coverage("""\ - if 1: - a = 2 - assert a == 2 - """, - [2,3], "") + def test_constant_if(self): + self.check_coverage("""\ + if 1: + a = 2 + assert a == 2 + """, + [2,3], "") def test_while(self): self.check_coverage("""\ @@ -1510,187 +1508,185 @@ class ExcludeTest(CoverageTest): [8,9], "", excludes=['#pragma: NO COVER']) -if sys.version_info >= (2, 4): - class Py24Test(CoverageTest): - """Tests of new syntax in Python 2.4.""" +class Py24Test(CoverageTest): + """Tests of new syntax in Python 2.4.""" - def test_function_decorators(self): - self.check_coverage("""\ - def require_int(func): - def wrapper(arg): - assert isinstance(arg, int) - return func(arg) + def test_function_decorators(self): + self.check_coverage("""\ + def require_int(func): + def wrapper(arg): + assert isinstance(arg, int) + return func(arg) + return wrapper + + @require_int + def p1(arg): + return arg*2 + + assert p1(10) == 20 + """, + [1,2,3,4,6,8,10,12], "") + + def test_function_decorators_with_args(self): + self.check_coverage("""\ + def boost_by(extra): + def decorator(func): + def wrapper(arg): + return extra*func(arg) return wrapper + return decorator - @require_int - def p1(arg): - return arg*2 + @boost_by(10) + def boosted(arg): + return arg*2 - assert p1(10) == 20 - """, - [1,2,3,4,6,8,10,12], "") + assert boosted(10) == 200 + """, + [1,2,3,4,5,6,8,10,12], "") - def test_function_decorators_with_args(self): - self.check_coverage("""\ - def boost_by(extra): - def decorator(func): - def wrapper(arg): - return extra*func(arg) - return wrapper - return decorator - - @boost_by(10) - def boosted(arg): - return arg*2 - - assert boosted(10) == 200 - """, - [1,2,3,4,5,6,8,10,12], "") + def test_double_function_decorators(self): + self.check_coverage("""\ + def require_int(func): + def wrapper(arg): + assert isinstance(arg, int) + return func(arg) + return wrapper - def test_double_function_decorators(self): - self.check_coverage("""\ - def require_int(func): + def boost_by(extra): + def decorator(func): def wrapper(arg): - assert isinstance(arg, int) - return func(arg) + return extra*func(arg) return wrapper + return decorator - def boost_by(extra): - def decorator(func): - def wrapper(arg): - return extra*func(arg) - return wrapper - return decorator + @require_int + @boost_by(10) + def boosted1(arg): + return arg*2 - @require_int - @boost_by(10) - def boosted1(arg): - return arg*2 + assert boosted1(10) == 200 - assert boosted1(10) == 200 + @boost_by(10) + @require_int + def boosted2(arg): + return arg*2 - @boost_by(10) - @require_int - def boosted2(arg): - return arg*2 + assert boosted2(10) == 200 + """, + ([1,2,3,4,5,7,8,9,10,11,12,14,15,17,19,21,22,24,26], + [1,2,3,4,5,7,8,9,10,11,12,14, 17,19,21, 24,26]), "") - assert boosted2(10) == 200 - """, - ([1,2,3,4,5,7,8,9,10,11,12,14,15,17,19,21,22,24,26], - [1,2,3,4,5,7,8,9,10,11,12,14, 17,19,21, 24,26]), "") +class Py25Test(CoverageTest): + """Tests of new syntax in Python 2.5.""" -if sys.version_info >= (2, 5): - class Py25Test(CoverageTest): - """Tests of new syntax in Python 2.5.""" + def test_with_statement(self): + self.check_coverage("""\ + from __future__ import with_statement - def test_with_statement(self): - self.check_coverage("""\ - from __future__ import with_statement + class Managed: + def __enter__(self): + desc = "enter" - class Managed: - def __enter__(self): - desc = "enter" + def __exit__(self, type, value, tb): + desc = "exit" - def __exit__(self, type, value, tb): - desc = "exit" + m = Managed() + with m: + desc = "block1a" + desc = "block1b" - m = Managed() + try: with m: - desc = "block1a" - desc = "block1b" - - try: - with m: - desc = "block2" - raise Exception("Boo!") - except: - desc = "caught" - """, - [1,3,4,5,7,8,10,11,12,13,15,16,17,18,19,20], "") + desc = "block2" + raise Exception("Boo!") + except: + desc = "caught" + """, + [1,3,4,5,7,8,10,11,12,13,15,16,17,18,19,20], "") - def test_try_except_finally(self): - self.check_coverage("""\ - a = 0; b = 0 - try: - a = 1 - except: - a = 99 - finally: - b = 2 - assert a == 1 and b == 2 - """, - [1,2,3,4,5,7,8], "4-5") - self.check_coverage("""\ - a = 0; b = 0 - try: - a = 1 - raise Exception("foo") - except: - a = 99 - finally: - b = 2 - assert a == 99 and b == 2 - """, - [1,2,3,4,5,6,8,9], "") - self.check_coverage("""\ - a = 0; b = 0 - try: - a = 1 - raise Exception("foo") - except ImportError: - a = 99 - except: - a = 123 - finally: - b = 2 - assert a == 123 and b == 2 - """, - [1,2,3,4,5,6,7,8,10,11], "6") - self.check_coverage("""\ - a = 0; b = 0 - try: - a = 1 - raise IOError("foo") - except ImportError: - a = 99 - except IOError: - a = 17 - except: - a = 123 - finally: - b = 2 - assert a == 17 and b == 2 - """, - [1,2,3,4,5,6,7,8,9,10,12,13], "6, 9-10") - self.check_coverage("""\ - a = 0; b = 0 - try: - a = 1 - except: - a = 99 - else: - a = 123 - finally: - b = 2 - assert a == 123 and b == 2 - """, - [1,2,3,4,5,7,9,10], "4-5") - self.check_coverage("""\ - a = 0; b = 0 - try: - a = 1 - raise Exception("foo") - except: - a = 99 - else: - a = 123 - finally: - b = 2 - assert a == 99 and b == 2 - """, - [1,2,3,4,5,6,8,10,11], "8") + def test_try_except_finally(self): + self.check_coverage("""\ + a = 0; b = 0 + try: + a = 1 + except: + a = 99 + finally: + b = 2 + assert a == 1 and b == 2 + """, + [1,2,3,4,5,7,8], "4-5") + self.check_coverage("""\ + a = 0; b = 0 + try: + a = 1 + raise Exception("foo") + except: + a = 99 + finally: + b = 2 + assert a == 99 and b == 2 + """, + [1,2,3,4,5,6,8,9], "") + self.check_coverage("""\ + a = 0; b = 0 + try: + a = 1 + raise Exception("foo") + except ImportError: + a = 99 + except: + a = 123 + finally: + b = 2 + assert a == 123 and b == 2 + """, + [1,2,3,4,5,6,7,8,10,11], "6") + self.check_coverage("""\ + a = 0; b = 0 + try: + a = 1 + raise IOError("foo") + except ImportError: + a = 99 + except IOError: + a = 17 + except: + a = 123 + finally: + b = 2 + assert a == 17 and b == 2 + """, + [1,2,3,4,5,6,7,8,9,10,12,13], "6, 9-10") + self.check_coverage("""\ + a = 0; b = 0 + try: + a = 1 + except: + a = 99 + else: + a = 123 + finally: + b = 2 + assert a == 123 and b == 2 + """, + [1,2,3,4,5,7,9,10], "4-5") + self.check_coverage("""\ + a = 0; b = 0 + try: + a = 1 + raise Exception("foo") + except: + a = 99 + else: + a = 123 + finally: + b = 2 + assert a == 99 and b == 2 + """, + [1,2,3,4,5,6,8,10,11], "8") class ModuleTest(CoverageTest): diff --git a/tests/test_html.py b/tests/test_html.py index 06132fb4..f22fdc21 100644 --- a/tests/test_html.py +++ b/tests/test_html.py @@ -177,22 +177,21 @@ class HtmlTitleTest(HtmlTestHelpers, CoverageTest): self.assertIn("Metrics & stuff!", index) self.assertIn("

Metrics & stuff!:", index) - if sys.version_info[:2] != (3,1): - def test_non_ascii_title_set_in_config_file(self): - self.create_initial_files() - self.make_file(".coveragerc", - "[html]\ntitle = «ταБЬℓσ» numbers" - ) - self.run_coverage() - index = open("htmlcov/index.html").read() - self.assertIn( - "«ταБЬℓσ»" - " numbers", index - ) - self.assertIn( - "<h1>«ταБЬℓσ»" - " numbers", index - ) + def test_non_ascii_title_set_in_config_file(self): + self.create_initial_files() + self.make_file(".coveragerc", + "[html]\ntitle = «ταБЬℓσ» numbers" + ) + self.run_coverage() + index = open("htmlcov/index.html").read() + self.assertIn( + "<title>«ταБЬℓσ»" + " numbers", index + ) + self.assertIn( + "<h1>«ταБЬℓσ»" + " numbers", index + ) def test_title_set_in_args(self): self.create_initial_files() diff --git a/tests/test_oddball.py b/tests/test_oddball.py index 4b18a4ee..eba507be 100644 --- a/tests/test_oddball.py +++ b/tests/test_oddball.py @@ -329,43 +329,42 @@ class ExceptionTest(CoverageTest): self.assertEqual(clean_lines, lines_expected) -if sys.version_info >= (2, 5): - class DoctestTest(CoverageTest): - """Tests invoked with doctest should measure properly.""" - - def setUp(self): - super(DoctestTest, self).setUp() - - # Oh, the irony! This test case exists because Python 2.4's - # doctest module doesn't play well with coverage. But nose fixes - # the problem by monkeypatching doctest. I want to undo the - # monkeypatch to be sure I'm getting the doctest module that users - # of coverage will get. Deleting the imported module here is - # enough: when the test imports doctest again, it will get a fresh - # copy without the monkeypatch. - del sys.modules['doctest'] - - def test_doctest(self): - self.check_coverage('''\ - def return_arg_or_void(arg): - """If <arg> is None, return "Void"; otherwise return <arg> - - >>> return_arg_or_void(None) - 'Void' - >>> return_arg_or_void("arg") - 'arg' - >>> return_arg_or_void("None") - 'None' - """ - if arg is None: - return "Void" - else: - return arg - - import doctest, sys - doctest.testmod(sys.modules[__name__]) # we're not __main__ :( - ''', - [1,11,12,14,16,17], "") +class DoctestTest(CoverageTest): + """Tests invoked with doctest should measure properly.""" + + def setUp(self): + super(DoctestTest, self).setUp() + + # Oh, the irony! This test case exists because Python 2.4's + # doctest module doesn't play well with coverage. But nose fixes + # the problem by monkeypatching doctest. I want to undo the + # monkeypatch to be sure I'm getting the doctest module that users + # of coverage will get. Deleting the imported module here is + # enough: when the test imports doctest again, it will get a fresh + # copy without the monkeypatch. + del sys.modules['doctest'] + + def test_doctest(self): + self.check_coverage('''\ + def return_arg_or_void(arg): + """If <arg> is None, return "Void"; otherwise return <arg> + + >>> return_arg_or_void(None) + 'Void' + >>> return_arg_or_void("arg") + 'arg' + >>> return_arg_or_void("None") + 'None' + """ + if arg is None: + return "Void" + else: + return arg + + import doctest, sys + doctest.testmod(sys.modules[__name__]) # we're not __main__ :( + ''', + [1,11,12,14,16,17], "") if hasattr(sys, 'gettrace'): diff --git a/tests/test_phystokens.py b/tests/test_phystokens.py index c1e51f1c..76e59f3b 100644 --- a/tests/test_phystokens.py +++ b/tests/test_phystokens.py @@ -86,11 +86,6 @@ if sys.version_info < (3, 0): run_in_temp_dir = False - if sys.version_info >= (2,4): - default_encoding = 'ascii' - else: - default_encoding = 'iso-8859-1' - def test_detect_source_encoding(self): # Various forms from http://www.python.org/dev/peps/pep-0263/ source = "# coding=cp850\n\n" @@ -110,11 +105,11 @@ if sys.version_info < (3, 0): def test_dont_detect_source_encoding_on_third_line(self): # A coding declaration doesn't count on the third line. source = "\n\n# coding=cp850\n\n" - self.assertEqual(source_encoding(source), self.default_encoding) + self.assertEqual(source_encoding(source), 'ascii') def test_detect_source_encoding_of_empty_file(self): # An important edge case. - self.assertEqual(source_encoding(""), self.default_encoding) + self.assertEqual(source_encoding(""), 'ascii') def test_bom(self): # A BOM means utf-8. diff --git a/tests/test_process.py b/tests/test_process.py index c49d90a9..d1107e32 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -324,23 +324,20 @@ class ProcessTest(CoverageTest): out_py = self.run_command("python run_me.py") self.assertMultiLineEqual(out_cov, out_py) - if sys.version_info >= (2, 6): - # Doesn't work in 2.5, and I don't care! For some reason, python -m - # in 2.5 has __builtins__ as a dictionary instead of a module? - def test_coverage_run_dashm_is_like_python_dashm(self): - # These -m commands assume the coverage tree is on the path. - out_cov = self.run_command("coverage run -m tests.try_execfile") - out_py = self.run_command("python -m tests.try_execfile") - self.assertMultiLineEqual(out_cov, out_py) + def test_coverage_run_dashm_is_like_python_dashm(self): + # These -m commands assume the coverage tree is on the path. + out_cov = self.run_command("coverage run -m tests.try_execfile") + out_py = self.run_command("python -m tests.try_execfile") + self.assertMultiLineEqual(out_cov, out_py) - def test_coverage_run_dashm_is_like_python_dashm_off_path(self): - # https://bitbucket.org/ned/coveragepy/issue/242 - tryfile = os.path.join(here, "try_execfile.py") - self.make_file("sub/__init__.py", "") - self.make_file("sub/run_me.py", open(tryfile).read()) - out_cov = self.run_command("coverage run -m sub.run_me") - out_py = self.run_command("python -m sub.run_me") - self.assertMultiLineEqual(out_cov, out_py) + def test_coverage_run_dashm_is_like_python_dashm_off_path(self): + # https://bitbucket.org/ned/coveragepy/issue/242 + tryfile = os.path.join(here, "try_execfile.py") + self.make_file("sub/__init__.py", "") + self.make_file("sub/run_me.py", open(tryfile).read()) + out_cov = self.run_command("coverage run -m sub.run_me") + out_py = self.run_command("python -m sub.run_me") + self.assertMultiLineEqual(out_cov, out_py) if sys.version_info >= (2, 7): # Coverage isn't bug-for-bug compatible in the behavior of -m for diff --git a/tox.ini b/tox.ini index 7e78ea4a..1b020493 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ # and then run "tox" from this directory. [tox] -envlist = py25, py26, py27, py31, py32, py33, pypy +envlist = py26, py27, py32, py33, pypy [testenv] commands = -- cgit v1.2.1 From ae983a48b6fe5b006f5f9e9899efc3778ac2b1b1 Mon Sep 17 00:00:00 2001 From: Ned Batchelder <ned@nedbatchelder.com> Date: Sat, 19 Oct 2013 21:23:21 -0400 Subject: Keep the paperwork up-to-date. --HG-- branch : 4.0 --- CHANGES.txt | 6 ++++++ TODO.txt | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index ddb0e476..4b5d996a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -2,6 +2,12 @@ Change history for Coverage.py ------------------------------ +4.0 +--- + +- Python versions supported are now 2.6, 2.7, 3.2, 3.3. + + 3.7.1 ----- diff --git a/TODO.txt b/TODO.txt index 0285b4fc..981c19c1 100644 --- a/TODO.txt +++ b/TODO.txt @@ -20,7 +20,7 @@ Key: - .startswith((,)) -- Remove code only run on <2.6 ++ Remove code only run on <2.6 - Change data file to json - Create data api - New ast-based branch coverage? -- cgit v1.2.1 From c7b1c99b06a453af879f4768e347ac89000cce42 Mon Sep 17 00:00:00 2001 From: Ned Batchelder <ned@nedbatchelder.com> Date: Sat, 19 Oct 2013 21:35:33 -0400 Subject: Get rid of our backward implementation of set, sorted, reversed, and rpartition. --HG-- branch : 4.0 --- TODO.txt | 2 +- coverage/backward.py | 41 ----------------------------------------- coverage/cmdline.py | 1 - coverage/control.py | 2 +- coverage/data.py | 2 +- coverage/misc.py | 2 +- coverage/parser.py | 3 +-- coverage/results.py | 2 +- coverage/xmlreport.py | 3 +-- tests/backunittest.py | 2 -- tests/coveragetest.py | 3 +-- tests/test_collector.py | 1 - tests/test_config.py | 1 - tests/test_files.py | 1 - tests/test_testing.py | 5 ++--- 15 files changed, 10 insertions(+), 61 deletions(-) diff --git a/TODO.txt b/TODO.txt index 981c19c1..2d935161 100644 --- a/TODO.txt +++ b/TODO.txt @@ -13,7 +13,7 @@ Key: - --branch = True ? - Remove 2.3, 2.4, 2.5 limitations - - set, sorted, reversed, rpartition + + set, sorted, reversed, rpartition - generator expressions - decorators - collections.defaultdict diff --git a/coverage/backward.py b/coverage/backward.py index 7d268545..124d0253 100644 --- a/coverage/backward.py +++ b/coverage/backward.py @@ -8,47 +8,6 @@ import os, re, sys -# Python 2.3 doesn't have `set` -try: - set = set # new in 2.4 -except NameError: - from sets import Set as set - -# Python 2.3 doesn't have `sorted`. -try: - sorted = sorted -except NameError: - def sorted(iterable): - """A 2.3-compatible implementation of `sorted`.""" - lst = list(iterable) - lst.sort() - return lst - -# Python 2.3 doesn't have `reversed`. -try: - reversed = reversed -except NameError: - def reversed(iterable): - """A 2.3-compatible implementation of `reversed`.""" - lst = list(iterable) - return lst[::-1] - -# rpartition is new in 2.5 -try: - "".rpartition -except AttributeError: - def rpartition(s, sep): - """Implement s.rpartition(sep) for old Pythons.""" - i = s.rfind(sep) - if i == -1: - return ('', '', s) - else: - return (s[:i], sep, s[i+len(sep):]) -else: - def rpartition(s, sep): - """A common interface for new Pythons.""" - return s.rpartition(sep) - # Pythons 2 and 3 differ on where to get StringIO try: from cStringIO import StringIO diff --git a/coverage/cmdline.py b/coverage/cmdline.py index 0881313e..f2f0c152 100644 --- a/coverage/cmdline.py +++ b/coverage/cmdline.py @@ -2,7 +2,6 @@ import optparse, os, sys, traceback -from coverage.backward import sorted # pylint: disable=W0622 from coverage.execfile import run_python_file, run_python_module from coverage.misc import CoverageException, ExceptionDuringRun, NoSource from coverage.debug import info_formatter diff --git a/coverage/control.py b/coverage/control.py index 4b76121c..31fc511e 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -3,7 +3,7 @@ import atexit, os, random, socket, sys from coverage.annotate import AnnotateReporter -from coverage.backward import string_class, iitems, sorted # pylint: disable=W0622 +from coverage.backward import string_class, iitems from coverage.codeunit import code_unit_factory, CodeUnit from coverage.collector import Collector from coverage.config import CoverageConfig diff --git a/coverage/data.py b/coverage/data.py index fb88c5b1..a32e20a4 100644 --- a/coverage/data.py +++ b/coverage/data.py @@ -2,7 +2,7 @@ import os -from coverage.backward import iitems, pickle, sorted # pylint: disable=W0622 +from coverage.backward import iitems, pickle from coverage.files import PathAliases from coverage.misc import file_be_gone diff --git a/coverage/misc.py b/coverage/misc.py index 2d2662da..70606287 100644 --- a/coverage/misc.py +++ b/coverage/misc.py @@ -5,7 +5,7 @@ import inspect import os import sys -from coverage.backward import md5, sorted # pylint: disable=W0622 +from coverage.backward import md5 from coverage.backward import string_class, to_bytes diff --git a/coverage/parser.py b/coverage/parser.py index 581c8518..2663baca 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -2,9 +2,8 @@ import dis, re, sys, token, tokenize -from coverage.backward import set, sorted, StringIO # pylint: disable=W0622 +from coverage.backward import StringIO from coverage.backward import open_source, range # pylint: disable=W0622 -from coverage.backward import reversed # pylint: disable=W0622 from coverage.backward import bytes_to_ints from coverage.bytecode import ByteCodes, CodeObjects from coverage.misc import nice_pair, expensive, join_regex diff --git a/coverage/results.py b/coverage/results.py index 2d13e818..6507d568 100644 --- a/coverage/results.py +++ b/coverage/results.py @@ -2,7 +2,7 @@ import os -from coverage.backward import iitems, set, sorted # pylint: disable=W0622 +from coverage.backward import iitems from coverage.misc import format_lines, join_regex, NoSource from coverage.parser import CodeParser diff --git a/coverage/xmlreport.py b/coverage/xmlreport.py index 78375249..1abfdefb 100644 --- a/coverage/xmlreport.py +++ b/coverage/xmlreport.py @@ -4,7 +4,6 @@ import os, sys, time import xml.dom.minidom from coverage import __url__, __version__ -from coverage.backward import sorted, rpartition # pylint: disable=W0622 from coverage.report import Reporter def rate(hit, num): @@ -97,7 +96,7 @@ class XmlReporter(Reporter): # Create the 'lines' and 'package' XML elements, which # are populated later. Note that a package == a directory. - package_name = rpartition(cu.name, ".")[0] + package_name = cu.name.rpartition(".")[0] className = cu.name package = self.packages.setdefault(package_name, [{}, 0, 0, 0, 0]) diff --git a/tests/backunittest.py b/tests/backunittest.py index 30da78eb..019e811c 100644 --- a/tests/backunittest.py +++ b/tests/backunittest.py @@ -2,8 +2,6 @@ import difflib, re, sys, unittest -from coverage.backward import set # pylint: disable=W0622 - def _need(method): """Do we need to define our own `method` method?""" diff --git a/tests/coveragetest.py b/tests/coveragetest.py index 9f7c79c9..4fe81910 100644 --- a/tests/coveragetest.py +++ b/tests/coveragetest.py @@ -4,8 +4,7 @@ import glob, imp, os, random, shlex, shutil, sys, tempfile, textwrap import atexit import coverage -from coverage.backward import sorted, StringIO # pylint: disable=W0622 -from coverage.backward import to_bytes +from coverage.backward import StringIO, to_bytes from coverage.control import _TEST_NAME_FILE from tests.backtest import run_command from tests.backunittest import TestCase diff --git a/tests/test_collector.py b/tests/test_collector.py index 2714398a..af3814f3 100644 --- a/tests/test_collector.py +++ b/tests/test_collector.py @@ -4,7 +4,6 @@ import re import coverage from coverage.backward import StringIO -from coverage.backward import set # pylint: disable=W0622 from tests.coveragetest import CoverageTest diff --git a/tests/test_config.py b/tests/test_config.py index c44fa80c..0862d6b2 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- """Test the config file handling for coverage.py""" -import sys import coverage from coverage.misc import CoverageException diff --git a/tests/test_files.py b/tests/test_files.py index b24e8b8b..230cd092 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -4,7 +4,6 @@ import os, os.path from coverage.files import FileLocator, TreeMatcher, FnmatchMatcher from coverage.files import PathAliases, find_python_files, abs_file -from coverage.backward import set # pylint: disable=W0622 from coverage.misc import CoverageException from tests.coveragetest import CoverageTest diff --git a/tests/test_testing.py b/tests/test_testing.py index c56d8110..c6d51ba5 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -2,11 +2,10 @@ """Tests that our test infrastructure is really working!""" import os, sys -from coverage.backward import to_bytes, rpartition +from coverage.backward import to_bytes from tests.backunittest import TestCase from tests.coveragetest import CoverageTest -from coverage.backward import set # pylint: disable=W0622 class TestingTest(TestCase): """Tests of helper methods on `backunittest.TestCase`.""" @@ -188,7 +187,7 @@ class CoverageTestTest(CoverageTest): executable = executable.split(":", 1)[1].strip() self.assertTrue(same_python_executable(executable, sys.executable)) environ = [l for l in out if "COV_FOOBAR" in l][0] - _, _, environ = rpartition(environ, ":") + _, _, environ = environ.rpartition(":") self.assertEqual(environ.strip(), "COV_FOOBAR = XYZZY") -- cgit v1.2.1 From 6224a804d07119eb228a11d306bf392e3d0b266a Mon Sep 17 00:00:00 2001 From: Ned Batchelder <ned@nedbatchelder.com> Date: Sat, 19 Oct 2013 21:42:29 -0400 Subject: Now I can use tuples with startswith and endswith. --HG-- branch : 4.0 --- TODO.txt | 2 +- coverage/codeunit.py | 2 +- coverage/execfile.py | 2 +- coverage/files.py | 2 +- tests/test_collector.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/TODO.txt b/TODO.txt index 2d935161..4dbc6649 100644 --- a/TODO.txt +++ b/TODO.txt @@ -17,7 +17,7 @@ Key: - generator expressions - decorators - collections.defaultdict - - .startswith((,)) + + .startswith((,)) + Remove code only run on <2.6 diff --git a/coverage/codeunit.py b/coverage/codeunit.py index ca1ae5c5..c58e237b 100644 --- a/coverage/codeunit.py +++ b/coverage/codeunit.py @@ -52,7 +52,7 @@ class CodeUnit(object): else: f = morf # .pyc files should always refer to a .py instead. - if f.endswith('.pyc') or f.endswith('.pyo'): + if f.endswith(('.pyc', '.pyo')): f = f[:-1] elif f.endswith('$py.class'): # Jython f = f[:-9] + ".py" diff --git a/coverage/execfile.py b/coverage/execfile.py index f6ebdf79..5d4ae690 100644 --- a/coverage/execfile.py +++ b/coverage/execfile.py @@ -94,7 +94,7 @@ def run_python_file(filename, args, package=None): try: # Make a code object somehow. - if filename.endswith(".pyc") or filename.endswith(".pyo"): + if filename.endswith((".pyc", ".pyo")): code = make_code_from_pyc(filename) else: code = make_code_from_py(filename) diff --git a/coverage/files.py b/coverage/files.py index 464535a8..94388f96 100644 --- a/coverage/files.py +++ b/coverage/files.py @@ -137,7 +137,7 @@ def prep_patterns(patterns): """ prepped = [] for p in patterns or []: - if p.startswith("*") or p.startswith("?"): + if p.startswith(("*", "?")): prepped.append(p) else: prepped.append(abs_file(p)) diff --git a/tests/test_collector.py b/tests/test_collector.py index af3814f3..7bd4bebb 100644 --- a/tests/test_collector.py +++ b/tests/test_collector.py @@ -48,7 +48,7 @@ class CollectorTest(CoverageTest): # duplicates. trace_lines = [ l for l in debug_out.getvalue().splitlines() - if l.startswith("Tracing ") or l.startswith("Not tracing ") + if l.startswith(("Tracing ", "Not tracing ")) ] filenames = [re.search(r"'[^']+'", l).group() for l in trace_lines] self.assertEqual(len(filenames), len(set(filenames))) -- cgit v1.2.1 From b3df60a544a54b4dd604d34137ff08e02b815e81 Mon Sep 17 00:00:00 2001 From: Ned Batchelder <ned@nedbatchelder.com> Date: Sat, 19 Oct 2013 21:52:22 -0400 Subject: Now I can use decorators. --HG-- branch : 4.0 --- TODO.txt | 3 ++- coverage/parser.py | 4 ++-- coverage/results.py | 20 ++++++++++---------- tests/coveragetest.py | 2 +- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/TODO.txt b/TODO.txt index 4dbc6649..a134bb47 100644 --- a/TODO.txt +++ b/TODO.txt @@ -15,9 +15,10 @@ Key: - Remove 2.3, 2.4, 2.5 limitations + set, sorted, reversed, rpartition - generator expressions - - decorators + + decorators - collections.defaultdict + .startswith((,)) + - "with" statements + Remove code only run on <2.6 diff --git a/coverage/parser.py b/coverage/parser.py index 2663baca..0873e7af 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -65,13 +65,13 @@ class CodeParser(object): # Lazily-created ByteParser self._byte_parser = None - def _get_byte_parser(self): + @property + def byte_parser(self): """Create a ByteParser on demand.""" if not self._byte_parser: self._byte_parser = \ ByteParser(text=self.text, filename=self.filename) return self._byte_parser - byte_parser = property(_get_byte_parser) def lines_matching(self, *regexes): """Find the lines matching one of a list of regexes. diff --git a/coverage/results.py b/coverage/results.py index 6507d568..7ffd66bf 100644 --- a/coverage/results.py +++ b/coverage/results.py @@ -210,25 +210,26 @@ class Numbers(object): self.n_partial_branches = n_partial_branches self.n_missing_branches = n_missing_branches + @classmethod def set_precision(cls, precision): """Set the number of decimal places used to report percentages.""" assert 0 <= precision < 10 cls._precision = precision cls._near0 = 1.0 / 10**precision cls._near100 = 100.0 - cls._near0 - set_precision = classmethod(set_precision) - def _get_n_executed(self): + @property + def n_executed(self): """Returns the number of executed statements.""" return self.n_statements - self.n_missing - n_executed = property(_get_n_executed) - def _get_n_executed_branches(self): + @property + def n_executed_branches(self): """Returns the number of executed branches.""" return self.n_branches - self.n_missing_branches - n_executed_branches = property(_get_n_executed_branches) - def _get_pc_covered(self): + @property + def pc_covered(self): """Returns a single percentage value for coverage.""" if self.n_statements > 0: pc_cov = (100.0 * (self.n_executed + self.n_executed_branches) / @@ -236,9 +237,9 @@ class Numbers(object): else: pc_cov = 100.0 return pc_cov - pc_covered = property(_get_pc_covered) - def _get_pc_covered_str(self): + @property + def pc_covered_str(self): """Returns the percent covered, as a string, without a percent sign. Note that "0" is only returned when the value is truly zero, and "100" @@ -254,15 +255,14 @@ class Numbers(object): else: pc = round(pc, self._precision) return "%.*f" % (self._precision, pc) - pc_covered_str = property(_get_pc_covered_str) + @classmethod def pc_str_width(cls): """How many characters wide can pc_covered_str be?""" width = 3 # "100" if cls._precision > 0: width += 1 + cls._precision return width - pc_str_width = classmethod(pc_str_width) def __add__(self, other): nums = Numbers() diff --git a/tests/coveragetest.py b/tests/coveragetest.py index 4fe81910..cb2957da 100644 --- a/tests/coveragetest.py +++ b/tests/coveragetest.py @@ -508,6 +508,7 @@ class CoverageTest(TestCase): # Map from class to info about how it ran. class_behaviors = {} + @classmethod def report_on_class_behavior(cls): """Called at process exit to report on class behavior.""" for test_class, behavior in cls.class_behaviors.items(): @@ -532,7 +533,6 @@ class CoverageTest(TestCase): where, ) ) - report_on_class_behavior = classmethod(report_on_class_behavior) def class_behavior(self): """Get the ClassBehavior instance for this test.""" -- cgit v1.2.1 From bad63e02b113626a048ea5eb253293c61902e291 Mon Sep 17 00:00:00 2001 From: Ned Batchelder <ned@nedbatchelder.com> Date: Sat, 19 Oct 2013 22:08:37 -0400 Subject: Generator expressons are ok now. --HG-- branch : 4.0 --- TODO.txt | 2 +- coverage/backward.py | 2 +- coverage/config.py | 2 +- coverage/data.py | 4 ++-- coverage/debug.py | 2 +- coverage/html.py | 2 +- coverage/misc.py | 4 ++-- coverage/parser.py | 10 +++++----- coverage/results.py | 16 ++++++++-------- coverage/xmlreport.py | 4 ++-- igor.py | 2 +- tests/coveragetest.py | 10 +++++----- tests/test_farm.py | 4 ++-- tests/test_phystokens.py | 2 +- tests/test_process.py | 2 +- tests/test_testing.py | 4 ++-- 16 files changed, 36 insertions(+), 36 deletions(-) diff --git a/TODO.txt b/TODO.txt index a134bb47..d53dc688 100644 --- a/TODO.txt +++ b/TODO.txt @@ -14,7 +14,7 @@ Key: - Remove 2.3, 2.4, 2.5 limitations + set, sorted, reversed, rpartition - - generator expressions + + generator expressions + decorators - collections.defaultdict + .startswith((,)) diff --git a/coverage/backward.py b/coverage/backward.py index 124d0253..8237d01b 100644 --- a/coverage/backward.py +++ b/coverage/backward.py @@ -123,7 +123,7 @@ else: def binary_bytes(byte_values): """Produce a byte string with the ints from `byte_values`.""" - return "".join([chr(b) for b in byte_values]) + return "".join(chr(b) for b in byte_values) def byte_to_int(byte_value): """Turn an element of a bytes object into an int.""" diff --git a/coverage/config.py b/coverage/config.py index 87318ff1..6223afda 100644 --- a/coverage/config.py +++ b/coverage/config.py @@ -25,7 +25,7 @@ class HandyConfigParser(configparser.RawConfigParser): def dollar_replace(m): """Called for each $replacement.""" # Only one of the groups will have matched, just get its text. - word = [w for w in m.groups() if w is not None][0] + word = next(w for w in m.groups() if w is not None) if word == "$": return "$" else: diff --git a/coverage/data.py b/coverage/data.py index a32e20a4..61b3554f 100644 --- a/coverage/data.py +++ b/coverage/data.py @@ -101,13 +101,13 @@ class CoverageData(object): def line_data(self): """Return the map from filenames to lists of line numbers executed.""" return dict( - [(f, sorted(lmap.keys())) for f, lmap in iitems(self.lines)] + (f, sorted(lmap.keys())) for f, lmap in iitems(self.lines) ) def arc_data(self): """Return the map from filenames to lists of line number pairs.""" return dict( - [(f, sorted(amap.keys())) for f, amap in iitems(self.arcs)] + (f, sorted(amap.keys())) for f, amap in iitems(self.arcs) ) def write_file(self, filename): diff --git a/coverage/debug.py b/coverage/debug.py index 104f3b1d..6908383d 100644 --- a/coverage/debug.py +++ b/coverage/debug.py @@ -41,7 +41,7 @@ def info_formatter(info): nicely formatted, ready to print. """ - label_len = max([len(l) for l, _d in info]) + label_len = max(len(l) for l, _d in info) for label, data in info: if data == []: data = "-none-" diff --git a/coverage/html.py b/coverage/html.py index 956f070e..e0262998 100644 --- a/coverage/html.py +++ b/coverage/html.py @@ -270,7 +270,7 @@ class HtmlReporter(Reporter): data("index.html"), self.template_globals ) - self.totals = sum([f['nums'] for f in self.files]) + self.totals = sum(f['nums'] for f in self.files) html = index_tmpl.render({ 'arcs': self.arcs, diff --git a/coverage/misc.py b/coverage/misc.py index 70606287..2a36d5c1 100644 --- a/coverage/misc.py +++ b/coverage/misc.py @@ -57,7 +57,7 @@ def format_lines(statements, lines): def short_stack(): """Return a string summarizing the call stack.""" stack = inspect.stack()[:0:-1] - return "\n".join(["%30s : %s @%d" % (t[3],t[1],t[2]) for t in stack]) + return "\n".join("%30s : %s @%d" % (t[3],t[1],t[2]) for t in stack) def expensive(fn): @@ -86,7 +86,7 @@ def bool_or_none(b): def join_regex(regexes): """Combine a list of regexes into one that matches any of them.""" if len(regexes) > 1: - return "|".join(["(%s)" % r for r in regexes]) + return "|".join("(%s)" % r for r in regexes) elif regexes: return regexes[0] else: diff --git a/coverage/parser.py b/coverage/parser.py index 0873e7af..010cd73a 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -365,7 +365,7 @@ class ByteParser(object): """ children = CodeObjects(self.code) - return [ByteParser(code=c, text=self.text) for c in children] + return (ByteParser(code=c, text=self.text) for c in children) def _bytes_lines(self): """Map byte offsets to line numbers in `code`. @@ -409,7 +409,7 @@ class ByteParser(object): def _block_stack_repr(self, block_stack): """Get a string version of `block_stack`, for debugging.""" blocks = ", ".join( - ["(%s, %r)" % (dis.opname[b[0]], b[1]) for b in block_stack] + "(%s, %r)" % (dis.opname[b[0]], b[1]) for b in block_stack ) return "[" + blocks + "]" @@ -547,9 +547,9 @@ class ByteParser(object): def validate_chunks(self, chunks): """Validate the rule that chunks have a single entrance.""" # starts is the entrances to the chunks - starts = set([ch.byte for ch in chunks]) + starts = set(ch.byte for ch in chunks) for ch in chunks: - assert all([(ex in starts or ex < 0) for ex in ch.exits]) + assert all((ex in starts or ex < 0) for ex in ch.exits) def _arcs(self): """Find the executable arcs in the code. @@ -562,7 +562,7 @@ class ByteParser(object): chunks = self._split_into_chunks() # A map from byte offsets to chunks jumped into. - byte_chunks = dict([(c.byte, c) for c in chunks]) + byte_chunks = dict((c.byte, c) for c in chunks) # There's always an entrance at the first chunk. yield (-1, byte_chunks[0].line) diff --git a/coverage/results.py b/coverage/results.py index 7ffd66bf..bfd9e52e 100644 --- a/coverage/results.py +++ b/coverage/results.py @@ -36,9 +36,9 @@ class Analysis(object): n_branches = self.total_branches() mba = self.missing_branch_arcs() n_partial_branches = sum( - [len(v) for k,v in iitems(mba) if k not in self.missing] + len(v) for k,v in iitems(mba) if k not in self.missing ) - n_missing_branches = sum([len(v) for k,v in iitems(mba)]) + n_missing_branches = sum(len(v) for k,v in iitems(mba)) else: n_branches = n_partial_branches = n_missing_branches = 0 self.no_branch = set() @@ -112,18 +112,18 @@ class Analysis(object): """Returns a sorted list of the arcs actually executed in the code.""" executed = self.coverage.data.executed_arcs(self.filename) m2fl = self.parser.first_line - executed = [(m2fl(l1), m2fl(l2)) for (l1,l2) in executed] + executed = ((m2fl(l1), m2fl(l2)) for (l1,l2) in executed) return sorted(executed) def arcs_missing(self): """Returns a sorted list of the arcs in the code not executed.""" possible = self.arc_possibilities() executed = self.arcs_executed() - missing = [ + missing = ( p for p in possible if p not in executed and p[0] not in self.no_branch - ] + ) return sorted(missing) def arcs_unpredicted(self): @@ -133,11 +133,11 @@ class Analysis(object): # Exclude arcs here which connect a line to itself. They can occur # in executed data in some cases. This is where they can cause # trouble, and here is where it's the least burden to remove them. - unpredicted = [ + unpredicted = ( e for e in executed if e not in possible and e[0] != e[1] - ] + ) return sorted(unpredicted) def branch_lines(self): @@ -148,7 +148,7 @@ class Analysis(object): def total_branches(self): """How many total branches are there?""" exit_counts = self.parser.exit_counts() - return sum([count for count in exit_counts.values() if count > 1]) + return sum(count for count in exit_counts.values() if count > 1) def missing_branch_arcs(self): """Return arcs that weren't executed from branch lines. diff --git a/coverage/xmlreport.py b/coverage/xmlreport.py index 1abfdefb..d4b102fa 100644 --- a/coverage/xmlreport.py +++ b/coverage/xmlreport.py @@ -137,8 +137,8 @@ class XmlReporter(Reporter): class_hits = class_lines - len(analysis.missing) if self.arcs: - class_branches = sum([t for t,k in branch_stats.values()]) - missing_branches = sum([t-k for t,k in branch_stats.values()]) + class_branches = sum(t for t, k in branch_stats.values()) + missing_branches = sum(t - k for t, k in branch_stats.values()) class_br_hits = class_branches - missing_branches else: class_branches = 0.0 diff --git a/igor.py b/igor.py index 12ec6c8f..9f33f153 100644 --- a/igor.py +++ b/igor.py @@ -216,7 +216,7 @@ def print_banner(label): if '__pypy__' in sys.builtin_module_names: pypy_version = sys.pypy_version_info # pylint: disable=E1101 - version += " (pypy %s)" % ".".join([str(v) for v in pypy_version]) + version += " (pypy %s)" % ".".join(str(v) for v in pypy_version) print('=== %s %s %s (%s) ===' % (impl, version, label, sys.executable)) diff --git a/tests/coveragetest.py b/tests/coveragetest.py index cb2957da..d4d82f12 100644 --- a/tests/coveragetest.py +++ b/tests/coveragetest.py @@ -266,10 +266,10 @@ class CoverageTest(TestCase): # Map chars to numbers for arcz_to_arcs _arcz_map = {'.': -1} - _arcz_map.update(dict([(c, ord(c)-ord('0')) for c in '123456789'])) + _arcz_map.update(dict((c, ord(c)-ord('0')) for c in '123456789')) _arcz_map.update(dict( - [(c, 10+ord(c)-ord('A')) for c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'] - )) + (c, 10+ord(c)-ord('A')) for c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + )) def arcz_to_arcs(self, arcz): """Convert a compact textual representation of arcs to a list of pairs. @@ -305,8 +305,8 @@ class CoverageTest(TestCase): def assertEqualArcs(self, a1, a2, msg=None): """Assert that the arc lists `a1` and `a2` are equal.""" # Make them into multi-line strings so we can see what's going wrong. - s1 = "\n".join([repr(a) for a in a1]) + "\n" - s2 = "\n".join([repr(a) for a in a2]) + "\n" + s1 = "\n".join(repr(a) for a in a1) + "\n" + s2 = "\n".join(repr(a) for a in a2) + "\n" self.assertMultiLineEqual(s1, s2, msg) def check_coverage(self, text, lines=None, missing="", report="", diff --git a/tests/test_farm.py b/tests/test_farm.py index fee28063..c86983e5 100644 --- a/tests/test_farm.py +++ b/tests/test_farm.py @@ -78,10 +78,10 @@ class FarmTestCase(object): copy run runfunc compare contains doesnt_contain clean skip """.split() if self.clean_only: - glo = dict([(fn, self.noop) for fn in fns]) + glo = dict((fn, self.noop) for fn in fns) glo['clean'] = self.clean else: - glo = dict([(fn, getattr(self, fn)) for fn in fns]) + glo = dict((fn, getattr(self, fn)) for fn in fns) if self.dont_clean: # pragma: not covered glo['clean'] = self.noop diff --git a/tests/test_phystokens.py b/tests/test_phystokens.py index 76e59f3b..9ff053c4 100644 --- a/tests/test_phystokens.py +++ b/tests/test_phystokens.py @@ -29,7 +29,7 @@ class PhysTokensTest(CoverageTest): """Tokenize `source`, then put it back together, should be the same.""" tokenized = "" for line in source_token_lines(source): - text = "".join([t for _,t in line]) + text = "".join(t for _, t in line) tokenized += text + "\n" # source_token_lines doesn't preserve trailing spaces, so trim all that # before comparing. diff --git a/tests/test_process.py b/tests/test_process.py index d1107e32..4453fc57 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -270,7 +270,7 @@ class ProcessTest(CoverageTest): if '__pypy__' in sys.builtin_module_names: # Pypy has an extra frame in the traceback for some reason lines2 = out2.splitlines() - out2 = "".join([l+"\n" for l in lines2 if "toplevel" not in l]) + out2 = "".join(l+"\n" for l in lines2 if "toplevel" not in l) self.assertMultiLineEqual(out, out2) # But also make sure that the output is what we expect. diff --git a/tests/test_testing.py b/tests/test_testing.py index c6d51ba5..64dca617 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -183,10 +183,10 @@ class CoverageTestTest(CoverageTest): # Try it with a "coverage debug sys" command. out = self.run_command("coverage debug sys").splitlines() # "environment: COV_FOOBAR = XYZZY" or "COV_FOOBAR = XYZZY" - executable = [l for l in out if "executable:" in l][0] + executable = next(l for l in out if "executable:" in l) executable = executable.split(":", 1)[1].strip() self.assertTrue(same_python_executable(executable, sys.executable)) - environ = [l for l in out if "COV_FOOBAR" in l][0] + environ = next(l for l in out if "COV_FOOBAR" in l) _, _, environ = environ.rpartition(":") self.assertEqual(environ.strip(), "COV_FOOBAR = XYZZY") -- cgit v1.2.1 From 35cfd9334d381d06e8a5364a2eaa4b7b8d7b0bbc Mon Sep 17 00:00:00 2001 From: Ned Batchelder <ned@nedbatchelder.com> Date: Sun, 20 Oct 2013 07:38:41 -0400 Subject: Now I can use collections.defaultdict --HG-- branch : 4.0 --- TODO.txt | 4 ++-- coverage/parser.py | 6 ++---- coverage/results.py | 5 ++--- tests/coveragetest.py | 9 +++------ 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/TODO.txt b/TODO.txt index d53dc688..30d5bd6a 100644 --- a/TODO.txt +++ b/TODO.txt @@ -16,10 +16,10 @@ Key: + set, sorted, reversed, rpartition + generator expressions + decorators - - collections.defaultdict + + collections.defaultdict + .startswith((,)) - "with" statements - + - .format() ? + Remove code only run on <2.6 - Change data file to json diff --git a/coverage/parser.py b/coverage/parser.py index 010cd73a..6332f637 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -1,6 +1,6 @@ """Code parsing for Coverage.""" -import dis, re, sys, token, tokenize +import collections, dis, re, sys, token, tokenize from coverage.backward import StringIO from coverage.backward import open_source, range # pylint: disable=W0622 @@ -242,7 +242,7 @@ class CodeParser(object): """ excluded_lines = self.first_lines(self.excluded) - exit_counts = {} + exit_counts = collections.defaultdict(int) for l1, l2 in self.arcs(): if l1 < 0: # Don't ever report -1 as a line number @@ -253,8 +253,6 @@ class CodeParser(object): if l2 in excluded_lines: # Arcs to excluded lines shouldn't count. continue - if l1 not in exit_counts: - exit_counts[l1] = 0 exit_counts[l1] += 1 # Class definitions have one extra exit, so remove one for each: diff --git a/coverage/results.py b/coverage/results.py index bfd9e52e..e6475afb 100644 --- a/coverage/results.py +++ b/coverage/results.py @@ -1,5 +1,6 @@ """Results of coverage measurement.""" +import collections import os from coverage.backward import iitems @@ -158,11 +159,9 @@ class Analysis(object): """ missing = self.arcs_missing() branch_lines = set(self.branch_lines()) - mba = {} + mba = collections.defaultdict(list) for l1, l2 in missing: if l1 in branch_lines: - if l1 not in mba: - mba[l1] = [] mba[l1].append(l2) return mba diff --git a/tests/coveragetest.py b/tests/coveragetest.py index d4d82f12..f3ca53a1 100644 --- a/tests/coveragetest.py +++ b/tests/coveragetest.py @@ -1,7 +1,7 @@ """Base test case class for coverage testing.""" import glob, imp, os, random, shlex, shutil, sys, tempfile, textwrap -import atexit +import atexit, collections import coverage from coverage.backward import StringIO, to_bytes @@ -506,7 +506,7 @@ class CoverageTest(TestCase): self.test_method_made_any_files = False # Map from class to info about how it ran. - class_behaviors = {} + class_behaviors = collections.defaultdict(ClassBehavior) @classmethod def report_on_class_behavior(cls): @@ -536,10 +536,7 @@ class CoverageTest(TestCase): def class_behavior(self): """Get the ClassBehavior instance for this test.""" - cls = self.__class__ - if cls not in self.class_behaviors: - self.class_behaviors[cls] = self.ClassBehavior() - return self.class_behaviors[cls] + return self.class_behaviors[self.__class__] # When the process ends, find out about bad classes. -- cgit v1.2.1 From 2e5688eedd1576e9b100386c0a9ae30828123f73 Mon Sep 17 00:00:00 2001 From: Ned Batchelder <ned@nedbatchelder.com> Date: Sun, 20 Oct 2013 07:40:37 -0400 Subject: My own decorators can be decorators --HG-- branch : 4.0 --- coverage/parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coverage/parser.py b/coverage/parser.py index 6332f637..37beeded 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -219,6 +219,7 @@ class CodeParser(object): return lines, excluded_lines + @expensive def arcs(self): """Get information about the arcs available in the code. @@ -233,8 +234,8 @@ class CodeParser(object): if fl1 != fl2: all_arcs.append((fl1, fl2)) return sorted(all_arcs) - arcs = expensive(arcs) + @expensive def exit_counts(self): """Get a mapping from line numbers to count of exits from that line. @@ -262,7 +263,6 @@ class CodeParser(object): exit_counts[l] -= 1 return exit_counts - exit_counts = expensive(exit_counts) ## Opcodes that guide the ByteParser. -- cgit v1.2.1 From 6b6a4488adc12d390c5e0c8f13829dd9bf125309 Mon Sep 17 00:00:00 2001 From: Ned Batchelder <ned@nedbatchelder.com> Date: Sun, 20 Oct 2013 07:58:57 -0400 Subject: with statements: no more finally close --HG-- branch : 4.0 --- TODO.txt | 3 ++- coverage/data.py | 10 ++-------- coverage/execfile.py | 8 ++------ coverage/html.py | 24 +++++------------------- coverage/parser.py | 10 ++-------- doc/_ext/px_cleaner.py | 11 ++--------- igor.py | 5 +---- setup.py | 5 +---- tests/coveragetest.py | 12 ++++-------- tests/osinfo.py | 5 +---- tests/test_data.py | 10 ++-------- tests/test_execfile.py | 5 +---- tests/test_process.py | 5 +---- 13 files changed, 26 insertions(+), 87 deletions(-) diff --git a/TODO.txt b/TODO.txt index 30d5bd6a..43a36597 100644 --- a/TODO.txt +++ b/TODO.txt @@ -18,8 +18,9 @@ Key: + decorators + collections.defaultdict + .startswith((,)) - - "with" statements + + "with" statements - .format() ? + - try/except/finally + Remove code only run on <2.6 - Change data file to json diff --git a/coverage/data.py b/coverage/data.py index 61b3554f..042b6405 100644 --- a/coverage/data.py +++ b/coverage/data.py @@ -128,11 +128,8 @@ class CoverageData(object): self.debug.write("Writing data to %r" % (filename,)) # Write the pickle to the file. - fdata = open(filename, 'wb') - try: + with open(filename, 'wb') as fdata: pickle.dump(data, fdata, 2) - finally: - fdata.close() def read_file(self, filename): """Read the coverage data from `filename`.""" @@ -142,11 +139,8 @@ class CoverageData(object): """Return the raw pickled data from `filename`.""" if self.debug and self.debug.should('dataio'): self.debug.write("Reading data from %r" % (filename,)) - fdata = open(filename, 'rb') - try: + with open(filename, 'rb') as fdata: data = pickle.load(fdata) - finally: - fdata.close() return data def _read_file(self, filename): diff --git a/coverage/execfile.py b/coverage/execfile.py index 5d4ae690..71ec9318 100644 --- a/coverage/execfile.py +++ b/coverage/execfile.py @@ -129,10 +129,8 @@ def make_code_from_py(filename): except IOError: raise NoSource("No file to run: %r" % filename) - try: + with source_file: source = source_file.read() - finally: - source_file.close() # We have the source. `compile` still needs the last line to be clean, # so make sure it is, then compile a code object from it. @@ -150,7 +148,7 @@ def make_code_from_pyc(filename): except IOError: raise NoCode("No file to run: %r" % filename) - try: + with fpyc: # First four bytes are a version-specific magic number. It has to # match or we won't run the file. magic = fpyc.read(4) @@ -165,7 +163,5 @@ def make_code_from_pyc(filename): # The rest of the file is the code object we want. code = marshal.load(fpyc) - finally: - fpyc.close() return code diff --git a/coverage/html.py b/coverage/html.py index e0262998..d8779233 100644 --- a/coverage/html.py +++ b/coverage/html.py @@ -43,11 +43,8 @@ def data_filename(fname, pkgdir=""): def data(fname): """Return the contents of a data file of ours.""" - data_file = open(data_filename(fname)) - try: + with open(data_filename(fname)) as data_file: return data_file.read() - finally: - data_file.close() class HtmlReporter(Reporter): @@ -140,11 +137,8 @@ class HtmlReporter(Reporter): def write_html(self, fname, html): """Write `html` to `fname`, properly encoded.""" - fout = open(fname, "wb") - try: + with open(fname, "wb") as fout: fout.write(html.encode('ascii', 'xmlcharrefreplace')) - finally: - fout.close() def file_hash(self, source, cu): """Compute a hash that changes if the file needs to be re-reported.""" @@ -156,10 +150,8 @@ class HtmlReporter(Reporter): def html_file(self, cu, analysis): """Generate an HTML file for one source file.""" source_file = cu.source_file() - try: + with source_file: source = source_file.read() - finally: - source_file.close() # Find out if the file on disk is already correct. flat_rootname = cu.flat_rootname() @@ -309,11 +301,8 @@ class HtmlStatus(object): usable = False try: status_file = os.path.join(directory, self.STATUS_FILE) - fstatus = open(status_file, "rb") - try: + with open(status_file, "rb") as fstatus: status = pickle.load(fstatus) - finally: - fstatus.close() except (IOError, ValueError): usable = False else: @@ -338,11 +327,8 @@ class HtmlStatus(object): 'settings': self.settings, 'files': self.files, } - fout = open(status_file, "wb") - try: + with open(status_file, "wb") as fout: pickle.dump(status, fout) - finally: - fout.close() def settings_hash(self): """Get the hash of the coverage.py settings.""" diff --git a/coverage/parser.py b/coverage/parser.py index 37beeded..d0fe9976 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -25,11 +25,8 @@ class CodeParser(object): self.text = text if not self.text: try: - sourcef = open_source(self.filename) - try: + with open_source(self.filename) as sourcef: self.text = sourcef.read() - finally: - sourcef.close() except IOError: _, err, _ = sys.exc_info() raise NoSource( @@ -328,11 +325,8 @@ class ByteParser(object): else: if not text: assert filename, "If no code or text, need a filename" - sourcef = open_source(filename) - try: + with open_source(filename) as sourcef: text = sourcef.read() - finally: - sourcef.close() self.text = text try: diff --git a/doc/_ext/px_cleaner.py b/doc/_ext/px_cleaner.py index a5c00ff3..24541207 100644 --- a/doc/_ext/px_cleaner.py +++ b/doc/_ext/px_cleaner.py @@ -5,17 +5,11 @@ import sys def clean_px(fname): """Clean a px file.""" - f = open(fname) - try: + with open(fname) as f: text = f.read() - finally: - f.close() text = text.lstrip() - f = open(fname, "w") - try: + with open(fname, "w") as f: f.write(text) - finally: - f.close() def clean_px_files(fnames): for fname in fnames: @@ -23,4 +17,3 @@ def clean_px_files(fnames): if __name__ == '__main__': clean_px_files(sys.argv[1:]) - diff --git a/igor.py b/igor.py index 9f33f153..6c5d56bf 100644 --- a/igor.py +++ b/igor.py @@ -62,11 +62,8 @@ def run_tests_with_coverage(tracer, *nose_args): import nose pth_dir = os.path.dirname(os.path.dirname(nose.__file__)) pth_path = os.path.join(pth_dir, "covcov.pth") - pth_file = open(pth_path, "w") - try: + with open(pth_path, "w") as pth_file: pth_file.write("import coverage; coverage.process_startup()\n") - finally: - pth_file.close() version = "%s%s" % sys.version_info[:2] suffix = "%s_%s_%s" % (version, tracer, socket.gethostname()) diff --git a/setup.py b/setup.py index e96bdb75..215102bd 100644 --- a/setup.py +++ b/setup.py @@ -54,11 +54,8 @@ doc = __doc__ # __doc__ will be overwritten by version.py. __version__ = __url__ = "" # Keep pylint happy. cov_ver_py = os.path.join(os.path.split(__file__)[0], "coverage/version.py") -version_file = open(cov_ver_py) -try: +with open(cov_ver_py) as version_file: exec(compile(version_file.read(), cov_ver_py, 'exec')) -finally: - version_file.close() doclines = (doc % __url__).splitlines() classifier_list = classifiers.splitlines() diff --git a/tests/coveragetest.py b/tests/coveragetest.py index f3ca53a1..e1c38b29 100644 --- a/tests/coveragetest.py +++ b/tests/coveragetest.py @@ -190,11 +190,8 @@ class CoverageTest(TestCase): os.makedirs(dirs) # Create the file. - f = open(filename, 'wb') - try: + with open(filename, 'wb') as f: f.write(to_bytes(text)) - finally: - f.close() return filename @@ -223,17 +220,16 @@ class CoverageTest(TestCase): """ modfile = modname + '.py' - f = open(modfile, 'r') for suff in imp.get_suffixes(): if suff[0] == '.py': break - try: + + with open(modfile, 'r') as f: # pylint: disable=W0631 # (Using possibly undefined loop variable 'suff') mod = imp.load_module(modname, f, modfile, suff) - finally: - f.close() + return mod def start_import_stop(self, cov, modname): diff --git a/tests/osinfo.py b/tests/osinfo.py index acbec231..a123123c 100644 --- a/tests/osinfo.py +++ b/tests/osinfo.py @@ -44,11 +44,8 @@ elif sys.platform == 'linux2': """Read the /proc/PID/status file to find memory use.""" try: # get pseudo file /proc/<pid>/status - t = open('/proc/%d/status' % os.getpid()) - try: + with open('/proc/%d/status' % os.getpid()) as t: v = t.read() - finally: - t.close() except IOError: return 0 # non-Linux? # get VmKey line e.g. 'VmRSS: 9999 kB\n ...' diff --git a/tests/test_data.py b/tests/test_data.py index 9c29289d..31578f26 100644 --- a/tests/test_data.py +++ b/tests/test_data.py @@ -92,11 +92,8 @@ class DataTest(CoverageTest): covdata.add_line_data(DATA_1) covdata.write() - fdata = open(".coverage", 'rb') - try: + with open(".coverage", 'rb') as fdata: data = pickle.load(fdata) - finally: - fdata.close() lines = data['lines'] self.assertSameElements(lines.keys(), MEASURED_FILES_1) @@ -111,11 +108,8 @@ class DataTest(CoverageTest): covdata.add_arc_data(ARC_DATA_3) covdata.write() - fdata = open(".coverage", 'rb') - try: + with open(".coverage", 'rb') as fdata: data = pickle.load(fdata) - finally: - fdata.close() self.assertSameElements(data['lines'].keys(), []) arcs = data['arcs'] diff --git a/tests/test_execfile.py b/tests/test_execfile.py index 24c521bd..ca13d7c8 100644 --- a/tests/test_execfile.py +++ b/tests/test_execfile.py @@ -54,11 +54,8 @@ class RunFileTest(CoverageTest): # Make sure we can read any sort of line ending. pylines = """# try newlines|print('Hello, world!')|""".split('|') for nl in ('\n', '\r\n', '\r'): - fpy = open('nl.py', 'wb') - try: + with open('nl.py', 'wb') as fpy: fpy.write(nl.join(pylines).encode('utf-8')) - finally: - fpy.close() run_python_file('nl.py', ['nl.py']) self.assertEqual(self.stdout(), "Hello, world!\n"*3) diff --git a/tests/test_process.py b/tests/test_process.py index 4453fc57..1ab56e8f 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -572,16 +572,13 @@ class ProcessStartupTest(CoverageTest): g = glob.glob(os.path.join(d, "*.pth")) if g: pth_path = os.path.join(d, "subcover.pth") - pth = open(pth_path, "w") - try: + with open(pth_path, "w") as pth: try: pth.write(pth_contents) self.pth_path = pth_path break except (IOError, OSError): # pragma: not covered pass - finally: - pth.close() else: # pragma: not covered raise Exception("Couldn't find a place for the .pth file") -- cgit v1.2.1 From 8c3cddefe07e25d96d9e9c4d7ea24b345d88eeec Mon Sep 17 00:00:00 2001 From: Ned Batchelder <ned@nedbatchelder.com> Date: Sun, 20 Oct 2013 08:05:24 -0400 Subject: try/except/finally is ok now. --HG-- branch : 4.0 --- TODO.txt | 2 +- coverage/cmdline.py | 21 ++++++++++---------- coverage/control.py | 11 +++++------ coverage/execfile.py | 55 ++++++++++++++++++++++++++-------------------------- 4 files changed, 43 insertions(+), 46 deletions(-) diff --git a/TODO.txt b/TODO.txt index 43a36597..c43c91af 100644 --- a/TODO.txt +++ b/TODO.txt @@ -20,7 +20,7 @@ Key: + .startswith((,)) + "with" statements - .format() ? - - try/except/finally + + try/except/finally + Remove code only run on <2.6 - Change data file to json diff --git a/coverage/cmdline.py b/coverage/cmdline.py index f2f0c152..9ff29f3a 100644 --- a/coverage/cmdline.py +++ b/coverage/cmdline.py @@ -564,17 +564,16 @@ class CoverageScript(object): self.coverage.start() code_ran = True try: - try: - if options.module: - sys.path[0] = '' - self.run_python_module(args[0], args) - else: - filename = args[0] - sys.path[0] = os.path.abspath(os.path.dirname(filename)) - self.run_python_file(filename, args) - except NoSource: - code_ran = False - raise + if options.module: + sys.path[0] = '' + self.run_python_module(args[0], args) + else: + filename = args[0] + sys.path[0] = os.path.abspath(os.path.dirname(filename)) + self.run_python_file(filename, args) + except NoSource: + code_ran = False + raise finally: self.coverage.stop() if code_ran: diff --git a/coverage/control.py b/coverage/control.py index 31fc511e..466f76dd 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -686,12 +686,11 @@ class coverage(object): outfile = open(self.config.xml_output, "w") file_to_close = outfile try: - try: - reporter = XmlReporter(self, self.config) - return reporter.report(morfs, outfile=outfile) - except CoverageException: - delete_file = True - raise + reporter = XmlReporter(self, self.config) + return reporter.report(morfs, outfile=outfile) + except CoverageException: + delete_file = True + raise finally: if file_to_close: file_to_close.close() diff --git a/coverage/execfile.py b/coverage/execfile.py index 71ec9318..aec65343 100644 --- a/coverage/execfile.py +++ b/coverage/execfile.py @@ -31,35 +31,34 @@ def run_python_module(modulename, args): openfile = None glo, loc = globals(), locals() try: - try: - # Search for the module - inside its parent package, if any - using - # standard import mechanics. - if '.' in modulename: - packagename, name = rsplit1(modulename, '.') - package = __import__(packagename, glo, loc, ['__path__']) - searchpath = package.__path__ - else: - packagename, name = None, modulename - searchpath = None # "top-level search" in imp.find_module() + # Search for the module - inside its parent package, if any - using + # standard import mechanics. + if '.' in modulename: + packagename, name = rsplit1(modulename, '.') + package = __import__(packagename, glo, loc, ['__path__']) + searchpath = package.__path__ + else: + packagename, name = None, modulename + searchpath = None # "top-level search" in imp.find_module() + openfile, pathname, _ = imp.find_module(name, searchpath) + + # Complain if this is a magic non-file module. + if openfile is None and pathname is None: + raise NoSource( + "module does not live in a file: %r" % modulename + ) + + # If `modulename` is actually a package, not a mere module, then we + # pretend to be Python 2.7 and try running its __main__.py script. + if openfile is None: + packagename = modulename + name = '__main__' + package = __import__(packagename, glo, loc, ['__path__']) + searchpath = package.__path__ openfile, pathname, _ = imp.find_module(name, searchpath) - - # Complain if this is a magic non-file module. - if openfile is None and pathname is None: - raise NoSource( - "module does not live in a file: %r" % modulename - ) - - # If `modulename` is actually a package, not a mere module, then we - # pretend to be Python 2.7 and try running its __main__.py script. - if openfile is None: - packagename = modulename - name = '__main__' - package = __import__(packagename, glo, loc, ['__path__']) - searchpath = package.__path__ - openfile, pathname, _ = imp.find_module(name, searchpath) - except ImportError: - _, err, _ = sys.exc_info() - raise NoSource(str(err)) + except ImportError: + _, err, _ = sys.exc_info() + raise NoSource(str(err)) finally: if openfile: openfile.close() -- cgit v1.2.1 From 50959ccaaa07ccfb5a01cb38eb5d2b548e0dfe9a Mon Sep 17 00:00:00 2001 From: Ned Batchelder <ned@nedbatchelder.com> Date: Sun, 20 Oct 2013 08:11:50 -0400 Subject: Not going to use print functions, but at least make them all look the same. --HG-- branch : 4.0 --- tests/test_process.py | 8 ++++---- tests/test_summary.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_process.py b/tests/test_process.py index 1ab56e8f..ddbbafd6 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -35,7 +35,7 @@ class ProcessTest(CoverageTest): import covmod1 import covmodzip1 a = 1 - print ('done') + print('done') """) self.assert_doesnt_exist(".coverage") @@ -52,7 +52,7 @@ class ProcessTest(CoverageTest): else: c = 1 d = 1 - print ('done') + print('done') """) out = self.run_command("coverage -x -p b_or_c.py b") @@ -88,7 +88,7 @@ class ProcessTest(CoverageTest): else: c = 1 d = 1 - print ('done') + print('done') """) out = self.run_command("coverage -x -p b_or_c.py b") @@ -128,7 +128,7 @@ class ProcessTest(CoverageTest): else: c = 1 d = 1 - print ('done') + print('done') """) self.make_file(".coveragerc", """\ diff --git a/tests/test_summary.py b/tests/test_summary.py index 8035513e..29167bf8 100644 --- a/tests/test_summary.py +++ b/tests/test_summary.py @@ -16,7 +16,7 @@ class SummaryTest(CoverageTest): import covmod1 import covmodzip1 a = 1 - print ('done') + print('done') """) # Parent class saves and restores sys.path, we can just modify it. sys.path.append(self.nice_file(os.path.dirname(__file__), 'modules')) -- cgit v1.2.1 From 6dfbb755d1f6994ccec9ae56ad7f2eedad2ed0d6 Mon Sep 17 00:00:00 2001 From: Ned Batchelder <ned@nedbatchelder.com> Date: Sun, 20 Oct 2013 08:23:52 -0400 Subject: Except clause can now use 'as', no need for lots of sys.exc_info --HG-- branch : 4.0 --- coverage/cmdline.py | 9 +++------ coverage/control.py | 3 +-- coverage/execfile.py | 3 +-- coverage/misc.py | 4 +--- coverage/parser.py | 11 ++++------- lab/parser.py | 3 +-- setup.py | 7 +++---- tests/backunittest.py | 5 ++--- 8 files changed, 16 insertions(+), 29 deletions(-) diff --git a/coverage/cmdline.py b/coverage/cmdline.py index 9ff29f3a..93732839 100644 --- a/coverage/cmdline.py +++ b/coverage/cmdline.py @@ -716,21 +716,18 @@ def main(argv=None): argv = sys.argv[1:] try: status = CoverageScript().command_line(argv) - except ExceptionDuringRun: + except ExceptionDuringRun as err: # An exception was caught while running the product code. The # sys.exc_info() return tuple is packed into an ExceptionDuringRun # exception. - _, err, _ = sys.exc_info() traceback.print_exception(*err.args) status = ERR - except CoverageException: + except CoverageException as err: # A controlled error inside coverage.py: print the message to the user. - _, err, _ = sys.exc_info() print(err) status = ERR - except SystemExit: + except SystemExit as err: # The user called `sys.exit()`. Exit with their argument, if any. - _, err, _ = sys.exc_info() if err.args: status = err.args[0] else: diff --git a/coverage/control.py b/coverage/control.py index 466f76dd..51ff0439 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -98,8 +98,7 @@ class coverage(object): config_file = ".coveragerc" try: self.config.from_file(config_file) - except ValueError: - _, err, _ = sys.exc_info() + except ValueError as err: raise CoverageException( "Couldn't read config file %s: %s" % (config_file, err) ) diff --git a/coverage/execfile.py b/coverage/execfile.py index aec65343..f90096e9 100644 --- a/coverage/execfile.py +++ b/coverage/execfile.py @@ -56,8 +56,7 @@ def run_python_module(modulename, args): package = __import__(packagename, glo, loc, ['__path__']) searchpath = package.__path__ openfile, pathname, _ = imp.find_module(name, searchpath) - except ImportError: - _, err, _ = sys.exc_info() + except ImportError as err: raise NoSource(str(err)) finally: if openfile: diff --git a/coverage/misc.py b/coverage/misc.py index 2a36d5c1..c3fd9e2a 100644 --- a/coverage/misc.py +++ b/coverage/misc.py @@ -3,7 +3,6 @@ import errno import inspect import os -import sys from coverage.backward import md5 from coverage.backward import string_class, to_bytes @@ -97,8 +96,7 @@ def file_be_gone(path): """Remove a file, and don't get annoyed if it doesn't exist.""" try: os.remove(path) - except OSError: - _, e, _ = sys.exc_info() + except OSError as e: if e.errno != errno.ENOENT: raise diff --git a/coverage/parser.py b/coverage/parser.py index d0fe9976..7e194705 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -1,6 +1,6 @@ """Code parsing for Coverage.""" -import collections, dis, re, sys, token, tokenize +import collections, dis, re, token, tokenize from coverage.backward import StringIO from coverage.backward import open_source, range # pylint: disable=W0622 @@ -27,8 +27,7 @@ class CodeParser(object): try: with open_source(self.filename) as sourcef: self.text = sourcef.read() - except IOError: - _, err, _ = sys.exc_info() + except IOError as err: raise NoSource( "No source for code: '%s': %s" % (self.filename, err) ) @@ -202,8 +201,7 @@ class CodeParser(object): """ try: self._raw_parse() - except (tokenize.TokenError, IndentationError): - _, tokerr, _ = sys.exc_info() + except (tokenize.TokenError, IndentationError) as tokerr: msg, lineno = tokerr.args raise NotPython( "Couldn't parse '%s' as Python source: '%s' at %s" % @@ -333,8 +331,7 @@ class ByteParser(object): # Python 2.3 and 2.4 don't like partial last lines, so be sure # the text ends nicely for them. self.code = compile(text + '\n', filename, "exec") - except SyntaxError: - _, synerr, _ = sys.exc_info() + except SyntaxError as synerr: raise NotPython( "Couldn't parse '%s' as Python source: '%s' at line %d" % (filename, synerr.msg, synerr.lineno) diff --git a/lab/parser.py b/lab/parser.py index ce6902a6..7eaa9448 100644 --- a/lab/parser.py +++ b/lab/parser.py @@ -57,8 +57,7 @@ class ParserMain(object): if options.dis or options.chunks: try: bp = ByteParser(filename=filename) - except CoverageException: - _, err, _ = sys.exc_info() + except CoverageException as err: print("%s" % (err,)) return diff --git a/setup.py b/setup.py index 215102bd..e8780f3a 100644 --- a/setup.py +++ b/setup.py @@ -144,9 +144,9 @@ class ve_build_ext(build_ext): build_ext.build_extension(self, ext) except ext_errors: raise BuildFailed() - except ValueError: + except ValueError as err: # this can happen on Windows 64 bit, see Python issue 7511 - if "'path'" in str(sys.exc_info()[1]): # works with both py 2/3 + if "'path'" in str(err): # works with both py 2/3 raise BuildFailed() raise @@ -186,9 +186,8 @@ def main(): # extension. Try it with, and if it fails, try it without. try: setup(**setup_args) - except BuildFailed: + except BuildFailed as exc: msg = "Couldn't install with extension module, trying without it..." - exc = sys.exc_info()[1] exc_msg = "%s: %s" % (exc.__class__.__name__, exc.cause) print("**\n** %s\n** %s\n**" % (msg, exc_msg)) diff --git a/tests/backunittest.py b/tests/backunittest.py index 019e811c..16414014 100644 --- a/tests/backunittest.py +++ b/tests/backunittest.py @@ -1,6 +1,6 @@ """Implementations of unittest features from the future.""" -import difflib, re, sys, unittest +import difflib, re, unittest def _need(method): @@ -55,8 +55,7 @@ class TestCase(unittest.TestCase): """ try: callobj(*args, **kw) - except excClass: - _, exc, _ = sys.exc_info() + except excClass as exc: excMsg = str(exc) if re.search(regexp, excMsg): # Message provided, and we got the right one: it passes. -- cgit v1.2.1 From 53ba0940b632b6f65efdcb046f0c496caddfbcd7 Mon Sep 17 00:00:00 2001 From: Ned Batchelder <ned@nedbatchelder.com> Date: Sun, 20 Oct 2013 08:47:35 -0400 Subject: No need for these test method replacements. --HG-- branch : 4.0 --- tests/backunittest.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/backunittest.py b/tests/backunittest.py index 16414014..0964ab1d 100644 --- a/tests/backunittest.py +++ b/tests/backunittest.py @@ -15,18 +15,6 @@ class TestCase(unittest.TestCase): the builtin `unittest` doesn't have them. """ - if _need('assertTrue'): - def assertTrue(self, exp, msg=None): - """Assert that `exp` is true.""" - if not exp: - self.fail(msg) - - if _need('assertFalse'): - def assertFalse(self, exp, msg=None): - """Assert that `exp` is false.""" - if exp: - self.fail(msg) - if _need('assertIn'): def assertIn(self, member, container, msg=None): """Assert that `member` is in `container`.""" -- cgit v1.2.1 From b2d5b1a2e3bfa3b907034cf07ed4a173081ce976 Mon Sep 17 00:00:00 2001 From: Ned Batchelder <ned@nedbatchelder.com> Date: Tue, 22 Oct 2013 21:25:28 -0400 Subject: Fix the parser tool so I can see just annotated source files. --HG-- branch : 4.0 --- lab/parser.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lab/parser.py b/lab/parser.py index 7eaa9448..4e19d411 100644 --- a/lab/parser.py +++ b/lab/parser.py @@ -54,12 +54,11 @@ class ParserMain(object): def one_file(self, options, filename): """Process just one file.""" - if options.dis or options.chunks: - try: - bp = ByteParser(filename=filename) - except CoverageException as err: - print("%s" % (err,)) - return + try: + bp = ByteParser(filename=filename) + except CoverageException as err: + print("%s" % (err,)) + return if options.dis: print("Main code:") -- cgit v1.2.1 From 7c66441eab3af17539c478a2cb4e19cd93ba0cf4 Mon Sep 17 00:00:00 2001 From: Ned Batchelder <ned@nedbatchelder.com> Date: Wed, 23 Oct 2013 22:35:51 -0400 Subject: enumerate has a start parameter! --HG-- branch : 4.0 --- coverage/html.py | 3 +-- coverage/parser.py | 4 ++-- igor.py | 6 +++--- lab/parser.py | 3 +-- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/coverage/html.py b/coverage/html.py index d8779233..e1966bfb 100644 --- a/coverage/html.py +++ b/coverage/html.py @@ -186,8 +186,7 @@ class HtmlReporter(Reporter): lines = [] - for lineno, line in enumerate(source_token_lines(source)): - lineno += 1 # 1-based line numbers. + for lineno, line in enumerate(source_token_lines(source), start=1): # Figure out how to mark this line. line_class = [] annotate_html = "" diff --git a/coverage/parser.py b/coverage/parser.py index 7e194705..f2885c07 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -79,9 +79,9 @@ class CodeParser(object): """ regex_c = re.compile(join_regex(regexes)) matches = set() - for i, ltext in enumerate(self.lines): + for i, ltext in enumerate(self.lines, start=1): if regex_c.search(ltext): - matches.add(i+1) + matches.add(i) return matches def _raw_parse(self): diff --git a/igor.py b/igor.py index 6c5d56bf..f7879d7c 100644 --- a/igor.py +++ b/igor.py @@ -158,17 +158,17 @@ def do_check_eol(): checked.add(fname) line = None - for n, line in enumerate(open(fname, "rb")): + for n, line in enumerate(open(fname, "rb"), start=1): if crlf: if "\r" in line: - print("%s@%d: CR found" % (fname, n+1)) + print("%s@%d: CR found" % (fname, n)) return if trail_white: line = line[:-1] if not crlf: line = line.rstrip('\r') if line.rstrip() != line: - print("%s@%d: trailing whitespace found" % (fname, n+1)) + print("%s@%d: trailing whitespace found" % (fname, n)) return if line is not None and not line.strip(): diff --git a/lab/parser.py b/lab/parser.py index 4e19d411..a8e03eec 100644 --- a/lab/parser.py +++ b/lab/parser.py @@ -86,8 +86,7 @@ class ParserMain(object): exit_counts = cp.exit_counts() - for i, ltext in enumerate(cp.lines): - lineno = i+1 + for lineno, ltext in enumerate(cp.lines, start=1): m0 = m1 = m2 = m3 = a = ' ' if lineno in cp.statement_starts: m0 = '-' -- cgit v1.2.1