def mount(self, app, path): '''Mount a child app under `path`.''' # Check for reversable name conflicts. for key in app._view_lookup.keys(): if key in self._view_lookup: raise ReversableNameConflictError(key) self._map.add(Submount(path, app._map._rules)) self._view_lookup.update(app._view_lookup) self.children.append(app)
def create_url_map(debug=False): """Instantiate all WSGI Apps and put them into the URL-Map.""" debug_rules = [ Rule("/dump.py", endpoint=dump_environ_app), Rule("/form.py", endpoint=test_formdata), ] cmk_app = CheckmkApp() api_app = CheckmkRESTAPI(debug=debug).wsgi_app return Map([ Submount('/<string:site>', [ Submount("/check_mk", [ Rule("/", endpoint=cmk_app), *(debug_rules if debug else []), Rule("/api/<string:version>/<path:path>", endpoint=api_app), Rule("/<string:script>", endpoint=cmk_app), ]), ]) ])
def create_url_map(debug=False): """Instantiate all WSGI Apps and put them into the URL-Map.""" _api_app = CheckmkApiApp( __name__, debug=debug, specification_dir=openapi_spec_dir(), ) # NOTE # The URL will always contain the most up to date major version number, so that clients # exploring the API (browsers, etc.) will have a structural stability guarantee. Within major # versions only additions of fields or endpoints are allowed, never field changes or removals. # If a new major version is created it should be ADDED here and not replace the older version. # NOTE: v0 means totally unstable until we hit v1. _api_app.add_api_blueprint( 'checkmk.yaml', base_path='/%s/check_mk/api/v0/' % cmk_version.omd_site(), ) wrapped_api_app = with_context_middleware( OverrideRequestMethod(_api_app).wsgi_app) cmk_app = CheckmkApp() debug_rules = [ Rule("/dump.py", endpoint=dump_environ_app), Rule("/form.py", endpoint=test_formdata), ] return Map([ Submount('/<string:site>', [ Submount("/check_mk", [ Rule("/", endpoint=cmk_app), *(debug_rules if debug else []), Submount('/api', [ Rule("/", endpoint=wrapped_api_app), Rule("/<path:path>", endpoint=wrapped_api_app), ]), Rule("/<string:script>", endpoint=cmk_app), ]), ]) ])
def __init__(self, root=DEFAULT_ROOT, baseclass=Distro): logger.info("Searching %s", root) self.distros = {} for distro in self.walk(root, baseclass): path = os.path.splitext(os.path.relpath(distro.tree.root, root))[0] logger.info("Found %s %s at %s", distro.name, distro.version, path) self.distros[path] = distro rules = chain((Submount(('/%s' % path), distro.rules) for path, distro in self.distros.items()), ( Rule('/menu.ipxe', endpoint=self.ep_menu_ipxe), Rule('/<path:path>', endpoint=self.ep_static), )) self.urlmap = Map(rules) self.static = SharedDataMiddleware(NotFound(), {'/': root})
def _init_coll_routes(self, coll_prefix): routes = self._make_coll_routes(coll_prefix) # init loc routes, if any loc_keys = list(self.rewriterapp.loc_map.keys()) if loc_keys: routes.append(Rule('/', endpoint=self.serve_home)) submount_route = ', '.join(loc_keys) submount_route = '/<any({0}):lang>'.format(submount_route) self.url_map.add(Submount(submount_route, routes)) for route in routes: self.url_map.add(route)
def _build_rules(specs): """Adapts the list of anillo urlmapping specs into a list of werkzeug rules or rules subclasses. :param list specs: A list of anillo url mapping specs. :return: generator """ for spec in specs: if "context" in spec: yield Submount(spec["context"], list(_build_rules(spec.get("routes", [])))) else: rulespec = spec.copy() match = rulespec.pop("match") handler = rulespec.pop("handler") yield Rule(match, endpoint=handler, **rulespec)
def create_url_map(debug: bool = False) -> Map: """Instantiate all WSGI Apps and put them into the URL-Map.""" debug_rules = [ Rule("/dump.py", endpoint="debug-dump"), Rule("/form.py", endpoint="debug-form"), ] return Map([ Submount( "/<string:site>", [ Submount( "/check_mk", [ Rule("/", endpoint="cmk"), *(debug_rules if debug else []), Rule("/api/<string:version>/<path:path>", endpoint="rest-api"), Rule("/<string:script>", endpoint="cmk"), ], ), ], ) ])
def decorator( cls_def: ExposedClassDefinition) -> ExposedClassDefinition: """ :param cls_def: A class with atleast one method decoratored by CLSEndpointFlask.expose :return: Returns cls_def """ cls_name = cls_def.__name__ assert cls_name not in self._instances, \ f"There is already a {cls_name} in add_class" cls_obj = self._instances[cls_name] = cls_def() prefilter = self._find_prefilter(cls_obj) postfilter = self._find_postfilter(cls_obj) endpoints = { name: func for name, func in self._find_exposed(cls_obj) } # Does the class have pre or post filter methods? if prefilter or postfilter: # TODO to shorten this scope down, this decorator could be made into a staticmethod of CLSEndpointFlask for name, method in endpoints.items(): orig_method_rule = getattr(endpoints[name], "_EXPOSED") endpoints[name] = self._pre_and_postfilter_decorator( method, postfilter=postfilter, prefilter=prefilter) # partial_method = functools.partial(view_method_decorator, endpoints[name]) # # To make it easier for debugging, have the common attributes like __qualname__ copied over to the partial # partial_method = functools.update_wrapper(partial_method, endpoints[name]) # setattr(partial_method, "_EXPOSED", orig_method_rule) # endpoints[name] = partial_method else: # acknowledge nothing needs to be done to the endpoints pass sub_rule = Submount(class_uri, self._get_exposed_rules(endpoints)) self.url_map.add(sub_rule) # setup our exclusives self._assign_exclusive_rules(cls_obj, postfilter=postfilter, prefilter=prefilter) return cls_def
def get_url_adapter(self, app): """ Returns the URL adapter for the website """ cache_rv = self._url_adapter_cache.get(self.id) if cache_rv is not None: return cache_rv url_rules = app.get_urls()[:] # Add the static url url_rules.append( app.url_rule_class( app.static_url_path + '/<path:filename>', endpoint='static', ) ) for url_kwargs in self.url_map.get_rules_arguments(): rule = app.url_rule_class( url_kwargs.pop('rule'), **url_kwargs ) rule.provide_automatic_options = True url_rules.append(rule) # Add rule to map url_map = Map() if self.locales: # Create the URL map with locale prefix url_map.add( app.url_rule_class( '/', redirect_to='/%s' % self.default_locale.code, ), ) url_map.add(Submount('/<locale>', url_rules)) else: # Create a new map with the given URLs map(url_map.add, url_rules) # Add the rules from the application's url map filled through the # route decorator or otherwise for rule in app.url_map._rules: url_map.add(rule.empty()) self._url_adapter_cache.set(self.id, url_map) return url_map
def web_ui_rules(): return [ Rule('/', endpoint='index', methods=('GET',)), Submount(WEB_UI_URL_PREFIX, [ # convenience endpoint that serves certs without regard for # checking whether they belong to any particular (logical) # cert repo (these URLs aren't part of the "PKI API", for lack # of a better term) Rule('/any-cert/<arch>/<label>.<ext:use_pem>', endpoint='any-cert', methods=('GET',)), Rule('/cert-bundle/<arch>', endpoint='cert-bundle', methods=('GET',)), Rule('/pfx-download/<arch>', endpoint='pfx-download', methods=('POST',)), ]) ]
def subroute(self, prefix: str) -> Iterator["Klein"]: """ Within this block, C{@route} adds rules to a C{werkzeug.routing.Submount}. This is implemented by tinkering with the instance's C{_url_map} variable. A context manager allows us to gracefully use the pattern of "change a variable, do some things with the new value, then put it back to how it was before. Named "subroute" to try and give callers a better idea of its relationship to C{@route}. Usage: :: with app.subroute("/prefix") as app: @app.route("/foo") def foo_handler(request): return 'I respond to /prefix/foo' @type prefix: string @param prefix: The string that will be prepended to the paths of all routes established during the with-block. @return: Returns None. """ _map_before_submount = self._url_map segments = self._segments_in_url(prefix) class SubmountMap: def __init__(self) -> None: self.rules: List[Rule] = [] def add(self, rule: Rule) -> None: self.rules.append(rule) submount_map = SubmountMap() try: self._url_map = cast(Map, submount_map) self._subroute_segments += segments yield self _map_before_submount.add(Submount(prefix, submount_map.rules)) finally: self._url_map = _map_before_submount self._subroute_segments -= segments
def test_rule_templates(): """Rule templates""" testcase = RuleTemplate([ Submount('/test/$app', [ Rule('/foo/', endpoint='handle_foo'), Rule('/bar/', endpoint='handle_bar'), Rule('/baz/', endpoint='handle_baz') ]), EndpointPrefix( 'foo_', [Rule('/blah', endpoint='bar'), Rule('/meh', endpoint='baz')]), Subdomain( 'meh', [Rule('/blah', endpoint='x_bar'), Rule('/meh', endpoint='x_baz')]) ]) url_map = Map([ testcase(app='test1'), testcase(app='test2'), testcase(app='test3'), testcase(app='test4') ]) out = [(x.rule, x.subdomain, x.endpoint) for x in url_map.iter_rules()] assert out == ([('/test/test1/foo/', '', 'handle_foo'), ('/test/test1/bar/', '', 'handle_bar'), ('/test/test1/baz/', '', 'handle_baz'), ('/blah', '', 'foo_bar'), ('/meh', '', 'foo_baz'), ('/blah', 'meh', 'x_bar'), ('/meh', 'meh', 'x_baz'), ('/test/test2/foo/', '', 'handle_foo'), ('/test/test2/bar/', '', 'handle_bar'), ('/test/test2/baz/', '', 'handle_baz'), ('/blah', '', 'foo_bar'), ('/meh', '', 'foo_baz'), ('/blah', 'meh', 'x_bar'), ('/meh', 'meh', 'x_baz'), ('/test/test3/foo/', '', 'handle_foo'), ('/test/test3/bar/', '', 'handle_bar'), ('/test/test3/baz/', '', 'handle_baz'), ('/blah', '', 'foo_bar'), ('/meh', '', 'foo_baz'), ('/blah', 'meh', 'x_bar'), ('/meh', 'meh', 'x_baz'), ('/test/test4/foo/', '', 'handle_foo'), ('/test/test4/bar/', '', 'handle_bar'), ('/test/test4/baz/', '', 'handle_baz'), ('/blah', '', 'foo_bar'), ('/meh', '', 'foo_baz'), ('/blah', 'meh', 'x_bar'), ('/meh', 'meh', 'x_baz')])
def test_werkzeug_routing(self): from werkzeug.routing import Submount, Rule app = flask.Flask(__name__) app.url_map.add(Submount('/foo', [ Rule('/bar', endpoint='bar'), Rule('/', endpoint='index') ])) def bar(): return 'bar' def index(): return 'index' app.view_functions['bar'] = bar app.view_functions['index'] = index c = app.test_client() self.assert_equal(c.get('/foo/').data, b'index') self.assert_equal(c.get('/foo/bar').data, b'bar')
def test_endpoint_decorator(app, client): from werkzeug.routing import Submount, Rule app.url_map.add( Submount('/foo', [Rule('/bar', endpoint='bar'), Rule('/', endpoint='index')])) @app.endpoint('bar') def bar(): return 'bar' @app.endpoint('index') def index(): return 'index' assert client.get('/foo/').data == b'index' assert client.get('/foo/bar').data == b'bar'
def __init__(self, debug: bool = False): self.debug = debug # This intermediate data structure is necessary because `Rule`s can't contain anything # other than str anymore. Technically they could, but the typing is now fixed to str. self.endpoints: Dict[str, WSGIApplication] = { "swagger-ui": ServeSwaggerUI(prefix="/[^/]+/check_mk/api/[^/]+/ui"), "swagger-ui-yaml": ServeSpec("swagger-ui", "yaml"), "swagger-ui-json": ServeSpec("swagger-ui", "json"), "doc-yaml": ServeSpec("doc", "yaml"), "doc-json": ServeSpec("doc", "json"), } rules: List[Rule] = [] endpoint: Endpoint for endpoint in ENDPOINT_REGISTRY: if self.debug: # This helps us to make sure we can always generate a valid OpenAPI yaml file. _ = endpoint.to_operation_dict() rules.append( Rule( endpoint.default_path, methods=[endpoint.method], endpoint=endpoint.ident, )) self.endpoints[endpoint.ident] = Authenticate(endpoint.wrapped) self.url_map = Map([ Submount( "/<path:_path>", [ Rule("/ui/", endpoint="swagger-ui"), Rule("/ui/<path:path>", endpoint="swagger-ui"), Rule("/openapi-swagger-ui.yaml", endpoint="swagger-ui-yaml"), Rule("/openapi-swagger-ui.json", endpoint="swagger-ui-json"), Rule("/openapi-doc.yaml", endpoint="doc-yaml"), Rule("/openapi-doc.json", endpoint="doc-json"), *rules, ], ) ]) self.wsgi_app = with_context_middleware( OverrideRequestMethod(self._wsgi_app))
def __init__(self, debug: bool = False): self.debug = debug # TODO: Add resources for swagger-ui and json/yaml endpoints. # TODO: Add redoc.js endpoint. rules = [] for endpoint in ENDPOINT_REGISTRY: if self.debug: # This helps us to make sure we can always generate a valid OpenAPI yaml file. _ = endpoint.to_operation_dict() rules.append( Rule(endpoint.default_path, methods=[endpoint.method], endpoint=Authenticate(endpoint.wrapped))) spec_file_buffer = spec_file() swagger_ui = ServeSwaggerUI(prefix="^/[^/]+/check_mk/api/[^/]+/ui") self.url_map = Map([ Submount( "/<path:_path>", [ Rule("/ui/", endpoint=swagger_ui), Rule("/ui/<path:path>", endpoint=swagger_ui), # Rule("/doc/<path:file>", endpoint=serve_content()), Rule( "/openapi.yaml", endpoint=serve_content( file_handle=spec_file_buffer, content_type='application/x-yaml; charset=utf-8', ), ), Rule( "/openapi.json", endpoint=serve_content( file_handle=json_file(spec_file_buffer), content_type='application/json', ), ), *rules, ], ), ]) self.wsgi_app = with_context_middleware( OverrideRequestMethod(self._wsgi_app))
def test_werkzeug_routing(app, client): from werkzeug.routing import Submount, Rule app.url_map.add( Submount('/foo', [Rule('/bar', endpoint='bar'), Rule('/', endpoint='index')])) def bar(): return 'bar' def index(): return 'index' app.view_functions['bar'] = bar app.view_functions['index'] = index assert client.get('/foo/').data == b'index' assert client.get('/foo/bar').data == b'bar'
def get_submount(self) -> Submount: """ Gets the :class:`werkzeug.routing.Submount` for this Blueprint. .. versionadded:: 2.2.0 """ inner = [] # get child submounts for bp in self._children: inner.append(bp.get_submount()) for route in self.routes: inner.extend(route.get_rules()) # create the submount sm = Submount(self._prefix, rules=inner) return sm
def test_endpoint_decorator(): from werkzeug.routing import Submount, Rule app = flask.Flask(__name__) app.url_map.add( Submount('/foo', [Rule('/bar', endpoint='bar'), Rule('/', endpoint='index')])) @app.endpoint('bar') def bar(): return 'bar' @app.endpoint('index') def index(): return 'index' c = app.test_client() assert c.get('/foo/').data == b'index' assert c.get('/foo/bar').data == b'bar'
def subroute(self, prefix): """ Within this block, C{@route} adds rules to a C{werkzeug.routing.Submount}. This is implemented by tinkering with the instance's C{_url_map} variable. A context manager allows us to gracefully use the pattern of "change a variable, do some things with the new value, then put it back to how it was before. Named "subroute" to try and give callers a better idea of its relationship to C{@route}. Usage: :: with app.subroute("/prefix") as app: @app.route("/foo") def foo_handler(request): return 'I respond to /prefix/foo' @type prefix: string @param prefix: The string that will be prepended to the paths of all routes established during the with-block. @return: Returns None. """ _map_before_submount = self._url_map segments = self._segments_in_url(prefix) submount_map = namedtuple( 'submount', ['rules', 'add'])( [], lambda r: submount_map.rules.append(r)) try: self._url_map = submount_map self._subroute_segments += segments yield self _map_before_submount.add( Submount(prefix, submount_map.rules)) finally: self._url_map = _map_before_submount self._subroute_segments -= segments
def _init_coll_routes(self, coll_prefix): """Initialize and register the routes for specified collection path :param str coll_prefix: The collection path :rtype: None """ routes = self._make_coll_routes(coll_prefix) # init loc routes, if any loc_keys = list(self.rewriterapp.loc_map.keys()) if loc_keys: routes.append(Rule('/', endpoint=self.serve_home)) submount_route = ', '.join(loc_keys) submount_route = '/<any({0}):lang>'.format(submount_route) self.url_map.add(Submount(submount_route, routes)) for route in routes: self.url_map.add(route)
def __init__(self, conf, logger=None): self.conf = conf self.logger = logger or get_logger(self.conf) self.backend = XcuteBackend(self.conf, logger=self.logger) url_map = Map([ Rule('/status', endpoint='status'), Submount('/v1.0/xcute', [ Rule('/job/list', endpoint='job_list', methods=['GET']), Rule('/job/create', endpoint='job_create', methods=['POST']), Rule('/job/show', endpoint='job_show', methods=['GET']), Rule('/job/pause', endpoint='job_pause', methods=['POST']), Rule('/job/resume', endpoint='job_resume', methods=['POST']), Rule('/job/delete', endpoint='job_delete', methods=['DELETE']), Rule('/lock/list', endpoint='lock_list', methods=['GET']), Rule('/lock/show', endpoint='lock_show', methods=['GET']), ]) ]) super(XcuteServer, self).__init__(url_map, logger)
def __init__(self, debug: bool = False): self.debug = debug rules = [] for endpoint in ENDPOINT_REGISTRY: if self.debug: # This helps us to make sure we can always generate a valid OpenAPI yaml file. _ = endpoint.to_operation_dict() rules.append( Rule( endpoint.default_path, methods=[endpoint.method], endpoint=Authenticate(endpoint.wrapped), ) ) swagger_ui = ServeSwaggerUI(prefix="/[^/]+/check_mk/api/[^/]+/ui") self.url_map = Map( [ Submount( "/<path:_path>", [ Rule("/ui/", endpoint=swagger_ui), Rule("/ui/<path:path>", endpoint=swagger_ui), Rule( "/openapi-swagger-ui.yaml", endpoint=swagger_ui.serve_spec("swagger-ui", "yaml"), ), Rule( "/openapi-swagger-ui.json", endpoint=swagger_ui.serve_spec("swagger-ui", "json"), ), Rule("/openapi-doc.yaml", endpoint=swagger_ui.serve_spec("doc", "yaml")), Rule("/openapi-doc.json", endpoint=swagger_ui.serve_spec("doc", "json")), *rules, ], ), ] ) self.wsgi_app = with_context_middleware(OverrideRequestMethod(self._wsgi_app))
def test_endpoint_decorator(self): from werkzeug.routing import Submount, Rule from flask import Module app = flask.Flask(__name__) app.url_map.add(Submount('/foo', [ Rule('/bar', endpoint='bar'), Rule('/', endpoint='index') ])) module = Module(__name__, __name__) @module.endpoint('bar') def bar(): return 'bar' @module.endpoint('index') def index(): return 'index' app.register_module(module) c = app.test_client() assert c.get('/foo/').data == 'index' assert c.get('/foo/bar').data == 'bar'
def get_rules(self): return Submount(self.url_prefix, self._endpoint_handlers)
# Copyright 2013 Donald Stufft # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import absolute_import, division, print_function from __future__ import unicode_literals from werkzeug.routing import Rule, EndpointPrefix, Submount urls = [ EndpointPrefix("warehouse.legacy.simple.", [ Submount("/simple", [ Rule("/", methods=["GET"], endpoint="index"), Rule("/<project_name>/", methods=["GET"], endpoint="project"), ]), Rule("/packages/<path:path>", methods=["GET"], endpoint="package"), ]), EndpointPrefix("warehouse.legacy.pypi.", [ Rule("/pypi", methods=["GET", "POST"], endpoint="pypi"), ]), ]
api_url_rules = [ Rule('/_health', endpoint=acoustid.api.HealthHandler), Rule('/_health_ro', endpoint=acoustid.api.ReadOnlyHealthHandler), Rule('/_health_docker', endpoint=acoustid.api.ReadOnlyHealthHandler), Rule('/lookup', endpoint=acoustid.api.v1.LookupHandler), Rule('/submit', endpoint=acoustid.api.v1.SubmitHandler), Submount('/v2', [ Rule('/lookup', endpoint=acoustid.api.v2.LookupHandler), Rule('/submit', endpoint=acoustid.api.v2.SubmitHandler), Rule('/submission_status', endpoint=acoustid.api.v2.SubmissionStatusHandler), Rule('/fingerprint', endpoint=acoustid.api.v2.misc.GetFingerprintHandler), Rule('/track/list_by_mbid', endpoint=acoustid.api.v2.misc.TrackListByMBIDHandler), Rule('/track/list_by_puid', endpoint=acoustid.api.v2.misc.TrackListByPUIDHandler), Rule('/user/lookup', endpoint=acoustid.api.v2.misc.UserLookupHandler), Rule('/user/create_anonymous', endpoint=acoustid.api.v2.misc.UserCreateAnonymousHandler), Rule('/user/create_musicbrainz', endpoint=acoustid.api.v2.misc.UserCreateMusicBrainzHandler), Submount('/internal', [ Rule('/update_lookup_stats', endpoint=acoustid.api.v2.internal.UpdateLookupStatsHandler), Rule('/update_user_agent_stats', endpoint=acoustid.api.v2.internal.UpdateUserAgentStatsHandler), Rule('/lookup_stats', endpoint=acoustid.api.v2.internal.LookupStatsHandler), Rule('/create_account', endpoint=acoustid.api.v2.internal.CreateAccountHandler), Rule('/create_application', endpoint=acoustid.api.v2.internal.CreateApplicationHandler), Rule('/update_application_status', endpoint=acoustid.api.v2.internal.UpdateApplicationStatusHandler), ]), ]), ] # type: List[RuleFactory] admin_url_rules = [ Submount('/admin', [ ]) ] # type: List[RuleFactory]
def ep_path_search(request, path): logger.debug("conan_client_remote_s3 path search %s", request.args, path) fail_on_remaining(request.args) return json_response({}) URL_MAP = Map([ Submount( "/v1", [ Rule("/ping", endpoint=ep_ping), Rule("/users/check_credentials", endpoint=ep_users_check_credentials), Submount( "/conans", [ Rule("/search", endpoint=ep_search), Rule("/<path:path>/search", endpoint=ep_path_search), Rule("/<path:path>/digest", endpoint=ep_digest), Rule("/<path:path>/download_urls", endpoint=ep_download_urls), Rule("/<path:path>/upload_urls", endpoint=ep_upload_urls, methods=["POST"]), Rule("/<path:path>", endpoint=ep_snapshot), ], ) ], ), ]) @responder def application(environ, start_response): logger.debug("\nconan_client_remote_s3.application %s", environ) # traceback.print_stack()
url_map = Map([ # language dependent Submount('/<string(length=2):lang_code>', [ Rule('/', defaults={'order_by': 'newest'}) > 'kb.overview', Rule('/<any(hot, votes, activity):order_by>') > 'kb.overview', Rule('/<any(newest, hot, votes, activity):order_by>.atom') > 'kb.overview_feed', Rule('/unanswered/', defaults={'order_by': 'newest' }) > 'kb.unanswered', Rule('/unanswered/<any(hot, votes, activity):order_by>') > 'kb.unanswered', Rule('/unanswered/<any(newest, hot, votes, activity):order_by>.atom') > 'kb.unanswered_feed', Rule('/new') > 'kb.new', Rule('/topic/<int:id>-<slug>') > 'kb.topic', Rule('/topic/<int:id>') > 'kb.topic', Rule('/topic/<int:id>.atom') > 'kb.topic_feed', Rule('/topic/<int:id>-<slug>.atom') > 'kb.topic_feed', Rule('/tags/') > 'kb.tags', Rule('/tags/<name>/', defaults={'order_by': 'newest'}) > 'kb.by_tag', Rule('/tags/<name>/<any(hot, votes, activity):order_by>') > 'kb.by_tag', Rule('/tags/<name>/<any(newest, hot, votes, activity):order_by>.atom') > 'kb.by_tag_feed', Rule('/post/<int:id>/edit') > 'kb.edit_post', Rule('/post/<int:id>/delete') > 'kb.delete_post', Rule('/post/<int:id>/restore') > 'kb.restore_post', Rule('/post/<int:id>/revisions') > 'kb.post_revisions', Rule('/users/') > 'kb.userlist' ]), # kb sections not depending on the lang code
from werkzeug.routing import Map, Rule, Subdomain, Submount, EndpointPrefix m = Map([ # Static URLs EndpointPrefix('static/', [ Rule('/', endpoint='index'), Rule('/about', endpoint='about'), Rule('/help', endpoint='help'), ]), # Knowledge Base Subdomain('kb', [EndpointPrefix('kb/', [ Rule('/', endpoint='index'), Submount('/browse', [ Rule('/', endpoint='browse'), Rule('/<int:id>/', defaults={'page': 1}, endpoint='browse'), Rule('/<int:id>/<int:page>', endpoint='browse') ]) ])]) ])