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, |             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) |         signal = self.signal_router.name_index.get(event) | ||||||
|         if not signal: |         if not signal: | ||||||
|             raise NotFound("Could not find signal %s" % event) |             if self.config.EVENT_AUTOREGISTER: | ||||||
|         return wait_for(signal.ctx.event.wait(), timeout=timeout) |                 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): |     def enable_websocket(self, enable=True): | ||||||
|         """Enable or disable the support for websocket. |         """Enable or disable the support for websocket. | ||||||
|   | |||||||
| @@ -16,28 +16,29 @@ BASE_LOGO = """ | |||||||
| """ | """ | ||||||
|  |  | ||||||
| DEFAULT_CONFIG = { | 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_QUEUE_SIZE": 100, | ||||||
|     "REQUEST_BUFFER_SIZE": 65536,  # 64 KiB |     "REQUEST_BUFFER_SIZE": 65536,  # 64 KiB | ||||||
|  |     "REQUEST_ID_HEADER": "X-Request-ID", | ||||||
|  |     "REQUEST_MAX_SIZE": 100000000,  # 100 megabytes | ||||||
|     "REQUEST_TIMEOUT": 60,  # 60 seconds |     "REQUEST_TIMEOUT": 60,  # 60 seconds | ||||||
|     "RESPONSE_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_QUEUE": 32, | ||||||
|  |     "WEBSOCKET_MAX_SIZE": 2 ** 20,  # 1 megabyte | ||||||
|  |     "WEBSOCKET_PING_INTERVAL": 20, | ||||||
|  |     "WEBSOCKET_PING_TIMEOUT": 20, | ||||||
|     "WEBSOCKET_READ_LIMIT": 2 ** 16, |     "WEBSOCKET_READ_LIMIT": 2 ** 16, | ||||||
|     "WEBSOCKET_WRITE_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.futures import FutureSignal | ||||||
| from sanic.models.handler_types import SignalHandler | from sanic.models.handler_types import SignalHandler | ||||||
| @@ -60,10 +60,16 @@ class SignalMixin: | |||||||
|  |  | ||||||
|     def add_signal( |     def add_signal( | ||||||
|         self, |         self, | ||||||
|         handler, |         handler: Optional[Callable[..., Any]], | ||||||
|         event: str, |         event: str, | ||||||
|         condition: Dict[str, Any] = None, |         condition: Dict[str, Any] = None, | ||||||
|     ): |     ): | ||||||
|  |         if not handler: | ||||||
|  |  | ||||||
|  |             async def noop(): | ||||||
|  |                 ... | ||||||
|  |  | ||||||
|  |             handler = noop | ||||||
|         self.signal(event=event, condition=condition)(handler) |         self.signal(event=event, condition=condition)(handler) | ||||||
|         return handler |         return handler | ||||||
|  |  | ||||||
|   | |||||||
| @@ -257,17 +257,60 @@ def test_bad_finalize(app): | |||||||
|     assert counter == 0 |     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"): |     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") |     bp = Blueprint("bp") | ||||||
|     app.blueprint(bp) |     app.blueprint(bp) | ||||||
|  |  | ||||||
|     with pytest.raises(NotFound, match="Could not find signal does.not.exist"): |     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(): | def test_event_on_bp_not_registered(): | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Adam Hopkins
					Adam Hopkins