{
    "file_diffs": [
        {
            "old_file_content": "__all__ = ('UrlDispatcher', 'UrlMappingMatchInfo',\n           'Route', 'PlainRoute', 'DynamicRoute', 'StaticRoute')\n\nimport abc\nimport asyncio\n\nimport collections\nimport mimetypes\nimport re\nimport os\nimport inspect\n\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\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        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\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    @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 = StreamResponse()\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        single_chunk = file_size < self._chunk_size\n\n        if single_chunk:\n            resp.content_length = file_size\n        resp.start(request)\n\n        with open(filepath, 'rb') as f:\n            chunk = f.read(self._chunk_size)\n            if single_chunk:\n                resp.write(chunk)\n            else:\n                while chunk:\n                    resp.write(chunk)\n                    chunk = f.read(self._chunk_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 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 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        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        assert method in self.METHODS, 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):\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        self.register_route(route)\n        return route\n",
            "new_file_content": "__all__ = ('UrlDispatcher', 'UrlMappingMatchInfo',\n           'Route', 'PlainRoute', 'DynamicRoute', 'StaticRoute')\n\nimport abc\nimport asyncio\n\nimport collections\nimport mimetypes\nimport re\nimport os\nimport inspect\n\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\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        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\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    @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 = StreamResponse()\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        single_chunk = file_size < self._chunk_size\n\n        if single_chunk:\n            resp.content_length = file_size\n        resp.start(request)\n\n        with open(filepath, 'rb') as f:\n            chunk = f.read(self._chunk_size)\n            if single_chunk:\n                resp.write(chunk)\n            else:\n                while chunk:\n                    resp.write(chunk)\n                    chunk = f.read(self._chunk_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 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 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):\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        self.register_route(route)\n        return route\n",
            "header": {
                "file": {
                    "path": "aiohttp/web_urldispatcher.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "6255f00f",
                "new_commit_hash": "0c9b33ee",
                "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": 356,
                            "length": 13
                        },
                        "new_range": {
                            "start": 356,
                            "length": 17
                        },
                        "section": "class UrlDispatcher(AbstractRouter, collections.abc.Mapping):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    def add_route(self, method, path, handler,",
                                "type": "context"
                            },
                            {
                                "content": "                  *, name=None, expect_handler=None):",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        if not path.startswith('/'):",
                                "type": "added"
                            },
                            {
                                "content": "            raise ValueError(\"path should be started with /\")",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        assert callable(handler), handler",
                                "type": "context"
                            },
                            {
                                "content": "        if (not asyncio.iscoroutinefunction(handler) and",
                                "type": "context"
                            },
                            {
                                "content": "                not inspect.isgeneratorfunction(handler)):",
                                "type": "context"
                            },
                            {
                                "content": "            handler = asyncio.coroutine(handler)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        method = upstr(method)",
                                "type": "context"
                            },
                            {
                                "content": "        assert method in self.METHODS, method",
                                "type": "deleted"
                            },
                            {
                                "content": "        if method not in self.METHODS:",
                                "type": "added"
                            },
                            {
                                "content": "            raise ValueError(\"{} is not allowed HTTP method\".format(method))",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        if not ('{' in path or '}' in path or self.ROUTE_RE.search(path)):",
                                "type": "context"
                            },
                            {
                                "content": "            route = PlainRoute(",
                                "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 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        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        assert method in self.METHODS, 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):\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        self.register_route(route)\n        return route",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 289,
                            "end_lineno": 419,
                            "parent": null
                        },
                        {
                            "file_name": "aiohttp/web_urldispatcher.py",
                            "type": "method",
                            "name": "UrlDispatcher.add_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 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        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        assert method in self.METHODS, 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):\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        self.register_route(route)\n        return route",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 356,
                            "end_lineno": 403,
                            "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 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        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        assert method in self.METHODS, 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):\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        self.register_route(route)\n        return route",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 289,
                                "end_lineno": 419,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": ".. _aiohttp-web-reference:\n\nHTTP Server Reference\n=====================\n\n.. highlight:: python\n\n.. module:: aiohttp.web\n\n.. versionchanged:: 0.12\n\n   The module was deeply refactored in backward incompatible manner.\n\n.. _aiohttp-web-request:\n\n\nRequest\n-------\n\nThe Request object contains all the information about an incoming HTTP request.\n\nEvery :ref:`handler<aiohttp-web-handler>` accepts a request instance as the\nfirst positional parameter.\n\n.. note::\n\n   You should never create the :class:`Request` instance manually --\n   :mod:`aiohttp.web` does it for you.\n\n.. class:: Request\n\n   .. attribute:: scheme\n\n      A string representing the scheme of the request.\n\n      The scheme is ``'https'`` if transport for request handling is\n      *SSL* or ``secure_proxy_ssl_header`` is matching.\n\n      ``'http'`` otherwise.\n\n      Read-only :class:`str` property.\n\n   .. attribute:: method\n\n      *HTTP method*, read-only property.\n\n      The value is upper-cased :class:`str` like ``\"GET\"``,\n      ``\"POST\"``, ``\"PUT\"`` etc.\n\n   .. attribute:: version\n\n      *HTTP version* of request, Read-only property.\n\n      Returns :class:`aiohttp.protocol.HttpVersion` instance.\n\n   .. attribute:: host\n\n      *HOST* header of request, Read-only property.\n\n      Returns :class:`str` or ``None`` if HTTP request has no *HOST* header.\n\n   .. attribute:: path_qs\n\n      The URL including PATH_INFO and the query string. e.g, ``/app/blog?id=10``\n\n      Read-only :class:`str` property.\n\n   .. attribute:: path\n\n      The URL including *PATH INFO* without the host or scheme. e.g.,\n      ``/app/blog``. The path is URL-unquoted. For raw path info see\n      :attr:`raw_path`.\n\n      Read-only :class:`str` property.\n\n   .. attribute:: raw_path\n\n      The URL including raw *PATH INFO* without the host or scheme.\n      Warning, the path may be quoted and may contains non valid URL\n      characters, e.g.\n      ``/my%2Fpath%7Cwith%21some%25strange%24characters``.\n\n      For unquoted version please take a look on :attr:`path`.\n\n      Read-only :class:`str` property.\n\n   .. attribute:: query_string\n\n      The query string in the URL, e.g., ``id=10``\n\n      Read-only :class:`str` property.\n\n   .. attribute:: GET\n\n      A multidict with all the variables in the query string.\n\n      Read-only :class:`~aiohttp.multidict.MultiDictProxy` lazy property.\n\n   .. attribute:: POST\n\n      A multidict with all the variables in the POST parameters.\n      POST property available only after :meth:`Request.post` coroutine call.\n\n      Read-only :class:`~aiohttp.multidict.MultiDictProxy`.\n\n      :raises RuntimeError: if :meth:`Request.post` was not called \\\n                            before accessing the property.\n\n   .. attribute:: headers\n\n      A case-insensitive multidict proxy with all headers.\n\n      Read-only :class:`~aiohttp.multidict.CIMultiDictProxy` property.\n\n   .. attribute:: keep_alive\n\n      ``True`` if keep-alive connection enabled by HTTP client and\n      protocol version supports it, otherwise ``False``.\n\n      Read-only :class:`bool` property.\n\n   .. attribute:: match_info\n\n      Read-only property with :class:`~aiohttp.abc.AbstractMatchInfo`\n      instance for result of route resolving.\n\n      .. note::\n\n         Exact type of property depends on used router.  If\n         ``app.router`` is :class:`UrlDispatcher` the property contains\n         :class:`UrlMappingMatchInfo` instance.\n\n   .. attribute:: app\n\n      An :class:`Application` instance used to call :ref:`request handler\n      <aiohttp-web-handler>`, Read-only property.\n\n   .. attribute:: transport\n\n      An :ref:`transport<asyncio-transport>` used to process request,\n      Read-only property.\n\n      The property can be used, for example, for getting IP address of\n      client's peer::\n\n         peername = request.transport.get_extra_info('peername')\n         if peername is not None:\n             host, port = peername\n\n   .. attribute:: cookies\n\n      A multidict of all request's cookies.\n\n      Read-only :class:`~aiohttp.multidict.MultiDictProxy` lazy property.\n\n   .. attribute:: content\n\n      A :class:`~aiohttp.streams.FlowControlStreamReader` instance,\n      input stream for reading request's *BODY*.\n\n      Read-only property.\n\n      .. versionadded:: 0.15\n\n   .. attribute:: has_body\n\n      Return ``True`` if request has *HTTP BODY*, ``False`` otherwise.\n\n      Read-only :class:`bool` property.\n\n      .. versionadded:: 0.16\n\n   .. attribute:: payload\n\n      A :class:`~aiohttp.streams.FlowControlStreamReader` instance,\n      input stream for reading request's *BODY*.\n\n      Read-only property.\n\n      .. deprecated:: 0.15\n\n         Use :attr:`~Request.content` instead.\n\n   .. attribute:: content_type\n\n      Read-only property with *content* part of *Content-Type* header.\n\n      Returns :class:`str` like ``'text/html'``\n\n      .. note::\n\n         Returns value is ``'application/octet-stream'`` if no\n         Content-Type header present in HTTP headers according to\n         :rfc:`2616`\n\n   .. attribute:: charset\n\n      Read-only property that specifies the *encoding* for the request's BODY.\n\n      The value is parsed from the *Content-Type* HTTP header.\n\n      Returns :class:`str` like ``'utf-8'`` or ``None`` if\n      *Content-Type* has no charset information.\n\n   .. attribute:: content_length\n\n      Read-only property that returns length of the request's BODY.\n\n      The value is parsed from the *Content-Length* HTTP header.\n\n      Returns :class:`int` or ``None`` if *Content-Length* is absent.\n\n   .. attribute:: if_modified_since\n\n      Read-only property that returns the date specified in the\n      *If-Modified-Since* header.\n\n      Returns :class:`datetime.datetime` or ``None`` if\n      *If-Modified-Since* header is absent or is not a valid\n      HTTP date.\n\n   .. coroutinemethod:: read()\n\n      Read request body, returns :class:`bytes` object with body content.\n\n      .. note::\n\n         The method **does** store read data internally, subsequent\n         :meth:`~Request.read` call will return the same value.\n\n   .. coroutinemethod:: text()\n\n      Read request body, decode it using :attr:`charset` encoding or\n      ``UTF-8`` if no encoding was specified in *MIME-type*.\n\n      Returns :class:`str` with body content.\n\n      .. note::\n\n         The method **does** store read data internally, subsequent\n         :meth:`~Request.text` call will return the same value.\n\n   .. coroutinemethod:: json(*, loader=json.loads)\n\n      Read request body decoded as *json*.\n\n      The method is just a boilerplate :ref:`coroutine <coroutine>`\n      implemented as::\n\n         @asyncio.coroutine\n         def json(self, *, loader=json.loads):\n             body = yield from self.text()\n             return loader(body)\n\n      :param callable loader: any :term:`callable` that accepts\n                              :class:`str` and returns :class:`dict`\n                              with parsed JSON (:func:`json.loads` by\n                              default).\n\n      .. note::\n\n         The method **does** store read data internally, subsequent\n         :meth:`~Request.json` call will return the same value.\n\n   .. coroutinemethod:: post()\n\n      A :ref:`coroutine <coroutine>` that reads POST parameters from\n      request body.\n\n      Returns :class:`~aiohttp.multidict.MultiDictProxy` instance filled\n      with parsed data.\n\n      If :attr:`method` is not *POST*, *PUT* or *PATCH* or\n      :attr:`content_type` is not empty or\n      *application/x-www-form-urlencoded* or *multipart/form-data*\n      returns empty multidict.\n\n      .. note::\n\n         The method **does** store read data internally, subsequent\n         :meth:`~Request.post` call will return the same value.\n\n   .. coroutinemethod:: release()\n\n      Release request.\n\n      Eat unread part of HTTP BODY if present.\n\n      .. note::\n\n          User code may never call :meth:`~Request.release`, all\n          required work will be processed by :mod:`aiohttp.web`\n          internal machinery.\n\n\n.. _aiohttp-web-response:\n\n\nResponse classes\n----------------\n\nFor now, :mod:`aiohttp.web` has two classes for the *HTTP response*:\n:class:`StreamResponse` and :class:`Response`.\n\nUsually you need to use the second one. :class:`StreamResponse` is\nintended for streaming data, while :class:`Response` contains *HTTP\nBODY* as an attribute and sends own content as single piece with the\ncorrect *Content-Length HTTP header*.\n\nFor sake of design decisions :class:`Response` is derived from\n:class:`StreamResponse` parent class.\n\nThe response supports *keep-alive* handling out-of-the-box if\n*request* supports it.\n\nYou can disable *keep-alive* by :meth:`~StreamResponse.force_close` though.\n\nThe common case for sending an answer from\n:ref:`web-handler<aiohttp-web-handler>` is returning a\n:class:`Response` instance::\n\n   def handler(request):\n       return Response(\"All right!\")\n\n\nStreamResponse\n^^^^^^^^^^^^^^\n\n.. class:: StreamResponse(*, status=200, reason=None)\n\n   The base class for the *HTTP response* handling.\n\n   Contains methods for setting *HTTP response headers*, *cookies*,\n   *response status code*, writing *HTTP response BODY* and so on.\n\n   The most important thing you should know about *response* --- it\n   is *Finite State Machine*.\n\n   That means you can do any manipulations with *headers*,\n   *cookies* and *status code* only before :meth:`start`\n   called.\n\n   Once you call :meth:`start` any change of\n   the *HTTP header* part will raise :exc:`RuntimeError` exception.\n\n   Any :meth:`write` call after :meth:`write_eof` is also forbidden.\n\n   :param int status: HTTP status code, ``200`` by default.\n\n   :param str reason: HTTP reason. If param is ``None`` reason will be\n                      calculated basing on *status*\n                      parameter. Otherwise pass :class:`str` with\n                      arbitrary *status* explanation..\n\n   .. attribute:: started\n\n      Read-only :class:`bool` property, ``True`` if :meth:`start` has\n      been called, ``False`` otherwise.\n\n   .. attribute:: status\n\n      Read-only property for *HTTP response status code*, :class:`int`.\n\n      ``200`` (OK) by default.\n\n   .. attribute:: reason\n\n      Read-only property for *HTTP response reason*, :class:`str`.\n\n   .. method:: set_status(status, reason=None)\n\n      Set :attr:`status` and :attr:`reason`.\n\n      *reason* value is auto calculated if not specified (``None``).\n\n   .. attribute:: keep_alive\n\n      Read-only property, copy of :attr:`Request.keep_alive` by default.\n\n      Can be switched to ``False`` by :meth:`force_close` call.\n\n   .. method:: force_close\n\n      Disable :attr:`keep_alive` for connection. There are no ways to\n      enable it back.\n\n   .. attribute:: compression\n\n      Read-only :class:`bool` property, ``True`` if compression is enabled.\n\n      ``False`` by default.\n\n      .. versionadded:: 0.14\n\n      .. seealso:: :meth:`enable_compression`\n\n   .. method:: enable_compression(force=None)\n\n      Enable compression.\n\n      When *force* is unset compression encoding is selected based on\n      the request's *Accept-Encoding* header.\n\n      *Accept-Encoding* is not checked if *force* is set to a\n      :class:`ContentCoding`.\n\n      .. versionadded:: 0.14\n\n      .. seealso:: :attr:`compression`\n\n   .. attribute:: chunked\n\n      Read-only property, indicates if chunked encoding is on.\n\n      Can be enabled by :meth:`enable_chunked_encoding` call.\n\n      .. versionadded:: 0.14\n\n      .. seealso:: :attr:`enable_chunked_encoding`\n\n   .. method:: enable_chunked_encoding\n\n      Enables :attr:`chunked` encoding for response. There are no ways to\n      disable it back. With enabled :attr:`chunked` encoding each `write()`\n      operation encoded in separate chunk.\n\n      .. versionadded:: 0.14\n\n      .. seealso:: :attr:`chunked`\n\n   .. attribute:: headers\n\n      :class:`~aiohttp.multidict.CIMultiDict` instance\n      for *outgoing* *HTTP headers*.\n\n   .. attribute:: cookies\n\n      An instance of :class:`http.cookies.SimpleCookie` for *outgoing* cookies.\n\n      .. warning::\n\n         Direct setting up *Set-Cookie* header may be overwritten by\n         explicit calls to cookie manipulation.\n\n         We are encourage using of :attr:`cookies` and\n         :meth:`set_cookie`, :meth:`del_cookie` for cookie\n         manipulations.\n\n   .. method:: set_cookie(name, value, *, path='/', expires=None, \\\n                   domain=None, max_age=None, \\\n                   secure=None, httponly=None, version=None)\n\n      Convenient way for setting :attr:`cookies`, allows to specify\n      some additional properties like *max_age* in a single call.\n\n      :param str name: cookie name\n\n      :param str value: cookie value (will be converted to\n                        :class:`str` if value has another type).\n\n      :param expires: expiration date (optional)\n\n      :param str domain: cookie domain (optional)\n\n      :param int max_age: defines the lifetime of the cookie, in\n                          seconds.  The delta-seconds value is a\n                          decimal non- negative integer.  After\n                          delta-seconds seconds elapse, the client\n                          should discard the cookie.  A value of zero\n                          means the cookie should be discarded\n                          immediately.  (optional)\n\n      :param str path: specifies the subset of URLs to\n                       which this cookie applies. (optional, ``'/'`` by default)\n\n      :param bool secure: attribute (with no value) directs\n                          the user agent to use only (unspecified)\n                          secure means to contact the origin server\n                          whenever it sends back this cookie.\n                          The user agent (possibly under the user's\n                          control) may determine what level of\n                          security it considers appropriate for\n                          \"secure\" cookies.  The *secure* should be\n                          considered security advice from the server\n                          to the user agent, indicating that it is in\n                          the session's interest to protect the cookie\n                          contents. (optional)\n\n      :param bool httponly: ``True`` if the cookie HTTP only (optional)\n\n      :param int version: a decimal integer, identifies to which\n                          version of the state management\n                          specification the cookie\n                          conforms. (Optional, *version=1* by default)\n\n      .. versionchanged:: 0.14.3\n\n         Default value for *path* changed from ``None`` to ``'/'``.\n\n   .. method:: del_cookie(name, *, path='/', domain=None)\n\n      Deletes cookie.\n\n      :param str name: cookie name\n\n      :param str domain: optional cookie domain\n\n      :param str path: optional cookie path, ``'/'`` by default\n\n      .. versionchanged:: 0.14.3\n\n         Default value for *path* changed from ``None`` to ``'/'``.\n\n   .. attribute:: content_length\n\n      *Content-Length* for outgoing response.\n\n   .. attribute:: content_type\n\n      *Content* part of *Content-Type* for outgoing response.\n\n   .. attribute:: charset\n\n      *Charset* aka *encoding* part of *Content-Type* for outgoing response.\n\n      The value converted to lower-case on attribute assigning.\n\n   .. attribute:: last_modified\n\n      *Last-Modified* header for outgoing response.\n\n      This property accepts raw :class:`str` values,\n      :class:`datetime.datetime` objects, Unix timestamps specified\n      as an :class:`int` or a :class:`float` object, and the\n      value ``None`` to unset the header.\n\n   .. method:: start(request)\n\n      :param aiohttp.web.Request request: HTTP request object, that the\n                                          response answers.\n\n      Send *HTTP header*. You should not change any header data after\n      calling this method.\n\n   .. method:: write(data)\n\n      Send byte-ish data as the part of *response BODY*.\n\n      :meth:`start` must be called before.\n\n      Raises :exc:`TypeError` if data is not :class:`bytes`,\n      :class:`bytearray` or :class:`memoryview` instance.\n\n      Raises :exc:`RuntimeError` if :meth:`start` has not been called.\n\n      Raises :exc:`RuntimeError` if :meth:`write_eof` has been called.\n\n   .. coroutinemethod:: drain()\n\n      A :ref:`coroutine<coroutine>` to let the write buffer of the\n      underlying transport a chance to be flushed.\n\n      The intended use is to write::\n\n          resp.write(data)\n          yield from resp.drain()\n\n      Yielding from :meth:`drain` gives the opportunity for the loop\n      to schedule the write operation and flush the buffer. It should\n      especially be used when a possibly large amount of data is\n      written to the transport, and the coroutine does not yield-from\n      between calls to :meth:`write`.\n\n      .. versionadded:: 0.14\n\n   .. coroutinemethod:: write_eof()\n\n      A :ref:`coroutine<coroutine>` *may* be called as a mark of the\n      *HTTP response* processing finish.\n\n      *Internal machinery* will call this method at the end of\n      the request processing if needed.\n\n      After :meth:`write_eof` call any manipulations with the *response*\n      object are forbidden.\n\n\nResponse\n^^^^^^^^\n\n.. class:: Response(*, status=200, headers=None, content_type=None, \\\n                    body=None, text=None)\n\n   The most usable response class, inherited from :class:`StreamResponse`.\n\n   Accepts *body* argument for setting the *HTTP response BODY*.\n\n   The actual :attr:`body` sending happens in overridden\n   :meth:`~StreamResponse.write_eof`.\n\n   :param bytes body: response's BODY\n\n   :param int status: HTTP status code, 200 OK by default.\n\n   :param collections.abc.Mapping headers: HTTP headers that should be added to\n                           response's ones.\n\n   :param str text: response's BODY\n\n   :param str content_type: response's content type\n\n   .. attribute:: body\n\n      Read-write attribute for storing response's content aka BODY,\n      :class:`bytes`.\n\n      Setting :attr:`body` also recalculates\n      :attr:`~StreamResponse.content_length` value.\n\n      Resetting :attr:`body` (assigning ``None``) sets\n      :attr:`~StreamResponse.content_length` to ``None`` too, dropping\n      *Content-Length* HTTP header.\n\n   .. attribute:: text\n\n      Read-write attribute for storing response's content, represented as str,\n      :class:`str`.\n\n      Setting :attr:`str` also recalculates\n      :attr:`~StreamResponse.content_length` value and\n      :attr:`~StreamResponse.body` value\n\n      Resetting :attr:`body` (assigning ``None``) sets\n      :attr:`~StreamResponse.content_length` to ``None`` too, dropping\n      *Content-Length* HTTP header.\n\n\nWebSocketResponse\n^^^^^^^^^^^^^^^^^\n\n.. class:: WebSocketResponse(*, timeout=10.0, autoclose=True, \\\n                             autoping=True, protocols=())\n\n   Class for handling server-side websockets.\n\n   After starting (by :meth:`start` call) the response you\n   cannot use :meth:`~StreamResponse.write` method but should to\n   communicate with websocket client by :meth:`send_str`,\n   :meth:`receive` and others.\n\n   .. method:: start(request)\n\n      Starts websocket. After the call you can use websocket methods.\n\n      :param aiohttp.web.Request request: HTTP request object, that the\n                                          response answers.\n\n\n      :raises HTTPException: if websocket handshake has failed.\n\n   .. method:: can_start(request)\n\n      Performs checks for *request* data to figure out if websocket\n      can be started on the request.\n\n      If :meth:`can_start` call is success then :meth:`start` will success too.\n\n      :param aiohttp.web.Request request: HTTP request object, that the\n                                          response answers.\n\n      :return: ``(ok, protocol)`` pair, *ok* is ``True`` on success,\n               *protocol* is websocket subprotocol which is passed by\n               client and accepted by server (one of *protocols*\n               sequence from :class:`WebSocketResponse` ctor). *protocol* may be\n               ``None`` if client and server subprotocols are nit overlapping.\n\n      .. note:: The method newer raises exception.\n\n   .. attribute:: closed\n\n      Read-only property, ``True`` if connection has been closed or in process\n      of closing.\n      :const:`~aiohttp.websocket.MSG_CLOSE` message has been received from peer.\n\n   .. attribute:: close_code\n\n      Read-only property, close code from peer. It is set to ``None`` on\n      opened connection.\n\n   .. attribute:: protocol\n\n      Websocket *subprotocol* chosen after :meth:`start` call.\n\n      May be ``None`` if server and client protocols are\n      not overlapping.\n\n   .. method:: exception()\n\n      Returns last occured exception or None.\n\n   .. method:: ping(message=b'')\n\n      Send :const:`~aiohttp.websocket.MSG_PING` to peer.\n\n      :param message: optional payload of *ping* message,\n                      :class:`str` (converted to *UTF-8* encoded bytes)\n                      or :class:`bytes`.\n\n      :raise RuntimeError: if connections is not started or closing.\n\n   .. method:: pong(message=b'')\n\n      Send *unsolicited* :const:`~aiohttp.websocket.MSG_PONG` to peer.\n\n      :param message: optional payload of *pong* message,\n                      :class:`str` (converted to *UTF-8* encoded bytes)\n                      or :class:`bytes`.\n\n      :raise RuntimeError: if connections is not started or closing.\n\n   .. method:: send_str(data)\n\n      Send *data* to peer as :const:`~aiohttp.websocket.MSG_TEXT` message.\n\n      :param str data: data to send.\n\n      :raise RuntimeError: if connection is not started or closing\n\n      :raise TypeError: if data is not :class:`str`\n\n   .. method:: send_bytes(data)\n\n      Send *data* to peer as :const:`~aiohttp.websocket.MSG_BINARY` message.\n\n      :param data: data to send.\n\n      :raise RuntimeError: if connection is not started or closing\n\n      :raise TypeError: if data is not :class:`bytes`,\n                        :class:`bytearray` or :class:`memoryview`.\n\n   .. coroutinemethod:: close(*, code=1000, message=b'')\n\n      A :ref:`coroutine<coroutine>` that initiates closing\n      handshake by sending :const:`~aiohttp.websocket.MSG_CLOSE` message.\n\n      :param int code: closing code\n\n      :param message: optional payload of *pong* message,\n                      :class:`str` (converted to *UTF-8* encoded bytes)\n                      or :class:`bytes`.\n\n      :raise RuntimeError: if connection is not started or closing\n\n   .. coroutinemethod:: receive()\n\n      A :ref:`coroutine<coroutine>` that waits upcoming *data*\n      message from peer and returns it.\n\n      The coroutine implicitly handles\n      :const:`~aiohttp.websocket.MSG_PING`,\n      :const:`~aiohttp.websocket.MSG_PONG` and\n      :const:`~aiohttp.websocket.MSG_CLOSE` without returning the\n      message.\n\n      It process *ping-pong game* and performs *closing handshake* internally.\n\n      After websocket closing raises\n      :exc:`~aiohttp.errors.WSClientDisconnectedError` with\n      connection closing data.\n\n      :return: :class:`~aiohttp.websocket.Message`\n\n      :raise RuntimeError: if connection is not started\n\n      :raise: :exc:`~aiohttp.errors.WSClientDisconnectedError` on closing.\n\n   .. coroutinemethod:: receive_str()\n\n      A :ref:`coroutine<coroutine>` that calls :meth:`receive_mgs` but\n      also asserts the message type is\n      :const:`~aiohttp.websocket.MSG_TEXT`.\n\n      :return str: peer's message content.\n\n      :raise TypeError: if message is :const:`~aiohttp.websocket.MSG_BINARY`.\n\n   .. coroutinemethod:: receive_bytes()\n\n      A :ref:`coroutine<coroutine>` that calls :meth:`receive_mgs` but\n      also asserts the message type is\n      :const:`~aiohttp.websocket.MSG_BINARY`.\n\n      :return bytes: peer's message content.\n\n      :raise TypeError: if message is :const:`~aiohttp.websocket.MSG_TEXT`.\n\n\n.. versionadded:: 0.14\n\n.. seealso:: :ref:`WebSockets handling<aiohttp-web-websockets>`\n\n.. _aiohttp-web-app-and-router:\n\nApplication and Router\n----------------------\n\n\nApplication\n^^^^^^^^^^^\n\nApplication is a synonym for web-server.\n\nTo get fully working example, you have to make *application*, register\nsupported urls in *router* and create a *server socket* with\n:class:`aiohttp.RequestHandlerFactory` as a *protocol\nfactory*. *RequestHandlerFactory* could be constructed with\n:meth:`make_handler`.\n\n*Application* contains a *router* instance and a list of callbacks that\nwill be called during application finishing.\n\n*Application* is a :class:`dict`, so you can use it as registry for\narbitrary properties for later access from\n:ref:`handler<aiohttp-web-handler>` via :attr:`Request.app` property::\n\n   app = Application(loop=loop)\n   app['database'] = yield from aiopg.create_engine(**db_config)\n\n   @asyncio.coroutine\n   def handler(request):\n       with (yield from request.app['database']) as conn:\n           conn.execute(\"DELETE * FROM table\")\n\n\n.. class:: Application(*, loop=None, router=None, logger=<default>, \\\n                       middlewares=(), **kwargs)\n\n   The class inherits :class:`dict`.\n\n   :param loop: :ref:`event loop<asyncio-event-loop>` used\n                for processing HTTP requests.\n\n                If param is ``None`` :func:`asyncio.get_event_loop`\n                used for getting default event loop, but we strongly\n                recommend to use explicit loops everywhere.\n\n   :param router: :class:`aiohttp.abc.AbstractRouter` instance, the system\n                  creates :class:`UrlDispatcher` by default if\n                  *router* is ``None``.\n\n   :param logger: :class:`logging.Logger` instance for storing application logs.\n\n                  By default the value is ``logging.getLogger(\"aiohttp.web\")``\n\n   :param middlewares: :class:`list` of middleware factories, see\n                       :ref:`aiohttp-web-middlewares` for details.\n\n                       .. versionadded:: 0.13\n\n   .. attribute:: router\n\n      Read-only property that returns *router instance*.\n\n   .. attribute:: logger\n\n      :class:`logging.Logger` instance for storing application logs.\n\n   .. attribute:: loop\n\n      :ref:`event loop<asyncio-event-loop>` used for processing HTTP requests.\n\n   .. method:: make_handler(**kwargs)\n\n      Creates HTTP protocol factory for handling requests.\n\n      :param kwargs: additional parameters for :class:`RequestHandlerFactory`\n                     constructor.\n\n      You should pass result of the method as *protocol_factory* to\n      :meth:`~BaseEventLoop.create_server`, e.g.::\n\n         loop = asyncio.get_event_loop()\n\n         app = Application(loop=loop)\n\n         # setup route table\n         # app.router.add_route(...)\n\n         yield from loop.create_server(app.make_handler(),\n                                       '0.0.0.0', 8080)\n\n   .. coroutinemethod:: finish()\n\n      A :ref:`coroutine<coroutine>` that should be called after\n      server stopping.\n\n      This method executes functions registered by\n      :meth:`register_on_finish` in LIFO order.\n\n      If callback raises an exception, the error will be stored by\n      :meth:`~asyncio.BaseEventLoop.call_exception_handler` with keys:\n      *message*, *exception*, *application*.\n\n   .. method:: register_on_finish(self, func, *args, **kwargs):\n\n      Register *func* as a function to be executed at termination.\n      Any optional arguments that are to be passed to *func* must be\n      passed as arguments to :meth:`register_on_finish`.  It is possible to\n      register the same function and arguments more than once.\n\n      During the call of :meth:`finish` all functions registered are called in\n      last in, first out order.\n\n      *func* may be either regular function or :ref:`coroutine<coroutine>`,\n      :meth:`finish` will un-yield (`yield from`) the later.\n\n   .. note::\n\n      Application object has :attr:`route` attribute but has no\n      ``add_router`` method. The reason is: we want to support\n      different route implementations (even maybe not url-matching\n      based but traversal ones).\n\n      For sake of that fact we have very trivial ABC for\n      :class:`AbstractRouter`: it should have only\n      :meth:`AbstractRouter.resolve` coroutine.\n\n      No methods for adding routes or route reversing (getting URL by\n      route name). All those are router implementation details (but,\n      sure, you need to deal with that methods after choosing the\n      router for your application).\n\n\nRequestHandlerFactory\n^^^^^^^^^^^^^^^^^^^^^\n\nRequestHandlerFactory is responsible for creating HTTP protocol objects that\ncan handle http connections.\n\n   .. attribute:: connections\n\n      List of all currently oppened connections.\n\n   .. method:: finish_connections(timeout)\n\n      A :ref:`coroutine<coroutine>` that should be called to close all opened\n      connections.\n\n\nRouter\n^^^^^^\n\nFor dispatching URLs to :ref:`handlers<aiohttp-web-handler>`\n:mod:`aiohttp.web` uses *routers*.\n\nRouter is any object that implements :class:`AbstractRouter` interface.\n\n:mod:`aiohttp.web` provides an implementation called :class:`UrlDispatcher`.\n\n:class:`Application` uses :class:`UrlDispatcher` as :meth:`router` by default.\n\n.. class:: UrlDispatcher()\n\n   Straightforward url-matching router, implements\n   :class:`collections.abc.Mapping` for access to *named routes*.\n\n   Before running :class:`Application` you should fill *route\n   table* first by calling :meth:`add_route` and :meth:`add_static`.\n\n   :ref:`Handler<aiohttp-web-handler>` lookup is performed by iterating on\n   added *routes* in FIFO order. The first matching *route* will be used\n   to call corresponding *handler*.\n\n   If on route creation you specify *name* parameter the result is\n   *named route*.\n\n   *Named route* can be retrieved by ``app.router[name]`` call, checked for\n   existence by ``name in app.router`` etc.\n\n   .. seealso:: :ref:`Route classes <aiohttp-web-route>`\n\n   .. method:: add_route(method, path, handler, *, \\\n                         name=None, expect_handler=None)\n\n      Append :ref:`handler<aiohttp-web-handler>` to the end of route table.\n\n      *path* may be either *constant* string like ``'/a/b/c'`` or\n       *variable rule* like ``'/a/{var}'`` (see\n       :ref:`handling variable pathes<aiohttp-web-variable-handler>`)\n\n      Pay attention please: *handler* is converted to coroutine internally when\n      it is a regular function.\n\n      :param str method: HTTP method for route. Should be one of\n                         ``'GET'``, ``'POST'``, ``'PUT'``,\n                         ``'DELETE'``, ``'PATCH'``, ``'HEAD'``,\n                         ``'OPTIONS'`` or ``'*'`` for any method.\n\n                         The parameter is case-insensitive, e.g. you\n                         can push ``'get'`` as well as ``'GET'``.\n\n      :param str path: route path\n\n      :param callable handler: route handler\n\n      :param str name: optional route name.\n\n      :param coroutine expect_handler: optional *expect* header handler.\n\n      :returns: new :class:`PlainRoute` or :class:`DynamicRoute` instance.\n\n   .. method:: add_static(prefix, path, *, name=None, expect_handler=None, \\\n                          chunk_size=256*1024)\n\n      Adds router for returning static files.\n\n      Useful for handling static content like images, javascript and css files.\n\n      .. warning::\n\n         Use :meth:`add_static` for development only. In production,\n         static content should be processed by web servers like *nginx*\n         or *apache*.\n\n      :param str prefix: URL path prefix for handled static files\n\n      :param str path: path to the folder in file system that contains\n                       handled static files.\n\n      :param str name: optional route name.\n\n      :param coroutine expect_handler: optional *expect* header handler.\n\n      :param int chunk_size: size of single chunk for file\n                             downloading, 64Kb by default.\n\n                             Increasing *chunk_size* parameter to,\n                             say, 1Mb may increase file downloading\n                             speed but consumes more memory.\n\n                             .. versionadded:: 0.16\n\n   :returns: new :class:`StaticRoute` instance.\n\n   .. coroutinemethod:: resolve(requst)\n\n      A :ref:`coroutine<coroutine>` that returns\n      :class:`AbstractMatchInfo` for *request*.\n\n      The method never raises exception, but returns\n      :class:`AbstractMatchInfo` instance with:\n\n      1. :attr:`~AbstractMatchInfo.route` asigned to\n         :class:`SystemRoute` instance\n      2. :attr:`~AbstractMatchInfo.handler` which raises\n         :exc:`HTTPNotFound` or :exc:`HTTPMethodNotAllowed` on handler's\n         execution if there is no registered route for *request*.\n\n         *Middlewares* can process that exceptions to render\n         pretty-looking error page for example.\n\n      Used by internal machinery, end user unlikely need to call the method.\n\n      .. note:: The method uses :attr:`Request.raw_path` for pattern\n         matching against registered routes.\n\n      .. versionchanged:: 0.14\n\n         The method don't raise :exc:`HTTPNotFound` and\n         :exc:`HTTPMethodNotAllowed` anymore.\n\n\n.. _aiohttp-web-route:\n\nRoute\n^^^^^\n\nDefault router :class:`UrlDispatcher` operates with *routes*.\n\nUser should not instantiate route classes by hand but can give *named\nroute instance* by ``router[name]`` if he have added route by\n:meth:`UrlDispatcher.add_route` or :meth:`UrlDispatcher.add_static`\ncalls with non-empty *name* parameter.\n\nThe main usage of *named routes* is constructing URL by route name for\npassing it into *template engine* for example::\n\n   url = app.router['route_name'].url(query={'a': 1, 'b': 2})\n\nThere are three concrete route classes:* :class:`DynamicRoute` for\nurls with :ref:`variable pathes<aiohttp-web-variable-handler>` spec.\n\n\n* :class:`PlainRoute` for urls without :ref:`variable\n  pathes<aiohttp-web-variable-handler>`\n\n* :class:`DynamicRoute` for urls with :ref:`variable\n  pathes<aiohttp-web-variable-handler>` spec.\n\n* :class:`StaticRoute` for static file handlers.\n\n.. class:: Route\n\n   Base class for routes served by :class:`UrlDispatcher`.\n\n   .. attribute:: method\n\n   HTTP method handled by the route, e.g. *GET*, *POST* etc.\n\n   .. attribute:: handler\n\n   :ref:`handler<aiohttp-web-handler>` that processes the route.\n\n   .. attribute:: name\n\n   Name of the route.\n\n   .. method:: match(path)\n\n   Abstract method, accepts *URL path* and returns :class:`dict` with\n   parsed *path parts* for :class:`UrlMappingMatchInfo` or ``None`` if\n   the route cannot handle given *path*.\n\n   The method exists for internal usage, end user unlikely need to call it.\n\n   .. method:: url(*, query=None, **kwargs)\n\n   Abstract method for constructing url handled by the route.\n\n   *query* is a mapping or list of *(name, value)* pairs for\n   specifying *query* part of url (parameter is processed by\n   :func:`~urllib.parse.urlencode`).\n\n   Other available parameters depends on concrete route class and\n   described in descendant classes.\n\n.. class:: PlainRoute\n\n   The route class for handling plain *URL path*, e.g. ``\"/a/b/c\"``\n\n   .. method:: url(*, parts, query=None)\n\n   Construct url, doesn't accepts extra parameters::\n\n      >>> route.url(query={'d': 1, 'e': 2})\n      '/a/b/c/?d=1&e=2'``\n\n.. class:: DynamicRoute\n\n   The route class for handling :ref:`variable\n   path<aiohttp-web-variable-handler>`, e.g. ``\"/a/{name1}/{name2}\"``\n\n   .. method:: url(*, parts, query=None)\n\n   Construct url with given *dynamic parts*::\n\n       >>> route.url(parts={'name1': 'b', 'name2': 'c'},\n                     query={'d': 1, 'e': 2})\n       '/a/b/c/?d=1&e=2'\n\n\n.. class:: StaticRoute\n\n   The route class for handling static files, created by\n   :meth:`UrlDispatcher.add_static` call.\n\n   .. method:: url(*, filename, query=None)\n\n   Construct url for given *filename*::\n\n      >>> route.url(filename='img/logo.png', query={'param': 1})\n      '/path/to/static/img/logo.png?param=1'\n\n\n.. class:: SystemRoute\n\n   The route class for internal purposes.\n\n   Now it has used for handling *404: Not Found* and *405: Method Not Allowed*.\n\n   .. method:: url()\n\n   Always raises :exc:`RuntimeError`, :class:`SystemRoute` should not\n   be used in url construction expressions.\n\n\nMatchInfo\n^^^^^^^^^\n\nAfter route matching web application calls found handler if any.\n\nMatching result can be accessible from handler as\n:attr:`Request.match_info` attribute.\n\nIn general the result may be any object derived from\n:class:`AbstractMatchInfo` (:class:`UrlMappingMatchInfo` for default\n:class:`UrlDispatcher` router).\n\n.. class:: UrlMappingMatchInfo\n\n   Inherited from :class:`dict` and :class:`AbstractMatchInfo`. Dict\n   items are given from :meth:`Route.match` call return value.\n\n   .. attribute:: route\n\n   :class:`Route` instance for url matching.\n\n\n\nUtilities\n---------\n\n.. class:: FileField\n\n   A :func:`~collections.namedtuple` that is returned as multidict value\n   by :meth:`Request.POST` if field is uploaded file.\n\n   .. attribute:: name\n\n      Field name\n\n   .. attribute:: filename\n\n      File name as specified by uploading (client) side.\n\n   .. attribute:: file\n\n      An :class:`io.IOBase` instance with content of uploaded file.\n\n   .. attribute:: content_type\n\n      *MIME type* of uploaded file, ``'text/plain'`` by default.\n\n   .. seealso:: :ref:`aiohttp-web-file-upload`\n\n\nConstants\n---------\n\n.. class:: ContentCoding\n\n   An :class:`enum.Enum` class of available Content Codings.\n\n   .. attribute:: deflate\n\n   .. attribute:: gzip\n\n   .. attribute:: identity\n",
            "new_file_content": ".. _aiohttp-web-reference:\n\nHTTP Server Reference\n=====================\n\n.. highlight:: python\n\n.. module:: aiohttp.web\n\n.. versionchanged:: 0.12\n\n   The module was deeply refactored in backward incompatible manner.\n\n.. _aiohttp-web-request:\n\n\nRequest\n-------\n\nThe Request object contains all the information about an incoming HTTP request.\n\nEvery :ref:`handler<aiohttp-web-handler>` accepts a request instance as the\nfirst positional parameter.\n\n.. note::\n\n   You should never create the :class:`Request` instance manually --\n   :mod:`aiohttp.web` does it for you.\n\n.. class:: Request\n\n   .. attribute:: scheme\n\n      A string representing the scheme of the request.\n\n      The scheme is ``'https'`` if transport for request handling is\n      *SSL* or ``secure_proxy_ssl_header`` is matching.\n\n      ``'http'`` otherwise.\n\n      Read-only :class:`str` property.\n\n   .. attribute:: method\n\n      *HTTP method*, read-only property.\n\n      The value is upper-cased :class:`str` like ``\"GET\"``,\n      ``\"POST\"``, ``\"PUT\"`` etc.\n\n   .. attribute:: version\n\n      *HTTP version* of request, Read-only property.\n\n      Returns :class:`aiohttp.protocol.HttpVersion` instance.\n\n   .. attribute:: host\n\n      *HOST* header of request, Read-only property.\n\n      Returns :class:`str` or ``None`` if HTTP request has no *HOST* header.\n\n   .. attribute:: path_qs\n\n      The URL including PATH_INFO and the query string. e.g, ``/app/blog?id=10``\n\n      Read-only :class:`str` property.\n\n   .. attribute:: path\n\n      The URL including *PATH INFO* without the host or scheme. e.g.,\n      ``/app/blog``. The path is URL-unquoted. For raw path info see\n      :attr:`raw_path`.\n\n      Read-only :class:`str` property.\n\n   .. attribute:: raw_path\n\n      The URL including raw *PATH INFO* without the host or scheme.\n      Warning, the path may be quoted and may contains non valid URL\n      characters, e.g.\n      ``/my%2Fpath%7Cwith%21some%25strange%24characters``.\n\n      For unquoted version please take a look on :attr:`path`.\n\n      Read-only :class:`str` property.\n\n   .. attribute:: query_string\n\n      The query string in the URL, e.g., ``id=10``\n\n      Read-only :class:`str` property.\n\n   .. attribute:: GET\n\n      A multidict with all the variables in the query string.\n\n      Read-only :class:`~aiohttp.multidict.MultiDictProxy` lazy property.\n\n   .. attribute:: POST\n\n      A multidict with all the variables in the POST parameters.\n      POST property available only after :meth:`Request.post` coroutine call.\n\n      Read-only :class:`~aiohttp.multidict.MultiDictProxy`.\n\n      :raises RuntimeError: if :meth:`Request.post` was not called \\\n                            before accessing the property.\n\n   .. attribute:: headers\n\n      A case-insensitive multidict proxy with all headers.\n\n      Read-only :class:`~aiohttp.multidict.CIMultiDictProxy` property.\n\n   .. attribute:: keep_alive\n\n      ``True`` if keep-alive connection enabled by HTTP client and\n      protocol version supports it, otherwise ``False``.\n\n      Read-only :class:`bool` property.\n\n   .. attribute:: match_info\n\n      Read-only property with :class:`~aiohttp.abc.AbstractMatchInfo`\n      instance for result of route resolving.\n\n      .. note::\n\n         Exact type of property depends on used router.  If\n         ``app.router`` is :class:`UrlDispatcher` the property contains\n         :class:`UrlMappingMatchInfo` instance.\n\n   .. attribute:: app\n\n      An :class:`Application` instance used to call :ref:`request handler\n      <aiohttp-web-handler>`, Read-only property.\n\n   .. attribute:: transport\n\n      An :ref:`transport<asyncio-transport>` used to process request,\n      Read-only property.\n\n      The property can be used, for example, for getting IP address of\n      client's peer::\n\n         peername = request.transport.get_extra_info('peername')\n         if peername is not None:\n             host, port = peername\n\n   .. attribute:: cookies\n\n      A multidict of all request's cookies.\n\n      Read-only :class:`~aiohttp.multidict.MultiDictProxy` lazy property.\n\n   .. attribute:: content\n\n      A :class:`~aiohttp.streams.FlowControlStreamReader` instance,\n      input stream for reading request's *BODY*.\n\n      Read-only property.\n\n      .. versionadded:: 0.15\n\n   .. attribute:: has_body\n\n      Return ``True`` if request has *HTTP BODY*, ``False`` otherwise.\n\n      Read-only :class:`bool` property.\n\n      .. versionadded:: 0.16\n\n   .. attribute:: payload\n\n      A :class:`~aiohttp.streams.FlowControlStreamReader` instance,\n      input stream for reading request's *BODY*.\n\n      Read-only property.\n\n      .. deprecated:: 0.15\n\n         Use :attr:`~Request.content` instead.\n\n   .. attribute:: content_type\n\n      Read-only property with *content* part of *Content-Type* header.\n\n      Returns :class:`str` like ``'text/html'``\n\n      .. note::\n\n         Returns value is ``'application/octet-stream'`` if no\n         Content-Type header present in HTTP headers according to\n         :rfc:`2616`\n\n   .. attribute:: charset\n\n      Read-only property that specifies the *encoding* for the request's BODY.\n\n      The value is parsed from the *Content-Type* HTTP header.\n\n      Returns :class:`str` like ``'utf-8'`` or ``None`` if\n      *Content-Type* has no charset information.\n\n   .. attribute:: content_length\n\n      Read-only property that returns length of the request's BODY.\n\n      The value is parsed from the *Content-Length* HTTP header.\n\n      Returns :class:`int` or ``None`` if *Content-Length* is absent.\n\n   .. attribute:: if_modified_since\n\n      Read-only property that returns the date specified in the\n      *If-Modified-Since* header.\n\n      Returns :class:`datetime.datetime` or ``None`` if\n      *If-Modified-Since* header is absent or is not a valid\n      HTTP date.\n\n   .. coroutinemethod:: read()\n\n      Read request body, returns :class:`bytes` object with body content.\n\n      .. note::\n\n         The method **does** store read data internally, subsequent\n         :meth:`~Request.read` call will return the same value.\n\n   .. coroutinemethod:: text()\n\n      Read request body, decode it using :attr:`charset` encoding or\n      ``UTF-8`` if no encoding was specified in *MIME-type*.\n\n      Returns :class:`str` with body content.\n\n      .. note::\n\n         The method **does** store read data internally, subsequent\n         :meth:`~Request.text` call will return the same value.\n\n   .. coroutinemethod:: json(*, loader=json.loads)\n\n      Read request body decoded as *json*.\n\n      The method is just a boilerplate :ref:`coroutine <coroutine>`\n      implemented as::\n\n         @asyncio.coroutine\n         def json(self, *, loader=json.loads):\n             body = yield from self.text()\n             return loader(body)\n\n      :param callable loader: any :term:`callable` that accepts\n                              :class:`str` and returns :class:`dict`\n                              with parsed JSON (:func:`json.loads` by\n                              default).\n\n      .. note::\n\n         The method **does** store read data internally, subsequent\n         :meth:`~Request.json` call will return the same value.\n\n   .. coroutinemethod:: post()\n\n      A :ref:`coroutine <coroutine>` that reads POST parameters from\n      request body.\n\n      Returns :class:`~aiohttp.multidict.MultiDictProxy` instance filled\n      with parsed data.\n\n      If :attr:`method` is not *POST*, *PUT* or *PATCH* or\n      :attr:`content_type` is not empty or\n      *application/x-www-form-urlencoded* or *multipart/form-data*\n      returns empty multidict.\n\n      .. note::\n\n         The method **does** store read data internally, subsequent\n         :meth:`~Request.post` call will return the same value.\n\n   .. coroutinemethod:: release()\n\n      Release request.\n\n      Eat unread part of HTTP BODY if present.\n\n      .. note::\n\n          User code may never call :meth:`~Request.release`, all\n          required work will be processed by :mod:`aiohttp.web`\n          internal machinery.\n\n\n.. _aiohttp-web-response:\n\n\nResponse classes\n----------------\n\nFor now, :mod:`aiohttp.web` has two classes for the *HTTP response*:\n:class:`StreamResponse` and :class:`Response`.\n\nUsually you need to use the second one. :class:`StreamResponse` is\nintended for streaming data, while :class:`Response` contains *HTTP\nBODY* as an attribute and sends own content as single piece with the\ncorrect *Content-Length HTTP header*.\n\nFor sake of design decisions :class:`Response` is derived from\n:class:`StreamResponse` parent class.\n\nThe response supports *keep-alive* handling out-of-the-box if\n*request* supports it.\n\nYou can disable *keep-alive* by :meth:`~StreamResponse.force_close` though.\n\nThe common case for sending an answer from\n:ref:`web-handler<aiohttp-web-handler>` is returning a\n:class:`Response` instance::\n\n   def handler(request):\n       return Response(\"All right!\")\n\n\nStreamResponse\n^^^^^^^^^^^^^^\n\n.. class:: StreamResponse(*, status=200, reason=None)\n\n   The base class for the *HTTP response* handling.\n\n   Contains methods for setting *HTTP response headers*, *cookies*,\n   *response status code*, writing *HTTP response BODY* and so on.\n\n   The most important thing you should know about *response* --- it\n   is *Finite State Machine*.\n\n   That means you can do any manipulations with *headers*,\n   *cookies* and *status code* only before :meth:`start`\n   called.\n\n   Once you call :meth:`start` any change of\n   the *HTTP header* part will raise :exc:`RuntimeError` exception.\n\n   Any :meth:`write` call after :meth:`write_eof` is also forbidden.\n\n   :param int status: HTTP status code, ``200`` by default.\n\n   :param str reason: HTTP reason. If param is ``None`` reason will be\n                      calculated basing on *status*\n                      parameter. Otherwise pass :class:`str` with\n                      arbitrary *status* explanation..\n\n   .. attribute:: started\n\n      Read-only :class:`bool` property, ``True`` if :meth:`start` has\n      been called, ``False`` otherwise.\n\n   .. attribute:: status\n\n      Read-only property for *HTTP response status code*, :class:`int`.\n\n      ``200`` (OK) by default.\n\n   .. attribute:: reason\n\n      Read-only property for *HTTP response reason*, :class:`str`.\n\n   .. method:: set_status(status, reason=None)\n\n      Set :attr:`status` and :attr:`reason`.\n\n      *reason* value is auto calculated if not specified (``None``).\n\n   .. attribute:: keep_alive\n\n      Read-only property, copy of :attr:`Request.keep_alive` by default.\n\n      Can be switched to ``False`` by :meth:`force_close` call.\n\n   .. method:: force_close\n\n      Disable :attr:`keep_alive` for connection. There are no ways to\n      enable it back.\n\n   .. attribute:: compression\n\n      Read-only :class:`bool` property, ``True`` if compression is enabled.\n\n      ``False`` by default.\n\n      .. versionadded:: 0.14\n\n      .. seealso:: :meth:`enable_compression`\n\n   .. method:: enable_compression(force=None)\n\n      Enable compression.\n\n      When *force* is unset compression encoding is selected based on\n      the request's *Accept-Encoding* header.\n\n      *Accept-Encoding* is not checked if *force* is set to a\n      :class:`ContentCoding`.\n\n      .. versionadded:: 0.14\n\n      .. seealso:: :attr:`compression`\n\n   .. attribute:: chunked\n\n      Read-only property, indicates if chunked encoding is on.\n\n      Can be enabled by :meth:`enable_chunked_encoding` call.\n\n      .. versionadded:: 0.14\n\n      .. seealso:: :attr:`enable_chunked_encoding`\n\n   .. method:: enable_chunked_encoding\n\n      Enables :attr:`chunked` encoding for response. There are no ways to\n      disable it back. With enabled :attr:`chunked` encoding each `write()`\n      operation encoded in separate chunk.\n\n      .. versionadded:: 0.14\n\n      .. seealso:: :attr:`chunked`\n\n   .. attribute:: headers\n\n      :class:`~aiohttp.multidict.CIMultiDict` instance\n      for *outgoing* *HTTP headers*.\n\n   .. attribute:: cookies\n\n      An instance of :class:`http.cookies.SimpleCookie` for *outgoing* cookies.\n\n      .. warning::\n\n         Direct setting up *Set-Cookie* header may be overwritten by\n         explicit calls to cookie manipulation.\n\n         We are encourage using of :attr:`cookies` and\n         :meth:`set_cookie`, :meth:`del_cookie` for cookie\n         manipulations.\n\n   .. method:: set_cookie(name, value, *, path='/', expires=None, \\\n                   domain=None, max_age=None, \\\n                   secure=None, httponly=None, version=None)\n\n      Convenient way for setting :attr:`cookies`, allows to specify\n      some additional properties like *max_age* in a single call.\n\n      :param str name: cookie name\n\n      :param str value: cookie value (will be converted to\n                        :class:`str` if value has another type).\n\n      :param expires: expiration date (optional)\n\n      :param str domain: cookie domain (optional)\n\n      :param int max_age: defines the lifetime of the cookie, in\n                          seconds.  The delta-seconds value is a\n                          decimal non- negative integer.  After\n                          delta-seconds seconds elapse, the client\n                          should discard the cookie.  A value of zero\n                          means the cookie should be discarded\n                          immediately.  (optional)\n\n      :param str path: specifies the subset of URLs to\n                       which this cookie applies. (optional, ``'/'`` by default)\n\n      :param bool secure: attribute (with no value) directs\n                          the user agent to use only (unspecified)\n                          secure means to contact the origin server\n                          whenever it sends back this cookie.\n                          The user agent (possibly under the user's\n                          control) may determine what level of\n                          security it considers appropriate for\n                          \"secure\" cookies.  The *secure* should be\n                          considered security advice from the server\n                          to the user agent, indicating that it is in\n                          the session's interest to protect the cookie\n                          contents. (optional)\n\n      :param bool httponly: ``True`` if the cookie HTTP only (optional)\n\n      :param int version: a decimal integer, identifies to which\n                          version of the state management\n                          specification the cookie\n                          conforms. (Optional, *version=1* by default)\n\n      .. versionchanged:: 0.14.3\n\n         Default value for *path* changed from ``None`` to ``'/'``.\n\n   .. method:: del_cookie(name, *, path='/', domain=None)\n\n      Deletes cookie.\n\n      :param str name: cookie name\n\n      :param str domain: optional cookie domain\n\n      :param str path: optional cookie path, ``'/'`` by default\n\n      .. versionchanged:: 0.14.3\n\n         Default value for *path* changed from ``None`` to ``'/'``.\n\n   .. attribute:: content_length\n\n      *Content-Length* for outgoing response.\n\n   .. attribute:: content_type\n\n      *Content* part of *Content-Type* for outgoing response.\n\n   .. attribute:: charset\n\n      *Charset* aka *encoding* part of *Content-Type* for outgoing response.\n\n      The value converted to lower-case on attribute assigning.\n\n   .. attribute:: last_modified\n\n      *Last-Modified* header for outgoing response.\n\n      This property accepts raw :class:`str` values,\n      :class:`datetime.datetime` objects, Unix timestamps specified\n      as an :class:`int` or a :class:`float` object, and the\n      value ``None`` to unset the header.\n\n   .. method:: start(request)\n\n      :param aiohttp.web.Request request: HTTP request object, that the\n                                          response answers.\n\n      Send *HTTP header*. You should not change any header data after\n      calling this method.\n\n   .. method:: write(data)\n\n      Send byte-ish data as the part of *response BODY*.\n\n      :meth:`start` must be called before.\n\n      Raises :exc:`TypeError` if data is not :class:`bytes`,\n      :class:`bytearray` or :class:`memoryview` instance.\n\n      Raises :exc:`RuntimeError` if :meth:`start` has not been called.\n\n      Raises :exc:`RuntimeError` if :meth:`write_eof` has been called.\n\n   .. coroutinemethod:: drain()\n\n      A :ref:`coroutine<coroutine>` to let the write buffer of the\n      underlying transport a chance to be flushed.\n\n      The intended use is to write::\n\n          resp.write(data)\n          yield from resp.drain()\n\n      Yielding from :meth:`drain` gives the opportunity for the loop\n      to schedule the write operation and flush the buffer. It should\n      especially be used when a possibly large amount of data is\n      written to the transport, and the coroutine does not yield-from\n      between calls to :meth:`write`.\n\n      .. versionadded:: 0.14\n\n   .. coroutinemethod:: write_eof()\n\n      A :ref:`coroutine<coroutine>` *may* be called as a mark of the\n      *HTTP response* processing finish.\n\n      *Internal machinery* will call this method at the end of\n      the request processing if needed.\n\n      After :meth:`write_eof` call any manipulations with the *response*\n      object are forbidden.\n\n\nResponse\n^^^^^^^^\n\n.. class:: Response(*, status=200, headers=None, content_type=None, \\\n                    body=None, text=None)\n\n   The most usable response class, inherited from :class:`StreamResponse`.\n\n   Accepts *body* argument for setting the *HTTP response BODY*.\n\n   The actual :attr:`body` sending happens in overridden\n   :meth:`~StreamResponse.write_eof`.\n\n   :param bytes body: response's BODY\n\n   :param int status: HTTP status code, 200 OK by default.\n\n   :param collections.abc.Mapping headers: HTTP headers that should be added to\n                           response's ones.\n\n   :param str text: response's BODY\n\n   :param str content_type: response's content type\n\n   .. attribute:: body\n\n      Read-write attribute for storing response's content aka BODY,\n      :class:`bytes`.\n\n      Setting :attr:`body` also recalculates\n      :attr:`~StreamResponse.content_length` value.\n\n      Resetting :attr:`body` (assigning ``None``) sets\n      :attr:`~StreamResponse.content_length` to ``None`` too, dropping\n      *Content-Length* HTTP header.\n\n   .. attribute:: text\n\n      Read-write attribute for storing response's content, represented as str,\n      :class:`str`.\n\n      Setting :attr:`str` also recalculates\n      :attr:`~StreamResponse.content_length` value and\n      :attr:`~StreamResponse.body` value\n\n      Resetting :attr:`body` (assigning ``None``) sets\n      :attr:`~StreamResponse.content_length` to ``None`` too, dropping\n      *Content-Length* HTTP header.\n\n\nWebSocketResponse\n^^^^^^^^^^^^^^^^^\n\n.. class:: WebSocketResponse(*, timeout=10.0, autoclose=True, \\\n                             autoping=True, protocols=())\n\n   Class for handling server-side websockets.\n\n   After starting (by :meth:`start` call) the response you\n   cannot use :meth:`~StreamResponse.write` method but should to\n   communicate with websocket client by :meth:`send_str`,\n   :meth:`receive` and others.\n\n   .. method:: start(request)\n\n      Starts websocket. After the call you can use websocket methods.\n\n      :param aiohttp.web.Request request: HTTP request object, that the\n                                          response answers.\n\n\n      :raises HTTPException: if websocket handshake has failed.\n\n   .. method:: can_start(request)\n\n      Performs checks for *request* data to figure out if websocket\n      can be started on the request.\n\n      If :meth:`can_start` call is success then :meth:`start` will success too.\n\n      :param aiohttp.web.Request request: HTTP request object, that the\n                                          response answers.\n\n      :return: ``(ok, protocol)`` pair, *ok* is ``True`` on success,\n               *protocol* is websocket subprotocol which is passed by\n               client and accepted by server (one of *protocols*\n               sequence from :class:`WebSocketResponse` ctor). *protocol* may be\n               ``None`` if client and server subprotocols are nit overlapping.\n\n      .. note:: The method newer raises exception.\n\n   .. attribute:: closed\n\n      Read-only property, ``True`` if connection has been closed or in process\n      of closing.\n      :const:`~aiohttp.websocket.MSG_CLOSE` message has been received from peer.\n\n   .. attribute:: close_code\n\n      Read-only property, close code from peer. It is set to ``None`` on\n      opened connection.\n\n   .. attribute:: protocol\n\n      Websocket *subprotocol* chosen after :meth:`start` call.\n\n      May be ``None`` if server and client protocols are\n      not overlapping.\n\n   .. method:: exception()\n\n      Returns last occured exception or None.\n\n   .. method:: ping(message=b'')\n\n      Send :const:`~aiohttp.websocket.MSG_PING` to peer.\n\n      :param message: optional payload of *ping* message,\n                      :class:`str` (converted to *UTF-8* encoded bytes)\n                      or :class:`bytes`.\n\n      :raise RuntimeError: if connections is not started or closing.\n\n   .. method:: pong(message=b'')\n\n      Send *unsolicited* :const:`~aiohttp.websocket.MSG_PONG` to peer.\n\n      :param message: optional payload of *pong* message,\n                      :class:`str` (converted to *UTF-8* encoded bytes)\n                      or :class:`bytes`.\n\n      :raise RuntimeError: if connections is not started or closing.\n\n   .. method:: send_str(data)\n\n      Send *data* to peer as :const:`~aiohttp.websocket.MSG_TEXT` message.\n\n      :param str data: data to send.\n\n      :raise RuntimeError: if connection is not started or closing\n\n      :raise TypeError: if data is not :class:`str`\n\n   .. method:: send_bytes(data)\n\n      Send *data* to peer as :const:`~aiohttp.websocket.MSG_BINARY` message.\n\n      :param data: data to send.\n\n      :raise RuntimeError: if connection is not started or closing\n\n      :raise TypeError: if data is not :class:`bytes`,\n                        :class:`bytearray` or :class:`memoryview`.\n\n   .. coroutinemethod:: close(*, code=1000, message=b'')\n\n      A :ref:`coroutine<coroutine>` that initiates closing\n      handshake by sending :const:`~aiohttp.websocket.MSG_CLOSE` message.\n\n      :param int code: closing code\n\n      :param message: optional payload of *pong* message,\n                      :class:`str` (converted to *UTF-8* encoded bytes)\n                      or :class:`bytes`.\n\n      :raise RuntimeError: if connection is not started or closing\n\n   .. coroutinemethod:: receive()\n\n      A :ref:`coroutine<coroutine>` that waits upcoming *data*\n      message from peer and returns it.\n\n      The coroutine implicitly handles\n      :const:`~aiohttp.websocket.MSG_PING`,\n      :const:`~aiohttp.websocket.MSG_PONG` and\n      :const:`~aiohttp.websocket.MSG_CLOSE` without returning the\n      message.\n\n      It process *ping-pong game* and performs *closing handshake* internally.\n\n      After websocket closing raises\n      :exc:`~aiohttp.errors.WSClientDisconnectedError` with\n      connection closing data.\n\n      :return: :class:`~aiohttp.websocket.Message`\n\n      :raise RuntimeError: if connection is not started\n\n      :raise: :exc:`~aiohttp.errors.WSClientDisconnectedError` on closing.\n\n   .. coroutinemethod:: receive_str()\n\n      A :ref:`coroutine<coroutine>` that calls :meth:`receive_mgs` but\n      also asserts the message type is\n      :const:`~aiohttp.websocket.MSG_TEXT`.\n\n      :return str: peer's message content.\n\n      :raise TypeError: if message is :const:`~aiohttp.websocket.MSG_BINARY`.\n\n   .. coroutinemethod:: receive_bytes()\n\n      A :ref:`coroutine<coroutine>` that calls :meth:`receive_mgs` but\n      also asserts the message type is\n      :const:`~aiohttp.websocket.MSG_BINARY`.\n\n      :return bytes: peer's message content.\n\n      :raise TypeError: if message is :const:`~aiohttp.websocket.MSG_TEXT`.\n\n\n.. versionadded:: 0.14\n\n.. seealso:: :ref:`WebSockets handling<aiohttp-web-websockets>`\n\n.. _aiohttp-web-app-and-router:\n\nApplication and Router\n----------------------\n\n\nApplication\n^^^^^^^^^^^\n\nApplication is a synonym for web-server.\n\nTo get fully working example, you have to make *application*, register\nsupported urls in *router* and create a *server socket* with\n:class:`aiohttp.RequestHandlerFactory` as a *protocol\nfactory*. *RequestHandlerFactory* could be constructed with\n:meth:`make_handler`.\n\n*Application* contains a *router* instance and a list of callbacks that\nwill be called during application finishing.\n\n*Application* is a :class:`dict`, so you can use it as registry for\narbitrary properties for later access from\n:ref:`handler<aiohttp-web-handler>` via :attr:`Request.app` property::\n\n   app = Application(loop=loop)\n   app['database'] = yield from aiopg.create_engine(**db_config)\n\n   @asyncio.coroutine\n   def handler(request):\n       with (yield from request.app['database']) as conn:\n           conn.execute(\"DELETE * FROM table\")\n\n\n.. class:: Application(*, loop=None, router=None, logger=<default>, \\\n                       middlewares=(), **kwargs)\n\n   The class inherits :class:`dict`.\n\n   :param loop: :ref:`event loop<asyncio-event-loop>` used\n                for processing HTTP requests.\n\n                If param is ``None`` :func:`asyncio.get_event_loop`\n                used for getting default event loop, but we strongly\n                recommend to use explicit loops everywhere.\n\n   :param router: :class:`aiohttp.abc.AbstractRouter` instance, the system\n                  creates :class:`UrlDispatcher` by default if\n                  *router* is ``None``.\n\n   :param logger: :class:`logging.Logger` instance for storing application logs.\n\n                  By default the value is ``logging.getLogger(\"aiohttp.web\")``\n\n   :param middlewares: :class:`list` of middleware factories, see\n                       :ref:`aiohttp-web-middlewares` for details.\n\n                       .. versionadded:: 0.13\n\n   .. attribute:: router\n\n      Read-only property that returns *router instance*.\n\n   .. attribute:: logger\n\n      :class:`logging.Logger` instance for storing application logs.\n\n   .. attribute:: loop\n\n      :ref:`event loop<asyncio-event-loop>` used for processing HTTP requests.\n\n   .. method:: make_handler(**kwargs)\n\n      Creates HTTP protocol factory for handling requests.\n\n      :param kwargs: additional parameters for :class:`RequestHandlerFactory`\n                     constructor.\n\n      You should pass result of the method as *protocol_factory* to\n      :meth:`~BaseEventLoop.create_server`, e.g.::\n\n         loop = asyncio.get_event_loop()\n\n         app = Application(loop=loop)\n\n         # setup route table\n         # app.router.add_route(...)\n\n         yield from loop.create_server(app.make_handler(),\n                                       '0.0.0.0', 8080)\n\n   .. coroutinemethod:: finish()\n\n      A :ref:`coroutine<coroutine>` that should be called after\n      server stopping.\n\n      This method executes functions registered by\n      :meth:`register_on_finish` in LIFO order.\n\n      If callback raises an exception, the error will be stored by\n      :meth:`~asyncio.BaseEventLoop.call_exception_handler` with keys:\n      *message*, *exception*, *application*.\n\n   .. method:: register_on_finish(self, func, *args, **kwargs):\n\n      Register *func* as a function to be executed at termination.\n      Any optional arguments that are to be passed to *func* must be\n      passed as arguments to :meth:`register_on_finish`.  It is possible to\n      register the same function and arguments more than once.\n\n      During the call of :meth:`finish` all functions registered are called in\n      last in, first out order.\n\n      *func* may be either regular function or :ref:`coroutine<coroutine>`,\n      :meth:`finish` will un-yield (`yield from`) the later.\n\n   .. note::\n\n      Application object has :attr:`route` attribute but has no\n      ``add_route()`` method. The reason is: we want to support\n      different route implementations (even maybe not url-matching\n      based but traversal ones).\n\n      For sake of that fact we have very trivial ABC for\n      :class:`AbstractRouter`: it should have only\n      :meth:`AbstractRouter.resolve` coroutine.\n\n      No methods for adding routes or route reversing (getting URL by\n      route name). All those are router implementation details (but,\n      sure, you need to deal with that methods after choosing the\n      router for your application).\n\n\nRequestHandlerFactory\n^^^^^^^^^^^^^^^^^^^^^\n\nRequestHandlerFactory is responsible for creating HTTP protocol objects that\ncan handle http connections.\n\n   .. attribute:: connections\n\n      List of all currently oppened connections.\n\n   .. method:: finish_connections(timeout)\n\n      A :ref:`coroutine<coroutine>` that should be called to close all opened\n      connections.\n\n\nRouter\n^^^^^^\n\nFor dispatching URLs to :ref:`handlers<aiohttp-web-handler>`\n:mod:`aiohttp.web` uses *routers*.\n\nRouter is any object that implements :class:`AbstractRouter` interface.\n\n:mod:`aiohttp.web` provides an implementation called :class:`UrlDispatcher`.\n\n:class:`Application` uses :class:`UrlDispatcher` as :meth:`router` by default.\n\n.. class:: UrlDispatcher()\n\n   Straightforward url-matching router, implements\n   :class:`collections.abc.Mapping` for access to *named routes*.\n\n   Before running :class:`Application` you should fill *route\n   table* first by calling :meth:`add_route` and :meth:`add_static`.\n\n   :ref:`Handler<aiohttp-web-handler>` lookup is performed by iterating on\n   added *routes* in FIFO order. The first matching *route* will be used\n   to call corresponding *handler*.\n\n   If on route creation you specify *name* parameter the result is\n   *named route*.\n\n   *Named route* can be retrieved by ``app.router[name]`` call, checked for\n   existence by ``name in app.router`` etc.\n\n   .. seealso:: :ref:`Route classes <aiohttp-web-route>`\n\n   .. method:: add_route(method, path, handler, *, \\\n                         name=None, expect_handler=None)\n\n      Append :ref:`handler<aiohttp-web-handler>` to the end of route table.\n\n      *path* may be either *constant* string like ``'/a/b/c'`` or\n       *variable rule* like ``'/a/{var}'`` (see\n       :ref:`handling variable pathes<aiohttp-web-variable-handler>`)\n\n      Pay attention please: *handler* is converted to coroutine internally when\n      it is a regular function.\n\n      :param str method: HTTP method for route. Should be one of\n                         ``'GET'``, ``'POST'``, ``'PUT'``,\n                         ``'DELETE'``, ``'PATCH'``, ``'HEAD'``,\n                         ``'OPTIONS'`` or ``'*'`` for any method.\n\n                         The parameter is case-insensitive, e.g. you\n                         can push ``'get'`` as well as ``'GET'``.\n\n      :param str path: route path. Should be started with slash (``'/'``).\n\n      :param callable handler: route handler.\n\n      :param str name: optional route name.\n\n      :param coroutine expect_handler: optional *expect* header handler.\n\n      :returns: new :class:`PlainRoute` or :class:`DynamicRoute` instance.\n\n   .. method:: add_static(prefix, path, *, name=None, expect_handler=None, \\\n                          chunk_size=256*1024)\n\n      Adds router for returning static files.\n\n      Useful for handling static content like images, javascript and css files.\n\n      .. warning::\n\n         Use :meth:`add_static` for development only. In production,\n         static content should be processed by web servers like *nginx*\n         or *apache*.\n\n      :param str prefix: URL path prefix for handled static files\n\n      :param str path: path to the folder in file system that contains\n                       handled static files.\n\n      :param str name: optional route name.\n\n      :param coroutine expect_handler: optional *expect* header handler.\n\n      :param int chunk_size: size of single chunk for file\n                             downloading, 64Kb by default.\n\n                             Increasing *chunk_size* parameter to,\n                             say, 1Mb may increase file downloading\n                             speed but consumes more memory.\n\n                             .. versionadded:: 0.16\n\n   :returns: new :class:`StaticRoute` instance.\n\n   .. coroutinemethod:: resolve(requst)\n\n      A :ref:`coroutine<coroutine>` that returns\n      :class:`AbstractMatchInfo` for *request*.\n\n      The method never raises exception, but returns\n      :class:`AbstractMatchInfo` instance with:\n\n      1. :attr:`~AbstractMatchInfo.route` asigned to\n         :class:`SystemRoute` instance\n      2. :attr:`~AbstractMatchInfo.handler` which raises\n         :exc:`HTTPNotFound` or :exc:`HTTPMethodNotAllowed` on handler's\n         execution if there is no registered route for *request*.\n\n         *Middlewares* can process that exceptions to render\n         pretty-looking error page for example.\n\n      Used by internal machinery, end user unlikely need to call the method.\n\n      .. note:: The method uses :attr:`Request.raw_path` for pattern\n         matching against registered routes.\n\n      .. versionchanged:: 0.14\n\n         The method don't raise :exc:`HTTPNotFound` and\n         :exc:`HTTPMethodNotAllowed` anymore.\n\n\n.. _aiohttp-web-route:\n\nRoute\n^^^^^\n\nDefault router :class:`UrlDispatcher` operates with *routes*.\n\nUser should not instantiate route classes by hand but can give *named\nroute instance* by ``router[name]`` if he have added route by\n:meth:`UrlDispatcher.add_route` or :meth:`UrlDispatcher.add_static`\ncalls with non-empty *name* parameter.\n\nThe main usage of *named routes* is constructing URL by route name for\npassing it into *template engine* for example::\n\n   url = app.router['route_name'].url(query={'a': 1, 'b': 2})\n\nThere are three concrete route classes:* :class:`DynamicRoute` for\nurls with :ref:`variable pathes<aiohttp-web-variable-handler>` spec.\n\n\n* :class:`PlainRoute` for urls without :ref:`variable\n  pathes<aiohttp-web-variable-handler>`\n\n* :class:`DynamicRoute` for urls with :ref:`variable\n  pathes<aiohttp-web-variable-handler>` spec.\n\n* :class:`StaticRoute` for static file handlers.\n\n.. class:: Route\n\n   Base class for routes served by :class:`UrlDispatcher`.\n\n   .. attribute:: method\n\n   HTTP method handled by the route, e.g. *GET*, *POST* etc.\n\n   .. attribute:: handler\n\n   :ref:`handler<aiohttp-web-handler>` that processes the route.\n\n   .. attribute:: name\n\n   Name of the route.\n\n   .. method:: match(path)\n\n   Abstract method, accepts *URL path* and returns :class:`dict` with\n   parsed *path parts* for :class:`UrlMappingMatchInfo` or ``None`` if\n   the route cannot handle given *path*.\n\n   The method exists for internal usage, end user unlikely need to call it.\n\n   .. method:: url(*, query=None, **kwargs)\n\n   Abstract method for constructing url handled by the route.\n\n   *query* is a mapping or list of *(name, value)* pairs for\n   specifying *query* part of url (parameter is processed by\n   :func:`~urllib.parse.urlencode`).\n\n   Other available parameters depends on concrete route class and\n   described in descendant classes.\n\n.. class:: PlainRoute\n\n   The route class for handling plain *URL path*, e.g. ``\"/a/b/c\"``\n\n   .. method:: url(*, parts, query=None)\n\n   Construct url, doesn't accepts extra parameters::\n\n      >>> route.url(query={'d': 1, 'e': 2})\n      '/a/b/c/?d=1&e=2'``\n\n.. class:: DynamicRoute\n\n   The route class for handling :ref:`variable\n   path<aiohttp-web-variable-handler>`, e.g. ``\"/a/{name1}/{name2}\"``\n\n   .. method:: url(*, parts, query=None)\n\n   Construct url with given *dynamic parts*::\n\n       >>> route.url(parts={'name1': 'b', 'name2': 'c'},\n                     query={'d': 1, 'e': 2})\n       '/a/b/c/?d=1&e=2'\n\n\n.. class:: StaticRoute\n\n   The route class for handling static files, created by\n   :meth:`UrlDispatcher.add_static` call.\n\n   .. method:: url(*, filename, query=None)\n\n   Construct url for given *filename*::\n\n      >>> route.url(filename='img/logo.png', query={'param': 1})\n      '/path/to/static/img/logo.png?param=1'\n\n\n.. class:: SystemRoute\n\n   The route class for internal purposes.\n\n   Now it has used for handling *404: Not Found* and *405: Method Not Allowed*.\n\n   .. method:: url()\n\n   Always raises :exc:`RuntimeError`, :class:`SystemRoute` should not\n   be used in url construction expressions.\n\n\nMatchInfo\n^^^^^^^^^\n\nAfter route matching web application calls found handler if any.\n\nMatching result can be accessible from handler as\n:attr:`Request.match_info` attribute.\n\nIn general the result may be any object derived from\n:class:`AbstractMatchInfo` (:class:`UrlMappingMatchInfo` for default\n:class:`UrlDispatcher` router).\n\n.. class:: UrlMappingMatchInfo\n\n   Inherited from :class:`dict` and :class:`AbstractMatchInfo`. Dict\n   items are given from :meth:`Route.match` call return value.\n\n   .. attribute:: route\n\n   :class:`Route` instance for url matching.\n\n\n\nUtilities\n---------\n\n.. class:: FileField\n\n   A :func:`~collections.namedtuple` that is returned as multidict value\n   by :meth:`Request.POST` if field is uploaded file.\n\n   .. attribute:: name\n\n      Field name\n\n   .. attribute:: filename\n\n      File name as specified by uploading (client) side.\n\n   .. attribute:: file\n\n      An :class:`io.IOBase` instance with content of uploaded file.\n\n   .. attribute:: content_type\n\n      *MIME type* of uploaded file, ``'text/plain'`` by default.\n\n   .. seealso:: :ref:`aiohttp-web-file-upload`\n\n\nConstants\n---------\n\n.. class:: ContentCoding\n\n   An :class:`enum.Enum` class of available Content Codings.\n\n   .. attribute:: deflate\n\n   .. attribute:: gzip\n\n   .. attribute:: identity\n",
            "header": {
                "file": {
                    "path": "docs/web_reference.rst"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "0f4a3d4b",
                "new_commit_hash": "b4f8b06b",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/docs/web_reference.rst"
            },
            "plus_file": {
                "path": "b/docs/web_reference.rst"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 918,
                            "length": 7
                        },
                        "new_range": {
                            "start": 918,
                            "length": 7
                        },
                        "section": "arbitrary properties for later access from"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "   .. note::",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "      Application object has :attr:`route` attribute but has no",
                                "type": "context"
                            },
                            {
                                "content": "      ``add_router`` method. The reason is: we want to support",
                                "type": "deleted"
                            },
                            {
                                "content": "      ``add_route()`` method. The reason is: we want to support",
                                "type": "added"
                            },
                            {
                                "content": "      different route implementations (even maybe not url-matching",
                                "type": "context"
                            },
                            {
                                "content": "      based but traversal ones).",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 1000,
                            "length": 9
                        },
                        "new_range": {
                            "start": 1000,
                            "length": 9
                        },
                        "section": "Router is any object that implements :class:`AbstractRouter` interface."
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "                         The parameter is case-insensitive, e.g. you",
                                "type": "context"
                            },
                            {
                                "content": "                         can push ``'get'`` as well as ``'GET'``.",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "      :param str path: route path",
                                "type": "deleted"
                            },
                            {
                                "content": "      :param str path: route path. Should be started with slash (``'/'``).",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "      :param callable handler: route handler",
                                "type": "deleted"
                            },
                            {
                                "content": "      :param callable handler: route handler.",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "      :param str name: optional route name.",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "import asyncio\nimport os\nimport unittest\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",
            "new_file_content": "import asyncio\nimport os\nimport unittest\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",
            "header": {
                "file": {
                    "path": "tests/test_urldispatch.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "269b18a0",
                "new_commit_hash": "7b462657",
                "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": 545,
                            "length": 3
                        },
                        "new_range": {
                            "start": 545,
                            "length": 13
                        },
                        "section": "class TestUrlDispatcher(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "            })",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        self.loop.run_until_complete(go())",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_add_route_not_started_with_slash(self):",
                                "type": "added"
                            },
                            {
                                "content": "        with self.assertRaises(ValueError):",
                                "type": "added"
                            },
                            {
                                "content": "            handler = self.make_handler()",
                                "type": "added"
                            },
                            {
                                "content": "            self.router.add_route('GET', 'invalid_path', handler)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_add_route_invalid_method(self):",
                                "type": "added"
                            },
                            {
                                "content": "        with self.assertRaises(ValueError):",
                                "type": "added"
                            },
                            {
                                "content": "            handler = self.make_handler()",
                                "type": "added"
                            },
                            {
                                "content": "            self.router.add_route('INVALID_METHOD', '/path', handler)",
                                "type": "added"
                            },
                            {
                                "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    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)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 18,
                            "end_lineno": 557,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "tests/test_urldispatch.py",
                            "type": "method",
                            "name": "TestUrlDispatcher.test_add_route_not_started_with_slash",
                            "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    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)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 549,
                            "end_lineno": 552,
                            "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    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)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 18,
                                "end_lineno": 557,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "tests/test_urldispatch.py",
                            "type": "method",
                            "name": "TestUrlDispatcher.test_add_route_invalid_method",
                            "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    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)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 554,
                            "end_lineno": 557,
                            "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    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)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 18,
                                "end_lineno": 557,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "c054f579dd04bfa5d3f0ee78d4cca4107f96d4c4^",
    "new_commit_hash": "c054f579dd04bfa5d3f0ee78d4cca4107f96d4c4",
    "commit_message": "Merge branch 'master' of github.com:KeepSafe/aiohttp",
    "commit_date": "2015-06-30T10:24:42+03:00",
    "metadata": {}
}
{
    "repo_name": "aiohttp",
    "new_commit_hash": "c054f579dd04bfa5d3f0ee78d4cca4107f96d4c4",
    "test_file_codes": [
        "import asyncio\nimport os\nimport unittest\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"
    ],
    "test_file_names": [
        "test_1.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Transforming aiohttp/worker.py\nTransforming aiohttp/client_reqrep.py\nTransforming aiohttp/server.py\nTransforming aiohttp/client.py\n",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nmake: *** No rule to make target '.develop'.  Stop.\nResolved 26 packages in 27ms\nInstalled 26 packages in 49ms\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_c054f579dd04bfa5d3f0ee78d4cca4107f96d4c4\nplugins: asyncio-0.25.0, mock-3.14.0, cov-6.0.0\nasyncio: mode=strict, asyncio_default_fixture_loop_scope=None\ncollected 57 items\n\nr2e_tests/test_1.py .....F.............................................. [ 91%]\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:391: 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_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_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, 56 passed in 0.59s =========================\n",
    "new_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_c054f579dd04bfa5d3f0ee78d4cca4107f96d4c4/.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_c054f579dd04bfa5d3f0ee78d4cca4107f96d4c4\nplugins: asyncio-0.25.0, mock-3.14.0, cov-6.0.0\nasyncio: mode=strict, asyncio_default_fixture_loop_scope=None\ncollected 57 items\n\nr2e_tests/test_1.py .FF..F.............................................. [ 91%]\n.....                                                                    [100%]\n\n=================================== FAILURES ===================================\n_______________ TestUrlDispatcher.test_add_route_invalid_method ________________\n\nself = <r2e_tests.test_1.TestUrlDispatcher testMethod=test_add_route_invalid_method>\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\nr2e_tests/test_1.py:557: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def add_route(self, method, path, handler,\n                  *, name=None, expect_handler=None):\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>       assert method in self.METHODS, method\nE       AssertionError: INVALID_METHOD\n\naiohttp/web_urldispatcher.py:365: AssertionError\n___________ TestUrlDispatcher.test_add_route_not_started_with_slash ____________\n\nself = <r2e_tests.test_1.TestUrlDispatcher testMethod=test_add_route_not_started_with_slash>\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)\nE           AssertionError: ValueError not raised\n\nr2e_tests/test_1.py:552: AssertionError\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:391: 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_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_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_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_invalid_method\nFAILED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_not_started_with_slash\nFAILED r2e_tests/test_1.py::TestUrlDispatcher::test_add_route_with_invalid_re\n========================= 3 failed, 54 passed in 0.24s =========================\n",
    "old_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_c054f579dd04bfa5d3f0ee78d4cca4107f96d4c4/.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 docs/web_reference.rst tests/test_urldispatch.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** UrlDispatcher Fails to Raise ValueError for Invalid HTTP Methods and Paths

**Description:**
When adding a route to the `UrlDispatcher` with an unsupported HTTP method or a path that doesn't start with a `/`, the dispatcher does not raise a `ValueError` as expected. Instead, it either raises an `AssertionError` or fails to raise any error, leading to inconsistent and unclear error handling.

**Example Code:**
```python
from aiohttp import web

app = web.Application()
router = app.router

handler = lambda request: web.Response(text='Hello')

# Attempt to add a route with an invalid HTTP method
router.add_route('INVALID_METHOD', '/path', handler)

# Attempt to add a route with a path not starting with '/'
router.add_route('GET', 'invalid_path', handler)
```

**Expected Behavior:**
Adding a route with an unsupported HTTP method or a path that does not start with `/` should raise a `ValueError` with a clear and descriptive error message.

**Actual Behavior:**
- Adding a route with an invalid HTTP method results in an `AssertionError: INVALID_METHOD`.
- Adding a route with a path not starting with `/` does not raise a `ValueError`, causing the application to accept invalid route configurations silently.
[/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
__all__ = ('UrlDispatcher', 'UrlMappingMatchInfo',
           'Route', 'PlainRoute', 'DynamicRoute', 'StaticRoute')

import abc
import asyncio

import collections
import mimetypes
import re
import os
import inspect

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


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):
        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

        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)

    @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 = StreamResponse()
        resp.content_type = ct
        if encoding:
            resp.headers[hdrs.CONTENT_ENCODING] = encoding
        resp.last_modified = st.st_mtime

        file_size = st.st_size
        single_chunk = file_size < self._chunk_size

        if single_chunk:
            resp.content_length = file_size
        resp.start(request)

        with open(filepath, 'rb') as f:
            chunk = f.read(self._chunk_size)
            if single_chunk:
                resp.write(chunk)
            else:
                while chunk:
                    resp.write(chunk)
                    chunk = f.read(self._chunk_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 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 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):

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

        method = upstr(method)
        assert method in self.METHODS, 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):
        """
        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)
        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:** UrlDispatcher Fails to Raise ValueError for Invalid HTTP Methods and Paths

**Description:**
When adding a route to the `UrlDispatcher` with an unsupported HTTP method or a path that doesn't start with a `/`, the dispatcher does not raise a `ValueError` as expected. Instead, it either raises an `AssertionError` or fails to raise any error, leading to inconsistent and unclear error handling.

**Example Code:**
```python
from aiohttp import web

app = web.Application()
router = app.router

handler = lambda request: web.Response(text='Hello')

# Attempt to add a route with an invalid HTTP method
router.add_route('INVALID_METHOD', '/path', handler)

# Attempt to add a route with a path not starting with '/'
router.add_route('GET', 'invalid_path', handler)
```

**Expected Behavior:**
Adding a route with an unsupported HTTP method or a path that does not start with `/` should raise a `ValueError` with a clear and descriptive error message.

**Actual Behavior:**
- Adding a route with an invalid HTTP method results in an `AssertionError: INVALID_METHOD`.
- Adding a route with a path not starting with `/` does not raise a `ValueError`, causing the application to accept invalid route configurations silently.
[/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_static_adds_slash": "PASSED",
    "TestUrlDispatcher.test_static_dont_add_trailing_slash": "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 6255f00f..0c9b33ee 100644
--- a/aiohttp/web_urldispatcher.py
+++ b/aiohttp/web_urldispatcher.py
@@ -356,13 +356,17 @@ class UrlDispatcher(AbstractRouter, collections.abc.Mapping):
     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)
-        assert method in self.METHODS, 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(

{"aiohttp/web_urldispatcher.py": "__all__ = ('UrlDispatcher', 'UrlMappingMatchInfo',\n           'Route', 'PlainRoute', 'DynamicRoute', 'StaticRoute')\n\nimport abc\nimport asyncio\n\nimport collections\nimport mimetypes\nimport re\nimport os\nimport inspect\n\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\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        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\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    @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 = StreamResponse()\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        single_chunk = file_size < self._chunk_size\n\n        if single_chunk:\n            resp.content_length = file_size\n        resp.start(request)\n\n        with open(filepath, 'rb') as f:\n            chunk = f.read(self._chunk_size)\n            if single_chunk:\n                resp.write(chunk)\n            else:\n                while chunk:\n                    resp.write(chunk)\n                    chunk = f.read(self._chunk_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 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 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        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        assert method in self.METHODS, 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):\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        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:** UrlDispatcher Fails to Raise ValueError for Invalid HTTP Methods and Paths

**Description:**
When adding a route to the `UrlDispatcher` with an unsupported HTTP method or a path that doesn't start with a `/`, the dispatcher does not raise a `ValueError` as expected. Instead, it either raises an `AssertionError` or fails to raise any error, leading to inconsistent and unclear error handling.

**Example Code:**
```python
from aiohttp import web

app = web.Application()
router = app.router

handler = lambda request: web.Response(text='Hello')

# Attempt to add a route with an invalid HTTP method
router.add_route('INVALID_METHOD', '/path', handler)

# Attempt to add a route with a path not starting with '/'
router.add_route('GET', 'invalid_path', handler)
```

**Expected Behavior:**
Adding a route with an unsupported HTTP method or a path that does not start with `/` should raise a `ValueError` with a clear and descriptive error message.

**Actual Behavior:**
- Adding a route with an invalid HTTP method results in an `AssertionError: INVALID_METHOD`.
- Adding a route with a path not starting with `/` does not raise a `ValueError`, causing the application to accept invalid route configurations silently.
[/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
__all__ = ('UrlDispatcher', 'UrlMappingMatchInfo',
           'Route', 'PlainRoute', 'DynamicRoute', 'StaticRoute')

import abc
import asyncio

import collections
import mimetypes
import re
import os
import inspect

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


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):
        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

        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)

    @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 = StreamResponse()
        resp.content_type = ct
        if encoding:
            resp.headers[hdrs.CONTENT_ENCODING] = encoding
        resp.last_modified = st.st_mtime

        file_size = st.st_size
        single_chunk = file_size < self._chunk_size

        if single_chunk:
            resp.content_length = file_size
        resp.start(request)

        with open(filepath, 'rb') as f:
            chunk = f.read(self._chunk_size)
            if single_chunk:
                resp.write(chunk)
            else:
                while chunk:
                    resp.write(chunk)
                    chunk = f.read(self._chunk_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 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 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):

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

        method = upstr(method)
        assert method in self.METHODS, 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):
        """
        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)
        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