Skip to content

Commit

Permalink
Avoid to create unnecessary resources (aio-libs#2586)
Browse files Browse the repository at this point in the history
Do not create a new resource when adding a route with the same
name and path of the last added resource.
  • Loading branch information
sheb authored and Sebastien Geffroy committed Dec 13, 2017
1 parent 7e3f555 commit e6ddf76
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGES/2586.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Avoid to create a new resource when adding a route with the same
name and path of the last added resource
18 changes: 18 additions & 0 deletions aiohttp/web_urldispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ def get_info(self):
def freeze(self):
pass

@abc.abstractmethod
def raw_match(self, path):
"""Perform a raw match against path"""


class AbstractRoute(abc.ABC):

Expand Down Expand Up @@ -332,6 +336,9 @@ def _match(self, path):
else:
return None

def raw_match(self, path):
return self._path == path

def get_info(self):
return {'path': self._path}

Expand Down Expand Up @@ -400,6 +407,9 @@ def _match(self, path):
return {key: unquote(value, unsafe='+') for key, value in
match.groupdict().items()}

def raw_match(self, path):
return self._formatter == path

def get_info(self):
return {'formatter': self._formatter,
'pattern': self._pattern}
Expand Down Expand Up @@ -428,6 +438,9 @@ def add_prefix(self, prefix):
assert len(prefix) > 1
self._prefix = prefix + self._prefix

def raw_match(self, prefix):
return self._prefix == prefix

# TODO: impl missing abstract methods


Expand Down Expand Up @@ -830,6 +843,11 @@ def register_resource(self, resource):
def add_resource(self, path, *, name=None):
if path and not path.startswith('/'):
raise ValueError("path should be started with / or be empty")
# Reuse last added resource if path and name are the same
if self._resources:
resource = self._resources[-1]
if resource.name == name and resource.raw_match(path):
return resource
if not ('{' in path or '}' in path or ROUTE_RE.search(path)):
url = URL(path)
resource = PlainResource(url.raw_path, name=name)
Expand Down
20 changes: 20 additions & 0 deletions tests/test_web_urldispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,3 +342,23 @@ async def handler(_):
r = await client.head('/b')
assert r.status == 405
await r.release()


@pytest.mark.parametrize("path", [
'/a',
'/{a}',
])
def test_reuse_last_added_resource(path):
"""
Test that adding a route with the same name and path of the last added
resource doesn't create a new resource.
"""
app = web.Application()

async def handler(request):
return web.Response()

app.router.add_get(path, handler, name="a")
app.router.add_post(path, handler, name="a")

assert len(app.router.resources()) == 1

0 comments on commit e6ddf76

Please sign in to comment.