1
0
Fork 0
forked from github/pelican

Merge pull request #2649 from iKevinY/py2-sunset

Remove Python 2 support
This commit is contained in:
Justin Mayer 2019-11-26 14:03:13 -08:00 committed by GitHub
commit 772005f431
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 203 additions and 627 deletions

1
.gitignore vendored
View file

@ -11,7 +11,6 @@ tags
.tox
.coverage
htmlcov
six-*.egg/
*.orig
venv
samples/output

View file

@ -11,7 +11,6 @@ env:
matrix:
- TOX_ENV=docs
- TOX_ENV=flake8
- TOX_ENV=py27
- TOX_ENV=py35
- TOX_ENV=py36
matrix:

2
THANKS
View file

@ -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

View file

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import os
import sys

View file

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

View file

@ -1,7 +1,6 @@
"""
python -m pelican module entry point to run via python -m
"""
from __future__ import absolute_import
from . import main

View file

@ -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

View file

@ -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.

View file

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

View file

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

View file

@ -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

View file

@ -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 = {}

View file

@ -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

View file

@ -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

View file

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

View file

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
from blinker import signal

View file

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

View file

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

View file

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import os
from shutil import rmtree

View file

@ -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}',

View file

@ -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

View file

@ -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,

View file

@ -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 = {

View file

@ -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):

View file

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

View file

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
from pelican.tests.support import unittest

View file

@ -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

View file

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import copy
import locale

View file

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import warnings

View file

@ -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

View file

@ -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(

View file

@ -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/"

View file

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

View file

@ -1,6 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import argparse
import os

View file

@ -1,6 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*- #
from __future__ import unicode_literals
AUTHOR = {{author}}
SITENAME = {{sitename}}

View file

@ -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.

View 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):

View file

@ -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):

View file

@ -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
View file

@ -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"]

View file

@ -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"

View file

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
AUTHOR = 'Alexis Métaireau'
SITENAME = "Alexis' log"

View file

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
AUTHOR = 'Alexis Métaireau'
SITENAME = "Alexis' log"

View file

@ -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',

View file

@ -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