{
    "file_diffs": [
        {
            "old_file_content": "import abc\nimport asyncio\n\nimport collections\nimport mimetypes\nimport re\nimport os\nimport inspect\n\nfrom collections.abc import Sized, Iterable, Container\nfrom urllib.parse import urlencode, unquote\n\nfrom . import hdrs\nfrom .abc import AbstractRouter, AbstractMatchInfo\nfrom .protocol import HttpVersion11\nfrom .web_exceptions import HTTPMethodNotAllowed, HTTPNotFound, HTTPNotModified\nfrom .web_reqrep import StreamResponse\nfrom .multidict import upstr\n\n\n__all__ = ('UrlDispatcher', 'UrlMappingMatchInfo',\n           'Route', 'PlainRoute', 'DynamicRoute', 'StaticRoute')\n\n\nclass UrlMappingMatchInfo(dict, AbstractMatchInfo):\n\n    def __init__(self, match_dict, route):\n        super().__init__(match_dict)\n        self._route = route\n\n    @property\n    def handler(self):\n        return self._route.handler\n\n    @property\n    def route(self):\n        return self._route\n\n    def __repr__(self):\n        return \"<MatchInfo {}: {}>\".format(super().__repr__(), self._route)\n\n\n@asyncio.coroutine\ndef _defaultExpectHandler(request):\n    \"\"\"Default handler for Except: 100-continue\"\"\"\n    if request.version == HttpVersion11:\n        request.transport.write(b\"HTTP/1.1 100 Continue\\r\\n\\r\\n\")\n\n\nclass Route(metaclass=abc.ABCMeta):\n\n    def __init__(self, method, handler, name, *, expect_handler=None):\n        if expect_handler is None:\n            expect_handler = _defaultExpectHandler\n        assert asyncio.iscoroutinefunction(expect_handler), \\\n            'Coroutine is expected, got {!r}'.format(expect_handler)\n\n        self._method = method\n        self._handler = handler\n        self._name = name\n        self._expect_handler = expect_handler\n\n    @property\n    def method(self):\n        return self._method\n\n    @property\n    def handler(self):\n        return self._handler\n\n    @property\n    def name(self):\n        return self._name\n\n    @abc.abstractmethod  # pragma: no branch\n    def match(self, path):\n        \"\"\"Return dict with info for given path or\n        None if route cannot process path.\"\"\"\n\n    @abc.abstractmethod  # pragma: no branch\n    def url(self, **kwargs):\n        \"\"\"Construct url for route with additional params.\"\"\"\n\n    @asyncio.coroutine\n    def handle_expect_header(self, request):\n        return (yield from self._expect_handler(request))\n\n    @staticmethod\n    def _append_query(url, query):\n        if query is not None:\n            return url + \"?\" + urlencode(query)\n        else:\n            return url\n\n\nclass PlainRoute(Route):\n\n    def __init__(self, method, handler, name, path, *, expect_handler=None):\n        super().__init__(method, handler, name, expect_handler=expect_handler)\n        self._path = path\n\n    def match(self, path):\n        # string comparison is about 10 times faster than regexp matching\n        if self._path == path:\n            return {}\n        else:\n            return None\n\n    def url(self, *, query=None):\n        return self._append_query(self._path, query)\n\n    def __repr__(self):\n        name = \"'\" + self.name + \"' \" if self.name is not None else \"\"\n        return \"<PlainRoute {name}[{method}] {path} -> {handler!r}\".format(\n            name=name, method=self.method, path=self._path,\n            handler=self.handler)\n\n\nclass DynamicRoute(Route):\n\n    def __init__(self, method, handler, name, pattern, formatter, *,\n                 expect_handler=None):\n        super().__init__(method, handler, name, expect_handler=expect_handler)\n        self._pattern = pattern\n        self._formatter = formatter\n\n    def match(self, path):\n        match = self._pattern.match(path)\n        if match is None:\n            return None\n        else:\n            return match.groupdict()\n\n    def url(self, *, parts, query=None):\n        url = self._formatter.format_map(parts)\n        return self._append_query(url, query)\n\n    def __repr__(self):\n        name = \"'\" + self.name + \"' \" if self.name is not None else \"\"\n        return (\"<DynamicRoute {name}[{method}] {formatter} -> {handler!r}\"\n                .format(name=name, method=self.method,\n                        formatter=self._formatter, handler=self.handler))\n\n\nclass StaticRoute(Route):\n\n    def __init__(self, name, prefix, directory, *,\n                 expect_handler=None, chunk_size=256*1024,\n                 response_factory=StreamResponse):\n        assert prefix.startswith('/'), prefix\n        assert prefix.endswith('/'), prefix\n        super().__init__(\n            'GET', self.handle, name, expect_handler=expect_handler)\n        self._prefix = prefix\n        self._prefix_len = len(self._prefix)\n        self._directory = os.path.abspath(directory) + os.sep\n        self._chunk_size = chunk_size\n        self._response_factory = response_factory\n\n        if not os.path.isdir(self._directory):\n            raise ValueError(\n                \"No directory exists at '{}'\".format(self._directory))\n\n    def match(self, path):\n        if not path.startswith(self._prefix):\n            return None\n        return {'filename': path[self._prefix_len:]}\n\n    def url(self, *, filename, query=None):\n        while filename.startswith('/'):\n            filename = filename[1:]\n        url = self._prefix + filename\n        return self._append_query(url, query)\n\n    def _sendfile_cb(self, fut, out_fd, in_fd, offset, count, loop,\n                     registered):\n        if registered:\n            loop.remove_writer(out_fd)\n        try:\n            n = os.sendfile(out_fd, in_fd, offset, count)\n            if n == 0:  # EOF reached\n                n = count\n        except (BlockingIOError, InterruptedError):\n            n = 0\n        except Exception as exc:\n            fut.set_exception(exc)\n            return\n\n        if n < count:\n            loop.add_writer(out_fd, self._sendfile_cb, fut, out_fd, in_fd,\n                            offset + n, count - n, loop, True)\n        else:\n            fut.set_result(None)\n\n    @asyncio.coroutine\n    def _sendfile_system(self, req, resp, fobj, count):\n        \"\"\"\n        Write `count` bytes of `fobj` to `resp` starting from `offset` using\n        the ``sendfile`` system call.\n\n        `req` should be a :obj:`aiohttp.web.Request` instance.\n\n        `resp` should be a :obj:`aiohttp.web.StreamResponse` instance.\n\n        `fobj` should be an open file object.\n\n        `offset` should be an integer >= 0.\n\n        `count` should be an integer > 0.\n        \"\"\"\n        transport = req.transport\n\n        if transport.get_extra_info(\"sslcontext\"):\n            yield from self._sendfile_fallback(req, resp, fobj, count)\n            return\n\n        yield from resp.drain()\n\n        loop = req.app.loop\n        out_fd = transport.get_extra_info(\"socket\").fileno()\n        in_fd = fobj.fileno()\n        fut = asyncio.Future(loop=loop)\n\n        self._sendfile_cb(fut, out_fd, in_fd, 0, count, loop, False)\n\n        yield from fut\n\n    @asyncio.coroutine\n    def _sendfile_fallback(self, req, resp, fobj, count):\n        \"\"\"\n        Mimic the :meth:`_sendfile_system` method, but without using the\n        ``sendfile`` system call. This should be used on systems that don't\n        support the ``sendfile`` system call.\n\n        To avoid blocking the event loop & to keep memory usage low, `fobj` is\n        transferred in chunks controlled by the `chunk_size` argument to\n        :class:`StaticRoute`.\n        \"\"\"\n        chunk_size = self._chunk_size\n\n        chunk = fobj.read(chunk_size)\n        while chunk and count > chunk_size:\n            resp.write(chunk)\n            yield from resp.drain()\n            count = count - chunk_size\n            chunk = fobj.read(chunk_size)\n\n        if chunk:\n            resp.write(chunk[:count])\n            yield from resp.drain()\n\n    if hasattr(os, \"sendfile\"):  # pragma: no cover\n        _sendfile = _sendfile_system\n    else:  # pragma: no cover\n        _sendfile = _sendfile_fallback\n\n    @asyncio.coroutine\n    def handle(self, request):\n        filename = request.match_info['filename']\n        filepath = os.path.abspath(os.path.join(self._directory, filename))\n        if not filepath.startswith(self._directory):\n            raise HTTPNotFound()\n        if not os.path.exists(filepath) or not os.path.isfile(filepath):\n            raise HTTPNotFound()\n\n        st = os.stat(filepath)\n\n        modsince = request.if_modified_since\n        if modsince is not None and st.st_mtime <= modsince.timestamp():\n            raise HTTPNotModified()\n\n        ct, encoding = mimetypes.guess_type(filepath)\n        if not ct:\n            ct = 'application/octet-stream'\n\n        resp = self._response_factory()\n        resp.content_type = ct\n        if encoding:\n            resp.headers[hdrs.CONTENT_ENCODING] = encoding\n        resp.last_modified = st.st_mtime\n\n        file_size = st.st_size\n\n        resp.content_length = file_size\n        yield from resp.prepare(request)\n\n        with open(filepath, 'rb') as f:\n            yield from self._sendfile(request, resp, f, file_size)\n\n        return resp\n\n    def __repr__(self):\n        name = \"'\" + self.name + \"' \" if self.name is not None else \"\"\n        return \"<StaticRoute {name}[{method}] {path} -> {directory!r}\".format(\n            name=name, method=self.method, path=self._prefix,\n            directory=self._directory)\n\n\nclass SystemRoute(Route):\n\n    def __init__(self, status, reason):\n        super().__init__(hdrs.METH_ANY, None, None)\n        self._status = status\n        self._reason = reason\n\n    def url(self, **kwargs):\n        raise RuntimeError(\".url() is not allowed for SystemRoute\")\n\n    def match(self, path):\n        return None\n\n    @property\n    def status(self):\n        return self._status\n\n    @property\n    def reason(self):\n        return self._reason\n\n    def __repr__(self):\n        return \"<SystemRoute {status}: {reason}>\".format(status=self._status,\n                                                         reason=self._reason)\n\n\nclass _NotFoundMatchInfo(UrlMappingMatchInfo):\n\n    route = SystemRoute(404, 'Not Found')\n\n    def __init__(self):\n        super().__init__({}, None)\n\n    @property\n    def handler(self):\n        return self._not_found\n\n    @asyncio.coroutine\n    def _not_found(self, request):\n        raise HTTPNotFound()\n\n    def __repr__(self):\n        return \"<MatchInfo: not found>\"\n\n\nclass _MethodNotAllowedMatchInfo(UrlMappingMatchInfo):\n\n    route = SystemRoute(405, 'Method Not Allowed')\n\n    def __init__(self, method, allowed_methods):\n        super().__init__({}, None)\n        self._method = method\n        self._allowed_methods = allowed_methods\n\n    @property\n    def handler(self):\n        return self._not_allowed\n\n    @asyncio.coroutine\n    def _not_allowed(self, request):\n        raise HTTPMethodNotAllowed(self._method, self._allowed_methods)\n\n    def __repr__(self):\n        return (\"<MatchInfo: method {} is not allowed (allowed methods: {}>\"\n                .format(self._method,\n                        ', '.join(sorted(self._allowed_methods))))\n\n\nclass RoutesView(Sized, Iterable, Container):\n\n    __slots__ = '_urls'\n\n    def __init__(self, urls):\n        self._urls = urls\n\n    def __len__(self):\n        return len(self._urls)\n\n    def __iter__(self):\n        yield from self._urls\n\n    def __contains__(self, route):\n        return route in self._urls\n\n\nclass UrlDispatcher(AbstractRouter, collections.abc.Mapping):\n\n    DYN = re.compile(r'^\\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*)\\}$')\n    DYN_WITH_RE = re.compile(\n        r'^\\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*):(?P<re>.+)\\}$')\n    GOOD = r'[^{}/]+'\n    ROUTE_RE = re.compile(r'(\\{[_a-zA-Z][^{}]*(?:\\{[^{}]*\\}[^{}]*)*\\})')\n\n    METHODS = {hdrs.METH_ANY, hdrs.METH_POST,\n               hdrs.METH_GET, hdrs.METH_PUT, hdrs.METH_DELETE,\n               hdrs.METH_PATCH, hdrs.METH_HEAD, hdrs.METH_OPTIONS}\n\n    def __init__(self):\n        super().__init__()\n        self._urls = []\n        self._routes = {}\n\n    @asyncio.coroutine\n    def resolve(self, request):\n        path = request.raw_path\n        method = request.method\n        allowed_methods = set()\n\n        for route in self._urls:\n            match_dict = route.match(path)\n            if match_dict is None:\n                continue\n\n            route_method = route.method\n            if route_method == method or route_method == hdrs.METH_ANY:\n                # Unquote separate matching parts\n                match_dict = {key: unquote(value) for key, value in\n                              match_dict.items()}\n                return UrlMappingMatchInfo(match_dict, route)\n\n            allowed_methods.add(route_method)\n        else:\n            if allowed_methods:\n                return _MethodNotAllowedMatchInfo(method, allowed_methods)\n            else:\n                return _NotFoundMatchInfo()\n\n    def __iter__(self):\n        return iter(self._routes)\n\n    def __len__(self):\n        return len(self._routes)\n\n    def __contains__(self, name):\n        return name in self._routes\n\n    def __getitem__(self, name):\n        return self._routes[name]\n\n    def routes(self):\n        return RoutesView(self._urls)\n\n    def register_route(self, route):\n        assert isinstance(route, Route), 'Instance of Route class is required.'\n\n        name = route.name\n        if name is not None:\n            if name in self._routes:\n                raise ValueError('Duplicate {!r}, '\n                                 'already handled by {!r}'\n                                 .format(name, self._routes[name]))\n            else:\n                self._routes[name] = route\n        self._urls.append(route)\n\n    def add_route(self, method, path, handler,\n                  *, name=None, expect_handler=None):\n\n        if not path.startswith('/'):\n            raise ValueError(\"path should be started with /\")\n\n        assert callable(handler), handler\n        if (not asyncio.iscoroutinefunction(handler) and\n                not inspect.isgeneratorfunction(handler)):\n            handler = asyncio.coroutine(handler)\n\n        method = upstr(method)\n        if method not in self.METHODS:\n            raise ValueError(\"{} is not allowed HTTP method\".format(method))\n\n        if not ('{' in path or '}' in path or self.ROUTE_RE.search(path)):\n            route = PlainRoute(\n                method, handler, name, path, expect_handler=expect_handler)\n            self.register_route(route)\n            return route\n\n        pattern = ''\n        formatter = ''\n        for part in self.ROUTE_RE.split(path):\n            match = self.DYN.match(part)\n            if match:\n                pattern += '(?P<{}>{})'.format(match.group('var'), self.GOOD)\n                formatter += '{' + match.group('var') + '}'\n                continue\n\n            match = self.DYN_WITH_RE.match(part)\n            if match:\n                pattern += '(?P<{var}>{re})'.format(**match.groupdict())\n                formatter += '{' + match.group('var') + '}'\n                continue\n\n            if '{' in part or '}' in part:\n                raise ValueError(\"Invalid path '{}'['{}']\".format(path, part))\n\n            formatter += part\n            pattern += re.escape(part)\n\n        try:\n            compiled = re.compile('^' + pattern + '$')\n        except re.error as exc:\n            raise ValueError(\n                \"Bad pattern '{}': {}\".format(pattern, exc)) from None\n        route = DynamicRoute(\n            method, handler, name, compiled,\n            formatter, expect_handler=expect_handler)\n        self.register_route(route)\n        return route\n\n    def add_static(self, prefix, path, *, name=None, expect_handler=None,\n                   chunk_size=256*1024, response_factory=StreamResponse):\n        \"\"\"\n        Adds static files view\n        :param prefix - url prefix\n        :param path - folder with files\n        \"\"\"\n        assert prefix.startswith('/')\n        if not prefix.endswith('/'):\n            prefix += '/'\n        route = StaticRoute(name, prefix, path,\n                            expect_handler=expect_handler,\n                            chunk_size=chunk_size,\n                            response_factory=response_factory)\n        self.register_route(route)\n        return route\n",
            "new_file_content": "import abc\nimport asyncio\n\nimport keyword\nimport collections\nimport mimetypes\nimport re\nimport os\nimport inspect\n\nfrom collections.abc import Sized, Iterable, Container\nfrom urllib.parse import urlencode, unquote\n\nfrom . import hdrs\nfrom .abc import AbstractRouter, AbstractMatchInfo\nfrom .protocol import HttpVersion11\nfrom .web_exceptions import HTTPMethodNotAllowed, HTTPNotFound, HTTPNotModified\nfrom .web_reqrep import StreamResponse\nfrom .multidict import upstr\n\n\n__all__ = ('UrlDispatcher', 'UrlMappingMatchInfo',\n           'Route', 'PlainRoute', 'DynamicRoute', 'StaticRoute')\n\n\nclass UrlMappingMatchInfo(dict, AbstractMatchInfo):\n\n    def __init__(self, match_dict, route):\n        super().__init__(match_dict)\n        self._route = route\n\n    @property\n    def handler(self):\n        return self._route.handler\n\n    @property\n    def route(self):\n        return self._route\n\n    def __repr__(self):\n        return \"<MatchInfo {}: {}>\".format(super().__repr__(), self._route)\n\n\n@asyncio.coroutine\ndef _defaultExpectHandler(request):\n    \"\"\"Default handler for Except: 100-continue\"\"\"\n    if request.version == HttpVersion11:\n        request.transport.write(b\"HTTP/1.1 100 Continue\\r\\n\\r\\n\")\n\n\nclass Route(metaclass=abc.ABCMeta):\n\n    def __init__(self, method, handler, name, *, expect_handler=None):\n        if expect_handler is None:\n            expect_handler = _defaultExpectHandler\n        assert asyncio.iscoroutinefunction(expect_handler), \\\n            'Coroutine is expected, got {!r}'.format(expect_handler)\n\n        self._method = method\n        self._handler = handler\n        self._name = name\n        self._expect_handler = expect_handler\n\n    @property\n    def method(self):\n        return self._method\n\n    @property\n    def handler(self):\n        return self._handler\n\n    @property\n    def name(self):\n        return self._name\n\n    @abc.abstractmethod  # pragma: no branch\n    def match(self, path):\n        \"\"\"Return dict with info for given path or\n        None if route cannot process path.\"\"\"\n\n    @abc.abstractmethod  # pragma: no branch\n    def url(self, **kwargs):\n        \"\"\"Construct url for route with additional params.\"\"\"\n\n    @asyncio.coroutine\n    def handle_expect_header(self, request):\n        return (yield from self._expect_handler(request))\n\n    @staticmethod\n    def _append_query(url, query):\n        if query is not None:\n            return url + \"?\" + urlencode(query)\n        else:\n            return url\n\n\nclass PlainRoute(Route):\n\n    def __init__(self, method, handler, name, path, *, expect_handler=None):\n        super().__init__(method, handler, name, expect_handler=expect_handler)\n        self._path = path\n\n    def match(self, path):\n        # string comparison is about 10 times faster than regexp matching\n        if self._path == path:\n            return {}\n        else:\n            return None\n\n    def url(self, *, query=None):\n        return self._append_query(self._path, query)\n\n    def __repr__(self):\n        name = \"'\" + self.name + \"' \" if self.name is not None else \"\"\n        return \"<PlainRoute {name}[{method}] {path} -> {handler!r}\".format(\n            name=name, method=self.method, path=self._path,\n            handler=self.handler)\n\n\nclass DynamicRoute(Route):\n\n    def __init__(self, method, handler, name, pattern, formatter, *,\n                 expect_handler=None):\n        super().__init__(method, handler, name, expect_handler=expect_handler)\n        self._pattern = pattern\n        self._formatter = formatter\n\n    def match(self, path):\n        match = self._pattern.match(path)\n        if match is None:\n            return None\n        else:\n            return match.groupdict()\n\n    def url(self, *, parts, query=None):\n        url = self._formatter.format_map(parts)\n        return self._append_query(url, query)\n\n    def __repr__(self):\n        name = \"'\" + self.name + \"' \" if self.name is not None else \"\"\n        return (\"<DynamicRoute {name}[{method}] {formatter} -> {handler!r}\"\n                .format(name=name, method=self.method,\n                        formatter=self._formatter, handler=self.handler))\n\n\nclass StaticRoute(Route):\n\n    def __init__(self, name, prefix, directory, *,\n                 expect_handler=None, chunk_size=256*1024,\n                 response_factory=StreamResponse):\n        assert prefix.startswith('/'), prefix\n        assert prefix.endswith('/'), prefix\n        super().__init__(\n            'GET', self.handle, name, expect_handler=expect_handler)\n        self._prefix = prefix\n        self._prefix_len = len(self._prefix)\n        self._directory = os.path.abspath(directory) + os.sep\n        self._chunk_size = chunk_size\n        self._response_factory = response_factory\n\n        if not os.path.isdir(self._directory):\n            raise ValueError(\n                \"No directory exists at '{}'\".format(self._directory))\n\n    def match(self, path):\n        if not path.startswith(self._prefix):\n            return None\n        return {'filename': path[self._prefix_len:]}\n\n    def url(self, *, filename, query=None):\n        while filename.startswith('/'):\n            filename = filename[1:]\n        url = self._prefix + filename\n        return self._append_query(url, query)\n\n    def _sendfile_cb(self, fut, out_fd, in_fd, offset, count, loop,\n                     registered):\n        if registered:\n            loop.remove_writer(out_fd)\n        try:\n            n = os.sendfile(out_fd, in_fd, offset, count)\n            if n == 0:  # EOF reached\n                n = count\n        except (BlockingIOError, InterruptedError):\n            n = 0\n        except Exception as exc:\n            fut.set_exception(exc)\n            return\n\n        if n < count:\n            loop.add_writer(out_fd, self._sendfile_cb, fut, out_fd, in_fd,\n                            offset + n, count - n, loop, True)\n        else:\n            fut.set_result(None)\n\n    @asyncio.coroutine\n    def _sendfile_system(self, req, resp, fobj, count):\n        \"\"\"\n        Write `count` bytes of `fobj` to `resp` starting from `offset` using\n        the ``sendfile`` system call.\n\n        `req` should be a :obj:`aiohttp.web.Request` instance.\n\n        `resp` should be a :obj:`aiohttp.web.StreamResponse` instance.\n\n        `fobj` should be an open file object.\n\n        `offset` should be an integer >= 0.\n\n        `count` should be an integer > 0.\n        \"\"\"\n        transport = req.transport\n\n        if transport.get_extra_info(\"sslcontext\"):\n            yield from self._sendfile_fallback(req, resp, fobj, count)\n            return\n\n        yield from resp.drain()\n\n        loop = req.app.loop\n        out_fd = transport.get_extra_info(\"socket\").fileno()\n        in_fd = fobj.fileno()\n        fut = asyncio.Future(loop=loop)\n\n        self._sendfile_cb(fut, out_fd, in_fd, 0, count, loop, False)\n\n        yield from fut\n\n    @asyncio.coroutine\n    def _sendfile_fallback(self, req, resp, fobj, count):\n        \"\"\"\n        Mimic the :meth:`_sendfile_system` method, but without using the\n        ``sendfile`` system call. This should be used on systems that don't\n        support the ``sendfile`` system call.\n\n        To avoid blocking the event loop & to keep memory usage low, `fobj` is\n        transferred in chunks controlled by the `chunk_size` argument to\n        :class:`StaticRoute`.\n        \"\"\"\n        chunk_size = self._chunk_size\n\n        chunk = fobj.read(chunk_size)\n        while chunk and count > chunk_size:\n            resp.write(chunk)\n            yield from resp.drain()\n            count = count - chunk_size\n            chunk = fobj.read(chunk_size)\n\n        if chunk:\n            resp.write(chunk[:count])\n            yield from resp.drain()\n\n    if hasattr(os, \"sendfile\"):  # pragma: no cover\n        _sendfile = _sendfile_system\n    else:  # pragma: no cover\n        _sendfile = _sendfile_fallback\n\n    @asyncio.coroutine\n    def handle(self, request):\n        filename = request.match_info['filename']\n        filepath = os.path.abspath(os.path.join(self._directory, filename))\n        if not filepath.startswith(self._directory):\n            raise HTTPNotFound()\n        if not os.path.exists(filepath) or not os.path.isfile(filepath):\n            raise HTTPNotFound()\n\n        st = os.stat(filepath)\n\n        modsince = request.if_modified_since\n        if modsince is not None and st.st_mtime <= modsince.timestamp():\n            raise HTTPNotModified()\n\n        ct, encoding = mimetypes.guess_type(filepath)\n        if not ct:\n            ct = 'application/octet-stream'\n\n        resp = self._response_factory()\n        resp.content_type = ct\n        if encoding:\n            resp.headers[hdrs.CONTENT_ENCODING] = encoding\n        resp.last_modified = st.st_mtime\n\n        file_size = st.st_size\n\n        resp.content_length = file_size\n        yield from resp.prepare(request)\n\n        with open(filepath, 'rb') as f:\n            yield from self._sendfile(request, resp, f, file_size)\n\n        return resp\n\n    def __repr__(self):\n        name = \"'\" + self.name + \"' \" if self.name is not None else \"\"\n        return \"<StaticRoute {name}[{method}] {path} -> {directory!r}\".format(\n            name=name, method=self.method, path=self._prefix,\n            directory=self._directory)\n\n\nclass SystemRoute(Route):\n\n    def __init__(self, status, reason):\n        super().__init__(hdrs.METH_ANY, None, None)\n        self._status = status\n        self._reason = reason\n\n    def url(self, **kwargs):\n        raise RuntimeError(\".url() is not allowed for SystemRoute\")\n\n    def match(self, path):\n        return None\n\n    @property\n    def status(self):\n        return self._status\n\n    @property\n    def reason(self):\n        return self._reason\n\n    def __repr__(self):\n        return \"<SystemRoute {status}: {reason}>\".format(status=self._status,\n                                                         reason=self._reason)\n\n\nclass _NotFoundMatchInfo(UrlMappingMatchInfo):\n\n    route = SystemRoute(404, 'Not Found')\n\n    def __init__(self):\n        super().__init__({}, None)\n\n    @property\n    def handler(self):\n        return self._not_found\n\n    @asyncio.coroutine\n    def _not_found(self, request):\n        raise HTTPNotFound()\n\n    def __repr__(self):\n        return \"<MatchInfo: not found>\"\n\n\nclass _MethodNotAllowedMatchInfo(UrlMappingMatchInfo):\n\n    route = SystemRoute(405, 'Method Not Allowed')\n\n    def __init__(self, method, allowed_methods):\n        super().__init__({}, None)\n        self._method = method\n        self._allowed_methods = allowed_methods\n\n    @property\n    def handler(self):\n        return self._not_allowed\n\n    @asyncio.coroutine\n    def _not_allowed(self, request):\n        raise HTTPMethodNotAllowed(self._method, self._allowed_methods)\n\n    def __repr__(self):\n        return (\"<MatchInfo: method {} is not allowed (allowed methods: {}>\"\n                .format(self._method,\n                        ', '.join(sorted(self._allowed_methods))))\n\n\nclass RoutesView(Sized, Iterable, Container):\n\n    __slots__ = '_urls'\n\n    def __init__(self, urls):\n        self._urls = urls\n\n    def __len__(self):\n        return len(self._urls)\n\n    def __iter__(self):\n        yield from self._urls\n\n    def __contains__(self, route):\n        return route in self._urls\n\n\nclass UrlDispatcher(AbstractRouter, collections.abc.Mapping):\n\n    DYN = re.compile(r'^\\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*)\\}$')\n    DYN_WITH_RE = re.compile(\n        r'^\\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*):(?P<re>.+)\\}$')\n    GOOD = r'[^{}/]+'\n    ROUTE_RE = re.compile(r'(\\{[_a-zA-Z][^{}]*(?:\\{[^{}]*\\}[^{}]*)*\\})')\n\n    METHODS = {hdrs.METH_ANY, hdrs.METH_POST,\n               hdrs.METH_GET, hdrs.METH_PUT, hdrs.METH_DELETE,\n               hdrs.METH_PATCH, hdrs.METH_HEAD, hdrs.METH_OPTIONS}\n\n    def __init__(self):\n        super().__init__()\n        self._urls = []\n        self._routes = {}\n\n    @asyncio.coroutine\n    def resolve(self, request):\n        path = request.raw_path\n        method = request.method\n        allowed_methods = set()\n\n        for route in self._urls:\n            match_dict = route.match(path)\n            if match_dict is None:\n                continue\n\n            route_method = route.method\n            if route_method == method or route_method == hdrs.METH_ANY:\n                # Unquote separate matching parts\n                match_dict = {key: unquote(value) for key, value in\n                              match_dict.items()}\n                return UrlMappingMatchInfo(match_dict, route)\n\n            allowed_methods.add(route_method)\n        else:\n            if allowed_methods:\n                return _MethodNotAllowedMatchInfo(method, allowed_methods)\n            else:\n                return _NotFoundMatchInfo()\n\n    def __iter__(self):\n        return iter(self._routes)\n\n    def __len__(self):\n        return len(self._routes)\n\n    def __contains__(self, name):\n        return name in self._routes\n\n    def __getitem__(self, name):\n        return self._routes[name]\n\n    def routes(self):\n        return RoutesView(self._urls)\n\n    def register_route(self, route):\n        assert isinstance(route, Route), 'Instance of Route class is required.'\n\n        name = route.name\n\n        if name is not None:\n            if not name.isidentifier() or keyword.iskeyword(name):\n                raise ValueError('Incorrect route name value, '\n                                 'Route name should be python identifier')\n            elif name in self._routes:\n                raise ValueError('Duplicate {!r}, '\n                                 'already handled by {!r}'\n                                 .format(name, self._routes[name]))\n            else:\n                self._routes[name] = route\n        self._urls.append(route)\n\n    def add_route(self, method, path, handler,\n                  *, name=None, expect_handler=None):\n\n        if not path.startswith('/'):\n            raise ValueError(\"path should be started with /\")\n\n        assert callable(handler), handler\n        if (not asyncio.iscoroutinefunction(handler) and\n                not inspect.isgeneratorfunction(handler)):\n            handler = asyncio.coroutine(handler)\n\n        method = upstr(method)\n        if method not in self.METHODS:\n            raise ValueError(\"{} is not allowed HTTP method\".format(method))\n\n        if not ('{' in path or '}' in path or self.ROUTE_RE.search(path)):\n            route = PlainRoute(\n                method, handler, name, path, expect_handler=expect_handler)\n            self.register_route(route)\n            return route\n\n        pattern = ''\n        formatter = ''\n        for part in self.ROUTE_RE.split(path):\n            match = self.DYN.match(part)\n            if match:\n                pattern += '(?P<{}>{})'.format(match.group('var'), self.GOOD)\n                formatter += '{' + match.group('var') + '}'\n                continue\n\n            match = self.DYN_WITH_RE.match(part)\n            if match:\n                pattern += '(?P<{var}>{re})'.format(**match.groupdict())\n                formatter += '{' + match.group('var') + '}'\n                continue\n\n            if '{' in part or '}' in part:\n                raise ValueError(\"Invalid path '{}'['{}']\".format(path, part))\n\n            formatter += part\n            pattern += re.escape(part)\n\n        try:\n            compiled = re.compile('^' + pattern + '$')\n        except re.error as exc:\n            raise ValueError(\n                \"Bad pattern '{}': {}\".format(pattern, exc)) from None\n        route = DynamicRoute(\n            method, handler, name, compiled,\n            formatter, expect_handler=expect_handler)\n        self.register_route(route)\n        return route\n\n    def add_static(self, prefix, path, *, name=None, expect_handler=None,\n                   chunk_size=256*1024, response_factory=StreamResponse):\n        \"\"\"\n        Adds static files view\n        :param prefix - url prefix\n        :param path - folder with files\n        \"\"\"\n        assert prefix.startswith('/')\n        if not prefix.endswith('/'):\n            prefix += '/'\n        route = StaticRoute(name, prefix, path,\n                            expect_handler=expect_handler,\n                            chunk_size=chunk_size,\n                            response_factory=response_factory)\n        self.register_route(route)\n        return route\n",
            "header": {
                "file": {
                    "path": "aiohttp/web_urldispatcher.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "44f6460d",
                "new_commit_hash": "58c8c2e6",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/aiohttp/web_urldispatcher.py"
            },
            "plus_file": {
                "path": "b/aiohttp/web_urldispatcher.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 1,
                            "length": 6
                        },
                        "new_range": {
                            "start": 1,
                            "length": 7
                        },
                        "section": ""
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "import abc",
                                "type": "context"
                            },
                            {
                                "content": "import asyncio",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "import keyword",
                                "type": "added"
                            },
                            {
                                "content": "import collections",
                                "type": "context"
                            },
                            {
                                "content": "import mimetypes",
                                "type": "context"
                            },
                            {
                                "content": "import re",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "aiohttp/web_urldispatcher.py",
                            "type": "import",
                            "name": "keyword",
                            "content": "import keyword",
                            "ast_type_str": "Import",
                            "start_lineno": 4,
                            "end_lineno": 4,
                            "parent": null
                        }
                    ],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 442,
                            "length": 8
                        },
                        "new_range": {
                            "start": 443,
                            "length": 12
                        },
                        "section": "class UrlDispatcher(AbstractRouter, collections.abc.Mapping):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        assert isinstance(route, Route), 'Instance of Route class is required.'",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        name = route.name",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        if name is not None:",
                                "type": "context"
                            },
                            {
                                "content": "            if name in self._routes:",
                                "type": "deleted"
                            },
                            {
                                "content": "            if not name.isidentifier() or keyword.iskeyword(name):",
                                "type": "added"
                            },
                            {
                                "content": "                raise ValueError('Incorrect route name value, '",
                                "type": "added"
                            },
                            {
                                "content": "                                 'Route name should be python identifier')",
                                "type": "added"
                            },
                            {
                                "content": "            elif name in self._routes:",
                                "type": "added"
                            },
                            {
                                "content": "                raise ValueError('Duplicate {!r}, '",
                                "type": "context"
                            },
                            {
                                "content": "                                 'already handled by {!r}'",
                                "type": "context"
                            },
                            {
                                "content": "                                 .format(name, self._routes[name]))",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "aiohttp/web_urldispatcher.py",
                            "type": "class",
                            "name": "UrlDispatcher",
                            "content": "class UrlDispatcher(AbstractRouter, collections.abc.Mapping):\n\n    DYN = re.compile(r'^\\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*)\\}$')\n    DYN_WITH_RE = re.compile(\n        r'^\\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*):(?P<re>.+)\\}$')\n    GOOD = r'[^{}/]+'\n    ROUTE_RE = re.compile(r'(\\{[_a-zA-Z][^{}]*(?:\\{[^{}]*\\}[^{}]*)*\\})')\n\n    METHODS = {hdrs.METH_ANY, hdrs.METH_POST,\n               hdrs.METH_GET, hdrs.METH_PUT, hdrs.METH_DELETE,\n               hdrs.METH_PATCH, hdrs.METH_HEAD, hdrs.METH_OPTIONS}\n\n    def __init__(self):\n        super().__init__()\n        self._urls = []\n        self._routes = {}\n\n    @asyncio.coroutine\n    def resolve(self, request):\n        path = request.raw_path\n        method = request.method\n        allowed_methods = set()\n\n        for route in self._urls:\n            match_dict = route.match(path)\n            if match_dict is None:\n                continue\n\n            route_method = route.method\n            if route_method == method or route_method == hdrs.METH_ANY:\n                # Unquote separate matching parts\n                match_dict = {key: unquote(value) for key, value in\n                              match_dict.items()}\n                return UrlMappingMatchInfo(match_dict, route)\n\n            allowed_methods.add(route_method)\n        else:\n            if allowed_methods:\n                return _MethodNotAllowedMatchInfo(method, allowed_methods)\n            else:\n                return _NotFoundMatchInfo()\n\n    def __iter__(self):\n        return iter(self._routes)\n\n    def __len__(self):\n        return len(self._routes)\n\n    def __contains__(self, name):\n        return name in self._routes\n\n    def __getitem__(self, name):\n        return self._routes[name]\n\n    def routes(self):\n        return RoutesView(self._urls)\n\n    def register_route(self, route):\n        assert isinstance(route, Route), 'Instance of Route class is required.'\n\n        name = route.name\n        if name is not None:\n            if name in self._routes:\n                raise ValueError('Duplicate {!r}, '\n                                 'already handled by {!r}'\n                                 .format(name, self._routes[name]))\n            else:\n                self._routes[name] = route\n        self._urls.append(route)\n\n    def add_route(self, method, path, handler,\n                  *, name=None, expect_handler=None):\n\n        if not path.startswith('/'):\n            raise ValueError(\"path should be started with /\")\n\n        assert callable(handler), handler\n        if (not asyncio.iscoroutinefunction(handler) and\n                not inspect.isgeneratorfunction(handler)):\n            handler = asyncio.coroutine(handler)\n\n        method = upstr(method)\n        if method not in self.METHODS:\n            raise ValueError(\"{} is not allowed HTTP method\".format(method))\n\n        if not ('{' in path or '}' in path or self.ROUTE_RE.search(path)):\n            route = PlainRoute(\n                method, handler, name, path, expect_handler=expect_handler)\n            self.register_route(route)\n            return route\n\n        pattern = ''\n        formatter = ''\n        for part in self.ROUTE_RE.split(path):\n            match = self.DYN.match(part)\n            if match:\n                pattern += '(?P<{}>{})'.format(match.group('var'), self.GOOD)\n                formatter += '{' + match.group('var') + '}'\n                continue\n\n            match = self.DYN_WITH_RE.match(part)\n            if match:\n                pattern += '(?P<{var}>{re})'.format(**match.groupdict())\n                formatter += '{' + match.group('var') + '}'\n                continue\n\n            if '{' in part or '}' in part:\n                raise ValueError(\"Invalid path '{}'['{}']\".format(path, part))\n\n            formatter += part\n            pattern += re.escape(part)\n\n        try:\n            compiled = re.compile('^' + pattern + '$')\n        except re.error as exc:\n            raise ValueError(\n                \"Bad pattern '{}': {}\".format(pattern, exc)) from None\n        route = DynamicRoute(\n            method, handler, name, compiled,\n            formatter, expect_handler=expect_handler)\n        self.register_route(route)\n        return route\n\n    def add_static(self, prefix, path, *, name=None, expect_handler=None,\n                   chunk_size=256*1024, response_factory=StreamResponse):\n        \"\"\"\n        Adds static files view\n        :param prefix - url prefix\n        :param path - folder with files\n        \"\"\"\n        assert prefix.startswith('/')\n        if not prefix.endswith('/'):\n            prefix += '/'\n        route = StaticRoute(name, prefix, path,\n                            expect_handler=expect_handler,\n                            chunk_size=chunk_size,\n                            response_factory=response_factory)\n        self.register_route(route)\n        return route",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 384,
                            "end_lineno": 522,
                            "parent": null
                        },
                        {
                            "file_name": "aiohttp/web_urldispatcher.py",
                            "type": "method",
                            "name": "UrlDispatcher.register_route",
                            "content": "class UrlDispatcher(AbstractRouter, collections.abc.Mapping):\n\n    DYN = re.compile(r'^\\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*)\\}$')\n    DYN_WITH_RE = re.compile(\n        r'^\\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*):(?P<re>.+)\\}$')\n    GOOD = r'[^{}/]+'\n    ROUTE_RE = re.compile(r'(\\{[_a-zA-Z][^{}]*(?:\\{[^{}]*\\}[^{}]*)*\\})')\n\n    METHODS = {hdrs.METH_ANY, hdrs.METH_POST,\n               hdrs.METH_GET, hdrs.METH_PUT, hdrs.METH_DELETE,\n               hdrs.METH_PATCH, hdrs.METH_HEAD, hdrs.METH_OPTIONS}\n\n    def __init__(self):\n        super().__init__()\n        self._urls = []\n        self._routes = {}\n\n    @asyncio.coroutine\n    def resolve(self, request):\n        path = request.raw_path\n        method = request.method\n        allowed_methods = set()\n\n        for route in self._urls:\n            match_dict = route.match(path)\n            if match_dict is None:\n                continue\n\n            route_method = route.method\n            if route_method == method or route_method == hdrs.METH_ANY:\n                # Unquote separate matching parts\n                match_dict = {key: unquote(value) for key, value in\n                              match_dict.items()}\n                return UrlMappingMatchInfo(match_dict, route)\n\n            allowed_methods.add(route_method)\n        else:\n            if allowed_methods:\n                return _MethodNotAllowedMatchInfo(method, allowed_methods)\n            else:\n                return _NotFoundMatchInfo()\n\n    def __iter__(self):\n        return iter(self._routes)\n\n    def __len__(self):\n        return len(self._routes)\n\n    def __contains__(self, name):\n        return name in self._routes\n\n    def __getitem__(self, name):\n        return self._routes[name]\n\n    def routes(self):\n        return RoutesView(self._urls)\n\n    def register_route(self, route):\n        assert isinstance(route, Route), 'Instance of Route class is required.'\n\n        name = route.name\n        if name is not None:\n            if name in self._routes:\n                raise ValueError('Duplicate {!r}, '\n                                 'already handled by {!r}'\n                                 .format(name, self._routes[name]))\n            else:\n                self._routes[name] = route\n        self._urls.append(route)\n\n    def add_route(self, method, path, handler,\n                  *, name=None, expect_handler=None):\n\n        if not path.startswith('/'):\n            raise ValueError(\"path should be started with /\")\n\n        assert callable(handler), handler\n        if (not asyncio.iscoroutinefunction(handler) and\n                not inspect.isgeneratorfunction(handler)):\n            handler = asyncio.coroutine(handler)\n\n        method = upstr(method)\n        if method not in self.METHODS:\n            raise ValueError(\"{} is not allowed HTTP method\".format(method))\n\n        if not ('{' in path or '}' in path or self.ROUTE_RE.search(path)):\n            route = PlainRoute(\n                method, handler, name, path, expect_handler=expect_handler)\n            self.register_route(route)\n            return route\n\n        pattern = ''\n        formatter = ''\n        for part in self.ROUTE_RE.split(path):\n            match = self.DYN.match(part)\n            if match:\n                pattern += '(?P<{}>{})'.format(match.group('var'), self.GOOD)\n                formatter += '{' + match.group('var') + '}'\n                continue\n\n            match = self.DYN_WITH_RE.match(part)\n            if match:\n                pattern += '(?P<{var}>{re})'.format(**match.groupdict())\n                formatter += '{' + match.group('var') + '}'\n                continue\n\n            if '{' in part or '}' in part:\n                raise ValueError(\"Invalid path '{}'['{}']\".format(path, part))\n\n            formatter += part\n            pattern += re.escape(part)\n\n        try:\n            compiled = re.compile('^' + pattern + '$')\n        except re.error as exc:\n            raise ValueError(\n                \"Bad pattern '{}': {}\".format(pattern, exc)) from None\n        route = DynamicRoute(\n            method, handler, name, compiled,\n            formatter, expect_handler=expect_handler)\n        self.register_route(route)\n        return route\n\n    def add_static(self, prefix, path, *, name=None, expect_handler=None,\n                   chunk_size=256*1024, response_factory=StreamResponse):\n        \"\"\"\n        Adds static files view\n        :param prefix - url prefix\n        :param path - folder with files\n        \"\"\"\n        assert prefix.startswith('/')\n        if not prefix.endswith('/'):\n            prefix += '/'\n        route = StaticRoute(name, prefix, path,\n                            expect_handler=expect_handler,\n                            chunk_size=chunk_size,\n                            response_factory=response_factory)\n        self.register_route(route)\n        return route",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 441,
                            "end_lineno": 452,
                            "parent": {
                                "file_name": "aiohttp/web_urldispatcher.py",
                                "type": "class",
                                "name": "UrlDispatcher",
                                "content": "class UrlDispatcher(AbstractRouter, collections.abc.Mapping):\n\n    DYN = re.compile(r'^\\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*)\\}$')\n    DYN_WITH_RE = re.compile(\n        r'^\\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*):(?P<re>.+)\\}$')\n    GOOD = r'[^{}/]+'\n    ROUTE_RE = re.compile(r'(\\{[_a-zA-Z][^{}]*(?:\\{[^{}]*\\}[^{}]*)*\\})')\n\n    METHODS = {hdrs.METH_ANY, hdrs.METH_POST,\n               hdrs.METH_GET, hdrs.METH_PUT, hdrs.METH_DELETE,\n               hdrs.METH_PATCH, hdrs.METH_HEAD, hdrs.METH_OPTIONS}\n\n    def __init__(self):\n        super().__init__()\n        self._urls = []\n        self._routes = {}\n\n    @asyncio.coroutine\n    def resolve(self, request):\n        path = request.raw_path\n        method = request.method\n        allowed_methods = set()\n\n        for route in self._urls:\n            match_dict = route.match(path)\n            if match_dict is None:\n                continue\n\n            route_method = route.method\n            if route_method == method or route_method == hdrs.METH_ANY:\n                # Unquote separate matching parts\n                match_dict = {key: unquote(value) for key, value in\n                              match_dict.items()}\n                return UrlMappingMatchInfo(match_dict, route)\n\n            allowed_methods.add(route_method)\n        else:\n            if allowed_methods:\n                return _MethodNotAllowedMatchInfo(method, allowed_methods)\n            else:\n                return _NotFoundMatchInfo()\n\n    def __iter__(self):\n        return iter(self._routes)\n\n    def __len__(self):\n        return len(self._routes)\n\n    def __contains__(self, name):\n        return name in self._routes\n\n    def __getitem__(self, name):\n        return self._routes[name]\n\n    def routes(self):\n        return RoutesView(self._urls)\n\n    def register_route(self, route):\n        assert isinstance(route, Route), 'Instance of Route class is required.'\n\n        name = route.name\n        if name is not None:\n            if name in self._routes:\n                raise ValueError('Duplicate {!r}, '\n                                 'already handled by {!r}'\n                                 .format(name, self._routes[name]))\n            else:\n                self._routes[name] = route\n        self._urls.append(route)\n\n    def add_route(self, method, path, handler,\n                  *, name=None, expect_handler=None):\n\n        if not path.startswith('/'):\n            raise ValueError(\"path should be started with /\")\n\n        assert callable(handler), handler\n        if (not asyncio.iscoroutinefunction(handler) and\n                not inspect.isgeneratorfunction(handler)):\n            handler = asyncio.coroutine(handler)\n\n        method = upstr(method)\n        if method not in self.METHODS:\n            raise ValueError(\"{} is not allowed HTTP method\".format(method))\n\n        if not ('{' in path or '}' in path or self.ROUTE_RE.search(path)):\n            route = PlainRoute(\n                method, handler, name, path, expect_handler=expect_handler)\n            self.register_route(route)\n            return route\n\n        pattern = ''\n        formatter = ''\n        for part in self.ROUTE_RE.split(path):\n            match = self.DYN.match(part)\n            if match:\n                pattern += '(?P<{}>{})'.format(match.group('var'), self.GOOD)\n                formatter += '{' + match.group('var') + '}'\n                continue\n\n            match = self.DYN_WITH_RE.match(part)\n            if match:\n                pattern += '(?P<{var}>{re})'.format(**match.groupdict())\n                formatter += '{' + match.group('var') + '}'\n                continue\n\n            if '{' in part or '}' in part:\n                raise ValueError(\"Invalid path '{}'['{}']\".format(path, part))\n\n            formatter += part\n            pattern += re.escape(part)\n\n        try:\n            compiled = re.compile('^' + pattern + '$')\n        except re.error as exc:\n            raise ValueError(\n                \"Bad pattern '{}': {}\".format(pattern, exc)) from None\n        route = DynamicRoute(\n            method, handler, name, compiled,\n            formatter, expect_handler=expect_handler)\n        self.register_route(route)\n        return route\n\n    def add_static(self, prefix, path, *, name=None, expect_handler=None,\n                   chunk_size=256*1024, response_factory=StreamResponse):\n        \"\"\"\n        Adds static files view\n        :param prefix - url prefix\n        :param path - folder with files\n        \"\"\"\n        assert prefix.startswith('/')\n        if not prefix.endswith('/'):\n            prefix += '/'\n        route = StaticRoute(name, prefix, path,\n                            expect_handler=expect_handler,\n                            chunk_size=chunk_size,\n                            response_factory=response_factory)\n        self.register_route(route)\n        return route",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 384,
                                "end_lineno": 522,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "import asyncio\nimport os\nimport unittest\nfrom collections.abc import Sized, Container, Iterable\nfrom unittest import mock\nfrom urllib.parse import unquote\nimport aiohttp.web\nfrom aiohttp import hdrs\nfrom aiohttp.web import (UrlDispatcher, Request, Response,\n                         HTTPMethodNotAllowed, HTTPNotFound)\nfrom aiohttp.multidict import CIMultiDict\nfrom aiohttp.protocol import HttpVersion, RawRequestMessage\nfrom aiohttp.web_urldispatcher import (_defaultExpectHandler,\n                                       DynamicRoute,\n                                       PlainRoute,\n                                       SystemRoute)\n\n\nclass TestUrlDispatcher(unittest.TestCase):\n\n    def setUp(self):\n        self.loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(None)\n        self.router = UrlDispatcher()\n\n    def tearDown(self):\n        self.loop.close()\n\n    def make_request(self, method, path):\n        self.app = mock.Mock()\n        message = RawRequestMessage(method, path, HttpVersion(1, 1),\n                                    CIMultiDict(), False, False)\n        self.payload = mock.Mock()\n        self.transport = mock.Mock()\n        self.reader = mock.Mock()\n        self.writer = mock.Mock()\n        req = Request(self.app, message, self.payload,\n                      self.transport, self.reader, self.writer)\n        return req\n\n    def make_handler(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            return Response(request)  # pragma: no cover\n\n        return handler\n\n    def test_system_route(self):\n        route = SystemRoute(201, 'test')\n        self.assertIsNone(route.match('any'))\n        with self.assertRaises(RuntimeError):\n            route.url()\n        self.assertEqual(\"<SystemRoute 201: test>\", repr(route))\n        self.assertEqual(201, route.status)\n        self.assertEqual('test', route.reason)\n\n    def test_register_route(self):\n        handler = self.make_handler()\n        route = PlainRoute('GET', handler, 'test', '/handler/to/path')\n        self.router.register_route(route)\n\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(route, info.route)\n        self.assertIs(handler, info.handler)\n        self.assertEqual(info.route.name, 'test')\n\n    def test_register_route_checks(self):\n        self.assertRaises(\n            AssertionError, self.router.register_route, object())\n\n        handler = self.make_handler()\n        route = PlainRoute('GET', handler, 'test', '/handler/to/path')\n        self.router.register_route(route)\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n    def test_add_route_root(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/', handler)\n        req = self.make_request('GET', '/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_route_simple(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path', handler)\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_with_matchdict(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/{to}', handler)\n        req = self.make_request('GET', '/handler/tail')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': 'tail'}, info)\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_with_name(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path', handler,\n                              name='name')\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual('name', info.route.name)\n\n    def test_add_with_tailing_slash(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path/', handler)\n        req = self.make_request('GET', '/handler/to/path/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({}, info)\n        self.assertIs(handler, info.handler)\n\n    def test_add_invalid_path(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('GET', '/{/', handler)\n\n    def test_add_url_invalid1(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id', handler)\n\n    def test_add_url_invalid2(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id{}}', handler)\n\n    def test_add_url_invalid3(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id{}', handler)\n\n    def test_add_url_invalid4(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id\"}', handler)\n\n    def test_add_url_escaping(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/+$', handler)\n\n        req = self.make_request('GET', '/+$')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertIs(handler, info.handler)\n\n    def test_any_method(self):\n        handler = self.make_handler()\n        route = self.router.add_route(hdrs.METH_ANY, '/', handler)\n\n        req = self.make_request('GET', '/')\n        info1 = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info1)\n        self.assertIs(route, info1.route)\n\n        req = self.make_request('POST', '/')\n        info2 = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info2)\n\n        self.assertIs(info1.route, info2.route)\n\n    def test_match_second_result_in_table(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/h1', handler1)\n        self.router.add_route('POST', '/h2', handler2)\n        req = self.make_request('POST', '/h2')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({}, info)\n        self.assertIs(handler2, info.handler)\n\n    def test_raise_method_not_allowed(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/', handler1)\n        self.router.add_route('POST', '/', handler2)\n        req = self.make_request('PUT', '/')\n\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n\n        with self.assertRaises(HTTPMethodNotAllowed) as ctx:\n            self.loop.run_until_complete(match_info.handler(req))\n\n        exc = ctx.exception\n        self.assertEqual('PUT', exc.method)\n        self.assertEqual(405, exc.status)\n        self.assertEqual({'POST', 'GET'}, exc.allowed_methods)\n\n    def test_raise_method_not_found(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/a', handler)\n        req = self.make_request('GET', '/b')\n\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n\n        with self.assertRaises(HTTPNotFound) as ctx:\n            self.loop.run_until_complete(match_info.handler(req))\n\n        exc = ctx.exception\n        self.assertEqual(404, exc.status)\n\n    def test_double_add_url_with_the_same_name(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/get', handler1, name='name')\n\n        regexp = (\"Duplicate 'name', already handled by\")\n        with self.assertRaisesRegex(ValueError, regexp):\n            self.router.add_route('GET', '/get_other', handler2, name='name')\n\n    def test_route_plain(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get', handler, name='name')\n        route2 = self.router['name']\n        url = route2.url()\n        self.assertEqual('/get', url)\n        self.assertIs(route, route2)\n\n    def test_route_unknown_route_name(self):\n        with self.assertRaises(KeyError):\n            self.router['unknown']\n\n    def test_route_dynamic(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{name}', handler,\n                                      name='name')\n\n        route2 = self.router['name']\n        url = route2.url(parts={'name': 'John'})\n        self.assertEqual('/get/John', url)\n        self.assertIs(route, route2)\n\n    def test_route_with_qs(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get', handler, name='name')\n\n        url = self.router['name'].url(query=[('a', 'b'), ('c', 1)])\n        self.assertEqual('/get?a=b&c=1', url)\n\n    def test_add_static(self):\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__),\n                                       name='static')\n        route2 = self.router['static']\n        url = route2.url(filename='/dir/a.txt')\n        self.assertEqual('/st/dir/a.txt', url)\n        self.assertIs(route, route2)\n\n    def test_plain_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/path', handler, name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_dynamic_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{name}', handler, name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_static_not_match(self):\n        self.router.add_static('/pre', os.path.dirname(aiohttp.__file__),\n                               name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_dynamic_with_trailing_slash(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{name}/', handler, name='name')\n        route = self.router['name']\n        self.assertEqual({'name': 'John'}, route.match('/get/John/'))\n\n    def test_len(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertEqual(2, len(self.router))\n\n    def test_iter(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertEqual({'name1', 'name2'}, set(iter(self.router)))\n\n    def test_contains(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertIn('name1', self.router)\n        self.assertNotIn('name3', self.router)\n\n    def test_plain_repr(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/path', handler, name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<PlainRoute 'name' \\[GET\\] /get/path\")\n\n    def test_dynamic_repr(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{path}', handler, name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<DynamicRoute 'name' \\[GET\\] /get/{path}\")\n\n    def test_static_repr(self):\n        self.router.add_static('/get', os.path.dirname(aiohttp.__file__),\n                               name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<StaticRoute 'name' \\[GET\\] /get/\")\n\n    def test_static_adds_slash(self):\n        route = self.router.add_static('/prefix',\n                                       os.path.dirname(aiohttp.__file__))\n        self.assertEqual('/prefix/', route._prefix)\n\n    def test_static_dont_add_trailing_slash(self):\n        route = self.router.add_static('/prefix/',\n                                       os.path.dirname(aiohttp.__file__))\n        self.assertEqual('/prefix/', route._prefix)\n\n    def test_add_route_with_re(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:\\d+}', handler)\n\n        req = self.make_request('GET', '/handler/1234')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234'}, info)\n\n        self.router.add_route('GET', r'/handler/{name}.html', handler)\n        req = self.make_request('GET', '/handler/test.html')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertEqual({'name': 'test'}, info)\n\n    def test_add_route_with_re_and_slashes(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:[^/]+/?}', handler)\n        req = self.make_request('GET', '/handler/1234/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234/'}, info)\n\n        self.router.add_route('GET', r'/handler/{to:.+}', handler)\n        req = self.make_request('GET', '/handler/1234/5/6/7')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234/5/6/7'}, info)\n\n    def test_add_route_with_re_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:\\d+}', handler)\n\n        req = self.make_request('GET', '/handler/tail')\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n        with self.assertRaises(HTTPNotFound):\n            self.loop.run_until_complete(match_info.handler(req))\n\n    def test_add_route_with_re_including_slashes(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:.+}/tail', handler)\n        req = self.make_request('GET', '/handler/re/with/slashes/tail')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': 're/with/slashes'}, info)\n\n    def test_add_route_with_invalid_re(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError) as ctx:\n            self.router.add_route('GET', r'/handler/{to:+++}', handler)\n        s = str(ctx.exception)\n        self.assertTrue(s.startswith(\n            \"Bad pattern '\\/handler\\/(?P<to>+++)': nothing to repeat\"), s)\n        self.assertIsNone(ctx.exception.__cause__)\n\n    def test_route_dynamic_with_regex_spec(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{num:^\\d+}', handler,\n                                      name='name')\n\n        url = route.url(parts={'num': '123'})\n        self.assertEqual('/get/123', url)\n\n    def test_route_dynamic_with_regex_spec_and_trailing_slash(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{num:^\\d+}/', handler,\n                                      name='name')\n\n        url = route.url(parts={'num': '123'})\n        self.assertEqual('/get/123/', url)\n\n    def test_route_dynamic_with_regex(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', r'/{one}/{two:.+}', handler)\n\n        url = route.url(parts={'one': 1, 'two': 2})\n        self.assertEqual('/1/2', url)\n\n    def test_regular_match_info(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/get/{name}', handler)\n\n            req = self.make_request('GET', '/get/john')\n            match_info = yield from self.router.resolve(req)\n            self.maxDiff = None\n            self.assertRegex(repr(match_info),\n                             \"<MatchInfo {'name': 'john'}: <DynamicRoute.+>>\")\n\n        self.loop.run_until_complete(go())\n\n    def test_not_found_repr(self):\n\n        @asyncio.coroutine\n        def go():\n            req = self.make_request('POST', '/path/to')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(\"<MatchInfo: not found>\", repr(match_info))\n\n        self.loop.run_until_complete(go())\n\n    def test_not_allowed_repr(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/path/to', handler)\n\n            handler2 = self.make_handler()\n            self.router.add_route('POST', '/path/to', handler2)\n\n            req = self.make_request('PUT', '/path/to')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(\"<MatchInfo: method PUT is not allowed \"\n                             \"(allowed methods: GET, POST>\", repr(match_info))\n\n        self.loop.run_until_complete(go())\n\n    def test_default_expect_handler(self):\n        route = self.router.add_route('GET', '/', self.make_handler())\n        self.assertIs(route._expect_handler, _defaultExpectHandler)\n\n    def test_custom_expect_handler_plain(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            pass\n\n        route = self.router.add_route(\n            'GET', '/', self.make_handler(), expect_handler=handler)\n        self.assertIs(route._expect_handler, handler)\n        self.assertIsInstance(route, PlainRoute)\n\n    def test_custom_expect_handler_dynamic(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            pass\n\n        route = self.router.add_route(\n            'GET', '/get/{name}', self.make_handler(), expect_handler=handler)\n        self.assertIs(route._expect_handler, handler)\n        self.assertIsInstance(route, DynamicRoute)\n\n    def test_expect_handler_non_coroutine(self):\n\n        def handler(request):\n            pass\n\n        self.assertRaises(\n            AssertionError, self.router.add_route,\n            'GET', '/', self.make_handler(), expect_handler=handler)\n\n    def test_dynamic_match_non_ascii(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{var}', handler)\n            req = self.make_request(\n                'GET',\n                '/%D1%80%D1%83%D1%81%20%D1%82%D0%B5%D0%BA%D1%81%D1%82')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'var': 'рус текст'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_with_static_part(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{name}.html', handler)\n            req = self.make_request('GET', '/file.html')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'name': 'file'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_two_part2(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{name}.{ext}', handler)\n            req = self.make_request('GET', '/file.html')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'name': 'file', 'ext': 'html'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_unquoted_path(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{path}/{subpath}', handler)\n            resource_id = 'my%2Fpath%7Cwith%21some%25strange%24characters'\n            req = self.make_request('GET', '/path/{0}'.format(resource_id))\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(match_info, {\n                'path': 'path',\n                'subpath': unquote(resource_id)\n            })\n\n        self.loop.run_until_complete(go())\n\n    def test_add_route_not_started_with_slash(self):\n        with self.assertRaises(ValueError):\n            handler = self.make_handler()\n            self.router.add_route('GET', 'invalid_path', handler)\n\n    def test_add_route_invalid_method(self):\n        with self.assertRaises(ValueError):\n            handler = self.make_handler()\n            self.router.add_route('INVALID_METHOD', '/path', handler)\n\n    def test_static_handle_eof(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            m_os.sendfile.return_value = 0\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertTrue(fut.done())\n            self.assertIsNone(fut.result())\n            self.assertFalse(loop.add_writer.called)\n            self.assertFalse(loop.remove_writer.called)\n\n    def test_static_handle_again(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            m_os.sendfile.side_effect = BlockingIOError()\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertFalse(fut.done())\n            loop.add_writer.assert_called_with(out_fd, route._sendfile_cb,\n                                               fut, out_fd, in_fd, 0, 100,\n                                               loop, True)\n            self.assertFalse(loop.remove_writer.called)\n\n    def test_static_handle_exception(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            exc = OSError()\n            m_os.sendfile.side_effect = exc\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertTrue(fut.done())\n            self.assertIs(exc, fut.exception())\n            self.assertFalse(loop.add_writer.called)\n            self.assertFalse(loop.remove_writer.called)\n\n    def fill_routes(self):\n        route1 = self.router.add_route('GET', '/plain', self.make_handler())\n        route2 = self.router.add_route('GET', '/variable/{name}',\n                                       self.make_handler())\n        route3 = self.router.add_static('/static',\n                                        os.path.dirname(aiohttp.__file__))\n        return route1, route2, route3\n\n    def test_routes_view_len(self):\n        self.fill_routes()\n        self.assertEqual(3, len(self.router.routes()))\n\n    def test_routes_view_iter(self):\n        routes = self.fill_routes()\n        self.assertEqual(list(routes), list(self.router.routes()))\n\n    def test_routes_view_contains(self):\n        routes = self.fill_routes()\n        for route in routes:\n            self.assertIn(route, self.router.routes())\n\n    def test_routes_abc(self):\n        self.assertIsInstance(self.router.routes(), Sized)\n        self.assertIsInstance(self.router.routes(), Iterable)\n        self.assertIsInstance(self.router.routes(), Container)\n",
            "new_file_content": "import asyncio\nimport os\nimport unittest\nfrom collections.abc import Sized, Container, Iterable\nfrom unittest import mock\nfrom urllib.parse import unquote\nimport aiohttp.web\nfrom aiohttp import hdrs\nfrom aiohttp.web import (UrlDispatcher, Request, Response,\n                         HTTPMethodNotAllowed, HTTPNotFound)\nfrom aiohttp.multidict import CIMultiDict\nfrom aiohttp.protocol import HttpVersion, RawRequestMessage\nfrom aiohttp.web_urldispatcher import (_defaultExpectHandler,\n                                       DynamicRoute,\n                                       PlainRoute,\n                                       SystemRoute)\n\n\nclass TestUrlDispatcher(unittest.TestCase):\n\n    def setUp(self):\n        self.loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(None)\n        self.router = UrlDispatcher()\n\n    def tearDown(self):\n        self.loop.close()\n\n    def make_request(self, method, path):\n        self.app = mock.Mock()\n        message = RawRequestMessage(method, path, HttpVersion(1, 1),\n                                    CIMultiDict(), False, False)\n        self.payload = mock.Mock()\n        self.transport = mock.Mock()\n        self.reader = mock.Mock()\n        self.writer = mock.Mock()\n        req = Request(self.app, message, self.payload,\n                      self.transport, self.reader, self.writer)\n        return req\n\n    def make_handler(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            return Response(request)  # pragma: no cover\n\n        return handler\n\n    def test_system_route(self):\n        route = SystemRoute(201, 'test')\n        self.assertIsNone(route.match('any'))\n        with self.assertRaises(RuntimeError):\n            route.url()\n        self.assertEqual(\"<SystemRoute 201: test>\", repr(route))\n        self.assertEqual(201, route.status)\n        self.assertEqual('test', route.reason)\n\n    def test_register_route(self):\n        handler = self.make_handler()\n        route = PlainRoute('GET', handler, 'test', '/handler/to/path')\n        self.router.register_route(route)\n\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(route, info.route)\n        self.assertIs(handler, info.handler)\n        self.assertEqual(info.route.name, 'test')\n\n    def test_register_route_checks(self):\n        self.assertRaises(\n            AssertionError, self.router.register_route, object())\n\n        handler = self.make_handler()\n        route = PlainRoute('GET', handler, 'test', '/handler/to/path')\n        self.router.register_route(route)\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n        route = PlainRoute('GET', handler, '1bad name', '/handler/to/path')\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n        route = PlainRoute('GET', handler, 'return', '/handler/to/path')\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n    def test_add_route_root(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/', handler)\n        req = self.make_request('GET', '/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_route_simple(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path', handler)\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_with_matchdict(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/{to}', handler)\n        req = self.make_request('GET', '/handler/tail')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': 'tail'}, info)\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_with_name(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path', handler,\n                              name='name')\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual('name', info.route.name)\n\n    def test_add_with_tailing_slash(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path/', handler)\n        req = self.make_request('GET', '/handler/to/path/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({}, info)\n        self.assertIs(handler, info.handler)\n\n    def test_add_invalid_path(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('GET', '/{/', handler)\n\n    def test_add_url_invalid1(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id', handler)\n\n    def test_add_url_invalid2(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id{}}', handler)\n\n    def test_add_url_invalid3(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id{}', handler)\n\n    def test_add_url_invalid4(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id\"}', handler)\n\n    def test_add_url_escaping(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/+$', handler)\n\n        req = self.make_request('GET', '/+$')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertIs(handler, info.handler)\n\n    def test_any_method(self):\n        handler = self.make_handler()\n        route = self.router.add_route(hdrs.METH_ANY, '/', handler)\n\n        req = self.make_request('GET', '/')\n        info1 = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info1)\n        self.assertIs(route, info1.route)\n\n        req = self.make_request('POST', '/')\n        info2 = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info2)\n\n        self.assertIs(info1.route, info2.route)\n\n    def test_match_second_result_in_table(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/h1', handler1)\n        self.router.add_route('POST', '/h2', handler2)\n        req = self.make_request('POST', '/h2')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({}, info)\n        self.assertIs(handler2, info.handler)\n\n    def test_raise_method_not_allowed(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/', handler1)\n        self.router.add_route('POST', '/', handler2)\n        req = self.make_request('PUT', '/')\n\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n\n        with self.assertRaises(HTTPMethodNotAllowed) as ctx:\n            self.loop.run_until_complete(match_info.handler(req))\n\n        exc = ctx.exception\n        self.assertEqual('PUT', exc.method)\n        self.assertEqual(405, exc.status)\n        self.assertEqual({'POST', 'GET'}, exc.allowed_methods)\n\n    def test_raise_method_not_found(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/a', handler)\n        req = self.make_request('GET', '/b')\n\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n\n        with self.assertRaises(HTTPNotFound) as ctx:\n            self.loop.run_until_complete(match_info.handler(req))\n\n        exc = ctx.exception\n        self.assertEqual(404, exc.status)\n\n    def test_double_add_url_with_the_same_name(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/get', handler1, name='name')\n\n        regexp = (\"Duplicate 'name', already handled by\")\n        with self.assertRaisesRegex(ValueError, regexp):\n            self.router.add_route('GET', '/get_other', handler2, name='name')\n\n    def test_route_plain(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get', handler, name='name')\n        route2 = self.router['name']\n        url = route2.url()\n        self.assertEqual('/get', url)\n        self.assertIs(route, route2)\n\n    def test_route_unknown_route_name(self):\n        with self.assertRaises(KeyError):\n            self.router['unknown']\n\n    def test_route_dynamic(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{name}', handler,\n                                      name='name')\n\n        route2 = self.router['name']\n        url = route2.url(parts={'name': 'John'})\n        self.assertEqual('/get/John', url)\n        self.assertIs(route, route2)\n\n    def test_route_with_qs(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get', handler, name='name')\n\n        url = self.router['name'].url(query=[('a', 'b'), ('c', 1)])\n        self.assertEqual('/get?a=b&c=1', url)\n\n    def test_add_static(self):\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__),\n                                       name='static')\n        route2 = self.router['static']\n        url = route2.url(filename='/dir/a.txt')\n        self.assertEqual('/st/dir/a.txt', url)\n        self.assertIs(route, route2)\n\n    def test_plain_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/path', handler, name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_dynamic_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{name}', handler, name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_static_not_match(self):\n        self.router.add_static('/pre', os.path.dirname(aiohttp.__file__),\n                               name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_dynamic_with_trailing_slash(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{name}/', handler, name='name')\n        route = self.router['name']\n        self.assertEqual({'name': 'John'}, route.match('/get/John/'))\n\n    def test_len(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertEqual(2, len(self.router))\n\n    def test_iter(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertEqual({'name1', 'name2'}, set(iter(self.router)))\n\n    def test_contains(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertIn('name1', self.router)\n        self.assertNotIn('name3', self.router)\n\n    def test_plain_repr(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/path', handler, name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<PlainRoute 'name' \\[GET\\] /get/path\")\n\n    def test_dynamic_repr(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{path}', handler, name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<DynamicRoute 'name' \\[GET\\] /get/{path}\")\n\n    def test_static_repr(self):\n        self.router.add_static('/get', os.path.dirname(aiohttp.__file__),\n                               name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<StaticRoute 'name' \\[GET\\] /get/\")\n\n    def test_static_adds_slash(self):\n        route = self.router.add_static('/prefix',\n                                       os.path.dirname(aiohttp.__file__))\n        self.assertEqual('/prefix/', route._prefix)\n\n    def test_static_dont_add_trailing_slash(self):\n        route = self.router.add_static('/prefix/',\n                                       os.path.dirname(aiohttp.__file__))\n        self.assertEqual('/prefix/', route._prefix)\n\n    def test_add_route_with_re(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:\\d+}', handler)\n\n        req = self.make_request('GET', '/handler/1234')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234'}, info)\n\n        self.router.add_route('GET', r'/handler/{name}.html', handler)\n        req = self.make_request('GET', '/handler/test.html')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertEqual({'name': 'test'}, info)\n\n    def test_add_route_with_re_and_slashes(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:[^/]+/?}', handler)\n        req = self.make_request('GET', '/handler/1234/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234/'}, info)\n\n        self.router.add_route('GET', r'/handler/{to:.+}', handler)\n        req = self.make_request('GET', '/handler/1234/5/6/7')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234/5/6/7'}, info)\n\n    def test_add_route_with_re_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:\\d+}', handler)\n\n        req = self.make_request('GET', '/handler/tail')\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n        with self.assertRaises(HTTPNotFound):\n            self.loop.run_until_complete(match_info.handler(req))\n\n    def test_add_route_with_re_including_slashes(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:.+}/tail', handler)\n        req = self.make_request('GET', '/handler/re/with/slashes/tail')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': 're/with/slashes'}, info)\n\n    def test_add_route_with_invalid_re(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError) as ctx:\n            self.router.add_route('GET', r'/handler/{to:+++}', handler)\n        s = str(ctx.exception)\n        self.assertTrue(s.startswith(\n            \"Bad pattern '\\/handler\\/(?P<to>+++)': nothing to repeat\"), s)\n        self.assertIsNone(ctx.exception.__cause__)\n\n    def test_route_dynamic_with_regex_spec(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{num:^\\d+}', handler,\n                                      name='name')\n\n        url = route.url(parts={'num': '123'})\n        self.assertEqual('/get/123', url)\n\n    def test_route_dynamic_with_regex_spec_and_trailing_slash(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{num:^\\d+}/', handler,\n                                      name='name')\n\n        url = route.url(parts={'num': '123'})\n        self.assertEqual('/get/123/', url)\n\n    def test_route_dynamic_with_regex(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', r'/{one}/{two:.+}', handler)\n\n        url = route.url(parts={'one': 1, 'two': 2})\n        self.assertEqual('/1/2', url)\n\n    def test_regular_match_info(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/get/{name}', handler)\n\n            req = self.make_request('GET', '/get/john')\n            match_info = yield from self.router.resolve(req)\n            self.maxDiff = None\n            self.assertRegex(repr(match_info),\n                             \"<MatchInfo {'name': 'john'}: <DynamicRoute.+>>\")\n\n        self.loop.run_until_complete(go())\n\n    def test_not_found_repr(self):\n\n        @asyncio.coroutine\n        def go():\n            req = self.make_request('POST', '/path/to')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(\"<MatchInfo: not found>\", repr(match_info))\n\n        self.loop.run_until_complete(go())\n\n    def test_not_allowed_repr(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/path/to', handler)\n\n            handler2 = self.make_handler()\n            self.router.add_route('POST', '/path/to', handler2)\n\n            req = self.make_request('PUT', '/path/to')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(\"<MatchInfo: method PUT is not allowed \"\n                             \"(allowed methods: GET, POST>\", repr(match_info))\n\n        self.loop.run_until_complete(go())\n\n    def test_default_expect_handler(self):\n        route = self.router.add_route('GET', '/', self.make_handler())\n        self.assertIs(route._expect_handler, _defaultExpectHandler)\n\n    def test_custom_expect_handler_plain(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            pass\n\n        route = self.router.add_route(\n            'GET', '/', self.make_handler(), expect_handler=handler)\n        self.assertIs(route._expect_handler, handler)\n        self.assertIsInstance(route, PlainRoute)\n\n    def test_custom_expect_handler_dynamic(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            pass\n\n        route = self.router.add_route(\n            'GET', '/get/{name}', self.make_handler(), expect_handler=handler)\n        self.assertIs(route._expect_handler, handler)\n        self.assertIsInstance(route, DynamicRoute)\n\n    def test_expect_handler_non_coroutine(self):\n\n        def handler(request):\n            pass\n\n        self.assertRaises(\n            AssertionError, self.router.add_route,\n            'GET', '/', self.make_handler(), expect_handler=handler)\n\n    def test_dynamic_match_non_ascii(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{var}', handler)\n            req = self.make_request(\n                'GET',\n                '/%D1%80%D1%83%D1%81%20%D1%82%D0%B5%D0%BA%D1%81%D1%82')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'var': 'рус текст'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_with_static_part(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{name}.html', handler)\n            req = self.make_request('GET', '/file.html')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'name': 'file'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_two_part2(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{name}.{ext}', handler)\n            req = self.make_request('GET', '/file.html')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'name': 'file', 'ext': 'html'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_unquoted_path(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{path}/{subpath}', handler)\n            resource_id = 'my%2Fpath%7Cwith%21some%25strange%24characters'\n            req = self.make_request('GET', '/path/{0}'.format(resource_id))\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(match_info, {\n                'path': 'path',\n                'subpath': unquote(resource_id)\n            })\n\n        self.loop.run_until_complete(go())\n\n    def test_add_route_not_started_with_slash(self):\n        with self.assertRaises(ValueError):\n            handler = self.make_handler()\n            self.router.add_route('GET', 'invalid_path', handler)\n\n    def test_add_route_invalid_method(self):\n        with self.assertRaises(ValueError):\n            handler = self.make_handler()\n            self.router.add_route('INVALID_METHOD', '/path', handler)\n\n    def test_static_handle_eof(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            m_os.sendfile.return_value = 0\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertTrue(fut.done())\n            self.assertIsNone(fut.result())\n            self.assertFalse(loop.add_writer.called)\n            self.assertFalse(loop.remove_writer.called)\n\n    def test_static_handle_again(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            m_os.sendfile.side_effect = BlockingIOError()\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertFalse(fut.done())\n            loop.add_writer.assert_called_with(out_fd, route._sendfile_cb,\n                                               fut, out_fd, in_fd, 0, 100,\n                                               loop, True)\n            self.assertFalse(loop.remove_writer.called)\n\n    def test_static_handle_exception(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            exc = OSError()\n            m_os.sendfile.side_effect = exc\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertTrue(fut.done())\n            self.assertIs(exc, fut.exception())\n            self.assertFalse(loop.add_writer.called)\n            self.assertFalse(loop.remove_writer.called)\n\n    def fill_routes(self):\n        route1 = self.router.add_route('GET', '/plain', self.make_handler())\n        route2 = self.router.add_route('GET', '/variable/{name}',\n                                       self.make_handler())\n        route3 = self.router.add_static('/static',\n                                        os.path.dirname(aiohttp.__file__))\n        return route1, route2, route3\n\n    def test_routes_view_len(self):\n        self.fill_routes()\n        self.assertEqual(3, len(self.router.routes()))\n\n    def test_routes_view_iter(self):\n        routes = self.fill_routes()\n        self.assertEqual(list(routes), list(self.router.routes()))\n\n    def test_routes_view_contains(self):\n        routes = self.fill_routes()\n        for route in routes:\n            self.assertIn(route, self.router.routes())\n\n    def test_routes_abc(self):\n        self.assertIsInstance(self.router.routes(), Sized)\n        self.assertIsInstance(self.router.routes(), Iterable)\n        self.assertIsInstance(self.router.routes(), Container)\n",
            "header": {
                "file": {
                    "path": "tests/test_urldispatch.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "0a79d0b7",
                "new_commit_hash": "fd5e6848",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tests/test_urldispatch.py"
            },
            "plus_file": {
                "path": "b/tests/test_urldispatch.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 77,
                            "length": 6
                        },
                        "new_range": {
                            "start": 77,
                            "length": 12
                        },
                        "section": "class TestUrlDispatcher(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        self.router.register_route(route)",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertRaises(ValueError, self.router.register_route, route)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        route = PlainRoute('GET', handler, '1bad name', '/handler/to/path')",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertRaises(ValueError, self.router.register_route, route)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        route = PlainRoute('GET', handler, 'return', '/handler/to/path')",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertRaises(ValueError, self.router.register_route, route)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_add_route_root(self):",
                                "type": "context"
                            },
                            {
                                "content": "        handler = self.make_handler()",
                                "type": "context"
                            },
                            {
                                "content": "        self.router.add_route('GET', '/', handler)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tests/test_urldispatch.py",
                            "type": "class",
                            "name": "TestUrlDispatcher",
                            "content": "class TestUrlDispatcher(unittest.TestCase):\n\n    def setUp(self):\n        self.loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(None)\n        self.router = UrlDispatcher()\n\n    def tearDown(self):\n        self.loop.close()\n\n    def make_request(self, method, path):\n        self.app = mock.Mock()\n        message = RawRequestMessage(method, path, HttpVersion(1, 1),\n                                    CIMultiDict(), False, False)\n        self.payload = mock.Mock()\n        self.transport = mock.Mock()\n        self.reader = mock.Mock()\n        self.writer = mock.Mock()\n        req = Request(self.app, message, self.payload,\n                      self.transport, self.reader, self.writer)\n        return req\n\n    def make_handler(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            return Response(request)  # pragma: no cover\n\n        return handler\n\n    def test_system_route(self):\n        route = SystemRoute(201, 'test')\n        self.assertIsNone(route.match('any'))\n        with self.assertRaises(RuntimeError):\n            route.url()\n        self.assertEqual(\"<SystemRoute 201: test>\", repr(route))\n        self.assertEqual(201, route.status)\n        self.assertEqual('test', route.reason)\n\n    def test_register_route(self):\n        handler = self.make_handler()\n        route = PlainRoute('GET', handler, 'test', '/handler/to/path')\n        self.router.register_route(route)\n\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(route, info.route)\n        self.assertIs(handler, info.handler)\n        self.assertEqual(info.route.name, 'test')\n\n    def test_register_route_checks(self):\n        self.assertRaises(\n            AssertionError, self.router.register_route, object())\n\n        handler = self.make_handler()\n        route = PlainRoute('GET', handler, 'test', '/handler/to/path')\n        self.router.register_route(route)\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n        route = PlainRoute('GET', handler, '1bad name', '/handler/to/path')\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n        route = PlainRoute('GET', handler, 'return', '/handler/to/path')\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n    def test_add_route_root(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/', handler)\n        req = self.make_request('GET', '/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_route_simple(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path', handler)\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_with_matchdict(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/{to}', handler)\n        req = self.make_request('GET', '/handler/tail')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': 'tail'}, info)\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_with_name(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path', handler,\n                              name='name')\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual('name', info.route.name)\n\n    def test_add_with_tailing_slash(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path/', handler)\n        req = self.make_request('GET', '/handler/to/path/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({}, info)\n        self.assertIs(handler, info.handler)\n\n    def test_add_invalid_path(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('GET', '/{/', handler)\n\n    def test_add_url_invalid1(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id', handler)\n\n    def test_add_url_invalid2(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id{}}', handler)\n\n    def test_add_url_invalid3(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id{}', handler)\n\n    def test_add_url_invalid4(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id\"}', handler)\n\n    def test_add_url_escaping(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/+$', handler)\n\n        req = self.make_request('GET', '/+$')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertIs(handler, info.handler)\n\n    def test_any_method(self):\n        handler = self.make_handler()\n        route = self.router.add_route(hdrs.METH_ANY, '/', handler)\n\n        req = self.make_request('GET', '/')\n        info1 = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info1)\n        self.assertIs(route, info1.route)\n\n        req = self.make_request('POST', '/')\n        info2 = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info2)\n\n        self.assertIs(info1.route, info2.route)\n\n    def test_match_second_result_in_table(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/h1', handler1)\n        self.router.add_route('POST', '/h2', handler2)\n        req = self.make_request('POST', '/h2')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({}, info)\n        self.assertIs(handler2, info.handler)\n\n    def test_raise_method_not_allowed(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/', handler1)\n        self.router.add_route('POST', '/', handler2)\n        req = self.make_request('PUT', '/')\n\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n\n        with self.assertRaises(HTTPMethodNotAllowed) as ctx:\n            self.loop.run_until_complete(match_info.handler(req))\n\n        exc = ctx.exception\n        self.assertEqual('PUT', exc.method)\n        self.assertEqual(405, exc.status)\n        self.assertEqual({'POST', 'GET'}, exc.allowed_methods)\n\n    def test_raise_method_not_found(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/a', handler)\n        req = self.make_request('GET', '/b')\n\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n\n        with self.assertRaises(HTTPNotFound) as ctx:\n            self.loop.run_until_complete(match_info.handler(req))\n\n        exc = ctx.exception\n        self.assertEqual(404, exc.status)\n\n    def test_double_add_url_with_the_same_name(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/get', handler1, name='name')\n\n        regexp = (\"Duplicate 'name', already handled by\")\n        with self.assertRaisesRegex(ValueError, regexp):\n            self.router.add_route('GET', '/get_other', handler2, name='name')\n\n    def test_route_plain(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get', handler, name='name')\n        route2 = self.router['name']\n        url = route2.url()\n        self.assertEqual('/get', url)\n        self.assertIs(route, route2)\n\n    def test_route_unknown_route_name(self):\n        with self.assertRaises(KeyError):\n            self.router['unknown']\n\n    def test_route_dynamic(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{name}', handler,\n                                      name='name')\n\n        route2 = self.router['name']\n        url = route2.url(parts={'name': 'John'})\n        self.assertEqual('/get/John', url)\n        self.assertIs(route, route2)\n\n    def test_route_with_qs(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get', handler, name='name')\n\n        url = self.router['name'].url(query=[('a', 'b'), ('c', 1)])\n        self.assertEqual('/get?a=b&c=1', url)\n\n    def test_add_static(self):\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__),\n                                       name='static')\n        route2 = self.router['static']\n        url = route2.url(filename='/dir/a.txt')\n        self.assertEqual('/st/dir/a.txt', url)\n        self.assertIs(route, route2)\n\n    def test_plain_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/path', handler, name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_dynamic_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{name}', handler, name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_static_not_match(self):\n        self.router.add_static('/pre', os.path.dirname(aiohttp.__file__),\n                               name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_dynamic_with_trailing_slash(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{name}/', handler, name='name')\n        route = self.router['name']\n        self.assertEqual({'name': 'John'}, route.match('/get/John/'))\n\n    def test_len(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertEqual(2, len(self.router))\n\n    def test_iter(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertEqual({'name1', 'name2'}, set(iter(self.router)))\n\n    def test_contains(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertIn('name1', self.router)\n        self.assertNotIn('name3', self.router)\n\n    def test_plain_repr(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/path', handler, name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<PlainRoute 'name' \\[GET\\] /get/path\")\n\n    def test_dynamic_repr(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{path}', handler, name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<DynamicRoute 'name' \\[GET\\] /get/{path}\")\n\n    def test_static_repr(self):\n        self.router.add_static('/get', os.path.dirname(aiohttp.__file__),\n                               name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<StaticRoute 'name' \\[GET\\] /get/\")\n\n    def test_static_adds_slash(self):\n        route = self.router.add_static('/prefix',\n                                       os.path.dirname(aiohttp.__file__))\n        self.assertEqual('/prefix/', route._prefix)\n\n    def test_static_dont_add_trailing_slash(self):\n        route = self.router.add_static('/prefix/',\n                                       os.path.dirname(aiohttp.__file__))\n        self.assertEqual('/prefix/', route._prefix)\n\n    def test_add_route_with_re(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:\\d+}', handler)\n\n        req = self.make_request('GET', '/handler/1234')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234'}, info)\n\n        self.router.add_route('GET', r'/handler/{name}.html', handler)\n        req = self.make_request('GET', '/handler/test.html')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertEqual({'name': 'test'}, info)\n\n    def test_add_route_with_re_and_slashes(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:[^/]+/?}', handler)\n        req = self.make_request('GET', '/handler/1234/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234/'}, info)\n\n        self.router.add_route('GET', r'/handler/{to:.+}', handler)\n        req = self.make_request('GET', '/handler/1234/5/6/7')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234/5/6/7'}, info)\n\n    def test_add_route_with_re_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:\\d+}', handler)\n\n        req = self.make_request('GET', '/handler/tail')\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n        with self.assertRaises(HTTPNotFound):\n            self.loop.run_until_complete(match_info.handler(req))\n\n    def test_add_route_with_re_including_slashes(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:.+}/tail', handler)\n        req = self.make_request('GET', '/handler/re/with/slashes/tail')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': 're/with/slashes'}, info)\n\n    def test_add_route_with_invalid_re(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError) as ctx:\n            self.router.add_route('GET', r'/handler/{to:+++}', handler)\n        s = str(ctx.exception)\n        self.assertTrue(s.startswith(\n            \"Bad pattern '\\/handler\\/(?P<to>+++)': nothing to repeat\"), s)\n        self.assertIsNone(ctx.exception.__cause__)\n\n    def test_route_dynamic_with_regex_spec(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{num:^\\d+}', handler,\n                                      name='name')\n\n        url = route.url(parts={'num': '123'})\n        self.assertEqual('/get/123', url)\n\n    def test_route_dynamic_with_regex_spec_and_trailing_slash(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{num:^\\d+}/', handler,\n                                      name='name')\n\n        url = route.url(parts={'num': '123'})\n        self.assertEqual('/get/123/', url)\n\n    def test_route_dynamic_with_regex(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', r'/{one}/{two:.+}', handler)\n\n        url = route.url(parts={'one': 1, 'two': 2})\n        self.assertEqual('/1/2', url)\n\n    def test_regular_match_info(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/get/{name}', handler)\n\n            req = self.make_request('GET', '/get/john')\n            match_info = yield from self.router.resolve(req)\n            self.maxDiff = None\n            self.assertRegex(repr(match_info),\n                             \"<MatchInfo {'name': 'john'}: <DynamicRoute.+>>\")\n\n        self.loop.run_until_complete(go())\n\n    def test_not_found_repr(self):\n\n        @asyncio.coroutine\n        def go():\n            req = self.make_request('POST', '/path/to')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(\"<MatchInfo: not found>\", repr(match_info))\n\n        self.loop.run_until_complete(go())\n\n    def test_not_allowed_repr(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/path/to', handler)\n\n            handler2 = self.make_handler()\n            self.router.add_route('POST', '/path/to', handler2)\n\n            req = self.make_request('PUT', '/path/to')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(\"<MatchInfo: method PUT is not allowed \"\n                             \"(allowed methods: GET, POST>\", repr(match_info))\n\n        self.loop.run_until_complete(go())\n\n    def test_default_expect_handler(self):\n        route = self.router.add_route('GET', '/', self.make_handler())\n        self.assertIs(route._expect_handler, _defaultExpectHandler)\n\n    def test_custom_expect_handler_plain(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            pass\n\n        route = self.router.add_route(\n            'GET', '/', self.make_handler(), expect_handler=handler)\n        self.assertIs(route._expect_handler, handler)\n        self.assertIsInstance(route, PlainRoute)\n\n    def test_custom_expect_handler_dynamic(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            pass\n\n        route = self.router.add_route(\n            'GET', '/get/{name}', self.make_handler(), expect_handler=handler)\n        self.assertIs(route._expect_handler, handler)\n        self.assertIsInstance(route, DynamicRoute)\n\n    def test_expect_handler_non_coroutine(self):\n\n        def handler(request):\n            pass\n\n        self.assertRaises(\n            AssertionError, self.router.add_route,\n            'GET', '/', self.make_handler(), expect_handler=handler)\n\n    def test_dynamic_match_non_ascii(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{var}', handler)\n            req = self.make_request(\n                'GET',\n                '/%D1%80%D1%83%D1%81%20%D1%82%D0%B5%D0%BA%D1%81%D1%82')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'var': 'рус текст'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_with_static_part(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{name}.html', handler)\n            req = self.make_request('GET', '/file.html')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'name': 'file'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_two_part2(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{name}.{ext}', handler)\n            req = self.make_request('GET', '/file.html')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'name': 'file', 'ext': 'html'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_unquoted_path(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{path}/{subpath}', handler)\n            resource_id = 'my%2Fpath%7Cwith%21some%25strange%24characters'\n            req = self.make_request('GET', '/path/{0}'.format(resource_id))\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(match_info, {\n                'path': 'path',\n                'subpath': unquote(resource_id)\n            })\n\n        self.loop.run_until_complete(go())\n\n    def test_add_route_not_started_with_slash(self):\n        with self.assertRaises(ValueError):\n            handler = self.make_handler()\n            self.router.add_route('GET', 'invalid_path', handler)\n\n    def test_add_route_invalid_method(self):\n        with self.assertRaises(ValueError):\n            handler = self.make_handler()\n            self.router.add_route('INVALID_METHOD', '/path', handler)\n\n    def test_static_handle_eof(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            m_os.sendfile.return_value = 0\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertTrue(fut.done())\n            self.assertIsNone(fut.result())\n            self.assertFalse(loop.add_writer.called)\n            self.assertFalse(loop.remove_writer.called)\n\n    def test_static_handle_again(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            m_os.sendfile.side_effect = BlockingIOError()\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertFalse(fut.done())\n            loop.add_writer.assert_called_with(out_fd, route._sendfile_cb,\n                                               fut, out_fd, in_fd, 0, 100,\n                                               loop, True)\n            self.assertFalse(loop.remove_writer.called)\n\n    def test_static_handle_exception(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            exc = OSError()\n            m_os.sendfile.side_effect = exc\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertTrue(fut.done())\n            self.assertIs(exc, fut.exception())\n            self.assertFalse(loop.add_writer.called)\n            self.assertFalse(loop.remove_writer.called)\n\n    def fill_routes(self):\n        route1 = self.router.add_route('GET', '/plain', self.make_handler())\n        route2 = self.router.add_route('GET', '/variable/{name}',\n                                       self.make_handler())\n        route3 = self.router.add_static('/static',\n                                        os.path.dirname(aiohttp.__file__))\n        return route1, route2, route3\n\n    def test_routes_view_len(self):\n        self.fill_routes()\n        self.assertEqual(3, len(self.router.routes()))\n\n    def test_routes_view_iter(self):\n        routes = self.fill_routes()\n        self.assertEqual(list(routes), list(self.router.routes()))\n\n    def test_routes_view_contains(self):\n        routes = self.fill_routes()\n        for route in routes:\n            self.assertIn(route, self.router.routes())\n\n    def test_routes_abc(self):\n        self.assertIsInstance(self.router.routes(), Sized)\n        self.assertIsInstance(self.router.routes(), Iterable)\n        self.assertIsInstance(self.router.routes(), Container)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 19,
                            "end_lineno": 640,
                            "parent": null
                        },
                        {
                            "file_name": "tests/test_urldispatch.py",
                            "type": "method",
                            "name": "TestUrlDispatcher.test_register_route_checks",
                            "content": "class TestUrlDispatcher(unittest.TestCase):\n\n    def setUp(self):\n        self.loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(None)\n        self.router = UrlDispatcher()\n\n    def tearDown(self):\n        self.loop.close()\n\n    def make_request(self, method, path):\n        self.app = mock.Mock()\n        message = RawRequestMessage(method, path, HttpVersion(1, 1),\n                                    CIMultiDict(), False, False)\n        self.payload = mock.Mock()\n        self.transport = mock.Mock()\n        self.reader = mock.Mock()\n        self.writer = mock.Mock()\n        req = Request(self.app, message, self.payload,\n                      self.transport, self.reader, self.writer)\n        return req\n\n    def make_handler(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            return Response(request)  # pragma: no cover\n\n        return handler\n\n    def test_system_route(self):\n        route = SystemRoute(201, 'test')\n        self.assertIsNone(route.match('any'))\n        with self.assertRaises(RuntimeError):\n            route.url()\n        self.assertEqual(\"<SystemRoute 201: test>\", repr(route))\n        self.assertEqual(201, route.status)\n        self.assertEqual('test', route.reason)\n\n    def test_register_route(self):\n        handler = self.make_handler()\n        route = PlainRoute('GET', handler, 'test', '/handler/to/path')\n        self.router.register_route(route)\n\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(route, info.route)\n        self.assertIs(handler, info.handler)\n        self.assertEqual(info.route.name, 'test')\n\n    def test_register_route_checks(self):\n        self.assertRaises(\n            AssertionError, self.router.register_route, object())\n\n        handler = self.make_handler()\n        route = PlainRoute('GET', handler, 'test', '/handler/to/path')\n        self.router.register_route(route)\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n        route = PlainRoute('GET', handler, '1bad name', '/handler/to/path')\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n        route = PlainRoute('GET', handler, 'return', '/handler/to/path')\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n    def test_add_route_root(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/', handler)\n        req = self.make_request('GET', '/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_route_simple(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path', handler)\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_with_matchdict(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/{to}', handler)\n        req = self.make_request('GET', '/handler/tail')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': 'tail'}, info)\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_with_name(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path', handler,\n                              name='name')\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual('name', info.route.name)\n\n    def test_add_with_tailing_slash(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path/', handler)\n        req = self.make_request('GET', '/handler/to/path/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({}, info)\n        self.assertIs(handler, info.handler)\n\n    def test_add_invalid_path(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('GET', '/{/', handler)\n\n    def test_add_url_invalid1(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id', handler)\n\n    def test_add_url_invalid2(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id{}}', handler)\n\n    def test_add_url_invalid3(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id{}', handler)\n\n    def test_add_url_invalid4(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id\"}', handler)\n\n    def test_add_url_escaping(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/+$', handler)\n\n        req = self.make_request('GET', '/+$')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertIs(handler, info.handler)\n\n    def test_any_method(self):\n        handler = self.make_handler()\n        route = self.router.add_route(hdrs.METH_ANY, '/', handler)\n\n        req = self.make_request('GET', '/')\n        info1 = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info1)\n        self.assertIs(route, info1.route)\n\n        req = self.make_request('POST', '/')\n        info2 = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info2)\n\n        self.assertIs(info1.route, info2.route)\n\n    def test_match_second_result_in_table(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/h1', handler1)\n        self.router.add_route('POST', '/h2', handler2)\n        req = self.make_request('POST', '/h2')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({}, info)\n        self.assertIs(handler2, info.handler)\n\n    def test_raise_method_not_allowed(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/', handler1)\n        self.router.add_route('POST', '/', handler2)\n        req = self.make_request('PUT', '/')\n\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n\n        with self.assertRaises(HTTPMethodNotAllowed) as ctx:\n            self.loop.run_until_complete(match_info.handler(req))\n\n        exc = ctx.exception\n        self.assertEqual('PUT', exc.method)\n        self.assertEqual(405, exc.status)\n        self.assertEqual({'POST', 'GET'}, exc.allowed_methods)\n\n    def test_raise_method_not_found(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/a', handler)\n        req = self.make_request('GET', '/b')\n\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n\n        with self.assertRaises(HTTPNotFound) as ctx:\n            self.loop.run_until_complete(match_info.handler(req))\n\n        exc = ctx.exception\n        self.assertEqual(404, exc.status)\n\n    def test_double_add_url_with_the_same_name(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/get', handler1, name='name')\n\n        regexp = (\"Duplicate 'name', already handled by\")\n        with self.assertRaisesRegex(ValueError, regexp):\n            self.router.add_route('GET', '/get_other', handler2, name='name')\n\n    def test_route_plain(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get', handler, name='name')\n        route2 = self.router['name']\n        url = route2.url()\n        self.assertEqual('/get', url)\n        self.assertIs(route, route2)\n\n    def test_route_unknown_route_name(self):\n        with self.assertRaises(KeyError):\n            self.router['unknown']\n\n    def test_route_dynamic(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{name}', handler,\n                                      name='name')\n\n        route2 = self.router['name']\n        url = route2.url(parts={'name': 'John'})\n        self.assertEqual('/get/John', url)\n        self.assertIs(route, route2)\n\n    def test_route_with_qs(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get', handler, name='name')\n\n        url = self.router['name'].url(query=[('a', 'b'), ('c', 1)])\n        self.assertEqual('/get?a=b&c=1', url)\n\n    def test_add_static(self):\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__),\n                                       name='static')\n        route2 = self.router['static']\n        url = route2.url(filename='/dir/a.txt')\n        self.assertEqual('/st/dir/a.txt', url)\n        self.assertIs(route, route2)\n\n    def test_plain_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/path', handler, name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_dynamic_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{name}', handler, name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_static_not_match(self):\n        self.router.add_static('/pre', os.path.dirname(aiohttp.__file__),\n                               name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_dynamic_with_trailing_slash(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{name}/', handler, name='name')\n        route = self.router['name']\n        self.assertEqual({'name': 'John'}, route.match('/get/John/'))\n\n    def test_len(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertEqual(2, len(self.router))\n\n    def test_iter(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertEqual({'name1', 'name2'}, set(iter(self.router)))\n\n    def test_contains(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertIn('name1', self.router)\n        self.assertNotIn('name3', self.router)\n\n    def test_plain_repr(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/path', handler, name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<PlainRoute 'name' \\[GET\\] /get/path\")\n\n    def test_dynamic_repr(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{path}', handler, name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<DynamicRoute 'name' \\[GET\\] /get/{path}\")\n\n    def test_static_repr(self):\n        self.router.add_static('/get', os.path.dirname(aiohttp.__file__),\n                               name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<StaticRoute 'name' \\[GET\\] /get/\")\n\n    def test_static_adds_slash(self):\n        route = self.router.add_static('/prefix',\n                                       os.path.dirname(aiohttp.__file__))\n        self.assertEqual('/prefix/', route._prefix)\n\n    def test_static_dont_add_trailing_slash(self):\n        route = self.router.add_static('/prefix/',\n                                       os.path.dirname(aiohttp.__file__))\n        self.assertEqual('/prefix/', route._prefix)\n\n    def test_add_route_with_re(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:\\d+}', handler)\n\n        req = self.make_request('GET', '/handler/1234')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234'}, info)\n\n        self.router.add_route('GET', r'/handler/{name}.html', handler)\n        req = self.make_request('GET', '/handler/test.html')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertEqual({'name': 'test'}, info)\n\n    def test_add_route_with_re_and_slashes(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:[^/]+/?}', handler)\n        req = self.make_request('GET', '/handler/1234/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234/'}, info)\n\n        self.router.add_route('GET', r'/handler/{to:.+}', handler)\n        req = self.make_request('GET', '/handler/1234/5/6/7')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234/5/6/7'}, info)\n\n    def test_add_route_with_re_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:\\d+}', handler)\n\n        req = self.make_request('GET', '/handler/tail')\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n        with self.assertRaises(HTTPNotFound):\n            self.loop.run_until_complete(match_info.handler(req))\n\n    def test_add_route_with_re_including_slashes(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:.+}/tail', handler)\n        req = self.make_request('GET', '/handler/re/with/slashes/tail')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': 're/with/slashes'}, info)\n\n    def test_add_route_with_invalid_re(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError) as ctx:\n            self.router.add_route('GET', r'/handler/{to:+++}', handler)\n        s = str(ctx.exception)\n        self.assertTrue(s.startswith(\n            \"Bad pattern '\\/handler\\/(?P<to>+++)': nothing to repeat\"), s)\n        self.assertIsNone(ctx.exception.__cause__)\n\n    def test_route_dynamic_with_regex_spec(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{num:^\\d+}', handler,\n                                      name='name')\n\n        url = route.url(parts={'num': '123'})\n        self.assertEqual('/get/123', url)\n\n    def test_route_dynamic_with_regex_spec_and_trailing_slash(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{num:^\\d+}/', handler,\n                                      name='name')\n\n        url = route.url(parts={'num': '123'})\n        self.assertEqual('/get/123/', url)\n\n    def test_route_dynamic_with_regex(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', r'/{one}/{two:.+}', handler)\n\n        url = route.url(parts={'one': 1, 'two': 2})\n        self.assertEqual('/1/2', url)\n\n    def test_regular_match_info(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/get/{name}', handler)\n\n            req = self.make_request('GET', '/get/john')\n            match_info = yield from self.router.resolve(req)\n            self.maxDiff = None\n            self.assertRegex(repr(match_info),\n                             \"<MatchInfo {'name': 'john'}: <DynamicRoute.+>>\")\n\n        self.loop.run_until_complete(go())\n\n    def test_not_found_repr(self):\n\n        @asyncio.coroutine\n        def go():\n            req = self.make_request('POST', '/path/to')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(\"<MatchInfo: not found>\", repr(match_info))\n\n        self.loop.run_until_complete(go())\n\n    def test_not_allowed_repr(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/path/to', handler)\n\n            handler2 = self.make_handler()\n            self.router.add_route('POST', '/path/to', handler2)\n\n            req = self.make_request('PUT', '/path/to')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(\"<MatchInfo: method PUT is not allowed \"\n                             \"(allowed methods: GET, POST>\", repr(match_info))\n\n        self.loop.run_until_complete(go())\n\n    def test_default_expect_handler(self):\n        route = self.router.add_route('GET', '/', self.make_handler())\n        self.assertIs(route._expect_handler, _defaultExpectHandler)\n\n    def test_custom_expect_handler_plain(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            pass\n\n        route = self.router.add_route(\n            'GET', '/', self.make_handler(), expect_handler=handler)\n        self.assertIs(route._expect_handler, handler)\n        self.assertIsInstance(route, PlainRoute)\n\n    def test_custom_expect_handler_dynamic(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            pass\n\n        route = self.router.add_route(\n            'GET', '/get/{name}', self.make_handler(), expect_handler=handler)\n        self.assertIs(route._expect_handler, handler)\n        self.assertIsInstance(route, DynamicRoute)\n\n    def test_expect_handler_non_coroutine(self):\n\n        def handler(request):\n            pass\n\n        self.assertRaises(\n            AssertionError, self.router.add_route,\n            'GET', '/', self.make_handler(), expect_handler=handler)\n\n    def test_dynamic_match_non_ascii(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{var}', handler)\n            req = self.make_request(\n                'GET',\n                '/%D1%80%D1%83%D1%81%20%D1%82%D0%B5%D0%BA%D1%81%D1%82')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'var': 'рус текст'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_with_static_part(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{name}.html', handler)\n            req = self.make_request('GET', '/file.html')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'name': 'file'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_two_part2(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{name}.{ext}', handler)\n            req = self.make_request('GET', '/file.html')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'name': 'file', 'ext': 'html'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_unquoted_path(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{path}/{subpath}', handler)\n            resource_id = 'my%2Fpath%7Cwith%21some%25strange%24characters'\n            req = self.make_request('GET', '/path/{0}'.format(resource_id))\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(match_info, {\n                'path': 'path',\n                'subpath': unquote(resource_id)\n            })\n\n        self.loop.run_until_complete(go())\n\n    def test_add_route_not_started_with_slash(self):\n        with self.assertRaises(ValueError):\n            handler = self.make_handler()\n            self.router.add_route('GET', 'invalid_path', handler)\n\n    def test_add_route_invalid_method(self):\n        with self.assertRaises(ValueError):\n            handler = self.make_handler()\n            self.router.add_route('INVALID_METHOD', '/path', handler)\n\n    def test_static_handle_eof(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            m_os.sendfile.return_value = 0\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertTrue(fut.done())\n            self.assertIsNone(fut.result())\n            self.assertFalse(loop.add_writer.called)\n            self.assertFalse(loop.remove_writer.called)\n\n    def test_static_handle_again(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            m_os.sendfile.side_effect = BlockingIOError()\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertFalse(fut.done())\n            loop.add_writer.assert_called_with(out_fd, route._sendfile_cb,\n                                               fut, out_fd, in_fd, 0, 100,\n                                               loop, True)\n            self.assertFalse(loop.remove_writer.called)\n\n    def test_static_handle_exception(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            exc = OSError()\n            m_os.sendfile.side_effect = exc\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertTrue(fut.done())\n            self.assertIs(exc, fut.exception())\n            self.assertFalse(loop.add_writer.called)\n            self.assertFalse(loop.remove_writer.called)\n\n    def fill_routes(self):\n        route1 = self.router.add_route('GET', '/plain', self.make_handler())\n        route2 = self.router.add_route('GET', '/variable/{name}',\n                                       self.make_handler())\n        route3 = self.router.add_static('/static',\n                                        os.path.dirname(aiohttp.__file__))\n        return route1, route2, route3\n\n    def test_routes_view_len(self):\n        self.fill_routes()\n        self.assertEqual(3, len(self.router.routes()))\n\n    def test_routes_view_iter(self):\n        routes = self.fill_routes()\n        self.assertEqual(list(routes), list(self.router.routes()))\n\n    def test_routes_view_contains(self):\n        routes = self.fill_routes()\n        for route in routes:\n            self.assertIn(route, self.router.routes())\n\n    def test_routes_abc(self):\n        self.assertIsInstance(self.router.routes(), Sized)\n        self.assertIsInstance(self.router.routes(), Iterable)\n        self.assertIsInstance(self.router.routes(), Container)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 71,
                            "end_lineno": 84,
                            "parent": {
                                "file_name": "tests/test_urldispatch.py",
                                "type": "class",
                                "name": "TestUrlDispatcher",
                                "content": "class TestUrlDispatcher(unittest.TestCase):\n\n    def setUp(self):\n        self.loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(None)\n        self.router = UrlDispatcher()\n\n    def tearDown(self):\n        self.loop.close()\n\n    def make_request(self, method, path):\n        self.app = mock.Mock()\n        message = RawRequestMessage(method, path, HttpVersion(1, 1),\n                                    CIMultiDict(), False, False)\n        self.payload = mock.Mock()\n        self.transport = mock.Mock()\n        self.reader = mock.Mock()\n        self.writer = mock.Mock()\n        req = Request(self.app, message, self.payload,\n                      self.transport, self.reader, self.writer)\n        return req\n\n    def make_handler(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            return Response(request)  # pragma: no cover\n\n        return handler\n\n    def test_system_route(self):\n        route = SystemRoute(201, 'test')\n        self.assertIsNone(route.match('any'))\n        with self.assertRaises(RuntimeError):\n            route.url()\n        self.assertEqual(\"<SystemRoute 201: test>\", repr(route))\n        self.assertEqual(201, route.status)\n        self.assertEqual('test', route.reason)\n\n    def test_register_route(self):\n        handler = self.make_handler()\n        route = PlainRoute('GET', handler, 'test', '/handler/to/path')\n        self.router.register_route(route)\n\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(route, info.route)\n        self.assertIs(handler, info.handler)\n        self.assertEqual(info.route.name, 'test')\n\n    def test_register_route_checks(self):\n        self.assertRaises(\n            AssertionError, self.router.register_route, object())\n\n        handler = self.make_handler()\n        route = PlainRoute('GET', handler, 'test', '/handler/to/path')\n        self.router.register_route(route)\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n        route = PlainRoute('GET', handler, '1bad name', '/handler/to/path')\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n        route = PlainRoute('GET', handler, 'return', '/handler/to/path')\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n    def test_add_route_root(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/', handler)\n        req = self.make_request('GET', '/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_route_simple(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path', handler)\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_with_matchdict(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/{to}', handler)\n        req = self.make_request('GET', '/handler/tail')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': 'tail'}, info)\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_with_name(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path', handler,\n                              name='name')\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual('name', info.route.name)\n\n    def test_add_with_tailing_slash(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path/', handler)\n        req = self.make_request('GET', '/handler/to/path/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({}, info)\n        self.assertIs(handler, info.handler)\n\n    def test_add_invalid_path(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('GET', '/{/', handler)\n\n    def test_add_url_invalid1(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id', handler)\n\n    def test_add_url_invalid2(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id{}}', handler)\n\n    def test_add_url_invalid3(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id{}', handler)\n\n    def test_add_url_invalid4(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id\"}', handler)\n\n    def test_add_url_escaping(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/+$', handler)\n\n        req = self.make_request('GET', '/+$')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertIs(handler, info.handler)\n\n    def test_any_method(self):\n        handler = self.make_handler()\n        route = self.router.add_route(hdrs.METH_ANY, '/', handler)\n\n        req = self.make_request('GET', '/')\n        info1 = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info1)\n        self.assertIs(route, info1.route)\n\n        req = self.make_request('POST', '/')\n        info2 = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info2)\n\n        self.assertIs(info1.route, info2.route)\n\n    def test_match_second_result_in_table(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/h1', handler1)\n        self.router.add_route('POST', '/h2', handler2)\n        req = self.make_request('POST', '/h2')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({}, info)\n        self.assertIs(handler2, info.handler)\n\n    def test_raise_method_not_allowed(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/', handler1)\n        self.router.add_route('POST', '/', handler2)\n        req = self.make_request('PUT', '/')\n\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n\n        with self.assertRaises(HTTPMethodNotAllowed) as ctx:\n            self.loop.run_until_complete(match_info.handler(req))\n\n        exc = ctx.exception\n        self.assertEqual('PUT', exc.method)\n        self.assertEqual(405, exc.status)\n        self.assertEqual({'POST', 'GET'}, exc.allowed_methods)\n\n    def test_raise_method_not_found(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/a', handler)\n        req = self.make_request('GET', '/b')\n\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n\n        with self.assertRaises(HTTPNotFound) as ctx:\n            self.loop.run_until_complete(match_info.handler(req))\n\n        exc = ctx.exception\n        self.assertEqual(404, exc.status)\n\n    def test_double_add_url_with_the_same_name(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/get', handler1, name='name')\n\n        regexp = (\"Duplicate 'name', already handled by\")\n        with self.assertRaisesRegex(ValueError, regexp):\n            self.router.add_route('GET', '/get_other', handler2, name='name')\n\n    def test_route_plain(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get', handler, name='name')\n        route2 = self.router['name']\n        url = route2.url()\n        self.assertEqual('/get', url)\n        self.assertIs(route, route2)\n\n    def test_route_unknown_route_name(self):\n        with self.assertRaises(KeyError):\n            self.router['unknown']\n\n    def test_route_dynamic(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{name}', handler,\n                                      name='name')\n\n        route2 = self.router['name']\n        url = route2.url(parts={'name': 'John'})\n        self.assertEqual('/get/John', url)\n        self.assertIs(route, route2)\n\n    def test_route_with_qs(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get', handler, name='name')\n\n        url = self.router['name'].url(query=[('a', 'b'), ('c', 1)])\n        self.assertEqual('/get?a=b&c=1', url)\n\n    def test_add_static(self):\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__),\n                                       name='static')\n        route2 = self.router['static']\n        url = route2.url(filename='/dir/a.txt')\n        self.assertEqual('/st/dir/a.txt', url)\n        self.assertIs(route, route2)\n\n    def test_plain_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/path', handler, name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_dynamic_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{name}', handler, name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_static_not_match(self):\n        self.router.add_static('/pre', os.path.dirname(aiohttp.__file__),\n                               name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_dynamic_with_trailing_slash(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{name}/', handler, name='name')\n        route = self.router['name']\n        self.assertEqual({'name': 'John'}, route.match('/get/John/'))\n\n    def test_len(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertEqual(2, len(self.router))\n\n    def test_iter(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertEqual({'name1', 'name2'}, set(iter(self.router)))\n\n    def test_contains(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertIn('name1', self.router)\n        self.assertNotIn('name3', self.router)\n\n    def test_plain_repr(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/path', handler, name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<PlainRoute 'name' \\[GET\\] /get/path\")\n\n    def test_dynamic_repr(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{path}', handler, name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<DynamicRoute 'name' \\[GET\\] /get/{path}\")\n\n    def test_static_repr(self):\n        self.router.add_static('/get', os.path.dirname(aiohttp.__file__),\n                               name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<StaticRoute 'name' \\[GET\\] /get/\")\n\n    def test_static_adds_slash(self):\n        route = self.router.add_static('/prefix',\n                                       os.path.dirname(aiohttp.__file__))\n        self.assertEqual('/prefix/', route._prefix)\n\n    def test_static_dont_add_trailing_slash(self):\n        route = self.router.add_static('/prefix/',\n                                       os.path.dirname(aiohttp.__file__))\n        self.assertEqual('/prefix/', route._prefix)\n\n    def test_add_route_with_re(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:\\d+}', handler)\n\n        req = self.make_request('GET', '/handler/1234')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234'}, info)\n\n        self.router.add_route('GET', r'/handler/{name}.html', handler)\n        req = self.make_request('GET', '/handler/test.html')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertEqual({'name': 'test'}, info)\n\n    def test_add_route_with_re_and_slashes(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:[^/]+/?}', handler)\n        req = self.make_request('GET', '/handler/1234/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234/'}, info)\n\n        self.router.add_route('GET', r'/handler/{to:.+}', handler)\n        req = self.make_request('GET', '/handler/1234/5/6/7')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234/5/6/7'}, info)\n\n    def test_add_route_with_re_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:\\d+}', handler)\n\n        req = self.make_request('GET', '/handler/tail')\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n        with self.assertRaises(HTTPNotFound):\n            self.loop.run_until_complete(match_info.handler(req))\n\n    def test_add_route_with_re_including_slashes(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:.+}/tail', handler)\n        req = self.make_request('GET', '/handler/re/with/slashes/tail')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': 're/with/slashes'}, info)\n\n    def test_add_route_with_invalid_re(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError) as ctx:\n            self.router.add_route('GET', r'/handler/{to:+++}', handler)\n        s = str(ctx.exception)\n        self.assertTrue(s.startswith(\n            \"Bad pattern '\\/handler\\/(?P<to>+++)': nothing to repeat\"), s)\n        self.assertIsNone(ctx.exception.__cause__)\n\n    def test_route_dynamic_with_regex_spec(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{num:^\\d+}', handler,\n                                      name='name')\n\n        url = route.url(parts={'num': '123'})\n        self.assertEqual('/get/123', url)\n\n    def test_route_dynamic_with_regex_spec_and_trailing_slash(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{num:^\\d+}/', handler,\n                                      name='name')\n\n        url = route.url(parts={'num': '123'})\n        self.assertEqual('/get/123/', url)\n\n    def test_route_dynamic_with_regex(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', r'/{one}/{two:.+}', handler)\n\n        url = route.url(parts={'one': 1, 'two': 2})\n        self.assertEqual('/1/2', url)\n\n    def test_regular_match_info(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/get/{name}', handler)\n\n            req = self.make_request('GET', '/get/john')\n            match_info = yield from self.router.resolve(req)\n            self.maxDiff = None\n            self.assertRegex(repr(match_info),\n                             \"<MatchInfo {'name': 'john'}: <DynamicRoute.+>>\")\n\n        self.loop.run_until_complete(go())\n\n    def test_not_found_repr(self):\n\n        @asyncio.coroutine\n        def go():\n            req = self.make_request('POST', '/path/to')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(\"<MatchInfo: not found>\", repr(match_info))\n\n        self.loop.run_until_complete(go())\n\n    def test_not_allowed_repr(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/path/to', handler)\n\n            handler2 = self.make_handler()\n            self.router.add_route('POST', '/path/to', handler2)\n\n            req = self.make_request('PUT', '/path/to')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(\"<MatchInfo: method PUT is not allowed \"\n                             \"(allowed methods: GET, POST>\", repr(match_info))\n\n        self.loop.run_until_complete(go())\n\n    def test_default_expect_handler(self):\n        route = self.router.add_route('GET', '/', self.make_handler())\n        self.assertIs(route._expect_handler, _defaultExpectHandler)\n\n    def test_custom_expect_handler_plain(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            pass\n\n        route = self.router.add_route(\n            'GET', '/', self.make_handler(), expect_handler=handler)\n        self.assertIs(route._expect_handler, handler)\n        self.assertIsInstance(route, PlainRoute)\n\n    def test_custom_expect_handler_dynamic(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            pass\n\n        route = self.router.add_route(\n            'GET', '/get/{name}', self.make_handler(), expect_handler=handler)\n        self.assertIs(route._expect_handler, handler)\n        self.assertIsInstance(route, DynamicRoute)\n\n    def test_expect_handler_non_coroutine(self):\n\n        def handler(request):\n            pass\n\n        self.assertRaises(\n            AssertionError, self.router.add_route,\n            'GET', '/', self.make_handler(), expect_handler=handler)\n\n    def test_dynamic_match_non_ascii(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{var}', handler)\n            req = self.make_request(\n                'GET',\n                '/%D1%80%D1%83%D1%81%20%D1%82%D0%B5%D0%BA%D1%81%D1%82')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'var': 'рус текст'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_with_static_part(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{name}.html', handler)\n            req = self.make_request('GET', '/file.html')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'name': 'file'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_two_part2(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{name}.{ext}', handler)\n            req = self.make_request('GET', '/file.html')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'name': 'file', 'ext': 'html'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_unquoted_path(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{path}/{subpath}', handler)\n            resource_id = 'my%2Fpath%7Cwith%21some%25strange%24characters'\n            req = self.make_request('GET', '/path/{0}'.format(resource_id))\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(match_info, {\n                'path': 'path',\n                'subpath': unquote(resource_id)\n            })\n\n        self.loop.run_until_complete(go())\n\n    def test_add_route_not_started_with_slash(self):\n        with self.assertRaises(ValueError):\n            handler = self.make_handler()\n            self.router.add_route('GET', 'invalid_path', handler)\n\n    def test_add_route_invalid_method(self):\n        with self.assertRaises(ValueError):\n            handler = self.make_handler()\n            self.router.add_route('INVALID_METHOD', '/path', handler)\n\n    def test_static_handle_eof(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            m_os.sendfile.return_value = 0\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertTrue(fut.done())\n            self.assertIsNone(fut.result())\n            self.assertFalse(loop.add_writer.called)\n            self.assertFalse(loop.remove_writer.called)\n\n    def test_static_handle_again(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            m_os.sendfile.side_effect = BlockingIOError()\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertFalse(fut.done())\n            loop.add_writer.assert_called_with(out_fd, route._sendfile_cb,\n                                               fut, out_fd, in_fd, 0, 100,\n                                               loop, True)\n            self.assertFalse(loop.remove_writer.called)\n\n    def test_static_handle_exception(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            exc = OSError()\n            m_os.sendfile.side_effect = exc\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertTrue(fut.done())\n            self.assertIs(exc, fut.exception())\n            self.assertFalse(loop.add_writer.called)\n            self.assertFalse(loop.remove_writer.called)\n\n    def fill_routes(self):\n        route1 = self.router.add_route('GET', '/plain', self.make_handler())\n        route2 = self.router.add_route('GET', '/variable/{name}',\n                                       self.make_handler())\n        route3 = self.router.add_static('/static',\n                                        os.path.dirname(aiohttp.__file__))\n        return route1, route2, route3\n\n    def test_routes_view_len(self):\n        self.fill_routes()\n        self.assertEqual(3, len(self.router.routes()))\n\n    def test_routes_view_iter(self):\n        routes = self.fill_routes()\n        self.assertEqual(list(routes), list(self.router.routes()))\n\n    def test_routes_view_contains(self):\n        routes = self.fill_routes()\n        for route in routes:\n            self.assertIn(route, self.router.routes())\n\n    def test_routes_abc(self):\n        self.assertIsInstance(self.router.routes(), Sized)\n        self.assertIsInstance(self.router.routes(), Iterable)\n        self.assertIsInstance(self.router.routes(), Container)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 19,
                                "end_lineno": 640,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "a2aa20dacbeb34544cc69765e20dabe5718c0d57^",
    "new_commit_hash": "a2aa20dacbeb34544cc69765e20dabe5718c0d57",
    "commit_message": "validate route name",
    "commit_date": "2015-10-15T03:06:29+03:00",
    "metadata": {}
}
{
    "repo_name": "aiohttp",
    "new_commit_hash": "a2aa20dacbeb34544cc69765e20dabe5718c0d57",
    "test_file_codes": [
        "import asyncio\nimport os\nimport unittest\nfrom collections.abc import Sized, Container, Iterable\nfrom unittest import mock\nfrom urllib.parse import unquote\nimport aiohttp.web\nfrom aiohttp import hdrs\nfrom aiohttp.web import (UrlDispatcher, Request, Response,\n                         HTTPMethodNotAllowed, HTTPNotFound)\nfrom aiohttp.multidict import CIMultiDict\nfrom aiohttp.protocol import HttpVersion, RawRequestMessage\nfrom aiohttp.web_urldispatcher import (_defaultExpectHandler,\n                                       DynamicRoute,\n                                       PlainRoute,\n                                       SystemRoute)\n\n\nclass TestUrlDispatcher(unittest.TestCase):\n\n    def setUp(self):\n        self.loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(None)\n        self.router = UrlDispatcher()\n\n    def tearDown(self):\n        self.loop.close()\n\n    def make_request(self, method, path):\n        self.app = mock.Mock()\n        message = RawRequestMessage(method, path, HttpVersion(1, 1),\n                                    CIMultiDict(), False, False)\n        self.payload = mock.Mock()\n        self.transport = mock.Mock()\n        self.reader = mock.Mock()\n        self.writer = mock.Mock()\n        req = Request(self.app, message, self.payload,\n                      self.transport, self.reader, self.writer)\n        return req\n\n    def make_handler(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            return Response(request)  # pragma: no cover\n\n        return handler\n\n    def test_system_route(self):\n        route = SystemRoute(201, 'test')\n        self.assertIsNone(route.match('any'))\n        with self.assertRaises(RuntimeError):\n            route.url()\n        self.assertEqual(\"<SystemRoute 201: test>\", repr(route))\n        self.assertEqual(201, route.status)\n        self.assertEqual('test', route.reason)\n\n    def test_register_route(self):\n        handler = self.make_handler()\n        route = PlainRoute('GET', handler, 'test', '/handler/to/path')\n        self.router.register_route(route)\n\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(route, info.route)\n        self.assertIs(handler, info.handler)\n        self.assertEqual(info.route.name, 'test')\n\n    def test_register_route_checks(self):\n        self.assertRaises(\n            AssertionError, self.router.register_route, object())\n\n        handler = self.make_handler()\n        route = PlainRoute('GET', handler, 'test', '/handler/to/path')\n        self.router.register_route(route)\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n        route = PlainRoute('GET', handler, '1bad name', '/handler/to/path')\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n        route = PlainRoute('GET', handler, 'return', '/handler/to/path')\n        self.assertRaises(ValueError, self.router.register_route, route)\n\n    def test_add_route_root(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/', handler)\n        req = self.make_request('GET', '/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_route_simple(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path', handler)\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual(0, len(info))\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_with_matchdict(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/{to}', handler)\n        req = self.make_request('GET', '/handler/tail')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': 'tail'}, info)\n        self.assertIs(handler, info.handler)\n        self.assertIsNone(info.route.name)\n\n    def test_add_with_name(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path', handler,\n                              name='name')\n        req = self.make_request('GET', '/handler/to/path')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual('name', info.route.name)\n\n    def test_add_with_tailing_slash(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/handler/to/path/', handler)\n        req = self.make_request('GET', '/handler/to/path/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({}, info)\n        self.assertIs(handler, info.handler)\n\n    def test_add_invalid_path(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('GET', '/{/', handler)\n\n    def test_add_url_invalid1(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id', handler)\n\n    def test_add_url_invalid2(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id{}}', handler)\n\n    def test_add_url_invalid3(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id{}', handler)\n\n    def test_add_url_invalid4(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError):\n            self.router.add_route('post', '/post/{id\"}', handler)\n\n    def test_add_url_escaping(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/+$', handler)\n\n        req = self.make_request('GET', '/+$')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertIs(handler, info.handler)\n\n    def test_any_method(self):\n        handler = self.make_handler()\n        route = self.router.add_route(hdrs.METH_ANY, '/', handler)\n\n        req = self.make_request('GET', '/')\n        info1 = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info1)\n        self.assertIs(route, info1.route)\n\n        req = self.make_request('POST', '/')\n        info2 = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info2)\n\n        self.assertIs(info1.route, info2.route)\n\n    def test_match_second_result_in_table(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/h1', handler1)\n        self.router.add_route('POST', '/h2', handler2)\n        req = self.make_request('POST', '/h2')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({}, info)\n        self.assertIs(handler2, info.handler)\n\n    def test_raise_method_not_allowed(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/', handler1)\n        self.router.add_route('POST', '/', handler2)\n        req = self.make_request('PUT', '/')\n\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n\n        with self.assertRaises(HTTPMethodNotAllowed) as ctx:\n            self.loop.run_until_complete(match_info.handler(req))\n\n        exc = ctx.exception\n        self.assertEqual('PUT', exc.method)\n        self.assertEqual(405, exc.status)\n        self.assertEqual({'POST', 'GET'}, exc.allowed_methods)\n\n    def test_raise_method_not_found(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/a', handler)\n        req = self.make_request('GET', '/b')\n\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n\n        with self.assertRaises(HTTPNotFound) as ctx:\n            self.loop.run_until_complete(match_info.handler(req))\n\n        exc = ctx.exception\n        self.assertEqual(404, exc.status)\n\n    def test_double_add_url_with_the_same_name(self):\n        handler1 = self.make_handler()\n        handler2 = self.make_handler()\n        self.router.add_route('GET', '/get', handler1, name='name')\n\n        regexp = (\"Duplicate 'name', already handled by\")\n        with self.assertRaisesRegex(ValueError, regexp):\n            self.router.add_route('GET', '/get_other', handler2, name='name')\n\n    def test_route_plain(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get', handler, name='name')\n        route2 = self.router['name']\n        url = route2.url()\n        self.assertEqual('/get', url)\n        self.assertIs(route, route2)\n\n    def test_route_unknown_route_name(self):\n        with self.assertRaises(KeyError):\n            self.router['unknown']\n\n    def test_route_dynamic(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{name}', handler,\n                                      name='name')\n\n        route2 = self.router['name']\n        url = route2.url(parts={'name': 'John'})\n        self.assertEqual('/get/John', url)\n        self.assertIs(route, route2)\n\n    def test_route_with_qs(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get', handler, name='name')\n\n        url = self.router['name'].url(query=[('a', 'b'), ('c', 1)])\n        self.assertEqual('/get?a=b&c=1', url)\n\n    def test_add_static(self):\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__),\n                                       name='static')\n        route2 = self.router['static']\n        url = route2.url(filename='/dir/a.txt')\n        self.assertEqual('/st/dir/a.txt', url)\n        self.assertIs(route, route2)\n\n    def test_plain_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/path', handler, name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_dynamic_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{name}', handler, name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_static_not_match(self):\n        self.router.add_static('/pre', os.path.dirname(aiohttp.__file__),\n                               name='name')\n        route = self.router['name']\n        self.assertIsNone(route.match('/another/path'))\n\n    def test_dynamic_with_trailing_slash(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{name}/', handler, name='name')\n        route = self.router['name']\n        self.assertEqual({'name': 'John'}, route.match('/get/John/'))\n\n    def test_len(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertEqual(2, len(self.router))\n\n    def test_iter(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertEqual({'name1', 'name2'}, set(iter(self.router)))\n\n    def test_contains(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get1', handler, name='name1')\n        self.router.add_route('GET', '/get2', handler, name='name2')\n        self.assertIn('name1', self.router)\n        self.assertNotIn('name3', self.router)\n\n    def test_plain_repr(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/path', handler, name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<PlainRoute 'name' \\[GET\\] /get/path\")\n\n    def test_dynamic_repr(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', '/get/{path}', handler, name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<DynamicRoute 'name' \\[GET\\] /get/{path}\")\n\n    def test_static_repr(self):\n        self.router.add_static('/get', os.path.dirname(aiohttp.__file__),\n                               name='name')\n        self.assertRegex(repr(self.router['name']),\n                         r\"<StaticRoute 'name' \\[GET\\] /get/\")\n\n    def test_static_adds_slash(self):\n        route = self.router.add_static('/prefix',\n                                       os.path.dirname(aiohttp.__file__))\n        self.assertEqual('/prefix/', route._prefix)\n\n    def test_static_dont_add_trailing_slash(self):\n        route = self.router.add_static('/prefix/',\n                                       os.path.dirname(aiohttp.__file__))\n        self.assertEqual('/prefix/', route._prefix)\n\n    def test_add_route_with_re(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:\\d+}', handler)\n\n        req = self.make_request('GET', '/handler/1234')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234'}, info)\n\n        self.router.add_route('GET', r'/handler/{name}.html', handler)\n        req = self.make_request('GET', '/handler/test.html')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertEqual({'name': 'test'}, info)\n\n    def test_add_route_with_re_and_slashes(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:[^/]+/?}', handler)\n        req = self.make_request('GET', '/handler/1234/')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234/'}, info)\n\n        self.router.add_route('GET', r'/handler/{to:.+}', handler)\n        req = self.make_request('GET', '/handler/1234/5/6/7')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': '1234/5/6/7'}, info)\n\n    def test_add_route_with_re_not_match(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:\\d+}', handler)\n\n        req = self.make_request('GET', '/handler/tail')\n        match_info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsInstance(match_info.route, SystemRoute)\n        self.assertEqual({}, match_info)\n        with self.assertRaises(HTTPNotFound):\n            self.loop.run_until_complete(match_info.handler(req))\n\n    def test_add_route_with_re_including_slashes(self):\n        handler = self.make_handler()\n        self.router.add_route('GET', r'/handler/{to:.+}/tail', handler)\n        req = self.make_request('GET', '/handler/re/with/slashes/tail')\n        info = self.loop.run_until_complete(self.router.resolve(req))\n        self.assertIsNotNone(info)\n        self.assertEqual({'to': 're/with/slashes'}, info)\n\n    def test_add_route_with_invalid_re(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError) as ctx:\n            self.router.add_route('GET', r'/handler/{to:+++}', handler)\n        s = str(ctx.exception)\n        self.assertTrue(s.startswith(\n            \"Bad pattern '\\/handler\\/(?P<to>+++)': nothing to repeat\"), s)\n        self.assertIsNone(ctx.exception.__cause__)\n\n    def test_route_dynamic_with_regex_spec(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{num:^\\d+}', handler,\n                                      name='name')\n\n        url = route.url(parts={'num': '123'})\n        self.assertEqual('/get/123', url)\n\n    def test_route_dynamic_with_regex_spec_and_trailing_slash(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', '/get/{num:^\\d+}/', handler,\n                                      name='name')\n\n        url = route.url(parts={'num': '123'})\n        self.assertEqual('/get/123/', url)\n\n    def test_route_dynamic_with_regex(self):\n        handler = self.make_handler()\n        route = self.router.add_route('GET', r'/{one}/{two:.+}', handler)\n\n        url = route.url(parts={'one': 1, 'two': 2})\n        self.assertEqual('/1/2', url)\n\n    def test_regular_match_info(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/get/{name}', handler)\n\n            req = self.make_request('GET', '/get/john')\n            match_info = yield from self.router.resolve(req)\n            self.maxDiff = None\n            self.assertRegex(repr(match_info),\n                             \"<MatchInfo {'name': 'john'}: <DynamicRoute.+>>\")\n\n        self.loop.run_until_complete(go())\n\n    def test_not_found_repr(self):\n\n        @asyncio.coroutine\n        def go():\n            req = self.make_request('POST', '/path/to')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(\"<MatchInfo: not found>\", repr(match_info))\n\n        self.loop.run_until_complete(go())\n\n    def test_not_allowed_repr(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/path/to', handler)\n\n            handler2 = self.make_handler()\n            self.router.add_route('POST', '/path/to', handler2)\n\n            req = self.make_request('PUT', '/path/to')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(\"<MatchInfo: method PUT is not allowed \"\n                             \"(allowed methods: GET, POST>\", repr(match_info))\n\n        self.loop.run_until_complete(go())\n\n    def test_default_expect_handler(self):\n        route = self.router.add_route('GET', '/', self.make_handler())\n        self.assertIs(route._expect_handler, _defaultExpectHandler)\n\n    def test_custom_expect_handler_plain(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            pass\n\n        route = self.router.add_route(\n            'GET', '/', self.make_handler(), expect_handler=handler)\n        self.assertIs(route._expect_handler, handler)\n        self.assertIsInstance(route, PlainRoute)\n\n    def test_custom_expect_handler_dynamic(self):\n\n        @asyncio.coroutine\n        def handler(request):\n            pass\n\n        route = self.router.add_route(\n            'GET', '/get/{name}', self.make_handler(), expect_handler=handler)\n        self.assertIs(route._expect_handler, handler)\n        self.assertIsInstance(route, DynamicRoute)\n\n    def test_expect_handler_non_coroutine(self):\n\n        def handler(request):\n            pass\n\n        self.assertRaises(\n            AssertionError, self.router.add_route,\n            'GET', '/', self.make_handler(), expect_handler=handler)\n\n    def test_dynamic_match_non_ascii(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{var}', handler)\n            req = self.make_request(\n                'GET',\n                '/%D1%80%D1%83%D1%81%20%D1%82%D0%B5%D0%BA%D1%81%D1%82')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'var': 'рус текст'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_with_static_part(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{name}.html', handler)\n            req = self.make_request('GET', '/file.html')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'name': 'file'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_two_part2(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{name}.{ext}', handler)\n            req = self.make_request('GET', '/file.html')\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual({'name': 'file', 'ext': 'html'}, match_info)\n\n        self.loop.run_until_complete(go())\n\n    def test_dynamic_match_unquoted_path(self):\n\n        @asyncio.coroutine\n        def go():\n            handler = self.make_handler()\n            self.router.add_route('GET', '/{path}/{subpath}', handler)\n            resource_id = 'my%2Fpath%7Cwith%21some%25strange%24characters'\n            req = self.make_request('GET', '/path/{0}'.format(resource_id))\n            match_info = yield from self.router.resolve(req)\n            self.assertEqual(match_info, {\n                'path': 'path',\n                'subpath': unquote(resource_id)\n            })\n\n        self.loop.run_until_complete(go())\n\n    def test_add_route_not_started_with_slash(self):\n        with self.assertRaises(ValueError):\n            handler = self.make_handler()\n            self.router.add_route('GET', 'invalid_path', handler)\n\n    def test_add_route_invalid_method(self):\n        with self.assertRaises(ValueError):\n            handler = self.make_handler()\n            self.router.add_route('INVALID_METHOD', '/path', handler)\n\n    def test_static_handle_eof(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            m_os.sendfile.return_value = 0\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertTrue(fut.done())\n            self.assertIsNone(fut.result())\n            self.assertFalse(loop.add_writer.called)\n            self.assertFalse(loop.remove_writer.called)\n\n    def test_static_handle_again(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            m_os.sendfile.side_effect = BlockingIOError()\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertFalse(fut.done())\n            loop.add_writer.assert_called_with(out_fd, route._sendfile_cb,\n                                               fut, out_fd, in_fd, 0, 100,\n                                               loop, True)\n            self.assertFalse(loop.remove_writer.called)\n\n    def test_static_handle_exception(self):\n        loop = mock.Mock()\n        route = self.router.add_static('/st',\n                                       os.path.dirname(aiohttp.__file__))\n        with mock.patch('aiohttp.web_urldispatcher.os') as m_os:\n            out_fd = 30\n            in_fd = 31\n            fut = asyncio.Future(loop=self.loop)\n            exc = OSError()\n            m_os.sendfile.side_effect = exc\n            route._sendfile_cb(fut, out_fd, in_fd, 0, 100, loop, False)\n            m_os.sendfile.assert_called_with(out_fd, in_fd, 0, 100)\n            self.assertTrue(fut.done())\n            self.assertIs(exc, fut.exception())\n            self.assertFalse(loop.add_writer.called)\n            self.assertFalse(loop.remove_writer.called)\n\n    def fill_routes(self):\n        route1 = self.router.add_route('GET', '/plain', self.make_handler())\n        route2 = self.router.add_route('GET', '/variable/{name}',\n                                       self.make_handler())\n        route3 = self.router.add_static('/static',\n                                        os.path.dirname(aiohttp.__file__))\n        return route1, route2, route3\n\n    def test_routes_view_len(self):\n        self.fill_routes()\n        self.assertEqual(3, len(self.router.routes()))\n\n    def test_routes_view_iter(self):\n        routes = self.fill_routes()\n        self.assertEqual(list(routes), list(self.router.routes()))\n\n    def test_routes_view_contains(self):\n        routes = self.fill_routes()\n        for route in routes:\n            self.assertIn(route, self.router.routes())\n\n    def test_routes_abc(self):\n        self.assertIsInstance(self.router.routes(), Sized)\n        self.assertIsInstance(self.router.routes(), Iterable)\n        self.assertIsInstance(self.router.routes(), Container)\n",
        "import asyncio\nimport aiohttp\nimport gc\nimport pytest\nimport re\nimport socket\nimport sys\nimport warnings\n\nfrom aiohttp import web\n\n\nclass _AssertWarnsContext:\n    \"\"\"A context manager used to implement TestCase.assertWarns* methods.\"\"\"\n\n    _base_type = Warning\n    _base_type_str = 'a warning type or tuple of warning types'\n\n    def __init__(self, expected, expected_regex=None):\n        self.expected = expected\n        if expected_regex is not None:\n            expected_regex = re.compile(expected_regex)\n        self.expected_regex = expected_regex\n        self.obj_name = None\n\n    def __enter__(self):\n        # The __warningregistry__'s need to be in a pristine state for tests\n        # to work properly.\n        for v in sys.modules.values():\n            if getattr(v, '__warningregistry__', None):\n                v.__warningregistry__ = {}\n        self.warnings_manager = warnings.catch_warnings(record=True)\n        self.warnings = self.warnings_manager.__enter__()\n        warnings.simplefilter(\"always\", self.expected)\n        return self\n\n    def __exit__(self, exc_type, exc_value, tb):\n        self.warnings_manager.__exit__(exc_type, exc_value, tb)\n        if exc_type is not None:\n            # let unexpected exceptions pass through\n            return\n        try:\n            exc_name = self.expected.__name__\n        except AttributeError:\n            exc_name = str(self.expected)\n        first_matching = None\n        for m in self.warnings:\n            w = m.message\n            if not isinstance(w, self.expected):\n                continue\n            if first_matching is None:\n                first_matching = w\n            if (self.expected_regex is not None and\n                    not self.expected_regex.search(str(w))):\n                continue\n            # store warning for later retrieval\n            self.warning = w\n            self.filename = m.filename\n            self.lineno = m.lineno\n            return\n        # Now we simply try to choose a helpful failure message\n        if first_matching is not None:\n            __tracebackhide__ = True\n            assert 0, '\"{}\" does not match \"{}\"'.format(\n                self.expected_regex.pattern, str(first_matching))\n        if self.obj_name:\n            __tracebackhide__ = True\n            assert 0, \"{} not triggered by {}\".format(exc_name,\n                                                      self.obj_name)\n        else:\n            __tracebackhide__ = True\n            assert 0, \"{} not triggered\".format(exc_name)\n\n\n@pytest.yield_fixture\ndef warning():\n    yield _AssertWarnsContext\n\n\n@pytest.fixture\ndef unused_port():\n    def f():\n        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:\n            s.bind(('127.0.0.1', 0))\n            return s.getsockname()[1]\n    return f\n\n\n@pytest.yield_fixture\ndef loop(request):\n    loop = asyncio.new_event_loop()\n    asyncio.set_event_loop(None)\n\n    yield loop\n\n    loop.stop()\n    loop.run_forever()\n    loop.close()\n    gc.collect()\n    asyncio.set_event_loop(None)\n\n\n@pytest.yield_fixture\ndef create_server(loop, unused_port):\n    app = handler = srv = None\n\n    @asyncio.coroutine\n    def create(*, debug=False, ssl_ctx=None):\n        nonlocal app, handler, srv\n        app = web.Application(loop=loop)\n        port = unused_port()\n        handler = app.make_handler(debug=debug, keep_alive_on=False)\n        srv = yield from loop.create_server(handler, '127.0.0.1', port,\n                                            ssl=ssl_ctx)\n        proto = \"https\" if ssl_ctx else \"http\"\n        url = \"{}://127.0.0.1:{}\".format(proto, port)\n        return app, url\n\n    yield create\n\n    @asyncio.coroutine\n    def finish():\n        yield from handler.finish_connections()\n        yield from app.finish()\n        srv.close()\n        yield from srv.wait_closed()\n\n    loop.run_until_complete(finish())\n\n\nclass Client:\n    def __init__(self, session, url):\n        self._session = session\n        if not url.endswith('/'):\n            url += '/'\n        self._url = url\n\n    def close(self):\n        self._session.close()\n\n    def get(self, path, **kwargs):\n        while path.startswith('/'):\n            path = path[1:]\n        url = self._url + path\n        return self._session.get(url, **kwargs)\n\n    def post(self, path, **kwargs):\n        while path.startswith('/'):\n            path = path[1:]\n        url = self._url + path\n        return self._session.post(url, **kwargs)\n\n\n@pytest.yield_fixture\ndef create_app_and_client(create_server, loop):\n    client = None\n\n    @asyncio.coroutine\n    def maker(*, server_params=None, client_params=None):\n        nonlocal client\n        if server_params is None:\n            server_params = {}\n        server_params.setdefault('debug', False)\n        server_params.setdefault('ssl_ctx', None)\n        app, url = yield from create_server(**server_params)\n        if client_params is None:\n            client_params = {}\n        client = Client(aiohttp.ClientSession(loop=loop, **client_params), url)\n        return app, client\n\n    yield maker\n    client.close()\n\n\n@pytest.mark.tryfirst\ndef pytest_pycollect_makeitem(collector, name, obj):\n    if collector.funcnamefilter(name):\n        if not callable(obj):\n            return\n        item = pytest.Function(name, parent=collector)\n        if 'run_loop' in item.keywords:\n            return list(collector._genfunctions(name, obj))\n\n\n@pytest.mark.tryfirst\ndef pytest_pyfunc_call(pyfuncitem):\n    \"\"\"\n    Run asyncio marked test functions in an event loop instead of a normal\n    function call.\n    \"\"\"\n    if 'run_loop' in pyfuncitem.keywords:\n        funcargs = pyfuncitem.funcargs\n        loop = funcargs['loop']\n        testargs = {arg: funcargs[arg]\n                    for arg in pyfuncitem._fixtureinfo.argnames}\n        loop.run_until_complete(pyfuncitem.obj(**testargs))\n        return True\n\n\ndef pytest_runtest_setup(item):\n    if 'run_loop' in item.keywords and 'loop' not in item.fixturenames:\n        # inject an event loop fixture for all async tests\n        item.fixturenames.append('loop')\n\n\ndef pytest_ignore_collect(path, config):\n    if 'test_py35' in str(path):\n        if sys.version_info < (3, 5, 0):\n            return True\n"
    ],
    "test_file_names": [
        "test_1.py",
        "conftest.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "uv pip install -U -r requirements-dev.txt\nTransforming aiohttp/worker.py\nTransforming aiohttp/client_reqrep.py\nTransforming aiohttp/server.py\n",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 68 packages in 930ms\n  × Failed to build `aiohttp @ file:///home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_a2aa20dacbeb34544cc69765e20dabe5718c0d57`\n  ├─▶ The build backend returned an error\n  ╰─▶ Call to `setuptools.build_meta:__legacy__.build_editable` failed (exit status: 1)\n\n      [stdout]\n      running editable_wheel\n      creating /home/gcpuser/.cache/uv/builds-v0/.tmpVS2CvF/.tmp-y_60urwg/aiohttp.egg-info\n      writing /home/gcpuser/.cache/uv/builds-v0/.tmpVS2CvF/.tmp-y_60urwg/aiohttp.egg-info/PKG-INFO\n      writing dependency_links to /home/gcpuser/.cache/uv/builds-v0/.tmpVS2CvF/.tmp-y_60urwg/aiohttp.egg-info/dependency_links.txt\n      writing requirements to /home/gcpuser/.cache/uv/builds-v0/.tmpVS2CvF/.tmp-y_60urwg/aiohttp.egg-info/requires.txt\n      writing top-level names to /home/gcpuser/.cache/uv/builds-v0/.tmpVS2CvF/.tmp-y_60urwg/aiohttp.egg-info/top_level.txt\n      writing manifest file '/home/gcpuser/.cache/uv/builds-v0/.tmpVS2CvF/.tmp-y_60urwg/aiohttp.egg-info/SOURCES.txt'\n      reading manifest file '/home/gcpuser/.cache/uv/builds-v0/.tmpVS2CvF/.tmp-y_60urwg/aiohttp.egg-info/SOURCES.txt'\n      reading manifest template 'MANIFEST.in'\n      adding license file 'LICENSE.txt'\n      writing manifest file '/home/gcpuser/.cache/uv/builds-v0/.tmpVS2CvF/.tmp-y_60urwg/aiohttp.egg-info/SOURCES.txt'\n      creating '/home/gcpuser/.cache/uv/builds-v0/.tmpVS2CvF/.tmp-y_60urwg/aiohttp-0.18.0a0.dist-info'\n      creating /home/gcpuser/.cache/uv/builds-v0/.tmpVS2CvF/.tmp-y_60urwg/aiohttp-0.18.0a0.dist-info/WHEEL\n      running build_py\n      running build_ext\n      building 'aiohttp._multidict' extension\n      creating /tmp/tmpv8li4pv2.build-temp/aiohttp\n      cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -fPIC\n      -I/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/include -I/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/include/python3.9 -c\n      aiohttp/_multidict.c -o /tmp/tmpv8li4pv2.build-temp/aiohttp/_multidict.o\n      ************************************************************\n      Cannot compile C accelerator module, use pure python version\n      ************************************************************\n      running editable_wheel\n\n      [stderr]\n      <string>:9: SetuptoolsDeprecationWarning: The test command is disabled and references to it are deprecated.\n      !!\n\n              ********************************************************************************\n              Please remove any references to `setuptools.command.test` in all supported versions of the affected package.\n\n              This deprecation is overdue, please update your project and remove deprecated\n              calls to avoid build errors in the future.\n              ********************************************************************************\n\n      !!\n      /home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/dist.py:261: UserWarning: Unknown distribution option:\n      'tests_require'\n        warnings.warn(msg)\n      warning: no previously-included files matching '*.pyc' found anywhere in distribution\n      warning: no previously-included files found matching 'aiohttp/_multidict.html'\n      warning: no previously-included files found matching 'aiohttp/_multidict.*.so'\n      warning: no previously-included files found matching 'aiohttp/_multidict.pyd'\n      warning: no previously-included files found matching 'aiohttp/_multidict.*.pyd'\n      warning: no previously-included files found matching 'aiohttp/_websocket.html'\n      warning: no previously-included files found matching 'aiohttp/_websocket.*.so'\n      warning: no previously-included files found matching 'aiohttp/_websocket.pyd'\n      warning: no previously-included files found matching 'aiohttp/_websocket.*.pyd'\n      no previously-included directories found matching 'docs/_build'\n      cc1: fatal error: aiohttp/_multidict.c: No such file or directory\n      compilation terminated.\n      Traceback (most recent call last):\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/spawn.py\", line 70, in spawn\n          subprocess.check_call(cmd, env=_inject_macos_ver(env))\n        File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/subprocess.py\", line 373, in check_call\n          raise CalledProcessError(retcode, cmd)\n      subprocess.CalledProcessError: Command '['/usr/bin/cc', '-pthread', '-Wno-unused-result', '-Wsign-compare', '-Wunreachable-code',\n      '-DNDEBUG', '-g', '-fwrapv', '-O3', '-Wall', '-fPIC', '-fPIC', '-I/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/include',\n      '-I/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/include/python3.9', '-c', 'aiohttp/_multidict.c', '-o',\n      '/tmp/tmpv8li4pv2.build-temp/aiohttp/_multidict.o']' returned non-zero exit status 1.\n\n      The above exception was the direct cause of the following exception:\n\n      Traceback (most recent call last):\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/unixccompiler.py\", line 200, in _compile\n          self.spawn(compiler_so + cc_args + [src, '-o', obj] + extra_postargs)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/ccompiler.py\", line 1045, in spawn\n          spawn(cmd, dry_run=self.dry_run, **kwargs)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/spawn.py\", line 76, in spawn\n          raise DistutilsExecError(\n      distutils.errors.DistutilsExecError: command '/usr/bin/cc' failed with exit code 1\n\n      During handling of the above exception, another exception occurred:\n\n      Traceback (most recent call last):\n        File \"<string>\", line 43, in build_extension\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/command/build_ext.py\", line 557, in build_extension\n          objects = self.compiler.compile(\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/ccompiler.py\", line 606, in compile\n          self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/unixccompiler.py\", line 202, in _compile\n          raise CompileError(msg)\n      distutils.errors.CompileError: command '/usr/bin/cc' failed with exit code 1\n\n      During handling of the above exception, another exception occurred:\n\n      Traceback (most recent call last):\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/command/editable_wheel.py\", line 139, in run\n          self._create_wheel_file(bdist_wheel)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/command/editable_wheel.py\", line 340, in _create_wheel_file\n          files, mapping = self._run_build_commands(dist_name, unpacked, lib, tmp)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/command/editable_wheel.py\", line 263, in _run_build_commands\n          self._run_build_subcommands()\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/command/editable_wheel.py\", line 290, in _run_build_subcommands\n          self.run_command(name)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/cmd.py\", line 316, in run_command\n          self.distribution.run_command(command)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/dist.py\", line 995, in run_command\n          super().run_command(command)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/dist.py\", line 973, in run_command\n          cmd_obj.run()\n        File \"<string>\", line 37, in run\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/command/build_ext.py\", line 359, in run\n          self.build_extensions()\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/command/build_ext.py\", line 476, in build_extensions\n          self._build_extensions_serial()\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/command/build_ext.py\", line 502, in\n      _build_extensions_serial\n          self.build_extension(ext)\n        File \"<string>\", line 46, in build_extension\n      BuildFailed\n      /home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/dist.py:973: _DebuggingTips: Problem in editable installation.\n      !!\n\n              ********************************************************************************\n              An error happened while installing `aiohttp` in editable mode.\n\n              The following steps are recommended to help debug this problem:\n\n              - Try to install the project normally, without using the editable mode.\n                Does the error still persist?\n                (If it does, try fixing the problem before attempting the editable mode).\n              - If you are using binary extensions, make sure you have all OS-level\n                dependencies installed (e.g. compilers, toolchains, binary libraries, ...).\n              - Try the latest version of setuptools (maybe the error was already fixed).\n              - If you (or your project dependencies) are using any setuptools extension\n                or customization, make sure they support the editable mode.\n\n              After following the steps above, if the problem still persists and\n              you think this is related to how setuptools handles editable installations,\n              please submit a reproducible example\n              (see https://stackoverflow.com/help/minimal-reproducible-example) to:\n\n                  https://github.com/pypa/setuptools/issues\n\n              See https://setuptools.pypa.io/en/latest/userguide/development_mode.html for details.\n              ********************************************************************************\n\n      !!\n        cmd_obj.run()\n      Traceback (most recent call last):\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/spawn.py\", line 70, in spawn\n          subprocess.check_call(cmd, env=_inject_macos_ver(env))\n        File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/subprocess.py\", line 373, in check_call\n          raise CalledProcessError(retcode, cmd)\n      subprocess.CalledProcessError: Command '['/usr/bin/cc', '-pthread', '-Wno-unused-result', '-Wsign-compare', '-Wunreachable-code',\n      '-DNDEBUG', '-g', '-fwrapv', '-O3', '-Wall', '-fPIC', '-fPIC', '-I/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/include',\n      '-I/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/include/python3.9', '-c', 'aiohttp/_multidict.c', '-o',\n      '/tmp/tmpv8li4pv2.build-temp/aiohttp/_multidict.o']' returned non-zero exit status 1.\n\n      The above exception was the direct cause of the following exception:\n\n      Traceback (most recent call last):\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/unixccompiler.py\", line 200, in _compile\n          self.spawn(compiler_so + cc_args + [src, '-o', obj] + extra_postargs)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/ccompiler.py\", line 1045, in spawn\n          spawn(cmd, dry_run=self.dry_run, **kwargs)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/spawn.py\", line 76, in spawn\n          raise DistutilsExecError(\n      distutils.errors.DistutilsExecError: command '/usr/bin/cc' failed with exit code 1\n\n      During handling of the above exception, another exception occurred:\n\n      Traceback (most recent call last):\n        File \"<string>\", line 43, in build_extension\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/command/build_ext.py\", line 557, in build_extension\n          objects = self.compiler.compile(\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/ccompiler.py\", line 606, in compile\n          self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/unixccompiler.py\", line 202, in _compile\n          raise CompileError(msg)\n      distutils.errors.CompileError: command '/usr/bin/cc' failed with exit code 1\n\n      During handling of the above exception, another exception occurred:\n\n      Traceback (most recent call last):\n        File \"<string>\", line 107, in <module>\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/__init__.py\", line 117, in setup\n          return distutils.core.setup(**attrs)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/core.py\", line 183, in setup\n          return run_commands(dist)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/core.py\", line 199, in run_commands\n          dist.run_commands()\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/dist.py\", line 954, in run_commands\n          self.run_command(cmd)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/dist.py\", line 995, in run_command\n          super().run_command(command)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/dist.py\", line 973, in run_command\n          cmd_obj.run()\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/command/editable_wheel.py\", line 139, in run\n          self._create_wheel_file(bdist_wheel)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/command/editable_wheel.py\", line 340, in _create_wheel_file\n          files, mapping = self._run_build_commands(dist_name, unpacked, lib, tmp)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/command/editable_wheel.py\", line 263, in _run_build_commands\n          self._run_build_subcommands()\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/command/editable_wheel.py\", line 290, in _run_build_subcommands\n          self.run_command(name)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/cmd.py\", line 316, in run_command\n          self.distribution.run_command(command)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/dist.py\", line 995, in run_command\n          super().run_command(command)\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/dist.py\", line 973, in run_command\n          cmd_obj.run()\n        File \"<string>\", line 37, in run\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/command/build_ext.py\", line 359, in run\n          self.build_extensions()\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/command/build_ext.py\", line 476, in build_extensions\n          self._build_extensions_serial()\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/_distutils/command/build_ext.py\", line 502, in\n      _build_extensions_serial\n          self.build_extension(ext)\n        File \"<string>\", line 46, in build_extension\n      BuildFailed\n\n      During handling of the above exception, another exception occurred:\n\n      Traceback (most recent call last):\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/command/egg_info.py\", line 300, in run\n          os.utime(self.egg_info, None)\n      FileNotFoundError: [Errno 2] No such file or directory\n\n      The above exception was the direct cause of the following exception:\n\n      Traceback (most recent call last):\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/command/editable_wheel.py\", line 132, in run\n          self._ensure_dist_info()\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/command/editable_wheel.py\", line 151, in _ensure_dist_info\n          dist_info.run()\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/command/dist_info.py\", line 94, in run\n          self.egg_info.run()\n        File \"/home/gcpuser/.cache/uv/builds-v0/.tmpy3OGkA/lib/python3.9/site-packages/setuptools/command/egg_info.py\", line 303, in run\n          raise distutils.errors.DistutilsFileError(msg) from e\n      distutils.errors.DistutilsFileError: Cannot update time stamp of directory '/home/gcpuser/.cache/uv/builds-v0/.tmpVS2CvF/.tmp-y_60urwg/aiohttp.egg-info'\n      error: Cannot update time stamp of directory '/home/gcpuser/.cache/uv/builds-v0/.tmpVS2CvF/.tmp-y_60urwg/aiohttp.egg-info'\n\n      hint: This usually indicates a problem with the package or the build environment.\nmake: *** [Makefile:4: .install-deps] Error 1\nResolved 26 packages in 23ms\nInstalled 26 packages in 20ms\n + async-generator==1.10\n + async-timeout==5.0.1\n + brotlipy==0.7.0\n + cffi==1.17.1\n + chardet==5.2.0\n + coverage==7.6.10\n + cryptography==44.0.0\n + cython==3.0.11\n + exceptiongroup==1.2.2\n + gunicorn==23.0.0\n + idna==3.10\n + iniconfig==2.0.0\n + multdict==0.0.5\n + multidict==6.1.0\n + packaging==24.2\n + pluggy==1.5.0\n + propcache==0.2.1\n + pycparser==2.22\n + pytest==8.3.4\n + pytest-asyncio==0.25.0\n + pytest-cov==6.0.0\n + pytest-mock==3.14.0\n + tomli==2.2.1\n + trustme==1.2.1\n + typing-extensions==4.12.2\n + yarl==1.18.3\n",
    "new_commit_res_code": 1,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_a2aa20dacbeb34544cc69765e20dabe5718c0d57\nplugins: asyncio-0.25.0, mock-3.14.0, cov-6.0.0\nasyncio: mode=strict, asyncio_default_fixture_loop_scope=None\ncollected 64 items\n\nr2e_tests/test_1.py .....F.............................................. [ 81%]\n............                                                             [100%]\n\n=================================== FAILURES ===================================\n_______________ TestUrlDispatcher.test_add_route_with_invalid_re _______________\n\nself = <r2e_tests.test_1.TestUrlDispatcher testMethod=test_add_route_with_invalid_re>\n\n    def test_add_route_with_invalid_re(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError) as ctx:\n            self.router.add_route('GET', r'/handler/{to:+++}', handler)\n        s = str(ctx.exception)\n>       self.assertTrue(s.startswith(\n            \"Bad pattern '\\/handler\\/(?P<to>+++)': nothing to repeat\"), s)\nE       AssertionError: False is not true : Bad pattern '/handler/(?P<to>+++)': nothing to repeat at position 17\n\nr2e_tests/test_1.py:398: AssertionError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_invalid_path\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_invalid_method\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_not_started_with_slash\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_root\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_simple\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_with_re\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_with_re_and_slashes\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_with_re_including_slashes\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_with_re_not_match\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_static\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_url_escaping\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_url_invalid1\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_url_invalid2\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_url_invalid3\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_url_invalid4\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_with_matchdict\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_with_name\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_with_tailing_slash\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_any_method\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_contains\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_custom_expect_handler_dynamic\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_custom_expect_handler_plain\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_default_expect_handler\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_double_add_url_with_the_same_name\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_dynamic_match_non_ascii\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_dynamic_match_two_part2\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_dynamic_match_unquoted_path\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_dynamic_match_with_static_part\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_dynamic_not_match\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_dynamic_repr\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_dynamic_with_trailing_slash\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_expect_handler_non_coroutine\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_iter\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_len\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_match_second_result_in_table\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_not_allowed_repr\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_not_found_repr\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_plain_not_match\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_plain_repr\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_raise_method_not_allowed\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_raise_method_not_found\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_register_route\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_register_route_checks\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_regular_match_info\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_route_dynamic\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_route_dynamic_with_regex\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_route_dynamic_with_regex_spec\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_route_dynamic_with_regex_spec_and_trailing_slash\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_route_plain\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_route_unknown_route_name\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_route_with_qs\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_routes_abc\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_routes_view_contains\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_routes_view_iter\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_routes_view_len\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_static_adds_slash\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_static_dont_add_trailing_slash\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_static_handle_again\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_static_handle_eof\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_static_handle_exception\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_static_not_match\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_static_repr\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_system_route\nFAILED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_with_invalid_re\n========================= 1 failed, 63 passed in 0.13s =========================\n",
    "new_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_a2aa20dacbeb34544cc69765e20dabe5718c0d57/.venv/lib/python3.9/site-packages/pytest_asyncio/plugin.py:207: PytestDeprecationWarning: The configuration option \"asyncio_default_fixture_loop_scope\" is unset.\nThe event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: \"function\", \"class\", \"module\", \"package\", \"session\"\n\n  warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))\n",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_a2aa20dacbeb34544cc69765e20dabe5718c0d57\nplugins: asyncio-0.25.0, mock-3.14.0, cov-6.0.0\nasyncio: mode=strict, asyncio_default_fixture_loop_scope=None\ncollected 64 items\n\nr2e_tests/test_1.py .....F.....................................F........ [ 81%]\n............                                                             [100%]\n\n=================================== FAILURES ===================================\n_______________ TestUrlDispatcher.test_add_route_with_invalid_re _______________\n\nself = <r2e_tests.test_1.TestUrlDispatcher testMethod=test_add_route_with_invalid_re>\n\n    def test_add_route_with_invalid_re(self):\n        handler = self.make_handler()\n        with self.assertRaises(ValueError) as ctx:\n            self.router.add_route('GET', r'/handler/{to:+++}', handler)\n        s = str(ctx.exception)\n>       self.assertTrue(s.startswith(\n            \"Bad pattern '\\/handler\\/(?P<to>+++)': nothing to repeat\"), s)\nE       AssertionError: False is not true : Bad pattern '/handler/(?P<to>+++)': nothing to repeat at position 17\n\nr2e_tests/test_1.py:398: AssertionError\n_________________ TestUrlDispatcher.test_register_route_checks _________________\n\nself = <r2e_tests.test_1.TestUrlDispatcher testMethod=test_register_route_checks>\n\n    def test_register_route_checks(self):\n        self.assertRaises(\n            AssertionError, self.router.register_route, object())\n    \n        handler = self.make_handler()\n        route = PlainRoute('GET', handler, 'test', '/handler/to/path')\n        self.router.register_route(route)\n        self.assertRaises(ValueError, self.router.register_route, route)\n    \n        route = PlainRoute('GET', handler, '1bad name', '/handler/to/path')\n>       self.assertRaises(ValueError, self.router.register_route, route)\nE       AssertionError: ValueError not raised by register_route\n\nr2e_tests/test_1.py:81: AssertionError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_invalid_path\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_invalid_method\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_not_started_with_slash\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_root\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_simple\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_with_re\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_with_re_and_slashes\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_with_re_including_slashes\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_with_re_not_match\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_static\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_url_escaping\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_url_invalid1\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_url_invalid2\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_url_invalid3\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_url_invalid4\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_with_matchdict\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_with_name\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_add_with_tailing_slash\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_any_method\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_contains\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_custom_expect_handler_dynamic\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_custom_expect_handler_plain\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_default_expect_handler\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_double_add_url_with_the_same_name\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_dynamic_match_non_ascii\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_dynamic_match_two_part2\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_dynamic_match_unquoted_path\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_dynamic_match_with_static_part\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_dynamic_not_match\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_dynamic_repr\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_dynamic_with_trailing_slash\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_expect_handler_non_coroutine\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_iter\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_len\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_match_second_result_in_table\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_not_allowed_repr\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_not_found_repr\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_plain_not_match\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_plain_repr\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_raise_method_not_allowed\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_raise_method_not_found\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_register_route\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_regular_match_info\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_route_dynamic\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_route_dynamic_with_regex\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_route_dynamic_with_regex_spec\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_route_dynamic_with_regex_spec_and_trailing_slash\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_route_plain\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_route_unknown_route_name\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_route_with_qs\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_routes_abc\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_routes_view_contains\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_routes_view_iter\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_routes_view_len\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_static_adds_slash\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_static_dont_add_trailing_slash\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_static_handle_again\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_static_handle_eof\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_static_handle_exception\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_static_not_match\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_static_repr\nPASSED r2e_tests/test_1.py::TestUrlDispatcher::test_system_route\nFAILED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_with_invalid_re\nFAILED r2e_tests/test_1.py::TestUrlDispatcher::test_register_route_checks - A...\n========================= 2 failed, 62 passed in 0.18s =========================\n",
    "old_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_a2aa20dacbeb34544cc69765e20dabe5718c0d57/.venv/lib/python3.9/site-packages/pytest_asyncio/plugin.py:207: PytestDeprecationWarning: The configuration option \"asyncio_default_fixture_loop_scope\" is unset.\nThe event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: \"function\", \"class\", \"module\", \"package\", \"session\"\n\n  warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))\n"
}
aiohttp/web_urldispatcher.py tests/test_urldispatch.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Registering a Route with Invalid Name Does Not Raise ValueError

**Description:**
When attempting to register a route with a name that is either not a valid Python identifier or is a reserved keyword, the system does not raise a `ValueError` as expected. This allows invalid route names to be registered, which can lead to unexpected behavior and conflicts within the routing system.

**Example Code:**
```python
handler = make_handler()

# Attempt to register a route with an invalid name (starts with a number)
route = PlainRoute('GET', handler, '1bad name', '/handler/to/path')
router.register_route(route)

# Attempt to register a route with a reserved Python keyword
route = PlainRoute('GET', handler, 'return', '/handler/to/path')
router.register_route(route)
```

**Expected Behavior:**
Registering a route with an invalid name should raise a `ValueError` indicating that the route name must be a valid Python identifier and cannot be a reserved keyword. This validation ensures that all route names are unique and adhere to Python's naming conventions.

**Actual Behavior:**
No error is raised when registering routes with invalid names. As a result, the routes are added without proper validation, leading to potential naming conflicts and unexpected behavior in the routing system.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### aiohttp/web_urldispatcher.py
import abc
import asyncio

import collections
import mimetypes
import re
import os
import inspect

from collections.abc import Sized, Iterable, Container
from urllib.parse import urlencode, unquote

from . import hdrs
from .abc import AbstractRouter, AbstractMatchInfo
from .protocol import HttpVersion11
from .web_exceptions import HTTPMethodNotAllowed, HTTPNotFound, HTTPNotModified
from .web_reqrep import StreamResponse
from .multidict import upstr


__all__ = ('UrlDispatcher', 'UrlMappingMatchInfo',
           'Route', 'PlainRoute', 'DynamicRoute', 'StaticRoute')


class UrlMappingMatchInfo(dict, AbstractMatchInfo):

    def __init__(self, match_dict, route):
        super().__init__(match_dict)
        self._route = route

    @property
    def handler(self):
        return self._route.handler

    @property
    def route(self):
        return self._route

    def __repr__(self):
        return "<MatchInfo {}: {}>".format(super().__repr__(), self._route)


@asyncio.coroutine
def _defaultExpectHandler(request):
    """Default handler for Except: 100-continue"""
    if request.version == HttpVersion11:
        request.transport.write(b"HTTP/1.1 100 Continue\r\n\r\n")


class Route(metaclass=abc.ABCMeta):

    def __init__(self, method, handler, name, *, expect_handler=None):
        if expect_handler is None:
            expect_handler = _defaultExpectHandler
        assert asyncio.iscoroutinefunction(expect_handler), \
            'Coroutine is expected, got {!r}'.format(expect_handler)

        self._method = method
        self._handler = handler
        self._name = name
        self._expect_handler = expect_handler

    @property
    def method(self):
        return self._method

    @property
    def handler(self):
        return self._handler

    @property
    def name(self):
        return self._name

    @abc.abstractmethod  # pragma: no branch
    def match(self, path):
        """Return dict with info for given path or
        None if route cannot process path."""

    @abc.abstractmethod  # pragma: no branch
    def url(self, **kwargs):
        """Construct url for route with additional params."""

    @asyncio.coroutine
    def handle_expect_header(self, request):
        return (yield from self._expect_handler(request))

    @staticmethod
    def _append_query(url, query):
        if query is not None:
            return url + "?" + urlencode(query)
        else:
            return url


class PlainRoute(Route):

    def __init__(self, method, handler, name, path, *, expect_handler=None):
        super().__init__(method, handler, name, expect_handler=expect_handler)
        self._path = path

    def match(self, path):
        # string comparison is about 10 times faster than regexp matching
        if self._path == path:
            return {}
        else:
            return None

    def url(self, *, query=None):
        return self._append_query(self._path, query)

    def __repr__(self):
        name = "'" + self.name + "' " if self.name is not None else ""
        return "<PlainRoute {name}[{method}] {path} -> {handler!r}".format(
            name=name, method=self.method, path=self._path,
            handler=self.handler)


class DynamicRoute(Route):

    def __init__(self, method, handler, name, pattern, formatter, *,
                 expect_handler=None):
        super().__init__(method, handler, name, expect_handler=expect_handler)
        self._pattern = pattern
        self._formatter = formatter

    def match(self, path):
        match = self._pattern.match(path)
        if match is None:
            return None
        else:
            return match.groupdict()

    def url(self, *, parts, query=None):
        url = self._formatter.format_map(parts)
        return self._append_query(url, query)

    def __repr__(self):
        name = "'" + self.name + "' " if self.name is not None else ""
        return ("<DynamicRoute {name}[{method}] {formatter} -> {handler!r}"
                .format(name=name, method=self.method,
                        formatter=self._formatter, handler=self.handler))


class StaticRoute(Route):

    def __init__(self, name, prefix, directory, *,
                 expect_handler=None, chunk_size=256*1024,
                 response_factory=StreamResponse):
        assert prefix.startswith('/'), prefix
        assert prefix.endswith('/'), prefix
        super().__init__(
            'GET', self.handle, name, expect_handler=expect_handler)
        self._prefix = prefix
        self._prefix_len = len(self._prefix)
        self._directory = os.path.abspath(directory) + os.sep
        self._chunk_size = chunk_size
        self._response_factory = response_factory

        if not os.path.isdir(self._directory):
            raise ValueError(
                "No directory exists at '{}'".format(self._directory))

    def match(self, path):
        if not path.startswith(self._prefix):
            return None
        return {'filename': path[self._prefix_len:]}

    def url(self, *, filename, query=None):
        while filename.startswith('/'):
            filename = filename[1:]
        url = self._prefix + filename
        return self._append_query(url, query)

    def _sendfile_cb(self, fut, out_fd, in_fd, offset, count, loop,
                     registered):
        if registered:
            loop.remove_writer(out_fd)
        try:
            n = os.sendfile(out_fd, in_fd, offset, count)
            if n == 0:  # EOF reached
                n = count
        except (BlockingIOError, InterruptedError):
            n = 0
        except Exception as exc:
            fut.set_exception(exc)
            return

        if n < count:
            loop.add_writer(out_fd, self._sendfile_cb, fut, out_fd, in_fd,
                            offset + n, count - n, loop, True)
        else:
            fut.set_result(None)

    @asyncio.coroutine
    def _sendfile_system(self, req, resp, fobj, count):
        """
        Write `count` bytes of `fobj` to `resp` starting from `offset` using
        the ``sendfile`` system call.

        `req` should be a :obj:`aiohttp.web.Request` instance.

        `resp` should be a :obj:`aiohttp.web.StreamResponse` instance.

        `fobj` should be an open file object.

        `offset` should be an integer >= 0.

        `count` should be an integer > 0.
        """
        transport = req.transport

        if transport.get_extra_info("sslcontext"):
            yield from self._sendfile_fallback(req, resp, fobj, count)
            return

        yield from resp.drain()

        loop = req.app.loop
        out_fd = transport.get_extra_info("socket").fileno()
        in_fd = fobj.fileno()
        fut = asyncio.Future(loop=loop)

        self._sendfile_cb(fut, out_fd, in_fd, 0, count, loop, False)

        yield from fut

    @asyncio.coroutine
    def _sendfile_fallback(self, req, resp, fobj, count):
        """
        Mimic the :meth:`_sendfile_system` method, but without using the
        ``sendfile`` system call. This should be used on systems that don't
        support the ``sendfile`` system call.

        To avoid blocking the event loop & to keep memory usage low, `fobj` is
        transferred in chunks controlled by the `chunk_size` argument to
        :class:`StaticRoute`.
        """
        chunk_size = self._chunk_size

        chunk = fobj.read(chunk_size)
        while chunk and count > chunk_size:
            resp.write(chunk)
            yield from resp.drain()
            count = count - chunk_size
            chunk = fobj.read(chunk_size)

        if chunk:
            resp.write(chunk[:count])
            yield from resp.drain()

    if hasattr(os, "sendfile"):  # pragma: no cover
        _sendfile = _sendfile_system
    else:  # pragma: no cover
        _sendfile = _sendfile_fallback

    @asyncio.coroutine
    def handle(self, request):
        filename = request.match_info['filename']
        filepath = os.path.abspath(os.path.join(self._directory, filename))
        if not filepath.startswith(self._directory):
            raise HTTPNotFound()
        if not os.path.exists(filepath) or not os.path.isfile(filepath):
            raise HTTPNotFound()

        st = os.stat(filepath)

        modsince = request.if_modified_since
        if modsince is not None and st.st_mtime <= modsince.timestamp():
            raise HTTPNotModified()

        ct, encoding = mimetypes.guess_type(filepath)
        if not ct:
            ct = 'application/octet-stream'

        resp = self._response_factory()
        resp.content_type = ct
        if encoding:
            resp.headers[hdrs.CONTENT_ENCODING] = encoding
        resp.last_modified = st.st_mtime

        file_size = st.st_size

        resp.content_length = file_size
        yield from resp.prepare(request)

        with open(filepath, 'rb') as f:
            yield from self._sendfile(request, resp, f, file_size)

        return resp

    def __repr__(self):
        name = "'" + self.name + "' " if self.name is not None else ""
        return "<StaticRoute {name}[{method}] {path} -> {directory!r}".format(
            name=name, method=self.method, path=self._prefix,
            directory=self._directory)


class SystemRoute(Route):

    def __init__(self, status, reason):
        super().__init__(hdrs.METH_ANY, None, None)
        self._status = status
        self._reason = reason

    def url(self, **kwargs):
        raise RuntimeError(".url() is not allowed for SystemRoute")

    def match(self, path):
        return None

    @property
    def status(self):
        return self._status

    @property
    def reason(self):
        return self._reason

    def __repr__(self):
        return "<SystemRoute {status}: {reason}>".format(status=self._status,
                                                         reason=self._reason)


class _NotFoundMatchInfo(UrlMappingMatchInfo):

    route = SystemRoute(404, 'Not Found')

    def __init__(self):
        super().__init__({}, None)

    @property
    def handler(self):
        return self._not_found

    @asyncio.coroutine
    def _not_found(self, request):
        raise HTTPNotFound()

    def __repr__(self):
        return "<MatchInfo: not found>"


class _MethodNotAllowedMatchInfo(UrlMappingMatchInfo):

    route = SystemRoute(405, 'Method Not Allowed')

    def __init__(self, method, allowed_methods):
        super().__init__({}, None)
        self._method = method
        self._allowed_methods = allowed_methods

    @property
    def handler(self):
        return self._not_allowed

    @asyncio.coroutine
    def _not_allowed(self, request):
        raise HTTPMethodNotAllowed(self._method, self._allowed_methods)

    def __repr__(self):
        return ("<MatchInfo: method {} is not allowed (allowed methods: {}>"
                .format(self._method,
                        ', '.join(sorted(self._allowed_methods))))


class RoutesView(Sized, Iterable, Container):

    __slots__ = '_urls'

    def __init__(self, urls):
        self._urls = urls

    def __len__(self):
        return len(self._urls)

    def __iter__(self):
        yield from self._urls

    def __contains__(self, route):
        return route in self._urls


class UrlDispatcher(AbstractRouter, collections.abc.Mapping):

    DYN = re.compile(r'^\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*)\}$')
    DYN_WITH_RE = re.compile(
        r'^\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*):(?P<re>.+)\}$')
    GOOD = r'[^{}/]+'
    ROUTE_RE = re.compile(r'(\{[_a-zA-Z][^{}]*(?:\{[^{}]*\}[^{}]*)*\})')

    METHODS = {hdrs.METH_ANY, hdrs.METH_POST,
               hdrs.METH_GET, hdrs.METH_PUT, hdrs.METH_DELETE,
               hdrs.METH_PATCH, hdrs.METH_HEAD, hdrs.METH_OPTIONS}

    def __init__(self):
        super().__init__()
        self._urls = []
        self._routes = {}

    @asyncio.coroutine
    def resolve(self, request):
        path = request.raw_path
        method = request.method
        allowed_methods = set()

        for route in self._urls:
            match_dict = route.match(path)
            if match_dict is None:
                continue

            route_method = route.method
            if route_method == method or route_method == hdrs.METH_ANY:
                # Unquote separate matching parts
                match_dict = {key: unquote(value) for key, value in
                              match_dict.items()}
                return UrlMappingMatchInfo(match_dict, route)

            allowed_methods.add(route_method)
        else:
            if allowed_methods:
                return _MethodNotAllowedMatchInfo(method, allowed_methods)
            else:
                return _NotFoundMatchInfo()

    def __iter__(self):
        return iter(self._routes)

    def __len__(self):
        return len(self._routes)

    def __contains__(self, name):
        return name in self._routes

    def __getitem__(self, name):
        return self._routes[name]

    def routes(self):
        return RoutesView(self._urls)

    def register_route(self, route):
        assert isinstance(route, Route), 'Instance of Route class is required.'

        name = route.name
        if name is not None:
            if name in self._routes:
                raise ValueError('Duplicate {!r}, '
                                 'already handled by {!r}'
                                 .format(name, self._routes[name]))
            else:
                self._routes[name] = route
        self._urls.append(route)

    def add_route(self, method, path, handler,
                  *, name=None, expect_handler=None):

        if not path.startswith('/'):
            raise ValueError("path should be started with /")

        assert callable(handler), handler
        if (not asyncio.iscoroutinefunction(handler) and
                not inspect.isgeneratorfunction(handler)):
            handler = asyncio.coroutine(handler)

        method = upstr(method)
        if method not in self.METHODS:
            raise ValueError("{} is not allowed HTTP method".format(method))

        if not ('{' in path or '}' in path or self.ROUTE_RE.search(path)):
            route = PlainRoute(
                method, handler, name, path, expect_handler=expect_handler)
            self.register_route(route)
            return route

        pattern = ''
        formatter = ''
        for part in self.ROUTE_RE.split(path):
            match = self.DYN.match(part)
            if match:
                pattern += '(?P<{}>{})'.format(match.group('var'), self.GOOD)
                formatter += '{' + match.group('var') + '}'
                continue

            match = self.DYN_WITH_RE.match(part)
            if match:
                pattern += '(?P<{var}>{re})'.format(**match.groupdict())
                formatter += '{' + match.group('var') + '}'
                continue

            if '{' in part or '}' in part:
                raise ValueError("Invalid path '{}'['{}']".format(path, part))

            formatter += part
            pattern += re.escape(part)

        try:
            compiled = re.compile('^' + pattern + '$')
        except re.error as exc:
            raise ValueError(
                "Bad pattern '{}': {}".format(pattern, exc)) from None
        route = DynamicRoute(
            method, handler, name, compiled,
            formatter, expect_handler=expect_handler)
        self.register_route(route)
        return route

    def add_static(self, prefix, path, *, name=None, expect_handler=None,
                   chunk_size=256*1024, response_factory=StreamResponse):
        """
        Adds static files view
        :param prefix - url prefix
        :param path - folder with files
        """
        assert prefix.startswith('/')
        if not prefix.endswith('/'):
            prefix += '/'
        route = StaticRoute(name, prefix, path,
                            expect_handler=expect_handler,
                            chunk_size=chunk_size,
                            response_factory=response_factory)
        self.register_route(route)
        return route

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]
**Title:** Registering a Route with Invalid Name Does Not Raise ValueError

**Description:**
When attempting to register a route with a name that is either not a valid Python identifier or is a reserved keyword, the system does not raise a `ValueError` as expected. This allows invalid route names to be registered, which can lead to unexpected behavior and conflicts within the routing system.

**Example Code:**
```python
handler = make_handler()

# Attempt to register a route with an invalid name (starts with a number)
route = PlainRoute('GET', handler, '1bad name', '/handler/to/path')
router.register_route(route)

# Attempt to register a route with a reserved Python keyword
route = PlainRoute('GET', handler, 'return', '/handler/to/path')
router.register_route(route)
```

**Expected Behavior:**
Registering a route with an invalid name should raise a `ValueError` indicating that the route name must be a valid Python identifier and cannot be a reserved keyword. This validation ensures that all route names are unique and adhere to Python's naming conventions.

**Actual Behavior:**
No error is raised when registering routes with invalid names. As a result, the routes are added without proper validation, leading to potential naming conflicts and unexpected behavior in the routing system.

[/ISSUE]
{
    "TestUrlDispatcher.test_add_invalid_path": "PASSED",
    "TestUrlDispatcher.test_add_route_invalid_method": "PASSED",
    "TestUrlDispatcher.test_add_route_not_started_with_slash": "PASSED",
    "TestUrlDispatcher.test_add_route_root": "PASSED",
    "TestUrlDispatcher.test_add_route_simple": "PASSED",
    "TestUrlDispatcher.test_add_route_with_re": "PASSED",
    "TestUrlDispatcher.test_add_route_with_re_and_slashes": "PASSED",
    "TestUrlDispatcher.test_add_route_with_re_including_slashes": "PASSED",
    "TestUrlDispatcher.test_add_route_with_re_not_match": "PASSED",
    "TestUrlDispatcher.test_add_static": "PASSED",
    "TestUrlDispatcher.test_add_url_escaping": "PASSED",
    "TestUrlDispatcher.test_add_url_invalid1": "PASSED",
    "TestUrlDispatcher.test_add_url_invalid2": "PASSED",
    "TestUrlDispatcher.test_add_url_invalid3": "PASSED",
    "TestUrlDispatcher.test_add_url_invalid4": "PASSED",
    "TestUrlDispatcher.test_add_with_matchdict": "PASSED",
    "TestUrlDispatcher.test_add_with_name": "PASSED",
    "TestUrlDispatcher.test_add_with_tailing_slash": "PASSED",
    "TestUrlDispatcher.test_any_method": "PASSED",
    "TestUrlDispatcher.test_contains": "PASSED",
    "TestUrlDispatcher.test_custom_expect_handler_dynamic": "PASSED",
    "TestUrlDispatcher.test_custom_expect_handler_plain": "PASSED",
    "TestUrlDispatcher.test_default_expect_handler": "PASSED",
    "TestUrlDispatcher.test_double_add_url_with_the_same_name": "PASSED",
    "TestUrlDispatcher.test_dynamic_match_non_ascii": "PASSED",
    "TestUrlDispatcher.test_dynamic_match_two_part2": "PASSED",
    "TestUrlDispatcher.test_dynamic_match_unquoted_path": "PASSED",
    "TestUrlDispatcher.test_dynamic_match_with_static_part": "PASSED",
    "TestUrlDispatcher.test_dynamic_not_match": "PASSED",
    "TestUrlDispatcher.test_dynamic_repr": "PASSED",
    "TestUrlDispatcher.test_dynamic_with_trailing_slash": "PASSED",
    "TestUrlDispatcher.test_expect_handler_non_coroutine": "PASSED",
    "TestUrlDispatcher.test_iter": "PASSED",
    "TestUrlDispatcher.test_len": "PASSED",
    "TestUrlDispatcher.test_match_second_result_in_table": "PASSED",
    "TestUrlDispatcher.test_not_allowed_repr": "PASSED",
    "TestUrlDispatcher.test_not_found_repr": "PASSED",
    "TestUrlDispatcher.test_plain_not_match": "PASSED",
    "TestUrlDispatcher.test_plain_repr": "PASSED",
    "TestUrlDispatcher.test_raise_method_not_allowed": "PASSED",
    "TestUrlDispatcher.test_raise_method_not_found": "PASSED",
    "TestUrlDispatcher.test_register_route": "PASSED",
    "TestUrlDispatcher.test_register_route_checks": "PASSED",
    "TestUrlDispatcher.test_regular_match_info": "PASSED",
    "TestUrlDispatcher.test_route_dynamic": "PASSED",
    "TestUrlDispatcher.test_route_dynamic_with_regex": "PASSED",
    "TestUrlDispatcher.test_route_dynamic_with_regex_spec": "PASSED",
    "TestUrlDispatcher.test_route_dynamic_with_regex_spec_and_trailing_slash": "PASSED",
    "TestUrlDispatcher.test_route_plain": "PASSED",
    "TestUrlDispatcher.test_route_unknown_route_name": "PASSED",
    "TestUrlDispatcher.test_route_with_qs": "PASSED",
    "TestUrlDispatcher.test_routes_abc": "PASSED",
    "TestUrlDispatcher.test_routes_view_contains": "PASSED",
    "TestUrlDispatcher.test_routes_view_iter": "PASSED",
    "TestUrlDispatcher.test_routes_view_len": "PASSED",
    "TestUrlDispatcher.test_static_adds_slash": "PASSED",
    "TestUrlDispatcher.test_static_dont_add_trailing_slash": "PASSED",
    "TestUrlDispatcher.test_static_handle_again": "PASSED",
    "TestUrlDispatcher.test_static_handle_eof": "PASSED",
    "TestUrlDispatcher.test_static_handle_exception": "PASSED",
    "TestUrlDispatcher.test_static_not_match": "PASSED",
    "TestUrlDispatcher.test_static_repr": "PASSED",
    "TestUrlDispatcher.test_system_route": "PASSED",
    "TestUrlDispatcher.test_add_route_with_invalid_re": "FAILED"
}
diff --git a/aiohttp/web_urldispatcher.py b/aiohttp/web_urldispatcher.py
index 44f6460d..58c8c2e6 100644
--- a/aiohttp/web_urldispatcher.py
+++ b/aiohttp/web_urldispatcher.py
@@ -1,6 +1,7 @@
 import abc
 import asyncio
 
+import keyword
 import collections
 import mimetypes
 import re
@@ -442,8 +443,12 @@ class UrlDispatcher(AbstractRouter, collections.abc.Mapping):
         assert isinstance(route, Route), 'Instance of Route class is required.'
 
         name = route.name
+
         if name is not None:
-            if name in self._routes:
+            if not name.isidentifier() or keyword.iskeyword(name):
+                raise ValueError('Incorrect route name value, '
+                                 'Route name should be python identifier')
+            elif name in self._routes:
                 raise ValueError('Duplicate {!r}, '
                                  'already handled by {!r}'
                                  .format(name, self._routes[name]))

{"aiohttp/web_urldispatcher.py": "import abc\nimport asyncio\n\nimport collections\nimport mimetypes\nimport re\nimport os\nimport inspect\n\nfrom collections.abc import Sized, Iterable, Container\nfrom urllib.parse import urlencode, unquote\n\nfrom . import hdrs\nfrom .abc import AbstractRouter, AbstractMatchInfo\nfrom .protocol import HttpVersion11\nfrom .web_exceptions import HTTPMethodNotAllowed, HTTPNotFound, HTTPNotModified\nfrom .web_reqrep import StreamResponse\nfrom .multidict import upstr\n\n\n__all__ = ('UrlDispatcher', 'UrlMappingMatchInfo',\n           'Route', 'PlainRoute', 'DynamicRoute', 'StaticRoute')\n\n\nclass UrlMappingMatchInfo(dict, AbstractMatchInfo):\n\n    def __init__(self, match_dict, route):\n        super().__init__(match_dict)\n        self._route = route\n\n    @property\n    def handler(self):\n        return self._route.handler\n\n    @property\n    def route(self):\n        return self._route\n\n    def __repr__(self):\n        return \"<MatchInfo {}: {}>\".format(super().__repr__(), self._route)\n\n\n@asyncio.coroutine\ndef _defaultExpectHandler(request):\n    \"\"\"Default handler for Except: 100-continue\"\"\"\n    if request.version == HttpVersion11:\n        request.transport.write(b\"HTTP/1.1 100 Continue\\r\\n\\r\\n\")\n\n\nclass Route(metaclass=abc.ABCMeta):\n\n    def __init__(self, method, handler, name, *, expect_handler=None):\n        if expect_handler is None:\n            expect_handler = _defaultExpectHandler\n        assert asyncio.iscoroutinefunction(expect_handler), \\\n            'Coroutine is expected, got {!r}'.format(expect_handler)\n\n        self._method = method\n        self._handler = handler\n        self._name = name\n        self._expect_handler = expect_handler\n\n    @property\n    def method(self):\n        return self._method\n\n    @property\n    def handler(self):\n        return self._handler\n\n    @property\n    def name(self):\n        return self._name\n\n    @abc.abstractmethod  # pragma: no branch\n    def match(self, path):\n        \"\"\"Return dict with info for given path or\n        None if route cannot process path.\"\"\"\n\n    @abc.abstractmethod  # pragma: no branch\n    def url(self, **kwargs):\n        \"\"\"Construct url for route with additional params.\"\"\"\n\n    @asyncio.coroutine\n    def handle_expect_header(self, request):\n        return (yield from self._expect_handler(request))\n\n    @staticmethod\n    def _append_query(url, query):\n        if query is not None:\n            return url + \"?\" + urlencode(query)\n        else:\n            return url\n\n\nclass PlainRoute(Route):\n\n    def __init__(self, method, handler, name, path, *, expect_handler=None):\n        super().__init__(method, handler, name, expect_handler=expect_handler)\n        self._path = path\n\n    def match(self, path):\n        # string comparison is about 10 times faster than regexp matching\n        if self._path == path:\n            return {}\n        else:\n            return None\n\n    def url(self, *, query=None):\n        return self._append_query(self._path, query)\n\n    def __repr__(self):\n        name = \"'\" + self.name + \"' \" if self.name is not None else \"\"\n        return \"<PlainRoute {name}[{method}] {path} -> {handler!r}\".format(\n            name=name, method=self.method, path=self._path,\n            handler=self.handler)\n\n\nclass DynamicRoute(Route):\n\n    def __init__(self, method, handler, name, pattern, formatter, *,\n                 expect_handler=None):\n        super().__init__(method, handler, name, expect_handler=expect_handler)\n        self._pattern = pattern\n        self._formatter = formatter\n\n    def match(self, path):\n        match = self._pattern.match(path)\n        if match is None:\n            return None\n        else:\n            return match.groupdict()\n\n    def url(self, *, parts, query=None):\n        url = self._formatter.format_map(parts)\n        return self._append_query(url, query)\n\n    def __repr__(self):\n        name = \"'\" + self.name + \"' \" if self.name is not None else \"\"\n        return (\"<DynamicRoute {name}[{method}] {formatter} -> {handler!r}\"\n                .format(name=name, method=self.method,\n                        formatter=self._formatter, handler=self.handler))\n\n\nclass StaticRoute(Route):\n\n    def __init__(self, name, prefix, directory, *,\n                 expect_handler=None, chunk_size=256*1024,\n                 response_factory=StreamResponse):\n        assert prefix.startswith('/'), prefix\n        assert prefix.endswith('/'), prefix\n        super().__init__(\n            'GET', self.handle, name, expect_handler=expect_handler)\n        self._prefix = prefix\n        self._prefix_len = len(self._prefix)\n        self._directory = os.path.abspath(directory) + os.sep\n        self._chunk_size = chunk_size\n        self._response_factory = response_factory\n\n        if not os.path.isdir(self._directory):\n            raise ValueError(\n                \"No directory exists at '{}'\".format(self._directory))\n\n    def match(self, path):\n        if not path.startswith(self._prefix):\n            return None\n        return {'filename': path[self._prefix_len:]}\n\n    def url(self, *, filename, query=None):\n        while filename.startswith('/'):\n            filename = filename[1:]\n        url = self._prefix + filename\n        return self._append_query(url, query)\n\n    def _sendfile_cb(self, fut, out_fd, in_fd, offset, count, loop,\n                     registered):\n        if registered:\n            loop.remove_writer(out_fd)\n        try:\n            n = os.sendfile(out_fd, in_fd, offset, count)\n            if n == 0:  # EOF reached\n                n = count\n        except (BlockingIOError, InterruptedError):\n            n = 0\n        except Exception as exc:\n            fut.set_exception(exc)\n            return\n\n        if n < count:\n            loop.add_writer(out_fd, self._sendfile_cb, fut, out_fd, in_fd,\n                            offset + n, count - n, loop, True)\n        else:\n            fut.set_result(None)\n\n    @asyncio.coroutine\n    def _sendfile_system(self, req, resp, fobj, count):\n        \"\"\"\n        Write `count` bytes of `fobj` to `resp` starting from `offset` using\n        the ``sendfile`` system call.\n\n        `req` should be a :obj:`aiohttp.web.Request` instance.\n\n        `resp` should be a :obj:`aiohttp.web.StreamResponse` instance.\n\n        `fobj` should be an open file object.\n\n        `offset` should be an integer >= 0.\n\n        `count` should be an integer > 0.\n        \"\"\"\n        transport = req.transport\n\n        if transport.get_extra_info(\"sslcontext\"):\n            yield from self._sendfile_fallback(req, resp, fobj, count)\n            return\n\n        yield from resp.drain()\n\n        loop = req.app.loop\n        out_fd = transport.get_extra_info(\"socket\").fileno()\n        in_fd = fobj.fileno()\n        fut = asyncio.Future(loop=loop)\n\n        self._sendfile_cb(fut, out_fd, in_fd, 0, count, loop, False)\n\n        yield from fut\n\n    @asyncio.coroutine\n    def _sendfile_fallback(self, req, resp, fobj, count):\n        \"\"\"\n        Mimic the :meth:`_sendfile_system` method, but without using the\n        ``sendfile`` system call. This should be used on systems that don't\n        support the ``sendfile`` system call.\n\n        To avoid blocking the event loop & to keep memory usage low, `fobj` is\n        transferred in chunks controlled by the `chunk_size` argument to\n        :class:`StaticRoute`.\n        \"\"\"\n        chunk_size = self._chunk_size\n\n        chunk = fobj.read(chunk_size)\n        while chunk and count > chunk_size:\n            resp.write(chunk)\n            yield from resp.drain()\n            count = count - chunk_size\n            chunk = fobj.read(chunk_size)\n\n        if chunk:\n            resp.write(chunk[:count])\n            yield from resp.drain()\n\n    if hasattr(os, \"sendfile\"):  # pragma: no cover\n        _sendfile = _sendfile_system\n    else:  # pragma: no cover\n        _sendfile = _sendfile_fallback\n\n    @asyncio.coroutine\n    def handle(self, request):\n        filename = request.match_info['filename']\n        filepath = os.path.abspath(os.path.join(self._directory, filename))\n        if not filepath.startswith(self._directory):\n            raise HTTPNotFound()\n        if not os.path.exists(filepath) or not os.path.isfile(filepath):\n            raise HTTPNotFound()\n\n        st = os.stat(filepath)\n\n        modsince = request.if_modified_since\n        if modsince is not None and st.st_mtime <= modsince.timestamp():\n            raise HTTPNotModified()\n\n        ct, encoding = mimetypes.guess_type(filepath)\n        if not ct:\n            ct = 'application/octet-stream'\n\n        resp = self._response_factory()\n        resp.content_type = ct\n        if encoding:\n            resp.headers[hdrs.CONTENT_ENCODING] = encoding\n        resp.last_modified = st.st_mtime\n\n        file_size = st.st_size\n\n        resp.content_length = file_size\n        yield from resp.prepare(request)\n\n        with open(filepath, 'rb') as f:\n            yield from self._sendfile(request, resp, f, file_size)\n\n        return resp\n\n    def __repr__(self):\n        name = \"'\" + self.name + \"' \" if self.name is not None else \"\"\n        return \"<StaticRoute {name}[{method}] {path} -> {directory!r}\".format(\n            name=name, method=self.method, path=self._prefix,\n            directory=self._directory)\n\n\nclass SystemRoute(Route):\n\n    def __init__(self, status, reason):\n        super().__init__(hdrs.METH_ANY, None, None)\n        self._status = status\n        self._reason = reason\n\n    def url(self, **kwargs):\n        raise RuntimeError(\".url() is not allowed for SystemRoute\")\n\n    def match(self, path):\n        return None\n\n    @property\n    def status(self):\n        return self._status\n\n    @property\n    def reason(self):\n        return self._reason\n\n    def __repr__(self):\n        return \"<SystemRoute {status}: {reason}>\".format(status=self._status,\n                                                         reason=self._reason)\n\n\nclass _NotFoundMatchInfo(UrlMappingMatchInfo):\n\n    route = SystemRoute(404, 'Not Found')\n\n    def __init__(self):\n        super().__init__({}, None)\n\n    @property\n    def handler(self):\n        return self._not_found\n\n    @asyncio.coroutine\n    def _not_found(self, request):\n        raise HTTPNotFound()\n\n    def __repr__(self):\n        return \"<MatchInfo: not found>\"\n\n\nclass _MethodNotAllowedMatchInfo(UrlMappingMatchInfo):\n\n    route = SystemRoute(405, 'Method Not Allowed')\n\n    def __init__(self, method, allowed_methods):\n        super().__init__({}, None)\n        self._method = method\n        self._allowed_methods = allowed_methods\n\n    @property\n    def handler(self):\n        return self._not_allowed\n\n    @asyncio.coroutine\n    def _not_allowed(self, request):\n        raise HTTPMethodNotAllowed(self._method, self._allowed_methods)\n\n    def __repr__(self):\n        return (\"<MatchInfo: method {} is not allowed (allowed methods: {}>\"\n                .format(self._method,\n                        ', '.join(sorted(self._allowed_methods))))\n\n\nclass RoutesView(Sized, Iterable, Container):\n\n    __slots__ = '_urls'\n\n    def __init__(self, urls):\n        self._urls = urls\n\n    def __len__(self):\n        return len(self._urls)\n\n    def __iter__(self):\n        yield from self._urls\n\n    def __contains__(self, route):\n        return route in self._urls\n\n\nclass UrlDispatcher(AbstractRouter, collections.abc.Mapping):\n\n    DYN = re.compile(r'^\\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*)\\}$')\n    DYN_WITH_RE = re.compile(\n        r'^\\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*):(?P<re>.+)\\}$')\n    GOOD = r'[^{}/]+'\n    ROUTE_RE = re.compile(r'(\\{[_a-zA-Z][^{}]*(?:\\{[^{}]*\\}[^{}]*)*\\})')\n\n    METHODS = {hdrs.METH_ANY, hdrs.METH_POST,\n               hdrs.METH_GET, hdrs.METH_PUT, hdrs.METH_DELETE,\n               hdrs.METH_PATCH, hdrs.METH_HEAD, hdrs.METH_OPTIONS}\n\n    def __init__(self):\n        super().__init__()\n        self._urls = []\n        self._routes = {}\n\n    @asyncio.coroutine\n    def resolve(self, request):\n        path = request.raw_path\n        method = request.method\n        allowed_methods = set()\n\n        for route in self._urls:\n            match_dict = route.match(path)\n            if match_dict is None:\n                continue\n\n            route_method = route.method\n            if route_method == method or route_method == hdrs.METH_ANY:\n                # Unquote separate matching parts\n                match_dict = {key: unquote(value) for key, value in\n                              match_dict.items()}\n                return UrlMappingMatchInfo(match_dict, route)\n\n            allowed_methods.add(route_method)\n        else:\n            if allowed_methods:\n                return _MethodNotAllowedMatchInfo(method, allowed_methods)\n            else:\n                return _NotFoundMatchInfo()\n\n    def __iter__(self):\n        return iter(self._routes)\n\n    def __len__(self):\n        return len(self._routes)\n\n    def __contains__(self, name):\n        return name in self._routes\n\n    def __getitem__(self, name):\n        return self._routes[name]\n\n    def routes(self):\n        return RoutesView(self._urls)\n\n    def register_route(self, route):\n        assert isinstance(route, Route), 'Instance of Route class is required.'\n\n        name = route.name\n        if name is not None:\n            if name in self._routes:\n                raise ValueError('Duplicate {!r}, '\n                                 'already handled by {!r}'\n                                 .format(name, self._routes[name]))\n            else:\n                self._routes[name] = route\n        self._urls.append(route)\n\n    def add_route(self, method, path, handler,\n                  *, name=None, expect_handler=None):\n\n        if not path.startswith('/'):\n            raise ValueError(\"path should be started with /\")\n\n        assert callable(handler), handler\n        if (not asyncio.iscoroutinefunction(handler) and\n                not inspect.isgeneratorfunction(handler)):\n            handler = asyncio.coroutine(handler)\n\n        method = upstr(method)\n        if method not in self.METHODS:\n            raise ValueError(\"{} is not allowed HTTP method\".format(method))\n\n        if not ('{' in path or '}' in path or self.ROUTE_RE.search(path)):\n            route = PlainRoute(\n                method, handler, name, path, expect_handler=expect_handler)\n            self.register_route(route)\n            return route\n\n        pattern = ''\n        formatter = ''\n        for part in self.ROUTE_RE.split(path):\n            match = self.DYN.match(part)\n            if match:\n                pattern += '(?P<{}>{})'.format(match.group('var'), self.GOOD)\n                formatter += '{' + match.group('var') + '}'\n                continue\n\n            match = self.DYN_WITH_RE.match(part)\n            if match:\n                pattern += '(?P<{var}>{re})'.format(**match.groupdict())\n                formatter += '{' + match.group('var') + '}'\n                continue\n\n            if '{' in part or '}' in part:\n                raise ValueError(\"Invalid path '{}'['{}']\".format(path, part))\n\n            formatter += part\n            pattern += re.escape(part)\n\n        try:\n            compiled = re.compile('^' + pattern + '$')\n        except re.error as exc:\n            raise ValueError(\n                \"Bad pattern '{}': {}\".format(pattern, exc)) from None\n        route = DynamicRoute(\n            method, handler, name, compiled,\n            formatter, expect_handler=expect_handler)\n        self.register_route(route)\n        return route\n\n    def add_static(self, prefix, path, *, name=None, expect_handler=None,\n                   chunk_size=256*1024, response_factory=StreamResponse):\n        \"\"\"\n        Adds static files view\n        :param prefix - url prefix\n        :param path - folder with files\n        \"\"\"\n        assert prefix.startswith('/')\n        if not prefix.endswith('/'):\n            prefix += '/'\n        route = StaticRoute(name, prefix, path,\n                            expect_handler=expect_handler,\n                            chunk_size=chunk_size,\n                            response_factory=response_factory)\n        self.register_route(route)\n        return route\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Registering a Route with Invalid Name Does Not Raise ValueError

**Description:**
When attempting to register a route with a name that is either not a valid Python identifier or is a reserved keyword, the system does not raise a `ValueError` as expected. This allows invalid route names to be registered, which can lead to unexpected behavior and conflicts within the routing system.

**Example Code:**
```python
handler = make_handler()

# Attempt to register a route with an invalid name (starts with a number)
route = PlainRoute('GET', handler, '1bad name', '/handler/to/path')
router.register_route(route)

# Attempt to register a route with a reserved Python keyword
route = PlainRoute('GET', handler, 'return', '/handler/to/path')
router.register_route(route)
```

**Expected Behavior:**
Registering a route with an invalid name should raise a `ValueError` indicating that the route name must be a valid Python identifier and cannot be a reserved keyword. This validation ensures that all route names are unique and adhere to Python's naming conventions.

**Actual Behavior:**
No error is raised when registering routes with invalid names. As a result, the routes are added without proper validation, leading to potential naming conflicts and unexpected behavior in the routing system.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### aiohttp/web_urldispatcher.py
import abc
import asyncio

import collections
import mimetypes
import re
import os
import inspect

from collections.abc import Sized, Iterable, Container
from urllib.parse import urlencode, unquote

from . import hdrs
from .abc import AbstractRouter, AbstractMatchInfo
from .protocol import HttpVersion11
from .web_exceptions import HTTPMethodNotAllowed, HTTPNotFound, HTTPNotModified
from .web_reqrep import StreamResponse
from .multidict import upstr


__all__ = ('UrlDispatcher', 'UrlMappingMatchInfo',
           'Route', 'PlainRoute', 'DynamicRoute', 'StaticRoute')


class UrlMappingMatchInfo(dict, AbstractMatchInfo):

    def __init__(self, match_dict, route):
        super().__init__(match_dict)
        self._route = route

    @property
    def handler(self):
        return self._route.handler

    @property
    def route(self):
        return self._route

    def __repr__(self):
        return "<MatchInfo {}: {}>".format(super().__repr__(), self._route)


@asyncio.coroutine
def _defaultExpectHandler(request):
    """Default handler for Except: 100-continue"""
    if request.version == HttpVersion11:
        request.transport.write(b"HTTP/1.1 100 Continue\r\n\r\n")


class Route(metaclass=abc.ABCMeta):

    def __init__(self, method, handler, name, *, expect_handler=None):
        if expect_handler is None:
            expect_handler = _defaultExpectHandler
        assert asyncio.iscoroutinefunction(expect_handler), \
            'Coroutine is expected, got {!r}'.format(expect_handler)

        self._method = method
        self._handler = handler
        self._name = name
        self._expect_handler = expect_handler

    @property
    def method(self):
        return self._method

    @property
    def handler(self):
        return self._handler

    @property
    def name(self):
        return self._name

    @abc.abstractmethod  # pragma: no branch
    def match(self, path):
        """Return dict with info for given path or
        None if route cannot process path."""

    @abc.abstractmethod  # pragma: no branch
    def url(self, **kwargs):
        """Construct url for route with additional params."""

    @asyncio.coroutine
    def handle_expect_header(self, request):
        return (yield from self._expect_handler(request))

    @staticmethod
    def _append_query(url, query):
        if query is not None:
            return url + "?" + urlencode(query)
        else:
            return url


class PlainRoute(Route):

    def __init__(self, method, handler, name, path, *, expect_handler=None):
        super().__init__(method, handler, name, expect_handler=expect_handler)
        self._path = path

    def match(self, path):
        # string comparison is about 10 times faster than regexp matching
        if self._path == path:
            return {}
        else:
            return None

    def url(self, *, query=None):
        return self._append_query(self._path, query)

    def __repr__(self):
        name = "'" + self.name + "' " if self.name is not None else ""
        return "<PlainRoute {name}[{method}] {path} -> {handler!r}".format(
            name=name, method=self.method, path=self._path,
            handler=self.handler)


class DynamicRoute(Route):

    def __init__(self, method, handler, name, pattern, formatter, *,
                 expect_handler=None):
        super().__init__(method, handler, name, expect_handler=expect_handler)
        self._pattern = pattern
        self._formatter = formatter

    def match(self, path):
        match = self._pattern.match(path)
        if match is None:
            return None
        else:
            return match.groupdict()

    def url(self, *, parts, query=None):
        url = self._formatter.format_map(parts)
        return self._append_query(url, query)

    def __repr__(self):
        name = "'" + self.name + "' " if self.name is not None else ""
        return ("<DynamicRoute {name}[{method}] {formatter} -> {handler!r}"
                .format(name=name, method=self.method,
                        formatter=self._formatter, handler=self.handler))


class StaticRoute(Route):

    def __init__(self, name, prefix, directory, *,
                 expect_handler=None, chunk_size=256*1024,
                 response_factory=StreamResponse):
        assert prefix.startswith('/'), prefix
        assert prefix.endswith('/'), prefix
        super().__init__(
            'GET', self.handle, name, expect_handler=expect_handler)
        self._prefix = prefix
        self._prefix_len = len(self._prefix)
        self._directory = os.path.abspath(directory) + os.sep
        self._chunk_size = chunk_size
        self._response_factory = response_factory

        if not os.path.isdir(self._directory):
            raise ValueError(
                "No directory exists at '{}'".format(self._directory))

    def match(self, path):
        if not path.startswith(self._prefix):
            return None
        return {'filename': path[self._prefix_len:]}

    def url(self, *, filename, query=None):
        while filename.startswith('/'):
            filename = filename[1:]
        url = self._prefix + filename
        return self._append_query(url, query)

    def _sendfile_cb(self, fut, out_fd, in_fd, offset, count, loop,
                     registered):
        if registered:
            loop.remove_writer(out_fd)
        try:
            n = os.sendfile(out_fd, in_fd, offset, count)
            if n == 0:  # EOF reached
                n = count
        except (BlockingIOError, InterruptedError):
            n = 0
        except Exception as exc:
            fut.set_exception(exc)
            return

        if n < count:
            loop.add_writer(out_fd, self._sendfile_cb, fut, out_fd, in_fd,
                            offset + n, count - n, loop, True)
        else:
            fut.set_result(None)

    @asyncio.coroutine
    def _sendfile_system(self, req, resp, fobj, count):
        """
        Write `count` bytes of `fobj` to `resp` starting from `offset` using
        the ``sendfile`` system call.

        `req` should be a :obj:`aiohttp.web.Request` instance.

        `resp` should be a :obj:`aiohttp.web.StreamResponse` instance.

        `fobj` should be an open file object.

        `offset` should be an integer >= 0.

        `count` should be an integer > 0.
        """
        transport = req.transport

        if transport.get_extra_info("sslcontext"):
            yield from self._sendfile_fallback(req, resp, fobj, count)
            return

        yield from resp.drain()

        loop = req.app.loop
        out_fd = transport.get_extra_info("socket").fileno()
        in_fd = fobj.fileno()
        fut = asyncio.Future(loop=loop)

        self._sendfile_cb(fut, out_fd, in_fd, 0, count, loop, False)

        yield from fut

    @asyncio.coroutine
    def _sendfile_fallback(self, req, resp, fobj, count):
        """
        Mimic the :meth:`_sendfile_system` method, but without using the
        ``sendfile`` system call. This should be used on systems that don't
        support the ``sendfile`` system call.

        To avoid blocking the event loop & to keep memory usage low, `fobj` is
        transferred in chunks controlled by the `chunk_size` argument to
        :class:`StaticRoute`.
        """
        chunk_size = self._chunk_size

        chunk = fobj.read(chunk_size)
        while chunk and count > chunk_size:
            resp.write(chunk)
            yield from resp.drain()
            count = count - chunk_size
            chunk = fobj.read(chunk_size)

        if chunk:
            resp.write(chunk[:count])
            yield from resp.drain()

    if hasattr(os, "sendfile"):  # pragma: no cover
        _sendfile = _sendfile_system
    else:  # pragma: no cover
        _sendfile = _sendfile_fallback

    @asyncio.coroutine
    def handle(self, request):
        filename = request.match_info['filename']
        filepath = os.path.abspath(os.path.join(self._directory, filename))
        if not filepath.startswith(self._directory):
            raise HTTPNotFound()
        if not os.path.exists(filepath) or not os.path.isfile(filepath):
            raise HTTPNotFound()

        st = os.stat(filepath)

        modsince = request.if_modified_since
        if modsince is not None and st.st_mtime <= modsince.timestamp():
            raise HTTPNotModified()

        ct, encoding = mimetypes.guess_type(filepath)
        if not ct:
            ct = 'application/octet-stream'

        resp = self._response_factory()
        resp.content_type = ct
        if encoding:
            resp.headers[hdrs.CONTENT_ENCODING] = encoding
        resp.last_modified = st.st_mtime

        file_size = st.st_size

        resp.content_length = file_size
        yield from resp.prepare(request)

        with open(filepath, 'rb') as f:
            yield from self._sendfile(request, resp, f, file_size)

        return resp

    def __repr__(self):
        name = "'" + self.name + "' " if self.name is not None else ""
        return "<StaticRoute {name}[{method}] {path} -> {directory!r}".format(
            name=name, method=self.method, path=self._prefix,
            directory=self._directory)


class SystemRoute(Route):

    def __init__(self, status, reason):
        super().__init__(hdrs.METH_ANY, None, None)
        self._status = status
        self._reason = reason

    def url(self, **kwargs):
        raise RuntimeError(".url() is not allowed for SystemRoute")

    def match(self, path):
        return None

    @property
    def status(self):
        return self._status

    @property
    def reason(self):
        return self._reason

    def __repr__(self):
        return "<SystemRoute {status}: {reason}>".format(status=self._status,
                                                         reason=self._reason)


class _NotFoundMatchInfo(UrlMappingMatchInfo):

    route = SystemRoute(404, 'Not Found')

    def __init__(self):
        super().__init__({}, None)

    @property
    def handler(self):
        return self._not_found

    @asyncio.coroutine
    def _not_found(self, request):
        raise HTTPNotFound()

    def __repr__(self):
        return "<MatchInfo: not found>"


class _MethodNotAllowedMatchInfo(UrlMappingMatchInfo):

    route = SystemRoute(405, 'Method Not Allowed')

    def __init__(self, method, allowed_methods):
        super().__init__({}, None)
        self._method = method
        self._allowed_methods = allowed_methods

    @property
    def handler(self):
        return self._not_allowed

    @asyncio.coroutine
    def _not_allowed(self, request):
        raise HTTPMethodNotAllowed(self._method, self._allowed_methods)

    def __repr__(self):
        return ("<MatchInfo: method {} is not allowed (allowed methods: {}>"
                .format(self._method,
                        ', '.join(sorted(self._allowed_methods))))


class RoutesView(Sized, Iterable, Container):

    __slots__ = '_urls'

    def __init__(self, urls):
        self._urls = urls

    def __len__(self):
        return len(self._urls)

    def __iter__(self):
        yield from self._urls

    def __contains__(self, route):
        return route in self._urls


class UrlDispatcher(AbstractRouter, collections.abc.Mapping):

    DYN = re.compile(r'^\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*)\}$')
    DYN_WITH_RE = re.compile(
        r'^\{(?P<var>[a-zA-Z][_a-zA-Z0-9]*):(?P<re>.+)\}$')
    GOOD = r'[^{}/]+'
    ROUTE_RE = re.compile(r'(\{[_a-zA-Z][^{}]*(?:\{[^{}]*\}[^{}]*)*\})')

    METHODS = {hdrs.METH_ANY, hdrs.METH_POST,
               hdrs.METH_GET, hdrs.METH_PUT, hdrs.METH_DELETE,
               hdrs.METH_PATCH, hdrs.METH_HEAD, hdrs.METH_OPTIONS}

    def __init__(self):
        super().__init__()
        self._urls = []
        self._routes = {}

    @asyncio.coroutine
    def resolve(self, request):
        path = request.raw_path
        method = request.method
        allowed_methods = set()

        for route in self._urls:
            match_dict = route.match(path)
            if match_dict is None:
                continue

            route_method = route.method
            if route_method == method or route_method == hdrs.METH_ANY:
                # Unquote separate matching parts
                match_dict = {key: unquote(value) for key, value in
                              match_dict.items()}
                return UrlMappingMatchInfo(match_dict, route)

            allowed_methods.add(route_method)
        else:
            if allowed_methods:
                return _MethodNotAllowedMatchInfo(method, allowed_methods)
            else:
                return _NotFoundMatchInfo()

    def __iter__(self):
        return iter(self._routes)

    def __len__(self):
        return len(self._routes)

    def __contains__(self, name):
        return name in self._routes

    def __getitem__(self, name):
        return self._routes[name]

    def routes(self):
        return RoutesView(self._urls)

    def register_route(self, route):
        assert isinstance(route, Route), 'Instance of Route class is required.'

        name = route.name
        if name is not None:
            if name in self._routes:
                raise ValueError('Duplicate {!r}, '
                                 'already handled by {!r}'
                                 .format(name, self._routes[name]))
            else:
                self._routes[name] = route
        self._urls.append(route)

    def add_route(self, method, path, handler,
                  *, name=None, expect_handler=None):

        if not path.startswith('/'):
            raise ValueError("path should be started with /")

        assert callable(handler), handler
        if (not asyncio.iscoroutinefunction(handler) and
                not inspect.isgeneratorfunction(handler)):
            handler = asyncio.coroutine(handler)

        method = upstr(method)
        if method not in self.METHODS:
            raise ValueError("{} is not allowed HTTP method".format(method))

        if not ('{' in path or '}' in path or self.ROUTE_RE.search(path)):
            route = PlainRoute(
                method, handler, name, path, expect_handler=expect_handler)
            self.register_route(route)
            return route

        pattern = ''
        formatter = ''
        for part in self.ROUTE_RE.split(path):
            match = self.DYN.match(part)
            if match:
                pattern += '(?P<{}>{})'.format(match.group('var'), self.GOOD)
                formatter += '{' + match.group('var') + '}'
                continue

            match = self.DYN_WITH_RE.match(part)
            if match:
                pattern += '(?P<{var}>{re})'.format(**match.groupdict())
                formatter += '{' + match.group('var') + '}'
                continue

            if '{' in part or '}' in part:
                raise ValueError("Invalid path '{}'['{}']".format(path, part))

            formatter += part
            pattern += re.escape(part)

        try:
            compiled = re.compile('^' + pattern + '$')
        except re.error as exc:
            raise ValueError(
                "Bad pattern '{}': {}".format(pattern, exc)) from None
        route = DynamicRoute(
            method, handler, name, compiled,
            formatter, expect_handler=expect_handler)
        self.register_route(route)
        return route

    def add_static(self, prefix, path, *, name=None, expect_handler=None,
                   chunk_size=256*1024, response_factory=StreamResponse):
        """
        Adds static files view
        :param prefix - url prefix
        :param path - folder with files
        """
        assert prefix.startswith('/')
        if not prefix.endswith('/'):
            prefix += '/'
        route = StaticRoute(name, prefix, path,
                            expect_handler=expect_handler,
                            chunk_size=chunk_size,
                            response_factory=response_factory)
        self.register_route(route)
        return route

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user