|
| 1 | +import os |
1 | 2 | import warnings |
2 | 3 |
|
3 | 4 | import pytest |
@@ -641,3 +642,160 @@ def pytest_configure(): |
641 | 642 | assert "INTERNALERROR" not in result.stderr.str() |
642 | 643 | warning = recwarn.pop() |
643 | 644 | assert str(warning.message) == "from pytest_configure" |
| 645 | + |
| 646 | + |
| 647 | +class TestStackLevel: |
| 648 | + @pytest.fixture |
| 649 | + def capwarn(self, testdir): |
| 650 | + class CapturedWarnings: |
| 651 | + captured = [] |
| 652 | + |
| 653 | + @classmethod |
| 654 | + def pytest_warning_captured(cls, warning_message, when, item, location): |
| 655 | + cls.captured.append((warning_message, location)) |
| 656 | + |
| 657 | + testdir.plugins = [CapturedWarnings()] |
| 658 | + |
| 659 | + return CapturedWarnings |
| 660 | + |
| 661 | + def test_issue4445_rewrite(self, testdir, capwarn): |
| 662 | + """#4445: Make sure the warning points to a reasonable location |
| 663 | + See origin of _issue_warning_captured at: _pytest.assertion.rewrite.py:241 |
| 664 | + """ |
| 665 | + testdir.makepyfile(some_mod="") |
| 666 | + conftest = testdir.makeconftest( |
| 667 | + """ |
| 668 | + import some_mod |
| 669 | + import pytest |
| 670 | +
|
| 671 | + pytest.register_assert_rewrite("some_mod") |
| 672 | + """ |
| 673 | + ) |
| 674 | + testdir.parseconfig() |
| 675 | + |
| 676 | + # with stacklevel=5 the warning originates from register_assert_rewrite |
| 677 | + # function in the created conftest.py |
| 678 | + assert len(capwarn.captured) == 1 |
| 679 | + warning, location = capwarn.captured.pop() |
| 680 | + file, lineno, func = location |
| 681 | + |
| 682 | + assert "Module already imported" in str(warning.message) |
| 683 | + assert file == str(conftest) |
| 684 | + assert func == "<module>" # the above conftest.py |
| 685 | + assert lineno == 4 |
| 686 | + |
| 687 | + def test_issue4445_preparse(self, testdir, capwarn): |
| 688 | + """#4445: Make sure the warning points to a reasonable location |
| 689 | + See origin of _issue_warning_captured at: _pytest.config.__init__.py:910 |
| 690 | + """ |
| 691 | + testdir.makeconftest( |
| 692 | + """ |
| 693 | + import nothing |
| 694 | + """ |
| 695 | + ) |
| 696 | + testdir.parseconfig("--help") |
| 697 | + |
| 698 | + # with stacklevel=2 the warning should originate from config._preparse and is |
| 699 | + # thrown by an errorneous conftest.py |
| 700 | + assert len(capwarn.captured) == 1 |
| 701 | + warning, location = capwarn.captured.pop() |
| 702 | + file, _, func = location |
| 703 | + |
| 704 | + assert "could not load initial conftests" in str(warning.message) |
| 705 | + assert "config{sep}__init__.py".format(sep=os.sep) in file |
| 706 | + assert func == "_preparse" |
| 707 | + |
| 708 | + def test_issue4445_import_plugin(self, testdir, capwarn): |
| 709 | + """#4445: Make sure the warning points to a reasonable location |
| 710 | + See origin of _issue_warning_captured at: _pytest.config.__init__.py:585 |
| 711 | + """ |
| 712 | + testdir.makepyfile( |
| 713 | + some_plugin=""" |
| 714 | + import pytest |
| 715 | + pytest.skip("thing", allow_module_level=True) |
| 716 | + """ |
| 717 | + ) |
| 718 | + testdir.syspathinsert() |
| 719 | + testdir.parseconfig("-p", "some_plugin") |
| 720 | + |
| 721 | + # with stacklevel=2 the warning should originate from |
| 722 | + # config.PytestPluginManager.import_plugin is thrown by a skipped plugin |
| 723 | + |
| 724 | + # During config parsing the the pluginargs are checked in a while loop |
| 725 | + # that as a result of the argument count runs import_plugin twice, hence |
| 726 | + # two identical warnings are captured (is this intentional?). |
| 727 | + assert len(capwarn.captured) == 2 |
| 728 | + warning, location = capwarn.captured.pop() |
| 729 | + file, _, func = location |
| 730 | + |
| 731 | + assert "skipped plugin 'some_plugin': thing" in str(warning.message) |
| 732 | + assert "config{sep}__init__.py".format(sep=os.sep) in file |
| 733 | + assert func == "import_plugin" |
| 734 | + |
| 735 | + def test_issue4445_resultlog(self, testdir, capwarn): |
| 736 | + """#4445: Make sure the warning points to a reasonable location |
| 737 | + See origin of _issue_warning_captured at: _pytest.resultlog.py:35 |
| 738 | + """ |
| 739 | + testdir.makepyfile( |
| 740 | + """ |
| 741 | + def test_dummy(): |
| 742 | + pass |
| 743 | + """ |
| 744 | + ) |
| 745 | + # Use parseconfigure() because the warning in resultlog.py is triggered in |
| 746 | + # the pytest_configure hook |
| 747 | + testdir.parseconfigure( |
| 748 | + "--result-log={dir}".format(dir=testdir.tmpdir.join("result.log")) |
| 749 | + ) |
| 750 | + |
| 751 | + # with stacklevel=2 the warning originates from resultlog.pytest_configure |
| 752 | + # and is thrown when --result-log is used |
| 753 | + warning, location = capwarn.captured.pop() |
| 754 | + file, _, func = location |
| 755 | + |
| 756 | + assert "--result-log is deprecated" in str(warning.message) |
| 757 | + assert "resultlog.py" in file |
| 758 | + assert func == "pytest_configure" |
| 759 | + |
| 760 | + def test_issue4445_cacheprovider_set(self, testdir, capwarn): |
| 761 | + """#4445: Make sure the warning points to a reasonable location |
| 762 | + See origin of _issue_warning_captured at: _pytest.cacheprovider.py:59 |
| 763 | + """ |
| 764 | + testdir.tmpdir.join(".pytest_cache").write("something wrong") |
| 765 | + testdir.runpytest(plugins=[capwarn()]) |
| 766 | + |
| 767 | + # with stacklevel=3 the warning originates from one stacklevel above |
| 768 | + # _issue_warning_captured in cacheprovider.Cache.set and is thrown |
| 769 | + # when there are errors during cache folder creation |
| 770 | + |
| 771 | + # set is called twice (in module stepwise and in cacheprovider) so emits |
| 772 | + # two warnings when there are errors during cache folder creation. (is this intentional?) |
| 773 | + assert len(capwarn.captured) == 2 |
| 774 | + warning, location = capwarn.captured.pop() |
| 775 | + file, lineno, func = location |
| 776 | + |
| 777 | + assert "could not create cache path" in str(warning.message) |
| 778 | + assert "cacheprovider.py" in file |
| 779 | + assert func == "set" |
| 780 | + |
| 781 | + def test_issue4445_issue5928_mark_generator(self, testdir): |
| 782 | + """#4445 and #5928: Make sure the warning from an unknown mark points to |
| 783 | + the test file where this mark is used. |
| 784 | + """ |
| 785 | + testfile = testdir.makepyfile( |
| 786 | + """ |
| 787 | + import pytest |
| 788 | +
|
| 789 | + @pytest.mark.unknown |
| 790 | + def test_it(): |
| 791 | + pass |
| 792 | + """ |
| 793 | + ) |
| 794 | + result = testdir.runpytest_subprocess() |
| 795 | + # with stacklevel=2 the warning should originate from the above created test file |
| 796 | + result.stdout.fnmatch_lines_random( |
| 797 | + [ |
| 798 | + "*{testfile}:3*".format(testfile=str(testfile)), |
| 799 | + "*Unknown pytest.mark.unknown*", |
| 800 | + ] |
| 801 | + ) |
0 commit comments