-
-
Notifications
You must be signed in to change notification settings - Fork 31.4k
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-90548: Make musl test skips smarter (fixes Alpine errors) #131313
Conversation
A relatively small number of tests fail when the underlying c library is provided by musl. This was originally reported in bpo-46390 by Christian Heimes. Among other changes, these tests were marked for skipping in pythongh-31947/ef1327e3 as part of bpo-40280 (emscripten support), but the skips were conditioned on the *platform* being emscripten (or wasi, skips for which ere added in 9b50585). In pythongh-131071 Victor Stinner added a linked_to_musl function to enable skipping a test in test_math that fails under musl, like it does on a number of other platforms. This check can successfully detect that python is running under musl on Alpine, which was the original problem report in bpo-46390. This PR replaces Victor's solution with an enhancement to platform.libc_ver that does the check more cheaply, and also gets the version number. The latter is important because the math test being skipped is due to a bug in musl that has been fixed, but as of this checkin date has not yet been released. When it is, the test skip can be fixed to check for the minimum needed version. The enhanced version of linked_to_musl is also used to do the skips of the other tests that generically fail under musl, as opposed to emscripten or wasi only failures. This will allow these tests to be skipped automatically on Alpine. This PR does *not* enhance libc_ver to support emscripten and wasi, as I'm not familiar with those platforms; instead it returns a version triple of (0, 0, 0) for those platforms. This means the musl tests will be skipped regardless of musl version, so ideally someone will add support to libc_ver for these platforms.
In adding tests for the new platform code I found a bug in the old code: if a valid version is passed for version and it is greater than the version found for an so *and* there is no glibc version, then the version from the argument was returned. The code changes here fix that, as well as fixing my own broken additions.
@@ -552,6 +552,7 @@ def test_libc_ver(self): | |||
(b'GLIBC_2.9', ('glibc', '2.9')), | |||
(b'libc.so.1.2.5', ('libc', '1.2.5')), | |||
(b'libc_pthread.so.1.2.5', ('libc', '1.2.5_pthread')), | |||
(b'/aports/main/musl/src/musl-1.2.5', ('musl', '1.2.5')), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add tests on version with 2 numbers and 4 numbers? Like /aports/main/musl/src/musl-1.2
and /aports/main/musl/src/musl-1.2.5.1
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could, but I don't believe musl will ever have such release numbers, so is it worth doing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parsing a binary file using a regular expression is a strange thing for me. So I prefer to have tests to make sure that the implementation is reliable. The question is more if the regex will match versions with 2 members (x.y) or 4 members (x.y.z.a), or if it only matchs version with 3 members (x.y.z).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough, though the existing tests don't do that, nor do they test the no-match cases. I could add such tests, but at that point I'd want to rewrite this test method to split it up into multiple tests, and I don't think that's in scope for this PR :) I'll add the couple of extra checks, though.
Lib/test/test_support.py
Outdated
@@ -746,7 +746,18 @@ def test_get_signal_name(self): | |||
|
|||
def test_linked_to_musl(self): | |||
linked = support.linked_to_musl() | |||
self.assertIsInstance(linked, bool) | |||
self.assertIsNotNone(linked) | |||
if support.is_wasi: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about is_emscripten?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used is_wasi as an example, but it doesn't hurt to add emscripten as well.
The code detecting the musl version works for me on Alpine Linux:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For my suggestions with dedents, please check them manually as I'm not entirely sure that I didn't mix tabs and spaces.
@unittest.skipIf( | ||
support.linked_to_musl(), | ||
'musl pathconf ignores the file descriptor and returns a constant', | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
) | |
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the style I used because it lines up better with how python's statements work (first line only is outdented, lack of outdent signals return to outer logic block). This is accepted by PEP 8, are there additional style constrains on the cpython code base these days?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't seen lots of use of hanging indents in the lib. There is no additional constraints but usually we try to be consistent with the surrounding code when possible.
Btw, do we want to create an issue (maybe an umbrella one for musl issues) or do we make it a |
There is an issue (gh-90548). I forgot the gh issue existed when I mentioned the bpo issue :( I'm not actually sure how one does the link, as I'm still coming up to speed on the "modern" way of doing development ;) |
No worries! the PR title should be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but please fix the important typo 'musl' in binary
.
Lib/platform.py
Outdated
with open(executable, 'rb') as f: | ||
binary = f.read(chunksize) | ||
pos = 0 | ||
while pos < len(binary): | ||
if b'libc' in binary or b'GLIBC' in binary: | ||
if b'libc' in binary or b'GLIBC' or 'musl' in binary: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if b'libc' in binary or b'GLIBC' or 'musl' in binary: | |
if b'libc' in binary or b'GLIBC' or b'musl' in binary: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, that's a nasty one. The actual fix is b'GLIBC
in binary or b'musl' in binary`. That's why it passed without the b...it just ran slower ;) (A lot slower, somewhat to my surprise.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I said, I won't block the PR for cosmetics only though I would have aligned with the surrounding/existing code when possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM in general.
Lib/platform.py
Outdated
libc_search = re.compile( | ||
br'(__libc_init)' | ||
br'|' | ||
br'(GLIBC_([0-9.]+))' | ||
br'|' | ||
br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)' | ||
br'|' | ||
br'(musl-([0-9.]+))' | ||
br'', | ||
re.ASCII) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, we can switch to the VERBOSE mode, which would be slightly more clear.
libc_search = re.compile( | |
br'(__libc_init)' | |
br'|' | |
br'(GLIBC_([0-9.]+))' | |
br'|' | |
br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)' | |
br'|' | |
br'(musl-([0-9.]+))' | |
br'', | |
re.ASCII) | |
libc_search = re.compile(br''' | |
(__libc_init) | |
| (GLIBC_([0-9.]+)) | |
| (libc(_\w+)?\.so(?:\.(\d[0-9.]*))?) | |
| (musl-([0-9.]+)) | |
''', | |
re.ASCII | re.VERBOSE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that.
Lib/test/support/__init__.py
Outdated
# emscripten (at least as far as we're concerned) and wasi use musl, | ||
# but platform doesn't know how to get the version, so set it to zero. | ||
if is_emscripten or is_wasi: | ||
return (_linked_to_musl := (0, 0, 0)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think that it is necessary to use the :=
operator here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is never necessary to use the :=
operator, so do you mean you prefer the more verbose style (which I'm fine with changing to), or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the more verbose style, which is also more sequential and clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
support.is_emscripten or support.is_wasi, | ||
"musl libc issue on Emscripten, bpo-46390" | ||
) | ||
@unittest.skipIf(support.linked_to_musl(), "musl libc issue, bpo-46390") | ||
@run_with_locales('LC_TIME', 'en_US', 'fr_FR', 'de_DE', 'ja_JP', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can add the linked_to_musl()
check in run_with_locales()
and run_with_locale()
. This may be non-trivial, depending on arguments, a dummy run can be supported even if no suitable locale was found. For now, the proposed change is good as is.
This didn't cause a test failure because the broken logic caused the regex to always run...which is a lot slower.
I'm thinking this is not worth backporting? |
I don't think that it's worth it to backport this change to stable branches. Supporting Alpine Linux can be seen as a new feature ;-) |
Make musl test skips smarter (fixes Alpine errors)
A relatively small number of tests fail when the underlying c library is
provided by musl. This was originally reported in bpo-46390 by
Christian Heimes. Among other changes, these tests were marked for
skipping in gh-31947/ef1327e3 as part of bpo-40280 (emscripten support),
but the skips were conditioned on the platform being emscripten (or
wasi, skips for which ere added in 9b50585).
In gh-131071 Victor Stinner added a linked_to_musl function to enable
skipping a test in test_math that fails under musl, like it does on a
number of other platforms. This check can successfully detect that
python is running under musl on Alpine, which was the original problem
report in bpo-46390.
This PR replaces Victor's solution with an enhancement to
platform.libc_ver that does the check more cheaply, and also gets the
version number. The latter is important because the math test being
skipped is due to a bug in musl that has been fixed, but as of this
checkin date has not yet been released. When it is, the test skip can
be fixed to check for the minimum needed version.
The enhanced version of linked_to_musl is also used to do the skips of
the other tests that generically fail under musl, as opposed to
emscripten or wasi only failures. This will allow these tests to be
skipped automatically on Alpine.
This PR does not enhance libc_ver to support emscripten and wasi, as
I'm not familiar with those platforms; instead it returns a version
triple of (0, 0, 0) for those platforms. This means the musl tests will
be skipped regardless of musl version, so ideally someone will add
support to libc_ver for these platforms.
📚 Documentation preview 📚: https://cpython-previews--131313.org.readthedocs.build/