forked from github/pelican
Merge pull request #2649 from iKevinY/py2-sunset
Remove Python 2 support
This commit is contained in:
commit
772005f431
45 changed files with 203 additions and 627 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -11,7 +11,6 @@ tags
|
|||
.tox
|
||||
.coverage
|
||||
htmlcov
|
||||
six-*.egg/
|
||||
*.orig
|
||||
venv
|
||||
samples/output
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ env:
|
|||
matrix:
|
||||
- TOX_ENV=docs
|
||||
- TOX_ENV=flake8
|
||||
- TOX_ENV=py27
|
||||
- TOX_ENV=py35
|
||||
- TOX_ENV=py36
|
||||
matrix:
|
||||
|
|
|
|||
2
THANKS
2
THANKS
|
|
@ -92,6 +92,7 @@ Joshua Adelman
|
|||
Julian Berman
|
||||
Justin Mayer
|
||||
Kevin Deldycke
|
||||
Kevin Yap
|
||||
Kyle Fuller
|
||||
Laureline Guerin
|
||||
Leonard Huang
|
||||
|
|
@ -117,6 +118,7 @@ Nico Di Rocco
|
|||
Nicolas Duhamel
|
||||
Nicolas Perriault
|
||||
Nicolas Steinmetz
|
||||
Paolo Melchiorre
|
||||
Paul Asselin
|
||||
Pavel Puchkin
|
||||
Perry Roper
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
|
|
|||
|
|
@ -1,12 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
try:
|
||||
import collections.abc as collections
|
||||
except ImportError:
|
||||
import collections
|
||||
import locale
|
||||
import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
|
|
@ -14,8 +8,7 @@ import pprint
|
|||
import sys
|
||||
import time
|
||||
import traceback
|
||||
|
||||
import six
|
||||
from collections.abc import Iterable
|
||||
|
||||
# pelican.log has to be the first pelican module to be loaded
|
||||
# because logging.setLoggerClass has to be called before logging.getLogger
|
||||
|
|
@ -76,11 +69,10 @@ class Pelican(object):
|
|||
sys.path.insert(0, pluginpath)
|
||||
for plugin in self.settings['PLUGINS']:
|
||||
# if it's a string, then import it
|
||||
if isinstance(plugin, six.string_types):
|
||||
if isinstance(plugin, str):
|
||||
logger.debug("Loading plugin `%s`", plugin)
|
||||
try:
|
||||
plugin = __import__(plugin, globals(), locals(),
|
||||
str('module'))
|
||||
plugin = __import__(plugin, globals(), locals(), 'module')
|
||||
except ImportError as e:
|
||||
logger.error(
|
||||
"Cannot load plugin `%s`\n%s", plugin, e)
|
||||
|
|
@ -189,7 +181,7 @@ class Pelican(object):
|
|||
for pair in signals.get_generators.send(self):
|
||||
(funct, value) = pair
|
||||
|
||||
if not isinstance(value, collections.Iterable):
|
||||
if not isinstance(value, Iterable):
|
||||
value = (value, )
|
||||
|
||||
for v in value:
|
||||
|
|
@ -375,15 +367,6 @@ def get_config(args):
|
|||
config['BIND'] = args.bind
|
||||
config['DEBUG'] = args.verbosity == logging.DEBUG
|
||||
|
||||
# argparse returns bytes in Py2. There is no definite answer as to which
|
||||
# encoding argparse (or sys.argv) uses.
|
||||
# "Best" option seems to be locale.getpreferredencoding()
|
||||
# http://mail.python.org/pipermail/python-list/2006-October/405766.html
|
||||
if not six.PY3:
|
||||
enc = locale.getpreferredencoding()
|
||||
for key in config:
|
||||
if key in ('PATH', 'OUTPUT_PATH', 'THEME'):
|
||||
config[key] = config[key].decode(enc)
|
||||
return config
|
||||
|
||||
|
||||
|
|
@ -397,7 +380,7 @@ def get_instance(args):
|
|||
settings = read_settings(config_file, override=get_config(args))
|
||||
|
||||
cls = settings['PELICAN_CLASS']
|
||||
if isinstance(cls, six.string_types):
|
||||
if isinstance(cls, str):
|
||||
module, cls_name = cls.rsplit('.', 1)
|
||||
module = __import__(module)
|
||||
cls = getattr(module, cls_name)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
"""
|
||||
python -m pelican module entry point to run via python -m
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
from . import main
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
|
||||
from six.moves import cPickle as pickle
|
||||
import pickle
|
||||
|
||||
from pelican.utils import mkdir_p
|
||||
|
||||
|
|
@ -82,9 +80,7 @@ class FileStampDataCacher(FileDataCacher):
|
|||
and base path for filestamping operations
|
||||
"""
|
||||
|
||||
super(FileStampDataCacher, self).__init__(settings, cache_name,
|
||||
caching_policy,
|
||||
load_policy)
|
||||
super().__init__(settings, cache_name, caching_policy, load_policy)
|
||||
|
||||
method = self.settings['CHECK_MODIFIED_METHOD']
|
||||
if method == 'mtime':
|
||||
|
|
@ -106,7 +102,7 @@ class FileStampDataCacher(FileDataCacher):
|
|||
def cache_data(self, filename, data):
|
||||
"""Cache stamp and data for the given file"""
|
||||
stamp = self._get_file_stamp(filename)
|
||||
super(FileStampDataCacher, self).cache_data(filename, (stamp, data))
|
||||
super().cache_data(filename, (stamp, data))
|
||||
|
||||
def _get_file_stamp(self, filename):
|
||||
"""Check if the given file has been modified
|
||||
|
|
@ -134,8 +130,7 @@ class FileStampDataCacher(FileDataCacher):
|
|||
and current file stamp.
|
||||
"""
|
||||
|
||||
stamp, data = super(FileStampDataCacher, self).get_cached_data(
|
||||
filename, (None, default))
|
||||
stamp, data = super().get_cached_data(filename, (None, default))
|
||||
if stamp != self._get_file_stamp(filename):
|
||||
return default
|
||||
return data
|
||||
|
|
|
|||
|
|
@ -1,25 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import copy
|
||||
import datetime
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from urllib.parse import urljoin, urlparse, urlunparse
|
||||
|
||||
import pytz
|
||||
|
||||
import six
|
||||
from six.moves.urllib.parse import urljoin, urlparse, urlunparse
|
||||
|
||||
from pelican import signals
|
||||
from pelican.settings import DEFAULT_CONFIG
|
||||
from pelican.utils import (SafeDatetime, deprecated_attribute, memoized,
|
||||
path_to_url, posixize_path,
|
||||
python_2_unicode_compatible, sanitised_join,
|
||||
set_date_tzinfo, slugify, strftime,
|
||||
truncate_html_words)
|
||||
from pelican.utils import (deprecated_attribute, memoized, path_to_url,
|
||||
posixize_path, sanitised_join, set_date_tzinfo,
|
||||
slugify, truncate_html_words)
|
||||
|
||||
# Import these so that they're avalaible when you import from pelican.contents.
|
||||
from pelican.urlwrappers import (Author, Category, Tag, URLWrapper) # NOQA
|
||||
|
|
@ -27,7 +22,6 @@ from pelican.urlwrappers import (Author, Category, Tag, URLWrapper) # NOQA
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Content(object):
|
||||
"""Represents a content.
|
||||
|
||||
|
|
@ -121,9 +115,6 @@ class Content(object):
|
|||
|
||||
if isinstance(self.date_format, tuple):
|
||||
locale_string = self.date_format[0]
|
||||
if sys.version_info < (3, ) and isinstance(locale_string,
|
||||
six.text_type):
|
||||
locale_string = locale_string.encode('ascii')
|
||||
locale.setlocale(locale.LC_ALL, locale_string)
|
||||
self.date_format = self.date_format[1]
|
||||
|
||||
|
|
@ -133,11 +124,11 @@ class Content(object):
|
|||
|
||||
if hasattr(self, 'date'):
|
||||
self.date = set_date_tzinfo(self.date, timezone)
|
||||
self.locale_date = strftime(self.date, self.date_format)
|
||||
self.locale_date = self.date.strftime(self.date_format)
|
||||
|
||||
if hasattr(self, 'modified'):
|
||||
self.modified = set_date_tzinfo(self.modified, timezone)
|
||||
self.locale_modified = strftime(self.modified, self.date_format)
|
||||
self.locale_modified = self.modified.strftime(self.date_format)
|
||||
|
||||
# manage status
|
||||
if not hasattr(self, 'status'):
|
||||
|
|
@ -213,7 +204,7 @@ class Content(object):
|
|||
'path': path_to_url(path),
|
||||
'slug': getattr(self, 'slug', ''),
|
||||
'lang': getattr(self, 'lang', 'en'),
|
||||
'date': getattr(self, 'date', SafeDatetime.now()),
|
||||
'date': getattr(self, 'date', datetime.datetime.now()),
|
||||
'author': self.author.slug if hasattr(self, 'author') else '',
|
||||
'category': self.category.slug if hasattr(self, 'category') else ''
|
||||
})
|
||||
|
|
@ -497,7 +488,7 @@ class Page(Content):
|
|||
|
||||
def _expand_settings(self, key):
|
||||
klass = 'draft_page' if self.status == 'draft' else None
|
||||
return super(Page, self)._expand_settings(key, klass)
|
||||
return super()._expand_settings(key, klass)
|
||||
|
||||
|
||||
class Article(Content):
|
||||
|
|
@ -507,34 +498,33 @@ class Article(Content):
|
|||
default_template = 'article'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Article, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# handle WITH_FUTURE_DATES (designate article to draft based on date)
|
||||
if not self.settings['WITH_FUTURE_DATES'] and hasattr(self, 'date'):
|
||||
if self.date.tzinfo is None:
|
||||
now = SafeDatetime.now()
|
||||
now = datetime.datetime.now()
|
||||
else:
|
||||
now = SafeDatetime.utcnow().replace(tzinfo=pytz.utc)
|
||||
now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
|
||||
if self.date > now:
|
||||
self.status = 'draft'
|
||||
|
||||
# if we are a draft and there is no date provided, set max datetime
|
||||
if not hasattr(self, 'date') and self.status == 'draft':
|
||||
self.date = SafeDatetime.max
|
||||
self.date = datetime.datetime.max
|
||||
|
||||
def _expand_settings(self, key):
|
||||
klass = 'draft' if self.status == 'draft' else 'article'
|
||||
return super(Article, self)._expand_settings(key, klass)
|
||||
return super()._expand_settings(key, klass)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Static(Content):
|
||||
mandatory_properties = ('title',)
|
||||
default_status = 'published'
|
||||
default_template = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Static, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
self._output_location_referenced = False
|
||||
|
||||
@deprecated_attribute(old='filepath', new='source_path', since=(3, 2, 0))
|
||||
|
|
@ -553,13 +543,13 @@ class Static(Content):
|
|||
def url(self):
|
||||
# Note when url has been referenced, so we can avoid overriding it.
|
||||
self._output_location_referenced = True
|
||||
return super(Static, self).url
|
||||
return super().url
|
||||
|
||||
@property
|
||||
def save_as(self):
|
||||
# Note when save_as has been referenced, so we can avoid overriding it.
|
||||
self._output_location_referenced = True
|
||||
return super(Static, self).save_as
|
||||
return super().save_as
|
||||
|
||||
def attach_to(self, content):
|
||||
"""Override our output directory with that of the given content object.
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import calendar
|
||||
import errno
|
||||
import fnmatch
|
||||
import logging
|
||||
import os
|
||||
from codecs import open
|
||||
from collections import defaultdict
|
||||
from functools import partial
|
||||
from itertools import chain, groupby
|
||||
|
|
@ -15,15 +13,12 @@ from operator import attrgetter
|
|||
from jinja2 import (BaseLoader, ChoiceLoader, Environment, FileSystemLoader,
|
||||
PrefixLoader, TemplateNotFound)
|
||||
|
||||
import six
|
||||
|
||||
from pelican import signals
|
||||
from pelican.cache import FileStampDataCacher
|
||||
from pelican.contents import Article, Page, Static
|
||||
from pelican.readers import Readers
|
||||
from pelican.utils import (DateFormatter, copy, mkdir_p, order_content,
|
||||
posixize_path, process_translations,
|
||||
python_2_unicode_compatible)
|
||||
posixize_path, process_translations)
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -33,7 +28,6 @@ class PelicanTemplateNotFound(Exception):
|
|||
pass
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Generator(object):
|
||||
"""Baseclass generator"""
|
||||
|
||||
|
|
@ -138,7 +132,7 @@ class Generator(object):
|
|||
extensions are allowed)
|
||||
"""
|
||||
# backward compatibility for older generators
|
||||
if isinstance(paths, six.string_types):
|
||||
if isinstance(paths, str):
|
||||
paths = [paths]
|
||||
|
||||
# group the exclude dir names by parent path, for use with os.walk()
|
||||
|
|
@ -247,7 +241,7 @@ class CachingGenerator(Generator, FileStampDataCacher):
|
|||
def _get_file_stamp(self, filename):
|
||||
'''Get filestamp for path relative to generator.path'''
|
||||
filename = os.path.join(self.path, filename)
|
||||
return super(CachingGenerator, self)._get_file_stamp(filename)
|
||||
return super()._get_file_stamp(filename)
|
||||
|
||||
|
||||
class _FileLoader(BaseLoader):
|
||||
|
|
@ -294,7 +288,7 @@ class ArticlesGenerator(CachingGenerator):
|
|||
self.authors = defaultdict(list)
|
||||
self.drafts = [] # only drafts in default language
|
||||
self.drafts_translations = []
|
||||
super(ArticlesGenerator, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
signals.article_generator_init.send(self)
|
||||
|
||||
def generate_feeds(self, writer):
|
||||
|
|
@ -513,8 +507,6 @@ class ArticlesGenerator(CachingGenerator):
|
|||
context["period"] = (_period,)
|
||||
else:
|
||||
month_name = calendar.month_name[_period[1]]
|
||||
if not six.PY3:
|
||||
month_name = month_name.decode('utf-8')
|
||||
if key == period_date_key['month']:
|
||||
context["period"] = (_period[0],
|
||||
month_name)
|
||||
|
|
@ -707,7 +699,7 @@ class PagesGenerator(CachingGenerator):
|
|||
self.hidden_translations = []
|
||||
self.draft_pages = []
|
||||
self.draft_translations = []
|
||||
super(PagesGenerator, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
signals.page_generator_init.send(self)
|
||||
|
||||
def generate_context(self):
|
||||
|
|
@ -793,7 +785,7 @@ class StaticGenerator(Generator):
|
|||
to output"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(StaticGenerator, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fallback_to_symlinks = False
|
||||
signals.static_generator_init.send(self)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
try:
|
||||
from collections.abc import Mapping
|
||||
except ImportError:
|
||||
from collections import Mapping
|
||||
|
||||
import six
|
||||
|
||||
__all__ = [
|
||||
'init'
|
||||
|
|
@ -21,7 +13,7 @@ __all__ = [
|
|||
class BaseFormatter(logging.Formatter):
|
||||
def __init__(self, fmt=None, datefmt=None):
|
||||
FORMAT = '%(customlevelname)s %(message)s'
|
||||
super(BaseFormatter, self).__init__(fmt=FORMAT, datefmt=datefmt)
|
||||
super().__init__(fmt=FORMAT, datefmt=datefmt)
|
||||
|
||||
def format(self, record):
|
||||
customlevel = self._get_levelname(record.levelname)
|
||||
|
|
@ -29,20 +21,17 @@ class BaseFormatter(logging.Formatter):
|
|||
# format multiline messages 'nicely' to make it clear they are together
|
||||
record.msg = record.msg.replace('\n', '\n | ')
|
||||
record.args = tuple(arg.replace('\n', '\n | ') if
|
||||
isinstance(arg, six.string_types) else
|
||||
isinstance(arg, str) else
|
||||
arg for arg in record.args)
|
||||
return super(BaseFormatter, self).format(record)
|
||||
return super().format(record)
|
||||
|
||||
def formatException(self, ei):
|
||||
''' prefix traceback info for better representation '''
|
||||
# .formatException returns a bytestring in py2 and unicode in py3
|
||||
# since .format will handle unicode conversion,
|
||||
# str() calls are used to normalize formatting string
|
||||
s = super(BaseFormatter, self).formatException(ei)
|
||||
s = super().formatException(ei)
|
||||
# fancy format traceback
|
||||
s = str('\n').join(str(' | ') + line for line in s.splitlines())
|
||||
s = '\n'.join(' | ' + line for line in s.splitlines())
|
||||
# separate the traceback from the preceding lines
|
||||
s = str(' |___\n{}').format(s)
|
||||
s = ' |___\n{}'.format(s)
|
||||
return s
|
||||
|
||||
def _get_levelname(self, name):
|
||||
|
|
@ -140,41 +129,7 @@ class LimitFilter(logging.Filter):
|
|||
return True
|
||||
|
||||
|
||||
class SafeLogger(logging.Logger):
|
||||
"""
|
||||
Base Logger which properly encodes Exceptions in Py2
|
||||
"""
|
||||
_exc_encoding = locale.getpreferredencoding()
|
||||
|
||||
def _log(self, level, msg, args, exc_info=None, extra=None):
|
||||
# if the only argument is a Mapping, Logger uses that for formatting
|
||||
# format values for that case
|
||||
if args and len(args) == 1 and isinstance(args[0], Mapping):
|
||||
args = ({k: self._decode_arg(v) for k, v in args[0].items()},)
|
||||
# otherwise, format each arg
|
||||
else:
|
||||
args = tuple(self._decode_arg(arg) for arg in args)
|
||||
super(SafeLogger, self)._log(
|
||||
level, msg, args, exc_info=exc_info, extra=extra)
|
||||
|
||||
def _decode_arg(self, arg):
|
||||
'''
|
||||
properly decode an arg for Py2 if it's Exception
|
||||
|
||||
|
||||
localized systems have errors in native language if locale is set
|
||||
so convert the message to unicode with the correct encoding
|
||||
'''
|
||||
if isinstance(arg, Exception):
|
||||
text = str('%s: %s') % (arg.__class__.__name__, arg)
|
||||
if six.PY2:
|
||||
text = text.decode(self._exc_encoding)
|
||||
return text
|
||||
else:
|
||||
return arg
|
||||
|
||||
|
||||
class LimitLogger(SafeLogger):
|
||||
class LimitLogger(logging.Logger):
|
||||
"""
|
||||
A logger which adds LimitFilter automatically
|
||||
"""
|
||||
|
|
@ -182,7 +137,7 @@ class LimitLogger(SafeLogger):
|
|||
limit_filter = LimitFilter()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(LimitLogger, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.enable_filter()
|
||||
|
||||
def disable_filter(self):
|
||||
|
|
@ -197,12 +152,12 @@ class FatalLogger(LimitLogger):
|
|||
errors_fatal = False
|
||||
|
||||
def warning(self, *args, **kwargs):
|
||||
super(FatalLogger, self).warning(*args, **kwargs)
|
||||
super().warning(*args, **kwargs)
|
||||
if FatalLogger.warnings_fatal:
|
||||
raise RuntimeError('Warning encountered')
|
||||
|
||||
def error(self, *args, **kwargs):
|
||||
super(FatalLogger, self).error(*args, **kwargs)
|
||||
super().error(*args, **kwargs)
|
||||
if FatalLogger.errors_fatal:
|
||||
raise RuntimeError('Error encountered')
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import functools
|
||||
import logging
|
||||
|
|
@ -7,8 +6,6 @@ import os
|
|||
from collections import namedtuple
|
||||
from math import ceil
|
||||
|
||||
import six
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
PaginationRule = namedtuple(
|
||||
'PaginationRule',
|
||||
|
|
@ -131,7 +128,7 @@ class Page(object):
|
|||
|
||||
prop_value = getattr(rule, key)
|
||||
|
||||
if not isinstance(prop_value, six.string_types):
|
||||
if not isinstance(prop_value, str):
|
||||
logger.warning('%s is set to %s', key, prop_value)
|
||||
return prop_value
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
from html import escape
|
||||
from html.parser import HTMLParser
|
||||
from io import StringIO
|
||||
|
||||
import docutils
|
||||
import docutils.core
|
||||
|
|
@ -12,16 +15,11 @@ import docutils.io
|
|||
from docutils.parsers.rst.languages import get_language as get_docutils_lang
|
||||
from docutils.writers.html4css1 import HTMLTranslator, Writer
|
||||
|
||||
import six
|
||||
from six import StringIO
|
||||
from six.moves.html_parser import HTMLParser
|
||||
|
||||
from pelican import rstdirectives # NOQA
|
||||
from pelican import signals
|
||||
from pelican.cache import FileStampDataCacher
|
||||
from pelican.contents import Author, Category, Page, Tag
|
||||
from pelican.utils import SafeDatetime, escape_html, get_date, pelican_open, \
|
||||
posixize_path
|
||||
from pelican.utils import get_date, pelican_open, posixize_path
|
||||
|
||||
try:
|
||||
from markdown import Markdown
|
||||
|
|
@ -79,7 +77,7 @@ def ensure_metadata_list(text):
|
|||
Regardless, all list items undergo .strip() before returning, and
|
||||
empty items are discarded.
|
||||
"""
|
||||
if isinstance(text, six.text_type):
|
||||
if isinstance(text, str):
|
||||
if ';' in text:
|
||||
text = text.split(';')
|
||||
else:
|
||||
|
|
@ -138,7 +136,7 @@ class BaseReader(object):
|
|||
class _FieldBodyTranslator(HTMLTranslator):
|
||||
|
||||
def __init__(self, document):
|
||||
HTMLTranslator.__init__(self, document)
|
||||
super().__init__(document)
|
||||
self.compact_p = None
|
||||
|
||||
def astext(self):
|
||||
|
|
@ -160,7 +158,7 @@ def render_node_to_html(document, node, field_body_translator_class):
|
|||
class PelicanHTMLWriter(Writer):
|
||||
|
||||
def __init__(self):
|
||||
Writer.__init__(self)
|
||||
super().__init__()
|
||||
self.translator_class = PelicanHTMLTranslator
|
||||
|
||||
|
||||
|
|
@ -203,21 +201,8 @@ class RstReader(BaseReader):
|
|||
writer_class = PelicanHTMLWriter
|
||||
field_body_translator_class = _FieldBodyTranslator
|
||||
|
||||
class FileInput(docutils.io.FileInput):
|
||||
"""Patch docutils.io.FileInput to remove "U" mode in py3.
|
||||
|
||||
Universal newlines is enabled by default and "U" mode is deprecated
|
||||
in py3.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if six.PY3:
|
||||
kwargs['mode'] = kwargs.get('mode', 'r').replace('U', '')
|
||||
docutils.io.FileInput.__init__(self, *args, **kwargs)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(RstReader, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
lang_code = self.settings.get('DEFAULT_LANG', 'en')
|
||||
if get_docutils_lang(lang_code):
|
||||
|
|
@ -276,7 +261,6 @@ class RstReader(BaseReader):
|
|||
|
||||
pub = docutils.core.Publisher(
|
||||
writer=self.writer_class(),
|
||||
source_class=self.FileInput,
|
||||
destination_class=docutils.io.StringOutput)
|
||||
pub.set_components('standalone', 'restructuredtext', 'html')
|
||||
pub.process_programmatic_settings(None, extra_params, None)
|
||||
|
|
@ -303,7 +287,7 @@ class MarkdownReader(BaseReader):
|
|||
file_extensions = ['md', 'markdown', 'mkd', 'mdown']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MarkdownReader, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
settings = self.settings['MARKDOWN']
|
||||
settings.setdefault('extension_configs', {})
|
||||
settings.setdefault('extensions', [])
|
||||
|
|
@ -366,11 +350,7 @@ class HTMLReader(BaseReader):
|
|||
|
||||
class _HTMLParser(HTMLParser):
|
||||
def __init__(self, settings, filename):
|
||||
try:
|
||||
# Python 3.5+
|
||||
HTMLParser.__init__(self, convert_charrefs=False)
|
||||
except TypeError:
|
||||
HTMLParser.__init__(self)
|
||||
super().__init__(convert_charrefs=False)
|
||||
self.body = ''
|
||||
self.metadata = {}
|
||||
self.settings = settings
|
||||
|
|
@ -415,7 +395,7 @@ class HTMLReader(BaseReader):
|
|||
self._in_body = False
|
||||
self._in_top_level = True
|
||||
elif self._in_body:
|
||||
self._data_buffer += '</{}>'.format(escape_html(tag))
|
||||
self._data_buffer += '</{}>'.format(escape(tag))
|
||||
|
||||
def handle_startendtag(self, tag, attrs):
|
||||
if tag == 'meta' and self._in_head:
|
||||
|
|
@ -436,16 +416,16 @@ class HTMLReader(BaseReader):
|
|||
self._data_buffer += '&#{};'.format(data)
|
||||
|
||||
def build_tag(self, tag, attrs, close_tag):
|
||||
result = '<{}'.format(escape_html(tag))
|
||||
result = '<{}'.format(escape(tag))
|
||||
for k, v in attrs:
|
||||
result += ' ' + escape_html(k)
|
||||
result += ' ' + escape(k)
|
||||
if v is not None:
|
||||
# If the attribute value contains a double quote, surround
|
||||
# with single quotes, otherwise use double quotes.
|
||||
if '"' in v:
|
||||
result += "='{}'".format(escape_html(v, quote=False))
|
||||
result += "='{}'".format(escape(v, quote=False))
|
||||
else:
|
||||
result += '="{}"'.format(escape_html(v, quote=False))
|
||||
result += '="{}"'.format(escape(v, quote=False))
|
||||
if close_tag:
|
||||
return result + ' />'
|
||||
return result + '>'
|
||||
|
|
@ -543,9 +523,7 @@ class Readers(FileStampDataCacher):
|
|||
self.settings['CONTENT_CACHING_LAYER'] == 'reader')
|
||||
caching_policy = cache_this_level and self.settings['CACHE_CONTENT']
|
||||
load_policy = cache_this_level and self.settings['LOAD_CONTENT_CACHE']
|
||||
super(Readers, self).__init__(settings, cache_name,
|
||||
caching_policy, load_policy,
|
||||
)
|
||||
super().__init__(settings, cache_name, caching_policy, load_policy)
|
||||
|
||||
@property
|
||||
def extensions(self):
|
||||
|
|
@ -685,10 +663,10 @@ def default_metadata(settings=None, process=None):
|
|||
metadata['category'] = value
|
||||
if settings.get('DEFAULT_DATE', None) and \
|
||||
settings['DEFAULT_DATE'] != 'fs':
|
||||
if isinstance(settings['DEFAULT_DATE'], six.string_types):
|
||||
if isinstance(settings['DEFAULT_DATE'], str):
|
||||
metadata['date'] = get_date(settings['DEFAULT_DATE'])
|
||||
else:
|
||||
metadata['date'] = SafeDatetime(*settings['DEFAULT_DATE'])
|
||||
metadata['date'] = datetime.datetime(*settings['DEFAULT_DATE'])
|
||||
return metadata
|
||||
|
||||
|
||||
|
|
@ -696,7 +674,7 @@ def path_metadata(full_path, source_path, settings=None):
|
|||
metadata = {}
|
||||
if settings:
|
||||
if settings.get('DEFAULT_DATE', None) == 'fs':
|
||||
metadata['date'] = SafeDatetime.fromtimestamp(
|
||||
metadata['date'] = datetime.datetime.fromtimestamp(
|
||||
os.stat(full_path).st_mtime)
|
||||
|
||||
# Apply EXTRA_PATH_METADATA for the source path and the paths of any
|
||||
|
|
@ -731,7 +709,7 @@ def parse_path_metadata(source_path, settings=None, process=None):
|
|||
... process=reader.process_metadata)
|
||||
>>> pprint.pprint(metadata) # doctest: +ELLIPSIS
|
||||
{'category': <pelican.urlwrappers.Category object at ...>,
|
||||
'date': SafeDatetime(2013, 1, 1, 0, 0),
|
||||
'date': datetime.datetime(2013, 1, 1, 0, 0),
|
||||
'slug': 'my-slug'}
|
||||
"""
|
||||
metadata = {}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import re
|
||||
|
||||
|
|
@ -10,8 +9,6 @@ from pygments import highlight
|
|||
from pygments.formatters import HtmlFormatter
|
||||
from pygments.lexers import TextLexer, get_lexer_by_name
|
||||
|
||||
import six
|
||||
|
||||
import pelican.settings as pys
|
||||
|
||||
|
||||
|
|
@ -49,7 +46,7 @@ class Pygments(Directive):
|
|||
|
||||
# Fetch the defaults
|
||||
if pys.PYGMENTS_RST_OPTIONS is not None:
|
||||
for k, v in six.iteritems(pys.PYGMENTS_RST_OPTIONS):
|
||||
for k, v in pys.PYGMENTS_RST_OPTIONS.items():
|
||||
# Locally set options overrides the defaults
|
||||
if k not in self.options:
|
||||
self.options[k] = v
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
|
|
@ -7,16 +6,14 @@ import os
|
|||
import posixpath
|
||||
import ssl
|
||||
import sys
|
||||
import urllib
|
||||
from http import server
|
||||
|
||||
try:
|
||||
from magic import from_file as magic_from_file
|
||||
except ImportError:
|
||||
magic_from_file = None
|
||||
|
||||
from six.moves import BaseHTTPServer
|
||||
from six.moves import SimpleHTTPServer as srvmod
|
||||
from six.moves import urllib
|
||||
|
||||
from pelican.log import init as init_logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -44,7 +41,7 @@ def parse_arguments():
|
|||
return parser.parse_args()
|
||||
|
||||
|
||||
class ComplexHTTPRequestHandler(srvmod.SimpleHTTPRequestHandler):
|
||||
class ComplexHTTPRequestHandler(server.SimpleHTTPRequestHandler):
|
||||
SUFFIXES = ['.html', '/index.html', '/', '']
|
||||
|
||||
def translate_path(self, path):
|
||||
|
|
@ -76,7 +73,7 @@ class ComplexHTTPRequestHandler(srvmod.SimpleHTTPRequestHandler):
|
|||
if not self.path:
|
||||
return
|
||||
|
||||
srvmod.SimpleHTTPRequestHandler.do_GET(self)
|
||||
server.SimpleHTTPRequestHandler.do_GET(self)
|
||||
|
||||
def get_path_that_exists(self, original_path):
|
||||
# Try to strip trailing slash
|
||||
|
|
@ -96,7 +93,7 @@ class ComplexHTTPRequestHandler(srvmod.SimpleHTTPRequestHandler):
|
|||
def guess_type(self, path):
|
||||
"""Guess at the mime type for the specified file.
|
||||
"""
|
||||
mimetype = srvmod.SimpleHTTPRequestHandler.guess_type(self, path)
|
||||
mimetype = server.SimpleHTTPRequestHandler.guess_type(self, path)
|
||||
|
||||
# If the default guess is too generic, try the python-magic library
|
||||
if mimetype == 'application/octet-stream' and magic_from_file:
|
||||
|
|
@ -105,9 +102,9 @@ class ComplexHTTPRequestHandler(srvmod.SimpleHTTPRequestHandler):
|
|||
return mimetype
|
||||
|
||||
|
||||
class RootedHTTPServer(BaseHTTPServer.HTTPServer):
|
||||
class RootedHTTPServer(server.HTTPServer):
|
||||
def __init__(self, base_path, *args, **kwargs):
|
||||
BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs)
|
||||
server.HTTPServer.__init__(self, *args, **kwargs)
|
||||
self.RequestHandlerClass.base_path = base_path
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import copy
|
||||
import importlib.util
|
||||
import inspect
|
||||
import locale
|
||||
import logging
|
||||
|
|
@ -10,24 +10,14 @@ import re
|
|||
from os.path import isabs
|
||||
from posixpath import join as posix_join
|
||||
|
||||
import six
|
||||
|
||||
from pelican.log import LimitFilter
|
||||
|
||||
|
||||
try:
|
||||
# spec_from_file_location is the recommended way in Python 3.5+
|
||||
import importlib.util
|
||||
|
||||
def load_source(name, path):
|
||||
spec = importlib.util.spec_from_file_location(name, path)
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(mod)
|
||||
return mod
|
||||
except ImportError:
|
||||
# but it does not exist in Python 2.7, so fall back to imp
|
||||
import imp
|
||||
load_source = imp.load_source
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -278,7 +268,7 @@ def handle_deprecated_settings(settings):
|
|||
del settings['PLUGIN_PATH']
|
||||
|
||||
# PLUGIN_PATHS: str -> [str]
|
||||
if isinstance(settings.get('PLUGIN_PATHS'), six.string_types):
|
||||
if isinstance(settings.get('PLUGIN_PATHS'), str):
|
||||
logger.warning("Defining PLUGIN_PATHS setting as string "
|
||||
"has been deprecated (should be a list)")
|
||||
settings['PLUGIN_PATHS'] = [settings['PLUGIN_PATHS']]
|
||||
|
|
@ -547,13 +537,13 @@ def configure_settings(settings):
|
|||
|
||||
# standardize strings to lists
|
||||
for key in ['LOCALE']:
|
||||
if key in settings and isinstance(settings[key], six.string_types):
|
||||
if key in settings and isinstance(settings[key], str):
|
||||
settings[key] = [settings[key]]
|
||||
|
||||
# check settings that must be a particular type
|
||||
for key, types in [
|
||||
('OUTPUT_SOURCES_EXTENSION', six.string_types),
|
||||
('FILENAME_METADATA', six.string_types),
|
||||
('OUTPUT_SOURCES_EXTENSION', str),
|
||||
('FILENAME_METADATA', str),
|
||||
]:
|
||||
if key in settings and not isinstance(settings[key], types):
|
||||
value = settings.pop(key)
|
||||
|
|
@ -647,7 +637,7 @@ def configure_settings(settings):
|
|||
'PAGE_PATHS',
|
||||
)
|
||||
for PATH_KEY in filter(lambda k: k in settings, path_keys):
|
||||
if isinstance(settings[PATH_KEY], six.string_types):
|
||||
if isinstance(settings[PATH_KEY], str):
|
||||
logger.warning("Detected misconfiguration with %s setting "
|
||||
"(must be a list), falling back to the default",
|
||||
PATH_KEY)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
from blinker import signal
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
AUTHOR = 'Alexis Métaireau'
|
||||
SITENAME = "Alexis' log"
|
||||
SITEURL = 'http://blog.notmyidea.org'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import locale
|
||||
import logging
|
||||
|
|
@ -10,12 +9,11 @@ import sys
|
|||
import unittest
|
||||
from contextlib import contextmanager
|
||||
from functools import wraps
|
||||
from io import StringIO
|
||||
from logging.handlers import BufferingHandler
|
||||
from shutil import rmtree
|
||||
from tempfile import mkdtemp
|
||||
|
||||
from six import StringIO
|
||||
|
||||
from pelican.contents import Article
|
||||
from pelican.readers import default_metadata
|
||||
from pelican.settings import DEFAULT_CONFIG
|
||||
|
|
@ -188,7 +186,7 @@ class LogCountHandler(BufferingHandler):
|
|||
"""Capturing and counting logged messages."""
|
||||
|
||||
def __init__(self, capacity=1000):
|
||||
super(LogCountHandler, self).__init__(capacity)
|
||||
super().__init__(capacity)
|
||||
|
||||
def count_logs(self, msg=None, level=None):
|
||||
return len([
|
||||
|
|
@ -204,13 +202,13 @@ class LoggedTestCase(unittest.TestCase):
|
|||
"""A test case that captures log messages."""
|
||||
|
||||
def setUp(self):
|
||||
super(LoggedTestCase, self).setUp()
|
||||
super().setUp()
|
||||
self._logcount_handler = LogCountHandler()
|
||||
logging.getLogger().addHandler(self._logcount_handler)
|
||||
|
||||
def tearDown(self):
|
||||
logging.getLogger().removeHandler(self._logcount_handler)
|
||||
super(LoggedTestCase, self).tearDown()
|
||||
super().tearDown()
|
||||
|
||||
def assertLogCountEqual(self, count=None, msg=None, **kwargs):
|
||||
actual = self._logcount_handler.count_logs(msg=msg, **kwargs)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
from shutil import rmtree
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import datetime
|
||||
import locale
|
||||
import logging
|
||||
import os.path
|
||||
|
|
@ -9,15 +9,12 @@ from sys import platform
|
|||
|
||||
from jinja2.utils import generate_lorem_ipsum
|
||||
|
||||
import six
|
||||
|
||||
from pelican.contents import Article, Author, Category, Page, Static
|
||||
from pelican.settings import DEFAULT_CONFIG
|
||||
from pelican.signals import content_object_init
|
||||
from pelican.tests.support import (LoggedTestCase, get_context, get_settings,
|
||||
unittest)
|
||||
from pelican.utils import (SafeDatetime, path_to_url, posixize_path,
|
||||
truncate_html_words)
|
||||
from pelican.utils import (path_to_url, posixize_path, truncate_html_words)
|
||||
|
||||
|
||||
# generate one paragraph, enclosed with <p>
|
||||
|
|
@ -28,7 +25,7 @@ TEST_SUMMARY = generate_lorem_ipsum(n=1, html=False)
|
|||
class TestPage(LoggedTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPage, self).setUp()
|
||||
super().setUp()
|
||||
self.old_locale = locale.setlocale(locale.LC_ALL)
|
||||
locale.setlocale(locale.LC_ALL, str('C'))
|
||||
self.page_kwargs = {
|
||||
|
|
@ -185,7 +182,7 @@ class TestPage(LoggedTestCase):
|
|||
|
||||
def test_datetime(self):
|
||||
# If DATETIME is set to a tuple, it should be used to override LOCALE
|
||||
dt = SafeDatetime(2015, 9, 13)
|
||||
dt = datetime.datetime(2015, 9, 13)
|
||||
|
||||
page_kwargs = self._copy_page_kwargs()
|
||||
|
||||
|
|
@ -286,9 +283,7 @@ class TestPage(LoggedTestCase):
|
|||
'<a href="http://notmyidea.org/category/category.html">link</a>'))
|
||||
|
||||
def test_intrasite_link(self):
|
||||
# type does not take unicode in PY2 and bytes in PY3, which in
|
||||
# combination with unicode literals leads to following insane line:
|
||||
cls_name = '_DummyArticle' if six.PY3 else b'_DummyArticle'
|
||||
cls_name = '_DummyArticle'
|
||||
article = type(cls_name, (object,), {'url': 'article.html'})
|
||||
|
||||
args = self.page_kwargs.copy()
|
||||
|
|
@ -370,9 +365,7 @@ class TestPage(LoggedTestCase):
|
|||
self.assertEqual(p.custom, linked)
|
||||
|
||||
def test_intrasite_link_more(self):
|
||||
# type does not take unicode in PY2 and bytes in PY3, which in
|
||||
# combination with unicode literals leads to following insane line:
|
||||
cls_name = '_DummyAsset' if six.PY3 else b'_DummyAsset'
|
||||
cls_name = '_DummyAsset'
|
||||
|
||||
args = self.page_kwargs.copy()
|
||||
args['settings'] = get_settings()
|
||||
|
|
@ -487,9 +480,7 @@ class TestPage(LoggedTestCase):
|
|||
)
|
||||
|
||||
def test_intrasite_link_markdown_spaces(self):
|
||||
# Markdown introduces %20 instead of spaces, this tests that
|
||||
# we support markdown doing this.
|
||||
cls_name = '_DummyArticle' if six.PY3 else b'_DummyArticle'
|
||||
cls_name = '_DummyArticle'
|
||||
article = type(cls_name, (object,), {'url': 'article-spaces.html'})
|
||||
|
||||
args = self.page_kwargs.copy()
|
||||
|
|
@ -512,7 +503,7 @@ class TestPage(LoggedTestCase):
|
|||
def test_intrasite_link_source_and_generated(self):
|
||||
"""Test linking both to the source and the generated article
|
||||
"""
|
||||
cls_name = '_DummyAsset' if six.PY3 else b'_DummyAsset'
|
||||
cls_name = '_DummyAsset'
|
||||
|
||||
args = self.page_kwargs.copy()
|
||||
args['settings'] = get_settings()
|
||||
|
|
@ -538,7 +529,7 @@ class TestPage(LoggedTestCase):
|
|||
def test_intrasite_link_to_static_content_with_filename(self):
|
||||
"""Test linking to a static resource with deprecated {filename}
|
||||
"""
|
||||
cls_name = '_DummyAsset' if six.PY3 else b'_DummyAsset'
|
||||
cls_name = '_DummyAsset'
|
||||
|
||||
args = self.page_kwargs.copy()
|
||||
args['settings'] = get_settings()
|
||||
|
|
@ -666,7 +657,7 @@ class TestArticle(TestPage):
|
|||
class TestStatic(LoggedTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestStatic, self).setUp()
|
||||
super().setUp()
|
||||
self.settings = get_settings(
|
||||
STATIC_SAVE_AS='{path}',
|
||||
STATIC_URL='{path}',
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import locale
|
||||
import os
|
||||
from codecs import open
|
||||
from shutil import copy, rmtree
|
||||
from tempfile import mkdtemp
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import locale
|
||||
import os
|
||||
import re
|
||||
from codecs import open
|
||||
|
||||
from pelican.settings import DEFAULT_CONFIG
|
||||
from pelican.tests.support import (mute, skipIfNoExecutable, temporary_folder,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import locale
|
||||
|
||||
|
|
@ -18,7 +17,7 @@ TEST_SUMMARY = generate_lorem_ipsum(n=1, html=False)
|
|||
|
||||
class TestPage(unittest.TestCase):
|
||||
def setUp(self):
|
||||
super(TestPage, self).setUp()
|
||||
super().setUp()
|
||||
self.old_locale = locale.setlocale(locale.LC_ALL)
|
||||
locale.setlocale(locale.LC_ALL, str('C'))
|
||||
self.page_kwargs = {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
try:
|
||||
import collections.abc as collections
|
||||
except ImportError:
|
||||
import collections
|
||||
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from collections.abc import Sequence
|
||||
from shutil import rmtree
|
||||
from tempfile import mkdtemp
|
||||
|
||||
|
|
@ -47,7 +42,7 @@ class TestPelican(LoggedTestCase):
|
|||
# to run pelican in different situations and see how it behaves
|
||||
|
||||
def setUp(self):
|
||||
super(TestPelican, self).setUp()
|
||||
super().setUp()
|
||||
self.temp_path = mkdtemp(prefix='pelicantests.')
|
||||
self.temp_cache = mkdtemp(prefix='pelican_cache.')
|
||||
self.maxDiff = None
|
||||
|
|
@ -58,7 +53,7 @@ class TestPelican(LoggedTestCase):
|
|||
rmtree(self.temp_path)
|
||||
rmtree(self.temp_cache)
|
||||
locale.setlocale(locale.LC_ALL, self.old_locale)
|
||||
super(TestPelican, self).tearDown()
|
||||
super().tearDown()
|
||||
|
||||
def assertDirsEqual(self, left_path, right_path):
|
||||
out, err = subprocess.Popen(
|
||||
|
|
@ -95,7 +90,7 @@ class TestPelican(LoggedTestCase):
|
|||
generator_classes[-1] is StaticGenerator,
|
||||
"StaticGenerator must be the last generator, but it isn't!")
|
||||
self.assertIsInstance(
|
||||
generator_classes, collections.Sequence,
|
||||
generator_classes, Sequence,
|
||||
"get_generator_classes() must return a Sequence to preserve order")
|
||||
|
||||
def test_basic_generation_works(self):
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
import six
|
||||
|
||||
from pelican import readers
|
||||
from pelican.tests.support import get_settings, unittest
|
||||
from pelican.utils import SafeDatetime
|
||||
|
|
@ -64,8 +61,7 @@ class TestAssertDictHasSubset(ReaderTest):
|
|||
self.assertDictHasSubset(self.dictionary, self.dictionary)
|
||||
|
||||
def test_fail_not_set(self):
|
||||
six.assertRaisesRegex(
|
||||
self,
|
||||
self.assertRaisesRegex(
|
||||
AssertionError,
|
||||
r'Expected.*key-c.*to have value.*val-c.*but was not in Dict',
|
||||
self.assertDictHasSubset,
|
||||
|
|
@ -73,8 +69,7 @@ class TestAssertDictHasSubset(ReaderTest):
|
|||
{'key-c': 'val-c'})
|
||||
|
||||
def test_fail_wrong_val(self):
|
||||
six.assertRaisesRegex(
|
||||
self,
|
||||
self.assertRaisesRegex(
|
||||
AssertionError,
|
||||
r'Expected .*key-a.* to have value .*val-b.* but was .*val-a.*',
|
||||
self.assertDictHasSubset,
|
||||
|
|
@ -445,7 +440,7 @@ class RstReaderTest(ReaderTest):
|
|||
def test_parse_error(self):
|
||||
# Verify that it raises an Exception, not nothing and not SystemExit or
|
||||
# some such
|
||||
with six.assertRaisesRegex(self, Exception, "underline too short"):
|
||||
with self.assertRaisesRegex(Exception, "underline too short"):
|
||||
self.read_file(path='../parse_error/parse_error.rst')
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
from pelican.tests.support import unittest
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import os
|
||||
from io import BytesIO
|
||||
from shutil import rmtree
|
||||
from tempfile import mkdtemp
|
||||
|
||||
from six import BytesIO
|
||||
|
||||
from pelican.server import ComplexHTTPRequestHandler
|
||||
from pelican.tests.support import unittest
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import copy
|
||||
import locale
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import warnings
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from pelican.tests.support import unittest
|
||||
from pelican.urlwrappers import Author, Category, Tag, URLWrapper
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import locale
|
||||
import logging
|
||||
|
|
@ -11,8 +10,6 @@ from tempfile import mkdtemp
|
|||
|
||||
import pytz
|
||||
|
||||
import six
|
||||
|
||||
from pelican import utils
|
||||
from pelican.generators import TemplatePagesGenerator
|
||||
from pelican.settings import read_settings
|
||||
|
|
@ -720,8 +717,7 @@ class TestSanitisedJoin(unittest.TestCase):
|
|||
@unittest.skipIf(platform == 'win32',
|
||||
"Different filesystem root on Windows")
|
||||
def test_detect_parent_breakout(self):
|
||||
with six.assertRaisesRegex(
|
||||
self,
|
||||
with self.assertRaisesRegex(
|
||||
RuntimeError,
|
||||
"Attempted to break out of output directory to /foo/test"):
|
||||
utils.sanitised_join(
|
||||
|
|
@ -732,8 +728,7 @@ class TestSanitisedJoin(unittest.TestCase):
|
|||
@unittest.skipIf(platform == 'win32',
|
||||
"Different filesystem root on Windows")
|
||||
def test_detect_root_breakout(self):
|
||||
with six.assertRaisesRegex(
|
||||
self,
|
||||
with self.assertRaisesRegex(
|
||||
RuntimeError,
|
||||
"Attempted to break out of output directory to /test"):
|
||||
utils.sanitised_join(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
|
|
@ -9,23 +8,17 @@ import re
|
|||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from codecs import open
|
||||
from collections import defaultdict
|
||||
|
||||
from six.moves.urllib.error import URLError
|
||||
from six.moves.urllib.parse import quote, urlparse, urlsplit, urlunsplit
|
||||
from six.moves.urllib.request import urlretrieve
|
||||
from html import unescape
|
||||
from urllib.error import URLError
|
||||
from urllib.parse import quote, urlparse, urlsplit, urlunsplit
|
||||
from urllib.request import urlretrieve
|
||||
|
||||
# because logging.setLoggerClass has to be called before logging.getLogger
|
||||
from pelican.log import init
|
||||
from pelican.settings import read_settings
|
||||
from pelican.utils import SafeDatetime, slugify
|
||||
|
||||
try:
|
||||
from html import unescape # py3.5+
|
||||
except ImportError:
|
||||
from six.moves.html_parser import HTMLParser
|
||||
unescape = HTMLParser().unescape
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -396,19 +389,8 @@ def posterous2fields(api_token, email, password):
|
|||
"""Imports posterous posts"""
|
||||
import base64
|
||||
from datetime import timedelta
|
||||
try:
|
||||
# py3k import
|
||||
import json
|
||||
except ImportError:
|
||||
# py2 import
|
||||
import simplejson as json
|
||||
|
||||
try:
|
||||
# py3k import
|
||||
import urllib.request as urllib_request
|
||||
except ImportError:
|
||||
# py2 import
|
||||
import urllib2 as urllib_request
|
||||
|
||||
def get_posterous_posts(api_token, email, password, page=1):
|
||||
base64string = base64.encodestring(
|
||||
|
|
@ -451,19 +433,8 @@ def posterous2fields(api_token, email, password):
|
|||
|
||||
def tumblr2fields(api_key, blogname):
|
||||
""" Imports Tumblr posts (API v2)"""
|
||||
try:
|
||||
# py3k import
|
||||
import json
|
||||
except ImportError:
|
||||
# py2 import
|
||||
import simplejson as json
|
||||
|
||||
try:
|
||||
# py3k import
|
||||
import urllib.request as urllib_request
|
||||
except ImportError:
|
||||
# py2 import
|
||||
import urllib2 as urllib_request
|
||||
|
||||
def get_tumblr_posts(api_key, blogname, offset=0):
|
||||
url = ("http://api.tumblr.com/v2/blog/%s.tumblr.com/"
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
import codecs
|
||||
import locale
|
||||
import os
|
||||
import sys
|
||||
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
|
|
@ -23,8 +20,6 @@ try:
|
|||
except ImportError:
|
||||
_DEFAULT_TIMEZONE = 'Europe/Paris'
|
||||
|
||||
import six
|
||||
|
||||
from pelican import __version__
|
||||
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
|
|
@ -77,41 +72,24 @@ CONF = {
|
|||
# url for list of valid timezones
|
||||
_TZ_URL = 'http://en.wikipedia.org/wiki/List_of_tz_database_time_zones'
|
||||
|
||||
_input_compat = six.moves.input
|
||||
str_compat = six.text_type
|
||||
|
||||
|
||||
# Create a 'marked' default path, to determine if someone has supplied
|
||||
# a path on the command-line.
|
||||
class _DEFAULT_PATH_TYPE(str_compat):
|
||||
class _DEFAULT_PATH_TYPE(str):
|
||||
is_default_path = True
|
||||
|
||||
|
||||
_DEFAULT_PATH = _DEFAULT_PATH_TYPE(os.curdir)
|
||||
|
||||
|
||||
def decoding_strings(f):
|
||||
def wrapper(*args, **kwargs):
|
||||
out = f(*args, **kwargs)
|
||||
if isinstance(out, six.string_types) and not six.PY3:
|
||||
# todo: make encoding configurable?
|
||||
if six.PY3:
|
||||
return out
|
||||
else:
|
||||
return out.decode(sys.stdin.encoding)
|
||||
return out
|
||||
return wrapper
|
||||
|
||||
|
||||
@decoding_strings
|
||||
def ask(question, answer=str_compat, default=None, length=None):
|
||||
if answer == str_compat:
|
||||
def ask(question, answer=str, default=None, length=None):
|
||||
if answer == str:
|
||||
r = ''
|
||||
while True:
|
||||
if default:
|
||||
r = _input_compat('> {0} [{1}] '.format(question, default))
|
||||
r = input('> {0} [{1}] '.format(question, default))
|
||||
else:
|
||||
r = _input_compat('> {0} '.format(question, default))
|
||||
r = input('> {0} '.format(question, default))
|
||||
|
||||
r = r.strip()
|
||||
|
||||
|
|
@ -133,11 +111,11 @@ def ask(question, answer=str_compat, default=None, length=None):
|
|||
r = None
|
||||
while True:
|
||||
if default is True:
|
||||
r = _input_compat('> {0} (Y/n) '.format(question))
|
||||
r = input('> {0} (Y/n) '.format(question))
|
||||
elif default is False:
|
||||
r = _input_compat('> {0} (y/N) '.format(question))
|
||||
r = input('> {0} (y/N) '.format(question))
|
||||
else:
|
||||
r = _input_compat('> {0} (y/n) '.format(question))
|
||||
r = input('> {0} (y/n) '.format(question))
|
||||
|
||||
r = r.strip().lower()
|
||||
|
||||
|
|
@ -157,9 +135,9 @@ def ask(question, answer=str_compat, default=None, length=None):
|
|||
r = None
|
||||
while True:
|
||||
if default:
|
||||
r = _input_compat('> {0} [{1}] '.format(question, default))
|
||||
r = input('> {0} [{1}] '.format(question, default))
|
||||
else:
|
||||
r = _input_compat('> {0} '.format(question))
|
||||
r = input('> {0} '.format(question))
|
||||
|
||||
r = r.strip()
|
||||
|
||||
|
|
@ -175,14 +153,14 @@ def ask(question, answer=str_compat, default=None, length=None):
|
|||
return r
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
'Argument `answer` must be str_compat, bool, or integer')
|
||||
'Argument `answer` must be str, bool, or integer')
|
||||
|
||||
|
||||
def ask_timezone(question, default, tzurl):
|
||||
"""Prompt for time zone and validate input"""
|
||||
lower_tz = [tz.lower() for tz in pytz.all_timezones]
|
||||
while True:
|
||||
r = ask(question, str_compat, default)
|
||||
r = ask(question, str, default)
|
||||
r = r.strip().replace(' ', '_').lower()
|
||||
if r in lower_tz:
|
||||
r = pytz.all_timezones[lower_tz.index(r)]
|
||||
|
|
@ -227,20 +205,20 @@ needed by Pelican.
|
|||
else:
|
||||
CONF['basedir'] = os.path.abspath(os.path.expanduser(
|
||||
ask('Where do you want to create your new web site?',
|
||||
answer=str_compat, default=args.path)))
|
||||
answer=str, default=args.path)))
|
||||
|
||||
CONF['sitename'] = ask('What will be the title of this web site?',
|
||||
answer=str_compat, default=args.title)
|
||||
answer=str, default=args.title)
|
||||
CONF['author'] = ask('Who will be the author of this web site?',
|
||||
answer=str_compat, default=args.author)
|
||||
answer=str, default=args.author)
|
||||
CONF['lang'] = ask('What will be the default language of this web site?',
|
||||
str_compat, args.lang or CONF['lang'], 2)
|
||||
str, args.lang or CONF['lang'], 2)
|
||||
|
||||
if ask('Do you want to specify a URL prefix? e.g., https://example.com ',
|
||||
answer=bool, default=True):
|
||||
CONF['siteurl'] = ask('What is your URL prefix? (see '
|
||||
'above example; no trailing slash)',
|
||||
str_compat, CONF['siteurl'])
|
||||
str, CONF['siteurl'])
|
||||
|
||||
CONF['with_pagination'] = ask('Do you want to enable article pagination?',
|
||||
bool, bool(CONF['default_pagination']))
|
||||
|
|
@ -263,49 +241,49 @@ needed by Pelican.
|
|||
answer=bool, default=False):
|
||||
CONF['ftp'] = True,
|
||||
CONF['ftp_host'] = ask('What is the hostname of your FTP server?',
|
||||
str_compat, CONF['ftp_host'])
|
||||
str, CONF['ftp_host'])
|
||||
CONF['ftp_user'] = ask('What is your username on that server?',
|
||||
str_compat, CONF['ftp_user'])
|
||||
str, CONF['ftp_user'])
|
||||
CONF['ftp_target_dir'] = ask('Where do you want to put your '
|
||||
'web site on that server?',
|
||||
str_compat, CONF['ftp_target_dir'])
|
||||
str, CONF['ftp_target_dir'])
|
||||
if ask('Do you want to upload your website using SSH?',
|
||||
answer=bool, default=False):
|
||||
CONF['ssh'] = True,
|
||||
CONF['ssh_host'] = ask('What is the hostname of your SSH server?',
|
||||
str_compat, CONF['ssh_host'])
|
||||
str, CONF['ssh_host'])
|
||||
CONF['ssh_port'] = ask('What is the port of your SSH server?',
|
||||
int, CONF['ssh_port'])
|
||||
CONF['ssh_user'] = ask('What is your username on that server?',
|
||||
str_compat, CONF['ssh_user'])
|
||||
str, CONF['ssh_user'])
|
||||
CONF['ssh_target_dir'] = ask('Where do you want to put your '
|
||||
'web site on that server?',
|
||||
str_compat, CONF['ssh_target_dir'])
|
||||
str, CONF['ssh_target_dir'])
|
||||
|
||||
if ask('Do you want to upload your website using Dropbox?',
|
||||
answer=bool, default=False):
|
||||
CONF['dropbox'] = True,
|
||||
CONF['dropbox_dir'] = ask('Where is your Dropbox directory?',
|
||||
str_compat, CONF['dropbox_dir'])
|
||||
str, CONF['dropbox_dir'])
|
||||
|
||||
if ask('Do you want to upload your website using S3?',
|
||||
answer=bool, default=False):
|
||||
CONF['s3'] = True,
|
||||
CONF['s3_bucket'] = ask('What is the name of your S3 bucket?',
|
||||
str_compat, CONF['s3_bucket'])
|
||||
str, CONF['s3_bucket'])
|
||||
|
||||
if ask('Do you want to upload your website using '
|
||||
'Rackspace Cloud Files?', answer=bool, default=False):
|
||||
CONF['cloudfiles'] = True,
|
||||
CONF['cloudfiles_username'] = ask('What is your Rackspace '
|
||||
'Cloud username?', str_compat,
|
||||
'Cloud username?', str,
|
||||
CONF['cloudfiles_username'])
|
||||
CONF['cloudfiles_api_key'] = ask('What is your Rackspace '
|
||||
'Cloud API key?', str_compat,
|
||||
'Cloud API key?', str,
|
||||
CONF['cloudfiles_api_key'])
|
||||
CONF['cloudfiles_container'] = ask('What is the name of your '
|
||||
'Cloud Files container?',
|
||||
str_compat,
|
||||
str,
|
||||
CONF['cloudfiles_container'])
|
||||
|
||||
if ask('Do you want to upload your website using GitHub Pages?',
|
||||
|
|
@ -330,7 +308,7 @@ needed by Pelican.
|
|||
print('Error: {0}'.format(e))
|
||||
|
||||
try:
|
||||
with codecs.open(os.path.join(CONF['basedir'], 'pelicanconf.py'),
|
||||
with open(os.path.join(CONF['basedir'], 'pelicanconf.py'),
|
||||
'w', 'utf-8') as fd:
|
||||
conf_python = dict()
|
||||
for key, value in CONF.items():
|
||||
|
|
@ -343,7 +321,7 @@ needed by Pelican.
|
|||
print('Error: {0}'.format(e))
|
||||
|
||||
try:
|
||||
with codecs.open(os.path.join(CONF['basedir'], 'publishconf.py'),
|
||||
with open(os.path.join(CONF['basedir'], 'publishconf.py'),
|
||||
'w', 'utf-8') as fd:
|
||||
_template = _jinja_env.get_template('publishconf.py.jinja2')
|
||||
fd.write(_template.render(**CONF))
|
||||
|
|
@ -353,7 +331,7 @@ needed by Pelican.
|
|||
|
||||
if automation:
|
||||
try:
|
||||
with codecs.open(os.path.join(CONF['basedir'], 'tasks.py'),
|
||||
with open(os.path.join(CONF['basedir'], 'tasks.py'),
|
||||
'w', 'utf-8') as fd:
|
||||
_template = _jinja_env.get_template('tasks.py.jinja2')
|
||||
fd.write(_template.render(**CONF))
|
||||
|
|
@ -361,10 +339,8 @@ needed by Pelican.
|
|||
except OSError as e:
|
||||
print('Error: {0}'.format(e))
|
||||
try:
|
||||
with codecs.open(os.path.join(CONF['basedir'], 'Makefile'),
|
||||
with open(os.path.join(CONF['basedir'], 'Makefile'),
|
||||
'w', 'utf-8') as fd:
|
||||
py_v = 'python'
|
||||
if six.PY3:
|
||||
py_v = 'python3'
|
||||
_template = _jinja_env.get_template('Makefile.jinja2')
|
||||
fd.write(_template.render(py_v=py_v, **CONF))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*- #
|
||||
from __future__ import unicode_literals
|
||||
|
||||
AUTHOR = {{author}}
|
||||
SITENAME = {{sitename}}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*- #
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# This file is only used if you use `make publish` or
|
||||
# explicitly specify it as your config file.
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import functools
|
||||
import logging
|
||||
import os
|
||||
|
||||
import six
|
||||
|
||||
from pelican.utils import python_2_unicode_compatible, slugify
|
||||
from pelican.utils import slugify
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
@functools.total_ordering
|
||||
class URLWrapper(object):
|
||||
def __init__(self, name, settings):
|
||||
|
|
@ -66,26 +62,26 @@ class URLWrapper(object):
|
|||
|
||||
def _normalize_key(self, key):
|
||||
subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])
|
||||
return six.text_type(slugify(key, regex_subs=subs))
|
||||
return slugify(key, regex_subs=subs)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, self.__class__):
|
||||
return self.slug == other.slug
|
||||
if isinstance(other, six.text_type):
|
||||
if isinstance(other, str):
|
||||
return self.slug == self._normalize_key(other)
|
||||
return False
|
||||
|
||||
def __ne__(self, other):
|
||||
if isinstance(other, self.__class__):
|
||||
return self.slug != other.slug
|
||||
if isinstance(other, six.text_type):
|
||||
if isinstance(other, str):
|
||||
return self.slug != self._normalize_key(other)
|
||||
return True
|
||||
|
||||
def __lt__(self, other):
|
||||
if isinstance(other, self.__class__):
|
||||
return self.slug < other.slug
|
||||
if isinstance(other, six.text_type):
|
||||
if isinstance(other, str):
|
||||
return self.slug < self._normalize_key(other)
|
||||
return False
|
||||
|
||||
|
|
@ -105,7 +101,7 @@ class URLWrapper(object):
|
|||
"""
|
||||
setting = "%s_%s" % (self.__class__.__name__.upper(), key)
|
||||
value = self.settings[setting]
|
||||
if not isinstance(value, six.string_types):
|
||||
if not isinstance(value, str):
|
||||
logger.warning('%s is set to %s', setting, value)
|
||||
return value
|
||||
else:
|
||||
|
|
@ -126,7 +122,7 @@ class Category(URLWrapper):
|
|||
|
||||
class Tag(URLWrapper):
|
||||
def __init__(self, name, *args, **kwargs):
|
||||
super(Tag, self).__init__(name.strip(), *args, **kwargs)
|
||||
super().__init__(name.strip(), *args, **kwargs)
|
||||
|
||||
|
||||
class Author(URLWrapper):
|
||||
|
|
|
|||
116
pelican/utils.py
116
pelican/utils.py
|
|
@ -1,9 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import codecs
|
||||
import datetime
|
||||
import errno
|
||||
import fnmatch
|
||||
import locale
|
||||
import logging
|
||||
|
|
@ -12,12 +9,12 @@ import re
|
|||
import shutil
|
||||
import sys
|
||||
import traceback
|
||||
try:
|
||||
import urllib
|
||||
from collections.abc import Hashable
|
||||
except ImportError:
|
||||
from collections import Hashable
|
||||
from contextlib import contextmanager
|
||||
from functools import partial
|
||||
from html import entities
|
||||
from html.parser import HTMLParser
|
||||
from itertools import groupby
|
||||
from operator import attrgetter
|
||||
|
||||
|
|
@ -27,14 +24,6 @@ from jinja2 import Markup
|
|||
|
||||
import pytz
|
||||
|
||||
import six
|
||||
from six.moves import html_entities
|
||||
from six.moves.html_parser import HTMLParser
|
||||
|
||||
try:
|
||||
from html import escape
|
||||
except ImportError:
|
||||
from cgi import escape
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -53,17 +42,11 @@ def sanitised_join(base_directory, *parts):
|
|||
|
||||
def strftime(date, date_format):
|
||||
'''
|
||||
Replacement for built-in strftime
|
||||
|
||||
This is necessary because of the way Py2 handles date format strings.
|
||||
Specifically, Py2 strftime takes a bytestring. In the case of text output
|
||||
(e.g. %b, %a, etc), the output is encoded with an encoding defined by
|
||||
locale.LC_TIME. Things get messy if the formatting string has chars that
|
||||
are not valid in LC_TIME defined encoding.
|
||||
Enhanced replacement for built-in strftime with zero stripping
|
||||
|
||||
This works by 'grabbing' possible format strings (those starting with %),
|
||||
formatting them with the date, (if necessary) decoding the output and
|
||||
replacing formatted output back.
|
||||
formatting them with the date, stripping any leading zeros if - prefix is
|
||||
used and replacing formatted output back.
|
||||
'''
|
||||
def strip_zeros(x):
|
||||
return x.lstrip('0') or '0'
|
||||
|
|
@ -76,10 +59,6 @@ def strftime(date, date_format):
|
|||
# replace candidates with placeholders for later % formatting
|
||||
template = re.sub(format_options, '%s', date_format)
|
||||
|
||||
# we need to convert formatted dates back to unicode in Py2
|
||||
# LC_TIME determines the encoding for built-in strftime outputs
|
||||
lang_code, enc = locale.getlocale(locale.LC_TIME)
|
||||
|
||||
formatted_candidates = []
|
||||
for candidate in candidates:
|
||||
# test for valid C89 directives only
|
||||
|
|
@ -98,10 +77,6 @@ def strftime(date, date_format):
|
|||
else:
|
||||
formatted = date.strftime(candidate)
|
||||
|
||||
# convert Py2 result to unicode
|
||||
if not six.PY3 and enc is not None:
|
||||
formatted = formatted.decode(enc)
|
||||
|
||||
# strip zeros if '-' prefix is used
|
||||
if conversion:
|
||||
formatted = conversion(formatted)
|
||||
|
|
@ -121,7 +96,7 @@ class SafeDatetime(datetime.datetime):
|
|||
if safe:
|
||||
return strftime(self, fmt)
|
||||
else:
|
||||
return super(SafeDatetime, self).strftime(fmt)
|
||||
return super().strftime(fmt)
|
||||
|
||||
|
||||
class DateFormatter(object):
|
||||
|
|
@ -150,22 +125,6 @@ class DateFormatter(object):
|
|||
return formatted
|
||||
|
||||
|
||||
def python_2_unicode_compatible(klass):
|
||||
"""
|
||||
A decorator that defines __unicode__ and __str__ methods under Python 2.
|
||||
Under Python 3 it does nothing.
|
||||
|
||||
To support Python 2 and 3 with a single code base, define a __str__ method
|
||||
returning text and apply this decorator to the class.
|
||||
|
||||
From django.utils.encoding.
|
||||
"""
|
||||
if not six.PY3:
|
||||
klass.__unicode__ = klass.__str__
|
||||
klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
|
||||
return klass
|
||||
|
||||
|
||||
class memoized(object):
|
||||
"""Function decorator to cache return values.
|
||||
|
||||
|
|
@ -214,15 +173,15 @@ def deprecated_attribute(old, new, since=None, remove=None, doc=None):
|
|||
content of the dummy method is ignored.
|
||||
"""
|
||||
def _warn():
|
||||
version = '.'.join(six.text_type(x) for x in since)
|
||||
version = '.'.join(str(x) for x in since)
|
||||
message = ['{} has been deprecated since {}'.format(old, version)]
|
||||
if remove:
|
||||
version = '.'.join(six.text_type(x) for x in remove)
|
||||
version = '.'.join(str(x) for x in remove)
|
||||
message.append(
|
||||
' and will be removed by version {}'.format(version))
|
||||
message.append('. Use {} instead.'.format(new))
|
||||
logger.warning(''.join(message))
|
||||
logger.debug(''.join(six.text_type(x) for x
|
||||
logger.debug(''.join(str(x) for x
|
||||
in traceback.format_stack()))
|
||||
|
||||
def fget(self):
|
||||
|
|
@ -254,15 +213,12 @@ def get_date(string):
|
|||
|
||||
|
||||
@contextmanager
|
||||
def pelican_open(filename, mode='rb', strip_crs=(sys.platform == 'win32')):
|
||||
def pelican_open(filename, mode='r', strip_crs=(sys.platform == 'win32')):
|
||||
"""Open a file and return its content"""
|
||||
|
||||
with codecs.open(filename, mode, encoding='utf-8') as infile:
|
||||
# utf-8-sig will clear any BOM if present
|
||||
with open(filename, mode, encoding='utf-8-sig') as infile:
|
||||
content = infile.read()
|
||||
if content[:1] == codecs.BOM_UTF8.decode('utf8'):
|
||||
content = content[1:]
|
||||
if strip_crs:
|
||||
content = content.replace('\r\n', '\n')
|
||||
yield content
|
||||
|
||||
|
||||
|
|
@ -279,10 +235,8 @@ def slugify(value, regex_subs=()):
|
|||
# value must be unicode per se
|
||||
import unicodedata
|
||||
from unidecode import unidecode
|
||||
# unidecode returns str in Py2 and 3, so in Py2 we have to make
|
||||
# it unicode again
|
||||
value = unidecode(value)
|
||||
if isinstance(value, six.binary_type):
|
||||
if isinstance(value, bytes):
|
||||
value = value.decode('ascii')
|
||||
# still unicode
|
||||
value = unicodedata.normalize('NFKD', value)
|
||||
|
|
@ -453,18 +407,11 @@ class _HTMLWordTruncator(HTMLParser):
|
|||
class TruncationCompleted(Exception):
|
||||
|
||||
def __init__(self, truncate_at):
|
||||
super(_HTMLWordTruncator.TruncationCompleted, self).__init__(
|
||||
truncate_at)
|
||||
super().__init__(truncate_at)
|
||||
self.truncate_at = truncate_at
|
||||
|
||||
def __init__(self, max_words):
|
||||
# In Python 2, HTMLParser is not a new-style class,
|
||||
# hence super() cannot be used.
|
||||
try:
|
||||
HTMLParser.__init__(self, convert_charrefs=False)
|
||||
except TypeError:
|
||||
# pre Python 3.3
|
||||
HTMLParser.__init__(self)
|
||||
super().__init__(convert_charrefs=False)
|
||||
|
||||
self.max_words = max_words
|
||||
self.words_found = 0
|
||||
|
|
@ -474,9 +421,7 @@ class _HTMLWordTruncator(HTMLParser):
|
|||
|
||||
def feed(self, *args, **kwargs):
|
||||
try:
|
||||
# With Python 2, super() cannot be used.
|
||||
# See the comment for __init__().
|
||||
HTMLParser.feed(self, *args, **kwargs)
|
||||
super().feed(*args, **kwargs)
|
||||
except self.TruncationCompleted as exc:
|
||||
self.truncate_at = exc.truncate_at
|
||||
else:
|
||||
|
|
@ -584,8 +529,8 @@ class _HTMLWordTruncator(HTMLParser):
|
|||
`name` is the entity ref without ampersand and semicolon (e.g. `mdash`)
|
||||
"""
|
||||
try:
|
||||
codepoint = html_entities.name2codepoint[name]
|
||||
char = six.unichr(codepoint)
|
||||
codepoint = entities.name2codepoint[name]
|
||||
char = chr(codepoint)
|
||||
except KeyError:
|
||||
char = ''
|
||||
self._handle_ref(name, char)
|
||||
|
|
@ -602,7 +547,7 @@ class _HTMLWordTruncator(HTMLParser):
|
|||
codepoint = int(name[1:], 16)
|
||||
else:
|
||||
codepoint = int(name)
|
||||
char = six.unichr(codepoint)
|
||||
char = chr(codepoint)
|
||||
except (ValueError, OverflowError):
|
||||
char = ''
|
||||
self._handle_ref('#' + name, char)
|
||||
|
|
@ -634,14 +579,6 @@ def truncate_html_words(s, num, end_text='…'):
|
|||
return out
|
||||
|
||||
|
||||
def escape_html(text, quote=True):
|
||||
"""Escape '&', '<' and '>' to HTML-safe sequences.
|
||||
|
||||
In Python 2 this uses cgi.escape and in Python 3 this uses html.escape. We
|
||||
wrap here to ensure the quote argument has an identical default."""
|
||||
return escape(text, quote=quote)
|
||||
|
||||
|
||||
def process_translations(content_list, translation_id=None):
|
||||
""" Finds translations and returns them.
|
||||
|
||||
|
|
@ -663,7 +600,7 @@ def process_translations(content_list, translation_id=None):
|
|||
if not translation_id:
|
||||
return content_list, []
|
||||
|
||||
if isinstance(translation_id, six.string_types):
|
||||
if isinstance(translation_id, str):
|
||||
translation_id = {translation_id}
|
||||
|
||||
index = []
|
||||
|
|
@ -753,7 +690,7 @@ def order_content(content_list, order_by='slug'):
|
|||
content_list.sort(key=order_by)
|
||||
except Exception:
|
||||
logger.error('Error sorting with function %s', order_by)
|
||||
elif isinstance(order_by, six.string_types):
|
||||
elif isinstance(order_by, str):
|
||||
if order_by.startswith('reversed-'):
|
||||
order_reversed = True
|
||||
order_by = order_by.replace('reversed-', '', 1)
|
||||
|
|
@ -857,11 +794,7 @@ def set_date_tzinfo(d, tz_name=None):
|
|||
|
||||
|
||||
def mkdir_p(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as e:
|
||||
if e.errno != errno.EEXIST or not os.path.isdir(path):
|
||||
raise
|
||||
os.makedirs(path, exist_ok=True)
|
||||
|
||||
|
||||
def split_all(path):
|
||||
|
|
@ -901,8 +834,7 @@ def is_selected_for_writing(settings, path):
|
|||
|
||||
def path_to_file_url(path):
|
||||
'''Convert file-system path to file:// URL'''
|
||||
return six.moves.urllib_parse.urljoin(
|
||||
"file://", six.moves.urllib.request.pathname2url(path))
|
||||
return urllib.parse.urljoin("file://", urllib.request.pathname2url(path))
|
||||
|
||||
|
||||
def maybe_pluralize(count, singular, plural):
|
||||
|
|
|
|||
|
|
@ -1,24 +1,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, unicode_literals, with_statement
|
||||
|
||||
import logging
|
||||
import os
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from feedgenerator import Atom1Feed, Rss201rev2Feed, get_tag_uri
|
||||
|
||||
from jinja2 import Markup
|
||||
|
||||
import six
|
||||
from six.moves.urllib.parse import urljoin
|
||||
|
||||
from pelican import signals
|
||||
from pelican.paginator import Paginator
|
||||
from pelican.utils import (get_relative_path, is_selected_for_writing,
|
||||
path_to_url, sanitised_join, set_date_tzinfo)
|
||||
|
||||
if not six.PY3:
|
||||
from codecs import open
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
|
@ -165,8 +159,7 @@ class Writer(object):
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
encoding = 'utf-8' if six.PY3 else None
|
||||
with self._open_w(complete_path, encoding, override_output) as fp:
|
||||
with self._open_w(complete_path, 'utf-8', override_output) as fp:
|
||||
feed.write(fp, 'utf-8')
|
||||
logger.info('Writing %s', complete_path)
|
||||
|
||||
|
|
|
|||
126
poetry.lock
generated
126
poetry.lock
generated
|
|
@ -17,15 +17,6 @@ version = "2.7.0"
|
|||
[package.dependencies]
|
||||
pytz = ">=2015.7"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "backports.functools_lru_cache"
|
||||
marker = "python_version < \"3\""
|
||||
name = "backports.functools-lru-cache"
|
||||
optional = false
|
||||
python-versions = ">=2.6"
|
||||
version = "1.5"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Screen-scraping library"
|
||||
|
|
@ -54,31 +45,13 @@ optional = false
|
|||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "0.4.1"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Updated configparser from Python 3.7 for Python 2.6+."
|
||||
marker = "python_version < \"3.2\""
|
||||
name = "configparser"
|
||||
optional = false
|
||||
python-versions = ">=2.6"
|
||||
version = "3.7.4"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Backports and enhancements for the contextlib module"
|
||||
marker = "python_version < \"3\""
|
||||
name = "contextlib2"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.5.5"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Docutils -- Python Documentation Utilities"
|
||||
name = "docutils"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.14"
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
version = "0.15.2"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
|
|
@ -88,20 +61,6 @@ optional = false
|
|||
python-versions = ">=2.7"
|
||||
version = "0.3"
|
||||
|
||||
[package.dependencies]
|
||||
[package.dependencies.configparser]
|
||||
python = ">=2.7,<2.8"
|
||||
version = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Python 3.4 Enum backported to 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4"
|
||||
marker = "python_version < \"3.4\""
|
||||
name = "enum34"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.1.6"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Standalone version of django.utils.feedgenerator"
|
||||
|
|
@ -136,22 +95,6 @@ mccabe = ">=0.6.0,<0.7.0"
|
|||
pycodestyle = ">=2.5.0,<2.6.0"
|
||||
pyflakes = ">=2.1.0,<2.2.0"
|
||||
|
||||
[package.dependencies.configparser]
|
||||
python = "<3.2"
|
||||
version = "*"
|
||||
|
||||
[package.dependencies.enum34]
|
||||
python = "<3.4"
|
||||
version = "*"
|
||||
|
||||
[package.dependencies.functools32]
|
||||
python = "<3.2"
|
||||
version = "*"
|
||||
|
||||
[package.dependencies.typing]
|
||||
python = "<3.5"
|
||||
version = "*"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Flake8 and pylama plugin that checks the ordering of import statements."
|
||||
|
|
@ -164,28 +107,6 @@ version = "0.18.1"
|
|||
pycodestyle = "*"
|
||||
setuptools = "*"
|
||||
|
||||
[package.dependencies.enum34]
|
||||
python = "<2.8"
|
||||
version = "*"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Python function signatures from PEP362 for Python 2.6, 2.7 and 3.2+"
|
||||
marker = "python_version < \"3.3\""
|
||||
name = "funcsigs"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.0.2"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Backport of the functools module from Python 3.2.3 for use on 2.7 and PyPy."
|
||||
marker = "python_version < \"3.2\""
|
||||
name = "functools32"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "3.2.3-2"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Getting image size from png/jpeg/jpeg2000/gif file"
|
||||
|
|
@ -205,14 +126,6 @@ version = "0.18"
|
|||
[package.dependencies]
|
||||
zipp = ">=0.5"
|
||||
|
||||
[package.dependencies.configparser]
|
||||
python = "<3"
|
||||
version = ">=3.5"
|
||||
|
||||
[package.dependencies.contextlib2]
|
||||
python = "<3"
|
||||
version = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "A small but fast and easy to use stand-alone template engine written in pure python."
|
||||
|
|
@ -270,10 +183,6 @@ version = "3.0.5"
|
|||
[package.dependencies]
|
||||
six = "*"
|
||||
|
||||
[package.dependencies.funcsigs]
|
||||
python = "<3.3"
|
||||
version = ">=1"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Core utilities for Python packages"
|
||||
|
|
@ -362,7 +271,7 @@ description = "Python 2 and 3 compatibility utilities"
|
|||
name = "six"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*"
|
||||
version = "1.12.0"
|
||||
version = "1.13.0"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
|
|
@ -388,11 +297,6 @@ optional = false
|
|||
python-versions = "*"
|
||||
version = "1.9.2"
|
||||
|
||||
[package.dependencies]
|
||||
[package.dependencies."backports.functools-lru-cache"]
|
||||
python = "<3"
|
||||
version = "*"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Python documentation generator"
|
||||
|
|
@ -449,15 +353,6 @@ six = ">=1.0.0,<2"
|
|||
toml = ">=0.9.4"
|
||||
virtualenv = ">=14.0.0"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Type Hints for Python"
|
||||
marker = "python_version < \"3.5\""
|
||||
name = "typing"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "3.7.4"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Filters to enhance web typography, including support for Django & Jinja templates"
|
||||
|
|
@ -497,27 +392,21 @@ version = "0.5.1"
|
|||
markdown = ["markdown"]
|
||||
|
||||
[metadata]
|
||||
content-hash = "d22ff0db3331186ab2f809313de1f9efef1f9c708cc354eaa1638a5111404612"
|
||||
python-versions = "~2.7 || ^3.5"
|
||||
content-hash = "b8fa239ebaf9bf4bcd5c2e02cf94d065a1add4e19d8354cedf19db6378d6b848"
|
||||
python-versions = "^3.5"
|
||||
|
||||
[metadata.hashes]
|
||||
alabaster = ["446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", "a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"]
|
||||
babel = ["af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab", "e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28"]
|
||||
"backports.functools-lru-cache" = ["9d98697f088eb1b0fa451391f91afb5e3ebde16bbdb272819fd091151fda4f1a", "f0b0e4eba956de51238e17573b7087e852dfe9854afd2e9c873f73fc0ca0a6dd"]
|
||||
beautifulsoup4 = ["034740f6cb549b4e932ae1ab975581e6103ac8f942200a0e9759065984391858", "945065979fb8529dd2f37dbb58f00b661bdbcbebf954f93b32fdf5263ef35348", "ba6d5c59906a85ac23dadfe5c88deaf3e179ef565f4898671253e50a78680718"]
|
||||
blinker = ["471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6"]
|
||||
colorama = ["05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", "f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"]
|
||||
configparser = ["8be81d89d6e7b4c0d4e44bcc525845f6da25821de80cb5e06e7e0238a2899e32", "da60d0014fd8c55eb48c1c5354352e363e2d30bbf7057e5e171a468390184c75"]
|
||||
contextlib2 = ["509f9419ee91cdd00ba34443217d5ca51f5a364a404e1dce9e8979cea969ca48", "f5260a6e679d2ff42ec91ec5252f4eeffdcf21053db9113bd0a8e4d953769c00"]
|
||||
docutils = ["02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", "51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", "7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6"]
|
||||
docutils = ["6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0", "9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827", "a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99"]
|
||||
entrypoints = ["589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", "c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"]
|
||||
enum34 = ["2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850", "644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a", "6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79", "8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1"]
|
||||
feedgenerator = ["5ae05daa9cfa47fa406ee4744d0b7fa1c8a05a7a47ee0ad328ddf55327cfb106"]
|
||||
filelock = ["18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59", "929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"]
|
||||
flake8 = ["859996073f341f2670741b51ec1e67a01da142831aa1fdc6242dbf88dffbe661", "a796a115208f5c03b18f332f7c11729812c8c3ded6c46319c59b53efd3819da8"]
|
||||
flake8-import-order = ["90a80e46886259b9c396b578d75c749801a41ee969a235e163cfe1be7afd2543", "a28dc39545ea4606c1ac3c24e9d05c849c6e5444a50fb7e9cdd430fc94de6e92"]
|
||||
funcsigs = ["330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca", "a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"]
|
||||
functools32 = ["89d824aa6c358c421a234d7f9ee0bd75933a67c29588ce50aaa3acdf4d403fa0", "f6253dfbe0538ad2e387bd8fdfd9293c925d63553f5813c4e587745416501e6d"]
|
||||
imagesize = ["3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8", "f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5"]
|
||||
importlib-metadata = ["6dfd58dfe281e8d240937776065dd3624ad5469c835248219bd16cf2e12dbeb7", "cb6ee23b46173539939964df59d3d72c3e0c1b5d54b84f1d8a7e912fe43612db"]
|
||||
jinja2 = ["065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", "14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b"]
|
||||
|
|
@ -535,7 +424,7 @@ pygments = ["71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127",
|
|||
pyparsing = ["1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a", "9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03"]
|
||||
python-dateutil = ["7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", "c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e"]
|
||||
pytz = ["303879e36b721603cc54604edcac9d20401bdbe31e1e4fdee5b9f98d5d31dfda", "d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141"]
|
||||
six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"]
|
||||
six = ["1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", "30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"]
|
||||
smartypants = ["8db97f7cbdf08d15b158a86037cd9e116b4cf37703d24e0419a0d64ca5808f0d"]
|
||||
snowballstemmer = ["9f3b9ffe0809d174f7047e121431acf99c89a7040f0ca84f94ba53a498e6d0c9"]
|
||||
soupsieve = ["72b5f1aea9101cf720a36bb2327ede866fd6f1a07b1e87c92a1cc18113cbc946", "e4e9c053d59795e440163733a7fec6c5972210e1790c507e4c7b051d6c5259de"]
|
||||
|
|
@ -543,7 +432,6 @@ sphinx = ["82cd2728c906be96e307b81352d3fd9fb731869234c6b835cc25e9a3dfb4b7e4", "b
|
|||
sphinx-rtd-theme = ["00cf895504a7895ee433807c62094cf1e95f065843bf3acd17037c3e9a2becd4", "728607e34d60456d736cc7991fd236afb828b21b82f956c5ea75f94c8414040a"]
|
||||
toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"]
|
||||
tox = ["dab0b0160dd187b654fc33d690ee1d7bf328bd5b8dc6ef3bb3cc468969c659ba", "ee35ffce74933a6c6ac10c9a0182e41763140a5a5070e21b114feca56eaccdcd"]
|
||||
typing = ["38566c558a0a94d6531012c8e917b1b8518a41e418f7f15f00e129cc80162ad3", "53765ec4f83a2b720214727e319607879fec4acde22c4fbb54fa2604e79e44ce", "84698954b4e6719e912ef9a42a2431407fe3755590831699debda6fba92aac55"]
|
||||
typogrify = ["8be4668cda434163ce229d87ca273a11922cb1614cb359970b7dc96eed13cb38"]
|
||||
unidecode = ["1d7a042116536098d05d599ef2b8616759f02985c85b4fef50c78a5aaf10822a", "2b6aab710c2a1647e928e36d69c21e76b453cd455f4e2621000e54b2a9b8cce8"]
|
||||
virtualenv = ["b7335cddd9260a3dd214b73a2521ffc09647bde3e9457fcca31dc3be3999d04a", "d28ca64c0f3f125f59cabf13e0a150e1c68e5eea60983cc4395d88c584495783"]
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ classifiers = [
|
|||
"Framework :: Pelican",
|
||||
"License :: OSI Approved :: GNU Affero General Public License v3",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python :: 2",
|
||||
"Programming Language :: Python :: 2.7",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
|
|
@ -29,7 +27,7 @@ classifiers = [
|
|||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "~2.7 || ^3.5"
|
||||
python = "^3.5"
|
||||
feedgenerator = "^1.9"
|
||||
jinja2 = "~2.10.1"
|
||||
pygments = "^2.4"
|
||||
|
|
@ -37,9 +35,8 @@ pytz = "^2019.1"
|
|||
blinker = "^1.4"
|
||||
unidecode = "^1.1"
|
||||
python-dateutil = "^2.8"
|
||||
docutils = "^0.14"
|
||||
docutils = "^0.15"
|
||||
markdown = {version = "~3.1.1", optional = true}
|
||||
six = "^1.4"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
BeautifulSoup4 = "^4.7"
|
||||
|
|
|
|||
1
samples/pelican.conf.py
vendored
1
samples/pelican.conf.py
vendored
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
AUTHOR = 'Alexis Métaireau'
|
||||
SITENAME = "Alexis' log"
|
||||
|
|
|
|||
1
samples/pelican.conf_FR.py
vendored
1
samples/pelican.conf_FR.py
vendored
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
AUTHOR = 'Alexis Métaireau'
|
||||
SITENAME = "Alexis' log"
|
||||
|
|
|
|||
12
setup.py
12
setup.py
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
import sys
|
||||
|
||||
from io import open
|
||||
from os import walk
|
||||
from os.path import join, relpath
|
||||
|
|
@ -9,8 +9,8 @@ from setuptools import setup
|
|||
|
||||
version = "4.2.0"
|
||||
|
||||
requires = ['feedgenerator >= 1.9', 'jinja2 >= 2.7', 'pygments', 'docutils',
|
||||
'pytz >= 0a', 'blinker', 'unidecode', 'six >= 1.4',
|
||||
requires = ['feedgenerator >= 1.9', 'jinja2 >= 2.7', 'pygments',
|
||||
'docutils>=0.15', 'pytz >= 0a', 'blinker', 'unidecode',
|
||||
'python-dateutil']
|
||||
|
||||
entry_points = {
|
||||
|
|
@ -25,9 +25,7 @@ entry_points = {
|
|||
README = open('README.rst', encoding='utf-8').read()
|
||||
CHANGELOG = open('docs/changelog.rst', encoding='utf-8').read()
|
||||
|
||||
description = u'\n'.join([README, CHANGELOG])
|
||||
if sys.version_info.major < 3:
|
||||
description = description.encode('utf-8')
|
||||
description = '\n'.join([README, CHANGELOG])
|
||||
|
||||
setup(
|
||||
name='pelican',
|
||||
|
|
@ -71,8 +69,6 @@ setup(
|
|||
'Framework :: Pelican',
|
||||
'License :: OSI Approved :: GNU Affero General Public License v3',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
|
|
|
|||
3
tox.ini
3
tox.ini
|
|
@ -1,9 +1,8 @@
|
|||
[tox]
|
||||
envlist = py{27,35,36,37},docs,flake8
|
||||
envlist = py{35,36,37},docs,flake8
|
||||
|
||||
[testenv]
|
||||
basepython =
|
||||
py27: python2.7
|
||||
py35: python3.5
|
||||
py36: python3.6
|
||||
py37: python3.7
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue