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

How to pass additional args to server function in Basic example file? #271

Closed
chmedly opened this issue Sep 20, 2017 · 7 comments
Closed

Comments

@chmedly
Copy link

chmedly commented Sep 20, 2017

I must be missing something simple here. I'm looking at the Basic server and client examples in the docs but it's not clear to me how to pass additional arguments to the 'hello' function. Here's a piece of code where I want to pass a multiprocessing pipe endpoint to the function. It doesn't work but I think illustrates what I'm trying to do.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import asyncio
import websockets
from multiprocessing import Process, Pipe

async def hello(websocket, path, parent_conn):
    name = await websocket.recv()
    parent_conn.send(name)
   
def f(conn):
    while True:
        if conn.poll():
            stuff = conn.recv()
            print("Stuff in fconn is: {}".format(stuff))
            
if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    p = Process(target=f, args=(child_conn,))
    p.start()
    start_server = websockets.serve(hello,
                            '127.0.0.1', 8765, parent_conn)
    
    asyncio.get_event_loop().run_until_complete(start_server)
    asyncio.get_event_loop().run_forever()
@cjerdonek
Copy link
Collaborator

I'm going off memory, but I'm pretty sure you can accomplish the same end goal by subclassing WebSocketServerProtocol and adding custom instance attributes. You might also want to look at the following issue, where I suggest that another approach should be possible (namely subclassing WebSocketServer, which would be more natural in certain circumstances): #230

@aaugustin
Copy link
Member

aaugustin commented Sep 20, 2017

Does this work?

import functools
start_server = websockets.serve(
    functools.partial(hello, parent_conn=parent_conn),
    '127.0.0.1', 8765)

@chmedly
Copy link
Author

chmedly commented Sep 21, 2017

to aaugustin:
Why yes it does!
Hmm, I need to read the partial docs again. It's like magic...
btw I put the parent_conn at the end of the args like below. But I'm guessing it might not matter?

async def hello(websocket, path, parent_conn):

Can you add this to the getting started section? It was one of the first questions I had and I went through all of the closed "issues" looking for clues about this.

@chmedly
Copy link
Author

chmedly commented Sep 21, 2017

Nope. It does matter where I put the argument. Putting it ahead of websocket or even in between give me this error.

TypeError: hello() got multiple values for argument 'parent_conn'

@aaugustin
Copy link
Member

websockets always passes 2 positional arguments to hello: websocket and path.

partial can add:

  • positional arguments at the beginning of the list of positional arguments: you can use this by defining hello(parent_conn, websocket, parent) and then passing functools.partial(parent_conn) to serve
  • keyword arguments: this is what you did above, in that case the arguments need to be after websocket and parent in the definition of hello, else these arguments don't end up in the right locations.

I don't think this is hello-world material, however it's worth adding to the docs.

@JDeuce
Copy link

JDeuce commented Dec 30, 2021

Looks like these docs added in 050a6ae eventually got removed in latest somehow.

Also there's an issue with them. The path argument was deprecated and some magic was added here: https://github.com/aaugustin/websockets/blob/668f320/src/websockets/legacy/server.py#L1123

When attempting to use a functools.partial with a simple 2 argument handler such as

async def handler(websocket, my_extra_argument)

...

websockets.serve(functools.partial(handler, my_extra_argument=...)

It will pass through that block and generate errors such as handler() got multiple values for argument 'my_extra_argument'

The workaround for now is to avoid getting caught by that deprecation block which checks if your functions expects 2 arguments, by simply adding a third dummy argument

async def handler(websocket, my_extra_argument, my_dummy_argument=None)

Maybe @aaugustin should reconsider the deprecation here for cases like this?

@aaugustin
Copy link
Member

I think this is the same as #1095.

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

No branches or pull requests

4 participants