def get_module_routes(module_name, custom_routes=None, exclusions=None,
                      arg_pattern=r'(?P<{}>[a-zA-Z0-9_\-]+)'):
    def has_method(module, cls_name, method_name):
        return all([
            method_name in vars(getattr(module, cls_name)),
            is_method(reduce(getattr, [module, cls_name, method_name]))
        ])

    def yield_args(module, cls_name, method_name):
        """Get signature of ``module.cls_name.method_name``

        Confession: This function doesn't actually ``yield`` the arguments,
            just returns a list. Trust me, it's better that way.

        :returns: List of arg names from method_name except ``self``
        :rtype: list
        """
        wrapped_method = reduce(getattr, [module, cls_name, method_name])
        method = extract_method(wrapped_method)

        # If using tornado_json.gen.coroutine, original args are annotated...
        argspec_args = getattr(method, "__argspec_args",
                               # otherwise just grab them from the method
                               inspect.getargspec(method).args)

        return [a for a in argspec_args if a not in ["self"]]

    def generate_auto_route(module, module_name, cls_name, method_name, url_name):
        """Generate URL for auto_route

        :rtype: str
        :returns: Constructed URL based on given arguments
        """
        def get_handler_name():
            """Get handler identifier for URL

            For the special case where ``url_name`` is
            ``__self__``, the handler is named a lowercase
            value of its own name with 'handler' removed
            from the ending if give; otherwise, we
            simply use the provided ``url_name``
            """
            if url_name == "__self__":
                if cls_name.lower().endswith('handler'):
                    return cls_name.lower().replace('handler', '', 1)
                return cls_name.lower()
            else:
                return url_name

        def get_arg_route():
            """Get remainder of URL determined by method argspec

            :returns: Remainder of URL which matches `\w+` regex
                with groups named by the method's argument spec.
                If there are no arguments given, returns ``""``.
            :rtype: str
            """
            if yield_args(module, cls_name, method_name):
                return "/{}/?$".format("/".join(
                    [arg_pattern.format(argname) for argname
                     in yield_args(module, cls_name, method_name)]
                ))
            return r"/?"

        return "/{}/{}{}".format(
            "/".join(module_name.split(".")[1:]),
            get_handler_name(),
            get_arg_route()
        )

    if not custom_routes:
        custom_routes = []
    if not exclusions:
        exclusions = []

    # Import module so we can get its request handlers
    module = importlib.import_module(module_name)

    # Generate list of RequestHandler names in custom_routes
    custom_routes_s = [c.__name__ for r, c in custom_routes]

    # rhs is a dict of {classname: pyclbr.Class} key, value pairs
    rhs = pyclbr.readmodule(module_name)

    # You better believe this is a list comprehension
    auto_routes = list(chain(*[
        list(set(chain(*[
            # Generate a route for each "name" specified in the
            #   __url_names__ attribute of the handler
            [
                # URL, requesthandler tuple
                (
                    generate_auto_route(
                        module, module_name, cls_name, method_name, url_name
                    ),
                    getattr(module, cls_name)
                ) for url_name in getattr(module, cls_name).__url_names__
                # Add routes for each custom URL specified in the
                #   __urls__ attribute of the handler
            ] + [
                (
                    url,
                    getattr(module, cls_name)
                ) for url in getattr(module, cls_name).__urls__
            ]
            # We create a route for each HTTP method in the handler
            #   so that we catch all possible routes if different
            #   HTTP methods have different argspecs and are expecting
            #   to catch different routes. Any duplicate routes
            #   are removed from the set() comparison.
            for method_name in HTTP_METHODS if has_method(
                module, cls_name, method_name)
        ])))
        # foreach classname, pyclbr.Class in rhs
        for cls_name, cls in rhs.items()
        # Only add the pair to auto_routes if:
        #    * the superclass is in the list of supers we want
        #    * the requesthandler isn't already paired in custom_routes
        #    * the requesthandler isn't manually excluded
        if is_handler_subclass(cls)
        and cls_name not in (custom_routes_s + exclusions)
    ]))

    routes = auto_routes + custom_routes
    return routes
Serializes this MapperSpec into a json-izable object.
dataset/ETHPy150Open hfaran/Tornado-JSON/tornado_json/routes.py/get_module_routes--crossover with--dataset/ETHPy150Open AppScale/appscale/AppServer/google/appengine/ext/mapreduce/model.py/MapperSpec.to_json