-
-
Notifications
You must be signed in to change notification settings - Fork 30.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-89545: Adds internal _wmi module on Windows for directly querying OS properties #96289
Conversation
zooba
commented
Aug 25, 2022
•
edited by bedevere-bot
Loading
edited by bedevere-bot
- Issue: platform() is not able to detect windows 11 #89545
…rying OS properties
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.
Nice enhancement! Some remarks.
Misc/NEWS.d/next/Windows/2022-08-26-00-11-18.gh-issue-89545.zmJMY_.rst
Outdated
Show resolved
Hide resolved
Co-authored-by: Victor Stinner <vstinner@python.org>
if (offset >= sizeof(buffer)) { | ||
err = ERROR_MORE_DATA; |
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'd prefer for the implementation to support a growable buffer with malloc()
, realloc()
, and free()
. The 8 KiB limit is enough for Win32_OperatingSystem
and Win32_Processor
, but it's more useful in general if the result size isn't limited (e.g. a query that returns an arbitrary number of instances).
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's an internal API, so we can always add that in when we find we need it in the stdlib.
I don't know of any existing APIs we have that would be more correct using WMI and would need some sort of "query everything" API.
I think the most straight-froward pipe-based implementation that supports cancel via Ctrl+C is to use a named pipe. For the read side, call |
Note that the There's no significant performance cost if calling Footnotes
|
Co-authored-by: Eryk Sun <eryksun@gmail.com>
I did remove the places I found that may trigger this on normal load, but the point is well made. However, I don't think we could reliably handle In any case, I think all that belongs in a new issue. At worst, we can always make |
Currently Python's standard library cannot use ctypes could potentially be used to call
Compared to a control event, it's a lot harder to create a hidden window, run a message loop, and handle |
If I substitute "onecore_apiset.lib" for "ole32.lib" in "PCbuild/pyproject.props", "_wmi.pyd" and "_ctypes.pyd" end up linking to "api-ms-win-core-com-l1-1-0.dll". This API set is implemented by "combase.dll", which doesn't immediately load "user32.dll". That said, "user32.dll" still gets loaded as soon as FWIW, linking with "onecore_apiset.lib" does solve the ctypes problem. I think a purely console or purely background script should at least be able to set a handler via |
If it's an issue, I suggest to call the _wmi module in a subprocess in the platform module. I don't think that the performance of platform module is critical and this module already spawns subprocesses to retrieve some data. We just have to make sure that the result is cached to only do that once ;-) I don't expect the Windows version to change while a process is running. |
Sorry if the point was lost in side discussions, but the main concern was the change to use |
Let's hope not 😆
Did we ever document the |
It's documented, but it's documented as being unreliable. So I removed the WMI check in |
If this is implemented, I suggest using multiprocessing. It implements If importing def _wmi_query(table, *keys):
table = {
"OS": "Win32_OperatingSystem",
"CPU": "Win32_Processor",
}[table]
query = "SELECT {} FROM {}".format(",".join(keys), table)
if _wmi._isguiprocess():
data = _wmi.exec_query(query)
else:
import multiprocessing
p = multiprocessing.Pool(1)
try:
data = p.apply(_wmi.exec_query, (query,))
finally:
p.close()
split_data = (i.partition("=") for i in data.split("\0"))
dict_data = {i[0]: i[2] for i in split_data}
return (dict_data[k] for k in keys) A more elaborate implementation would only close the process pool after it hasn't been used for a minute or so, like how COM implements the local server context. |
We can recommend it if people run into trouble. But I don't see any reason to do it preemptively. This is far from the only thing likely to load user32, and it should only impact people who are already doing things that we don't provide for them. Using the |
The effect of loading user32.dll and converting the current thread to a GUI thread is not trivial. Would it make sense to document the change in the sys.getwindowsversion() documentation? |
Not now that It probably makes more sense to document it in |
Co-authored-by: Eryk Sun <eryksun@gmail.com>
Currently the These three control events could be supported if the This is all for naught, however, whenever "python[w].exe" gets executed by "py[w].exe" or "venv[w]launcher.exe". The behavior of the launchers is probably worth fixing, but it's not critical. They're primarily intended for development, not deployment of applications and services. "py[w].exe" and "venvwlauncher.exe" load "user32.dll". Since they don't create a hidden window that handles Also, the control handler for the launchers returns A simple way to handle these cases is to remove the child process from the job object when either the session is known to be ending or the console window/tab is closing. In these cases, both the launcher and Python either have to exit on their own or eventually get terminated, so coupling them with a job object no longer matters. |
Basically, you mean it's to handle the signals and pass them along correctly. That's likely true, but it's not really that simple. The job object is already relied upon for termination by PID, so we need to keep the job object. In any case, definitely not part of this change. So I'll merge what is here and we can figure out termination edge cases in all our other mixed up stuff separately. (I'm honestly inclined to just always load user32 and run the loop to handle it, apart from the performance overhead that entails...) |
|
I'm on the failure |