From 2f035f1767107fd28a7f453485399e9b44b1de04 Mon Sep 17 00:00:00 2001 From: "Eevee (Alex Munroe)" Date: Fri, 2 Aug 2013 17:13:08 -0700 Subject: Python 3 compatibility, at least with syntax and builtins. Adds our very first dependency, on `six`. --- scss/__init__.py | 15 +++++++++------ scss/__main__.py | 4 ++-- scss/expression.py | 14 ++++++++------ scss/functions/compass/gradients.py | 12 +++++++----- scss/functions/compass/images.py | 13 +++++-------- scss/functions/core.py | 4 +++- scss/functions/extra.py | 15 ++++++--------- scss/rule.py | 9 +++++++-- scss/tool.py | 21 +++++++++++---------- scss/util.py | 12 ++++++------ setup.py | 3 +++ 11 files changed, 67 insertions(+), 55 deletions(-) diff --git a/scss/__init__.py b/scss/__init__.py index 4a70fcf..6ba4b9d 100644 --- a/scss/__init__.py +++ b/scss/__init__.py @@ -36,6 +36,7 @@ xCSS: """ from __future__ import absolute_import +from __future__ import print_function from scss.scss_meta import BUILD_INFO, PROJECT, VERSION, REVISION, URL, AUTHOR, AUTHOR_EMAIL, LICENSE @@ -54,6 +55,8 @@ import re import sys import textwrap +import six + from scss import config from scss.cssdefs import ( SEPARATOR, @@ -77,7 +80,7 @@ locate_blocks = None try: from scss._speedups import locate_blocks except ImportError: - print >>sys.stderr, "Scanning acceleration disabled (_speedups not found)!" + sys.stderr.write("Scanning acceleration disabled (_speedups not found)!\n") from scss._native import locate_blocks ################################################################################ @@ -322,12 +325,12 @@ class Scss(object): # defined globally to just searching the current directory self.search_paths = list(_default_search_paths) if self._search_paths is not None: - assert not isinstance(self._search_paths, basestring), \ + assert not isinstance(self._search_paths, six.string_types), \ "`search_paths` should be an iterable, not a string" self.search_paths.extend(self._search_paths) else: if config.LOAD_PATHS: - if isinstance(config.LOAD_PATHS, basestring): + if isinstance(config.LOAD_PATHS, six.string_types): # Back-compat: allow comma-delimited self.search_paths.extend(config.LOAD_PATHS.split(',')) else: @@ -725,7 +728,7 @@ class Scss(object): value = calculator.calculate(value) m_vars.set_variable(m_param, value) for p in m_params: - if p not in new_params and isinstance(m_vars.variable(p), basestring): + if p not in new_params and isinstance(m_vars.variable(p), six.string_types): value = calculator.calculate(m_vars.variable(p)) m_vars.set_variable(p, value) @@ -1022,7 +1025,7 @@ class Scss(object): # first_val = None # while True: # val = self.calculator.calculate(block.argument, rule, rule.context, rule.options) - # val = bool(False if not val or isinstance(val, basestring) and (val in ('0', 'false', 'undefined') or _variable_re.match(val)) else val) + # val = bool(False if not val or isinstance(val, six.string_types) and (val in ('0', 'false', 'undefined') or _variable_re.match(val)) else val) # if first_val is None: # first_val = val # if not val: @@ -1093,7 +1096,7 @@ class Scss(object): _prop = calculator.apply_vars(_prop) if value is None: pass - elif isinstance(value, basestring): + elif isinstance(value, six.string_types): # TODO kill this branch pass else: diff --git a/scss/__main__.py b/scss/__main__.py index c96ee59..792ead7 100644 --- a/scss/__main__.py +++ b/scss/__main__.py @@ -1,3 +1,3 @@ -import tool +import scss.tool -tool.main() +scss.tool.main() diff --git a/scss/expression.py b/scss/expression.py index 65eb4b3..6bd2bec 100644 --- a/scss/expression.py +++ b/scss/expression.py @@ -5,6 +5,8 @@ import logging import operator import re +import six + import scss.config as config from scss.cssdefs import COLOR_NAMES, is_builtin_css_function, _expr_glob_re, _interpolate_re, _variable_re from scss.types import BooleanValue, ColorValue, ListValue, Null, NumberValue, ParserValue, String @@ -54,7 +56,7 @@ class Calculator(object): return cont def apply_vars(self, cont): - if isinstance(cont, basestring) and '$' in cont: + if isinstance(cont, six.string_types) and '$' in cont: try: # Optimization: the full cont is a variable in the context, cont = self.namespace.variable(cont) @@ -93,7 +95,7 @@ class Calculator(object): # TODO only used by magic-import...? def interpolate(self, var): value = self.namespace.variable(var) - if var != value and isinstance(value, basestring): + if var != value and isinstance(value, six.string_types): _vi = self.evaluate_expression(value) if _vi is not None: value = _vi @@ -103,7 +105,7 @@ class Calculator(object): def evaluate_expression(self, expr): results = None - if not isinstance(expr, basestring): + if not isinstance(expr, six.string_types): results = expr if results is None: @@ -112,7 +114,7 @@ class Calculator(object): except KeyError: pass - if not isinstance(expr, basestring): + if not isinstance(expr, six.string_types): results = expr ast = None @@ -128,7 +130,7 @@ class Calculator(object): except SyntaxError: if config.DEBUG: raise - except Exception, e: + except Exception: # TODO hoist me up since the rule is gone #log.exception("Exception raised: %s in `%s' (%s)", e, expr, rule.file_and_line) if config.DEBUG: @@ -310,7 +312,7 @@ class Variable(Expression): raise return self.name else: - if isinstance(value, basestring): + if isinstance(value, six.string_types): evald = calculator.evaluate_expression(value) if evald is not None: return evald diff --git a/scss/functions/compass/gradients.py b/scss/functions/compass/gradients.py index e97465e..6698283 100644 --- a/scss/functions/compass/gradients.py +++ b/scss/functions/compass/gradients.py @@ -7,6 +7,8 @@ from __future__ import absolute_import import base64 import logging +import six + from scss.functions.library import FunctionLibrary from scss.functions.compass.helpers import opposite_position, position from scss.types import ColorValue, ListValue, NumberValue, StringValue @@ -23,7 +25,7 @@ def __color_stops(percentages, *args): if len(args) == 1: if isinstance(args[0], (list, tuple, ListValue)): return ListValue(args[0]).values() - elif isinstance(args[0], (StringValue, basestring)): + elif isinstance(args[0], (StringValue, six.string_types)): color_stops = [] colors = split_params(args[0].value) for color in colors: @@ -160,7 +162,7 @@ def color_stops_in_percentages(*args): def _get_gradient_position_and_angle(args): for arg in args: - if isinstance(arg, (StringValue, NumberValue, basestring)): + if isinstance(arg, (StringValue, NumberValue, six.string_types)): _arg = [arg] elif isinstance(arg, (list, tuple, ListValue)): _arg = arg @@ -190,7 +192,7 @@ def _get_gradient_position_and_angle(args): def _get_gradient_shape_and_size(args): for arg in args: - if isinstance(arg, (StringValue, NumberValue, basestring)): + if isinstance(arg, (StringValue, NumberValue, six.string_types)): _arg = [arg] elif isinstance(arg, (list, tuple, ListValue)): _arg = arg @@ -345,7 +347,7 @@ def radial_svg_gradient(*args): args = ListValue(args[0]).values() color_stops = args center = None - if isinstance(args[-1], (StringValue, NumberValue, basestring)): + if isinstance(args[-1], (StringValue, NumberValue, six.string_types)): center = args[-1] color_stops = args[:-1] color_stops = __color_stops(False, *color_stops) @@ -363,7 +365,7 @@ def linear_svg_gradient(*args): args = ListValue(args[0]).values() color_stops = args start = None - if isinstance(args[-1], (StringValue, NumberValue, basestring)): + if isinstance(args[-1], (StringValue, NumberValue, six.string_types)): start = args[-1] color_stops = args[:-1] color_stops = __color_stops(False, *color_stops) diff --git a/scss/functions/compass/images.py b/scss/functions/compass/images.py index 45fed74..1eeea38 100644 --- a/scss/functions/compass/images.py +++ b/scss/functions/compass/images.py @@ -1,6 +1,7 @@ """Image utilities ported from Compass.""" from __future__ import absolute_import +from __future__ import print_function import base64 import hashlib @@ -9,19 +10,15 @@ import mimetypes import os.path import time +import six + from scss import config from scss.functions.compass import _image_size_cache +from scss.functions.compass.helpers import add_cache_buster from scss.functions.library import FunctionLibrary from scss.types import ColorValue, ListValue, NumberValue, StringValue from scss.util import escape -from scss.functions.compass.helpers import add_cache_buster - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - try: from PIL import Image except ImportError: @@ -153,7 +150,7 @@ def _image_url(path, only_path=False, cache_buster=True, dst_color=None, src_col if cache_buster: url = add_cache_buster(url, filetime) if inline: - output = StringIO() + output = six.BytesIO() new_image.save(output, format='PNG') contents = output.getvalue() output.close() diff --git a/scss/functions/core.py b/scss/functions/core.py index 6569726..887662b 100644 --- a/scss/functions/core.py +++ b/scss/functions/core.py @@ -9,6 +9,8 @@ import logging import math import operator +import six + from scss.cssdefs import _variable_re from scss.functions.library import FunctionLibrary from scss.types import BooleanValue, ColorValue, ListValue, NumberValue, QuotedStringValue, StringValue, String @@ -560,5 +562,5 @@ def comparable(number1, number2): @register('if', 2) @register('if', 3) def if_(condition, if_true, if_false=''): - condition = bool(False if not condition or isinstance(condition, basestring) and (condition in ('0', 'false', 'undefined') or _variable_re.match(condition)) else condition) + condition = bool(False if not condition or isinstance(condition, six.string_types) and (condition in ('0', 'false', 'undefined') or _variable_re.match(condition)) else condition) return if_true.__class__(if_true) if condition else if_true.__class__(if_false) diff --git a/scss/functions/extra.py b/scss/functions/extra.py index 1ce8f8c..6f4b274 100644 --- a/scss/functions/extra.py +++ b/scss/functions/extra.py @@ -8,16 +8,13 @@ import logging import os.path import random +import six + from scss import config from scss.functions.library import FunctionLibrary from scss.types import ColorValue, NumberValue, StringValue, ListValue from scss.util import escape -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - try: from PIL import Image, ImageDraw except ImportError: @@ -325,7 +322,7 @@ def background_noise(density=None, opacity=None, size=None, monochrome=False, in inline = True # Retry inline version url = '%s%s' % (config.ASSETS_URL, asset_file) if inline: - output = StringIO() + output = six.BytesIO() new_image.save(output, format='PNG') contents = output.getvalue() output.close() @@ -409,7 +406,7 @@ def background_brushed(density=None, intensity=None, color=None, opacity=None, s inline = True # Retry inline version url = '%s%s' % (config.ASSETS_URL, asset_file) if inline: - output = StringIO() + output = six.BytesIO() new_image.save(output, format='PNG') contents = output.getvalue() output.close() @@ -476,7 +473,7 @@ def _grid_image(left_gutter, width, right_gutter, height, columns=1, grid_color= inline = True # Retry inline version url = '%s%s' % (config.ASSETS_URL, asset_file) if inline: - output = StringIO() + output = six.BytesIO() new_image.save(output, format='PNG') contents = output.getvalue() output.close() @@ -501,7 +498,7 @@ def image_color(color, width=1, height=1): size=(w, h), color=(c[0], c[1], c[2], int(c[3] * 255.0)) ) - output = StringIO() + output = six.BytesIO() new_image.save(output, format='PNG') contents = output.getvalue() output.close() diff --git a/scss/rule.py b/scss/rule.py index a650c4f..5b7cbfc 100644 --- a/scss/rule.py +++ b/scss/rule.py @@ -1,8 +1,13 @@ +from __future__ import absolute_import +from __future__ import print_function + +import six + from scss.cssdefs import _has_placeholder_re def normalize_var(name): - if isinstance(name, basestring): + if isinstance(name, six.string_types): return name.replace('_', '-') else: return name @@ -79,7 +84,7 @@ class Namespace(object): def set_variable(self, name, value): name = normalize_var(name) - assert not (isinstance(value, basestring) and value.startswith('$')) + assert not (isinstance(value, six.string_types) and value.startswith('$')) #assert isinstance(value, Value) self._variables[name] = value diff --git a/scss/tool.py b/scss/tool.py index b08d9be..c11e6c3 100644 --- a/scss/tool.py +++ b/scss/tool.py @@ -1,5 +1,6 @@ #!/usr/bin/env python from __future__ import absolute_import +from __future__ import print_function import logging import os @@ -109,7 +110,7 @@ def main(): import doctest doctest.testfile('tests/tests.rst') elif options.version: - print BUILD_INFO + print(BUILD_INFO) elif options.interactive: from pprint import pprint try: @@ -131,7 +132,7 @@ def main(): options = css.scss_opts source_file = SourceFile.from_string('', '', line_numbers=False) rule = SassRule(source_file, context=context, options=options, is_sass=is_sass) - print "Welcome to %s interactive shell" % BUILD_INFO + print("Welcome to %s interactive shell" % (BUILD_INFO,)) while True: try: s = raw_input('>>> ').strip() @@ -171,7 +172,7 @@ def main(): if code: final_cont += code final_cont = css.post_process(final_cont) - print final_cont + print(final_cont) continue elif s == 'ls' or s.startswith('show(') or s.startswith('show ') or s.startswith('ls(') or s.startswith('ls '): m = re.match(r'(?:show|ls)(\()?\s*([^,/\\) ]*)(?:[,/\\ ]([^,/\\ )]+))*(?(1)\))', s, re.IGNORECASE) @@ -218,9 +219,9 @@ def main(): fn_name, _, _ = k.partition(':') if fn_name not in seen: seen.add(fn_name) - print fn_name + '(' + ', '.join(p + (': ' + mixin[1].get(p) if p in mixin[1] else '') for p in mixin[0]) + ') {' - print ' ' + '\n '.join(l for l in mixin[2].split('\n')) - print '}' + print(fn_name + '(' + ', '.join(p + (': ' + mixin[1].get(p) if p in mixin[1] else '') for p in mixin[0]) + ') {') + print(' ' + '\n '.join(l for l in mixin[2].split('\n'))) + print('}') else: d = dict((k[len(name) + 2:].split(':')[0], v) for k, v in options.items() if k.startswith('@' + name + ' ')) pprint(sorted(d)) @@ -233,8 +234,8 @@ def main(): continue s = to_str(css.calculator.calculate(s, context, rule)) s = css.post_process(s) - print s - print "Bye!" + print(s) + print("Bye!") elif options.watch: import time try: @@ -285,7 +286,7 @@ def main(): else: dest_path = os.path.join(os.path.dirname(src_path), fname) - print "Compiling %s => %s" % (src_path, dest_path) + print("Compiling %s => %s" % (src_path, dest_path)) dest_file = open(dest_path, 'w') dest_file.write(self.css.compile(scss_file=src_path)) @@ -329,7 +330,7 @@ def main(): output.write(css.compile(sys.stdin.read(), is_sass=options.is_sass)) for f, t in profiling.items(): - print >>sys.stderr, "%s took %03fs" % (f, t) + sys.stderr.write("%s took %03fs" % (f, t)) if __name__ == "__main__": main() diff --git a/scss/util.py b/scss/util.py index fae1868..57d568e 100644 --- a/scss/util.py +++ b/scss/util.py @@ -1,12 +1,11 @@ +from __future__ import absolute_import +from __future__ import print_function + import re import sys import time -import cProfile -try: - from cStringIO import StringIO -except: - from StringIO import StringIO +import six from scss import config @@ -112,10 +111,11 @@ def print_timing(level=0): ################################################################################ # Profiler decorator def profile(fn): + import cProfile import pstats def wrapper(*args, **kwargs): profiler = cProfile.Profile() - stream = StringIO() + stream = six.StringIO() profiler.enable() try: res = fn(*args, **kwargs) diff --git a/setup.py b/setup.py index 2bd31bc..85de7db 100644 --- a/setup.py +++ b/setup.py @@ -100,6 +100,9 @@ def run_setup(with_binary): "Topic :: Text Processing :: Markup", "Topic :: Software Development :: Libraries :: Python Modules" ], + requires=[ + 'six', + ], packages=[ 'scss', 'scss.functions', -- cgit v1.2.1