def testSplitLeaf(self): r = Route('bla/foo/<id>/pluto/leaf') p, l = r.split() self.assertFalse(p.is_leaf) self.assertTrue(l.is_leaf) self.assertEqual(p.path, '/bla/foo/<id>/pluto/') self.assertEqual(l.path, '/leaf')
def testSplitDir(self): r = Route('bla/foo/<id>/pluto/') self.assertEqual(r.level, 4) p, l = r.split() self.assertFalse(p.is_leaf) self.assertFalse(l.is_leaf) self.assertEqual(p.path, '/bla/foo/<id>/') self.assertEqual(l.path, '/pluto/')
def testIntVariable(self): r = Route('<int:id>/') self.assertEqual(str(r), '/<int:id>/') self.assertEqual(r.variables, set(['id'])) self.assertEqual(r.breadcrumbs, ((True, 'id'),)) self.assertEqual(r.match('35/'), {'id': 35}) self.assertEqual(r.url(id=1), '/1/') self.assertRaises(ValueError, r.url, id='bla')
def testSimple(self): r = Route('bla/') self.assertFalse(r.is_leaf) self.assertEqual(r.level,1) self.assertEqual(len(r.variables), 0) self.assertEqual(r.rule,'bla/') self.assertEqual(r.match('bla/'),{}) self.assertEqual(r.match('bladdd/'),None) self.assertEqual(r.match('bla/another/'), {'__remaining__':'another/'})
def testPathVaiable(self): r = Route('bla/<path:rest>', defaults={'rest': ''}) self.assertEqual(r.variables, set(['rest'])) self.assertEqual(r.level, 2) self.assertTrue(r.is_leaf) self.assertEqual(r.match('bla/a/b/c.html'), {'rest': 'a/b/c.html'}) self.assertEqual(r.match('bla/'), {'rest': ''}) self.assertEqual(r.url(rest='a/'), '/bla/a/') self.assertEqual(r.url(), '/bla/')
def testRoot(self): r = Route('/') self.assertFalse(r.is_leaf) self.assertEqual(r.rule, '') r = Route('////') self.assertFalse(r.is_leaf) self.assertEqual(r.rule, '') self.assertEqual(r.match(''), {}) self.assertEqual(r.match('bee/'), {'__remaining__': 'bee/'})
def testStringVariable(self): r = Route('<name>/') self.assertFalse(r.is_leaf) self.assertEqual(r.variables, set(['name'])) self.assertEqual(r.breadcrumbs, ((True, 'name'),)) self.assertEqual(r.rule, '<name>/') self.assertEqual(r.match('bla-foo/'), {'name': 'bla-foo'}) self.assertEqual(r.match('bla/another/'), {'name': 'bla', '__remaining__': 'another/'}) self.assertEqual(r.url(name='luca'), '/luca/')
def testIntVariableFixDigits(self): r = Route('<int(2):id>/') self.assertEqual(str(r),'/<int(2):id>/') self.assertEqual(r.variables, set(['id'])) self.assertEqual(r.breadcrumbs, ((True,'id'),)) self.assertEqual(r.match('35/'),{'id':35}) self.assertEqual(r.match('355/'),None) self.assertEqual(r.match('6/'),None) self.assertEqual(r.match('ch/'),None) self.assertEqual(r.url(id = 13), '/13/') self.assertEqual(r.url(id = 1), '/01/') self.assertRaises(ValueError,lambda : r.url(id = 134)) self.assertRaises(ValueError,lambda : r.url(id = 'bl')) self.assertRaises(ValueError,lambda : r.url(id = 'bla'))
def test2StringVariables(self): r = Route('<name>/<child>/') self.assertFalse(r.is_leaf) self.assertEqual(r.level, 2) self.assertEqual(r.variables, set(['name', 'child'])) self.assertEqual(r.breadcrumbs, ((True, 'name'), (True, 'child'))) self.assertEqual(r.rule, '<name>/<child>/') self.assertEqual(r.match('bla/foo/'), {'name': 'bla', 'child': 'foo'}) self.assertEqual(r.match('bla/foo/another/'), {'name': 'bla', 'child': 'foo', '__remaining__': 'another/'}) self.assertRaises(KeyError, r.url, name='luca') self.assertEqual(r.url(name='luca', child='joshua'), '/luca/joshua/')
def testIntVariableMinMax(self): r = Route('<int(min=1):cid>/') self.assertEqual(str(r),'/<int(min=1):cid>/') self.assertEqual(r.variables, set(['cid'])) self.assertEqual(r.breadcrumbs,((True,'cid'),)) self.assertEqual(r.match('1/'),{'cid':1}) self.assertEqual(r.match('476876/'),{'cid':476876}) self.assertEqual(r.match('0/'),None) self.assertEqual(r.match('-5/'),None) self.assertEqual(r.url(cid = 13), '/13/') self.assertEqual(r.url(cid = 1), '/1/') self.assertRaises(ValueError,lambda : r.url(cid = 0)) self.assertRaises(ValueError,lambda : r.url(cid = -10)) self.assertRaises(ValueError,lambda : r.url(cid = 'bla'))
def page(self, path): '''Obtain a page object from a path ''' key = self.cache_key() try: sitemap = self.app.cache_server.get_json(key) assert isinstance(sitemap, list) except Exception: sitemap = None if not sitemap: sitemap = self.build_map() self.app.cache_server.set_json(key, sitemap) for page in sitemap: route = Route(page['path']) if route.match(path): return page
def __init__(self, app, name, url=None, jwt=None, spec=None): if name == '*': name = '' self.route = Route('%s/<path:path>' % name) self.urlp = urlparse(url) self.jwt = jwt self.spec = spec self.router = RestRoot(self.urlp.path) if spec: self.router.add_child(Specification(spec))
def match(self, path, sitemap=None): '''Match a path with a page form ``sitemap`` If no sitemap is given, use the default sitemap form the :meth:`site_map` method. If no page is matched returns Nothing. ''' if sitemap is None: sitemap = self.site_map(self.app) for page in sitemap: route = Route(page['path']) if isinstance(path, Route): if path == route: return page else: matched = route.match(path) if matched is not None and '__remaining__' not in matched: return page
class Proxy(LocalMixin): '''Proxy requests to another server ''' def __init__(self, route, url): self.route = Route(route) self.url = url @local_property def http_client(self): '''The :class:`.HttpClient` used by this proxy middleware for accessing upstream resources''' return HttpClient(decompress=False, store_cookies=False) def __call__(self, environ, start_response): request = wsgi_request(environ) path = request.path match = self.route.match(path[1:]) if match is not None: query = request.get('QUERY_STRING', '') path = urljoin(self.url, match.pop('__remaining__', '')) if query: path = '%s?%s' % (path, query) return self._call(request, path, start_response) @task def _call(self, request, path, start_response): data, files = yield from as_coroutine(request.data_and_files()) response = yield from self.http_client.request( request.method, path, data=data, files=files, headers=self.request_headers(request.environ), version=request.get('SERVER_PROTOCOL')) response.raise_for_status() start_response(response.get_status(), list(response.headers)) return [response.get_content()] def request_headers(self, environ): '''Fill request headers from the environ dictionary and modify them via the list of :attr:`headers_middleware`. The returned headers will be sent to the target uri. ''' headers = Headers(kind='client') for k in environ: if k.startswith('HTTP_'): head = k[5:].replace('_', '-') headers[head] = environ[k] for head in ENVIRON_HEADERS: k = head.replace('-', '_').upper() v = environ.get(k) if v: headers[head] = v return headers
def testSplitRoot(self): r = Route('') self.assertEqual(r.level, 0) p, li = r.split() self.assertFalse(p.is_leaf) self.assertEqual(p.path, '/') self.assertEqual(li, None) r = Route('bla') p, li = r.split() self.assertFalse(p.is_leaf) self.assertTrue(li.is_leaf) self.assertEqual(p.path, '/') self.assertEqual(li.path, '/bla') r = Route('bla/') p, li = r.split() self.assertFalse(p.is_leaf) self.assertFalse(li.is_leaf) self.assertEqual(p.path, '/') self.assertEqual(li.path, '/bla/')
def __init__(self, app, name, spec, spec_path, url, jwt=None, cors=True): self.init_app(app) if name == '*': name = '' self.spec = spec self.route = Route('%s/<path:path>' % name) self.url = url self.jwt = jwt self.cors = cors self.registry = {} self._spec_path = spec_path self._router = [Specification(spec_path, api=self)] self.spec.add_schema(ErrorSchema) self.spec.add_schema(ErrorMessageSchema)
def testSimpleLevel2(self): r = Route('bla/foo/') self.assertFalse(r.is_leaf) self.assertEqual(r.level, 2) self.assertEqual(len(r.variables), 0) self.assertEqual(r.rule, 'bla/foo/') self.assertEqual(r.match('bla/'), None) self.assertEqual(r.match('bla/foo/'), {}) self.assertEqual(r.match('bla/fooddd/'), None) self.assertEqual(r.match('bla/foo/another/'), {'__remaining__': 'another/'})
def test2StringVariables(self): r = Route('<name>/<child>/') self.assertFalse(r.is_leaf) self.assertEqual(r.level, 2) self.assertEqual(r.variables, set(['name', 'child'])) self.assertEqual(r.breadcrumbs, ((True, 'name'), (True, 'child'))) self.assertEqual(r.rule, '<name>/<child>/') self.assertEqual(r.match('bla/foo/'), {'name': 'bla', 'child': 'foo'}) self.assertEqual(r.match('bla/foo/another/'), { 'name': 'bla', 'child': 'foo', '__remaining__': 'another/' }) self.assertRaises(KeyError, lambda: r.url(name='luca')) self.assertEqual(r.url(name='luca', child='joshua'), '/luca/joshua/')
class ApiSpec: """Information about an API """ def __init__(self, app, name, url=None, jwt=None, spec=None): if name == '*': name = '' self.route = Route('%s/<path:path>' % name) self.urlp = urlparse(url) self.jwt = jwt self.spec = spec self.router = RestRoot(self.urlp.path) if spec: self.router.add_child(Specification(spec)) def __repr__(self): return self.path __str__ = __repr__ @property def path(self): return self.route.path @property def netloc(self): return self.urlp.netloc def match(self, path): return self.route.match(path) def url(self, request, path=None): urlp = list(self.urlp) if path: urlp[2] = remove_double_slash('%s/%s' % (urlp[2], str(path))) if not urlp[1]: r_url = urlparse(request.absolute_uri('/')) urlp[0] = r_url.scheme urlp[1] = r_url.netloc return urlunparse(urlp)
def testSplitRoot(self): r = Route('') self.assertEqual(r.level, 0) p, l = r.split() self.assertFalse(p.is_leaf) self.assertEqual(p.path, '/') self.assertEqual(l, None) r = Route('bla') p, l = r.split() self.assertFalse(p.is_leaf) self.assertTrue(l.is_leaf) self.assertEqual(p.path, '/') self.assertEqual(l.path, '/bla') r = Route('bla/') p, l = r.split() self.assertFalse(p.is_leaf) self.assertFalse(l.is_leaf) self.assertEqual(p.path, '/') self.assertEqual(l.path, '/bla/')
def testIntVariableFixDigits(self): r = Route('<int(2):id>/') self.assertEqual(str(r), '/<int(2):id>/') self.assertEqual(r.variables, set(['id'])) self.assertEqual(r.breadcrumbs, ((True, 'id'), )) self.assertEqual(r.match('35/'), {'id': 35}) self.assertEqual(r.match('355/'), None) self.assertEqual(r.match('6/'), None) self.assertEqual(r.match('ch/'), None) self.assertEqual(r.url(id=13), '/13/') self.assertEqual(r.url(id=1), '/01/') self.assertRaises(ValueError, lambda: r.url(id=134)) self.assertRaises(ValueError, lambda: r.url(id='bl')) self.assertRaises(ValueError, lambda: r.url(id='bla'))
def __init__(self, routefrom, routeto): super().__init__(routefrom, routeto=Route(routeto))
def testIntVariableMinMax(self): r = Route('<int(min=1):cid>/') self.assertEqual(str(r), '/<int(min=1):cid>/') self.assertEqual(r.variables, set(['cid'])) self.assertEqual(r.breadcrumbs, ((True, 'cid'), )) self.assertEqual(r.match('1/'), {'cid': 1}) self.assertEqual(r.match('476876/'), {'cid': 476876}) self.assertEqual(r.match('0/'), None) self.assertEqual(r.match('-5/'), None) self.assertEqual(r.url(cid=13), '/13/') self.assertEqual(r.url(cid=1), '/1/') self.assertRaises(ValueError, lambda: r.url(cid=0)) self.assertRaises(ValueError, lambda: r.url(cid=-10)) self.assertRaises(ValueError, lambda: r.url(cid='bla'))
def testMalformedRule1(self): self.assertRaises(ValueError, lambda: Route('<bla')) self.assertRaises(ValueError, lambda: Route('<bla/')) self.assertRaises(ValueError, lambda: Route('bla>/')) self.assertRaises(ValueError, lambda: Route('/<bla'))
def testMalformedRule2(self): self.assertRaises(ValueError, lambda: Route('<foo>/<bla')) self.assertRaises(ValueError, lambda: Route('ciao/<bla/')) self.assertRaises(ValueError, lambda: Route('ahhh>/bla>/')) self.assertRaises(ValueError, lambda: Route('ahhh/bla>/'))
def testDefaults(self): r = Route('bla/<id>/add/<path:path>', {'path': ''}) self.assertEqual(r.url(id=10), '/bla/10/add/') self.assertEqual(r.url(id=10, path='ciao/luca'), '/bla/10/add/ciao/luca')
def test_empty_url(self): r = Route('') self.assertEqual(r.rule, '') self.assertEqual(r.url(), '/') self.assertEqual(r.path, '/')
def __init__(self, route, url): self.route = Route(route) self.url = url
def path(self, **urlargs): return Route(self.url).url(**urlargs)
class Api(models.Component): """An Api is a set of OpenAPI paths under a base Url """ def __init__(self, app, name, spec, spec_path, url, jwt=None, cors=True): self.init_app(app) if name == '*': name = '' self.spec = spec self.route = Route('%s/<path:path>' % name) self.url = url self.jwt = jwt self.cors = cors self.registry = {} self._spec_path = spec_path self._router = [Specification(spec_path, api=self)] self.spec.add_schema(ErrorSchema) self.spec.add_schema(ErrorMessageSchema) @property def spec_path(self): """Full path to Api Spec document """ return ( '%s/%s' % (self.url.path, self._spec_path) if self.url.path else self._spec_path ) @classmethod def from_cfg(cls, app, cfg): schema = api_schema.load(cfg) if schema.errors: app.logger.error('Could not create Api: %s', schema.errors) return data = api_schema.dump(schema.data).data url = urlparse(data['BASE_PATH']) spec = OpenAPI( data['TITLE'], version=data['VERSION'], info=dict(description=data.get('DESCRIPTION', '')), plugins=data['SPEC_PLUGINS'], default_responses=app.config['DEFAULT_REST_RESPONSES'] ) return cls(app, data['MODEL'], spec, data['SPEC_PATH'], url, cors=data['CORS']) def __repr__(self): return self.path __str__ = __repr__ @property def path(self): return self.route.path @property def netloc(self): return self.spec.doc.get('host') @property def scheme(self): schemes = self.spec.doc.get('schemes') if schemes: return schemes[-1] def match(self, path): return self.route.match(path) def add_child(self, router): assert isinstance(self._router, list), 'Cannot add child' self._router.append(router) def router(self): """Return the base router of this API. If the base router is not available it first builds the paths and subsequently returns it """ if isinstance(self._router, list): # base router root = RestRoot(self.url.path) for router in self._router: root.add_child(self._prepare_router(router)) self._router = root # build the spec so that all lazy operations are done here json.dumps(self.spec_dict()) return self._router def spec_dict(self): return self.spec.to_dict() # INTERNALS def _prepare_router(self, router): path = self.spec.add_path(router) # # inject api spec in the router router.api_spec = self.spec # # add CORS route to the router if self.cors: router.options = cors( [method.upper() for method in path.operations] ) for child in router.routes: child.__doc__ = router.__doc__ self._prepare_router(child) return router
def testMalformedRule3(self): self.assertRaises(ValueError, lambda: Route('<foo>/<foo>')) self.assertRaises(ValueError, lambda: Route('<foo>/bla/<foo>')) self.assertRaises(ValueError, lambda: Route('<foo>/<bla>/<foo>'))
def test_add_string(self): r = Route('add/<path:path>', {'path': 'foo'}) r2 = r + 'bla' self.assertEqual(r2.rule, 'add/<path:path>/bla') self.assertEqual(str(r2), '/add/<path:path>/bla') self.assertNotEqual(r2, '/add/<path:path>/bla')
def testDefaultsAddition(self): r = Route('add/<path:path>', {'path': ''}) r2 = Route('bla/<id>/') + r self.assertEqual(r2.defaults, r.defaults)