Merge pull request #158, fixes issue 504
This commit is contained in:
		
						commit
						c47835f5ec
					
				
							
								
								
									
										1
									
								
								AUTHORS
								
								
								
								
							
							
						
						
									
										1
									
								
								AUTHORS
								
								
								
								
							|  | @ -41,3 +41,4 @@ Jurko Gospodnetić | ||||||
| Marc Schlaich | Marc Schlaich | ||||||
| Christopher Gilling | Christopher Gilling | ||||||
| Daniel Grana | Daniel Grana | ||||||
|  | Andy Freeland | ||||||
|  |  | ||||||
|  | @ -1,6 +1,10 @@ | ||||||
| NEXT (2.6) | NEXT (2.6) | ||||||
| ----------------------------------- | ----------------------------------- | ||||||
| 
 | 
 | ||||||
|  | - change -v output to include full node IDs of tests.  Users can copy | ||||||
|  |   a node ID from a test run, including line number, and use it as a | ||||||
|  |   positional argument in order to run only a single test. | ||||||
|  | 
 | ||||||
| - fix issue 475: fail early and comprehensible if calling | - fix issue 475: fail early and comprehensible if calling | ||||||
|   pytest.raises with wrong exception type. |   pytest.raises with wrong exception type. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| import py | import py | ||||||
| # DON't import pytest here because it causes import cycle troubles | # DON't import pytest here because it causes import cycle troubles | ||||||
|  | import re | ||||||
| import sys, os | import sys, os | ||||||
| from _pytest import hookspec # the extension point definitions | from _pytest import hookspec # the extension point definitions | ||||||
| from _pytest.core import PluginManager | from _pytest.core import PluginManager | ||||||
|  | @ -180,7 +181,7 @@ class Parser: | ||||||
|                     a = option.attrs() |                     a = option.attrs() | ||||||
|                     arggroup.add_argument(*n, **a) |                     arggroup.add_argument(*n, **a) | ||||||
|         # bash like autocompletion for dirs (appending '/') |         # bash like autocompletion for dirs (appending '/') | ||||||
|         optparser.add_argument(FILE_OR_DIR, nargs='*' |         optparser.add_argument(FILE_OR_DIR, nargs='*', type=node_with_line_number, | ||||||
|                                ).completer=filescompleter |                                ).completer=filescompleter | ||||||
|         return optparser |         return optparser | ||||||
| 
 | 
 | ||||||
|  | @ -699,7 +700,7 @@ class Config(object): | ||||||
|         except ConftestImportFailure: |         except ConftestImportFailure: | ||||||
|             e = sys.exc_info()[1] |             e = sys.exc_info()[1] | ||||||
|             if ns.help or ns.version: |             if ns.help or ns.version: | ||||||
|                 # we don't want to prevent --help/--version to work  |                 # we don't want to prevent --help/--version to work | ||||||
|                 # so just let is pass and print a warning at the end |                 # so just let is pass and print a warning at the end | ||||||
|                 self.pluginmanager._warnings.append( |                 self.pluginmanager._warnings.append( | ||||||
|                         "could not load initial conftests (%s)\n" % e.path) |                         "could not load initial conftests (%s)\n" % e.path) | ||||||
|  | @ -839,6 +840,12 @@ def getcfg(args, inibasenames): | ||||||
|     return {} |     return {} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def node_with_line_number(string): | ||||||
|  |     split = string.split('[') | ||||||
|  |     split[0] = re.sub(r'@\d+', '', split[0]) | ||||||
|  |     return '['.join(split) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| def setns(obj, dic): | def setns(obj, dic): | ||||||
|     import pytest |     import pytest | ||||||
|     for name, value in dic.items(): |     for name, value in dic.items(): | ||||||
|  |  | ||||||
|  | @ -382,9 +382,11 @@ class TerminalReporter: | ||||||
|             line = str(fspath) |             line = str(fspath) | ||||||
|             if lineno is not None: |             if lineno is not None: | ||||||
|                 lineno += 1 |                 lineno += 1 | ||||||
|                 line += ":" + str(lineno) |                 line += "@" + str(lineno) | ||||||
|             if domain: |             if domain: | ||||||
|                 line += ": " + str(domain) |                 split = str(domain).split('[') | ||||||
|  |                 split[0] = split[0].replace('.', '::')  # don't replace '.' in params | ||||||
|  |                 line += "::" + '['.join(split) | ||||||
|         else: |         else: | ||||||
|             line = "[location]" |             line = "[location]" | ||||||
|         return line + " " |         return line + " " | ||||||
|  |  | ||||||
|  | @ -1620,22 +1620,22 @@ class TestFixtureMarker: | ||||||
|         """) |         """) | ||||||
|         result = testdir.runpytest("-v") |         result = testdir.runpytest("-v") | ||||||
|         result.stdout.fnmatch_lines(""" |         result.stdout.fnmatch_lines(""" | ||||||
|             test_mod1.py:1: test_func[s1] PASSED |             test_mod1.py@1::test_func[s1] PASSED | ||||||
|             test_mod2.py:1: test_func2[s1] PASSED |             test_mod2.py@1::test_func2[s1] PASSED | ||||||
|             test_mod2.py:3: test_func3[s1-m1] PASSED |             test_mod2.py@3::test_func3[s1-m1] PASSED | ||||||
|             test_mod2.py:5: test_func3b[s1-m1] PASSED |             test_mod2.py@5::test_func3b[s1-m1] PASSED | ||||||
|             test_mod2.py:3: test_func3[s1-m2] PASSED |             test_mod2.py@3::test_func3[s1-m2] PASSED | ||||||
|             test_mod2.py:5: test_func3b[s1-m2] PASSED |             test_mod2.py@5::test_func3b[s1-m2] PASSED | ||||||
|             test_mod1.py:1: test_func[s2] PASSED |             test_mod1.py@1::test_func[s2] PASSED | ||||||
|             test_mod2.py:1: test_func2[s2] PASSED |             test_mod2.py@1::test_func2[s2] PASSED | ||||||
|             test_mod2.py:3: test_func3[s2-m1] PASSED |             test_mod2.py@3::test_func3[s2-m1] PASSED | ||||||
|             test_mod2.py:5: test_func3b[s2-m1] PASSED |             test_mod2.py@5::test_func3b[s2-m1] PASSED | ||||||
|             test_mod2.py:7: test_func4[m1] PASSED |             test_mod2.py@7::test_func4[m1] PASSED | ||||||
|             test_mod2.py:3: test_func3[s2-m2] PASSED |             test_mod2.py@3::test_func3[s2-m2] PASSED | ||||||
|             test_mod2.py:5: test_func3b[s2-m2] PASSED |             test_mod2.py@5::test_func3b[s2-m2] PASSED | ||||||
|             test_mod2.py:7: test_func4[m2] PASSED |             test_mod2.py@7::test_func4[m2] PASSED | ||||||
|             test_mod1.py:3: test_func1[m1] PASSED |             test_mod1.py@3::test_func1[m1] PASSED | ||||||
|             test_mod1.py:3: test_func1[m2] PASSED |             test_mod1.py@3::test_func1[m2] PASSED | ||||||
|         """) |         """) | ||||||
| 
 | 
 | ||||||
|     def test_class_ordering(self, testdir): |     def test_class_ordering(self, testdir): | ||||||
|  | @ -1672,18 +1672,18 @@ class TestFixtureMarker: | ||||||
|         """) |         """) | ||||||
|         result = testdir.runpytest("-vs") |         result = testdir.runpytest("-vs") | ||||||
|         result.stdout.fnmatch_lines(""" |         result.stdout.fnmatch_lines(""" | ||||||
|             test_class_ordering.py:4: TestClass2.test_1[1-a] PASSED |             test_class_ordering.py@4::TestClass2::test_1[1-a] PASSED | ||||||
|             test_class_ordering.py:4: TestClass2.test_1[2-a] PASSED |             test_class_ordering.py@4::TestClass2::test_1[2-a] PASSED | ||||||
|             test_class_ordering.py:6: TestClass2.test_2[1-a] PASSED |             test_class_ordering.py@6::TestClass2::test_2[1-a] PASSED | ||||||
|             test_class_ordering.py:6: TestClass2.test_2[2-a] PASSED |             test_class_ordering.py@6::TestClass2::test_2[2-a] PASSED | ||||||
|             test_class_ordering.py:4: TestClass2.test_1[1-b] PASSED |             test_class_ordering.py@4::TestClass2::test_1[1-b] PASSED | ||||||
|             test_class_ordering.py:4: TestClass2.test_1[2-b] PASSED |             test_class_ordering.py@4::TestClass2::test_1[2-b] PASSED | ||||||
|             test_class_ordering.py:6: TestClass2.test_2[1-b] PASSED |             test_class_ordering.py@6::TestClass2::test_2[1-b] PASSED | ||||||
|             test_class_ordering.py:6: TestClass2.test_2[2-b] PASSED |             test_class_ordering.py@6::TestClass2::test_2[2-b] PASSED | ||||||
|             test_class_ordering.py:9: TestClass.test_3[1-a] PASSED |             test_class_ordering.py@9::TestClass::test_3[1-a] PASSED | ||||||
|             test_class_ordering.py:9: TestClass.test_3[2-a] PASSED |             test_class_ordering.py@9::TestClass::test_3[2-a] PASSED | ||||||
|             test_class_ordering.py:9: TestClass.test_3[1-b] PASSED |             test_class_ordering.py@9::TestClass::test_3[1-b] PASSED | ||||||
|             test_class_ordering.py:9: TestClass.test_3[2-b] PASSED |             test_class_ordering.py@9::TestClass::test_3[2-b] PASSED | ||||||
|         """) |         """) | ||||||
| 
 | 
 | ||||||
|     def test_parametrize_separated_order_higher_scope_first(self, testdir): |     def test_parametrize_separated_order_higher_scope_first(self, testdir): | ||||||
|  | @ -2094,7 +2094,7 @@ class TestErrors: | ||||||
|             def fix1(request): |             def fix1(request): | ||||||
|                 def f(): |                 def f(): | ||||||
|                     raise KeyError |                     raise KeyError | ||||||
|                 request.addfinalizer(f)  |                 request.addfinalizer(f) | ||||||
|                 return object() |                 return object() | ||||||
| 
 | 
 | ||||||
|             l = [] |             l = [] | ||||||
|  | @ -2113,7 +2113,7 @@ class TestErrors: | ||||||
|             *KeyError* |             *KeyError* | ||||||
|             *3 pass*2 error* |             *3 pass*2 error* | ||||||
|         """) |         """) | ||||||
|          | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def test_setupfunc_missing_funcarg(self, testdir): |     def test_setupfunc_missing_funcarg(self, testdir): | ||||||
|  |  | ||||||
|  | @ -145,6 +145,10 @@ class TestParser: | ||||||
|         assert args.R == True |         assert args.R == True | ||||||
|         assert args.S == False |         assert args.S == False | ||||||
| 
 | 
 | ||||||
|  |     def test_parse_removes_line_number_from_positional_arguments(self, parser): | ||||||
|  |         args = parser.parse(['path@2::func', 'path2@5::func2[param with @]']) | ||||||
|  |         assert getattr(args, parseopt.FILE_OR_DIR) == ['path::func', 'path2::func2[param with @]'] | ||||||
|  | 
 | ||||||
|     def test_parse_defaultgetter(self): |     def test_parse_defaultgetter(self): | ||||||
|         def defaultget(option): |         def defaultget(option): | ||||||
|             if not hasattr(option, 'type'): |             if not hasattr(option, 'type'): | ||||||
|  |  | ||||||
|  | @ -51,9 +51,9 @@ class TestTerminal: | ||||||
|         result = testdir.runpytest(*option.args) |         result = testdir.runpytest(*option.args) | ||||||
|         if option.verbose: |         if option.verbose: | ||||||
|             result.stdout.fnmatch_lines([ |             result.stdout.fnmatch_lines([ | ||||||
|                 "*test_pass_skip_fail.py:2: *test_ok*PASS*", |                 "*test_pass_skip_fail.py@2::test_ok PASS*", | ||||||
|                 "*test_pass_skip_fail.py:4: *test_skip*SKIP*", |                 "*test_pass_skip_fail.py@4::test_skip SKIP*", | ||||||
|                 "*test_pass_skip_fail.py:6: *test_func*FAIL*", |                 "*test_pass_skip_fail.py@6::test_func FAIL*", | ||||||
|             ]) |             ]) | ||||||
|         else: |         else: | ||||||
|             result.stdout.fnmatch_lines([ |             result.stdout.fnmatch_lines([ | ||||||
|  | @ -126,7 +126,7 @@ class TestTerminal: | ||||||
|         ]) |         ]) | ||||||
|         result = testdir.runpytest("-v", p2) |         result = testdir.runpytest("-v", p2) | ||||||
|         result.stdout.fnmatch_lines([ |         result.stdout.fnmatch_lines([ | ||||||
|             "*test_p2.py <- *test_p1.py:2: TestMore.test_p1*", |             "*test_p2.py <- *test_p1.py@2::TestMore::test_p1*", | ||||||
|         ]) |         ]) | ||||||
| 
 | 
 | ||||||
|     def test_itemreport_directclasses_not_shown_as_subclasses(self, testdir): |     def test_itemreport_directclasses_not_shown_as_subclasses(self, testdir): | ||||||
|  | @ -450,17 +450,17 @@ class TestTerminalFunctional: | ||||||
|         """) |         """) | ||||||
|         result = testdir.runpytest(p1, '-v') |         result = testdir.runpytest(p1, '-v') | ||||||
|         result.stdout.fnmatch_lines([ |         result.stdout.fnmatch_lines([ | ||||||
|             "*test_verbose_reporting.py:2: test_fail*FAIL*", |             "*test_verbose_reporting.py@2::test_fail *FAIL*", | ||||||
|             "*test_verbose_reporting.py:4: test_pass*PASS*", |             "*test_verbose_reporting.py@4::test_pass *PASS*", | ||||||
|             "*test_verbose_reporting.py:7: TestClass.test_skip*SKIP*", |             "*test_verbose_reporting.py@7::TestClass::test_skip *SKIP*", | ||||||
|             "*test_verbose_reporting.py:10: test_gen*FAIL*", |             "*test_verbose_reporting.py@10::test_gen*0* *FAIL*", | ||||||
|         ]) |         ]) | ||||||
|         assert result.ret == 1 |         assert result.ret == 1 | ||||||
| 
 | 
 | ||||||
|         pytestconfig.pluginmanager.skipifmissing("xdist") |         pytestconfig.pluginmanager.skipifmissing("xdist") | ||||||
|         result = testdir.runpytest(p1, '-v', '-n 1') |         result = testdir.runpytest(p1, '-v', '-n 1') | ||||||
|         result.stdout.fnmatch_lines([ |         result.stdout.fnmatch_lines([ | ||||||
|             "*FAIL*test_verbose_reporting.py:2: test_fail*", |             "*FAIL*test_verbose_reporting.py@2::test_fail*", | ||||||
|         ]) |         ]) | ||||||
|         assert result.ret == 1 |         assert result.ret == 1 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -29,8 +29,8 @@ def test_runTest_method(testdir): | ||||||
|         """) |         """) | ||||||
|     result = testdir.runpytest("-v") |     result = testdir.runpytest("-v") | ||||||
|     result.stdout.fnmatch_lines(""" |     result.stdout.fnmatch_lines(""" | ||||||
|         *MyTestCaseWithRunTest.runTest* |         *MyTestCaseWithRunTest::runTest* | ||||||
|         *MyTestCaseWithoutRunTest.test_something* |         *MyTestCaseWithoutRunTest::test_something* | ||||||
|         *2 passed* |         *2 passed* | ||||||
|     """) |     """) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue