aboutsummaryrefslogtreecommitdiffstats
path: root/nikola/utils.py
diff options
context:
space:
mode:
authorLibravatarAgustin Henze <tin@sluc.org.ar>2013-03-13 20:58:39 -0300
committerLibravatarAgustin Henze <tin@sluc.org.ar>2013-03-13 20:58:39 -0300
commit1004b9f3c61574acbdb3ec2f303d35307949fb7e (patch)
tree3ae41121a82650e6889fda82a4316f989dfc0b4b /nikola/utils.py
parent1c7c74d71f5dc9d13d029c9df8d46f27907a7503 (diff)
parent8b14a1e5b2ca574fdd4fd2377567ec98a110d4b6 (diff)
Merge tag 'upstream/5.4.2'
Upstream version 5.4.2
Diffstat (limited to 'nikola/utils.py')
-rw-r--r--nikola/utils.py161
1 files changed, 37 insertions, 124 deletions
diff --git a/nikola/utils.py b/nikola/utils.py
index eeb0c45..5589d68 100644
--- a/nikola/utils.py
+++ b/nikola/utils.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
# Copyright (c) 2012 Roberto Alsina y otros.
# Permission is hereby granted, free of charge, to any
@@ -33,7 +34,6 @@ import re
import codecs
import json
import shutil
-import string
import subprocess
import sys
from zipfile import ZipFile as zip
@@ -42,6 +42,7 @@ try:
except ImportError:
pass
+import pytz
if sys.version_info[0] == 3:
# Python 3
@@ -50,7 +51,7 @@ if sys.version_info[0] == 3:
unichr = chr
else:
bytes_str = str
- unicode_str = unicode
+ unicode_str = unicode # NOQA
from doit import tools
from unidecode import unidecode
@@ -58,9 +59,8 @@ from unidecode import unidecode
import PyRSS2Gen as rss
__all__ = ['get_theme_path', 'get_theme_chain', 'load_messages', 'copy_tree',
- 'generic_rss_renderer',
- 'copy_file', 'slugify', 'unslugify', 'get_meta', 'to_datetime',
- 'apply_filters', 'config_changed', 'get_crumbs']
+ 'generic_rss_renderer', 'copy_file', 'slugify', 'unslugify',
+ 'to_datetime', 'apply_filters', 'config_changed', 'get_crumbs']
class CustomEncoder(json.JSONEncoder):
@@ -86,13 +86,13 @@ class config_changed(tools.config_changed):
byte_data = data
return hashlib.md5(byte_data).hexdigest()
else:
- raise Exception(
- ('Invalid type of config_changed parameter got %s' +
- ', must be string or dict') % (type(self.config),))
+ raise Exception('Invalid type of config_changed parameter -- got '
+ '{0}, must be string or dict'.format(type(
+ self.config)))
def __repr__(self):
- return "Change with config: %s" % json.dumps(
- self.config, cls=CustomEncoder)
+ return "Change with config: {0}".format(json.dumps(self.config,
+ cls=CustomEncoder))
def get_theme_path(theme):
@@ -107,111 +107,7 @@ def get_theme_path(theme):
'data', 'themes', theme)
if os.path.isdir(dir_name):
return dir_name
- raise Exception("Can't find theme '%s'" % theme)
-
-
-def re_meta(line, match):
- """re.compile for meta"""
- reStr = re.compile('^%s(.*)' % re.escape(match))
- result = reStr.findall(line)
- if result:
- return result[0].strip()
- else:
- return ''
-
-
-def _get_metadata_from_filename_by_regex(filename, metadata_regexp):
- """
- Tries to ried the metadata from the filename based on the given re.
- This requires to use symbolic group names in the pattern.
-
- The part to read the metadata from the filename based on a regular
- expression is taken from Pelican - pelican/readers.py
- """
- title = slug = date = tags = link = description = ''
- match = re.match(metadata_regexp, filename)
- if match:
- # .items() for py3k compat.
- for key, value in match.groupdict().items():
- key = key.lower() # metadata must be lowercase
-
- if key == 'title':
- title = value
- if key == 'slug':
- slug = value
- if key == 'date':
- date = value
- if key == 'tags':
- tags = value
- if key == 'link':
- link = value
- if key == 'description':
- description = value
-
- return (title, slug, date, tags, link, description)
-
-
-def _get_metadata_from_file(source_path, title='', slug='', date='', tags='',
- link='', description=''):
- re_md_title = re.compile(r'^%s([^%s].*)' %
- (re.escape('#'), re.escape('#')))
- # Assuming rst titles are going to be at least 4 chars long
- # otherwise this detects things like ''' wich breaks other markups.
- re_rst_title = re.compile(r'^([%s]{4,})' % re.escape(string.punctuation))
-
- with codecs.open(source_path, "r", "utf8") as meta_file:
- meta_data = meta_file.readlines(15)
-
- for i, meta in enumerate(meta_data):
- if not title:
- title = re_meta(meta, '.. title:')
- if not title:
- if re_rst_title.findall(meta) and i > 0:
- title = meta_data[i - 1].strip()
- if not title:
- if re_md_title.findall(meta):
- title = re_md_title.findall(meta)[0]
- if not slug:
- slug = re_meta(meta, '.. slug:')
- if not date:
- date = re_meta(meta, '.. date:')
- if not tags:
- tags = re_meta(meta, '.. tags:')
- if not link:
- link = re_meta(meta, '.. link:')
- if not description:
- description = re_meta(meta, '.. description:')
-
- return (title, slug, date, tags, link, description)
-
-
-def get_meta(source_path, file_metadata_regexp=None):
- """Get post's meta from source.
-
- If ``file_metadata_regexp`` ist given it will be tried to read
- metadata from the filename.
- If any metadata is then found inside the file the metadata from the
- file will override previous findings.
- """
- title = slug = date = tags = link = description = ''
-
- if not (file_metadata_regexp is None):
- (title, slug, date, tags, link,
- description) = _get_metadata_from_filename_by_regex(
- source_path, file_metadata_regexp)
-
- (title, slug, date, tags, link, description) = _get_metadata_from_file(
- source_path, title, slug, date, tags, link, description)
-
- if not slug:
- # If no slug is found in the metadata use the filename
- slug = slugify(os.path.splitext(os.path.basename(source_path))[0])
-
- if not title:
- # If no title is found, use the filename without extension
- title = os.path.splitext(os.path.basename(source_path))[0]
-
- return (title, slug, date, tags, link, description)
+ raise Exception("Can't find theme '{0}'".format(theme))
def get_template_engine(themes):
@@ -267,8 +163,8 @@ def load_messages(themes, translations):
sorted(english.MESSAGES.keys()) and \
lang not in warned:
# FIXME: get real logging in place
- print("Warning: Incomplete translation for language '%s'." %
- lang)
+ print("Warning: Incomplete translation for language "
+ "'{0}'.".format(lang))
warned.append(lang)
messages[lang].update(english.MESSAGES)
messages[lang].update(translation.MESSAGES)
@@ -325,7 +221,9 @@ def generic_rss_renderer(lang, title, link, description, timeline, output_path,
'link': post.permalink(lang, absolute=True),
'description': post.text(lang, teaser_only=rss_teasers),
'guid': post.permalink(lang, absolute=True),
- 'pubDate': post.date,
+ # PyRSS2Gen's pubDate is GMT time.
+ 'pubDate': (post.date if post.date.tzinfo is None else
+ post.date.astimezone(pytz.timezone('UTC'))),
}
items.append(rss.RSSItem(**args))
rss_obj = rss.RSS2(
@@ -386,6 +284,16 @@ def slugify(value):
and converts spaces to hyphens.
From Django's "django/template/defaultfilters.py".
+
+ >>> slugify('\xe1\xe9\xed.\xf3\xfa')
+ 'aeiou'
+
+ >>> slugify('foo/bar')
+ 'foobar'
+
+ >>> slugify('foo bar')
+ 'foo-bar'
+
"""
value = unidecode(value)
# WARNING: this may not be python2/3 equivalent
@@ -418,22 +326,23 @@ def extract_all(zipfile):
namelist = z.namelist()
for f in namelist:
if f.endswith('/') and '..' in f:
- raise UnsafeZipException(
- 'The zip file contains ".." and is not safe to expand.')
+ raise UnsafeZipException('The zip file contains ".." and is '
+ 'not safe to expand.')
for f in namelist:
if f.endswith('/'):
if not os.path.isdir(f):
try:
os.makedirs(f)
except:
- raise OSError("mkdir '%s' error!" % f)
+ raise OSError("Failed making {0} directory "
+ "tree!".format(f))
else:
z.extract(f)
os.chdir(pwd)
# From https://github.com/lepture/liquidluck/blob/develop/liquidluck/utils.py
-def to_datetime(value):
+def to_datetime(value, tzinfo=None):
if isinstance(value, datetime.datetime):
return value
supported_formats = [
@@ -451,10 +360,14 @@ def to_datetime(value):
]
for format in supported_formats:
try:
- return datetime.datetime.strptime(value, format)
+ dt = datetime.datetime.strptime(value, format)
+ if tzinfo is None:
+ return dt
+ # Build a localized time by using a given timezone.
+ return tzinfo.localize(dt)
except ValueError:
pass
- raise ValueError('Unrecognized date/time: %r' % value)
+ raise ValueError('Unrecognized date/time: {0!r}'.format(value))
def apply_filters(task, filters):