def test_equality(self):
        tag = Tag('test', settings={})
        cat = Category('test', settings={})
        author = Author('test', settings={})

        # same name, but different class
        self.assertNotEqual(tag, cat)
        self.assertNotEqual(tag, author)

        # should be equal vs text representing the same name
        self.assertEqual(tag, u'test')

        # should not be equal vs binary
        self.assertNotEqual(tag, b'test')

        # Tags describing the same should be equal
        tag_equal = Tag('Test', settings={})
        self.assertEqual(tag, tag_equal)

        # Author describing the same should be equal
        author_equal = Author('Test', settings={})
        self.assertEqual(author, author_equal)

        cat_ascii = Category('指導書', settings={})
        self.assertEqual(cat_ascii, u'zhi dao shu')
Beispiel #2
0
 def test_tag_cloud_random(self):
     tag_cloud.generate_tag_cloud(self.generator)
     expected = [
             (Tag('plugins', self._settings), 1),
             (Tag('fun', self._settings), 4),
             (Tag('python', self._settings), 4),
             (Tag('pelican', self._settings), 1)
         ]
     six.assertCountEqual(self, self.generator.tag_cloud, expected)
Beispiel #3
0
 def test_tag_cloud_size_rev(self):
     self.generator.settings['TAG_CLOUD_STEPS'] = 10
     self.generator.settings['TAG_CLOUD_SORTING'] = 'size-rev'
     tag_cloud.generate_tag_cloud(self.generator)
     expected = [(Tag('python', self._settings), 10),
                 (Tag('fun', self._settings), 3),
                 (Tag('plugins', self._settings), 2),
                 (Tag('pelican', self._settings), 1)]
     self.assertEqual(self.generator.tag_cloud, expected)
Beispiel #4
0
 def test_tag_cloud_badge(self):
     self.generator.settings['TAG_CLOUD_STEPS'] = 10
     self.generator.settings['TAG_CLOUD_BADGE'] = True
     tag_cloud.generate_tag_cloud(self.generator)
     expected = [(Tag('pelican', self._settings), 1, 5),
                 (Tag('plugins', self._settings), 2, 4),
                 (Tag('fun', self._settings), 3, 3),
                 (Tag('python', self._settings), 10, 1)]
     six.assertCountEqual(self, self.generator.tag_cloud, expected)
Beispiel #5
0
 def test_tag_cloud_random(self):
     self.generator.settings['TAG_CLOUD_STEPS'] = 10
     self.generator.settings['TAG_CLOUD_BADGE'] = False
     tag_cloud.generate_tag_cloud(self.generator)
     expected = [(Tag('pelican', self._settings), 1),
                 (Tag('plugins', self._settings), 2),
                 (Tag('fun', self._settings), 3),
                 (Tag('python', self._settings), 10)]
     six.assertCountEqual(self, self.generator.tag_cloud, expected)
Beispiel #6
0
 def test_tag_cloud_size(self):
     self.generator.settings['TAG_CLOUD_SORTING'] = 'size'
     tag_cloud.generate_tag_cloud(self.generator)
     expected = [
             (Tag('pelican', self._settings), 1),
             (Tag('plugins', self._settings), 1),
             (Tag('fun', self._settings), 4),
             (Tag('python', self._settings), 4)
         ]
     self.assertEqual(self.generator.tag_cloud, expected)
Beispiel #7
0
 def test_tag_cloud_size(self):
     self.generator.settings["TAG_CLOUD_STEPS"] = 10
     self.generator.settings["TAG_CLOUD_SORTING"] = "size"
     tag_cloud.generate_tag_cloud(self.generator)
     expected = [
         (Tag("pelican", self._settings), 1),
         (Tag("plugins", self._settings), 2),
         (Tag("fun", self._settings), 3),
         (Tag("python", self._settings), 10),
     ]
     self.assertEqual(self.generator.tag_cloud, expected)
Beispiel #8
0
 def test_tag_cloud_badge(self):
     self.generator.settings["TAG_CLOUD_STEPS"] = 10
     self.generator.settings["TAG_CLOUD_BADGE"] = True
     tag_cloud.generate_tag_cloud(self.generator)
     expected = [
         (Tag("pelican", self._settings), 1, 5),
         (Tag("plugins", self._settings), 2, 4),
         (Tag("fun", self._settings), 3, 3),
         (Tag("python", self._settings), 10, 1),
     ]
     six.assertCountEqual(self, self.generator.tag_cloud, expected)
Beispiel #9
0
        def replacer(m):
            what = m.group('what')
            value = m.group('value')
            origin = m.group('path')

            # we support only filename for now. the plan is to support
            # categories, tags, etc. in the future, but let's keep things
            # simple for now.

            # XXX Put this in a different location.
            if what == 'filename':
                if value.startswith('/'):
                    value = value[1:]
                else:
                    # relative to the source path of this content
                    value = self.get_relative_source_path(
                        os.path.join(self.relative_dir, value)
                    )

                if value in self._context['filenames']:
                    origin = '/'.join((siteurl,
                             self._context['filenames'][value].url))
                    origin = origin.replace('\\', '/')  # Fow windows paths.
                else:
                    logger.warning("Unable to find {fn}, skipping url"
                                   " replacement".format(fn=value))
            elif what == 'category':
                origin = Category(value, self.settings).url
            elif what == 'tag':
                origin = Tag(value, self.settings).url

            return ''.join((m.group('markup'), m.group('quote'), origin,
                            m.group('quote')))
Beispiel #10
0
        def replacer(m):
            what = m.group('what')
            value = urlparse(m.group('value'))
            path = value.path
            origin = m.group('path')

            # XXX Put this in a different location.
            if what == 'filename':
                if path.startswith('/'):
                    path = path[1:]
                else:
                    # relative to the source path of this content
                    path = self.get_relative_source_path(
                        os.path.join(self.relative_dir, path))

                if path in self._context['filenames']:
                    origin = '/'.join(
                        (siteurl, self._context['filenames'][path].url))
                    origin = origin.replace('\\', '/')  # for Windows paths.
                else:
                    logger.warning("Unable to find {fn}, skipping url"
                                   " replacement".format(fn=path))
            elif what == 'category':
                origin = Category(path, self.settings).url
            elif what == 'tag':
                origin = Tag(path, self.settings).url

            # keep all other parts, such as query, fragment, etc.
            parts = list(value)
            parts[2] = origin
            origin = urlunparse(parts)

            return ''.join((m.group('markup'), m.group('quote'), origin,
                            m.group('quote')))
Beispiel #11
0
    def __init__(self, tag_names=None, date=()):
        if tag_names:
            self.tags = [Tag(name=name, settings={}) for name in tag_names]

        if date:
            self.date = datetime.datetime(*date)
        else:
            self.date = datetime.datetime(1970, 1, 1)
Beispiel #12
0
        def replacer(m):
            what = m.group('what')
            value = urlparse(m.group('value'))
            path = value.path
            origin = m.group('path')

            # XXX Put this in a different location.
            if what in {'filename', 'attach'}:
                if path.startswith('/'):
                    path = path[1:]
                else:
                    # relative to the source path of this content
                    path = self.get_relative_source_path(
                        os.path.join(self.relative_dir, path))

                if path not in self._context['filenames']:
                    unquoted_path = path.replace('%20', ' ')

                    if unquoted_path in self._context['filenames']:
                        path = unquoted_path

                linked_content = self._context['filenames'].get(path)
                if linked_content:
                    if what == 'attach':
                        if isinstance(linked_content, Static):
                            linked_content.attach_to(self)
                        else:
                            logger.warning(
                                "%s used {attach} link syntax on a "
                                "non-static file. Use {filename} instead.",
                                self.get_relative_source_path())
                    origin = '/'.join((siteurl, linked_content.url))
                    origin = origin.replace('\\', '/')  # for Windows paths.
                else:
                    logger.warning(
                        "Unable to find `%s`, skipping url replacement.",
                        value.geturl(),
                        extra={
                            'limit_msg': ("Other resources were not found "
                                          "and their urls not replaced")
                        })
            elif what == 'category':
                origin = '/'.join((siteurl, Category(path, self.settings).url))
            elif what == 'tag':
                origin = '/'.join((siteurl, Tag(path, self.settings).url))
            else:
                logger.warning(
                    "Replacement Indicator '%s' not recognized, "
                    "skipping replacement", what)

            # keep all other parts, such as query, fragment, etc.
            parts = list(value)
            parts[2] = origin
            origin = urlunparse(parts)

            return ''.join((m.group('markup'), m.group('quote'), origin,
                            m.group('quote')))
    def test_slugify_with_substitutions_and_dots(self):
        tag = Tag('Tag Dot', settings={'TAG_REGEX_SUBSTITUTIONS': [
            ('Tag Dot', 'tag.dot'),
        ]})
        cat = Category('Category Dot',
                       settings={'CATEGORY_REGEX_SUBSTITUTIONS': [
                           ('Category Dot', 'cat.dot'),
                       ]})

        self.assertEqual(tag.slug, 'tag.dot')
        self.assertEqual(cat.slug, 'cat.dot')
Beispiel #14
0
        def replacer(m):
            what = m.group('what')
            value = urlparse(m.group('value'))
            path = value.path
            origin = m.group('path')

            # XXX Put this in a different location.
            if what == 'filename':
                if path.startswith('/'):
                    path = path[1:]
                else:
                    # relative to the source path of this content
                    path = self.get_relative_source_path(
                        os.path.join(self.relative_dir, path))

                if path not in self._context['filenames']:
                    unquoted_path = path.replace('%20', ' ')

                    if unquoted_path in self._context['filenames']:
                        path = unquoted_path

                if path in self._context['filenames']:
                    origin = '/'.join(
                        (siteurl, self._context['filenames'][path].url))
                    origin = origin.replace('\\', '/')  # for Windows paths.
                else:
                    logger.warning(
                        "Unable to find `%s`, skipping url replacement.",
                        value.geturl(),
                        extra={
                            'limit_msg': ("Other resources were not found "
                                          "and their urls not replaced")
                        })
            elif what == 'category':
                origin = Category(path, self.settings).url
            elif what == 'tag':
                origin = Tag(path, self.settings).url

            # keep all other parts, such as query, fragment, etc.
            parts = list(value)
            parts[2] = origin
            origin = urlunparse(parts)

            return ''.join((m.group('markup'), m.group('quote'), origin,
                            m.group('quote')))
Beispiel #15
0
    def _link_replacer(self, siteurl, m):
        what = m.group('what')
        value = urlparse(m.group('value'))
        path = value.path
        origin = m.group('path')

        # urllib.parse.urljoin() produces `a.html` for urljoin("..", "a.html")
        # so if RELATIVE_URLS are enabled, we fall back to os.path.join() to
        # properly get `../a.html`. However, os.path.join() produces
        # `baz/http://foo/bar.html` for join("baz", "http://foo/bar.html")
        # instead of correct "http://foo/bar.html", so one has to pick a side
        # as there is no silver bullet.
        if self.settings['RELATIVE_URLS']:
            joiner = os.path.join
        else:
            joiner = urljoin

            # However, it's not *that* simple: urljoin("blog", "index.html")
            # produces just `index.html` instead of `blog/index.html` (unlike
            # os.path.join()), so in order to get a correct answer one needs to
            # append a trailing slash to siteurl in that case. This also makes
            # the new behavior fully compatible with Pelican 3.7.1.
            if not siteurl.endswith('/'):
                siteurl += '/'

        # XXX Put this in a different location.
        if what in {'filename', 'static', 'attach'}:

            def _get_linked_content(key, url):
                nonlocal value

                def _find_path(path):
                    if path.startswith('/'):
                        path = path[1:]
                    else:
                        # relative to the source path of this content
                        path = self.get_relative_source_path(
                            os.path.join(self.relative_dir, path))
                    return self._context[key].get(path, None)

                # try path
                result = _find_path(url.path)
                if result is not None:
                    return result

                # try unquoted path
                result = _find_path(unquote(url.path))
                if result is not None:
                    return result

                # try html unescaped url
                unescaped_url = urlparse(unescape(url.geturl()))
                result = _find_path(unescaped_url.path)
                if result is not None:
                    value = unescaped_url
                    return result

                # check if a static file is linked with {filename}
                if what == 'filename' and key == 'generated_content':
                    linked_content = _get_linked_content(
                        'static_content', value)
                    if linked_content:
                        logger.warning(
                            '{filename} used for linking to static'
                            ' content %s in %s. Use {static} instead',
                            value.path, self.get_relative_source_path())
                        return linked_content

                return None

            if what == 'filename':
                key = 'generated_content'
            else:
                key = 'static_content'

            linked_content = _get_linked_content(key, value)
            if linked_content:
                if what == 'attach':
                    linked_content.attach_to(self)
                origin = joiner(siteurl, linked_content.url)
                origin = origin.replace('\\', '/')  # for Windows paths.
            else:
                logger.warning(
                    "Unable to find '%s', skipping url replacement.",
                    value.geturl(),
                    extra={
                        'limit_msg': ("Other resources were not found "
                                      "and their urls not replaced")
                    })
        elif what == 'category':
            origin = joiner(siteurl, Category(path, self.settings).url)
        elif what == 'tag':
            origin = joiner(siteurl, Tag(path, self.settings).url)
        elif what == 'index':
            origin = joiner(siteurl, self.settings['INDEX_SAVE_AS'])
        elif what == 'author':
            origin = joiner(siteurl, Author(path, self.settings).url)
        else:
            logger.warning(
                "Replacement Indicator '%s' not recognized, "
                "skipping replacement", what)

        # keep all other parts, such as query, fragment, etc.
        parts = list(value)
        parts[2] = origin
        origin = urlunparse(parts)

        return ''.join(
            (m.group('markup'), m.group('quote'), origin, m.group('quote')))
Beispiel #16
0
    def parse_jpeg(self, *, source_path: str) -> Tuple[str, dict]:
        JpegReader.logger.info(source_path)

        img = Image.open(source_path)

        image_data = Exiv2Parser.get_values(source_path)

        title = image_data.get(Exiv.DESCRIPTION.value, 'Untitled')
        author = image_data.get(Exiv.ARTIST.value, 'Unknown')
        date_string = image_data.get(Exiv.DATETIME.value, '')

        date = datetime.strptime(date_string, "%Y:%m:%d %H:%M:%S")
        slug = URLWrapper(image_data.get(Exiv.HEADLINE.value, title),
                          self.settings).slug
        description_long = image_data.get(Exiv.COMMENT.value, '')
        summary = image_data.get(Exiv.CAPTION.value, description_long[:140])

        tags = [
            Tag(tag, self.settings)
            for tag in image_data.get(Exiv.KEYWORDS.value, list())
        ]

        content_root = self.settings[PelicanConfig.PATH.value]
        path_output = self.settings[PelicanConfig.OUTPUT_PATH.value]
        relative_source = dirname(source_path[len(content_root):]).lstrip(sep)
        if self.settings[PelicanConfig.USE_FOLDER_AS_CATEGORY.value]:
            category = relative_source.split(sep)[-1]
        else:
            category = image_data.get(Exiv.CATEGORY.value, None)

        type_of_content = relative_source.split(sep)[
            0]  # either 'blog' or 'pages' as far as I know.
        url_site = self.settings[PelicanConfig.SITE_URL.value]

        if type_of_content.lower() == PelicanClass.PAGES.value:
            url_document = self.settings[PelicanConfig.PAGE_URL.value]
            document_save_as = self.settings[PelicanConfig.PAGE_SAVE_AS.value]
        else:  # Assume PelicanClass.BLOG
            url_document = self.settings[PelicanConfig.ARTICLE_URL.value]
            document_save_as = self.settings[
                PelicanConfig.ARTICLE_SAVE_AS.value]

        page_url_complete = join(url_site, url_document)

        author_wrapper = Author(author, self.settings)

        # Move image in place:
        metadata = {
            PelicanMetadata.TITLE.value: title,
            PelicanMetadata.AUTHORS.value: [author_wrapper],
            PelicanMetadata.DATE.value: date,
            PelicanMetadata.SLUG.value: slug,
            PelicanMetadata.TAGS.value: tags,
            PelicanMetadata.CUSTOM_ALL.value: image_data
        }
        if category is not None:
            metadata[PelicanMetadata.CATEGORY.value] = Category(
                category, self.settings)

        thumb_name = '{0}_thumb.jpg'.format(slug)
        original_name = '{0}.jpg'.format(slug)

        path_output_html = join(path_output,
                                document_save_as).format(**metadata)
        path_output_dir = dirname(path_output_html)
        path_output_original = join(path_output_dir, original_name)
        path_output_thumb = join(path_output_dir, thumb_name)

        # Here we generate the summary info incase this is used for articles we get nice thumbnails and summary
        metadata[PelicanMetadata.SUMMARY.value] = summary
        metadata[PelicanMetadata.FEATURED_IMAGE.value] = join(
            url_site, path_output_thumb[len(path_output):])
        if Exiv.OBJECT_NAME.value in image_data:
            metadata[PelicanMetadata.TEMPLATE.value] = image_data[
                Exiv.OBJECT_NAME.value]

        # Write the size/HTML out before we reduce the image to a thumb
        content = "<img src='{src}' alt='{alt}' style='width: {width}px; height: auto; max-width: 100%;'></img><p>{body}</p>" \
            .format(src=original_name, alt=title, width=img.width, height=img.height, body=description_long)

        # Ensure the directory levels exist
        if not isdir(path_output_dir):
            makedirs(path_output_dir)
        img.save(path_output_original)
        img.thumbnail(self.thumb_size)
        img.save(path_output_thumb)

        # Debug info if we need it
        JpegReader.logger.debug(content)
        JpegReader.logger.debug(str(metadata))
        JpegReader.logger.debug(path_output_html)

        return content, metadata
Beispiel #17
0
    def _link_replacer(self, siteurl, m):
        what = m.group('what')
        value = urlparse(m.group('value'))
        path = value.path
        origin = m.group('path')

        # urllib.parse.urljoin() produces `a.html` for urljoin("..", "a.html")
        # so if RELATIVE_URLS are enabled, we fall back to os.path.join() to
        # properly get `../a.html`. However, os.path.join() produces
        # `baz/http://foo/bar.html` for join("baz", "http://foo/bar.html")
        # instead of correct "http://foo/bar.html", so one has to pick a side
        # as there is no silver bullet.
        if self.settings['RELATIVE_URLS']:
            joiner = os.path.join
        else:
            joiner = urljoin

            # However, it's not *that* simple: urljoin("blog", "index.html")
            # produces just `index.html` instead of `blog/index.html` (unlike
            # os.path.join()), so in order to get a correct answer one needs to
            # append a trailing slash to siteurl in that case. This also makes
            # the new behavior fully compatible with Pelican 3.7.1.
            if not siteurl.endswith('/'):
                siteurl += '/'

        # XXX Put this in a different location.
        if what in {'filename', 'attach'}:
            if path.startswith('/'):
                path = path[1:]
            else:
                # relative to the source path of this content
                path = self.get_relative_source_path(
                    os.path.join(self.relative_dir, path))

            if path not in self._context['filenames']:
                unquoted_path = path.replace('%20', ' ')

                if unquoted_path in self._context['filenames']:
                    path = unquoted_path

            linked_content = self._context['filenames'].get(path)
            if linked_content:
                if what == 'attach':
                    if isinstance(linked_content, Static):
                        linked_content.attach_to(self)
                    else:
                        logger.warning(
                            "%s used {attach} link syntax on a "
                            "non-static file. Use {filename} instead.",
                            self.get_relative_source_path())
                origin = joiner(siteurl, linked_content.url)
                origin = origin.replace('\\', '/')  # for Windows paths.
            else:
                logger.warning(
                    "Unable to find '%s', skipping url replacement.",
                    value.geturl(),
                    extra={
                        'limit_msg': ("Other resources were not found "
                                      "and their urls not replaced")
                    })
        elif what == 'category':
            origin = joiner(siteurl, Category(path, self.settings).url)
        elif what == 'tag':
            origin = joiner(siteurl, Tag(path, self.settings).url)
        elif what == 'index':
            origin = joiner(siteurl, self.settings['INDEX_SAVE_AS'])
        elif what == 'author':
            origin = joiner(siteurl, Author(path, self.settings).url)
        else:
            logger.warning(
                "Replacement Indicator '%s' not recognized, "
                "skipping replacement", what)

        # keep all other parts, such as query, fragment, etc.
        parts = list(value)
        parts[2] = origin
        origin = urlunparse(parts)

        return ''.join(
            (m.group('markup'), m.group('quote'), origin, m.group('quote')))