python-engineio 4.13.4__tar.gz → 4.14.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. python_engineio-4.14.0/PKG-INFO +60 -0
  2. python_engineio-4.14.0/README.md +29 -0
  3. {python_engineio-4.13.4 → python_engineio-4.14.0}/pyproject.toml +6 -3
  4. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/async_client.py +20 -8
  5. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/async_drivers/asgi.py +2 -1
  6. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/client.py +18 -2
  7. python_engineio-4.14.0/src/python_engineio.egg-info/PKG-INFO +60 -0
  8. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/async/test_asgi.py +21 -0
  9. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/async/test_client.py +60 -2
  10. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/async/test_socket.py +19 -0
  11. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/common/test_client.py +49 -2
  12. python_engineio-4.13.4/PKG-INFO +0 -52
  13. python_engineio-4.13.4/README.md +0 -24
  14. python_engineio-4.13.4/src/python_engineio.egg-info/PKG-INFO +0 -52
  15. {python_engineio-4.13.4 → python_engineio-4.14.0}/LICENSE +0 -0
  16. {python_engineio-4.13.4 → python_engineio-4.14.0}/MANIFEST.in +0 -0
  17. {python_engineio-4.13.4 → python_engineio-4.14.0}/docs/_static/README.md +0 -0
  18. {python_engineio-4.13.4 → python_engineio-4.14.0}/setup.cfg +0 -0
  19. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/__init__.py +0 -0
  20. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/async_drivers/__init__.py +0 -0
  21. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/async_drivers/_websocket_wsgi.py +0 -0
  22. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/async_drivers/aiohttp.py +0 -0
  23. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/async_drivers/eventlet.py +0 -0
  24. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/async_drivers/gevent.py +0 -0
  25. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/async_drivers/gevent_uwsgi.py +0 -0
  26. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/async_drivers/sanic.py +0 -0
  27. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/async_drivers/threading.py +0 -0
  28. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/async_drivers/tornado.py +0 -0
  29. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/async_server.py +0 -0
  30. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/async_socket.py +0 -0
  31. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/base_client.py +0 -0
  32. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/base_server.py +0 -0
  33. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/base_socket.py +0 -0
  34. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/exceptions.py +0 -0
  35. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/json.py +0 -0
  36. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/middleware.py +0 -0
  37. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/packet.py +0 -0
  38. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/payload.py +0 -0
  39. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/server.py +0 -0
  40. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/socket.py +0 -0
  41. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/engineio/static_files.py +0 -0
  42. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/python_engineio.egg-info/SOURCES.txt +0 -0
  43. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/python_engineio.egg-info/dependency_links.txt +0 -0
  44. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/python_engineio.egg-info/not-zip-safe +0 -0
  45. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/python_engineio.egg-info/requires.txt +0 -0
  46. {python_engineio-4.13.4 → python_engineio-4.14.0}/src/python_engineio.egg-info/top_level.txt +0 -0
  47. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/async/__init__.py +0 -0
  48. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/async/index.html +0 -0
  49. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/async/test_aiohttp.py +0 -0
  50. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/async/test_sanic.py +0 -0
  51. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/async/test_server.py +0 -0
  52. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/async/test_tornado.py +0 -0
  53. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/common/__init__.py +0 -0
  54. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/common/index.html +0 -0
  55. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/common/test_middleware.py +0 -0
  56. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/common/test_packet.py +0 -0
  57. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/common/test_payload.py +0 -0
  58. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/common/test_server.py +0 -0
  59. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/common/test_socket.py +0 -0
  60. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/performance/README.md +0 -0
  61. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/performance/binary_b64_packet.py +0 -0
  62. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/performance/binary_packet.py +0 -0
  63. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/performance/json_packet.py +0 -0
  64. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/performance/payload.py +0 -0
  65. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/performance/run.sh +0 -0
  66. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/performance/server_receive.py +0 -0
  67. {python_engineio-4.13.4 → python_engineio-4.14.0}/tests/performance/text_packet.py +0 -0
  68. {python_engineio-4.13.4 → python_engineio-4.14.0}/tox.ini +0 -0
@@ -0,0 +1,60 @@
1
+ Metadata-Version: 2.4
2
+ Name: python-engineio
3
+ Version: 4.14.0
4
+ Summary: Engine.IO server and client for Python
5
+ Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>
6
+ License: MIT
7
+ Project-URL: homepage, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio
8
+ Project-URL: documentation, https://python-engineio.readthedocs.io/
9
+ Project-URL: repository, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio
10
+ Project-URL: issues, https://github.com/miguelgrinberg/python-engineio/issues
11
+ Project-URL: changelog, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/src/branch/main/CHANGES.md
12
+ Classifier: Environment :: Web Environment
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Operating System :: OS Independent
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: simple-websocket>=0.10.0
20
+ Provides-Extra: client
21
+ Requires-Dist: requests>=2.21.0; extra == "client"
22
+ Requires-Dist: websocket-client>=0.54.0; extra == "client"
23
+ Provides-Extra: asyncio-client
24
+ Requires-Dist: aiohttp>=3.11; extra == "asyncio-client"
25
+ Provides-Extra: dev
26
+ Requires-Dist: tox; extra == "dev"
27
+ Provides-Extra: docs
28
+ Requires-Dist: sphinx; extra == "docs"
29
+ Requires-Dist: furo; extra == "docs"
30
+ Dynamic: license-file
31
+
32
+ python-engineio
33
+ ===============
34
+
35
+ [![tests](https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/badges/workflows/tests.yml/badge.svg)](https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/actions)
36
+
37
+ Python implementation of the `Engine.IO` realtime client and server.
38
+
39
+ Resources
40
+ ---------
41
+
42
+ - [git](https://code.miguelgrinberg.com/miguelgrinberg/python-engineio)
43
+ - [Change Log](https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/src/branch/main/CHANGES.md)
44
+ - [Documentation](https://python-engineio.readthedocs.io/)
45
+ - [PyPI](https://pypi.python.org/pypi/python-engineio)
46
+ - [Contributor's guide](CONTRIBUTING.md)
47
+ - [Security policy](SECURITY.md)
48
+
49
+ Sponsor this project
50
+ --------------------
51
+
52
+ This project relies on contributions from its users. If you benefit from it please consider making a single or ongoing monetary contribution in one of the following platforms:
53
+
54
+ - [Github Sponsors](https://github.com/sponsors/miguelgrinberg)
55
+ - [Patreon](https://patreon.com/miguelgrinberg)
56
+ - [Buy me a Coffee](https://buymeacoffee.com/miguelgrinberg)
57
+ - [thanks.dev](https://thanks.dev/u/gh/miguelgrinberg)
58
+ - [PayPal](https://paypal.me/miguelgrinberg)
59
+
60
+ Thank you!
@@ -0,0 +1,29 @@
1
+ python-engineio
2
+ ===============
3
+
4
+ [![tests](https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/badges/workflows/tests.yml/badge.svg)](https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/actions)
5
+
6
+ Python implementation of the `Engine.IO` realtime client and server.
7
+
8
+ Resources
9
+ ---------
10
+
11
+ - [git](https://code.miguelgrinberg.com/miguelgrinberg/python-engineio)
12
+ - [Change Log](https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/src/branch/main/CHANGES.md)
13
+ - [Documentation](https://python-engineio.readthedocs.io/)
14
+ - [PyPI](https://pypi.python.org/pypi/python-engineio)
15
+ - [Contributor's guide](CONTRIBUTING.md)
16
+ - [Security policy](SECURITY.md)
17
+
18
+ Sponsor this project
19
+ --------------------
20
+
21
+ This project relies on contributions from its users. If you benefit from it please consider making a single or ongoing monetary contribution in one of the following platforms:
22
+
23
+ - [Github Sponsors](https://github.com/sponsors/miguelgrinberg)
24
+ - [Patreon](https://patreon.com/miguelgrinberg)
25
+ - [Buy me a Coffee](https://buymeacoffee.com/miguelgrinberg)
26
+ - [thanks.dev](https://thanks.dev/u/gh/miguelgrinberg)
27
+ - [PayPal](https://paypal.me/miguelgrinberg)
28
+
29
+ Thank you!
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-engineio"
3
- version = "4.13.4"
3
+ version = "4.14.0"
4
4
  license = {text = "MIT"}
5
5
  authors = [{name = "Miguel Grinberg", email = "miguel.grinberg@gmail.com"}]
6
6
  description = "Engine.IO server and client for Python"
@@ -18,8 +18,11 @@ file = "README.md"
18
18
  content-type = "text/markdown"
19
19
 
20
20
  [project.urls]
21
- Homepage = "https://github.com/miguelgrinberg/python-engineio"
22
- "Bug Tracker" = "https://github.com/miguelgrinberg/python-engineio/issues"
21
+ homepage = "https://code.miguelgrinberg.com/miguelgrinberg/python-engineio"
22
+ documentation = "https://python-engineio.readthedocs.io/"
23
+ repository = "https://code.miguelgrinberg.com/miguelgrinberg/python-engineio"
24
+ issues = "https://github.com/miguelgrinberg/python-engineio/issues"
25
+ changelog = "https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/src/branch/main/CHANGES.md"
23
26
 
24
27
  [project.optional-dependencies]
25
28
  client = [
@@ -284,7 +284,13 @@ class AsyncClient(base_client.BaseClient):
284
284
 
285
285
  self.state = 'connected'
286
286
  base_client.connected_clients.append(self)
287
- await self._trigger_event('connect', run_async=False)
287
+ try:
288
+ await self._trigger_event('connect', run_async=False)
289
+ except Exception as exc:
290
+ base_client.connected_clients.remove(self)
291
+ await self._reset()
292
+ raise exceptions.ConnectionError(
293
+ 'Connect handler failed: ' + str(exc))
288
294
 
289
295
  for pkt in p.packets[1:]:
290
296
  await self._receive_packet(pkt)
@@ -406,7 +412,13 @@ class AsyncClient(base_client.BaseClient):
406
412
 
407
413
  self.state = 'connected'
408
414
  base_client.connected_clients.append(self)
409
- await self._trigger_event('connect', run_async=False)
415
+ try:
416
+ await self._trigger_event('connect', run_async=False)
417
+ except Exception as exc:
418
+ base_client.connected_clients.remove(self)
419
+ await self._reset()
420
+ raise exceptions.ConnectionError(
421
+ 'Connect handler failed: ' + str(exc))
410
422
 
411
423
  self.ws = ws
412
424
  self.write_loop_task = self.start_background_task(self._write_loop)
@@ -495,9 +507,9 @@ class AsyncClient(base_client.BaseClient):
495
507
  except:
496
508
  self.logger.exception(event + ' async handler error')
497
509
  if event == 'connect':
498
- # if connect handler raised error we reject the
499
- # connection
500
- return False
510
+ # for the connection event we reraise the exception
511
+ # to stop the connection from completing
512
+ raise
501
513
  else:
502
514
  if run_async:
503
515
  async def async_handler():
@@ -522,9 +534,9 @@ class AsyncClient(base_client.BaseClient):
522
534
  except:
523
535
  self.logger.exception(event + ' handler error')
524
536
  if event == 'connect':
525
- # if connect handler raised error we reject the
526
- # connection
527
- return False
537
+ # for the connection event we reraise the exception
538
+ # to stop the connection from completing
539
+ raise
528
540
  return ret
529
541
 
530
542
  async def _read_loop_polling(self):
@@ -147,7 +147,8 @@ async def translate_request(scope, receive, send):
147
147
  while self.event.get('more_body'):
148
148
  self.event = await receive()
149
149
  if self.event['type'] == 'http.request':
150
- self.payload += self.event.get('body') or b''
150
+ if length is None or len(self.payload) < length:
151
+ self.payload += self.event.get('body') or b''
151
152
  if length is None:
152
153
  r = self.payload
153
154
  self.payload = b''
@@ -229,7 +229,13 @@ class Client(base_client.BaseClient):
229
229
 
230
230
  self.state = 'connected'
231
231
  base_client.connected_clients.append(self)
232
- self._trigger_event('connect', run_async=False)
232
+ try:
233
+ self._trigger_event('connect', run_async=False, reraise=True)
234
+ except Exception as exc:
235
+ base_client.connected_clients.remove(self)
236
+ self._reset()
237
+ raise exceptions.ConnectionError(
238
+ 'Connect handler failed: ' + str(exc))
233
239
 
234
240
  for pkt in p.packets[1:]:
235
241
  self._receive_packet(pkt)
@@ -403,7 +409,13 @@ class Client(base_client.BaseClient):
403
409
 
404
410
  self.state = 'connected'
405
411
  base_client.connected_clients.append(self)
406
- self._trigger_event('connect', run_async=False)
412
+ try:
413
+ self._trigger_event('connect', run_async=False, reraise=True)
414
+ except Exception as exc:
415
+ base_client.connected_clients.remove(self)
416
+ self._reset()
417
+ raise exceptions.ConnectionError(
418
+ 'Connect handler failed: ' + str(exc))
407
419
  self.ws = ws
408
420
  self.ws.settimeout(self.ping_interval + self.ping_timeout)
409
421
 
@@ -477,6 +489,10 @@ class Client(base_client.BaseClient):
477
489
  raise
478
490
  except:
479
491
  self.logger.exception(event + ' handler error')
492
+ if event == 'connect':
493
+ # for the connection event we reraise the exception
494
+ # to stop the connection from completing
495
+ raise
480
496
 
481
497
  def _read_loop_polling(self):
482
498
  """Read packets by polling the Engine.IO server."""
@@ -0,0 +1,60 @@
1
+ Metadata-Version: 2.4
2
+ Name: python-engineio
3
+ Version: 4.14.0
4
+ Summary: Engine.IO server and client for Python
5
+ Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>
6
+ License: MIT
7
+ Project-URL: homepage, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio
8
+ Project-URL: documentation, https://python-engineio.readthedocs.io/
9
+ Project-URL: repository, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio
10
+ Project-URL: issues, https://github.com/miguelgrinberg/python-engineio/issues
11
+ Project-URL: changelog, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/src/branch/main/CHANGES.md
12
+ Classifier: Environment :: Web Environment
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Operating System :: OS Independent
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: simple-websocket>=0.10.0
20
+ Provides-Extra: client
21
+ Requires-Dist: requests>=2.21.0; extra == "client"
22
+ Requires-Dist: websocket-client>=0.54.0; extra == "client"
23
+ Provides-Extra: asyncio-client
24
+ Requires-Dist: aiohttp>=3.11; extra == "asyncio-client"
25
+ Provides-Extra: dev
26
+ Requires-Dist: tox; extra == "dev"
27
+ Provides-Extra: docs
28
+ Requires-Dist: sphinx; extra == "docs"
29
+ Requires-Dist: furo; extra == "docs"
30
+ Dynamic: license-file
31
+
32
+ python-engineio
33
+ ===============
34
+
35
+ [![tests](https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/badges/workflows/tests.yml/badge.svg)](https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/actions)
36
+
37
+ Python implementation of the `Engine.IO` realtime client and server.
38
+
39
+ Resources
40
+ ---------
41
+
42
+ - [git](https://code.miguelgrinberg.com/miguelgrinberg/python-engineio)
43
+ - [Change Log](https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/src/branch/main/CHANGES.md)
44
+ - [Documentation](https://python-engineio.readthedocs.io/)
45
+ - [PyPI](https://pypi.python.org/pypi/python-engineio)
46
+ - [Contributor's guide](CONTRIBUTING.md)
47
+ - [Security policy](SECURITY.md)
48
+
49
+ Sponsor this project
50
+ --------------------
51
+
52
+ This project relies on contributions from its users. If you benefit from it please consider making a single or ongoing monetary contribution in one of the following platforms:
53
+
54
+ - [Github Sponsors](https://github.com/sponsors/miguelgrinberg)
55
+ - [Patreon](https://patreon.com/miguelgrinberg)
56
+ - [Buy me a Coffee](https://buymeacoffee.com/miguelgrinberg)
57
+ - [thanks.dev](https://thanks.dev/u/gh/miguelgrinberg)
58
+ - [PayPal](https://paypal.me/miguelgrinberg)
59
+
60
+ Thank you!
@@ -441,6 +441,27 @@ class TestAsgi:
441
441
  body = await environ['wsgi.input'].read()
442
442
  assert body == b'hello world'
443
443
 
444
+ async def test_translate_request_read_zero(self):
445
+ receive = mock.AsyncMock(
446
+ return_value={'type': 'http.request', 'body': b'hello world'}
447
+ )
448
+ send = mock.AsyncMock()
449
+ environ = await async_asgi.translate_request(
450
+ {
451
+ 'type': 'http',
452
+ 'method': 'PUT',
453
+ 'headers': [
454
+ (b'content-type', b'application/json'),
455
+ (b'content-length', b'123'),
456
+ ],
457
+ 'path': '/foo/bar',
458
+ },
459
+ receive,
460
+ send,
461
+ )
462
+ body = await environ['wsgi.input'].read(0)
463
+ assert body == b''
464
+
444
465
  async def test_translate_websocket_request(self):
445
466
  receive = mock.AsyncMock(return_value={'type': 'websocket.connect'})
446
467
  send = mock.AsyncMock()
@@ -105,6 +105,62 @@ class TestAsyncClient:
105
105
  'http://foo', {'Foo': 'Bar'}, 'engine.io'
106
106
  )
107
107
 
108
+ async def test_connect_polling_handler_failure(self):
109
+ c = async_client.AsyncClient()
110
+ c._send_request = mock.AsyncMock()
111
+ c._send_request.return_value.status = 200
112
+ c._send_request.return_value.read = mock.AsyncMock(
113
+ return_value=payload.Payload(
114
+ packets=[
115
+ packet.Packet(
116
+ packet.OPEN,
117
+ {
118
+ 'sid': '123',
119
+ 'upgrades': [],
120
+ 'pingInterval': 1000,
121
+ 'pingTimeout': 2000,
122
+ },
123
+ )
124
+ ]
125
+ ).encode().encode('utf-8')
126
+ )
127
+
128
+ @c.on('connect')
129
+ def connect():
130
+ raise ValueError('Failed on purpose')
131
+
132
+ with pytest.raises(exceptions.ConnectionError,
133
+ match='Connect handler failed: Failed on purpose'):
134
+ await c.connect('http://foo')
135
+
136
+ @mock.patch('engineio.client.time.time', return_value=123.456)
137
+ @mock.patch('engineio.async_client.aiohttp.ClientWSTimeout',
138
+ new=mock_ws_timeout)
139
+ async def test_connect_websocket_handler_failure(self, _time):
140
+ c = async_client.AsyncClient()
141
+ c.http = mock.MagicMock(closed=False)
142
+ c.http.ws_connect = mock.AsyncMock()
143
+ c.http.close = mock.AsyncMock()
144
+ ws = c.http.ws_connect.return_value
145
+ ws.receive = mock.AsyncMock()
146
+ ws.receive.return_value.data = packet.Packet(
147
+ packet.OPEN,
148
+ {
149
+ 'sid': '123',
150
+ 'upgrades': [],
151
+ 'pingInterval': 1000,
152
+ 'pingTimeout': 2000,
153
+ },
154
+ ).encode()
155
+
156
+ @c.on('connect')
157
+ def connect():
158
+ raise ValueError('Failed on purpose')
159
+
160
+ with pytest.raises(exceptions.ConnectionError,
161
+ match='Connect handler failed: Failed on purpose'):
162
+ await c.connect('http://foo', transports='websocket')
163
+
108
164
  async def test_wait(self):
109
165
  c = async_client.AsyncClient()
110
166
  done = []
@@ -918,7 +974,8 @@ class TestAsyncClient:
918
974
  c = async_client.AsyncClient()
919
975
  c.on('connect', handler=connect_handler)
920
976
  c.on('message', handler=foo_handler)
921
- assert not await c._trigger_event('connect', '123')
977
+ with pytest.raises(ZeroDivisionError):
978
+ await c._trigger_event('connect', '123')
922
979
  assert await c._trigger_event('message', 'bar') is None
923
980
 
924
981
  async def test_trigger_event_coroutine_error(self):
@@ -931,7 +988,8 @@ class TestAsyncClient:
931
988
  c = async_client.AsyncClient()
932
989
  c.on('connect', handler=connect_handler)
933
990
  c.on('message', handler=foo_handler)
934
- assert not await c._trigger_event('connect', '123')
991
+ with pytest.raises(ZeroDivisionError):
992
+ await c._trigger_event('connect', '123')
935
993
  assert await c._trigger_event('message', 'bar') is None
936
994
 
937
995
  async def test_trigger_event_function_async(self):
@@ -209,6 +209,8 @@ class TestSocket:
209
209
  }
210
210
  await s.handle_post_request(environ)
211
211
  assert s.receive.await_count == 2
212
+ assert s.receive.call_args_list[0][0][0].data == 'hello'
213
+ assert s.receive.call_args_list[1][0][0].data == 'bye'
212
214
 
213
215
  async def test_polling_write_too_large(self):
214
216
  mock_server = self._get_mock_server()
@@ -227,6 +229,23 @@ class TestSocket:
227
229
  with pytest.raises(exceptions.ContentTooLongError):
228
230
  await s.handle_post_request(environ)
229
231
 
232
+ async def test_polling_write_without_content_length(self):
233
+ mock_server = self._get_mock_server()
234
+ pkt1 = packet.Packet(packet.MESSAGE, data='hello')
235
+ pkt2 = packet.Packet(packet.MESSAGE, data='bye')
236
+ p = payload.Payload(packets=[pkt1, pkt2]).encode().encode('utf-8')
237
+ s = async_socket.AsyncSocket(mock_server, 'foo')
238
+ s.receive = mock.AsyncMock()
239
+ environ = {
240
+ 'REQUEST_METHOD': 'POST',
241
+ 'QUERY_STRING': 'sid=foo',
242
+ 'wsgi.input': self._get_read_mock_coro(p),
243
+ }
244
+ await s.handle_post_request(environ)
245
+ assert s.receive.await_count == 2
246
+ assert environ['wsgi.input'].read.call_count == 1
247
+ assert environ['wsgi.input'].read.call_args[0] == (0,)
248
+
230
249
  async def test_upgrade_handshake(self):
231
250
  mock_server = self._get_mock_server()
232
251
  s = async_socket.AsyncSocket(mock_server, 'foo')
@@ -169,6 +169,53 @@ class TestClient:
169
169
  'http://foo', {'Foo': 'Bar'}, 'engine.io'
170
170
  )
171
171
 
172
+ @mock.patch('engineio.client.Client._send_request')
173
+ def test_connect_polling_handler_failure(self, _send_request):
174
+ _send_request.return_value.status_code = 200
175
+ _send_request.return_value.content = payload.Payload(
176
+ packets=[
177
+ packet.Packet(
178
+ packet.OPEN,
179
+ {
180
+ 'sid': '123',
181
+ 'upgrades': [],
182
+ 'pingInterval': 1000,
183
+ 'pingTimeout': 2000,
184
+ },
185
+ )
186
+ ]
187
+ ).encode().encode('utf-8')
188
+ c = client.Client()
189
+
190
+ @c.on('connect')
191
+ def connect():
192
+ raise ValueError('Failed on purpose')
193
+
194
+ with pytest.raises(exceptions.ConnectionError,
195
+ match='Connect handler failed: Failed on purpose'):
196
+ c.connect('http://foo')
197
+
198
+ @mock.patch('engineio.client.websocket.create_connection')
199
+ def test_connect_websocket_handler_failure(self, create_connection):
200
+ create_connection.return_value.recv.return_value = packet.Packet(
201
+ packet.OPEN,
202
+ {
203
+ 'sid': '123',
204
+ 'upgrades': [],
205
+ 'pingInterval': 1000,
206
+ 'pingTimeout': 2000,
207
+ },
208
+ ).encode()
209
+ c = client.Client()
210
+
211
+ @c.on('connect')
212
+ def connect():
213
+ raise ValueError('Failed on purpose')
214
+
215
+ with pytest.raises(exceptions.ConnectionError,
216
+ match='Connect handler failed: Failed on purpose'):
217
+ c.connect('http://foo', transports='websocket')
218
+
172
219
  def test_wait(self):
173
220
  c = client.Client()
174
221
  c.read_loop_task = mock.MagicMock()
@@ -1281,8 +1328,8 @@ class TestClient:
1281
1328
  def bar(data):
1282
1329
  return 1 / 0
1283
1330
 
1284
- r = c._trigger_event('connect', run_async=False)
1285
- assert r is None
1331
+ with pytest.raises(ZeroDivisionError):
1332
+ r = c._trigger_event('connect', run_async=False)
1286
1333
  r = c._trigger_event('message', 123, run_async=False)
1287
1334
  assert r is None
1288
1335
 
@@ -1,52 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: python-engineio
3
- Version: 4.13.4
4
- Summary: Engine.IO server and client for Python
5
- Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>
6
- License: MIT
7
- Project-URL: Homepage, https://github.com/miguelgrinberg/python-engineio
8
- Project-URL: Bug Tracker, https://github.com/miguelgrinberg/python-engineio/issues
9
- Classifier: Environment :: Web Environment
10
- Classifier: Intended Audience :: Developers
11
- Classifier: Programming Language :: Python :: 3
12
- Classifier: Operating System :: OS Independent
13
- Requires-Python: >=3.8
14
- Description-Content-Type: text/markdown
15
- License-File: LICENSE
16
- Requires-Dist: simple-websocket>=0.10.0
17
- Provides-Extra: client
18
- Requires-Dist: requests>=2.21.0; extra == "client"
19
- Requires-Dist: websocket-client>=0.54.0; extra == "client"
20
- Provides-Extra: asyncio-client
21
- Requires-Dist: aiohttp>=3.11; extra == "asyncio-client"
22
- Provides-Extra: dev
23
- Requires-Dist: tox; extra == "dev"
24
- Provides-Extra: docs
25
- Requires-Dist: sphinx; extra == "docs"
26
- Requires-Dist: furo; extra == "docs"
27
- Dynamic: license-file
28
-
29
- python-engineio
30
- ===============
31
-
32
- [![Build status](https://github.com/miguelgrinberg/python-engineio/workflows/build/badge.svg)](https://github.com/miguelgrinberg/python-engineio/actions) [![codecov](https://codecov.io/gh/miguelgrinberg/python-engineio/branch/main/graph/badge.svg)](https://codecov.io/gh/miguelgrinberg/python-engineio)
33
-
34
- Python implementation of the `Engine.IO` realtime client and server.
35
-
36
- Sponsors
37
- --------
38
-
39
- The following organizations are funding this project:
40
-
41
- ![Socket.IO](https://images.opencollective.com/socketio/050e5eb/logo/64.png)<br>[Socket.IO](https://socket.io) | [Add your company here!](https://github.com/sponsors/miguelgrinberg)|
42
- -|-
43
-
44
- Many individual sponsors also support this project through small ongoing contributions. Why not [join them](https://github.com/sponsors/miguelgrinberg)?
45
-
46
- Resources
47
- ---------
48
-
49
- - [Documentation](https://python-engineio.readthedocs.io/)
50
- - [PyPI](https://pypi.python.org/pypi/python-engineio)
51
- - [Change Log](https://github.com/miguelgrinberg/python-engineio/blob/main/CHANGES.md)
52
- - Questions? See the [questions](https://stackoverflow.com/questions/tagged/python-socketio) others have asked on Stack Overflow, or [ask](https://stackoverflow.com/questions/ask?tags=python+python-socketio) your own question.
@@ -1,24 +0,0 @@
1
- python-engineio
2
- ===============
3
-
4
- [![Build status](https://github.com/miguelgrinberg/python-engineio/workflows/build/badge.svg)](https://github.com/miguelgrinberg/python-engineio/actions) [![codecov](https://codecov.io/gh/miguelgrinberg/python-engineio/branch/main/graph/badge.svg)](https://codecov.io/gh/miguelgrinberg/python-engineio)
5
-
6
- Python implementation of the `Engine.IO` realtime client and server.
7
-
8
- Sponsors
9
- --------
10
-
11
- The following organizations are funding this project:
12
-
13
- ![Socket.IO](https://images.opencollective.com/socketio/050e5eb/logo/64.png)<br>[Socket.IO](https://socket.io) | [Add your company here!](https://github.com/sponsors/miguelgrinberg)|
14
- -|-
15
-
16
- Many individual sponsors also support this project through small ongoing contributions. Why not [join them](https://github.com/sponsors/miguelgrinberg)?
17
-
18
- Resources
19
- ---------
20
-
21
- - [Documentation](https://python-engineio.readthedocs.io/)
22
- - [PyPI](https://pypi.python.org/pypi/python-engineio)
23
- - [Change Log](https://github.com/miguelgrinberg/python-engineio/blob/main/CHANGES.md)
24
- - Questions? See the [questions](https://stackoverflow.com/questions/tagged/python-socketio) others have asked on Stack Overflow, or [ask](https://stackoverflow.com/questions/ask?tags=python+python-socketio) your own question.
@@ -1,52 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: python-engineio
3
- Version: 4.13.4
4
- Summary: Engine.IO server and client for Python
5
- Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>
6
- License: MIT
7
- Project-URL: Homepage, https://github.com/miguelgrinberg/python-engineio
8
- Project-URL: Bug Tracker, https://github.com/miguelgrinberg/python-engineio/issues
9
- Classifier: Environment :: Web Environment
10
- Classifier: Intended Audience :: Developers
11
- Classifier: Programming Language :: Python :: 3
12
- Classifier: Operating System :: OS Independent
13
- Requires-Python: >=3.8
14
- Description-Content-Type: text/markdown
15
- License-File: LICENSE
16
- Requires-Dist: simple-websocket>=0.10.0
17
- Provides-Extra: client
18
- Requires-Dist: requests>=2.21.0; extra == "client"
19
- Requires-Dist: websocket-client>=0.54.0; extra == "client"
20
- Provides-Extra: asyncio-client
21
- Requires-Dist: aiohttp>=3.11; extra == "asyncio-client"
22
- Provides-Extra: dev
23
- Requires-Dist: tox; extra == "dev"
24
- Provides-Extra: docs
25
- Requires-Dist: sphinx; extra == "docs"
26
- Requires-Dist: furo; extra == "docs"
27
- Dynamic: license-file
28
-
29
- python-engineio
30
- ===============
31
-
32
- [![Build status](https://github.com/miguelgrinberg/python-engineio/workflows/build/badge.svg)](https://github.com/miguelgrinberg/python-engineio/actions) [![codecov](https://codecov.io/gh/miguelgrinberg/python-engineio/branch/main/graph/badge.svg)](https://codecov.io/gh/miguelgrinberg/python-engineio)
33
-
34
- Python implementation of the `Engine.IO` realtime client and server.
35
-
36
- Sponsors
37
- --------
38
-
39
- The following organizations are funding this project:
40
-
41
- ![Socket.IO](https://images.opencollective.com/socketio/050e5eb/logo/64.png)<br>[Socket.IO](https://socket.io) | [Add your company here!](https://github.com/sponsors/miguelgrinberg)|
42
- -|-
43
-
44
- Many individual sponsors also support this project through small ongoing contributions. Why not [join them](https://github.com/sponsors/miguelgrinberg)?
45
-
46
- Resources
47
- ---------
48
-
49
- - [Documentation](https://python-engineio.readthedocs.io/)
50
- - [PyPI](https://pypi.python.org/pypi/python-engineio)
51
- - [Change Log](https://github.com/miguelgrinberg/python-engineio/blob/main/CHANGES.md)
52
- - Questions? See the [questions](https://stackoverflow.com/questions/tagged/python-socketio) others have asked on Stack Overflow, or [ask](https://stackoverflow.com/questions/ask?tags=python+python-socketio) your own question.