nicegui
nicegui copied to clipboard
`asyncio.create_subprocess_exec` does not work on windows
Transferred from #454
One example file uses asyncio and its create_subprocess_exec
function. If run on windows, this function raises a NotImplementedError
, because, as far as I can tell, it's not available on windows.
It would be interesting to research if an alternative solution could be found to make the example file run on all platforms.
I also have this problem with script executor example.
Error is:
in _make_subprocess_transport raise NotImplementedError
I found a workaround using this code in main.py of the script executor
example:
import subprocess
sync def run_command(command: str) -> None:
'''Run a command in the background and display the output in the pre-created dialog.'''
dialog.open()
result.content = ''
process = subprocess.Popen(
command,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
cwd=os.path.dirname(os.path.abspath(__file__))
)
# NOTE we need to read the output in chunks, otherwise the process will block
output = ''
while True:
new = process.stdout.read(4096)
if not new:
break
output += new.decode()
# NOTE the content of the markdown element is replaced every time we have new output
result.content = f'```\n{output}\n```
Thanks for the code, @spehj. Unfortunately neither the Popen call nor the stdout.read are async. That means the UI will block. This may not be noticeable to you but may have huge impact when you want to use the example in a production setting.
I'm still dumbfounded that the create_subprocess_exec
from the Python standard library is not working on Windows.
I just found https://github.com/tiangolo/fastapi/issues/964 which says that Uvicorn, the ASGI webserver used by FastAPI/NiceGUI is picking the wrong event loop. Can anybody with Windows confirm that without FastAPI/NiceGUI the create_subprocess_exec
is working?
Thanks, you're right @rodja, it's blocking but I couldn't find better solution.
I used this code to test if create_subprocess_exec
works on Windows:
import asyncio
async def test_create_subprocess():
process = await asyncio.create_subprocess_exec("ipconfig", stdout=asyncio.subprocess.PIPE)
stdout, stderr = await process.communicate()
print(stdout.decode())
asyncio.run(test_create_subprocess())
... and it works fine.
In the solution to https://github.com/encode/uvicorn/issues/1220 it seems that Uvicorn only changes the event loop if reload is activated. Can someone with Windows verify that the original example works as expected if you set ui.run(reload=False)
?
@rodja I can confirm that with ui.run(reload=False)
the original example works as expected.
Great. Then a quick fix for the example would be to use
ui.run(reload=platform.system() != "Windows")
But maybe someone finds another, more sophisticated solution?
ui.run(reload=platform.system() != 'Windows')
It works, thankyou