Add initial (experimental) Python 3 support.main
@@ -2,7 +2,7 @@ sudo: false | |||
language: python | |||
python: | |||
- "2.7" | |||
- "3.5" | |||
addons: | |||
apt: | |||
@@ -40,6 +40,9 @@ install: | |||
# Run each tox environment separately | |||
env: | |||
- TOX_ENV=py27 | |||
- TOX_ENV=py33 | |||
- TOX_ENV=py34 | |||
- TOX_ENV=py35 | |||
- TOX_ENV=pep8 | |||
before_script: | |||
@@ -1,3 +1,9 @@ | |||
Version TBA | |||
=========== | |||
* Experimental Python 3 support | |||
Version 0.8.9 (2015-11-09) | |||
=========================================================== | |||
@@ -0,0 +1,91 @@ | |||
"""2/3 compatibility module for Hyde.""" | |||
# This module is for cross-version compatibility. As such, several | |||
# assignments and import will look invalid to checkers like flake8. | |||
# These lines are being marked with ``# NOQA`` to allow flake8 checking | |||
# to pass. | |||
import sys | |||
PY3 = sys.version_info.major == 3 | |||
if PY3: | |||
# Imports that have moved. | |||
from collections import UserDict # NOQA | |||
from functools import reduce # NOQA | |||
from http.server import HTTPServer, SimpleHTTPRequestHandler # NOQA | |||
from io import StringIO # NOQA | |||
from urllib import parse # NOQA | |||
from urllib.parse import quote, unquote # NOQA | |||
# Types that have changed name. | |||
filter = filter # NOQA | |||
input = input # NOQA | |||
basestring = str # NOQA | |||
str = str # NOQA | |||
zip = zip # NOQA | |||
def execfile(filename, globals, locals): | |||
"""Python 3 replacement for ``execfile``.""" | |||
# Credit: 2to3 and this StackOverflow answer | |||
# (http://stackoverflow.com/a/437857/841994) take similar | |||
# approaches. | |||
with open(filename) as f: | |||
code = compile(f.read(), filename, 'exec') | |||
exec(code, globals, locals) | |||
def reraise(tp, value, tb=None): | |||
"""Reraise exceptions.""" | |||
if getattr(value, '__traceback__', tb) is not tb: | |||
raise value.with_traceback(tb) | |||
raise value | |||
else: | |||
# Imports that have moved. | |||
from itertools import ifilter as filter, izip as zip # NOQA | |||
reduce = reduce | |||
from BaseHTTPServer import HTTPServer # NOQA | |||
from SimpleHTTPServer import SimpleHTTPRequestHandler # NOQA | |||
from cStringIO import StringIO # NOQA | |||
from UserDict import IterableUserDict as UserDict # NOQA | |||
import urlparse as parse # NOQA | |||
from urllib import quote, unquote # NOQA | |||
# Types that have changed name. | |||
input = raw_input # NOQA | |||
basestring = basestring # NOQA | |||
str = unicode # NOQA | |||
execfile = execfile # NOQA | |||
exec('def reraise(tp, value, tb=None):\n raise tp, value, tb') | |||
def iteritems(d): | |||
"""Return iterable items from a dict.""" | |||
if hasattr(d, 'iteritems'): | |||
return d.iteritems() | |||
else: | |||
return iter(d.items()) | |||
def with_metaclass(meta, *bases): | |||
"""Assign a metaclass in a 2/3 compatible fashion.""" | |||
# Note: borrowed from https://github.com/dirn/Simon/ | |||
# This requires a bit of explanation: the basic idea is to make a | |||
# dummy metaclass for one level of class instantiation that replaces | |||
# itself with the actual metaclass. Because of internal type checks | |||
# we also need to make sure that we downgrade the custom metaclass | |||
# for one level to something closer to type (that's why __call__ and | |||
# __init__ comes back from type etc.). | |||
# | |||
# This has the advantage over six.with_metaclass in that it does not | |||
# introduce dummy classes into the final MRO. | |||
class metaclass(meta): | |||
__call__ = type.__call__ | |||
__init__ = type.__init__ | |||
def __new__(cls, name, this_bases, d): | |||
if this_bases is None: | |||
return type.__new__(cls, name, (), d) | |||
return meta(name, bases, d) | |||
return metaclass('DummyMetaClass', None, {}) |
@@ -1,10 +1,10 @@ | |||
class HydeException(Exception): | |||
from hyde._compat import reraise | |||
""" | |||
Base class for exceptions from hyde | |||
""" | |||
class HydeException(Exception): | |||
"""Base class for exceptions from hyde.""" | |||
@staticmethod | |||
def reraise(message, exc_info): | |||
_, _, tb = exc_info | |||
raise HydeException(message), None, tb | |||
reraise(HydeException, HydeException(message), tb) |
@@ -3,7 +3,7 @@ | |||
CSS plugins | |||
""" | |||
from hyde._compat import str | |||
from hyde.plugin import CLTransformer, Plugin | |||
from hyde.exceptions import HydeException | |||
@@ -109,9 +109,9 @@ class LessCSSPlugin(CLTransformer): | |||
less = self.app | |||
source = File.make_temp(text) | |||
target = File.make_temp('') | |||
args = [unicode(less)] | |||
args = [str(less)] | |||
args.extend(self.process_args(supported)) | |||
args.extend([unicode(source), unicode(target)]) | |||
args.extend([str(source), str(target)]) | |||
try: | |||
self.call_app(args) | |||
except subprocess.CalledProcessError: | |||
@@ -223,9 +223,9 @@ class StylusPlugin(CLTransformer): | |||
source = File.make_temp(text.strip()) | |||
supported = [("compress", "c"), ("include", "I")] | |||
args = [unicode(stylus)] | |||
args = [str(stylus)] | |||
args.extend(self.process_args(supported)) | |||
args.append(unicode(source)) | |||
args.append(str(source)) | |||
try: | |||
self.call_app(args) | |||
except subprocess.CalledProcessError: | |||
@@ -251,7 +251,7 @@ class CleverCSSPlugin(Plugin): | |||
super(CleverCSSPlugin, self).__init__(site) | |||
try: | |||
import clevercss | |||
except ImportError, e: | |||
except ImportError as e: | |||
raise HydeException('Unable to import CleverCSS: ' + e.message) | |||
else: | |||
self.clevercss = clevercss | |||
@@ -329,7 +329,7 @@ class SassyCSSPlugin(Plugin): | |||
super(SassyCSSPlugin, self).__init__(site) | |||
try: | |||
import scss | |||
except ImportError, e: | |||
except ImportError as e: | |||
raise HydeException('Unable to import pyScss: ' + e.message) | |||
else: | |||
self.scss = scss | |||
@@ -419,7 +419,7 @@ class SassPlugin(Plugin): | |||
super(SassPlugin, self).__init__(site) | |||
try: | |||
import sass | |||
except ImportError, e: | |||
except ImportError as e: | |||
raise HydeException('Unable to import libsass: ' + e.message) | |||
else: | |||
self.sass = sass | |||
@@ -489,6 +489,6 @@ class SassPlugin(Plugin): | |||
self.logger.error(resource) | |||
try: | |||
return self.sass.compile(string=text, **options) | |||
except Exception, exc: | |||
except Exception as exc: | |||
self.logger.error(exc) | |||
raise |
@@ -5,6 +5,7 @@ Depends plugin | |||
/// Experimental: Not working yet. | |||
""" | |||
from hyde._compat import basestring | |||
from hyde.plugin import Plugin | |||
@@ -14,6 +14,7 @@ import re | |||
from fswrap import File | |||
from hyde._compat import str | |||
from hyde.exceptions import HydeException | |||
@@ -27,7 +28,7 @@ class PILPlugin(Plugin): | |||
# No pillow | |||
try: | |||
import Image | |||
except ImportError, e: | |||
except ImportError as e: | |||
raise HydeException('Unable to load PIL: ' + e.message) | |||
self.Image = Image | |||
@@ -442,9 +443,9 @@ class JPEGOptimPlugin(CLTransformer): | |||
target = File(self.site.config.deploy_root_path.child( | |||
resource.relative_deploy_path)) | |||
jpegoptim = self.app | |||
args = [unicode(jpegoptim)] | |||
args = [str(jpegoptim)] | |||
args.extend(self.process_args(supported)) | |||
args.extend(["-q", unicode(target)]) | |||
args.extend(["-q", str(target)]) | |||
self.call_app(args) | |||
@@ -499,9 +500,9 @@ class JPEGTranPlugin(CLTransformer): | |||
resource.relative_deploy_path)) | |||
target = File.make_temp('') | |||
jpegtran = self.app | |||
args = [unicode(jpegtran)] | |||
args = [str(jpegtran)] | |||
args.extend(self.process_args(supported)) | |||
args.extend(["-outfile", unicode(target), unicode(source)]) | |||
args.extend(["-outfile", str(target), str(source)]) | |||
self.call_app(args) | |||
target.copy_to(source) | |||
target.delete() | |||
@@ -570,7 +571,7 @@ class OptiPNGPlugin(CLTransformer): | |||
target = File(self.site.config.deploy_root_path.child( | |||
resource.relative_deploy_path)) | |||
optipng = self.app | |||
args = [unicode(optipng)] | |||
args = [str(optipng)] | |||
args.extend(self.process_args(supported)) | |||
args.extend([unicode(target)]) | |||
args.extend([str(target)]) | |||
self.call_app(args) |
@@ -5,6 +5,7 @@ JavaScript plugins | |||
import subprocess | |||
import sys | |||
from hyde._compat import str | |||
from hyde.exceptions import HydeException | |||
from hyde.plugin import CLTransformer | |||
@@ -79,9 +80,9 @@ class UglifyPlugin(CLTransformer): | |||
uglify = self.app | |||
source = File.make_temp(text) | |||
target = File.make_temp('') | |||
args = [unicode(uglify)] | |||
args = [str(uglify)] | |||
args.extend(self.process_args(supported)) | |||
args.extend(["-o", unicode(target), unicode(source)]) | |||
args.extend(["-o", str(target), str(source)]) | |||
self.call_app(args) | |||
out = target.read_all() | |||
return out | |||
@@ -127,9 +128,9 @@ class RequireJSPlugin(CLTransformer): | |||
rjs = self.app | |||
target = File.make_temp('') | |||
args = [unicode(rjs)] | |||
args = [str(rjs)] | |||
args.extend( | |||
['-o', unicode(resource), ("out=" + target.fully_expanded_path)]) | |||
['-o', str(resource), ("out=" + target.fully_expanded_path)]) | |||
try: | |||
self.call_app(args) | |||
@@ -184,6 +185,6 @@ class CoffeePlugin(CLTransformer): | |||
coffee = self.app | |||
source = File.make_temp(text) | |||
args = [unicode(coffee)] | |||
args.extend(["-c", "-p", unicode(source)]) | |||
args = [str(coffee)] | |||
args.extend(["-c", "-p", str(source)]) | |||
return self.call_app(args) |
@@ -5,11 +5,11 @@ Contains classes and utilities related to meta data in hyde. | |||
from collections import namedtuple | |||
from functools import partial | |||
from itertools import ifilter | |||
from operator import attrgetter | |||
import re | |||
import sys | |||
from hyde._compat import basestring, filter, iteritems, str | |||
from hyde.exceptions import HydeException | |||
from hyde.model import Expando | |||
from hyde.plugin import Plugin | |||
@@ -263,7 +263,7 @@ def get_tagger_sort_method(site): | |||
def walk_resources_tagged_with(node, tag): | |||
tags = set(unicode(tag).split('+')) | |||
tags = set(str(tag).split('+')) | |||
walker = get_tagger_sort_method(node.site) | |||
for resource in walker(): | |||
try: | |||
@@ -329,7 +329,7 @@ class TaggerPlugin(Plugin): | |||
except AttributeError: | |||
tag_meta = {} | |||
for tagname, meta in tag_meta.iteritems(): | |||
for tagname, meta in iteritems(tag_meta): | |||
# Don't allow name and resources in meta | |||
if 'resources' in meta: | |||
del(meta['resources']) | |||
@@ -376,7 +376,7 @@ class TaggerPlugin(Plugin): | |||
self.logger.debug("Generating archives for tags") | |||
for name, config in archive_config.to_dict().iteritems(): | |||
for name, config in iteritems(archive_config.to_dict()): | |||
self._create_tag_archive(config) | |||
def _create_tag_archive(self, config): | |||
@@ -413,7 +413,7 @@ extends: false | |||
{%% set walker = source['walk_resources_tagged_with_%(tag)s'] %%} | |||
{%% extends "%(template)s" %%} | |||
""" | |||
for tagname, tag in self.site.tagger.tags.to_dict().iteritems(): | |||
for tagname, tag in iteritems(self.site.tagger.tags.to_dict()): | |||
tag_data = { | |||
"tag": tagname, | |||
"node": source.name, | |||
@@ -482,8 +482,8 @@ def sort_method(node, settings=None): | |||
excluder_ = partial(attributes_checker, attributes=attr) | |||
resources = ifilter(lambda x: excluder_(x) and filter_(x), | |||
node.walk_resources()) | |||
resources = filter(lambda x: excluder_(x) and filter_(x), | |||
node.walk_resources()) | |||
return sorted(resources, | |||
key=attrgetter(*attr), | |||
reverse=reverse) | |||
@@ -44,6 +44,7 @@ import os | |||
import json | |||
import tempfile | |||
from hyde._compat import execfile, iteritems | |||
from hyde.plugin import Plugin | |||
from hyde.model import Expando | |||
from hyde.ext.plugins.meta import MetaPlugin as _MetaPlugin | |||
@@ -166,7 +167,7 @@ class SphinxPlugin(Plugin): | |||
if not settings.block_map: | |||
output.append(sphinx_output["body"]) | |||
else: | |||
for (nm, content) in sphinx_output.iteritems(): | |||
for (nm, content) in iteritems(sphinx_output): | |||
try: | |||
block = getattr(settings.block_map, nm) | |||
except AttributeError: | |||
@@ -3,6 +3,7 @@ | |||
Plugins related to structure | |||
""" | |||
from hyde._compat import reduce | |||
from hyde.ext.plugins.meta import Metadata | |||
from hyde.plugin import Plugin | |||
from hyde.site import Resource | |||
@@ -3,14 +3,14 @@ Contains classes and utilities that help publishing a hyde website to | |||
distributed version control systems. | |||
""" | |||
from hyde._compat import str, with_metaclass | |||
from hyde.publisher import Publisher | |||
import abc | |||
from subprocess import Popen, PIPE | |||
class DVCS(Publisher): | |||
__metaclass__ = abc.ABCMeta | |||
class DVCS(with_metaclass(abc.ABCMeta, Publisher)): | |||
def initialize(self, settings): | |||
self.settings = settings | |||
@@ -62,7 +62,7 @@ class Git(DVCS): | |||
def add(self, path="."): | |||
cmd = Popen('git add "%s"' % path, | |||
cwd=unicode(self.path), stdout=PIPE, shell=True) | |||
cwd=str(self.path), stdout=PIPE, shell=True) | |||
cmdresult = cmd.communicate()[0] | |||
if cmd.returncode: | |||
raise Exception(cmdresult) | |||
@@ -70,7 +70,7 @@ class Git(DVCS): | |||
def pull(self): | |||
self.switch(self.branch) | |||
cmd = Popen("git pull origin %s" % self.branch, | |||
cwd=unicode(self.path), | |||
cwd=str(self.path), | |||
stdout=PIPE, | |||
shell=True) | |||
cmdresult = cmd.communicate()[0] | |||
@@ -79,7 +79,7 @@ class Git(DVCS): | |||
def push(self): | |||
cmd = Popen("git push origin %s" % self.branch, | |||
cwd=unicode(self.path), stdout=PIPE, | |||
cwd=str(self.path), stdout=PIPE, | |||
shell=True) | |||
cmdresult = cmd.communicate()[0] | |||
if cmd.returncode: | |||
@@ -87,7 +87,7 @@ class Git(DVCS): | |||
def commit(self, message): | |||
cmd = Popen('git commit -a -m"%s"' % message, | |||
cwd=unicode(self.path), stdout=PIPE, shell=True) | |||
cwd=str(self.path), stdout=PIPE, shell=True) | |||
cmdresult = cmd.communicate()[0] | |||
if cmd.returncode: | |||
raise Exception(cmdresult) | |||
@@ -95,14 +95,14 @@ class Git(DVCS): | |||
def switch(self, branch): | |||
self.branch = branch | |||
cmd = Popen('git checkout %s' % branch, | |||
cwd=unicode(self.path), stdout=PIPE, shell=True) | |||
cwd=str(self.path), stdout=PIPE, shell=True) | |||
cmdresult = cmd.communicate()[0] | |||
if cmd.returncode: | |||
raise Exception(cmdresult) | |||
def merge(self, branch): | |||
cmd = Popen('git merge %s' % branch, | |||
cwd=unicode(self.path), stdout=PIPE, shell=True) | |||
cwd=str(self.path), stdout=PIPE, shell=True) | |||
cmdresult = cmd.communicate()[0] | |||
if cmd.returncode: | |||
raise Exception(cmdresult) |
@@ -15,6 +15,7 @@ import getpass | |||
import hashlib | |||
from hyde._compat import basestring, input | |||
from hyde.publisher import Publisher | |||
from commando.util import getLoggerWithNullHandler | |||
@@ -47,8 +48,8 @@ class PyFS(Publisher): | |||
def prompt_for_credentials(self): | |||
credentials = {} | |||
if "%(username)s" in self.url: | |||
print "Username: ", | |||
credentials["username"] = raw_input().strip() | |||
print("Username: ",) | |||
credentials["username"] = input().strip() | |||
if "%(password)s" in self.url: | |||
credentials["password"] = getpass.getpass("Password: ") | |||
if credentials: | |||
@@ -13,6 +13,7 @@ import urlparse | |||
from base64 import standard_b64encode | |||
import ConfigParser | |||
from hyde._compat import input | |||
from hyde.publisher import Publisher | |||
from commando.util import getLoggerWithNullHandler | |||
@@ -47,8 +48,8 @@ class PyPI(Publisher): | |||
pass | |||
# Prompt for username on command-line | |||
if self.username is None: | |||
print "Username: ", | |||
self.username = raw_input().strip() | |||
print("Username: ",) | |||
self.username = input().strip() | |||
# Try to find password in .pypirc | |||
if self.password is None: | |||
if pypirc is not None: | |||
@@ -30,6 +30,7 @@ within the ``deploy/`` directory: | |||
rsync -r -e ssh ./ username@ssh.server.com:/www/username/mysite/ | |||
""" | |||
from hyde._compat import str | |||
from hyde.publisher import Publisher | |||
from subprocess import Popen, PIPE | |||
@@ -54,7 +55,7 @@ class SSH(Publisher): | |||
target=self.target) | |||
deploy_path = self.site.config.deploy_root_path.path | |||
cmd = Popen(command, cwd=unicode(deploy_path), stdout=PIPE, shell=True) | |||
cmd = Popen(command, cwd=str(deploy_path), stdout=PIPE, shell=True) | |||
cmdresult = cmd.communicate()[0] | |||
if cmd.returncode: | |||
raise Exception(cmdresult) |
@@ -8,8 +8,8 @@ import itertools | |||
import os | |||
import re | |||
import sys | |||
from urllib import quote, unquote | |||
from hyde._compat import PY3, quote, unquote, str, StringIO | |||
from hyde.exceptions import HydeException | |||
from hyde.model import Expando | |||
from hyde.template import HtmlWrap, Template | |||
@@ -79,7 +79,10 @@ def urlencode(ctx, url, safe=None): | |||
@contextfilter | |||
def urldecode(ctx, url): | |||
return unquote(url).decode('utf8') | |||
url = unquote(url) | |||
if not PY3: | |||
url = url.decode('utf8') | |||
return url | |||
@contextfilter | |||
@@ -125,18 +128,17 @@ def asciidoc(env, value): | |||
try: | |||
from asciidocapi import AsciiDocAPI | |||
except ImportError: | |||
print u"Requires AsciiDoc library to use AsciiDoc tag." | |||
print(u"Requires AsciiDoc library to use AsciiDoc tag.") | |||
raise | |||
import StringIO | |||
output = value | |||
asciidoc = AsciiDocAPI() | |||
asciidoc.options('--no-header-footer') | |||
result = StringIO.StringIO() | |||
result = StringIO() | |||
asciidoc.execute( | |||
StringIO.StringIO(output.encode('utf-8')), result, backend='html4') | |||
return unicode(result.getvalue(), "utf-8") | |||
StringIO(output.encode('utf-8')), result, backend='html4') | |||
return str(result.getvalue(), "utf-8") | |||
@environmentfilter | |||
@@ -238,7 +240,7 @@ class Spaceless(Extension): | |||
""" | |||
Parses the statements and calls back to strip spaces. | |||
""" | |||
lineno = parser.stream.next().lineno | |||
lineno = next(parser.stream).lineno | |||
body = parser.parse_statements(['name:endspaceless'], | |||
drop_needle=True) | |||
return nodes.CallBlock( | |||
@@ -253,7 +255,7 @@ class Spaceless(Extension): | |||
""" | |||
if not caller: | |||
return '' | |||
return re.sub(r'>\s+<', '><', unicode(caller().strip())) | |||
return re.sub(r'>\s+<', '><', str(caller().strip())) | |||
class Asciidoc(Extension): | |||
@@ -268,7 +270,7 @@ class Asciidoc(Extension): | |||
Parses the statements and defers to the callback | |||
for asciidoc processing. | |||
""" | |||
lineno = parser.stream.next().lineno | |||
lineno = next(parser.stream).lineno | |||
body = parser.parse_statements(['name:endasciidoc'], drop_needle=True) | |||
return nodes.CallBlock( | |||
@@ -297,7 +299,7 @@ class Markdown(Extension): | |||
Parses the statements and defers to the callback | |||
for markdown processing. | |||
""" | |||
lineno = parser.stream.next().lineno | |||
lineno = next(parser.stream).lineno | |||
body = parser.parse_statements(['name:endmarkdown'], drop_needle=True) | |||
return nodes.CallBlock( | |||
@@ -325,7 +327,7 @@ class restructuredText(Extension): | |||
""" | |||
Simply extract our content | |||
""" | |||
lineno = parser.stream.next().lineno | |||
lineno = next(parser.stream).lineno | |||
body = parser.parse_statements( | |||
['name:endrestructuredtext'], drop_needle=True) | |||
@@ -357,7 +359,7 @@ class YamlVar(Extension): | |||
Parses the contained data and defers to the callback to load it as | |||
yaml. | |||
""" | |||
lineno = parser.stream.next().lineno | |||
lineno = next(parser.stream).lineno | |||
var = parser.stream.expect('name').value | |||
body = parser.parse_statements(['name:endyaml'], drop_needle=True) | |||
return [ | |||
@@ -396,7 +398,7 @@ def parse_kwargs(parser): | |||
if parser.stream.current.test('string'): | |||
value = parser.parse_expression() | |||
else: | |||
value = nodes.Const(parser.stream.next().value) | |||
value = nodes.Const(next(parser.stream).value) | |||
return (name, value) | |||
@@ -413,7 +415,7 @@ class Syntax(Extension): | |||
Parses the statements and defers to the callback for | |||
pygments processing. | |||
""" | |||
lineno = parser.stream.next().lineno | |||
lineno = next(parser.stream).lineno | |||
lex = nodes.Const(None) | |||
filename = nodes.Const(None) | |||
@@ -428,7 +430,7 @@ class Syntax(Extension): | |||
if name == 'lex' \ | |||
else (value1, value) | |||
else: | |||
lex = nodes.Const(parser.stream.next().value) | |||
lex = nodes.Const(next(parser.stream).value) | |||
if parser.stream.skip_if('comma'): | |||
filename = parser.parse_expression() | |||
@@ -496,10 +498,10 @@ class Reference(Extension): | |||
""" | |||
Parse the variable name that the content must be assigned to. | |||
""" | |||
token = parser.stream.next() | |||
token = next(parser.stream) | |||
lineno = token.lineno | |||
tag = token.value | |||
name = parser.stream.next().value | |||
name = next(parser.stream).value | |||
body = parser.parse_statements(['name:end%s' % tag], drop_needle=True) | |||
return nodes.CallBlock(self.call_method('_render_output', | |||
args=[ | |||
@@ -533,12 +535,12 @@ class Refer(Extension): | |||
""" | |||
Parse the referred template and the namespace. | |||
""" | |||
token = parser.stream.next() | |||
token = next(parser.stream) | |||
lineno = token.lineno | |||
parser.stream.expect('name:to') | |||
template = parser.parse_expression() | |||
parser.stream.expect('name:as') | |||
namespace = parser.stream.next().value | |||
namespace = next(parser.stream).value | |||
includeNode = nodes.Include(lineno=lineno) | |||
includeNode.with_context = True | |||
includeNode.ignore_missing = False | |||
@@ -623,11 +625,11 @@ class HydeLoader(FileSystemLoader): | |||
config = site.config if hasattr(site, 'config') else None | |||
if config: | |||
super(HydeLoader, self).__init__([ | |||
unicode(config.content_root_path), | |||
unicode(config.layout_root_path), | |||
str(config.content_root_path), | |||
str(config.layout_root_path), | |||
]) | |||
else: | |||
super(HydeLoader, self).__init__(unicode(sitepath)) | |||
super(HydeLoader, self).__init__(str(sitepath)) | |||
self.site = site | |||
self.preprocessor = preprocessor | |||
@@ -650,10 +652,10 @@ class HydeLoader(FileSystemLoader): | |||
except UnicodeDecodeError: | |||
HydeException.reraise( | |||
"Unicode error when processing %s" % template, sys.exc_info()) | |||
except TemplateError, exc: | |||
except TemplateError as exc: | |||
HydeException.reraise('Error when processing %s: %s' % ( | |||
template, | |||
unicode(exc) | |||
str(exc) | |||
), sys.exc_info()) | |||
if self.preprocessor: | |||
@@ -800,9 +802,9 @@ class Jinja2Template(Template): | |||
from jinja2.meta import find_referenced_templates | |||
try: | |||
ast = self.env.parse(text) | |||
except Exception, e: | |||
except Exception as e: | |||
HydeException.reraise( | |||
"Error processing %s: \n%s" % (path, unicode(e)), | |||
"Error processing %s: \n%s" % (path, str(e)), | |||
sys.exc_info()) | |||
tpls = find_referenced_templates(ast) | |||
@@ -336,7 +336,7 @@ class Generator(object): | |||
try: | |||
text = self.template.render_resource(resource, | |||
context) | |||
except Exception, e: | |||
except Exception as e: | |||
HydeException.reraise("Error occurred when processing" | |||
"template: [%s]: %s" % | |||
(resource, repr(e)), | |||
@@ -6,6 +6,8 @@ import os | |||
from fswrap import File, Folder | |||
from hyde._compat import str | |||
HYDE_DATA = "HYDE_DATA" | |||
LAYOUTS = "layouts" | |||
@@ -39,6 +41,6 @@ class Layout(object): | |||
Finds the layout folder from the given root folder. | |||
If it does not exist, return None | |||
""" | |||
layouts_folder = Folder(unicode(root)).child_folder(LAYOUTS) | |||
layouts_folder = Folder(str(root)).child_folder(LAYOUTS) | |||
layout_folder = layouts_folder.child_folder(layout_name) | |||
return layout_folder if layout_folder.exists else None |
@@ -5,11 +5,12 @@ Contains data structures and utilities for hyde. | |||
import codecs | |||
import yaml | |||
from datetime import datetime | |||
from UserDict import IterableUserDict | |||
from commando.util import getLoggerWithNullHandler | |||
from fswrap import File, Folder | |||
from hyde._compat import iteritems, str, UserDict | |||
logger = getLoggerWithNullHandler('hyde.engine') | |||
SEQS = (tuple, list, set, frozenset) | |||
@@ -45,7 +46,7 @@ class Expando(object): | |||
Returns an iterator for all the items in the | |||
dictionary as key value pairs. | |||
""" | |||
return self.__dict__.iteritems() | |||
return iteritems(self.__dict__) | |||
def update(self, d): | |||
""" | |||
@@ -63,10 +64,10 @@ class Expando(object): | |||
Sets the expando attribute after | |||
transforming the value. | |||
""" | |||
setattr(self, unicode(key).encode('utf-8'), make_expando(value)) | |||
setattr(self, str(key), make_expando(value)) | |||
def __repr__(self): | |||
return unicode(self.to_dict()) | |||
return str(self.to_dict()) | |||
def to_dict(self): | |||
""" | |||
@@ -128,7 +129,7 @@ class Context(object): | |||
return context | |||
class Dependents(IterableUserDict): | |||
class Dependents(UserDict): | |||
""" | |||
Represents the dependency graph for hyde. | |||
@@ -2,6 +2,7 @@ | |||
""" | |||
Contains definition for a plugin protocol and other utiltities. | |||
""" | |||
from hyde._compat import str | |||
from hyde.exceptions import HydeException | |||
from hyde.util import first_match, discover_executable | |||
from hyde.model import Expando | |||
@@ -17,6 +18,8 @@ import sys | |||
from commando.util import getLoggerWithNullHandler, load_python_object | |||
from fswrap import File | |||
from hyde._compat import with_metaclass | |||
logger = getLoggerWithNullHandler('hyde.engine') | |||
# Plugins have been reorganized. Map old plugin paths to new. | |||
@@ -106,12 +109,11 @@ class PluginProxy(object): | |||
"Unknown plugin method [%s] called." % method_name) | |||
class Plugin(object): | |||
class Plugin(with_metaclass(abc.ABCMeta)): | |||
""" | |||
The plugin protocol | |||
""" | |||
__metaclass__ = abc.ABCMeta | |||
def __init__(self, site): | |||
super(Plugin, self).__init__() | |||
@@ -440,14 +442,14 @@ class CLTransformer(Plugin): | |||
try: | |||
self.logger.debug( | |||
"Calling executable [%s] with arguments %s" % | |||
(args[0], unicode(args[1:]))) | |||
(args[0], str(args[1:]))) | |||
return subprocess.check_output(args) | |||
except subprocess.CalledProcessError, error: | |||
except subprocess.CalledProcessError as error: | |||
self.logger.error(error.output) | |||
raise | |||
class TextyPlugin(Plugin): | |||
class TextyPlugin(with_metaclass(abc.ABCMeta, Plugin)): | |||
""" | |||
Base class for text preprocessing plugins. | |||
@@ -457,8 +459,6 @@ class TextyPlugin(Plugin): | |||
can inherit from this class. | |||
""" | |||
__metaclass__ = abc.ABCMeta | |||
def __init__(self, site): | |||
super(TextyPlugin, self).__init__(site) | |||
self.open_pattern = self.default_open_pattern | |||
@@ -3,20 +3,20 @@ from operator import attrgetter | |||
from commando.util import getLoggerWithNullHandler, load_python_object | |||
from hyde._compat import with_metaclass | |||
""" | |||
Contains abstract classes and utilities that help publishing a website to a | |||
server. | |||
""" | |||
class Publisher(object): | |||
class Publisher(with_metaclass(abc.ABCMeta)): | |||
""" | |||
The abstract base class for publishers. | |||
""" | |||
__metaclass__ = abc.ABCMeta | |||
def __init__(self, site, settings, message): | |||
super(Publisher, self).__init__() | |||
self.logger = getLoggerWithNullHandler( | |||
@@ -4,13 +4,13 @@ Contains classes and utilities for serving a site | |||
generated from hyde. | |||
""" | |||
import threading | |||
import urlparse | |||
import urllib | |||
import traceback | |||
from datetime import datetime | |||
from SimpleHTTPServer import SimpleHTTPRequestHandler | |||
from BaseHTTPServer import HTTPServer | |||
from hyde._compat import (HTTPServer, iteritems, parse, PY3, | |||
SimpleHTTPRequestHandler, unquote) | |||
from hyde.generator import Generator | |||
from fswrap import File, Folder | |||
@@ -35,8 +35,8 @@ class HydeRequestHandler(SimpleHTTPRequestHandler): | |||
""" | |||
self.server.request_time = datetime.now() | |||
logger.debug("Processing request: [%s]" % self.path) | |||
result = urlparse.urlparse(self.path) | |||
query = urlparse.parse_qs(result.query) | |||
result = parse.urlparse(self.path) | |||
query = parse.parse_qs(result.query) | |||
if 'refresh' in query or result.query == 'refresh': | |||
self.server.regenerate() | |||
if 'refresh' in query: | |||
@@ -44,7 +44,7 @@ class HydeRequestHandler(SimpleHTTPRequestHandler): | |||
parts = list(tuple(result)) | |||
parts[4] = urllib.urlencode(query) | |||
parts = tuple(parts) | |||
new_url = urlparse.urlunparse(parts) | |||
new_url = parse.urlunparse(parts) | |||
logger.info('Redirecting... [%s]' % new_url) | |||
self.redirect(new_url) | |||
else: | |||
@@ -56,7 +56,10 @@ class HydeRequestHandler(SimpleHTTPRequestHandler): | |||
referring to the `site` variable in the server. | |||
""" | |||
site = self.server.site | |||
result = urlparse.urlparse(urllib.unquote(self.path).decode('utf-8')) | |||
path = unquote(self.path) | |||
if not PY3: | |||
path = path.decode('utf-8') | |||
result = parse.urlparse(path) | |||
logger.debug( | |||
"Trying to load file based on request: [%s]" % result.path) | |||
path = result.path.lstrip('/') | |||
@@ -150,7 +153,7 @@ class HydeWebServer(HTTPServer): | |||
except AttributeError: | |||
extensions = {} | |||
for extension, type in extensions.iteritems(): | |||
for extension, type in iteritems(extensions): | |||
ext = "." + extension if not extension == 'default' else '' | |||
HydeRequestHandler.extensions_map[ext] = type | |||
@@ -165,7 +168,7 @@ class HydeWebServer(HTTPServer): | |||
self.site.config.reload() | |||
self.site.load() | |||
self.generator.generate_all(incremental=False) | |||
except Exception, exception: | |||
except Exception as exception: | |||
logger.error('Error occured when regenerating the site [%s]' | |||
% exception.message) | |||
logger.debug(traceback.format_exc()) | |||
@@ -182,7 +185,7 @@ class HydeWebServer(HTTPServer): | |||
try: | |||
logger.debug('Serving node [%s]' % node) | |||
self.generator.generate_node(node, incremental=True) | |||
except Exception, exception: | |||
except Exception as exception: | |||
logger.error( | |||
'Error [%s] occured when generating the node [%s]' | |||
% (repr(exception), node)) | |||
@@ -201,7 +204,7 @@ class HydeWebServer(HTTPServer): | |||
try: | |||
logger.debug('Serving resource [%s]' % resource) | |||
self.generator.generate_resource(resource, incremental=True) | |||
except Exception, exception: | |||
except Exception as exception: | |||
logger.error( | |||
'Error [%s] occured when serving the resource [%s]' | |||
% (repr(exception), resource)) | |||
@@ -5,10 +5,9 @@ Parses & holds information about the site to be generated. | |||
import os | |||
import fnmatch | |||
import sys | |||
import urlparse | |||
from functools import wraps | |||
from urllib import quote | |||
from hyde._compat import parse, quote, str | |||
from hyde.exceptions import HydeException | |||
from hyde.model import Config | |||
@@ -19,7 +18,7 @@ from fswrap import FS, File, Folder | |||
def path_normalized(f): | |||
@wraps(f) | |||
def wrapper(self, path): | |||
return f(self, unicode(path).replace('/', os.sep)) | |||
return f(self, str(path).replace('/', os.sep)) | |||
return wrapper | |||
logger = getLoggerWithNullHandler('hyde.engine') | |||
@@ -138,7 +137,7 @@ class Node(Processable): | |||
self.root = self | |||
self.module = None | |||
self.site = None | |||
self.source_folder = Folder(unicode(source_folder)) | |||
self.source_folder = Folder(str(source_folder)) | |||
self.parent = parent | |||
if parent: | |||
self.root = self.parent.root | |||
@@ -249,7 +248,7 @@ class RootNode(Node): | |||
""" | |||
if Folder(path) == self.source_folder: | |||
return self | |||
return self.node_map.get(unicode(Folder(path)), None) | |||
return self.node_map.get(str(Folder(path)), None) | |||
@path_normalized | |||
def node_from_relative_path(self, relative_path): | |||
@@ -258,7 +257,7 @@ class RootNode(Node): | |||
If no match is found it returns None. | |||
""" | |||
return self.node_from_path( | |||
self.source_folder.child(unicode(relative_path))) | |||
self.source_folder.child(str(relative_path))) | |||
@path_normalized | |||
def resource_from_path(self, path): | |||
@@ -266,7 +265,7 @@ class RootNode(Node): | |||
Gets the resource that maps to the given path. | |||
If no match is found it returns None. | |||
""" | |||
return self.resource_map.get(unicode(File(path)), None) | |||
return self.resource_map.get(str(File(path)), None) | |||
@path_normalized | |||
def resource_from_relative_path(self, relative_path): | |||
@@ -282,7 +281,7 @@ class RootNode(Node): | |||
Handles the case where the relative deploy path of a | |||
resource has changed. | |||
""" | |||
self.resource_deploy_map[unicode(item.relative_deploy_path)] = item | |||
self.resource_deploy_map[str(item.relative_deploy_path)] = item | |||
@path_normalized | |||
def resource_from_relative_deploy_path(self, relative_deploy_path): | |||
@@ -323,7 +322,7 @@ class RootNode(Node): | |||
node = parent if parent else self | |||
for h_folder in hierarchy: | |||
node = node.add_child_node(h_folder) | |||
self.node_map[unicode(h_folder)] = node | |||
self.node_map[str(h_folder)] = node | |||
logger.debug("Added node [%s] to [%s]" % ( | |||
node.relative_path, self.source_folder)) | |||
@@ -352,7 +351,7 @@ class RootNode(Node): | |||
if not node: | |||
node = self.add_node(afile.parent) | |||
resource = node.add_child_resource(afile) | |||
self.resource_map[unicode(afile)] = resource | |||
self.resource_map[str(afile)] = resource | |||
relative_path = resource.relative_path | |||
resource.simple_copy = any(fnmatch.fnmatch(relative_path, pattern) | |||
for pattern in self.site.config.simple_copy) | |||
@@ -395,10 +394,11 @@ class RootNode(Node): | |||
def _encode_path(base, path, safe): | |||
base = base.strip().replace(os.sep, '/').encode('utf-8') | |||
path = path.strip().replace(os.sep, '/').encode('utf-8') | |||
base = base.strip().replace(os.sep, '/') | |||
path = path.strip().replace(os.sep, '/') | |||
path = quote(path, safe) if safe is not None else quote(path) | |||
return base.rstrip('/') + '/' + path.lstrip('/') | |||
full_path = base.rstrip('/') + '/' + path.lstrip('/') | |||
return full_path | |||
class Site(object): | |||
@@ -471,7 +471,7 @@ class Site(object): | |||
configuration and returns the appropriate url. The return value | |||
is url encoded. | |||
""" | |||
if urlparse.urlparse(path)[:2] != ("", ""): | |||
if parse.urlparse(path)[:2] != ("", ""): | |||
return path | |||
if self.is_media(path): | |||
@@ -3,6 +3,7 @@ | |||
""" | |||
Abstract classes and utilities for template engines | |||
""" | |||
from hyde._compat import with_metaclass | |||
from hyde.exceptions import HydeException | |||
import abc | |||
@@ -30,24 +31,25 @@ class HtmlWrap(object): | |||
PyQuery = None | |||
self.q = PyQuery(html) if PyQuery else None | |||
def __unicode__(self): | |||
def __str__(self): | |||
return self.raw | |||
# Support __unicode__ as well as __str__ for backward compatibility. | |||
__unicode__ = __str__ | |||
def __call__(self, selector=None): | |||
if not self.q: | |||
return self.raw | |||
return self.q(selector).html() | |||
class Template(object): | |||
class Template(with_metaclass(abc.ABCMeta)): | |||
""" | |||
Interface for hyde template engines. To use a different template engine, | |||
the following interface must be implemented. | |||
""" | |||
__metaclass__ = abc.ABCMeta | |||
def __init__(self, sitepath): | |||
self.sitepath = sitepath | |||
self.logger = getLoggerWithNullHandler(self.__class__.__name__) | |||
@@ -3,7 +3,9 @@ Module for python 2.6 compatibility. | |||
""" | |||
import os | |||
from functools import partial | |||
from itertools import izip, tee | |||
from itertools import tee | |||
from hyde._compat import str, zip | |||
def make_method(method_name, method_): | |||
@@ -26,7 +28,7 @@ def add_method(obj, method_name, method_, *args, **kwargs): | |||
def pairwalk(iterable): | |||
a, b = tee(iterable) | |||
next(b, None) | |||
return izip(a, b) | |||
return zip(a, b) | |||
def first_match(predicate, iterable): | |||
@@ -49,7 +51,7 @@ def discover_executable(name, sitepath): | |||
# Check if an executable can be found in the site path first. | |||
# If not check the os $PATH for its presence. | |||
paths = [unicode(sitepath)] + os.environ['PATH'].split(os.pathsep) | |||
paths = [str(sitepath)] + os.environ['PATH'].split(os.pathsep) | |||
for path in paths: | |||
full_name = os.path.join(path, name) | |||
if os.path.exists(full_name): | |||
@@ -72,9 +72,8 @@ def find_package_data( | |||
bad_name = True | |||
if show_ignored: | |||
print >> sys.stderr, ( | |||
"Directory %s ignored by pattern %s" | |||
% (fn, pattern)) | |||
msg = "Directory {} ignored by pattern {}" | |||
sys.stderr.write(msg.format(fn, pattern)) | |||
break | |||
if bad_name: | |||
continue | |||
@@ -96,9 +95,8 @@ def find_package_data( | |||
bad_name = True | |||
if show_ignored: | |||
print >> sys.stderr, ( | |||
"File %s ignored by pattern %s" | |||
% (fn, pattern)) | |||
msg = "File {} ignored by pattern {}" | |||
sys.stderr.write(msg.format(fn, pattern)) | |||
break | |||
if bad_name: | |||
continue | |||
@@ -157,6 +155,12 @@ setup(name=PROJECT, | |||
'Operating System :: POSIX', | |||
'Operating System :: Microsoft :: Windows', | |||
'Programming Language :: Python', | |||
'Programming Language :: Python :: 2', | |||
'Programming Language :: Python :: 2.7', | |||
'Programming Language :: Python :: 3', | |||
'Programming Language :: Python :: 3.3', | |||
'Programming Language :: Python :: 3.4', | |||
'Programming Language :: Python :: 3.5', | |||
'Topic :: Software Development', | |||
'Topic :: Software Development :: Build Tools', | |||
'Topic :: Software Development :: Code Generators', | |||
@@ -41,8 +41,8 @@ class TestSass(object): | |||
assert target.exists | |||
text = target.read_all() | |||
expected_text = File(SCSS_SOURCE.child('expected-sass.css')).read_all() | |||
print "TEXT" + "-" * 80 | |||
print text | |||
print "-" * 80 | |||
print expected_text | |||
print("TEXT" + "-" * 80) | |||
print(text) | |||
print("-" * 80) | |||
print(expected_text) | |||
assert_no_diff(expected_text, text) |
@@ -3,9 +3,9 @@ Use nose | |||
`$ pip install nose` | |||
`$ nosetests` | |||
""" | |||
from hyde._compat import quote | |||
from hyde.generator import Generator | |||
from hyde.site import Site | |||
from urllib import quote | |||
from fswrap import File | |||
@@ -46,7 +46,7 @@ class TestTextlinks(object): | |||
site.config.media_url = '/media' | |||
tlink = File(site.content.source_folder.child('tlink.html')) | |||
tlink.write(text % d) | |||
print tlink.read_all() | |||
print(tlink.read_all()) | |||
gen = Generator(site) | |||
gen.generate_all() | |||
f = File(site.config.deploy_root_path.child(tlink.name)) | |||
@@ -5,7 +5,7 @@ Use nose | |||
`$ nosetests` | |||
""" | |||
from hyde._compat import str | |||
from hyde.engine import Engine | |||
from hyde.exceptions import HydeException | |||
from hyde.layout import Layout | |||
@@ -42,7 +42,7 @@ def delete_test_site_at_user(): | |||
def test_ensure_exception_when_site_yaml_exists(): | |||
e = Engine(raise_exceptions=True) | |||
File(TEST_SITE.child('site.yaml')).write("Hey") | |||
e.run(e.parse(['-s', unicode(TEST_SITE), 'create'])) | |||
e.run(e.parse(['-s', str(TEST_SITE), 'create'])) | |||
@raises(HydeException) | |||
@@ -50,7 +50,7 @@ def test_ensure_exception_when_site_yaml_exists(): | |||
def test_ensure_exception_when_content_folder_exists(): | |||
e = Engine(raise_exceptions=True) | |||
TEST_SITE.child_folder('content').make() | |||
e.run(e.parse(['-s', unicode(TEST_SITE), 'create'])) | |||
e.run(e.parse(['-s', str(TEST_SITE), 'create'])) | |||
@raises(HydeException) | |||
@@ -58,13 +58,13 @@ def test_ensure_exception_when_content_folder_exists(): | |||
def test_ensure_exception_when_layout_folder_exists(): | |||
e = Engine(raise_exceptions=True) | |||
TEST_SITE.child_folder('layout').make() | |||
e.run(e.parse(['-s', unicode(TEST_SITE), 'create'])) | |||
e.run(e.parse(['-s', str(TEST_SITE), 'create'])) | |||
@with_setup(create_test_site, delete_test_site) | |||
def test_ensure_no_exception_when_empty_site_exists(): | |||
e = Engine(raise_exceptions=True) | |||
e.run(e.parse(['-s', unicode(TEST_SITE), 'create'])) | |||
e.run(e.parse(['-s', str(TEST_SITE), 'create'])) | |||
verify_site_contents(TEST_SITE, Layout.find_layout()) | |||
@@ -72,16 +72,16 @@ def test_ensure_no_exception_when_empty_site_exists(): | |||
def test_ensure_no_exception_when_forced(): | |||
e = Engine(raise_exceptions=True) | |||
TEST_SITE.child_folder('layout').make() | |||
e.run(e.parse(['-s', unicode(TEST_SITE), 'create', '-f'])) | |||
e.run(e.parse(['-s', str(TEST_SITE), 'create', '-f'])) | |||
verify_site_contents(TEST_SITE, Layout.find_layout()) | |||
TEST_SITE.delete() | |||
TEST_SITE.child_folder('content').make() | |||
e.run(e.parse(['-s', unicode(TEST_SITE), 'create', '-f'])) | |||
e.run(e.parse(['-s', str(TEST_SITE), 'create', '-f'])) | |||
verify_site_contents(TEST_SITE, Layout.find_layout()) | |||
TEST_SITE.delete() | |||
TEST_SITE.make() | |||
File(TEST_SITE.child('site.yaml')).write("Hey") | |||
e.run(e.parse(['-s', unicode(TEST_SITE), 'create', '-f'])) | |||
e.run(e.parse(['-s', str(TEST_SITE), 'create', '-f'])) | |||
verify_site_contents(TEST_SITE, Layout.find_layout()) | |||
@@ -89,7 +89,7 @@ def test_ensure_no_exception_when_forced(): | |||
def test_ensure_no_exception_when_sitepath_does_not_exist(): | |||
e = Engine(raise_exceptions=True) | |||
TEST_SITE.delete() | |||
e.run(e.parse(['-s', unicode(TEST_SITE), 'create', '-f'])) | |||
e.run(e.parse(['-s', str(TEST_SITE), 'create', '-f'])) | |||
verify_site_contents(TEST_SITE, Layout.find_layout()) | |||
@@ -97,7 +97,7 @@ def test_ensure_no_exception_when_sitepath_does_not_exist(): | |||
def test_ensure_can_create_site_at_user(): | |||
e = Engine(raise_exceptions=True) | |||
TEST_SITE_AT_USER.delete() | |||
e.run(e.parse(['-s', unicode(TEST_SITE_AT_USER), 'create', '-f'])) | |||
e.run(e.parse(['-s', str(TEST_SITE_AT_USER), 'create', '-f'])) | |||
verify_site_contents(TEST_SITE_AT_USER, Layout.find_layout()) | |||
@@ -107,9 +107,10 @@ def verify_site_contents(site, layout): | |||
assert site.child_folder('layout').exists | |||
assert File(site.child('info.yaml')).exists | |||
expected = map( | |||
lambda f: f.get_relative_path(layout), layout.walker.walk_all()) | |||
actual = map(lambda f: f.get_relative_path(site), site.walker.walk_all()) | |||
expected = list(map( | |||
lambda f: f.get_relative_path(layout), layout.walker.walk_all())) | |||
actual = list(map( | |||
lambda f: f.get_relative_path(site), site.walker.walk_all())) | |||
assert actual | |||
assert expected | |||
@@ -122,4 +123,4 @@ def verify_site_contents(site, layout): | |||
@with_setup(create_test_site, delete_test_site) | |||
def test_ensure_exception_when_layout_is_invalid(): | |||
e = Engine(raise_exceptions=True) | |||
e.run(e.parse(['-s', unicode(TEST_SITE), 'create', '-l', 'junk'])) | |||
e.run(e.parse(['-s', str(TEST_SITE), 'create', '-l', 'junk'])) |
@@ -9,6 +9,7 @@ Some code borrowed from rwbench.py from the jinja2 examples | |||
from datetime import datetime | |||
from random import choice, randrange | |||
from hyde._compat import PY3 | |||
from hyde.ext.templates.jinja import Jinja2Template | |||
from hyde.site import Site | |||
from hyde.generator import Generator | |||
@@ -16,6 +17,7 @@ from hyde.model import Config | |||
from fswrap import File | |||
from jinja2.utils import generate_lorem_ipsum | |||
from nose.plugins.skip import SkipTest | |||
from nose.tools import nottest | |||
from pyquery import PyQuery | |||
@@ -49,7 +51,7 @@ class User(object): | |||
self.username = username | |||
users = map(User, [u'John Doe', u'Jane Doe', u'Peter Somewhat']) | |||
users = list(map(User, [u'John Doe', u'Jane Doe', u'Peter Somewhat'])) | |||
articles = map(Article, range(20)) | |||
navigation = [ | |||
('index', 'Index'), | |||
@@ -132,6 +134,11 @@ def test_spaceless(): | |||
def test_asciidoc(): | |||
if PY3: | |||
# asciidoc is not supported under Python 3. Supporting it is out | |||
# of the scope of this project, so its tests are simply skipped | |||
# when run under Python 3. | |||
raise SkipTest | |||
source = """ | |||
{%asciidoc%} | |||
== Heading 2 == | |||
@@ -6,6 +6,7 @@ Use nose | |||
""" | |||
import os | |||
from hyde._compat import str | |||
from hyde.layout import Layout, HYDE_DATA, LAYOUTS | |||
from fswrap import File | |||
@@ -36,7 +37,7 @@ def test_find_layout_from_env_var(): | |||
f = Layout.find_layout() | |||
LAYOUT_ROOT.make() | |||
f.copy_to(LAYOUT_ROOT) | |||
os.environ[HYDE_DATA] = unicode(DATA_ROOT) | |||
os.environ[HYDE_DATA] = str(DATA_ROOT) | |||
f = Layout.find_layout() | |||
assert f.parent == LAYOUT_ROOT | |||
assert f.name == 'basic' | |||
@@ -24,14 +24,14 @@ class PluginLoaderStub(Plugin): | |||
class NoReturnPlugin(Plugin): | |||
def begin_text_resource(self, resource, text): | |||
print "NoReturnPlugin" | |||
print("NoReturnPlugin") | |||
return None | |||
class ConstantReturnPlugin(Plugin): | |||
def begin_text_resource(self, resource, text): | |||
print "ConstantReturnPlugin" | |||
print("ConstantReturnPlugin") | |||
return "Jam" | |||
@@ -5,8 +5,8 @@ Use nose | |||
`$ nosetests` | |||
""" | |||
import yaml | |||
from urllib import quote | |||
from hyde._compat import quote | |||
from hyde.model import Config | |||
from hyde.site import Node, RootNode, Site | |||
@@ -242,8 +242,8 @@ class TestSiteWithConfig(object): | |||
s = Site(self.SITE_PATH, config=self.config) | |||
s.load() | |||
path = '".jpg/abc' | |||
print s.content_url(path, "") | |||
print "/" + quote(path, "") | |||
print(s.content_url(path, "")) | |||
print("/" + quote(path, "")) | |||
assert s.content_url(path, "") == "/" + quote(path, "") | |||
def test_media_url(self): | |||
@@ -1,13 +1,15 @@ | |||
import re | |||
import difflib | |||
from hyde._compat import str | |||
def strip_spaces_between_tags(value): | |||
""" | |||
Stolen from `django.util.html` | |||
Returns the given HTML with spaces between tags removed. | |||
""" | |||
return re.sub(r'>\s+<', '><', unicode(value)) | |||
return re.sub(r'>\s+<', '><', str(value)) | |||
def assert_no_diff(expected, out): | |||
@@ -1,5 +1,5 @@ | |||
[tox] | |||
envlist = py27,pep8 | |||
envlist = py{27,33,34,35},pep8 | |||
[testenv] | |||
usedevelop = True | |||
@@ -8,11 +8,11 @@ sitepackages = True | |||
# Needed for asciidoc | |||
passenv = PYTHONPATH | |||
deps = -r{toxinidir}/dev-req.txt | |||
commands = nosetests | |||
commands = nosetests {posargs} | |||
[testenv:pep8] | |||
deps = flake8 | |||
commands = flake8 | |||
commands = flake8 {posargs} | |||
[flake8] | |||
exclude = .tox | |||