You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
platform module functions execute for a long time if user has no permissions to WMI #112278
From Python 3.12, probably since #89545 was implemented, the invocation of functions from platform modules takes a multiple of 5 seconds if the user has no permissions to perform WMI queries. It can be reproduced by connecting to a Windows machine using SSH and executing a Python script from cmd or ps. Access to WMI for remote sessions is turned off by default but this probably can be achieved also by removing permissions using wmimgmt.msc application.
For example, the execution of the system function in Python 3.12:
user@WIN16 c:\Python3.12>python.exe -m timeit -s "import platform" -n 1 -r 1 "platform.system()"
1 loop, best of 1: 10.2 sec per loop
and the same in Python 3.11:
user@WIN16 c:\Python3.11>python.exe -m timeit -s "import platform" -n 1 -r 1 "platform.system()"
1 loop, best of 1: 18.1 msec per loop
(timeit used with -n 1 -r 1 to avoid using cache in the platform module. When results get cached then of course it works fast).
It's very hard to work around this or avoid the delay. Even if you do not use platform in your code, or use sys/os replacements like os.name or sys.getwindowsversion() it sooner or later turns out that the platform module is used by some 3rd party library you import because it is widely used in Python's world.
As an example, merely importing aiohttp or SQLAlchemy in a session over SSH on Windows Server 2019 using Python 3.12:
Python 3.12.0 (tags/v3.12.0:0fb18b0, Oct 2 2023, 13:03:39) [MSC v.1935 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.timeit('import aiohttp', number=1)
10.157976499991491
Python 3.12.0 (tags/v3.12.0:0fb18b0, Oct 2 2023, 13:03:39) [MSC v.1935 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.timeit('import sqlalchemy', number=1)
10.204078600043431
I think we can replace the platform._wmi_query with the dummy implementation when first failure, this can reduce the time costs to nearly 5 seconds, (just one timeout when connect to WMI):
PS C:\Users\xxxxx\Source\cpython> .\python.bat -m timeit -s "import platform" -n 1 -r 1 "platform.system()"
Running Debug|x64 interpreter...
1 loop, best of 1: 5.12 sec per loop
This should be backported to 3.12 as well, but they're right in the middle of getting 3.12.1 ready and I don't think this is that urgent. Monkeypatch platform._wmi_query early in your app if you need to suppress it.
Thank you for fixing this! For 3.12.1 we will use the runtime hooks feature from pyinstaller to override the _wmi_query function before anything else is run.
The timeout is too short - I'm getting failures on some of my test machines. It wouldn't surprise me if it's due to them being slower, and so COM takes longer to load and initialize on its first use.
We can either make the timeout longer (I'd suggest 1 second), or add a second event that sets just before the connection attempt. That way we can wait for everything to load with a long timeout, but only wait for the connection with a short timeout.
The timeout is too short - I'm getting failures on some of my test machines. It wouldn't surprise me if it's due to them being slower, and so COM takes longer to load and initialize on its first use.
We can either make the timeout longer (I'd suggest 1 second), or add a second event that sets just before the connection attempt. That way we can wait for everything to load with a long timeout, but only wait for the connection with a short timeout.
Increasing the timeout to 1 second will lead to _wmi_query taking more than 1 second to call without WMI permission, even if the COM has loaded and initialized. Therefore, I think the second approach is better.
Thanks for the PR! That makes the backport a bit more complicated, but I think once we've seen it's stable in 3.13 then we can just backport the entire file - nothing else should've changed here for 3.13.
Activity
kfrydel commentedon Nov 21, 2023
It's very hard to work around this or avoid the delay. Even if you do not use
platformin your code, or usesys/osreplacements likeos.nameorsys.getwindowsversion()it sooner or later turns out that theplatformmodule is used by some 3rd party library you import because it is widely used in Python's world.gozdal commentedon Nov 22, 2023
As an example, merely importing aiohttp or SQLAlchemy in a session over SSH on Windows Server 2019 using Python 3.12:
cc @zooba as the original author
radkujawa commentedon Nov 22, 2023
bumping this, it is a serious issue in my project
aisk commentedon Dec 3, 2023
I think we can replace the
platform._wmi_querywith the dummy implementation when first failure, this can reduce the time costs to nearly 5 seconds, (just one timeout when connect to WMI):Then I think we should set the timeout for the connection to WMI. But https://learn.microsoft.com/en-us/windows/win32/api/wbemcli/nf-wbemcli-iwbemlocator-connectserver said that the timeout can only be set to "2 minutes or less" and there seems to no other way to set it to a custom value. So using a
Eventobject to simulate the timeout may be a solution.gh-112278: Disable WMI queries on Windows after they time out (GH-112658
zooba commentedon Dec 7, 2023
This should be backported to 3.12 as well, but they're right in the middle of getting 3.12.1 ready and I don't think this is that urgent. Monkeypatch
platform._wmi_queryearly in your app if you need to suppress it.kfrydel commentedon Dec 7, 2023
Thank you for fixing this! For 3.12.1 we will use the runtime hooks feature from pyinstaller to override the
_wmi_queryfunction before anything else is run.zooba commentedon Dec 8, 2023
The timeout is too short - I'm getting failures on some of my test machines. It wouldn't surprise me if it's due to them being slower, and so COM takes longer to load and initialize on its first use.
We can either make the timeout longer (I'd suggest 1 second), or add a second event that sets just before the connection attempt. That way we can wait for everything to load with a long timeout, but only wait for the connection with a short timeout.
aisk commentedon Dec 8, 2023
Increasing the timeout to 1 second will lead to
_wmi_querytaking more than 1 second to call without WMI permission, even if the COM has loaded and initialized. Therefore, I think the second approach is better.gh-112278: In _wmi, treat initialization timeout separately from conn…
zooba commentedon Dec 8, 2023
Thanks for the PR! That makes the backport a bit more complicated, but I think once we've seen it's stable in 3.13 then we can just backport the entire file - nothing else should've changed here for 3.13.
5 remaining items
gh-112278: Add retry in WMI tests in case of slow initialization (GH-…
pythongh-112278: Add retry in WMI tests in case of slow initialization (
pythongh-112278: Disable WMI queries on Windows after they time out (p…
pythongh-112278: In _wmi, treat initialization timeout separately fro…
pythongh-112278: Add retry in WMI tests in case of slow initialization (
pythongh-112278: Improve error handling in wmi module and tests
zooba commentedon Apr 12, 2024
If the fix in #117818 reduces/fixes the occasional errors we've been getting in CI, then I'll consider this issue complete and close it.
Reviews/manual testing appreciated.
gh-112278: Improve error handling in wmi module and tests (GH-117818)
pythongh-112278: Improve error handling in wmi module and tests (pyth…
gh-112278: Improve error handling in wmi module and tests (GH-117818)
pythongh-112278: Improve error handling in wmi module and tests (pyth…
pythongh-112278: Disable WMI queries on Windows after they time out (p…
pythongh-112278: In _wmi, treat initialization timeout separately fro…
pythongh-112278: Add retry in WMI tests in case of slow initialization (