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')
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)
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)
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)
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)
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)
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)
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)
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')))
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')))
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)
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')
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')))
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')))
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
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')))