def base_url(self): """ :return: The base_url for this adapter. It simply joins the provided base_url in the __init__ method and joins it with the ``request.url_root``. If this app provided is actually a blueprint, it will return join the blueprints url_prefix in between :rtype: unicode """ if getattr(self.app, "url_prefix", None): return join_url_parts(request.url_root, self.app.url_prefix, self.url_prefix) return join_url_parts(request.url_root, self.url_prefix)
def register_route(self, endpoint, endpoint_func=None, route=None, methods=None, **options): """ Registers the endpoints on the flask application or blueprint. It does so by using the add_url_rule on the blueprint/app. It wraps the endpoint_func with the ``flask_dispatch_wrapper`` which returns an updated function. This function appropriately sets the RequestContainer object before passing it to the apimethod. :param unicode endpoint: The name of the endpoint. This is typically used in flask for reversing urls :param method endpoint_func: The actual function that is going to be called. This is generally going to be a @apimethod decorated, ResourceBase subclass method. :param unicode route: The actual route that is going to be used. :param list methods: The http verbs that can be used with this endpoint :param dict options: The additional options to pass to the add_url_rule """ valid_flask_options = ('defaults', 'subdomain', 'methods', 'build_only', 'endpoint', 'strict_slashes', 'redirect_to', 'alias', 'host') route = join_url_parts(self.url_prefix, route) # Remove invalid flask options. options_copy = options.copy() for key, value in six.iteritems(options_copy): if key not in valid_flask_options: options.pop(key, None) self.app.add_url_rule(route, endpoint=endpoint, view_func=flask_dispatch_wrapper(self, endpoint_func, self.argument_getter), methods=methods, **options)
def _generate_endpoint_dict(cls): """ Generates a dictionary of the endpoints on the class which are @apimethod decorated. :param ResourceMetaClass cls: The ResourceBase subclass that you are trying to get the endpoints from. :type cls: :return: :rtype: """ endpoint_dictionary = {} for name, method in _get_apimethods(cls): _logger.debug('Found the apimethod %s on the class %s', name, cls.__name__) all_routes = [] for route, endpoint, options in method.routes: base_url = cls.base_url_sans_pks if options.get( 'no_pks', False) else cls.base_url route = join_url_parts(base_url, route) all_routes.append( dict(route=route, endpoint_func=method, **options)) _logger.info('Registering routes: %s as key %s', all_routes, name) endpoint_dictionary[name] = all_routes return endpoint_dictionary
def combine_base_url_with_resource_url(self, resource_url): """ Does exactly what it says it does. Uses ``join_url_parts`` with the ``self.base_url`` and ``resource_url`` argument together. :param unicode resource_url: The part to join with the ``self.base_url`` :return: The joined url :rtype: unicode """ return join_url_parts(self.base_url, resource_url)
def base_url_sans_pks(cls): """ A class property that returns the base url without the pks. This is just the /{namespace}/{resource_name} For example if the _namespace = '/api' and the _resource_name = 'resource' this would return '/api/resource' regardless if there are pks or not. :return: The base url without the pks :rtype: unicode """ pks = cls.pks[:-1] or [] #only use the last primary key element parts = ['<{0}>'.format(pk) for pk in pks] base_url = join_url_parts(cls.namespace, cls.resource_name).lstrip('/') base_url = join_url_parts(base_url, *parts).strip('/') return '/{0}/'.format(base_url) if not cls.append_slash else '/{0}/'.format(base_url)
def base_url(cls): """ Gets the base_url for the resource This is prepended to all routes indicated by an apimethod decorator. :return: The base_url for the resource(s) :rtype: unicode """ pks = cls.pks or [] parts = ['<{0}>'.format(pk) for pk in pks] base_url = join_url_parts(cls.base_url_sans_pks, *parts).strip('/') return '/{0}'.format(base_url) if not cls.append_slash else '/{0}/'.format(base_url)
def base_url(cls): """ Gets the base_url for the resource This is prepended to all routes indicated by an apimethod decorator. :return: The base_url for the resource(s) :rtype: unicode """ pks = cls.pks or [] parts = ['<{0}>'.format(pk) for pk in pks] base_url = join_url_parts(cls.base_url_sans_pks, *parts).lstrip('/') return '/{0}'.format( base_url) if not cls.append_slash else '/{0}/'.format(base_url)
def base_url_sans_pks(cls): """ A class property that returns the base url without the pks. This is just the /{namespace}/{resource_name} For example if the _namespace = '/api' and the _resource_name = 'resource' this would return '/api/resource' regardless if there are pks or not. :return: The base url without the pks :rtype: unicode """ pks = cls.pks[:-1] or [ ] #only use the last primary key element parts = ['<{0}>'.format(pk) for pk in pks] base_url = join_url_parts(cls.namespace, cls.resource_name).lstrip('/') base_url = join_url_parts(base_url, *parts).strip('/') return '/{0}/'.format( base_url) if not cls.append_slash else '/{0}/'.format( base_url)
def base_url_sans_pks(cls): """ A class property that returns the base url without the pks. This is just the /{namespace}/{resource_name} For example if the _namespace = '/api' and the _resource_name = 'resource' this would return '/api/resource' regardless if there are pks or not. :return: The base url without the pks :rtype: unicode """ base_url = join_url_parts(cls.namespace, cls.resource_name).lstrip('/') return '/{0}'.format(base_url) if not cls.append_slash else '/{0}/'.format(base_url)
def _construct_id(resource): """ Constructs a JSON API compatible id. May not work particularly well for composite ids since apparently JSON API hates them. It will simply join the pks with a `"/"` in the appropriate order. :param ResourceBase resource: The resource whose id needs to be constructed. :return: The id in a format `<pk1>/<pk2>` :rtype: unicode """ pks = resource.pks id_parts = [resource.item_pks[pk] for pk in pks] id_ = join_url_parts(*id_parts) return id_
def base_url_sans_pks(cls): """ A class property that eturns the base url without the pks. This is just the /{namespace}/{resource_name} For example if the _namespace = '/api' and the _resource_name = 'resource' this would return '/api/resource' regardless if there are pks or not. :return: The base url without the pks :rtype: unicode """ base_url = join_url_parts(cls.namespace, cls.resource_name).lstrip('/') return '/{0}'.format( base_url) if not cls.append_slash else '/{0}/'.format(base_url)
def url(self): """ Lazily constructs the url for this specific resource using the specific pks as specified in the pks tuple. :return: The url for this resource :rtype: unicode """ if not self._url: base_url = self.base_url_sans_pks if self.no_pks else self.base_url base_url = join_url_parts(base_url, self.route_extension) url = create_url(base_url, **self.item_pks).strip('/') url = '/{0}'.format(url) if not self.append_slash else '/{0}/'.format(url) query_string = self.query_string if query_string: url = '{0}?{1}'.format(url, query_string) self._url = url return self._url
def url(self): """ Lazily constructs the url for this specific resource using the specific pks as specified in the pks tuple. :return: The url for this resource :rtype: unicode """ if not self._url: base_url = self.base_url_sans_pks if self.no_pks else self.base_url base_url = join_url_parts(base_url, self.route_extension) url = create_url(base_url, **self.item_pks).strip('/') url = '/{0}'.format( url) if not self.append_slash else '/{0}/'.format(url) query_string = self.query_string if query_string: url = '{0}?{1}'.format(url, query_string) self._url = url return self._url
def _construct_id(resource): """ Constructs a JSON API compatible id. May not work particularly well for composite ids since apparently JSON API hates them. It will simply join the pks with a `"/"` in the appropriate order. Additionally, for resources with no_pks=True, it will return an empty string. :param ResourceBase resource: The resource whose id needs to be constructed. :return: The id in a format `<pk1>/<pk2>` :rtype: unicode """ if resource.no_pks: return "" pks = resource.pks id_parts = [resource.item_pks[pk] for pk in pks] id_ = join_url_parts(*id_parts) return id_
def register_route(self, endpoint, endpoint_func=None, route=None, methods=None, **options): """ Adds a route to the url_map which is used when getting the url_patterns property which are then added to the django app. :param unicode endpoint: The name of this endpoint :param function endpoint_func: the function that should be called when this endpoint is hit. :param unicode route: The url that corresponds to this endpoint. Each unique url generates a MethodRouter which then dispatches them to the appopriate endpoints for the http verbs :param list methods: The http verbs that correspond to this endpoint :param dict options: Additional options. Not used at this time """ route = join_url_parts(self.base_url, route) route = self._convert_url_to_regex(route) if route not in self.url_map: self.url_map[route] = self.method_route_class(route, self, self.error_handler) method_router = self.url_map[route] method_router.add_route(endpoint_func=endpoint_func, endpoint=endpoint, methods=methods, **options)
def _generate_endpoint_dict(cls): """ Generates a dictionary of the endpoints on the class which are @apimethod decorated. :param ResourceMetaClass cls: The ResourceBase subclass that you are trying to get the endpoints from. :type cls: :return: :rtype: """ endpoint_dictionary = {} for name, method in _get_apimethods(cls): _logger.debug('Found the apimethod %s on the class %s', name, cls.__name__) all_routes = [] for route, endpoint, options in method.routes: base_url = cls.base_url_sans_pks if options.get('no_pks', False) else cls.base_url #TODO: Add trailing slash here if no_pks?? route = join_url_parts(base_url, route) all_routes.append(dict(route=route, endpoint_func=method, **options)) _logger.info('Registering routes: %s as key %s', all_routes, name) endpoint_dictionary[name] = all_routes return endpoint_dictionary
def test_join_url_parts(self): url = join_url_parts() self.assertIsInstance(url, six.text_type) self.assertEqual('', url) url = join_url_parts('/something', '/another', '/thing') self.assertEqual(url, '/something/another/thing') url = join_url_parts('something/', '/another/', '/thing') self.assertEqual(url, 'something/another/thing') url = join_url_parts('something//', '/another') self.assertEqual(url, 'something/another') url = join_url_parts('/', '/another') self.assertEqual('/another', url) url = join_url_parts('/', '/') self.assertEqual('/', url)
def test_join_url_parts_ints(self): """joining parts when a single int. Ensuring that it is unicode""" resp = join_url_parts(1) self.assertEqual(resp, '1')