Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-108927: Fix removing testing modules from sys.modules #108952

Merged

Conversation

serhiy-storchaka
Copy link
Member

@serhiy-storchaka serhiy-storchaka commented Sep 5, 2023

The code that does this properly never worked since Python 3.0.

And removing only the tested module breaks import machinery if it has submodules used in other tests.

It breaks import machinery if the test module has submodules used in
other tests.
@Yhg1s
Copy link
Member

Yhg1s commented Sep 5, 2023

Presumably the reload (the reason for the unload) was intentional. Do we know why that was added? Do those reasons still apply?

@@ -434,10 +434,6 @@ def regrtest_runner(result, test_func, ns) -> None:
def _load_run_test(result: TestResult, ns: Namespace) -> None:
# Load the test function, run the test function.
module_name = abs_module_name(result.test_name, ns.testdir)

# Remove the module from sys.module to reload it if it was already imported
sys.modules.pop(module_name, None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hum. I think that the problem is that only a single module is unload from sys.modules.

If we want to save/restore modules, IMO the whole sys.modules dictionary must be saved/restored. Not a single entry.

Would it make sense to save/restore the whole sys.modules dict? Would it fix #108927 ?

@serhiy-storchaka
Copy link
Member Author

Tests crash with this change, and it means that there is other huge issue hidden until now.

If we want to save/restore modules, IMO the whole sys.modules dictionary must be saved/restored. Not a single entry.

It is already done in run_test() in main.py, so I do not understand why it did not have effect and why removing the module was needed here.

@vstinner
Copy link
Member

vstinner commented Sep 6, 2023

Unloading the test module is done for 23 years (commit 5796d26) and so far, so I'm surprised that today it became a problem. Maybe it's not the right place to fix the issue.

commit 5796d26794eee634a4a06637d99d8d5c58da2bdb
Author: Guido van Rossum <guido@python.org>
Date:   Fri Apr 21 21:35:06 2000 +0000

    Patch by Vladimir Marangozov to unload additionally imported modules
    after each test has been run.  This avoids excessive memory growth
    during the tests.

diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py
index 6364d7179c..924890ab76 100755
--- a/Lib/test/regrtest.py
+++ b/Lib/test/regrtest.py
@@ -105,6 +105,7 @@ def main(tests=None, testdir=None):
     if single:
         tests = tests[:1]
     test_support.verbose = verbose      # Tell tests to be moderately quiet
+    save_modules = sys.modules.keys()
     for test in tests:
         if not quiet:
             print test
@@ -118,6 +119,10 @@ def main(tests=None, testdir=None):
                 print "test", test,
                 print "skipped -- an optional feature could not be imported"
             skipped.append(test)
+        # Unload the newly imported modules (best effort finalization)
+        for module in sys.modules.keys():
+            if module not in save_modules:
+                test_support.unload(module)
     if good and not quiet:
         if not bad and not skipped and len(good) > 1:
             print "All",

@vstinner
Copy link
Member

vstinner commented Sep 6, 2023

It is already done in run_test() in main.py, so I do not understand why it did not have effect and why removing the module was needed here.

I would prefer to dig deeper before changing this code.

@serhiy-storchaka
Copy link
Member Author

The crash is not related to this change. See #108976. If exclude test_pdb, all tests are passed successfully.

@serhiy-storchaka
Copy link
Member Author

Unloading the test module is done for 23 years (commit 5796d26) and so far, so I'm surprised that today it became a problem.

Ah, that code does not work since 3.0.

It saves sys.modules.keys() which is a view in Python 3, and reflects the current content of sys.modules, so the code never finds any "newly imported" modules.

@serhiy-storchaka serhiy-storchaka changed the title gh-108927: Do not remove tested modules from sys.modules gh-108927: Fix removing testing modules from sys.modules Sep 6, 2023
@@ -318,9 +318,9 @@ def run_tests_sequentially(self, runtests):
result = self.run_test(test_name, runtests, tracer)

# Unload the newly imported modules (best effort finalization)
for module in sys.modules.keys():
for module in list(sys.modules):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for module in list(sys.modules):
for module in sys.modules:

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it does not work, because the dict is modified during iteration.

…Wav.rst

Co-authored-by: Brett Cannon <brett@python.org>
@@ -318,9 +318,9 @@ def run_tests_sequentially(self, runtests):
result = self.run_test(test_name, runtests, tracer)

# Unload the newly imported modules (best effort finalization)
for module in sys.modules.keys():
for module in list(sys.modules):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this code. Why do we have to unload test modules?

If it's important to unload test modules, I would suggest to move this code inside single.py, to make a more consistent behavior for the different ways to run tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you ask why the code of libregrtest is so complicated? 🤷‍♂️

I think that it only makes sense in the single-process run. As well as removing the testing module before reloading in _load_run_test(). In the multi-process run it is only a waste of time. As well as significant part of save_env (except cleaning up external resources like filesystem).

@vstinner
Copy link
Member

vstinner commented Sep 13, 2023

It saves sys.modules.keys() which is a view in Python 3, and reflects the current content of sys.modules, so the code never finds any "newly imported" modules.

Oh... I see :-) So if the code is dead for 20+ years, maybe remove it? I don't know what's the best option here.

I would expect that running a test would restore Python (sys.modules) in the exact same state.

Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks for updated tests. I confirm that tests fail I revert Lib/test/libregrtest/ changes.

Lib/test/test_regrtest.py Outdated Show resolved Hide resolved
Co-authored-by: Victor Stinner <vstinner@python.org>
@serhiy-storchaka serhiy-storchaka added needs backport to 3.11 only security fixes needs backport to 3.12 bug and security fixes labels Dec 4, 2023
@serhiy-storchaka serhiy-storchaka enabled auto-merge (squash) December 4, 2023 15:11
@serhiy-storchaka serhiy-storchaka merged commit e08b70f into python:main Dec 4, 2023
36 checks passed
@miss-islington-app
Copy link

Thanks @serhiy-storchaka for the PR 🌮🎉.. I'm working now to backport this PR to: 3.11, 3.12.
🐍🍒⛏🤖

@bedevere-app
Copy link

bedevere-app bot commented Dec 4, 2023

GH-112711 is a backport of this pull request to the 3.12 branch.

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Dec 4, 2023
…nGH-108952)

It breaks import machinery if the test module has submodules used in
other tests.
(cherry picked from commit e08b70f)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
@bedevere-app bedevere-app bot removed the needs backport to 3.12 bug and security fixes label Dec 4, 2023
@bedevere-app
Copy link

bedevere-app bot commented Dec 4, 2023

GH-112712 is a backport of this pull request to the 3.11 branch.

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Dec 4, 2023
…nGH-108952)

It breaks import machinery if the test module has submodules used in
other tests.
(cherry picked from commit e08b70f)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
@bedevere-app bedevere-app bot removed the needs backport to 3.11 only security fixes label Dec 4, 2023
serhiy-storchaka added a commit that referenced this pull request Dec 4, 2023
…08952) (ПР-112712)

It breaks import machinery if the test module has submodules used in
other tests.
(cherry picked from commit e08b70f)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
serhiy-storchaka added a commit that referenced this pull request Dec 4, 2023
…08952) (ПР-112711)

It breaks import machinery if the test module has submodules used in
other tests.
(cherry picked from commit e08b70f)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
@Yhg1s
Copy link
Member

Yhg1s commented Dec 5, 2023

It looks like the new test fails when running the tests from an installed Python installation (see https://buildbot.python.org/all/#/builders/350/builds/4974 and https://buildbot.python.org/all/#/builders/1154/builds/418), could someone take a look?

@serhiy-storchaka serhiy-storchaka deleted the regretest-no-remove-test-module branch December 5, 2023 17:12
@serhiy-storchaka
Copy link
Member Author

Thank you @Yhg1s. Please look at #112765.

@hroncok
Copy link
Contributor

hroncok commented Dec 6, 2023

It looks like the new test fails when running the tests from an installed Python installation

FTR we are seeing the failures with the recently released 3.11.7.

@vstinner
Copy link
Member

vstinner commented Dec 6, 2023

@hroncok:

FTR we are seeing the failures with the recently released 3.11.7.

I suppose that #112784 already fixed the issue in the 3.11 branch. Sadly, this fix is not part of 3.11.7 release.

Buildbots were too slow to report the failure on the 3.11 branch before the release? It seems like we have "Installed" buildbot builders on the 3.11 branch.

@hroncok
Copy link
Contributor

hroncok commented Dec 6, 2023

Yes. What's done is done, but may I suggest a release not be made with commits before the buildbots have time to recognize a failure?

@vstinner
Copy link
Member

vstinner commented Dec 6, 2023

  • 3.11 commit 8dbda1c: Mon Dec 4 17:16:03 2023 +0100
  • Git tag v3.11.7: Mon Dec 4 17:56:31 2023 +0000

Ah right, there were less than 1 hour between the commit and the tag.

@hroncok:

Yes. What's done is done, but may I suggest a release not be made with commits before the buildbots have time to recognize a failure?

Usually, the branch is not locked around bugfix 3.x.y releases.

cc @pablogsal 3.11 release manager.

@pablogsal
Copy link
Member

The release script blocks if there are failing build bots so this was releaseable because all buildbots were green at the time (or the API reported green).

Is very difficult to time this correctly because even if we block a branch we do this hours before the release so we don't know when all builsbots have finished.

We can discuss blocking a day in advance to prevent this from happening or some other mechanism.

I will discuss this with other RMs to see what can be done.

@vstinner
Copy link
Member

vstinner commented Dec 6, 2023

In my experience, it's rare to discover bugs so soon just after a release. I'm not sure that it's worth it to deeply change the release process.

Maybe the release process should run tests on installed Python, rather than in the source code directory.

aisk pushed a commit to aisk/cpython that referenced this pull request Feb 11, 2024
…nGH-108952)

It breaks import machinery if the test module has submodules used in
other tests.
Glyphack pushed a commit to Glyphack/cpython that referenced this pull request Sep 2, 2024
…nGH-108952)

It breaks import machinery if the test module has submodules used in
other tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tests Tests in the Lib/test dir type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants