diff --git a/beets/util/__init__.py b/beets/util/__init__.py index 49fac8fbd..0d5a70e72 100644 --- a/beets/util/__init__.py +++ b/beets/util/__init__.py @@ -14,7 +14,8 @@ """Miscellaneous utility functions.""" -from __future__ import division, absolute_import, print_function +from __future__ import (division, absolute_import, print_function, + unicode_literals) import os import sys @@ -315,13 +316,13 @@ def bytestring_path(path): path (ensuring that we never deal with Unicode pathnames). """ # Pass through bytestrings. - if isinstance(path, str): + if isinstance(path, bytes): return path # On Windows, remove the magic prefix added by `syspath`. This makes # ``bytestring_path(syspath(X)) == X``, i.e., we can safely # round-trip through `syspath`. - if os.path.__name__ == 'ntpath' and path.startswith(WINDOWS_MAGIC_PREFIX): + if os.path.__name__ == b'ntpath' and path.startswith(WINDOWS_MAGIC_PREFIX): path = path[len(WINDOWS_MAGIC_PREFIX):] # Try to encode with default encodings, but fall back to UTF8. @@ -340,7 +341,7 @@ def displayable_path(path, separator=u'; '): return separator.join(displayable_path(p) for p in path) elif isinstance(path, unicode): return path - elif not isinstance(path, str): + elif not isinstance(path, bytes): # A non-string object: just get its unicode representation. return unicode(path) @@ -358,7 +359,7 @@ def syspath(path, prefix=True): *really* know what you're doing. """ # Don't do anything if we're not on windows - if os.path.__name__ != 'ntpath': + if os.path.__name__ != b'ntpath': return path if not isinstance(path, unicode): @@ -496,12 +497,12 @@ def unique_path(path): # shares, which are sufficiently common as to cause frequent problems. # http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx CHAR_REPLACE = [ - (re.compile(ur'[\\/]'), u'_'), # / and \ -- forbidden everywhere. - (re.compile(ur'^\.'), u'_'), # Leading dot (hidden files on Unix). - (re.compile(ur'[\x00-\x1f]'), u''), # Control characters. - (re.compile(ur'[<>:"\?\*\|]'), u'_'), # Windows "reserved characters". - (re.compile(ur'\.$'), u'_'), # Trailing dots. - (re.compile(ur'\s+$'), u''), # Trailing whitespace. + (re.compile(r'[\\/]'), u'_'), # / and \ -- forbidden everywhere. + (re.compile(r'^\.'), u'_'), # Leading dot (hidden files on Unix). + (re.compile(r'[\x00-\x1f]'), u''), # Control characters. + (re.compile(r'[<>:"\?\*\|]'), u'_'), # Windows "reserved characters". + (re.compile(r'\.$'), u'_'), # Trailing dots. + (re.compile(r'\s+$'), u''), # Trailing whitespace. ] @@ -555,8 +556,8 @@ def as_string(value): if value is None: return u'' elif isinstance(value, buffer): - return str(value).decode('utf8', 'ignore') - elif isinstance(value, str): + return bytes(value).decode('utf8', 'ignore') + elif isinstance(value, bytes): return value.decode('utf8', 'ignore') else: return unicode(value) @@ -615,19 +616,19 @@ def cpu_count(): """ # Adapted from the soundconverter project: # https://github.com/kassoulet/soundconverter - if sys.platform == 'win32': + if sys.platform == b'win32': try: num = int(os.environ['NUMBER_OF_PROCESSORS']) except (ValueError, KeyError): num = 0 - elif sys.platform == 'darwin': + elif sys.platform == b'darwin': try: num = int(command_output(['sysctl', '-n', 'hw.ncpu'])) except ValueError: num = 0 else: try: - num = os.sysconf('SC_NPROCESSORS_ONLN') + num = os.sysconf(b'SC_NPROCESSORS_ONLN') except (ValueError, OSError, AttributeError): num = 0 if num >= 1: @@ -655,7 +656,7 @@ def command_output(cmd, shell=False): cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - close_fds=platform.system() != 'Windows', + close_fds=platform.system() != b'Windows', shell=shell ) stdout, stderr = proc.communicate() @@ -674,7 +675,7 @@ def max_filename_length(path, limit=MAX_FILENAME_LENGTH): misreports its capacity). If it cannot be determined (e.g., on Windows), return `limit`. """ - if hasattr(os, 'statvfs'): + if hasattr(os, b'statvfs'): try: res = os.statvfs(path) except OSError: diff --git a/beets/util/artresizer.py b/beets/util/artresizer.py index aef5eb3ed..d47a30a1c 100644 --- a/beets/util/artresizer.py +++ b/beets/util/artresizer.py @@ -15,7 +15,8 @@ """Abstraction layer to resize images using PIL, ImageMagick, or a public resizing proxy if neither is available. """ -from __future__ import division, absolute_import, print_function +from __future__ import (division, absolute_import, print_function, + unicode_literals) import urllib import subprocess diff --git a/beets/util/bluelet.py b/beets/util/bluelet.py index ae8ab541c..6dcd92a1b 100644 --- a/beets/util/bluelet.py +++ b/beets/util/bluelet.py @@ -5,7 +5,8 @@ asyncore. Bluelet: easy concurrency without all the messy parallelism. """ -from __future__ import division, absolute_import, print_function +from __future__ import (division, absolute_import, print_function, + unicode_literals) import socket import select diff --git a/beets/util/enumeration.py b/beets/util/enumeration.py index c25332afb..dc0a6fa42 100644 --- a/beets/util/enumeration.py +++ b/beets/util/enumeration.py @@ -12,7 +12,8 @@ # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. -from __future__ import division, absolute_import, print_function +from __future__ import (division, absolute_import, print_function, + unicode_literals) from enum import Enum diff --git a/beets/util/functemplate.py b/beets/util/functemplate.py index 1bc984ba2..180f46733 100644 --- a/beets/util/functemplate.py +++ b/beets/util/functemplate.py @@ -26,7 +26,8 @@ This is sort of like a tiny, horrible degeneration of a real templating engine like Jinja2 or Mustache. """ -from __future__ import division, absolute_import, print_function +from __future__ import (division, absolute_import, print_function, + unicode_literals) import re import ast @@ -40,8 +41,8 @@ GROUP_CLOSE = u'}' ARG_SEP = u',' ESCAPE_CHAR = u'$' -VARIABLE_PREFIX = '__var_' -FUNCTION_PREFIX = '__func_' +VARIABLE_PREFIX = b'__var_' +FUNCTION_PREFIX = b'__func_' class Environment(object): @@ -70,11 +71,11 @@ def ex_literal(val): value. """ if val is None: - return ast.Name('None', ast.Load()) + return ast.Name(b'None', ast.Load()) elif isinstance(val, (int, float, long)): return ast.Num(val) elif isinstance(val, bool): - return ast.Name(str(val), ast.Load()) + return ast.Name(bytes(val), ast.Load()) elif isinstance(val, basestring): return ast.Str(val) raise TypeError('no literal for {0}'.format(type(val))) @@ -111,9 +112,9 @@ def compile_func(arg_names, statements, name='_the_func', debug=False): bytecode of the compiled function. """ func_def = ast.FunctionDef( - name, + name.encode('utf8'), ast.arguments( - [ast.Name(n, ast.Param()) for n in arg_names], + [ast.Name(n.encode('utf8'), ast.Param()) for n in arg_names], None, None, [ex_literal(None) for _ in arg_names], ), @@ -123,7 +124,11 @@ def compile_func(arg_names, statements, name='_the_func', debug=False): mod = ast.Module([func_def]) ast.fix_missing_locations(mod) - prog = compile(mod, '', 'exec') + try: + prog = compile(mod, '', 'exec') + except: + print(ast.dump(mod)) + raise # Debug: show bytecode. if debug: @@ -206,11 +211,11 @@ class Call(object): # Create a subexpression that joins the result components of # the arguments. arg_exprs.append(ex_call( - ast.Attribute(ex_literal(u''), 'join', ast.Load()), + ast.Attribute(ex_literal(u''), b'join', ast.Load()), [ex_call( - 'map', + b'map', [ - ex_rvalue('unicode'), + ex_rvalue(b'unicode'), ast.List(subexprs, ast.Load()), ] )], @@ -290,7 +295,7 @@ class Parser(object): # Common parsing resources. special_chars = (SYMBOL_DELIM, FUNC_DELIM, GROUP_OPEN, GROUP_CLOSE, ARG_SEP, ESCAPE_CHAR) - special_char_re = re.compile(ur'[%s]|$' % + special_char_re = re.compile(r'[%s]|$' % u''.join(re.escape(c) for c in special_chars)) def parse_expression(self): @@ -478,7 +483,7 @@ class Parser(object): Updates ``pos``. """ remainder = self.string[self.pos:] - ident = re.match(ur'\w*', remainder).group(0) + ident = re.match(r'\w*', remainder).group(0) self.pos += len(ident) return ident @@ -533,9 +538,9 @@ class Template(object): argnames = [] for varname in varnames: - argnames.append(VARIABLE_PREFIX.encode('utf8') + varname) + argnames.append(VARIABLE_PREFIX + varname) for funcname in funcnames: - argnames.append(FUNCTION_PREFIX.encode('utf8') + funcname) + argnames.append(FUNCTION_PREFIX + funcname) func = compile_func( argnames, diff --git a/beets/util/pipeline.py b/beets/util/pipeline.py index 4f6dcd410..7387a8200 100644 --- a/beets/util/pipeline.py +++ b/beets/util/pipeline.py @@ -31,14 +31,15 @@ To do so, pass an iterable of coroutines to the Pipeline constructor in place of any single coroutine. """ -from __future__ import division, absolute_import, print_function +from __future__ import (division, absolute_import, print_function, + unicode_literals) import Queue from threading import Thread, Lock import sys -BUBBLE = '__PIPELINE_BUBBLE__' -POISON = '__PIPELINE_POISON__' +BUBBLE = b'__PIPELINE_BUBBLE__' +POISON = b'__PIPELINE_POISON__' DEFAULT_QUEUE_SIZE = 16