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 get_subcategories(generator, metadata): if 'SUBCATEGORY_SAVE_AS' not in generator.settings: generator.settings['SUBCATEGORY_SAVE_AS'] = os.path.join( 'subcategory', '{savepath}.html') if 'SUBCATEGORY_URL' not in generator.settings: generator.settings['SUBCATEGORY_URL'] = 'subcategory/{fullurl}.html' if ('PAGINATED_TEMPLATES' in generator.settings and 'subcategory' not in generator.settings['PAGINATED_TEMPLATES']): generator.settings['PAGINATED_TEMPLATES']['subcategory'] = None if 'subcategory_path' in metadata: category_list = text_type(metadata.get('subcategory_path')).split('/') else: category_list = text_type(metadata.get('category')).split('/') category = (category_list.pop(0)).strip() category = Category(category, generator.settings) metadata['category'] = category #generate a list of subcategories with their parents sub_list = [] parent = category.name for subcategory in category_list: subcategory = parent + '/' + subcategory.strip() sub_list.append(subcategory) parent = subcategory metadata['subcategories'] = sub_list
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 get_subcategories(generator, metadata): if "SUBCATEGORY_SAVE_AS" not in generator.settings: generator.settings["SUBCATEGORY_SAVE_AS"] = os.path.join( "subcategory", "{savepath}.html") if "SUBCATEGORY_URL" not in generator.settings: generator.settings["SUBCATEGORY_URL"] = "subcategory/{fullurl}.html" if ("PAGINATED_TEMPLATES" in generator.settings and "subcategory" not in generator.settings["PAGINATED_TEMPLATES"]): generator.settings["PAGINATED_TEMPLATES"]["subcategory"] = None if "subcategory_path" in metadata: category_list = text_type(metadata.get("subcategory_path")).split("/") else: category_list = text_type(metadata.get("category")).split("/") category = (category_list.pop(0)).strip() category = Category(category, generator.settings) metadata["category"] = category # generate a list of subcategories with their parents sub_list = [] parent = category.name for subcategory in category_list: subcategory = parent + "/" + subcategory.strip() sub_list.append(subcategory) parent = subcategory metadata["subcategories"] = sub_list
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 photoreel(generator): if 'PHOTOREEL' in generator.settings.keys(): if generator.settings['PHOTOREEL'] == False: return 0 else: return 0 if 'SITEURL' in generator.settings.keys(): siteurl = generator.settings['SITEURL'] else: siteurl = "" if 'PHOTOREEL_NUM_ARTICLES' in generator.settings.keys(): maxcount = generator.settings['PHOTOREEL_NUM_ARTICLES'] else: maxcount = 5 if 'PHOTOREEL_TRANSITION_TIME' in generator.settings.keys(): transtime = generator.settings['PHOTOREEL_TRANSITION_TIME'] else: transtime = 1 if 'PHOTOREEL_NEXT_SLIDE_TIME' in generator.settings.keys(): nextslidetime = generator.settings['PHOTOREEL_NEXT_SLIDE_TIME'] else: nextslidetime = 3 count = 0 content = "<div class='photoreel-container'><div class='photoreel-left'><a>⬅</a></div>" dots = "<div class='photoreel-dots'>" for article in generator.articles: if 'archiveloc' in article.metadata.keys( ) and 'mainimg' in article.metadata.keys(): content += "<div class='photoreel-photo photoreel-photo-" + str( count ) + "'><a href='" + siteurl + "/" + article.url + "'><img src='" + os.path.join( article.metadata['archiveloc'], article.metadata['mainimg'] ) + "'><span class='photoreel-title'>" + article.metadata[ 'title'] + "</span></a></div>" dots += "<a class='photoreel-dot photoreel-dot-" + str( count) + "' data-count='" + str(count) + "'></a>" count += 1 if count == maxcount: break content += "<div class='photoreel-right'><a>➡</a></div>" + dots + "</div></div>" content += """ <link rel="stylesheet" href='""" + siteurl + """/theme/css/photoreel.css' type="text/css" /> <script>var maxcount = """ + str(maxcount) + """;var transtime = """ + str( transtime) + """;var nextslidetime = """ + str( nextslidetime) + """;</script> <script src='""" + siteurl + """/theme/js/photoreel.js'></script> """ metadata = { 'title': 'Imperial College Caving Club', 'date': datetime.strptime('9999-12-31', '%Y-%m-%d'), 'category': Category('Photo Reel', generator.settings), 'type': 'stickyindex', 'save_as': 'articles/photo-reel.html' } generator.articles.insert(0, Article(content, metadata))
def _build_article(content='', **metadata): defaults = dict( author=Author(AUTHOR, DEFAULT_CONFIG), category=Category(CATEGORY, DEFAULT_CONFIG), date=DATE, title=HEADLINE, url=ARTICLE_URL, ) defaults.update(metadata) return Article(content=content, settings=DEFAULT_CONFIG, metadata=defaults)
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 process_article(article, category_hash): if not hasattr(article, 'subcategories'): return for subcategory in article.subcategories: if subcategory not in category_hash: category_hash[subcategory] = (Category(subcategory, article.category.settings), []) category_hash[subcategory][1].append(article)
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 get_subcategories(generator, metadata): # get the subcat for a given article? if 'SUBCATEGORY_SAVE_AS' not in generator.settings: generator.settings['SUBCATEGORY_SAVE_AS'] = os.path.join( 'subcategory', '{savepath}.html') if 'SUBCATEGORY_URL' not in generator.settings: generator.settings['SUBCATEGORY_URL'] = 'subcategory/{fullurl}.html' #category_list = text_type(metadata.get('category')).split('/') category_list = text_type(metadata.get('path_no_ext')).split('/')[:-1] category = (category_list.pop(0)).strip() category = Category(category, generator.settings) metadata['category'] = category #generate a list of subcategories with their parents sub_list = [] parent = category.name for subcategory in category_list: subcategory.strip() subcategory = parent + '/' + subcategory sub_list.append(subcategory) parent = subcategory metadata['subcategories'] = sub_list
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')))