Issue 1:
Front End

From the same page, if Connect button clicked multiple times, multiple WebSocket requests landing in the backend.

<!DOCTYPE html>
<html>
<head>
<title>Chat</title>
</head>
<body>
<h1>WebSocket Chat</h1>
<form action="" onsubmit="sendMessage(event)">
<label>Token: <input type="text" id="token" autocomplete="off" value="some-key-token"/></label>
<button onclick="connect(event)">Connect</button>
<hr>
<!-- <label>Message: <input type="text" id="messageText" autocomplete="off"/></label> -->
<!-- <button>Send</button> -->
</form>
<ul id='messages'>
</ul>
<script>
var ws = null;
function connect(event) {
var token = document.getElementById("token")
ws = new WebSocket("ws://localhost:6003/ws/v1/inbox/test?token=" + token.value);

ws.onopen = function () {
console.log('socket opened');
};
ws.onmessage = function(event) {
var messages = document.getElementById('messages')
var message = document.createElement('li')
var content = document.createTextNode(event.data)
<!-- var data = document.createTextNode(event.data) -->
<!-- var content = "message:" + data.message -->
message.appendChild(content)
messages.appendChild(message)
};

ws.onclose = function(e) {
console.log('socket closed from server');
}

ws.onerror = function(err) {
console.error(err)
};

event.preventDefault()
}
function sendMessage(event) {
var input = document.getElementById("messageText")
ws.send(input.value)
input.value = ''
event.preventDefault()
}
</script>
</body>
</html>

Back End

Here we are adding incoming WebSockets to a list. Here we want to compare incoming WebSockets considering the request source. The important thing a user should be able to connect from different devices, browsers, or browser tabs.

from fastapi import FastAPI, Request, Depends, WebSocket, WebSocketDisconnect, Query

app = FastAPI()

class WebSocketConnectionModel:
user_id: int
account_id: int
connection_date_time_utc: datetime
socket: WebSocket

class SocketManager:
def __init__(self):
self.connections: List[WebSocketConnectionModel] = []

def len(self):
return len(self.connections)

def connect(self, account_id: int, user_id: int, websocket: WebSocket):
connection = WebSocketConnectionModel()
connection.account_id = account_id
connection.user_id = user_id
connection.socket = websocket
connection.connection_date_time_utc = datetime.utcnow()
self.connections.append(connection)
return connection

def disconnect(self, item: WebSocketConnectionModel):
self.connections.remove(item)

manager = SocketManager()

async def websocket_test(websocket: WebSocket, access_token: str = Query(..., alias="token")):
user = get_current_user_from_query_token(access_token)
await websocket.accept()
#add connection to a list
connection = manager.connect(user.account_id, user.id, websocket)
try:
while True:
data = await websocket.receive_json()
except WebSocketDisconnect:
manager.disconnect(connection)

app.add_websocket_route("/ws/v1/inbox/test", facebook_inbox.websocket_test)

Is there any way to identify incoming WebSocket object and compare with an existing list, to avoid adding duplicates? Is there any unique identifier in WebSocket object?

Issue 2:
First Check

I added a very descriptive title to this issue.

I used the GitHub search to find a similar issue and didn't find it.

I searched the FastAPI documentation, with the integrated search.

I already searched in Google "How to X in FastAPI" and didn't find any information.

I already read and followed all the tutorial in the docs and didn't find an answer.

I already checked if it is not related to FastAPI but to Pydantic.

I already checked if it is not related to FastAPI but to Swagger UI.

I already checked if it is not related to FastAPI but to ReDoc.

Commit to Help

I commit to help with one of those options 👆

Example Code

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles

app = FastAPI()

@app.get("/")
async def root():
return {'message': 'success'}

Description

Attempt to run the file with uvicorn:

(.venv) ➜ hmx1 uvicorn app2:app --reload --port 8002
INFO: Uvicorn running on http://127.0.0.1:8002 (Press CTRL+C to quit)
INFO: Started reloader process [70344] using statreload
Process SpawnProcess-1:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
self.run()
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/uvicorn/subprocess.py", line 61, in subprocess_started
target(sockets=sockets)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/uvicorn/server.py", line 48, in run
loop.run_until_complete(self.serve(sockets=sockets))
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/uvicorn/server.py", line 55, in serve
config.load()
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/uvicorn/config.py", line 308, in load
self.loaded_app = import_from_string(self.app)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/uvicorn/importer.py", line 23, in import_from_string
raise exc from None
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/uvicorn/importer.py", line 20, in import_from_string
module = importlib.import_module(module_str)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
File "<frozen importlib._bootstrap>", line 991, in _find_and_load
File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 783, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "./app2.py", line 2, in <module>
from fastapi.staticfiles import StaticFiles
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/fastapi/staticfiles.py", line 1, in <module>
from starlette.staticfiles import StaticFiles as StaticFiles # noqa
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/starlette/staticfiles.py", line 7, in <module>
from aiofiles.os import stat as aio_stat
ModuleNotFoundError: No module named 'aiofiles'

Operating System

macOS

Operating System Details

(.venv) ➜ hmx1 pip freeze
aiofiles==0.8.0
anyio==3.4.0
asgiref==3.4.1
Chameleon==3.9.1
click==8.0.3
fastapi==0.70.0
fastapi-chameleon==0.1.12
h11==0.12.0
idna==3.3
Jinja2==3.0.3
MarkupSafe==2.0.1
pydantic==1.8.2
sniffio==1.2.0
starlette==0.16.0
typing-extensions==4.0.1
uvicorn==0.15.0

FastAPI Version

0.70.0

Python Version

Python 3.8.7

Additional Context

I'm just trying to follow the tutorial at https://fastapi.tiangolo.com/advanced/templates/.

I can do the import interactively from a python terminal, but it fails when using uvicorn.

Python 3.8.7 (v3.8.7:6503f05dd5, Dec 21 2020, 12:45:15)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from fastapi.staticfiles import StaticFiles
>>>