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

pythonPackages.sanic: 19.3.1 -> 19.6.3 (and fix websockets and other issues) #68321

Merged
merged 4 commits into from Sep 30, 2019

Conversation

simonchatts
Copy link
Contributor

Motivation for this change

In pythonPackages, the sanic package requires websockets version 6.x, but the default provided is version 7.0.

The current workaround is just to delete the version bounds on this dependency. This moves the problem to runtime: the first time the websocket functionality is actually used, it fails (see below for a test case and resulting crash).

The change here brings in the correct version of the websockets Python package, so that this works.

Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nix-review --run "nix-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Ensured that relevant documentation is up to date
  • Fits CONTRIBUTING.md.
Test case

In case useful, here's a minimal concrete test case.

If this is server.py:

from sanic import Sanic
from sanic.websocket import WebSocketProtocol

app = Sanic()

@app.websocket('/ws')
async def foo(req, ws):
  await ws.send('hello from websocket!')

app.run(protocol=WebSocketProtocol)

and you run this server via

nix-shell --pure -p 'python3.withPackages(p: [p.sanic])' --command 'python server.py'

(along with an assumed -I nixpkgs=<path to nixpkgs>), and invoke a test client:

nix-shell -p websocat --command 'websocat ws://127.0.0.1:8000/ws'

then with the current code, you get a crashdump:

[2019-09-08 19:35:50 +0100] [1688] [ERROR] Exception occurred while handling uri: 'ws://127.0.0.1:8000/ws'
Traceback (most recent call last):
  File "/nix/store/034m3rj9j27zvdldvpn6bdzpm0h3fn7c-python3-3.7.4-env/lib/python3.7/site-packages/sanic/app.py", line 917, in handle_request
    response = await response
  File "/nix/store/034m3rj9j27zvdldvpn6bdzpm0h3fn7c-python3-3.7.4-env/lib/python3.7/site-packages/sanic/app.py", line 473, in websocket_handler
    ws = await protocol.websocket_handshake(request, subprotocols)
  File "/nix/store/034m3rj9j27zvdldvpn6bdzpm0h3fn7c-python3-3.7.4-env/lib/python3.7/site-packages/sanic/websocket.py", line 69, in websocket_handshake
    key = handshake.check_request(request.headers)
  File "/nix/store/034m3rj9j27zvdldvpn6bdzpm0h3fn7c-python3-3.7.4-env/lib/python3.7/site-packages/websockets/handshake.py", line 82, in check_request
    [parse_connection(value) for value in headers.get_all('Connection')], []
AttributeError: 'multidict._multidict.CIMultiDict' object has no attribute 'get_all'

With the code changes here, you just see the correct client output:

hello from websocket!
Notify maintainers

cc @costrouc

Copy link
Member

@FRidh FRidh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple versions of a Python package in the Python packages set is not allowed.

@FRidh
Copy link
Member

FRidh commented Sep 8, 2019

Maybe bumping the version of sanic is a solution.

@simonchatts
Copy link
Contributor Author

Ah yes, makes sense now you say it. The very latest release of sanic updates to the version of websockets in nixpkg - I’ll give it a test, and update this PR if it seems stable. Thanks for the feedback!

@simonchatts
Copy link
Contributor Author

simonchatts commented Sep 9, 2019

OK, I've updated sanic to the latest release. This required several other cascading changes:

  • The newer version of sanic now depends on requests-async, which in turn depends on httpcore. These aren't in nixpkgs, but they are also marked as deprecated by their author. So rather than introduce an already-dying maintenance burden, I've declared them just as local packages within sanic.
  • The h11 Python package in the dependency graph was already broken for Python 3, so fixed that (by applying a one-line patch from their repo that has yet to be released).
  • The uvicorn framework is used for sanic testing, and this was pinned to an old version of uvloop. I've updated this, and tested with all the other packages that depend on uvicorn (edit: this is fastapi and starlette as well as sanic, where I tested a minimal web server for each).

I've tested the result on both nixos and macOS, and everything looks good so far.

@simonchatts simonchatts changed the title pythonPackages.sanic: provide correct websockets-6.x dependency pythonPackages.sanic: 19.3.1 -> 19.6.3 (and fix websockets and other issues) Sep 9, 2019
@ofborg ofborg bot requested a review from wd15 September 9, 2019 19:44
@lheckemann
Copy link
Member

Is this a fix that should be backported to 19.09?

@simonchatts
Copy link
Contributor Author

@lheckemann I assume this is tradeoff judgment aimed at the reviewers and code owners. But I can say that without some sort of changes like these, in 19.09:

  • h11 is broken for python3 (and hence dependent packages like uvicorn, fastapi, starlette and wsproto)
  • sanic’s websockets functionality is broken

@wd15
Copy link
Contributor

wd15 commented Sep 11, 2019

The datasette tests don't seem to be passing with this change. However, I updated datasette to the lastest version and it builds and passes the tests (sanic is no longer a dependency). Here are the changes. Shall I try and add that into this PR or feel free to just duplicate?

@simonchatts
Copy link
Contributor Author

Thanks @wd15! I've just duplicated as suggested to keep things simple.

I've also checked that the other python package that depends on sanic (pytest-sanic, in addition to datasette) at least builds with these changes.

@lheckemann lheckemann added this to the 20.03 milestone Sep 12, 2019
@wd15
Copy link
Contributor

wd15 commented Sep 12, 2019

Also, mitmproxy seems to hang forever during the test stage as well as failing a few. It at least attempts to build now with these changes so is not a regression.

@wd15
Copy link
Contributor

wd15 commented Sep 16, 2019

After merging in the latest master (2ff3620) into this branch and resolving h11 conflicts nix-review passes so I'm giving my approval to this PR.

Result of nix-review 1 using Linux 5.0.0-27-generic #28-Ubuntu x86_64 GNU/Linux

5 packages were built:
  • datasette (python37Packages.datasette)
  • python37Packages.fastapi (python37Packages.datasette)
  • python37Packages.sanic (python37Packages.datasette)
  • python37Packages.starlette (python37Packages.datasette)
  • python37Packages.uvicorn (python37Packages.datasette)

It looks like the issues with mitmproxy have been resolved

@zimbatm
Copy link
Member

zimbatm commented Sep 19, 2019

it's rare to see so detailed reports in a PR. <3 @simonchatts

It looks like h11 has been fixed for python3 in master already. Do you mind rebasing the PR one last time?

@simonchatts
Copy link
Contributor Author

Thanks @zimbatm - rebased with the existing h11 fix.

@Mic92
Copy link
Member

Mic92 commented Sep 23, 2019

looks there is a conflict again.

Copy link
Member

@zimbatm zimbatm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one last rebase?

@simonchatts
Copy link
Contributor Author

Thanks @zimbatm! I've done the rebase and suggested comment in my local repo, but hit a problem: @jonringer recently upgraded the Python websockets from 7.x to 8.x. Sanic requires 7.x.

I presume this sort of issue has come up before - any advice @wd15 @FRidh?

BTW @jonringer that websockets 8.x upgrade also breaks on Darwin, since it also enables the tests but they don't work on Darwin (hit OSError: AF_UNIX path too long) but that's a minor detail here.

@jonringer
Copy link
Contributor

oops :( I got added to extra-users recently to ofborg, so I'll be more aware of when darwin fails

The new version depend on two packages that are not currently in nixpkgs, and
marked as already deprecated by their author. So just include them locally. Also,
adapt to the fact that the version of websockets in nixpkgs is 8.x, when sanic
wants 7.x.
Patch donated by @wd51, and removes sanic dependency.
@simonchatts
Copy link
Contributor Author

I think I have a resolution to the major version conflict for websockets: the changes for websockets 8.x are actually very tame for sanic's usage, and they are already almost compatible.

So I've updated this branch with a small modification to sanic to use the 8.x websockets now in nixpkgs. (I'll also try to upstream these, so this should all be simpler in the future.) I've tested these with some apps that make heavy use of sanic websockets, and it all looks fine so far.

@jonringer I've also fixed the Darwin test issue with websockets here, but can obviously drop this if it's already covered by some other commit.

I think this resolves all the pending issues.

@Mic92
Copy link
Member

Mic92 commented Sep 30, 2019

@GrahamcOfBorg build python37Packages.datasette datasette python37Packages.sanic python37Packages.uvicorn

@Mic92 Mic92 merged commit 13ae344 into NixOS:master Sep 30, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants