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

windows support #82

Closed
seewindcn opened this issue Jun 20, 2018 · 22 comments
Closed

windows support #82

seewindcn opened this issue Jun 20, 2018 · 22 comments
Milestone

Comments

@seewindcn
Copy link

Can uvicorn support windows?
I am develops in windows, and want to use uvicorn.

@tomchristie
Copy link
Member

Certainly the latest version (0.2) should, as there's no platform-specific stuff in there.

I don't know if there's any issues or not prior to that (or with 0.2 running under gunicorn) but happy to hear of any issues if you're seeing them

@seewindcn
Copy link
Author

I have try to run under windows, there some stuff want to modify:

  1. uvloop no support; want to use the default loop;
  2. signals no support; disable UvicornWorker.init_signals and Server.set_signal_handlers

@tomchristie tomchristie reopened this Jul 11, 2018
@tomchristie
Copy link
Member

uvloop no support; want to use the default loop;

Okay, that's easy enough to do: --loop asyncio tho we might want to detect windows or pypy, and choose our loop and parser policies accordingly.

See also MagicStack/uvloop#14 and MagicStack/uvloop#62

signals no support; disable UvicornWorker.init_signals and Server.set_signal_handlers

Okay, I've disable them in #122
I've attempted to support catching Ctrl+C through signal.signal, but it's not clear to me if it's sufficient as implemented. (See https://stackoverflow.com/questions/24774980/why-cant-i-catch-sigint-when-asyncio-event-loop-is-running/24775107#24775107)

It's possible that we ought to start a new thread on windows specifically to catch signals.

@tomchristie
Copy link
Member

Released as 0.2.10.

It'd be hugely helpful for anyone running on windows to try...

uvicorn app:app --loop asyncio

(Use the basic example app in the README to keep everything else simple)

And see if:

  • Does it start up okay now and serve requests? (If not what output do you see?)
  • Does it terminates okay on Ctrl+C events now? (What output do you see? Does nothing happen, or is it a clean termination, or is a python exception displayed?)
  • Can it be terminated by process explorer or whatever?

@daniil-konovalenko
Copy link

daniil-konovalenko commented Jul 13, 2018

Hey @tomchristie, the installation on Windows fails because uvloop does not support Windows at the moment. Is there an option to install uvicorn without uvloop?

I found an ugly workaround of installing uvicorn with --no-dependencies and then installing every dependecy except uvloop manually.
Also worth noting that httptools requires a whole Visual Studio 2015 to build

Test results

I tested it on 64-bit Windows 10 Pro 1803 and Anaconda Python 3.6.5

Does it start up okay now and serve requests? (If not what output do you see?)

Yes, it works pretty well

Does it terminates okay on Ctrl+C events now? (What output do you see? Does nothing happen, or is it a clean termination, or is a python exception displayed?)

Yes, it terminates on Ctrl+C, not without an exception though:

(venv) C:\Users\ddkon\Projects\uvicorn-win-test>uvicorn app:App --loop asyncio
* Uvicorn running on http://127.0.0.1:8000 🦄 (Press CTRL+C to quit)
INFO: Started worker [10504]
INFO: 127.0.0.1 - "GET / HTTP/1.1" 200
INFO: 127.0.0.1 - "GET /favicon.ico HTTP/1.1" 200
INFO: 127.0.0.1 - "GET / HTTP/1.1" 200
INFO: 127.0.0.1 - "GET /favicon.ico HTTP/1.1" 200
INFO: 127.0.0.1 - "GET / HTTP/1.1" 200
INFO: 127.0.0.1 - "GET /favicon.ico HTTP/1.1" 200
INFO: 127.0.0.1 - "GET /what HTTP/1.1" 200
INFO: 127.0.0.1 - "GET /favicon.ico HTTP/1.1" 200
Traceback (most recent call last):
  File "c:\users\ddkon\anaconda3\Lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "c:\users\ddkon\anaconda3\Lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Users\ddkon\Projects\uvicorn-win-test\venv\Scripts\uvicorn.exe\__main__.py", line 9, in <module>
  File "c:\users\ddkon\projects\uvicorn-win-test\venv\lib\site-packages\click\core.py", line 722, in __call__
    return self.main(*args, **kwargs)
  File "c:\users\ddkon\projects\uvicorn-win-test\venv\lib\site-packages\click\core.py", line 697, in main
    rv = self.invoke(ctx)
  File "c:\users\ddkon\projects\uvicorn-win-test\venv\lib\site-packages\click\core.py", line 895, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "c:\users\ddkon\projects\uvicorn-win-test\venv\lib\site-packages\click\core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "c:\users\ddkon\projects\uvicorn-win-test\venv\lib\site-packages\uvicorn\main.py", line 50, in main
    server.run()
  File "c:\users\ddkon\projects\uvicorn-win-test\venv\lib\site-packages\uvicorn\main.py", line 142, in run
    self.loop.run_forever()
  File "c:\users\ddkon\anaconda3\Lib\asyncio\base_events.py", line 422, in run_forever
    self._run_once()
  File "c:\users\ddkon\anaconda3\Lib\asyncio\base_events.py", line 1396, in _run_once
    event_list = self._selector.select(timeout)
  File "c:\users\ddkon\anaconda3\Lib\selectors.py", line 323, in select
    r, w, _ = self._select(self._readers, self._writers, [], timeout)
  File "c:\users\ddkon\anaconda3\Lib\selectors.py", line 314, in _select
    r, w, x = select.select(r, w, w, timeout)
  File "c:\users\ddkon\projects\uvicorn-win-test\venv\lib\site-packages\uvicorn\main.py", line 145, in handle_exit
    self.logger.warning("Received signal {}. Shutting down.".format(sig.name))
AttributeError: 'int' object has no attribute 'name'

Can it be terminated by process explorer or whatever?

Yes, it is visible in Task Manager and I was able to terminate it from there
image

@tomchristie
Copy link
Member

Wonderful, thanks so much! 😎😎😎

So ‘pip install uvicorn’ raises an error then?
Will have to think about how to handle that gracefully. Presumably setup.py could detect if it’s being installed on windows and adapt the requirements. (Running with ‘—loop uvloop —http h11’ would make sense.)

The Ctrl-C exception looks easy enough to resolve.

And thanks again, that’s super-helpful!

@uranusjr
Copy link

uranusjr commented Jul 13, 2018

One other installation issue: Currently setup.py uses the built-in open to read README. This would likely cause problems in the majority of Windows machines, where the default system encoding cannot decode the Unicorn emoji. This is not difficult to resolve for a Python 3-only project—simply add encoding='utf8' to open.

Getting past that (I cloned and manually deleted the emoji), you’ll hit the uvloop support problem mentioned previously:

> pip install .\uvicorn\
Processing c:\users\uranusjr\documents\playground\uvicorn-play\uvicorn
Collecting click (from uvicorn==0.2.12)
  Using cached https://files.pythonhosted.org/packages/34/c1/8806f99713ddb993c5366c362b2f908f18269f8d792aff1abfd700775a77/click-6.7-py2.py3-none-any.whl
Collecting h11 (from uvicorn==0.2.12)
  Using cached https://files.pythonhosted.org/packages/f9/f3/8e4cf5fa1a3d8bda942a0b1cf92f87815494216fd439f82eb99073141ba0/h11-0.8.1-py2.py3-none-any.whl
Collecting httptools (from uvicorn==0.2.12)
  Using cached https://files.pythonhosted.org/packages/a3/75/40cdb732e8ef547d9f34ceb83c43ea7188c0ffb719ddc6a1ad160464292d/httptools-0.0.11.tar.gz
Collecting uvloop (from uvicorn==0.2.12)
  Using cached https://files.pythonhosted.org/packages/cd/e5/1492d3a6ee52f261df764eece684513bb8abbe988d4bd3d94093f39e2bea/uvloop-0.11.0.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "C:\Users\uranusjr\AppData\Local\Temp\pip-install-mlbym38h\uvloop\setup.py", line 15, in <module>
        raise RuntimeError('uvloop does not support Windows at the moment')
    RuntimeError: uvloop does not support Windows at the moment

@uranusjr
Copy link

uranusjr commented Jul 14, 2018

Some additional information.

Running with Python 3.7, httptools does not require me the whole Visual Studio to build. Minimal VS 2017 Build Tools setup (toolkit v14.1, CRT SDK, and Windows 10 SDK) is enough for me to get it working. I didn’t test, but imagine the same would apply for 3.6 (which also supports VSBT 14.1) and 3.5 (VSBT 14.0 should work here).

Windows detection is straightforward with modern PEP 508 support. A simple change to the uvloop requirement into

"uvloop; platform_system!='Windows'",

And it installs for me 😃

I am not sure what’s the actual requirement of uvloop, but maybe os_name=='posix' or sys_platform!='win32' could be better markers.

@daniil-konovalenko
Copy link

I'm glad I could help!
Yeah, it does raise an error, such as the one that @uranusjr posted.
I was thinking that it might be a good idea to make uvloop an optional dependency (Yuri Selivanov strongly advises to). What do you think?

@tomchristie
Copy link
Member

I’d like the behaviour to be that it’s used by default, but falls back to asyncio gracefully. We’re very close to that now - just need a few tweaks to setup.py and modify the defaulting behaviour in main.py a little

@tomchristie
Copy link
Member

Okay, I think we should be looking much better now! 👍

Version 0.2.13 released, with fixes from #130

Anyone able to give it a whirl? 😄

@uranusjr
Copy link

I would strongly recommend using PEP 508 environment markers to specify dependencies instead. This allows for the same effect (in relatively recent Setuptools and pip), prevents the packager from needing to maintain platform-specific artifacts (e.g. wheels), and has immensely better compatibility with the new trend of locking-aware dependency management tools like Pipenv and Poetry.

The following should be functionality-wise equivalent to the if-elif-else clause:

requirements = [
    'click',
    'h11',
    'websockets>=6.0',
    "httptools; platform_system != 'Windows' and 'CYGWIN' not in platform_system and platform_python_implementation != 'PyPy'",
    "uvloop; platform_system != 'Windows' and 'CYGWIN' not in platform_system and platform_python_implementation != 'PyPy'",
]

@tomchristie
Copy link
Member

Presumably things are problematic ATM, as we're importing httptools regardless of if it's installed or not.

@tomchristie
Copy link
Member

@uranusjr Okay, I could be up for that. Any idea which versions of pip will support it, or if there's likely any other compatibility issues it could introduce?

@uranusjr
Copy link

The markers were introduced in Setuptools 36.2.0, released 2017-07-13. This version is officially bundled in ensurepip only after 3.6.5, but all major package managers have picked it up long before that.

Syntax support shouldn’t be a problem as long as the user updates setuptools (or pip, which implies a setuptools update) in a remotely regular basis. (And there is little reason not to, since setuptools maintains backward compatibility next to forever.) Practically I have yet to see anyone actually complain about this.

@tomchristie
Copy link
Member

Practically I have yet to see anyone actually complain about this.

@uranusjr Okay - Are there any reasonably prominent examples of projects using it? (Just so I can make a call on ubiquity of support) Thanks for all this!

@tomchristie
Copy link
Member

Treating this as a separate issue, at #135

@tomchristie
Copy link
Member

tomchristie commented Jul 19, 2018

I believe we now have functioning windows support from 0.2.14 onwards.
Confirmation from anyone would be ace! /cc @daniil-konovalenko @uranusjr

@uranusjr
Copy link

uranusjr commented Jul 19, 2018

Running the example in README gives me the following error:

C:\Users\uranusjr\Documents\playground\uvicorn-play
(uvicorn-play) λ python -c "import uvicorn; print(uvicorn.__version__)"
0.2.14

C:\Users\uranusjr\Documents\playground\uvicorn-play
(uvicorn-play) λ uvicorn app:App
Traceback (most recent call last):
  File "C:\Users\uranusjr\AppData\Local\Programs\Python\Python37\Lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "C:\Users\uranusjr\AppData\Local\Programs\Python\Python37\Lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Users\uranusjr\Documents\playground\uvicorn-play\.venv\Scripts\uvicorn.exe\__main__.py", line 9, in <module>
  File "c:\users\uranusjr\documents\playground\uvicorn-play\.venv\lib\site-packages\click\core.py", line 722, in __call__
    return self.main(*args, **kwargs)
  File "c:\users\uranusjr\documents\playground\uvicorn-play\.venv\lib\site-packages\click\core.py", line 697, in main
    rv = self.invoke(ctx)
  File "c:\users\uranusjr\documents\playground\uvicorn-play\.venv\lib\site-packages\click\core.py", line 895, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "c:\users\uranusjr\documents\playground\uvicorn-play\.venv\lib\site-packages\click\core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "c:\users\uranusjr\documents\playground\uvicorn-play\.venv\lib\site-packages\uvicorn\main.py", line 55, in main
    run(app, host, port, http, loop, log_level)
  File "c:\users\uranusjr\documents\playground\uvicorn-play\.venv\lib\site-packages\uvicorn\main.py", line 64, in run
    loop_setup = import_from_string(LOOP_SETUPS[loop])
  File "c:\users\uranusjr\documents\playground\uvicorn-play\.venv\lib\site-packages\uvicorn\importer.py", line 20, in import_from_string
    module = importlib.import_module(module_str)
  File "c:\users\uranusjr\documents\playground\uvicorn-play\.venv\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 953, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 965, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'uvicorn.loops'

Didn’t look deep but it seems like a circular import problem?

@tomchristie
Copy link
Member

I think we do now have windows support properly enabled again.
Confirmations from anyone would be much appreciated. 😄

(Also any thoughts on CI services that'd allow me to test against this?)

@tomchristie tomchristie added this to the Version 1.0 milestone Jul 25, 2018
@uranusjr
Copy link

Can confirm uvicorn now works out of the package as of 0.2.22 🕺

@tomchristie
Copy link
Member

Rad! ✨

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants