Event autoregister (#2140)
* Add event autoregistration * Setup tests * Cleanup IDE added imports * Remove unused imports
This commit is contained in:
		
							
								
								
									
										14
									
								
								sanic/app.py
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								sanic/app.py
									
									
									
									
									
								
							| @@ -382,11 +382,19 @@ class Sanic(BaseSanic): | ||||
|             condition=condition, | ||||
|         ) | ||||
|  | ||||
|     def event(self, event: str, timeout: Optional[Union[int, float]] = None): | ||||
|     async def event( | ||||
|         self, event: str, timeout: Optional[Union[int, float]] = None | ||||
|     ): | ||||
|         signal = self.signal_router.name_index.get(event) | ||||
|         if not signal: | ||||
|             raise NotFound("Could not find signal %s" % event) | ||||
|         return wait_for(signal.ctx.event.wait(), timeout=timeout) | ||||
|             if self.config.EVENT_AUTOREGISTER: | ||||
|                 self.signal_router.reset() | ||||
|                 self.add_signal(None, event) | ||||
|                 signal = self.signal_router.name_index.get(event) | ||||
|                 self.signal_router.finalize() | ||||
|             else: | ||||
|                 raise NotFound("Could not find signal %s" % event) | ||||
|         return await wait_for(signal.ctx.event.wait(), timeout=timeout) | ||||
|  | ||||
|     def enable_websocket(self, enable=True): | ||||
|         """Enable or disable the support for websocket. | ||||
|   | ||||
| @@ -16,28 +16,29 @@ BASE_LOGO = """ | ||||
| """ | ||||
|  | ||||
| DEFAULT_CONFIG = { | ||||
|     "REQUEST_MAX_SIZE": 100000000,  # 100 megabytes | ||||
|     "ACCESS_LOG": True, | ||||
|     "EVENT_AUTOREGISTER": False, | ||||
|     "FALLBACK_ERROR_FORMAT": "html", | ||||
|     "FORWARDED_FOR_HEADER": "X-Forwarded-For", | ||||
|     "FORWARDED_SECRET": None, | ||||
|     "GRACEFUL_SHUTDOWN_TIMEOUT": 15.0,  # 15 sec | ||||
|     "KEEP_ALIVE_TIMEOUT": 5,  # 5 seconds | ||||
|     "KEEP_ALIVE": True, | ||||
|     "PROXIES_COUNT": None, | ||||
|     "REAL_IP_HEADER": None, | ||||
|     "REGISTER": True, | ||||
|     "REQUEST_BUFFER_QUEUE_SIZE": 100, | ||||
|     "REQUEST_BUFFER_SIZE": 65536,  # 64 KiB | ||||
|     "REQUEST_ID_HEADER": "X-Request-ID", | ||||
|     "REQUEST_MAX_SIZE": 100000000,  # 100 megabytes | ||||
|     "REQUEST_TIMEOUT": 60,  # 60 seconds | ||||
|     "RESPONSE_TIMEOUT": 60,  # 60 seconds | ||||
|     "KEEP_ALIVE": True, | ||||
|     "KEEP_ALIVE_TIMEOUT": 5,  # 5 seconds | ||||
|     "WEBSOCKET_MAX_SIZE": 2 ** 20,  # 1 megabyte | ||||
|     "WEBSOCKET_MAX_QUEUE": 32, | ||||
|     "WEBSOCKET_MAX_SIZE": 2 ** 20,  # 1 megabyte | ||||
|     "WEBSOCKET_PING_INTERVAL": 20, | ||||
|     "WEBSOCKET_PING_TIMEOUT": 20, | ||||
|     "WEBSOCKET_READ_LIMIT": 2 ** 16, | ||||
|     "WEBSOCKET_WRITE_LIMIT": 2 ** 16, | ||||
|     "WEBSOCKET_PING_TIMEOUT": 20, | ||||
|     "WEBSOCKET_PING_INTERVAL": 20, | ||||
|     "GRACEFUL_SHUTDOWN_TIMEOUT": 15.0,  # 15 sec | ||||
|     "ACCESS_LOG": True, | ||||
|     "FORWARDED_SECRET": None, | ||||
|     "REAL_IP_HEADER": None, | ||||
|     "PROXIES_COUNT": None, | ||||
|     "FORWARDED_FOR_HEADER": "X-Forwarded-For", | ||||
|     "REQUEST_ID_HEADER": "X-Request-ID", | ||||
|     "FALLBACK_ERROR_FORMAT": "html", | ||||
|     "REGISTER": True, | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| from typing import Any, Callable, Dict, Set | ||||
| from typing import Any, Callable, Dict, Optional, Set | ||||
|  | ||||
| from sanic.models.futures import FutureSignal | ||||
| from sanic.models.handler_types import SignalHandler | ||||
| @@ -60,10 +60,16 @@ class SignalMixin: | ||||
|  | ||||
|     def add_signal( | ||||
|         self, | ||||
|         handler, | ||||
|         handler: Optional[Callable[..., Any]], | ||||
|         event: str, | ||||
|         condition: Dict[str, Any] = None, | ||||
|     ): | ||||
|         if not handler: | ||||
|  | ||||
|             async def noop(): | ||||
|                 ... | ||||
|  | ||||
|             handler = noop | ||||
|         self.signal(event=event, condition=condition)(handler) | ||||
|         return handler | ||||
|  | ||||
|   | ||||
| @@ -257,17 +257,60 @@ def test_bad_finalize(app): | ||||
|     assert counter == 0 | ||||
|  | ||||
|  | ||||
| def test_event_not_exist(app): | ||||
| @pytest.mark.asyncio | ||||
| async def test_event_not_exist(app): | ||||
|     with pytest.raises(NotFound, match="Could not find signal does.not.exist"): | ||||
|         app.event("does.not.exist") | ||||
|         await app.event("does.not.exist") | ||||
|  | ||||
|  | ||||
| def test_event_not_exist_on_bp(app): | ||||
| @pytest.mark.asyncio | ||||
| async def test_event_not_exist_on_bp(app): | ||||
|     bp = Blueprint("bp") | ||||
|     app.blueprint(bp) | ||||
|  | ||||
|     with pytest.raises(NotFound, match="Could not find signal does.not.exist"): | ||||
|         bp.event("does.not.exist") | ||||
|         await bp.event("does.not.exist") | ||||
|  | ||||
|  | ||||
| @pytest.mark.asyncio | ||||
| async def test_event_not_exist_with_autoregister(app): | ||||
|     app.config.EVENT_AUTOREGISTER = True | ||||
|     try: | ||||
|         await app.event("does.not.exist", timeout=0.1) | ||||
|     except asyncio.TimeoutError: | ||||
|         ... | ||||
|  | ||||
|  | ||||
| @pytest.mark.asyncio | ||||
| async def test_dispatch_signal_triggers_non_exist_event_with_autoregister(app): | ||||
|     @app.signal("some.stand.in") | ||||
|     async def signal_handler(): | ||||
|         ... | ||||
|  | ||||
|     app.config.EVENT_AUTOREGISTER = True | ||||
|     app_counter = 0 | ||||
|     app.signal_router.finalize() | ||||
|  | ||||
|     async def do_wait(): | ||||
|         nonlocal app_counter | ||||
|         await app.event("foo.bar.baz") | ||||
|         app_counter += 1 | ||||
|  | ||||
|     fut = asyncio.ensure_future(do_wait()) | ||||
|     await app.dispatch("foo.bar.baz") | ||||
|     await fut | ||||
|  | ||||
|     assert app_counter == 1 | ||||
|  | ||||
|  | ||||
| @pytest.mark.asyncio | ||||
| async def test_dispatch_not_exist(app): | ||||
|     @app.signal("do.something.start") | ||||
|     async def signal_handler(): | ||||
|         ... | ||||
|  | ||||
|     app.signal_router.finalize() | ||||
|     await app.dispatch("does.not.exist") | ||||
|  | ||||
|  | ||||
| def test_event_on_bp_not_registered(): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Adam Hopkins
					Adam Hopkins