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