From d51de88096b9a7632cffaac85b552b63fa72dd10 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Wed, 24 Jun 2020 22:10:09 -0700 Subject: [PATCH] fixed whitespaces --- gluon/rewrite.py | 984 ++++++++++++++++++++++++++++------------------- 1 file changed, 596 insertions(+), 388 deletions(-) diff --git a/gluon/rewrite.py b/gluon/rewrite.py index debb6e67..60bd5313 100644 --- a/gluon/rewrite.py +++ b/gluon/rewrite.py @@ -1,4 +1,3 @@ - # -*- coding: utf-8 -*- """ @@ -25,20 +24,26 @@ from gluon.storage import Storage, List from gluon.http import HTTP from gluon.fileutils import abspath, read_file from gluon.settings import global_settings -from gluon._compat import urllib_unquote, urllib_quote, iteritems, xrange, urllib_quote_plus +from gluon._compat import ( + urllib_unquote, + urllib_quote, + iteritems, + xrange, + urllib_quote_plus, +) isdir = os.path.isdir isfile = os.path.isfile exists = os.path.exists pjoin = os.path.join -logger = logging.getLogger('web2py.rewrite') +logger = logging.getLogger("web2py.rewrite") THREAD_LOCAL = threading.local() # thread-local storage for routing params -REGEX_AT = re.compile(r'(?(.*)') -REGEX_VERSION = re.compile(r'^(_[\d]+\.[\d]+\.[\d]+)$') +REGEX_AT = re.compile(r"(?(.*)") +REGEX_VERSION = re.compile(r"^(_[\d]+\.[\d]+\.[\d]+)$") # pattern to find valid paths in url /application/controller/... # this could be: @@ -50,34 +55,36 @@ REGEX_VERSION = re.compile(r'^(_[\d]+\.[\d]+\.[\d]+)$') # file and args may also contain '-', '=', '.' and '/' # apps in routes_apps_raw must parse raw_args into args -REGEX_URL = re.compile(r'^/((?P\w+)(/(?P\w+)(/(?P(?P\w+)(\.(?P[\w.]+))?(?P.*)))?)?)?$') -REGEX_ARGS = re.compile(r'[^\w/.@=-]') +REGEX_URL = re.compile( + r"^/((?P\w+)(/(?P\w+)(/(?P(?P\w+)(\.(?P[\w.]+))?(?P.*)))?)?)?$" +) +REGEX_ARGS = re.compile(r"[^\w/.@=-]") def _router_default(): """Returns new copy of default base router""" router = Storage( - default_application='init', - applications='ALL', - default_controller='default', - controllers='DEFAULT', - default_function='index', + default_application="init", + applications="ALL", + default_controller="default", + controllers="DEFAULT", + default_function="index", functions=dict(), default_language=None, languages=None, - root_static=['favicon.ico', 'robots.txt'], + root_static=["favicon.ico", "robots.txt"], map_static=None, domains=None, exclusive_domain=False, map_hyphen=False, - acfe_match=r'\w+$', # legal app/ctlr/fcn/ext + acfe_match=r"\w+$", # legal app/ctlr/fcn/ext # # Implementation note: # The file_match & args_match patterns use look-behind to avoid # pathological backtracking from nested patterns. # - file_match=r'([+=@$%\w-]|(?<=[+=@$%\w-])[./])*$', # legal static subpath - args_match=r'([\w@ =-]|(?<=[\w@ -])\.)*$', + file_match=r"([+=@$%\w-]|(?<=[+=@$%\w-])[./])*$", # legal static subpath + args_match=r"([\w@ =-]|(?<=[\w@ -])\.)*$", ) return router @@ -95,13 +102,17 @@ def _params_default(app=None): p.routes_onerror = [] p.routes_apps_raw = [] p.error_handler = None - p.error_message = '

%s

' - p.error_message_ticket = \ - '

Internal error

Ticket issued:
%(ticket)s' + p.error_message = "

%s

" + p.error_message_ticket = ( + '

Internal error

Ticket issued: %(ticket)s" + ) p.routers = None - p.logging = 'off' + p.logging = "off" return p + params_apps = dict() params = _params_default(app=None) # regex rewrite parameters THREAD_LOCAL.routes = params # default to base regex rewrite parameters @@ -110,35 +121,50 @@ routers = None def log_rewrite(string): """Log rewrite activity under control of routes.py""" - if params.logging == 'debug': # catch common cases first + if params.logging == "debug": # catch common cases first logger.debug(string) - elif params.logging == 'off' or not params.logging: + elif params.logging == "off" or not params.logging: pass - elif params.logging == 'print': + elif params.logging == "print": print(string) - elif params.logging == 'info': + elif params.logging == "info": logger.info(string) - elif params.logging == 'warning': + elif params.logging == "warning": logger.warning(string) - elif params.logging == 'error': + elif params.logging == "error": logger.error(string) - elif params.logging == 'critical': + elif params.logging == "critical": logger.critical(string) else: logger.debug(string) + ROUTER_KEYS = set( - ('default_application', 'applications', - 'default_controller', 'controllers', - 'default_function', 'functions', - 'default_language', 'languages', - 'domain', 'domains', 'root_static', 'path_prefix', - 'exclusive_domain', 'map_hyphen', 'map_static', - 'acfe_match', 'file_match', 'args_match')) + ( + "default_application", + "applications", + "default_controller", + "controllers", + "default_function", + "functions", + "default_language", + "languages", + "domain", + "domains", + "root_static", + "path_prefix", + "exclusive_domain", + "map_hyphen", + "map_static", + "acfe_match", + "file_match", + "args_match", + ) +) ROUTER_BASE_KEYS = set( - ('applications', 'default_application', - 'domains', 'path_prefix')) + ("applications", "default_application", "domains", "path_prefix") +) # The external interface to rewrite consists of: # @@ -159,23 +185,22 @@ ROUTER_BASE_KEYS = set( def fixup_missing_path_info(environ): eget = environ.get - path_info = eget('PATH_INFO') - request_uri = eget('REQUEST_URI') + path_info = eget("PATH_INFO") + request_uri = eget("REQUEST_URI") if not path_info and request_uri: # for fcgi, get path_info and # query_string from request_uri - items = request_uri.split('?') - path_info = environ['PATH_INFO'] = items[0] - environ['QUERY_STRING'] = items[1] if len(items) > 1 else '' + items = request_uri.split("?") + path_info = environ["PATH_INFO"] = items[0] + environ["QUERY_STRING"] = items[1] if len(items) > 1 else "" elif not request_uri: - query_string = eget('QUERY_STRING') + query_string = eget("QUERY_STRING") if query_string: - environ['REQUEST_URI'] = '%s?%s' % (path_info, query_string) + environ["REQUEST_URI"] = "%s?%s" % (path_info, query_string) else: - environ['REQUEST_URI'] = path_info - if not eget('HTTP_HOST'): - environ['HTTP_HOST'] = \ - '%s:%s' % (eget('SERVER_NAME'), eget('SERVER_PORT')) + environ["REQUEST_URI"] = path_info + if not eget("HTTP_HOST"): + environ["HTTP_HOST"] = "%s:%s" % (eget("SERVER_NAME"), eget("SERVER_PORT")) def url_in(request, environ): @@ -185,15 +210,37 @@ def url_in(request, environ): return regex_url_in(request, environ) -def url_out(request, environ, application, controller, function, - args, other, scheme, host, port, language=None): +def url_out( + request, + environ, + application, + controller, + function, + args, + other, + scheme, + host, + port, + language=None, +): """Assembles and rewrites outgoing URL""" if routers: - acf = map_url_out(request, environ, application, controller, - function, args, other, scheme, host, port, language) - url = '%s%s' % (acf, other) + acf = map_url_out( + request, + environ, + application, + controller, + function, + args, + other, + scheme, + host, + port, + language, + ) + url = "%s%s" % (acf, other) else: - url = '/%s/%s/%s%s' % (application, controller, function, other) + url = "/%s/%s/%s%s" % (application, controller, function, other) url = regex_filter_out(url, environ) # # fill in scheme and host if absolute URL is requested @@ -202,10 +249,12 @@ def url_out(request, environ, application, controller, function, if host is True or (host is None and (scheme or port is not None)): host = request.env.http_host if not scheme or scheme is True: - scheme = request.env.get('wsgi_url_scheme', 'http').lower() if request else 'http' + scheme = ( + request.env.get("wsgi_url_scheme", "http").lower() if request else "http" + ) if host: - host_port = host if not port else host.split(':', 1)[0] + ':%s' % port - url = '%s://%s%s' % (scheme, host_port, url) + host_port = host if not port else host.split(":", 1)[0] + ":%s" % port + url = "%s://%s%s" % (scheme, host_port, url) return url @@ -215,37 +264,43 @@ def try_rewrite_on_error(http_response, request, environ, ticket=None): """ status = int(str(http_response.status).split()[0]) if status >= 399 and THREAD_LOCAL.routes.routes_onerror: - keys = set(('%s/%s' % (request.application, status), - '%s/*' % (request.application), - '*/%s' % (status), - '*/*')) + keys = set( + ( + "%s/%s" % (request.application, status), + "%s/*" % (request.application), + "*/%s" % (status), + "*/*", + ) + ) for (key, uri) in THREAD_LOCAL.routes.routes_onerror: if key in keys: - if uri == '!': + if uri == "!": # do nothing! return http_response, environ - elif '?' in uri: - path_info, query_string = uri.split('?', 1) - query_string += '&' + elif "?" in uri: + path_info, query_string = uri.split("?", 1) + query_string += "&" else: - path_info, query_string = uri, '' - query_string += \ - 'code=%s&ticket=%s&requested_uri=%s&request_url=%s' % \ - (status, ticket, urllib_quote_plus( - request.env.request_uri), request.url) - if uri.startswith('http://') or uri.startswith('https://'): + path_info, query_string = uri, "" + query_string += "code=%s&ticket=%s&requested_uri=%s&request_url=%s" % ( + status, + ticket, + urllib_quote_plus(request.env.request_uri), + request.url, + ) + if uri.startswith("http://") or uri.startswith("https://"): # make up a response - url = '%s?%s' % (path_info, query_string) + url = "%s?%s" % (path_info, query_string) message = 'You are being redirected here' return HTTP(303, message % url, Location=url), environ - elif not environ.get('__ROUTES_ONERROR__', False): + elif not environ.get("__ROUTES_ONERROR__", False): # wsgibase will be called recursively with # the routes_onerror path. - environ['__ROUTES_ONERROR__'] = True # limit recursion - path_info = '/' + path_info.lstrip('/') - environ['PATH_INFO'] = path_info - environ['QUERY_STRING'] = query_string - environ['WEB2PY_STATUS_CODE'] = status + environ["__ROUTES_ONERROR__"] = True # limit recursion + path_info = "/" + path_info.lstrip("/") + environ["PATH_INFO"] = path_info + environ["QUERY_STRING"] = query_string + environ["WEB2PY_STATUS_CODE"] = status return None, environ # do nothing! return http_response, environ @@ -255,29 +310,43 @@ def try_redirect_on_error(http_object, request, ticket=None): """Called from main.wsgibase to rewrite the http response""" status = int(str(http_object.status).split()[0]) if status > 399 and THREAD_LOCAL.routes.routes_onerror: - keys = set(('%s/%s' % (request.application, status), - '%s/*' % (request.application), - '*/%s' % (status), - '*/*')) + keys = set( + ( + "%s/%s" % (request.application, status), + "%s/*" % (request.application), + "*/%s" % (status), + "*/*", + ) + ) for (key, redir) in THREAD_LOCAL.routes.routes_onerror: if key in keys: - if redir == '!': + if redir == "!": break - elif '?' in redir: - url = '%s&code=%s&ticket=%s&requested_uri=%s&request_url=%s' % \ - (redir, status, ticket, - urllib_quote_plus(request.env.request_uri), - request.url) + elif "?" in redir: + url = "%s&code=%s&ticket=%s&requested_uri=%s&request_url=%s" % ( + redir, + status, + ticket, + urllib_quote_plus(request.env.request_uri), + request.url, + ) else: - url = '%s?code=%s&ticket=%s&requested_uri=%s&request_url=%s' % \ - (redir, status, ticket, - urllib_quote_plus(request.env.request_uri), - request.url) - return HTTP(303, 'You are being redirected here' % url, Location=url) + url = "%s?code=%s&ticket=%s&requested_uri=%s&request_url=%s" % ( + redir, + status, + ticket, + urllib_quote_plus(request.env.request_uri), + request.url, + ) + return HTTP( + 303, + 'You are being redirected here' % url, + Location=url, + ) return http_object -def load(routes='routes.py', app=None, data=None, rdict=None): +def load(routes="routes.py", app=None, data=None, rdict=None): """ load: read (if file) and parse routes store results in params @@ -292,58 +361,66 @@ def load(routes='routes.py', app=None, data=None, rdict=None): global params_apps params_apps = dict() params = _params_default(app=None) # regex rewrite parameters - THREAD_LOCAL.routes = params # default to base regex rewrite parameters + THREAD_LOCAL.routes = params # default to base regex rewrite parameters routers = None if isinstance(rdict, dict): symbols = dict(routers=rdict) - path = 'rdict' + path = "rdict" else: if data is not None: - path = 'routes' + path = "routes" else: if app is None: path = abspath(routes) else: - path = abspath('applications', app, routes) + path = abspath("applications", app, routes) if not exists(path): return - data = read_file(path).replace('\r\n', '\n') + data = read_file(path).replace("\r\n", "\n") symbols = dict(app=app) try: exec(data, symbols) except SyntaxError as e: logger.error( - '%s has a syntax error and will not be loaded\n' % path - + traceback.format_exc()) + "%s has a syntax error and will not be loaded\n" % path + + traceback.format_exc() + ) raise e p = _params_default(app) - for sym in ('routes_app', 'routes_in', 'routes_out'): + for sym in ("routes_app", "routes_in", "routes_out"): if sym in symbols: for items in symbols[sym]: p[sym].append(compile_regex(*items)) - for sym in ('routes_onerror', 'routes_apps_raw', - 'error_handler', 'error_message', 'error_message_ticket', - 'default_application', 'default_controller', 'default_function', - 'logging'): + for sym in ( + "routes_onerror", + "routes_apps_raw", + "error_handler", + "error_message", + "error_message_ticket", + "default_application", + "default_controller", + "default_function", + "logging", + ): if sym in symbols: p[sym] = symbols[sym] - if 'routers' in symbols: - p.routers = Storage(symbols['routers']) + if "routers" in symbols: + p.routers = Storage(symbols["routers"]) for key in p.routers: if isinstance(p.routers[key], dict): p.routers[key] = Storage(p.routers[key]) if app is None: - params = p # install base rewrite parameters - THREAD_LOCAL.routes = params # install default as current routes + params = p # install base rewrite parameters + THREAD_LOCAL.routes = params # install default as current routes # # create the BASE router if routers in use # - routers = params.routers # establish routers if present + routers = params.routers # establish routers if present if isinstance(routers, dict): routers = Storage(routers) if routers is not None: @@ -357,21 +434,25 @@ def load(routes='routes.py', app=None, data=None, rdict=None): # parse the app-specific routes.py if present # all_apps = [] - apppath = abspath('applications') + apppath = abspath("applications") for appname in os.listdir(apppath): - if not appname.startswith('.') and \ - isdir(abspath(apppath, appname)) and \ - isdir(abspath(apppath, appname, 'controllers')): + if ( + not appname.startswith(".") + and isdir(abspath(apppath, appname)) + and isdir(abspath(apppath, appname, "controllers")) + ): all_apps.append(appname) if routers: - router = Storage(routers.BASE) # new copy + router = Storage(routers.BASE) # new copy if appname in routers: for key in routers[appname].keys(): if key in ROUTER_BASE_KEYS: - raise SyntaxError("BASE-only key '%s' in router '%s'" % (key, appname)) + raise SyntaxError( + "BASE-only key '%s' in router '%s'" % (key, appname) + ) router.update(routers[appname]) routers[appname] = router - if exists(abspath('applications', appname, routes)): + if exists(abspath("applications", appname, routes)): load(routes, appname) if routers: @@ -383,7 +464,7 @@ def load(routes='routes.py', app=None, data=None, rdict=None): if app in p.routers: routers[app].update(p.routers[app]) - log_rewrite('URL rewrite is on. configuration in %s' % path) + log_rewrite("URL rewrite is on. configuration in %s" % path) def compile_regex(k, v, env=None): @@ -397,29 +478,31 @@ def compile_regex(k, v, env=None): """ k0 = k # original k for error reporting # bracket regex in ^...$ if not already done - if not k[0] == '^': - k = '^%s' % k - if not k[-1] == '$': - k = '%s$' % k + if not k[0] == "^": + k = "^%s" % k + if not k[-1] == "$": + k = "%s$" % k # if there are no :-separated parts, prepend a catch-all for the IP address - if k.find(':') < 0: + if k.find(":") < 0: # k = '^.*?:%s' % k[1:] - k = '^.*?:https?://[^:/]+:[a-z]+ %s' % k[1:] + k = "^.*?:https?://[^:/]+:[a-z]+ %s" % k[1:] # if there's no ://, provide a catch-all for the protocol, host & method - if k.find('://') < 0: - i = k.find(':/') + if k.find("://") < 0: + i = k.find(":/") if i < 0: - raise SyntaxError("routes pattern syntax error: path needs leading '/' [%s]" % k0) - k = '%s:https?://[^:/]+:[a-z]+ %s' % (k[:i], k[i + 1:]) + raise SyntaxError( + "routes pattern syntax error: path needs leading '/' [%s]" % k0 + ) + k = "%s:https?://[^:/]+:[a-z]+ %s" % (k[:i], k[i + 1 :]) # $anything -> ?P.* for item in REGEX_ANYTHING.findall(k): - k = k.replace(item, '(?P.*)') + k = k.replace(item, "(?P.*)") # $a (etc) -> ?P\w+ for item in REGEX_AT.findall(k): - k = k.replace(item, r'(?P<%s>\w+)' % item[1:]) + k = k.replace(item, r"(?P<%s>\w+)" % item[1:]) # same for replacement pattern, but with \g for item in REGEX_AT.findall(v): - v = v.replace(item, r'\g<%s>' % item[1:]) + v = v.replace(item, r"\g<%s>" % item[1:]) return (re.compile(k, re.DOTALL), v, env or {}) @@ -431,19 +514,19 @@ def load_routers(all_apps): # on behalf of unit tests if app not in all_apps: all_apps.append(app) - router = Storage(routers.BASE) # new copy - if app != 'BASE': + router = Storage(routers.BASE) # new copy + if app != "BASE": keys = set(routers[app]).intersection(ROUTER_BASE_KEYS) if keys: - raise SyntaxError("BASE-only key(s) %s in router '%s'" % ( - tuple(keys), app)) + raise SyntaxError( + "BASE-only key(s) %s in router '%s'" % (tuple(keys), app) + ) router.update(routers[app]) routers[app] = router router = routers[app] keys = set(router).difference(ROUTER_KEYS) if keys: - raise SyntaxError("unknown key(s) %s in router '%s'" % ( - tuple(keys), app)) + raise SyntaxError("unknown key(s) %s in router '%s'" % (tuple(keys), app)) if not router.controllers: router.controllers = set() elif not isinstance(router.controllers, str): @@ -456,31 +539,32 @@ def load_routers(all_apps): if isinstance(router.functions, (set, tuple, list)): functions = set(router.functions) if isinstance(router.default_function, str): - functions.add( - router.default_function) # legacy compatibility + functions.add(router.default_function) # legacy compatibility router.functions = {router.default_controller: functions} for controller in router.functions: - router.functions[controller] = set( - router.functions[controller]) + router.functions[controller] = set(router.functions[controller]) else: router.functions = dict() - if app != 'BASE': + if app != "BASE": for base_only in ROUTER_BASE_KEYS: router.pop(base_only, None) - if 'domain' in router: + if "domain" in router: routers.BASE.domains[router.domain] = app - if isinstance(router.controllers, str) and router.controllers == 'DEFAULT': + if isinstance(router.controllers, str) and router.controllers == "DEFAULT": router.controllers = set() - if isdir(abspath('applications', app)): - cpath = abspath('applications', app, 'controllers') + if isdir(abspath("applications", app)): + cpath = abspath("applications", app, "controllers") for cname in os.listdir(cpath): - if isfile(abspath(cpath, cname)) and cname.endswith('.py'): + if isfile(abspath(cpath, cname)) and cname.endswith(".py"): router.controllers.add(cname[:-3]) if router.controllers: - router.controllers.add('static') + router.controllers.add("static") router.controllers.add(router.default_controller) - if isinstance(routers.BASE.applications, str) and routers.BASE.applications == 'ALL': + if ( + isinstance(routers.BASE.applications, str) + and routers.BASE.applications == "ALL" + ): routers.BASE.applications = list(all_apps) if routers.BASE.applications: routers.BASE.applications = set(routers.BASE.applications) @@ -499,7 +583,7 @@ def load_routers(all_apps): # convert path_prefix to a list of path elements if router.path_prefix: if isinstance(router.path_prefix, str): - router.path_prefix = router.path_prefix.strip('/').split('/') + router.path_prefix = router.path_prefix.strip("/").split("/") # rewrite BASE.domains as tuples # @@ -510,17 +594,17 @@ def load_routers(all_apps): domains = dict() if routers.BASE.domains: for (d, a) in iteritems(routers.BASE.domains): - (domain, app) = (d.strip(':'), a.strip('/')) - if ':' in domain: - (domain, port) = domain.split(':') + (domain, app) = (d.strip(":"), a.strip("/")) + if ":" in domain: + (domain, port) = domain.split(":") else: port = None - if '/' in app: - (app, ctlr) = app.split('/', 1) + if "/" in app: + (app, ctlr) = app.split("/", 1) else: ctlr = None - if ctlr and '/' in ctlr: - (ctlr, fcn) = ctlr.split('/') + if ctlr and "/" in ctlr: + (ctlr, fcn) = ctlr.split("/") else: fcn = None if app not in all_apps and app not in routers: @@ -531,22 +615,25 @@ def load_routers(all_apps): def regex_uri(e, regexes, tag, default=None): """Filters incoming URI against a list of regexes""" - path = e['PATH_INFO'] - host = e.get('HTTP_HOST', e.get('SERVER_NAME', 'localhost')).lower() - i = host.find(':') + path = e["PATH_INFO"] + host = e.get("HTTP_HOST", e.get("SERVER_NAME", "localhost")).lower() + i = host.find(":") if i > 0: host = host[:i] - key = '%s:%s://%s:%s %s' % \ - (e.get('REMOTE_ADDR', 'localhost'), - e.get('wsgi.url_scheme', 'http').lower(), host, - e.get('REQUEST_METHOD', 'get').lower(), path) + key = "%s:%s://%s:%s %s" % ( + e.get("REMOTE_ADDR", "localhost"), + e.get("wsgi.url_scheme", "http").lower(), + host, + e.get("REQUEST_METHOD", "get").lower(), + path, + ) for (regex, value, custom_env) in regexes: if regex.match(key): e.update(custom_env) rewritten = regex.sub(value, key) - log_rewrite('%s: [%s] [%s] -> %s' % (tag, key, value, rewritten)) + log_rewrite("%s: [%s] [%s] -> %s" % (tag, key, value, rewritten)) return rewritten - log_rewrite('%s: [%s] -> %s (not rewritten)' % (tag, key, default)) + log_rewrite("%s: [%s] -> %s (not rewritten)" % (tag, key, default)) return default @@ -571,37 +658,36 @@ def regex_select(env=None, app=None, request=None): def regex_filter_in(e): """Regex rewrite incoming URL""" routes = THREAD_LOCAL.routes - query = e.get('QUERY_STRING', None) - e['WEB2PY_ORIGINAL_URI'] = e['PATH_INFO'] + (query and ('?' + query) or '') + query = e.get("QUERY_STRING", None) + e["WEB2PY_ORIGINAL_URI"] = e["PATH_INFO"] + (query and ("?" + query) or "") if routes.routes_in: - path = regex_uri(e, routes.routes_in, - "routes_in", e['PATH_INFO']) + path = regex_uri(e, routes.routes_in, "routes_in", e["PATH_INFO"]) rmatch = REGEX_REDIRECT.match(path) if rmatch: raise HTTP(int(rmatch.group(1)), location=rmatch.group(2)) - items = path.split('?', 1) - e['PATH_INFO'] = items[0] + items = path.split("?", 1) + e["PATH_INFO"] = items[0] if len(items) > 1: if query: - query = '%s&%s' % (items[1], query) + query = "%s&%s" % (items[1], query) else: query = items[1] - e['QUERY_STRING'] = query + e["QUERY_STRING"] = query if query: - e['REQUEST_URI'] = '%s?%s' % (e['PATH_INFO'], query) + e["REQUEST_URI"] = "%s?%s" % (e["PATH_INFO"], query) else: - e['REQUEST_URI'] = e['PATH_INFO'] + e["REQUEST_URI"] = e["PATH_INFO"] return e def sluggify(key): - return key.lower().replace('.', '_') + return key.lower().replace(".", "_") def invalid_url(routes): - raise HTTP(400, - routes.error_message % 'invalid request', - web2py_error='invalid path') + raise HTTP( + 400, routes.error_message % "invalid request", web2py_error="invalid path" + ) def regex_url_in(request, environ): @@ -617,34 +703,34 @@ def regex_url_in(request, environ): routes = THREAD_LOCAL.routes if routes.routes_in: environ = regex_filter_in(environ) - request.env.update( - (k.lower().replace('.', '_'), v) for k, v in iteritems(environ)) + request.env.update((k.lower().replace(".", "_"), v) for k, v in iteritems(environ)) # ################################################## # serve if a static file # ################################################## - path = urllib_unquote(request.env.path_info) or '/' - path = path.replace('\\', '/') - if path.endswith('/') and len(path) > 1: + path = urllib_unquote(request.env.path_info) or "/" + path = path.replace("\\", "/") + if path.endswith("/") and len(path) > 1: path = path[:-1] match = REGEX_URL.match(path) if not match: invalid_url(routes) - request.raw_args = (match.group('s') or '') - if request.raw_args.startswith('/'): + request.raw_args = match.group("s") or "" + if request.raw_args.startswith("/"): request.raw_args = request.raw_args[1:] - if match.group('c') == 'static': - application = match.group('a') - version, filename = None, match.group('z') + if match.group("c") == "static": + application = match.group("a") + version, filename = None, match.group("z") if not filename: raise HTTP(404) - filename = filename.replace(' ','_') - items = filename.split('/', 1) + filename = filename.replace(" ", "_") + items = filename.split("/", 1) if REGEX_VERSION.match(items[0]): version, filename = items - static_folder = pjoin(global_settings.applications_parent, - 'applications', application, 'static') + static_folder = pjoin( + global_settings.applications_parent, "applications", application, "static" + ) static_file = os.path.abspath(pjoin(static_folder, filename)) if not static_file.startswith(static_folder): invalid_url(routes) @@ -653,17 +739,17 @@ def regex_url_in(request, environ): # ################################################## # parse application, controller and function # ################################################## - request.application = match.group('a') or routes.default_application - request.controller = match.group('c') or routes.default_controller - request.function = match.group('f') or routes.default_function - request.raw_extension = match.group('e') - request.extension = request.raw_extension or 'html' + request.application = match.group("a") or routes.default_application + request.controller = match.group("c") or routes.default_controller + request.function = match.group("f") or routes.default_function + request.raw_extension = match.group("e") + request.extension = request.raw_extension or "html" if request.application in routes.routes_apps_raw: # application is responsible for parsing args request.args = None elif request.raw_args: - args = REGEX_ARGS.sub('_', request.raw_args) - request.args = List(args.split('/')) + args = REGEX_ARGS.sub("_", request.raw_args) + request.args = List(args.split("/")) else: request.args = List([]) return (None, None, environ) @@ -671,64 +757,79 @@ def regex_url_in(request, environ): def regex_filter_out(url, e=None): """Regex rewrite outgoing URL""" - if not hasattr(THREAD_LOCAL, 'routes'): - regex_select() # ensure routes is set (for application threads) + if not hasattr(THREAD_LOCAL, "routes"): + regex_select() # ensure routes is set (for application threads) routes = THREAD_LOCAL.routes if routers: return url # already filtered if routes.routes_out: - items = url.split('?', 1) + items = url.split("?", 1) if e: - host = e.get('http_host', 'localhost').lower() - i = host.find(':') + host = e.get("http_host", "localhost").lower() + i = host.find(":") if i > 0: host = host[:i] - items[0] = '%s:%s://%s:%s %s' % \ - (e.get('remote_addr', ''), - e.get('wsgi_url_scheme', 'http').lower(), host, - e.get('request_method', 'get').lower(), items[0]) + items[0] = "%s:%s://%s:%s %s" % ( + e.get("remote_addr", ""), + e.get("wsgi_url_scheme", "http").lower(), + host, + e.get("request_method", "get").lower(), + items[0], + ) else: - items[0] = ':http://localhost:get %s' % items[0] + items[0] = ":http://localhost:get %s" % items[0] for (regex, value, tmp) in routes.routes_out: if regex.match(items[0]): - rewritten = '?'.join([regex.sub(value, items[0])] + items[1:]) - log_rewrite('routes_out: [%s] -> %s' % (url, rewritten)) + rewritten = "?".join([regex.sub(value, items[0])] + items[1:]) + log_rewrite("routes_out: [%s] -> %s" % (url, rewritten)) return rewritten - log_rewrite('routes_out: [%s] not rewritten' % url) + log_rewrite("routes_out: [%s] not rewritten" % url) return url -def filter_url(url, method='get', remote='0.0.0.0', - out=False, app=False, lang=None, - domain=(None, None), env=False, scheme=None, - host=None, port=None, language=None): +def filter_url( + url, + method="get", + remote="0.0.0.0", + out=False, + app=False, + lang=None, + domain=(None, None), + env=False, + scheme=None, + host=None, + port=None, + language=None, +): """ doctest/unittest interface to regex_filter_in() and regex_filter_out() """ - match = re.match(r'^(?Phttp|https|HTTP|HTTPS)\://(?P[^/]*)(?P.*)', url) - urlscheme = match.group('scheme').lower() - urlhost = match.group('host').lower() - uri = match.group('uri') - k = uri.find('?') + match = re.match( + r"^(?Phttp|https|HTTP|HTTPS)\://(?P[^/]*)(?P.*)", url + ) + urlscheme = match.group("scheme").lower() + urlhost = match.group("host").lower() + uri = match.group("uri") + k = uri.find("?") if k < 0: k = len(uri) if isinstance(domain, str): domain = (domain, None) - (path_info, query_string) = (uri[:k], uri[k + 1:]) - path_info = urllib_unquote(path_info) # simulate server + (path_info, query_string) = (uri[:k], uri[k + 1 :]) + path_info = urllib_unquote(path_info) # simulate server e = { - 'REMOTE_ADDR': remote, - 'REQUEST_METHOD': method, - 'wsgi.url_scheme': urlscheme, - 'HTTP_HOST': urlhost, - 'REQUEST_URI': uri, - 'PATH_INFO': path_info, - 'QUERY_STRING': query_string, - #for filter_out request.env use lowercase - 'remote_addr': remote, - 'request_method': method, - 'wsgi_url_scheme': urlscheme, - 'http_host': urlhost + "REMOTE_ADDR": remote, + "REQUEST_METHOD": method, + "wsgi.url_scheme": urlscheme, + "HTTP_HOST": urlhost, + "REQUEST_URI": uri, + "PATH_INFO": path_info, + "QUERY_STRING": query_string, + # for filter_out request.env use lowercase + "remote_addr": remote, + "request_method": method, + "wsgi_url_scheme": urlscheme, + "http_host": urlhost, } request = Storage() @@ -746,10 +847,9 @@ def filter_url(url, method='get', remote='0.0.0.0', # rewrite outbound URL # if out: - (request.env.domain_application, - request.env.domain_controller) = domain - items = path_info.lstrip('/').split('/') - if items[-1] == '': + (request.env.domain_application, request.env.domain_controller) = domain + items = path_info.lstrip("/").split("/") + if items[-1] == "": items.pop() # adjust trailing empty args assert len(items) >= 3, "at least /a/c/f is required" a = items.pop(0) @@ -758,15 +858,16 @@ def filter_url(url, method='get', remote='0.0.0.0', if not routers: return regex_filter_out(uri, e) acf = map_url_out( - request, None, a, c, f, items, None, scheme, host, port, language=language) + request, None, a, c, f, items, None, scheme, host, port, language=language + ) if items: - url = '%s/%s' % (acf, '/'.join(items)) - if items[-1] == '': - url += '/' + url = "%s/%s" % (acf, "/".join(items)) + if items[-1] == "": + url += "/" else: url = acf if query_string: - url += '?' + query_string + url += "?" + query_string return url # rewrite inbound URL @@ -774,14 +875,13 @@ def filter_url(url, method='get', remote='0.0.0.0', (static, version, e) = url_in(request, e) if static: return static - result = "/%s/%s/%s" % ( - request.application, request.controller, request.function) - if request.extension and request.extension != 'html': + result = "/%s/%s/%s" % (request.application, request.controller, request.function) + if request.extension and request.extension != "html": result += ".%s" % request.extension if request.args: result += " %s" % request.args - if e['QUERY_STRING']: - result += " ?%s" % e['QUERY_STRING'] + if e["QUERY_STRING"]: + result += " ?%s" % e["QUERY_STRING"] if request.uri_language: result += " (%s)" % request.uri_language if env: @@ -789,25 +889,30 @@ def filter_url(url, method='get', remote='0.0.0.0', return result -def filter_err(status, application='app', ticket='tkt'): +def filter_err(status, application="app", ticket="tkt"): """doctest/unittest interface to routes_onerror""" routes = THREAD_LOCAL.routes if status > 399 and routes.routes_onerror: - keys = set(('%s/%s' % (application, status), - '%s/*' % (application), - '*/%s' % (status), - '*/*')) + keys = set( + ( + "%s/%s" % (application, status), + "%s/*" % (application), + "*/%s" % (status), + "*/*", + ) + ) for (key, redir) in routes.routes_onerror: if key in keys: - if redir == '!': + if redir == "!": break - elif '?' in redir: - url = redir + '&' + 'code=%s&ticket=%s' % (status, ticket) + elif "?" in redir: + url = redir + "&" + "code=%s&ticket=%s" % (status, ticket) else: - url = redir + '?' + 'code=%s&ticket=%s' % (status, ticket) + url = redir + "?" + "code=%s&ticket=%s" % (status, ticket) return url # redirection return status # no action + # router support # @@ -825,7 +930,7 @@ class MapUrlIn(object): self.language = None self.controller = None self.function = None - self.extension = 'html' + self.extension = "html" self.controllers = set() self.functions = dict() @@ -834,38 +939,42 @@ class MapUrlIn(object): self.map_hyphen = False self.exclusive_domain = False - path = self.env['PATH_INFO'] - self.query = self.env.get('QUERY_STRING', None) - path = path.lstrip('/') - self.env['PATH_INFO'] = '/' + path + path = self.env["PATH_INFO"] + self.query = self.env.get("QUERY_STRING", None) + path = path.lstrip("/") + self.env["PATH_INFO"] = "/" + path if self.query: - self.env['WEB2PY_ORIGINAL_URI'] = '%s?%s' % ( - self.env['PATH_INFO'], self.query) + self.env["WEB2PY_ORIGINAL_URI"] = "%s?%s" % ( + self.env["PATH_INFO"], + self.query, + ) else: - self.env['WEB2PY_ORIGINAL_URI'] = self.env['PATH_INFO'] + self.env["WEB2PY_ORIGINAL_URI"] = self.env["PATH_INFO"] # to handle empty args, strip exactly one trailing slash, if present # .../arg1// represents one trailing empty arg # - if path.endswith('/'): + if path.endswith("/"): path = path[:-1] - self.args = List(path.split('/') if path else []) + self.args = List(path.split("/") if path else []) # see http://www.python.org/dev/peps/pep-3333/#url-reconstruction for URL composition - self.remote_addr = self.env.get('REMOTE_ADDR', 'localhost') - self.scheme = self.env.get('wsgi.url_scheme', 'http').lower() - self.method = self.env.get('REQUEST_METHOD', 'get').lower() - (self.host, self.port) = (self.env.get('HTTP_HOST'), None) + self.remote_addr = self.env.get("REMOTE_ADDR", "localhost") + self.scheme = self.env.get("wsgi.url_scheme", "http").lower() + self.method = self.env.get("REQUEST_METHOD", "get").lower() + (self.host, self.port) = (self.env.get("HTTP_HOST"), None) if not self.host: (self.host, self.port) = ( - self.env.get('SERVER_NAME'), self.env.get('SERVER_PORT')) + self.env.get("SERVER_NAME"), + self.env.get("SERVER_PORT"), + ) if not self.host: - self.host = 'localhost' - self.port = '80' - if ':' in self.host: - (self.host, self.port) = self.host.rsplit(':', 1) # for ipv6 support + self.host = "localhost" + self.port = "80" + if ":" in self.host: + (self.host, self.port) = self.host.rsplit(":", 1) # for ipv6 support if not self.port: - self.port = '443' if self.scheme == 'https' else '80' + self.port = "443" if self.scheme == "https" else "80" def map_prefix(self): """Strips path prefix, if present in its entirety""" @@ -887,51 +996,69 @@ class MapUrlIn(object): self.domain_function = None self.map_hyphen = base.map_hyphen arg0 = self.harg0 - if not base.exclusive_domain and base.applications and arg0 in base.applications: + if ( + not base.exclusive_domain + and base.applications + and arg0 in base.applications + ): self.application = arg0 elif not base.exclusive_domain and arg0 and not base.applications: self.application = arg0 elif (self.host, self.port) in base.domains: - (self.application, self.domain_controller, - self.domain_function) = base.domains[(self.host, self.port)] - self.env['domain_application'] = self.application - self.env['domain_controller'] = self.domain_controller - self.env['domain_function'] = self.domain_function + ( + self.application, + self.domain_controller, + self.domain_function, + ) = base.domains[(self.host, self.port)] + self.env["domain_application"] = self.application + self.env["domain_controller"] = self.domain_controller + self.env["domain_function"] = self.domain_function elif (self.host, None) in base.domains: - (self.application, self.domain_controller, - self.domain_function) = base.domains[(self.host, None)] - self.env['domain_application'] = self.application - self.env['domain_controller'] = self.domain_controller - self.env['domain_function'] = self.domain_function + ( + self.application, + self.domain_controller, + self.domain_function, + ) = base.domains[(self.host, None)] + self.env["domain_application"] = self.application + self.env["domain_controller"] = self.domain_controller + self.env["domain_function"] = self.domain_function elif base.applications and arg0 in base.applications: self.application = arg0 elif arg0 and not base.applications: self.application = arg0 else: - self.application = base.default_application or '' + self.application = base.default_application or "" self.pop_arg_if(self.application == arg0) if not base._acfe_match.match(self.application): raise HTTP( - 400, THREAD_LOCAL.routes.error_message % 'invalid request', - web2py_error="invalid application: '%s'" % self.application) + 400, + THREAD_LOCAL.routes.error_message % "invalid request", + web2py_error="invalid application: '%s'" % self.application, + ) - if self.application not in routers and \ - (self.application != THREAD_LOCAL.routes.default_application or self.application == 'welcome'): + if self.application not in routers and ( + self.application != THREAD_LOCAL.routes.default_application + or self.application == "welcome" + ): raise HTTP( - 400, THREAD_LOCAL.routes.error_message % 'invalid request', - web2py_error="unknown application: '%s'" % self.application) + 400, + THREAD_LOCAL.routes.error_message % "invalid request", + web2py_error="unknown application: '%s'" % self.application, + ) # set the application router # log_rewrite("select application=%s" % self.application) self.request.application = self.application if self.application not in routers: - self.router = routers.BASE # support gluon.main.wsgibase init->welcome + self.router = routers.BASE # support gluon.main.wsgibase init->welcome else: - self.router = routers[self.application] # application router + self.router = routers[self.application] # application router self.controllers = self.router.controllers - self.default_controller = self.domain_controller or self.router.default_controller + self.default_controller = ( + self.domain_controller or self.router.default_controller + ) self.functions = self.router.functions self.languages = self.router.languages self.default_language = self.router.default_language @@ -951,10 +1078,14 @@ class MapUrlIn(object): """ if len(self.args) == 1 and self.arg0 in self.router.root_static: - self.controller = self.request.controller = 'static' - root_static_file = pjoin(global_settings.applications_parent, - 'applications', self.application, - self.controller, self.arg0) + self.controller = self.request.controller = "static" + root_static_file = pjoin( + global_settings.applications_parent, + "applications", + self.application, + self.controller, + self.arg0, + ) log_rewrite("route: root static=%s" % root_static_file) return root_static_file, None return None, None @@ -975,95 +1106,113 @@ class MapUrlIn(object): """Identifies controller""" # handle controller # - arg0 = self.harg0 # map hyphens + arg0 = self.harg0 # map hyphens if not arg0 or (self.controllers and arg0 not in self.controllers): - self.controller = self.default_controller or '' + self.controller = self.default_controller or "" else: self.controller = arg0 self.pop_arg_if(arg0 == self.controller) log_rewrite("route: controller=%s" % self.controller) if not self.router._acfe_match.match(self.controller): raise HTTP( - 400, THREAD_LOCAL.routes.error_message % 'invalid request', - web2py_error='invalid controller') + 400, + THREAD_LOCAL.routes.error_message % "invalid request", + web2py_error="invalid controller", + ) def map_static(self): """ Handles static files file_match but no hyphen mapping """ - if self.controller != 'static': + if self.controller != "static": return None, None version = REGEX_VERSION.match(self.args(0)) if self.args and version: - file = '/'.join(self.args[1:]) + file = "/".join(self.args[1:]) else: - file = '/'.join(self.args) + file = "/".join(self.args) if len(self.args) == 0: - bad_static = True # require a file name - elif '/' in self.file_match: + bad_static = True # require a file name + elif "/" in self.file_match: # match the path bad_static = not self.router._file_match.match(file) else: # match path elements bad_static = False for name in self.args: - bad_static = bad_static or name in ( - '', '.', '..') or not self.router._file_match.match(name) + bad_static = ( + bad_static + or name in ("", ".", "..") + or not self.router._file_match.match(name) + ) if bad_static: - log_rewrite('bad static path=%s' % file) - raise HTTP(400, - THREAD_LOCAL.routes.error_message % 'invalid request', - web2py_error='invalid static file') + log_rewrite("bad static path=%s" % file) + raise HTTP( + 400, + THREAD_LOCAL.routes.error_message % "invalid request", + web2py_error="invalid static file", + ) # # support language-specific static subdirectories, # eg /appname/en/static/filename => applications/appname/static/en/filename # if language-specific file doesn't exist, try same file in static # if self.language: - static_file = pjoin(global_settings.applications_parent, - 'applications', self.application, - 'static', self.language, file) + static_file = pjoin( + global_settings.applications_parent, + "applications", + self.application, + "static", + self.language, + file, + ) if not self.language or not isfile(static_file): - static_file = pjoin(global_settings.applications_parent, - 'applications', self.application, - 'static', file) + static_file = pjoin( + global_settings.applications_parent, + "applications", + self.application, + "static", + file, + ) self.extension = None log_rewrite("route: static=%s" % static_file) return static_file, version def map_function(self): """Handles function.extension""" - arg0 = self.harg0 # map hyphens + arg0 = self.harg0 # map hyphens functions = self.functions.get(self.controller, set()) if isinstance(self.router.default_function, dict): - default_function = self.router.default_function.get( - self.controller, None) + default_function = self.router.default_function.get(self.controller, None) else: default_function = self.router.default_function # str or None default_function = self.domain_function or default_function - if not arg0 or functions and arg0.split('.')[0] not in functions: + if not arg0 or functions and arg0.split(".")[0] not in functions: self.function = default_function or "" self.pop_arg_if(arg0 and self.function == arg0) else: - func_ext = arg0.split('.') + func_ext = arg0.split(".") if len(func_ext) > 1: self.function = func_ext[0] self.extension = func_ext[-1] else: self.function = arg0 self.pop_arg_if(True) - log_rewrite( - "route: function.ext=%s.%s" % (self.function, self.extension)) + log_rewrite("route: function.ext=%s.%s" % (self.function, self.extension)) if not self.router._acfe_match.match(self.function): raise HTTP( - 400, THREAD_LOCAL.routes.error_message % 'invalid request', - web2py_error='invalid function') + 400, + THREAD_LOCAL.routes.error_message % "invalid request", + web2py_error="invalid function", + ) if self.extension and not self.router._acfe_match.match(self.extension): raise HTTP( - 400, THREAD_LOCAL.routes.error_message % 'invalid request', - web2py_error='invalid extension') + 400, + THREAD_LOCAL.routes.error_message % "invalid request", + web2py_error="invalid extension", + ) def validate_args(self): """ @@ -1072,12 +1221,15 @@ class MapUrlIn(object): for arg in self.args: if not self.router._args_match.match(arg): raise HTTP( - 400, THREAD_LOCAL.routes.error_message % 'invalid request', - web2py_error='invalid arg <%s>' % arg) + 400, + THREAD_LOCAL.routes.error_message % "invalid request", + web2py_error="invalid arg <%s>" % arg, + ) def sluggify(self): self.request.env.update( - (k.lower().replace('.', '_'), v) for k, v in iteritems(self.env)) + (k.lower().replace(".", "_"), v) for k, v in iteritems(self.env) + ) def update_request(self): """ @@ -1092,22 +1244,24 @@ class MapUrlIn(object): self.request.args = self.args if self.language: self.request.uri_language = self.language - uri = '/%s/%s' % (self.controller, self.function) + uri = "/%s/%s" % (self.controller, self.function) app = self.application if self.map_hyphen: - uri = uri.replace('_', '-') - app = app.replace('_', '-') - if self.extension and self.extension != 'html': - uri += '.' + self.extension + uri = uri.replace("_", "-") + app = app.replace("_", "-") + if self.extension and self.extension != "html": + uri += "." + self.extension if self.language: - uri = '/%s%s' % (self.language, uri) - uri = '/%s%s%s%s' % ( + uri = "/%s%s" % (self.language, uri) + uri = "/%s%s%s%s" % ( app, uri, - urllib_quote('/' + '/'.join( - str(x) for x in self.args)) if self.args else '', - ('?' + self.query) if self.query else '') - self.env['REQUEST_URI'] = uri + urllib_quote("/" + "/".join(str(x) for x in self.args)) + if self.args + else "", + ("?" + self.query) if self.query else "", + ) + self.env["REQUEST_URI"] = uri self.sluggify() @property @@ -1119,7 +1273,7 @@ class MapUrlIn(object): def harg0(self): """Returns first arg with optional hyphen mapping""" if self.map_hyphen and self.args(0): - return self.args(0).replace('-', '_') + return self.args(0).replace("-", "_") return self.args(0) def pop_arg_if(self, dopop): @@ -1131,8 +1285,20 @@ class MapUrlIn(object): class MapUrlOut(object): """Logic for mapping outgoing URLs""" - def __init__(self, request, env, application, controller, - function, args, other, scheme, host, port, language): + def __init__( + self, + request, + env, + application, + controller, + function, + args, + other, + scheme, + host, + port, + language, + ): """initialize a map-out object""" self.default_application = routers.BASE.default_application if application in routers: @@ -1143,8 +1309,7 @@ class MapUrlOut(object): self.env = env self.application = application self.controller = controller - self.is_static = ( - controller == 'static' or controller.startswith('static/')) + self.is_static = controller == "static" or controller.startswith("static/") self.function = function self.args = args self.other = other @@ -1167,15 +1332,18 @@ class MapUrlOut(object): self.domain_controller = request and self.request.env.domain_controller if isinstance(self.router.default_function, dict): self.default_function = self.router.default_function.get( - self.controller, None) + self.controller, None + ) else: self.default_function = self.router.default_function - if (self.router.exclusive_domain + if ( + self.router.exclusive_domain and self.domain_application and self.domain_application != self.application - and not self.host): - raise SyntaxError('cross-domain conflict: must specify host') + and not self.host + ): + raise SyntaxError("cross-domain conflict: must specify host") lang = self.language if self.language else request and request.uri_language if lang and self.languages and lang in self.languages: @@ -1215,13 +1383,21 @@ class MapUrlOut(object): # omit controller if default controller # - default_controller = ((self.application == self.domain_application) and self.domain_controller) or router.default_controller or '' + default_controller = ( + ((self.application == self.domain_application) and self.domain_controller) + or router.default_controller + or "" + ) if self.controller == default_controller: self.omit_controller = True # omit function if possible # - if self.functions and self.function in self.functions and self.function == self.default_function: + if ( + self.functions + and self.function in self.functions + and self.function == self.default_function + ): self.omit_function = True # prohibit ambiguous cases @@ -1241,7 +1417,11 @@ class MapUrlOut(object): if not self.controllers or self.function in self.controllers: self.omit_controller = False if self.args: - if self.args[0] in self.functions or self.args[0] in self.controllers or self.args[0] in applications: + if ( + self.args[0] in self.functions + or self.args[0] in self.controllers + or self.args[0] in applications + ): self.omit_function = False if self.omit_controller: if self.function in self.controllers or self.function in applications: @@ -1263,36 +1443,38 @@ class MapUrlOut(object): def build_acf(self): "Builds a/c/f from components" - acf = '' + acf = "" if self.map_hyphen: - self.controller = self.controller.replace('_', '-') - if self.controller != 'static' and not self.controller.startswith('static/'): - self.application = self.application.replace('_', '-') - self.function = self.function.replace('_', '-') + self.controller = self.controller.replace("_", "-") + if self.controller != "static" and not self.controller.startswith( + "static/" + ): + self.application = self.application.replace("_", "-") + self.function = self.function.replace("_", "-") if not self.omit_application: - acf += '/' + self.application + acf += "/" + self.application # handle case of flipping lang/static/file to static/lang/file for external rewrite if self.is_static and self.map_static is False and not self.omit_language: - acf += '/' + self.controller + '/' + self.language + acf += "/" + self.controller + "/" + self.language else: if not self.omit_language: - acf += '/' + self.language + acf += "/" + self.language if not self.omit_controller: - acf += '/' + self.controller + acf += "/" + self.controller if not self.omit_function: - acf += '/' + self.function + acf += "/" + self.function if self.path_prefix: - acf = '/' + '/'.join(self.path_prefix) + acf + acf = "/" + "/".join(self.path_prefix) + acf if self.args: return acf - return acf or '/' + return acf or "/" def acf(self): """Converts components to /app/lang/controller/function""" if not routers: - return None # use regex filter - self.omit_lang() # try to omit language - self.omit_acf() # try to omit a/c/f + return None # use regex filter + self.omit_lang() # try to omit language + self.omit_acf() # try to omit a/c/f return self.build_acf() # build and return the /a/lang/c/f string @@ -1304,7 +1486,7 @@ def map_url_in(request, env, app=False): map = MapUrlIn(request=request, env=env) map.sluggify() map.map_prefix() # strip prefix if present - map.map_app() # determine application + map.map_app() # determine application # configure THREAD_LOCAL.routes for error rewrite # @@ -1314,14 +1496,18 @@ def map_url_in(request, env, app=False): if app: return map.application - root_static_file, version = map.map_root_static( - ) # handle root-static files + root_static_file, version = map.map_root_static() # handle root-static files if root_static_file: map.update_request() return (root_static_file, version, map.env) # handle mapping of lang/static to static/lang in externally-rewritten URLs # in case we have to handle them ourselves - if map.languages and map.map_static is False and map.arg0 == 'static' and map.args(1) in map.languages: + if ( + map.languages + and map.map_static is False + and map.arg0 == "static" + and map.args(1) in map.languages + ): map.map_controller() map.map_language() else: @@ -1337,8 +1523,19 @@ def map_url_in(request, env, app=False): return (None, None, map.env) -def map_url_out(request, env, application, controller, - function, args, other, scheme, host, port, language=None): +def map_url_out( + request, + env, + application, + controller, + function, + args, + other, + scheme, + host, + port, + language=None, +): """ Supply /a/c/f (or /a/lang/c/f) portion of outgoing url @@ -1364,8 +1561,19 @@ def map_url_out(request, env, application, controller, We assume that language names do not collide with a/c/f names. """ - map = MapUrlOut(request, env, application, controller, - function, args, other, scheme, host, port, language) + map = MapUrlOut( + request, + env, + application, + controller, + function, + args, + other, + scheme, + host, + port, + language, + ) return map.acf()