def render_template(self, content, vars, filename=None): """ Return a bytestring representing a templated file based on the input (content) and the variable names defined (vars). ``filename`` is used for exception reporting.""" # this method must not be named "template_renderer" fbo of extension # scaffolds that need to work under pyramid 1.2 and 1.3, and which # need to do "template_renderer = # staticmethod(paste_script_template_renderer)" content = native_(content, fsenc) try: return bytes_( substitute_double_braces(content, TypeMapper(vars)), fsenc) except Exception as e: _add_except(e, ' in file %s' % filename) raise
def quote_path_segment(segment, safe=''): """ %s """ % quote_path_segment_doc # The bit of this code that deals with ``_segment_cache`` is an # optimization: we cache all the computation of URL path segments # in this module-scope dictionary with the original string (or # unicode value) as the key, so we can look it up later without # needing to reencode or re-url-quote it try: return _segment_cache[(segment, safe)] except KeyError: if segment.__class__ not in (text_type, binary_type): segment = str(segment) result = url_quote(native_(segment, 'utf-8'), safe) # we don't need a lock to mutate _segment_cache, as the below # will generate exactly one Python bytecode (STORE_SUBSCR) _segment_cache[(segment, safe)] = result return result
def pre(self, command, output_dir, vars): """ Overrides :meth:`pyramid.scaffold.template.Template.pre`, adding several variables to the default variables list (including ``random_string``, and ``package_logger``). It also prevents common misnamings (such as naming a package "site" or naming a package logger "root". """ if vars["package"] == "site": raise ValueError( 'Sorry, you may not name your package "site". ' 'The package name "site" has a special meaning in ' 'Python. Please name it anything except "site".' ) vars["random_string"] = native_(binascii.hexlify(os.urandom(20))) package_logger = vars["package"] if package_logger == "root": # Rename the app logger in the rare case a project is named 'root' package_logger = "app" vars["package_logger"] = package_logger return Template.pre(self, command, output_dir, vars)
def matcher(path): # This function really wants to consume Unicode patterns natively, # but if someone passes us a bytestring, we allow it by converting it # to Unicode using the ASCII decoding. We decode it using ASCII # because we don't want to accept bytestrings with high-order # characters in them here as we have no idea what the encoding # represents. if path.__class__ is not text_type: path = text_(path, 'ascii') m = match(path) if m is None: return None d = {} for k, v in m.groupdict().items(): # k and v will be Unicode 2.6.4 and lower doesnt accept unicode # kwargs as **kw, so we explicitly cast the keys to native # strings in case someone wants to pass the result as **kw nk = native_(k, 'ascii') if k == remainder: d[nk] = split_path_info(v) else: d[nk] = v return d
def copy_dir( source, dest, vars, verbosity, simulate, indent=0, sub_vars=True, interactive=False, overwrite=True, template_renderer=None, out_=sys.stdout, ): """ Copies the ``source`` directory to the ``dest`` directory. ``vars``: A dictionary of variables to use in any substitutions. ``verbosity``: Higher numbers will show more about what is happening. ``simulate``: If true, then don't actually *do* anything. ``indent``: Indent any messages by this amount. ``sub_vars``: If true, variables in ``_tmpl`` files and ``+var+`` in filenames will be substituted. ``overwrite``: If false, then don't every overwrite anything. ``interactive``: If you are overwriting a file and interactive is true, then ask before overwriting. ``template_renderer``: This is a function for rendering templates (if you don't want to use string.Template). It should have the signature ``template_renderer(content_as_string, vars_as_dict, filename=filename)``. """ def out(msg): out_.write(msg) out_.write("\n") out_.flush() # This allows you to use a leading +dot+ in filenames which would # otherwise be skipped because leading dots make the file hidden: vars.setdefault("dot", ".") vars.setdefault("plus", "+") use_pkg_resources = isinstance(source, tuple) if use_pkg_resources: names = sorted(pkg_resources.resource_listdir(source[0], source[1])) else: names = sorted(os.listdir(source)) pad = " " * (indent * 2) if not os.path.exists(dest): if verbosity >= 1: out("%sCreating %s/" % (pad, dest)) if not simulate: makedirs(dest, verbosity=verbosity, pad=pad) elif verbosity >= 2: out("%sDirectory %s exists" % (pad, dest)) for name in names: if use_pkg_resources: full = "/".join([source[1], name]) else: full = os.path.join(source, name) reason = should_skip_file(name) if reason: if verbosity >= 2: reason = pad + reason % {"filename": full} out(reason) continue # pragma: no cover if sub_vars: dest_full = os.path.join(dest, substitute_filename(name, vars)) sub_file = False if dest_full.endswith("_tmpl"): dest_full = dest_full[:-5] sub_file = sub_vars if use_pkg_resources and pkg_resources.resource_isdir(source[0], full): if verbosity: out("%sRecursing into %s" % (pad, os.path.basename(full))) copy_dir( (source[0], full), dest_full, vars, verbosity, simulate, indent=indent + 1, sub_vars=sub_vars, interactive=interactive, template_renderer=template_renderer, out_=out_, ) continue elif not use_pkg_resources and os.path.isdir(full): if verbosity: out("%sRecursing into %s" % (pad, os.path.basename(full))) copy_dir( full, dest_full, vars, verbosity, simulate, indent=indent + 1, sub_vars=sub_vars, interactive=interactive, template_renderer=template_renderer, out_=out_, ) continue elif use_pkg_resources: content = pkg_resources.resource_string(source[0], full) else: f = open(full, "rb") content = f.read() f.close() if sub_file: try: content = substitute_content(content, vars, filename=full, template_renderer=template_renderer) except SkipTemplate: continue # pragma: no cover if content is None: continue # pragma: no cover already_exists = os.path.exists(dest_full) if already_exists: f = open(dest_full, "rb") old_content = f.read() f.close() if old_content == content: if verbosity: out("%s%s already exists (same content)" % (pad, dest_full)) continue # pragma: no cover if interactive: if not query_interactive( native_(full, fsenc), native_(dest_full, fsenc), native_(content, fsenc), native_(old_content, fsenc), simulate=simulate, out_=out_, ): continue elif not overwrite: continue # pragma: no cover if verbosity and use_pkg_resources: out("%sCopying %s to %s" % (pad, full, dest_full)) elif verbosity: out("%sCopying %s to %s" % (pad, os.path.basename(full), dest_full)) if not simulate: f = open(dest_full, "wb") f.write(content) f.close()
def route_url(self, route_name, *elements, **kw): """Generates a fully qualified URL for a named :app:`Pyramid` :term:`route configuration`. Use the route's ``name`` as the first positional argument. Additional positional arguments (``*elements``) are appended to the URL as path segments after it is generated. Use keyword arguments to supply values which match any dynamic path elements in the route definition. Raises a :exc:`KeyError` exception if the URL cannot be generated for any reason (not enough arguments, for example). For example, if you've defined a route named "foobar" with the path ``{foo}/{bar}/*traverse``:: request.route_url('foobar', foo='1') => <KeyError exception> request.route_url('foobar', foo='1', bar='2') => <KeyError exception> request.route_url('foobar', foo='1', bar='2', traverse=('a','b')) => http://e.com/1/2/a/b request.route_url('foobar', foo='1', bar='2', traverse='/a/b') => http://e.com/1/2/a/b Values replacing ``:segment`` arguments can be passed as strings or Unicode objects. They will be encoded to UTF-8 and URL-quoted before being placed into the generated URL. Values replacing ``*remainder`` arguments can be passed as strings *or* tuples of Unicode/string values. If a tuple is passed as a ``*remainder`` replacement value, its values are URL-quoted and encoded to UTF-8. The resulting strings are joined with slashes and rendered into the URL. If a string is passed as a ``*remainder`` replacement value, it is tacked on to the URL after being URL-quoted-except-for-embedded-slashes. 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 :func:`pyramid.encode.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 route URL is ``http://example.com/route/url``, the resulting generated URL will be ``http://example.com/route/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``. Note that if ``_scheme`` is passed as ``https``, and ``_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 ``_app_url`` is present, it will be used as the protocol/hostname/port/leading path prefix of the generated URL. For example, using an ``_app_url`` of ``http://example.com:8080/foo`` would cause the URL ``http://example.com:8080/foo/fleeb/flub`` to be returned from this function if the expansion of the route pattern associated with the ``route_name`` expanded to ``/fleeb/flub``. If ``_app_url`` is not specified, the result of ``request.application_url`` will be used as the prefix (the default). If both ``_app_url`` and any of ``_scheme``, ``_host``, or ``_port`` are passed, ``_app_url`` takes precedence and any values passed for ``_scheme``, ``_host``, and ``_port`` will be ignored. This function raises a :exc:`KeyError` if the URL cannot be generated due to missing replacement names. Extra replacement names are ignored. If the route object which matches the ``route_name`` argument has a :term:`pregenerator`, the ``*elements`` and ``**kw`` arguments passed to this function might be augmented or changed. """ try: reg = self.registry except AttributeError: reg = get_current_registry() # b/c mapper = reg.getUtility(IRoutesMapper) route = mapper.get_route(route_name) if route is None: raise KeyError('No such route named %s' % route_name) if route.pregenerator is not None: elements, kw = route.pregenerator(self, elements, kw) anchor = '' qs = '' app_url = None host = None scheme = None port = None if '_query' in kw: query = kw.pop('_query') if query: qs = '?' + urlencode(query, doseq=True) if '_anchor' in kw: anchor = kw.pop('_anchor') anchor = native_(anchor, 'utf-8') anchor = '#' + anchor if '_app_url' in kw: app_url = kw.pop('_app_url') if '_host' in kw: host = kw.pop('_host') if '_scheme' in kw: scheme = kw.pop('_scheme') if '_port' in kw: port = kw.pop('_port') if app_url is None: if (scheme is not None or host is not None or port is not None): app_url = self._partial_application_url(scheme, host, port) else: app_url = self.application_url path = route.generate(kw) # raises KeyError if generate fails if elements: suffix = _join_elements(elements) if not path.endswith('/'): suffix = '/' + suffix else: suffix = '' return app_url + path + 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
def _compile_route(route): # This function really wants to consume Unicode patterns natively, but if # someone passes us a bytestring, we allow it by converting it to Unicode # using the ASCII decoding. We decode it using ASCII because we don't # want to accept bytestrings with high-order characters in them here as # we have no idea what the encoding represents. if route.__class__ is not text_type: try: route = text_(route, 'ascii') except UnicodeDecodeError: raise ValueError( 'The pattern value passed to add_route must be ' 'either a Unicode string or a plain string without ' 'any non-ASCII characters (you provided %r).' % route) if old_route_re.search(route) and not route_re.search(route): route = old_route_re.sub(update_pattern, route) if not route.startswith('/'): route = '/' + route remainder = None if star_at_end.search(route): route, remainder = route.rsplit('*', 1) pat = route_re.split(route) # every element in "pat" will be Unicode (regardless of whether the # route_re regex pattern is itself Unicode or str) pat.reverse() rpat = [] gen = [] prefix = pat.pop() # invar: always at least one element (route='/'+route) # We want to generate URL-encoded URLs, so we url-quote the prefix, being # careful not to quote any embedded slashes. We have to replace '%' with # '%%' afterwards, as the strings that go into "gen" are used as string # replacement targets. gen.append(quote_path_segment(prefix, safe='/').replace('%', '%%')) # native rpat.append(re.escape(prefix)) # unicode while pat: name = pat.pop() # unicode name = name[1:-1] if ':' in name: # reg may contain colons as well, # so we must strictly split name into two parts name, reg = name.split(':', 1) else: reg = '[^/]+' gen.append('%%(%s)s' % native_(name)) # native name = '(?P<%s>%s)' % (name, reg) # unicode rpat.append(name) s = pat.pop() # unicode if s: rpat.append(re.escape(s)) # unicode # We want to generate URL-encoded URLs, so we url-quote this # literal in the pattern, being careful not to quote the embedded # slashes. We have to replace '%' with '%%' afterwards, as the # strings that go into "gen" are used as string replacement # targets. What is appended to gen is a native string. gen.append(quote_path_segment(s, safe='/').replace('%', '%%')) if remainder: rpat.append('(?P<%s>.*?)' % remainder) # unicode gen.append('%%(%s)s' % native_(remainder)) # native pattern = ''.join(rpat) + '$' # unicode match = re.compile(pattern).match def matcher(path): # This function really wants to consume Unicode patterns natively, # but if someone passes us a bytestring, we allow it by converting it # to Unicode using the ASCII decoding. We decode it using ASCII # because we don't want to accept bytestrings with high-order # characters in them here as we have no idea what the encoding # represents. if path.__class__ is not text_type: path = text_(path, 'ascii') m = match(path) if m is None: return None d = {} for k, v in m.groupdict().items(): # k and v will be Unicode 2.6.4 and lower doesnt accept unicode # kwargs as **kw, so we explicitly cast the keys to native # strings in case someone wants to pass the result as **kw nk = native_(k, 'ascii') if k == remainder: d[nk] = split_path_info(v) else: d[nk] = v return d gen = ''.join(gen) def generator(dict): newdict = {} for k, v in dict.items(): if PY3: # pragma: no cover if v.__class__ is binary_type: # url_quote below needs a native string, not bytes on Py3 v = v.decode('utf-8') else: if v.__class__ is text_type: # url_quote below needs bytes, not unicode on Py2 v = v.encode('utf-8') if k == remainder: # a stararg argument if is_nonstr_iter(v): v = '/'.join([quote_path_segment(x) for x in v]) # native else: if v.__class__ not in string_types: v = str(v) v = quote_path_segment(v, safe='/') else: if v.__class__ not in string_types: v = str(v) # v may be bytes (py2) or native string (py3) v = quote_path_segment(v) # at this point, the value will be a native string newdict[k] = v result = gen % newdict # native string result return result return matcher, generator