Example #1
0
def render_to_dir(output_dir, urls_to_distill, stdout):
    mimes = {}
    load_urls(stdout)
    renderer = DistillRender(output_dir, urls_to_distill)
    for page_uri, file_name, http_response in renderer.render():
        if file_name:
            local_uri = file_name
            full_path = os.path.join(output_dir, file_name)
        else:
            local_uri = page_uri
            if page_uri.startswith(os.sep):
                page_uri = page_uri[1:]
            full_path = os.path.join(output_dir, page_uri)
        try:
            content = http_response.content  # .decode(settings.DEFAULT_CHARSET) # PATCH#1: utf-8 rendering correction
        except Exception as e:
            err = 'Failed to encode {} into {}: {}'
            DistillError(err.format(page_uri, settings.DEFAULT_CHARSET, e))
        mime = http_response.get('Content-Type')
        renamed = ' (renamed from "{}")'.format(page_uri) if file_name else ''
        msg = 'Rendering page: {} -> {} ["{}", {} bytes] {}'
        stdout(msg.format(local_uri, full_path, mime, len(content), renamed))
        try:
            dirname = os.path.dirname(full_path)
            if not os.path.isdir(dirname):
                os.makedirs(dirname)
            with open(full_path,
                      'wb') as f:  # PATCH#2: utf-8 rendering correction
                f.write(content)
        except IOError as e:
            if e.errno == errno.EISDIR:
                err = ('Output path: {} is a directory! Try adding a '
                       '"distill_file" arg to your distill_url()')
                raise DistillError(err.format(full_path))
            else:
                raise
        mimes[full_path] = mime.split(';')[0].strip()
    static_url = settings.STATIC_URL
    static_url = static_url[1:] if static_url.startswith('/') else static_url
    static_output_dir = os.path.join(output_dir, static_url)
    for file_from, file_to in renderer.copy_static(settings.STATIC_ROOT,
                                                   static_output_dir):
        stdout('Copying static: {} -> {}'.format(file_from, file_to))
    media_url = settings.MEDIA_URL
    media_url = media_url[1:] if media_url.startswith('/') else media_url
    media_output_dir = os.path.join(output_dir, media_url)
    for file_from, file_to in renderer.copy_static(settings.MEDIA_ROOT,
                                                   media_output_dir):
        stdout('Copying media: {} -> {}'.format(file_from, file_to))
    return True
Example #2
0
 def get_uri_values(self, func):
     try:
         v = func()
     except Exception as e:
         raise DistillError('Failed to call distill function: {}'.format(e))
     if not v:
         return (None, )
     elif isinstance(v, (list, tuple)):
         return v
     elif isinstance(v, types.GeneratorType):
         return list(v)
     else:
         err = 'Distill function returned an invalid type: {}'
         raise DistillError(err.format(type(v)))
Example #3
0
def render_to_dir(output_dir, urls_to_distill, stdout):
    mimes = {}
    load_urls(stdout)
    renderer = DistillRender(output_dir, urls_to_distill)
    for page_uri, file_name, http_response in renderer.render():
        if file_name:
            local_uri = file_name
            full_path = os.path.join(output_dir, file_name)
        else:
            local_uri = page_uri
            if page_uri.startswith('/'):
                page_uri = page_uri[1:]
            page_path = page_uri.replace('/', os.sep)
            full_path = os.path.join(output_dir, page_path)
        content = http_response.content
        mime = http_response.get('Content-Type')
        renamed = ' (renamed from "{}")'.format(page_uri) if file_name else ''
        msg = 'Rendering page: {} -> {} ["{}", {} bytes] {}'
        stdout(msg.format(local_uri, full_path, mime, len(content), renamed))
        try:
            dirname = os.path.dirname(full_path)
            if not os.path.isdir(dirname):
                os.makedirs(dirname)
            with open(full_path, 'wb') as f:
                f.write(content)
        except IOError as e:
            if e.errno == errno.EISDIR:
                err = ('Output path: {} is a directory! Try adding a '
                       '"distill_file" arg to your distill_url()')
                raise DistillError(err.format(full_path))
            else:
                raise
        mimes[full_path] = mime.split(';')[0].strip()
    return True
Example #4
0
def distill_url(*a, **k):
    distill_func = k.get('distill_func')
    distill_file = k.get('distill_file')
    if distill_file:
        del k['distill_file']
    if distill_func:
        del k['distill_func']
        name = k.get('name')
        if not name:
            raise DistillError('Distill function provided with no name')
        if not callable(distill_func):
            err = 'Distill function not callable: {}'
            raise DistillError(err.format(distill_func))
        urls_to_distill.append((distill_func, distill_file, name, a, k))
    else:
        e = 'URL registered with distill_url but no distill function supplied'
        raise DistillWarning(e)
    return url(*a, **k)
Example #5
0
 def generate_uri(self, view_name, param_set):
     if isinstance(param_set, (list, tuple)):
         uri = reverse(view_name, args=param_set)
     elif isinstance(param_set, dict):
         uri = reverse(view_name, kwargs=param_set)
     else:
         err = 'Distill function returned an invalid type: {}'
         raise DistillError(err.format(type(param_set)))
     return uri
Example #6
0
 def render_view(self, uri, param_set, args):
     if len(args) < 2:
         raise DistillError('Invalid view arguments')
     view_regex, view_func = args[0], args[1]
     request_factory = RequestFactory()
     request = request_factory.get(uri)
     if isinstance(param_set, dict):
         a, k = (), param_set
     else:
         a, k = param_set, {}
     response = view_func(request, *a, **k)
     if self._is_str(response):
         response = HttpResponse(response)
     elif isinstance(response, TemplateResponse):
         response.render()
     if response.status_code != 200:
         err = 'View returned a non-200 status code: {}'
         raise DistillError(err.format(response.status_code))
     return response
Example #7
0
 def render_view(self, uri, param_set, args):
     if len(args) < 2:
         raise DistillError('Invalid view arguments')
     view_regex, view_func = args[0], args[1]
     request_factory = RequestFactory()
     request = request_factory.get(uri)
     setattr(request, 'session', DummyInterface('request.session'))
     if isinstance(param_set, dict):
         a, k = (), param_set
     else:
         a, k = param_set, {}
     try:
         response = view_func(request, *a, **k)
     except Exception as err:
         e = 'Failed to render view "{}": {}'.format(uri, err)
         raise DistillError(e) from err
     if self._is_str(response):
         response = HttpResponse(response)
     elif isinstance(response, SimpleTemplateResponse):
         response.render()
     if response.status_code != 200:
         err = 'View returned a non-200 status code: {}'
         raise DistillError(err.format(response.status_code))
     return response
Example #8
0
 def generate_uri(self, url, view_name, param_set):
     namespace = namespace_map.get(url, '')
     view_name_ns = namespace + ':' + view_name if namespace else view_name
     if isinstance(param_set, (list, tuple)):
         try:
             uri = reverse(view_name, args=param_set)
         except NoReverseMatch:
             uri = reverse(view_name_ns, args=param_set)
     elif isinstance(param_set, dict):
         try:
             uri = reverse(view_name, kwargs=param_set)
         except NoReverseMatch:
             uri = reverse(view_name_ns, args=param_set)
     else:
         err = 'Distill function returned an invalid type: {}'
         raise DistillError(err.format(type(param_set)))
     return uri
Example #9
0
                    entry.url_patterns, namespace_path + [entry.namespace])
            else:
                url_patterns_resolved += iter_resolved_urls(
                    entry.url_patterns, namespace_path)
        else:
            url_patterns_resolved.append((namespace_path, entry))
    return url_patterns_resolved


for (namespaces, url) in iter_resolved_urls(urlconf.urlpatterns):
    if namespaces:
        nspath = ':'.join(namespaces)
        if url in namespace_map:
            raise DistillError(
                f'Ambiguous namespace for URL "{url}" in namespace '
                f'"{nspath}", Distill does not support the same Django '
                'app being include()ed more than once in the same '
                'project')
        else:
            namespace_map[url] = nspath


class DummyInterface:
    '''
        Implements a dummy interface which raises a warning if any attributes or
        methods are accessed. This is used to replace specific non-implemented features,
        like sessions, which may be in end users site code but has no relevance for
        a static site and can be ignored. As this may be a non-obvious breaking change
        to a users site display a descriptive warning when rendering.
    '''
Example #10
0
 def distill_path(*args, **kwargs):
     err = ('Your installed version of Django ({}) does not supprt '
            'django.urls.path, please upgrade')
     raise DistillError(err.format(django_version))
Example #11
0
 def distill_url(*args, **kwargs):
     err = ('Your installed version of Django ({}) does not supprt '
            'django.urls.url or django.conf.urls.url, use '
            'django_distill.distill_re_path or django_distill.distill_path')
     raise DistillError(err.format(django_version))