Skip to content

Commit

Permalink
Add app.pre_frozen state (#3237)
Browse files Browse the repository at this point in the history
  • Loading branch information
asvetlov authored Sep 4, 2018
1 parent 7a0359f commit 864ef49
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGES/3237.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add ``app.pre_frozen`` state to properly handle startup signals in sub-applications.
30 changes: 22 additions & 8 deletions aiohttp/web_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class Application(MutableMapping):
ATTRS = frozenset([
'logger', '_debug', '_router', '_loop', '_handler_args',
'_middlewares', '_middlewares_handlers', '_run_middlewares',
'_state', '_frozen', '_subapps',
'_state', '_frozen', '_pre_frozen', '_subapps',
'_on_response_prepare', '_on_startup', '_on_shutdown',
'_on_cleanup', '_client_max_size', '_cleanup_ctx'])

Expand Down Expand Up @@ -68,6 +68,7 @@ def __init__(self, *,
self._run_middlewares = None # initialized on freezing
self._state = {}
self._frozen = False
self._pre_frozen = False
self._subapps = []

self._on_response_prepare = Signal(self) # type: _RespPrepareSignal
Expand Down Expand Up @@ -146,14 +147,14 @@ def _set_loop(self, loop):
subapp._set_loop(loop)

@property
def frozen(self) -> bool:
return self._frozen
def pre_frozen(self) -> bool:
return self._pre_frozen

def freeze(self) -> None:
if self._frozen:
def pre_freeze(self) -> None:
if self._pre_frozen:
return

self._frozen = True
self._pre_frozen = True
self._middlewares.freeze()
self._router.freeze()
self._on_response_prepare.freeze()
Expand All @@ -171,10 +172,23 @@ def freeze(self) -> None:
self._run_middlewares = True if self.middlewares else False

for subapp in self._subapps:
subapp.freeze()
subapp.pre_freeze()
self._run_middlewares =\
self._run_middlewares or subapp._run_middlewares

@property
def frozen(self) -> bool:
return self._frozen

def freeze(self) -> None:
if self._frozen:
return

self.pre_freeze()
self._frozen = True
for subapp in self._subapps:
subapp.freeze()

@property
def debug(self) -> bool:
return self._debug
Expand Down Expand Up @@ -208,7 +222,7 @@ def add_subapp(self, prefix: str, subapp: 'Application'):
self.router.register_resource(resource)
self._reg_subapp_signals(subapp)
self._subapps.append(subapp)
subapp.freeze()
subapp.pre_freeze()
if self._loop is not None:
subapp._set_loop(self._loop)
return resource
Expand Down
80 changes: 78 additions & 2 deletions tests/test_web_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,12 +248,13 @@ async def middleware(request, handler):
assert root._run_middlewares is True


def test_subapp_frozen_after_adding():
def test_subapp_pre_frozen_after_adding():
app = web.Application()
subapp = web.Application()

app.add_subapp('/prefix', subapp)
assert subapp.frozen
assert subapp.pre_frozen
assert not subapp.frozen


@pytest.mark.skipif(not PY_36,
Expand Down Expand Up @@ -455,3 +456,78 @@ async def sub_handler(request):
assert resp.status == 200
resp = await client.get('/sub/')
assert resp.status == 201


async def test_subapp_on_startup(aiohttp_client):

subapp = web.Application()

startup_called = False

async def on_startup(app):
nonlocal startup_called
startup_called = True
app['startup'] = True

subapp.on_startup.append(on_startup)

ctx_pre_called = False
ctx_post_called = False

@async_generator
async def cleanup_ctx(app):
nonlocal ctx_pre_called, ctx_post_called
ctx_pre_called = True
app['cleanup'] = True
await yield_(None)
ctx_post_called = True

subapp.cleanup_ctx.append(cleanup_ctx)

shutdown_called = False

async def on_shutdown(app):
nonlocal shutdown_called
shutdown_called = True

subapp.on_shutdown.append(on_shutdown)

cleanup_called = False

async def on_cleanup(app):
nonlocal cleanup_called
cleanup_called = True

subapp.on_cleanup.append(on_cleanup)

app = web.Application()

app.add_subapp('/subapp', subapp)

assert not startup_called
assert not ctx_pre_called
assert not ctx_post_called
assert not shutdown_called
assert not cleanup_called

assert subapp.on_startup.frozen
assert subapp.cleanup_ctx.frozen
assert subapp.on_shutdown.frozen
assert subapp.on_cleanup.frozen
assert subapp.router.frozen

client = await aiohttp_client(app)

assert startup_called
assert ctx_pre_called
assert not ctx_post_called
assert not shutdown_called
assert not cleanup_called

await client.close()

assert startup_called
assert ctx_pre_called
assert ctx_post_called
assert shutdown_called
assert cleanup_called

0 comments on commit 864ef49

Please sign in to comment.