def register(): log.info('===>>> Mapping {} to resource {}'.format(entity, resource)) registry.cms_entity_resources[entity] = resource if add_url_adapter: config.add_resource_url_adapter( lambda resource2, request: ResourceURL(resource(request, resource2), request), entity)
def resource_url(self, resource, *elements, **kw): """ Generate a string representing the absolute URL of the :term:`resource` object based on the ``wsgi.url_scheme``, ``HTTP_HOST`` or ``SERVER_NAME`` in the request, plus any ``SCRIPT_NAME``. The overall result of this method is always a UTF-8 encoded string. Examples:: request.resource_url(resource) => http://example.com/ request.resource_url(resource, 'a.html') => http://example.com/a.html request.resource_url(resource, 'a.html', query={'q':'1'}) => http://example.com/a.html?q=1 request.resource_url(resource, 'a.html', anchor='abc') => http://example.com/a.html#abc request.resource_url(resource, app_url='') => / Any positional arguments passed in as ``elements`` must be strings Unicode objects, or integer objects. These will be joined by slashes and appended to the generated resource URL. Each of the elements passed in is URL-quoted before being appended; if any element is Unicode, it will converted to a UTF-8 bytestring before being URL-quoted. If any element is an integer, it will be converted to its string representation before being URL-quoted. .. warning:: if no ``elements`` arguments are specified, the resource URL will end with a trailing slash. If any ``elements`` are used, the generated URL will *not* end in a trailing slash. If a keyword argument ``query`` is present, it will be used to compose a query string that will be tacked on to the end of the URL. The value of ``query`` may be a sequence of two-tuples *or* a data structure with an ``.items()`` method that returns a sequence of two-tuples (presumably a dictionary). This data structure will be turned into a query string per the documentation of :func:``pyramid.url.urlencode`` function. This will produce a query string in the ``x-www-form-urlencoded`` encoding. A non-``x-www-form-urlencoded`` query string may be used by passing a *string* value as ``query`` in which case it will be URL-quoted (e.g. query="foo bar" will become "foo%20bar"). However, the result will not need to be in ``k=v`` form as required by ``x-www-form-urlencoded``. After the query data is turned into a query string, a leading ``?`` is prepended, and the resulting string is appended to the generated URL. .. note:: Python data structures that are passed as ``query`` which are sequences or dictionaries are turned into a string under the same rules as when run through :func:`urllib.urlencode` with the ``doseq`` argument equal to ``True``. This means that sequences can be passed as values, and a k=v pair will be placed into the query string for each value. .. versionchanged:: 1.5 Allow the ``query`` option to be a string to enable alternative encodings. If a keyword argument ``anchor`` is present, its string representation will be used as a named anchor in the generated URL (e.g. if ``anchor`` is passed as ``foo`` and the resource URL is ``http://example.com/resource/url``, the resulting generated URL will be ``http://example.com/resource/url#foo``). .. note:: If ``anchor`` is passed as a string, it should be UTF-8 encoded. If ``anchor`` is passed as a Unicode object, it will be converted to UTF-8 before being appended to the URL. .. versionchanged:: 1.5 The ``anchor`` option will be escaped instead of using its raw string representation. If both ``anchor`` and ``query`` are specified, the anchor element will always follow the query element, e.g. ``http://example.com?foo=1#bar``. If any of the keyword arguments ``scheme``, ``host``, or ``port`` is passed and is non-``None``, the provided value will replace the named portion in the generated URL. For example, if you pass ``host='foo.com'``, and the URL that would have been generated without the host replacement is ``http://example.com/a``, the result will be ``http://foo.com/a``. If ``scheme`` is passed as ``https``, and an explicit ``port`` is not passed, the ``port`` value is assumed to have been passed as ``443``. Likewise, if ``scheme`` is passed as ``http`` and ``port`` is not passed, the ``port`` value is assumed to have been passed as ``80``. To avoid this behavior, always explicitly pass ``port`` whenever you pass ``scheme``. If a keyword argument ``app_url`` is passed and is not ``None``, it should be a string that will be used as the port/hostname/initial path portion of the generated URL instead of the default request application URL. For example, if ``app_url='http://foo'``, then the resulting url of a resource that has a path of ``/baz/bar`` will be ``http://foo/baz/bar``. If you want to generate completely relative URLs with no leading scheme, host, port, or initial path, you can pass ``app_url=''``. Passing ``app_url=''`` when the resource path is ``/baz/bar`` will return ``/baz/bar``. .. versionadded:: 1.3 ``app_url`` If ``app_url`` is passed and any of ``scheme``, ``port``, or ``host`` are also passed, ``app_url`` will take precedence and the values passed for ``scheme``, ``host``, and/or ``port`` will be ignored. If the ``resource`` passed in has a ``__resource_url__`` method, it will be used to generate the URL (scheme, host, port, path) for the base resource which is operated upon by this function. .. seealso:: See also :ref:`overriding_resource_url_generation`. .. versionadded:: 1.5 ``route_name``, ``route_kw``, and ``route_remainder_name`` If ``route_name`` is passed, this function will delegate its URL production to the ``route_url`` function. Calling ``resource_url(someresource, 'element1', 'element2', query={'a':1}, route_name='blogentry')`` is roughly equivalent to doing:: remainder_path = request.resource_path(someobject) url = request.route_url( 'blogentry', 'element1', 'element2', _query={'a':'1'}, traverse=traversal_path, ) It is only sensible to pass ``route_name`` if the route being named has a ``*remainder`` stararg value such as ``*traverse``. The remainder value will be ignored in the output otherwise. By default, the resource path value will be passed as the name ``traverse`` when ``route_url`` is called. You can influence this by passing a different ``route_remainder_name`` value if the route has a different ``*stararg`` value at its end. For example if the route pattern you want to replace has a ``*subpath`` stararg ala ``/foo*subpath``:: request.resource_url( resource, route_name='myroute', route_remainder_name='subpath' ) If ``route_name`` is passed, it is also permissible to pass ``route_kw``, which will passed as additional keyword arguments to ``route_url``. Saying ``resource_url(someresource, 'element1', 'element2', route_name='blogentry', route_kw={'id':'4'}, _query={'a':'1'})`` is roughly equivalent to:: remainder_path = request.resource_path_tuple(someobject) kw = {'id':'4', '_query':{'a':'1'}, 'traverse':traversal_path} url = request.route_url( 'blogentry', 'element1', 'element2', **kw, ) If ``route_kw`` or ``route_remainder_name`` is passed, but ``route_name`` is not passed, both ``route_kw`` and ``route_remainder_name`` will be ignored. If ``route_name`` is passed, the ``__resource_url__`` method of the resource passed is ignored unconditionally. This feature is incompatible with resources which generate their own URLs. .. note:: If the :term:`resource` used is the result of a :term:`traversal`, it must be :term:`location`-aware. The resource can also be the context of a :term:`URL dispatch`; contexts found this way do not need to be location-aware. .. note:: If a 'virtual root path' is present in the request environment (the value of the WSGI environ key ``HTTP_X_VHM_ROOT``), and the resource was obtained via :term:`traversal`, the URL path will not include the virtual root prefix (it will be stripped off the left hand side of the generated URL). .. note:: For backwards compatibility purposes, this method is also aliased as the ``model_url`` method of request. """ try: reg = self.registry except AttributeError: reg = get_current_registry() # b/c url_adapter = reg.queryMultiAdapter((resource, self), IResourceURL) if url_adapter is None: url_adapter = ResourceURL(resource, self) virtual_path = getattr(url_adapter, 'virtual_path', None) if virtual_path is None: # old-style IContextURL adapter (Pyramid 1.2 and previous) warnings.warn( 'Pyramid is using an IContextURL adapter to generate a ' 'resource URL; any "app_url", "host", "port", or "scheme" ' 'arguments passed to resource_url are being ignored. To ' 'avoid this behavior, as of Pyramid 1.3, register an ' 'IResourceURL adapter instead of an IContextURL ' 'adapter for the resource type(s). IContextURL adapters ' 'will be ignored in a later major release of Pyramid.', DeprecationWarning, 2) resource_url = url_adapter() else: # IResourceURL adapter (Pyramid 1.3 and after) app_url = None scheme = None host = None port = None if 'route_name' in kw: newkw = {} route_name = kw['route_name'] remainder = getattr(url_adapter, 'virtual_path_tuple', None) if remainder is None: # older user-supplied IResourceURL adapter without 1.5 # virtual_path_tuple remainder = tuple(url_adapter.virtual_path.split('/')) remainder_name = kw.get('route_remainder_name', 'traverse') newkw[remainder_name] = remainder for name in ('app_url', 'scheme', 'host', 'port', 'query', 'anchor'): val = kw.get(name, None) if val is not None: newkw['_' + name] = val if 'route_kw' in kw: route_kw = kw.get('route_kw') if route_kw is not None: newkw.update(route_kw) return self.route_url(route_name, *elements, **newkw) if 'app_url' in kw: app_url = kw['app_url'] if 'scheme' in kw: scheme = kw['scheme'] if 'host' in kw: host = kw['host'] if 'port' in kw: port = kw['port'] if app_url is None: if scheme or host or port: app_url = self._partial_application_url(scheme, host, port) else: app_url = self.application_url resource_url = None local_url = getattr(resource, '__resource_url__', None) if local_url is not None: # the resource handles its own url generation d = dict( virtual_path=virtual_path, physical_path=url_adapter.physical_path, app_url=app_url, ) # allow __resource_url__ to punt by returning None resource_url = local_url(self, d) if resource_url is None: # the resource did not handle its own url generation or the # __resource_url__ function returned None resource_url = app_url + virtual_path qs = '' anchor = '' if 'query' in kw: query = kw['query'] if isinstance(query, string_types): qs = '?' + url_quote(query, QUERY_SAFE) elif query: qs = '?' + urlencode(query, doseq=True) if 'anchor' in kw: anchor = kw['anchor'] anchor = url_quote(anchor, ANCHOR_SAFE) anchor = '#' + anchor if elements: suffix = _join_elements(elements) else: suffix = '' return resource_url + suffix + qs + anchor
def resource_url(self, resource, *elements, **kw): """ Generate a string representing the absolute URL of the :term:`resource` object based on the ``wsgi.url_scheme``, ``HTTP_HOST`` or ``SERVER_NAME`` in the request, plus any ``SCRIPT_NAME``. The overall result of this method is always a UTF-8 encoded string. Examples:: request.resource_url(resource) => http://example.com/ request.resource_url(resource, 'a.html') => http://example.com/a.html request.resource_url(resource, 'a.html', query={'q':'1'}) => http://example.com/a.html?q=1 request.resource_url(resource, 'a.html', anchor='abc') => http://example.com/a.html#abc request.resource_url(resource, app_url='') => / Any positional arguments passed in as ``elements`` must be strings Unicode objects, or integer objects. These will be joined by slashes and appended to the generated resource URL. Each of the elements passed in is URL-quoted before being appended; if any element is Unicode, it will converted to a UTF-8 bytestring before being URL-quoted. If any element is an integer, it will be converted to its string representation before being URL-quoted. .. warning:: if no ``elements`` arguments are specified, the resource URL will end with a trailing slash. If any ``elements`` are used, the generated URL will *not* end in trailing a slash. If a keyword argument ``query`` is present, it will be used to compose a query string that will be tacked on to the end of the URL. The value of ``query`` must be a sequence of two-tuples *or* a data structure with an ``.items()`` method that returns a sequence of two-tuples (presumably a dictionary). This data structure will be turned into a query string per the documentation of ``pyramid.url.urlencode`` function. After the query data is turned into a query string, a leading ``?`` is prepended, and the resulting string is appended to the generated URL. .. note:: Python data structures that are passed as ``query`` which are sequences or dictionaries are turned into a string under the same rules as when run through :func:`urllib.urlencode` with the ``doseq`` argument equal to ``True``. This means that sequences can be passed as values, and a k=v pair will be placed into the query string for each value. If a keyword argument ``anchor`` is present, its string representation will be used as a named anchor in the generated URL (e.g. if ``anchor`` is passed as ``foo`` and the resource URL is ``http://example.com/resource/url``, the resulting generated URL will be ``http://example.com/resource/url#foo``). .. note:: If ``anchor`` is passed as a string, it should be UTF-8 encoded. If ``anchor`` is passed as a Unicode object, it will be converted to UTF-8 before being appended to the URL. The anchor value is not quoted in any way before being appended to the generated URL. If both ``anchor`` and ``query`` are specified, the anchor element will always follow the query element, e.g. ``http://example.com?foo=1#bar``. If any of the keyword arguments ``scheme``, ``host``, or ``port`` is passed and is non-``None``, the provided value will replace the named portion in the generated URL. For example, if you pass ``host='foo.com'``, and the URL that would have been generated without the host replacement is ``http://example.com/a``, the result will be ``https://foo.com/a``. If ``scheme`` is passed as ``https``, and an explicit ``port`` is not passed, the ``port`` value is assumed to have been passed as ``443``. Likewise, if ``scheme`` is passed as ``http`` and ``port`` is not passed, the ``port`` value is assumed to have been passed as ``80``. To avoid this behavior, always explicitly pass ``port`` whenever you pass ``scheme``. If a keyword argument ``app_url`` is passed and is not ``None``, it should be a string that will be used as the port/hostname/initial path portion of the generated URL instead of the default request application URL. For example, if ``app_url='http://foo'``, then the resulting url of a resource that has a path of ``/baz/bar`` will be ``http://foo/baz/bar``. If you want to generate completely relative URLs with no leading scheme, host, port, or initial path, you can pass ``app_url=''`. Passing ``app_url=''` when the resource path is ``/baz/bar`` will return ``/baz/bar``. .. note:: ``app_url`` is new as of Pyramid 1.3. If ``app_url`` is passed and any of ``scheme``, ``port``, or ``host`` are also passed, ``app_url`` will take precedence and the values passed for ``scheme``, ``host``, and/or ``port`` will be ignored. If the ``resource`` passed in has a ``__resource_url__`` method, it will be used to generate the URL (scheme, host, port, path) that for the base resource which is operated upon by this function. See also :ref:`overriding_resource_url_generation`. .. note:: If the :term:`resource` used is the result of a :term:`traversal`, it must be :term:`location`-aware. The resource can also be the context of a :term:`URL dispatch`; contexts found this way do not need to be location-aware. .. note:: If a 'virtual root path' is present in the request environment (the value of the WSGI environ key ``HTTP_X_VHM_ROOT``), and the resource was obtained via :term:`traversal`, the URL path will not include the virtual root prefix (it will be stripped off the left hand side of the generated URL). .. note:: For backwards compatibility purposes, this method is also aliased as the ``model_url`` method of request. """ try: reg = self.registry except AttributeError: reg = get_current_registry() # b/c url_adapter = reg.queryMultiAdapter((resource, self), IResourceURL) if url_adapter is None: url_adapter = ResourceURL(resource, self) virtual_path = getattr(url_adapter, 'virtual_path', None) if virtual_path is None: # old-style IContextURL adapter (Pyramid 1.2 and previous) warnings.warn( 'Pyramid is using an IContextURL adapter to generate a ' 'resource URL; any "app_url", "host", "port", or "scheme" ' 'arguments passed to resource_url are being ignored. To ' 'avoid this behavior, as of Pyramid 1.3, register an ' 'IResourceURL adapter instead of an IContextURL ' 'adapter for the resource type(s). IContextURL adapters ' 'will be ignored in a later major release of Pyramid.', DeprecationWarning, 2) resource_url = url_adapter() else: # newer-style IResourceURL adapter (Pyramid 1.3 and after) app_url = None scheme = None host = None port = None if 'app_url' in kw: app_url = kw['app_url'] if 'scheme' in kw: scheme = kw['scheme'] if 'host' in kw: host = kw['host'] if 'port' in kw: port = kw['port'] if app_url is None: if scheme or host or port: app_url = self._partial_application_url(scheme, host, port) else: app_url = self.application_url resource_url = None local_url = getattr(resource, '__resource_url__', None) if local_url is not None: # the resource handles its own url generation d = dict( virtual_path = virtual_path, physical_path = url_adapter.physical_path, app_url = app_url, ) # allow __resource_url__ to punt by returning None resource_url = local_url(self, d) if resource_url is None: # the resource did not handle its own url generation or the # __resource_url__ function returned None resource_url = app_url + virtual_path qs = '' anchor = '' if 'query' in kw: query = kw['query'] if query: qs = '?' + urlencode(query, doseq=True) if 'anchor' in kw: anchor = kw['anchor'] if isinstance(anchor, text_type): anchor = native_(anchor, 'utf-8') anchor = '#' + anchor if elements: suffix = _join_elements(elements) else: suffix = '' return resource_url + suffix + qs + anchor