diff hglib/client.py @ 142:fe74d5599539

hglib: wrap all application string literals in util.b() (issue4520) Conversion also included changing use of string interpolation to string concatenation as bytes interpolation does not exist in Python 3. Indexing related to bytes was also changed to length-1 bytes through slicing as Python 3 returns an int in this instance. Tests have not been switched to using util.b() so that the change to application code can be independently verified as not being broken.
author Brett Cannon <brett@python.org>
date Sun, 08 Mar 2015 13:08:37 -0400
parents dc63978871ed
children f3c430afa598
line wrap: on
line diff
--- a/hglib/client.py	Sat Mar 07 10:08:52 2015 -0500
+++ b/hglib/client.py	Sun Mar 08 13:08:37 2015 -0400
@@ -1,7 +1,7 @@
 import subprocess, os, struct, cStringIO, re, datetime
 import hglib, error, util, templates, merge, context
 
-from util import cmdbuilder
+from util import b, cmdbuilder
 
 class revision(tuple):
     def __new__(cls, rev, node, tags, branch, author, desc, date):
@@ -72,11 +72,11 @@
     def _readhello(self):
         """ read the hello message the server sends when started """
         ch, msg = self._readchannel()
-        assert ch == 'o'
+        assert ch == b('o')
 
-        msg = msg.split('\n')
+        msg = msg.split(b('\n'))
 
-        self.capabilities = msg[0][len('capabilities: '):]
+        self.capabilities = msg[0][len(b('capabilities: ')):]
         if not self.capabilities:
             raise error.ResponseError(
                 "bad hello message: expected 'capabilities: '"
@@ -85,9 +85,9 @@
         self.capabilities = set(self.capabilities.split())
 
         # at the very least the server should be able to run commands
-        assert 'runcommand' in self.capabilities
+        assert b('runcommand') in self.capabilities
 
-        self._encoding = msg[1][len('encoding: '):]
+        self._encoding = msg[1][len(b('encoding: ')):]
         if not self._encoding:
             raise error.ResponseError("bad hello message: expected 'encoding: '"
                                       ", got %r" % msg[1])
@@ -97,7 +97,7 @@
         if not data:
             raise error.ServerError()
         channel, length = struct.unpack(hgclient.outputfmt, data)
-        if channel in 'IL':
+        if channel in b('IL'):
             return channel, length
         else:
             return channel, self.server.stdout.read(length)
@@ -110,7 +110,7 @@
         revs = []
         for rev in util.grouper(7, splitted):
             # truncate the timezone and convert to a local datetime
-            posixtime = float(rev[6].split('.', 1)[0])
+            posixtime = float(rev[6].split(b('.'), 1)[0])
             dt = datetime.datetime.fromtimestamp(posixtime)
             revs.append(revision(rev[0], rev[1], rev[2], rev[3],
                                  rev[4], rev[5], dt))
@@ -125,8 +125,8 @@
         if not self.server:
             raise ValueError("server not connected")
 
-        self.server.stdin.write('runcommand\n')
-        writeblock('\0'.join(args))
+        self.server.stdin.write(b('runcommand\n'))
+        writeblock(b('\0').join(args))
 
         while True:
             channel, data = self._readchannel()
@@ -138,7 +138,7 @@
             elif channel in outchannels:
                 outchannels[channel](data)
             # result channel, command finished
-            elif channel == 'r':
+            elif channel == b('r'):
                 return struct.unpack(hgclient.retfmt, data)[0]
             # a channel that we don't know and can't ignore
             elif channel.isupper():
@@ -162,18 +162,17 @@
         input is used to reply to bulk data requests by the server
         It receives the max number of bytes to return
         """
-
         out, err = cStringIO.StringIO(), cStringIO.StringIO()
-        outchannels = {'o' : out.write, 'e' : err.write}
+        outchannels = {b('o') : out.write, b('e') : err.write}
 
         inchannels = {}
         if prompt is not None:
             def func(size):
                 reply = prompt(size, out.getvalue())
-                return str(reply)
-            inchannels['L'] = func
+                return reply
+            inchannels[b('L')] = func
         if input is not None:
-            inchannels['I'] = input
+            inchannels[b('I')] = input
 
         ret = self.runcommand(args, inchannels, outchannels)
         out, err = out.getvalue(), err.getvalue()
@@ -222,7 +221,7 @@
         if not isinstance(files, list):
             files = [files]
 
-        args = cmdbuilder('add', n=dryrun, S=subrepos, I=include, X=exclude,
+        args = cmdbuilder(b('add'), n=dryrun, S=subrepos, I=include, X=exclude,
                           *files)
 
         eh = util.reterrorhandler(args)
@@ -257,7 +256,7 @@
         if not isinstance(files, list):
             files = [files]
 
-        args = cmdbuilder('addremove', s=similarity, n=dryrun, I=include,
+        args = cmdbuilder(b('addremove'), s=similarity, n=dryrun, I=include,
                           X=exclude, *files)
 
         eh = util.reterrorhandler(args)
@@ -289,7 +288,7 @@
         if not isinstance(files, list):
             files = [files]
 
-        args = cmdbuilder('annotate', r=rev, no_follow=nofollow, a=text,
+        args = cmdbuilder(b('annotate'), r=rev, no_follow=nofollow, a=text,
                           u=user, f=file, d=date, n=number, c=changeset,
                           l=line, v=verbose, I=include, X=exclude,
                           hidden=self.hidden, *files)
@@ -297,7 +296,7 @@
         out = self.rawcommand(args)
 
         for line in out.splitlines():
-            yield tuple(line.split(': ', 1))
+            yield tuple(line.split(b(': '), 1))
 
     def archive(self, dest, rev=None, nodecode=False, prefix=None, type=None,
                 subrepos=False, include=None, exclude=None):
@@ -334,7 +333,8 @@
         exclude - exclude names matching the given patterns
 
         """
-        args = cmdbuilder('archive', dest, r=rev, no_decode=nodecode, p=prefix,
+        args = cmdbuilder(b('archive'), dest, r=rev,
+                          no_decode=nodecode, p=prefix,
                           t=type, S=subrepos, I=include, X=exclude,
                           hidden=self.hidden)
 
@@ -362,8 +362,8 @@
         if message and logfile:
             raise ValueError("cannot specify both a message and a logfile")
 
-        args = cmdbuilder('backout', r=rev, merge=merge, parent=parent, t=tool,
-                          m=message, l=logfile, d=date, u=user,
+        args = cmdbuilder(b('backout'), r=rev, merge=merge, parent=parent,
+                          t=tool, m=message, l=logfile, d=date, u=user,
                           hidden=self.hidden)
 
         self.rawcommand(args)
@@ -381,7 +381,7 @@
         inactive - do not mark the new bookmark active
         rename - rename the bookmark given by rename to name
         """
-        args = cmdbuilder('bookmark', name, r=rev, f=force, d=delete,
+        args = cmdbuilder(b('bookmark'), name, r=rev, f=force, d=delete,
                           i=inactive, m=rename)
 
         self.rawcommand(args)
@@ -393,18 +393,18 @@
 
         If there isn't a current one, -1 is returned as the index.
         """
-        args = cmdbuilder('bookmarks', hidden=self.hidden)
+        args = cmdbuilder(b('bookmarks'), hidden=self.hidden)
         out = self.rawcommand(args)
 
         bms = []
         current = -1
-        if out.rstrip() != 'no bookmarks set':
+        if out.rstrip() != b('no bookmarks set'):
             for line in out.splitlines():
                 iscurrent, line = line[0:3], line[3:]
-                if '*' in iscurrent:
+                if b('*') in iscurrent:
                     current = len(bms)
-                name, line = line.split(' ', 1)
-                rev, node = line.split(':')
+                name, line = line.split(b(' '), 1)
+                rev, node = line.split(b(':'))
                 bms.append((name, int(rev), node))
         return bms, current
 
@@ -427,7 +427,7 @@
         if name and clean:
             raise ValueError('cannot use both name and clean')
 
-        args = cmdbuilder('branch', name, f=force, C=clean)
+        args = cmdbuilder(b('branch'), name, f=force, C=clean)
         out = self.rawcommand(args).rstrip()
 
         if name:
@@ -445,13 +445,13 @@
         active - show only branches that have unmerged heads
         closed - show normal and closed branches
         """
-        args = cmdbuilder('branches', a=active, c=closed, hidden=self.hidden)
+        args = cmdbuilder(b('branches'), a=active, c=closed, hidden=self.hidden)
         out = self.rawcommand(args)
 
         branches = []
         for line in out.rstrip().splitlines():
-            namerev, node = line.rsplit(':', 1)
-            name, rev = namerev.rsplit(' ', 1)
+            namerev, node = line.rsplit(b(':'), 1)
+            name, rev = namerev.rsplit(b(' '), 1)
             name = name.rstrip()
             node = node.split()[0] # get rid of ' (inactive)'
             branches.append((name, int(rev), node))
@@ -485,7 +485,7 @@
         Return True if a bundle was created, False if no changes were found.
 
         """
-        args = cmdbuilder('bundle', file, destrepo, f=force, r=rev, b=branch,
+        args = cmdbuilder(b('bundle'), file, destrepo, f=force, r=rev, b=branch,
                           base=base, a=all, t=type, e=ssh, remotecmd=remotecmd,
                           insecure=insecure, hidden=self.hidden)
 
@@ -509,13 +509,13 @@
         "%p"  root-relative path name of file being printed
 
         """
-        args = cmdbuilder('cat', r=rev, o=output, hidden=self.hidden, *files)
+        args = cmdbuilder(b('cat'), r=rev, o=output, hidden=self.hidden, *files)
         out = self.rawcommand(args)
 
         if not output:
             return out
 
-    def clone(self, source='.', dest=None, branch=None, updaterev=None,
+    def clone(self, source=b('.'), dest=None, branch=None, updaterev=None,
               revrange=None):
         """
         Create a copy of an existing repository specified by source in a new
@@ -527,7 +527,7 @@
         updaterev - revision, tag or branch to check out
         revrange - include the specified changeset
         """
-        args = cmdbuilder('clone', source, dest, b=branch,
+        args = cmdbuilder(b('clone'), source, dest, b=branch,
                           u=updaterev, r=revrange)
         self.rawcommand(args)
 
@@ -549,18 +549,18 @@
         """
         if amend and message is None and logfile is None:
             # retrieve current commit message
-            message = self.log('.')[0][5]
+            message = self.log(b('.'))[0][5]
         if message is None and logfile is None and not amend:
             raise ValueError("must provide at least a message or a logfile")
         elif message and logfile:
             raise ValueError("cannot specify both a message and a logfile")
 
         # --debug will print the committed cset
-        args = cmdbuilder('commit', debug=True, m=message, A=addremove,
+        args = cmdbuilder(b('commit'), debug=True, m=message, A=addremove,
                           close_branch=closebranch, d=date, u=user, l=logfile,
                           I=include, X=exclude, amend=amend)
         out = self.rawcommand(args)
-        rev, node = out.splitlines()[-1].rsplit(':')
+        rev, node = out.splitlines()[-1].rsplit(b(':'))
         return int(rev.split()[-1]), node
 
     def config(self, names=[], untrusted=False, showsource=False):
@@ -572,21 +572,22 @@
 
         """
         def splitline(s):
-            k, value = s.rstrip().split('=', 1)
-            section, key = k.split('.', 1)
-            return (section, key, value)
+            k, value = s.rstrip().split(b('='), 1)
+            section, key = k.split(b('.'), 1)
+            return section, key, value
 
         if not isinstance(names, list):
             names = [names]
 
-        args = cmdbuilder('showconfig', u=untrusted, debug=showsource, *names)
+        args = cmdbuilder(b('showconfig'), u=untrusted, debug=showsource,
+                          *names)
         out = self.rawcommand(args)
 
         conf = []
         if showsource:
-            out = util.skiplines(out, 'read config from: ')
+            out = util.skiplines(out, b('read config from: '))
             for line in out.splitlines():
-                m = re.match(r"(.+?:(?:\d+:)?) (.*)", line)
+                m = re.match(b(r"(.+?:(?:\d+:)?) (.*)"), line)
                 t = splitline(m.group(2))
                 conf.append((m.group(1)[:-1], t[0], t[1], t[2]))
         else:
@@ -600,11 +601,11 @@
         """
         Return the server's encoding (as reported in the hello message).
         """
-        if not 'getencoding' in self.capabilities:
+        if not b('getencoding') in self.capabilities:
             raise CapabilityError('getencoding')
 
         if not self._encoding:
-            self.server.stdin.write('getencoding\n')
+            self.server.stdin.write(b('getencoding\n'))
             self._encoding = self._readfromchannel('r')
 
         return self._encoding
@@ -630,7 +631,7 @@
             source = [source]
 
         source.append(dest)
-        args = cmdbuilder('copy', A=after, f=force, n=dryrun,
+        args = cmdbuilder(b('copy'), A=after, f=force, n=dryrun,
                           I=include, X=exclude, *source)
 
         eh = util.reterrorhandler(args)
@@ -666,7 +667,7 @@
         if change and revs:
             raise ValueError('cannot specify both change and rev')
 
-        args = cmdbuilder('diff', r=revs, c=change,
+        args = cmdbuilder(b('diff'), r=revs, c=change,
                           a=text, g=git, nodates=nodates,
                           p=showfunction, reverse=reverse,
                           w=ignoreallspace, b=ignorespacechange,
@@ -701,7 +702,7 @@
         """
         if not isinstance(revs, list):
             revs = [revs]
-        args = cmdbuilder('export', o=output, switch_parent=switchparent,
+        args = cmdbuilder(b('export'), o=output, switch_parent=switchparent,
                           a=text, g=git, nodates=nodates, hidden=self.hidden,
                           *revs)
 
@@ -726,7 +727,7 @@
         if not isinstance(files, list):
             files = [files]
 
-        args = cmdbuilder('forget', I=include, X=exclude, *files)
+        args = cmdbuilder(b('forget'), I=include, X=exclude, *files)
 
         eh = util.reterrorhandler(args)
         self.rawcommand(args, eh=eh)
@@ -761,18 +762,18 @@
         if not isinstance(files, list):
             files = [files]
 
-        args = cmdbuilder('grep', all=all, a=text, f=follow, i=ignorecase,
+        args = cmdbuilder(b('grep'), all=all, a=text, f=follow, i=ignorecase,
                           l=fileswithmatches, n=line, u=user, d=date,
                           I=include, X=exclude, hidden=self.hidden,
                           *[pattern] + files)
-        args.append('-0')
+        args.append(b('-0'))
 
         def eh(ret, out, err):
             if ret != 1:
                 raise error.CommandError(args, ret, out, err)
-            return ''
+            return b('')
 
-        out = self.rawcommand(args, eh=eh).split('\0')
+        out = self.rawcommand(args, eh=eh).split(b('\0'))
 
         fieldcount = 3
         if user:
@@ -804,16 +805,16 @@
         if not isinstance(rev, list):
             rev = [rev]
 
-        args = cmdbuilder('heads', r=startrev, t=topological, c=closed,
+        args = cmdbuilder(b('heads'), r=startrev, t=topological, c=closed,
                           template=templates.changeset, hidden=self.hidden,
                           *rev)
 
         def eh(ret, out, err):
             if ret != 1:
                 raise error.CommandError(args, ret, out, err)
-            return ''
+            return b('')
 
-        out = self.rawcommand(args, eh=eh).split('\0')[:-1]
+        out = self.rawcommand(args, eh=eh).split(b('\0'))[:-1]
         return self._parserevs(out)
 
     def identify(self, rev=None, source=None, num=False, id=False, branch=False,
@@ -836,7 +837,7 @@
         bookmarks - show bookmarks
 
         """
-        args = cmdbuilder('identify', source, r=rev, n=num, i=id,
+        args = cmdbuilder(b('identify'), source, r=rev, n=num, i=id,
                           b=branch, t=tags, B=bookmarks,
                           hidden=self.hidden)
 
@@ -878,7 +879,7 @@
             prompt = None
             input = None
 
-        args = cmdbuilder('import', strip=strip, force=force,
+        args = cmdbuilder(b('import'), strip=strip, force=force,
                           no_commit=nocommit, bypass=bypass, exact=exact,
                           import_branch=importbranch, message=message,
                           date=date, user=user, similarity=similarity, _=stdin,
@@ -911,7 +912,7 @@
         subrepos - recurse into subrepositories
 
         """
-        args = cmdbuilder('incoming', path,
+        args = cmdbuilder(b('incoming'), path,
                           template=templates.changeset, r=revrange,
                           f=force, n=newest, bundle=bundle,
                           B=bookmarks, b=branch, l=limit, M=nomerges,
@@ -932,7 +933,7 @@
                 bms.append(tuple(line.split()))
             return bms
         else:
-            out = out.split('\0')[:-1]
+            out = out.split(b('\0'))[:-1]
             return self._parserevs(out)
 
     def log(self, revrange=None, files=[], follow=False,
@@ -983,7 +984,7 @@
         """
         if hidden is None:
             hidden = self.hidden
-        args = cmdbuilder('log', template=templates.changeset,
+        args = cmdbuilder(b('log'), template=templates.changeset,
                           r=revrange, f=follow, follow_first=followfirst,
                           d=date, C=copies, k=keyword, removed=removed,
                           m=onlymerges, u=user, b=branch, P=prune,
@@ -991,7 +992,7 @@
                           hidden=hidden, *files)
 
         out = self.rawcommand(args)
-        out = out.split('\0')[:-1]
+        out = out.split(b('\0'))[:-1]
 
         return self._parserevs(out)
 
@@ -1005,7 +1006,7 @@
         (just the name). This includes deleted and renamed files.
 
         """
-        args = cmdbuilder('manifest', r=rev, all=all, debug=True,
+        args = cmdbuilder(b('manifest'), r=rev, all=all, debug=True,
                           hidden=self.hidden)
 
         out = self.rawcommand(args)
@@ -1017,9 +1018,9 @@
             for line in out.splitlines():
                 node = line[0:40]
                 perm = line[41:44]
-                symlink = line[45] == '@'
-                executable = line[45] == '*'
-                yield (node, perm, executable, symlink, line[47:])
+                symlink = line[45:46] == b('@')
+                executable = line[45:46] == b('*')
+                yield node, perm, executable, symlink, line[47:]
 
     def merge(self, rev=None, force=False, tool=None, cb=merge.handlers.abort):
         """Merge working directory with rev. If no revision is specified, the
@@ -1047,15 +1048,15 @@
 
         """
         # we can't really use --preview since merge doesn't support --template
-        args = cmdbuilder('merge', r=rev, f=force, t=tool)
+        args = cmdbuilder(b('merge'), r=rev, f=force, t=tool)
 
         prompt = None
         if cb is merge.handlers.abort:
             prompt = cb
         elif cb is merge.handlers.noninteractive:
-            args.append('-y')
+            args.append(b('-y'))
         else:
-            prompt = lambda size, output: cb(output) + '\n'
+            prompt = lambda size, output: cb(output) + b('\n')
 
         self.rawcommand(args, prompt=prompt)
 
@@ -1080,7 +1081,7 @@
             source = [source]
 
         source.append(dest)
-        args = cmdbuilder('move', A=after, f=force, n=dryrun,
+        args = cmdbuilder(b('move'), A=after, f=force, n=dryrun,
                           I=include, X=exclude, *source)
 
         eh = util.reterrorhandler(args)
@@ -1108,7 +1109,7 @@
         subrepositories
 
         """
-        args = cmdbuilder('outgoing',
+        args = cmdbuilder(b('outgoing'),
                           path,
                           template=templates.changeset, r=revrange,
                           f=force, n=newest, B=bookmarks,
@@ -1129,7 +1130,7 @@
                 bms.append(tuple(line.split()))
             return bms
         else:
-            out = out.split('\0')[:-1]
+            out = out.split(b('\0'))[:-1]
             return self._parserevs(out)
 
     def parents(self, rev=None, file=None):
@@ -1140,14 +1141,14 @@
         is returned.
 
         """
-        args = cmdbuilder('parents', file, template=templates.changeset, r=rev,
-                          hidden=self.hidden)
+        args = cmdbuilder(b('parents'), file, template=templates.changeset,
+                          r=rev, hidden=self.hidden)
 
         out = self.rawcommand(args)
         if not out:
             return
 
-        out = out.split('\0')[:-1]
+        out = out.split(b('\0'))[:-1]
 
         return self._parserevs(out)
 
@@ -1161,13 +1162,14 @@
         used, too.
         """
         if not name:
-            out = self.rawcommand(['paths'])
+            out = self.rawcommand([b('paths')])
             if not out:
                 return {}
 
-            return dict([s.split(' = ') for s in out.rstrip().split('\n')])
+            return dict([s.split(b(' = '))
+                         for s in out.rstrip().split(b('\n'))])
         else:
-            args = cmdbuilder('paths', name)
+            args = cmdbuilder(b('paths'), name)
             out = self.rawcommand(args)
             return out.rstrip()
 
@@ -1196,7 +1198,7 @@
         tool - specify merge tool for rebase
 
         """
-        args = cmdbuilder('pull', source, r=rev, u=update, f=force,
+        args = cmdbuilder(b('pull'), source, r=rev, u=update, f=force,
                           B=bookmark, b=branch, e=ssh,
                           remotecmd=remotecmd, insecure=insecure,
                           t=tool)
@@ -1233,7 +1235,7 @@
          web.cacerts config)
 
         """
-        args = cmdbuilder('push', dest, r=rev, f=force, B=bookmark, b=branch,
+        args = cmdbuilder(b('push'), dest, r=rev, f=force, B=bookmark, b=branch,
                           new_branch=newbranch, e=ssh, remotecmd=remotecmd,
                           insecure=insecure)
 
@@ -1259,7 +1261,7 @@
         if not isinstance(files, list):
             files = [files]
 
-        args = cmdbuilder('remove', A=after, f=force, I=include, X=exclude,
+        args = cmdbuilder(b('remove'), A=after, f=force, I=include, X=exclude,
                           *files)
 
         eh = util.reterrorhandler(args)
@@ -1287,7 +1289,7 @@
         if not isinstance(file, list):
             file = [file]
 
-        args = cmdbuilder('resolve', a=all, l=listfiles, m=mark, u=unmark,
+        args = cmdbuilder(b('resolve'), a=all, l=listfiles, m=mark, u=unmark,
                           t=tool, I=include, X=exclude, *file)
 
         out = self.rawcommand(args)
@@ -1295,7 +1297,7 @@
         if listfiles:
             l = []
             for line in out.splitlines():
-                l.append(tuple(line.split(' ', 1)))
+                l.append(tuple(line.split(b(' '), 1)))
             return l
 
     def revert(self, files, rev=None, all=False, date=None, nobackup=False,
@@ -1330,7 +1332,7 @@
         if not isinstance(files, list):
             files = [files]
 
-        args = cmdbuilder('revert', r=rev, a=all, d=date,
+        args = cmdbuilder(b('revert'), r=rev, a=all, d=date,
                           no_backup=nobackup, n=dryrun, I=include, X=exclude,
                           hidden=self.hidden, *files)
 
@@ -1343,7 +1345,7 @@
         """
         Return the root directory of the current repository.
         """
-        return self.rawcommand(['root']).rstrip()
+        return self.rawcommand([b('root')]).rstrip()
 
     def status(self, rev=None, change=None, all=False, modified=False,
                added=False, removed=False, deleted=False, clean=False,
@@ -1380,22 +1382,22 @@
         if rev and change:
             raise ValueError('cannot specify both rev and change')
 
-        args = cmdbuilder('status', rev=rev, change=change, A=all, m=modified,
-                          a=added, r=removed, d=deleted, c=clean, u=unknown,
-                          i=ignored, C=copies, S=subrepos, I=include,
+        args = cmdbuilder(b('status'), rev=rev, change=change, A=all,
+                          m=modified, a=added, r=removed, d=deleted, c=clean,
+                          u=unknown, i=ignored, C=copies, S=subrepos, I=include,
                           X=exclude, hidden=self.hidden)
 
-        args.append('-0')
+        args.append(b('-0'))
 
         out = self.rawcommand(args)
         l = []
 
-        for entry in out.split('\0'):
+        for entry in out.split(b('\0')):
             if entry:
-                if entry[0] == ' ':
-                    l.append((' ', entry[2:]))
+                if entry[0:1] == b(' '):
+                    l.append((b(' '), entry[2:]))
                 else:
-                    l.append(tuple(entry.split(' ', 1)))
+                    l.append(tuple(entry.split(b(' '), 1)))
 
         return l
 
@@ -1422,7 +1424,7 @@
         if not isinstance(names, list):
             names = [names]
 
-        args = cmdbuilder('tag', r=rev, m=message, f=force, l=local,
+        args = cmdbuilder(b('tag'), r=rev, m=message, f=force, l=local,
                           remove=remove, d=date, u=user, hidden=self.hidden,
                           *names)
 
@@ -1432,17 +1434,17 @@
         """
         Return a list of repository tags as: (name, rev, node, islocal)
         """
-        args = cmdbuilder('tags', v=True)
+        args = cmdbuilder(b('tags'), v=True)
 
         out = self.rawcommand(args)
 
         t = []
         for line in out.splitlines():
-            taglocal = line.endswith(' local')
+            taglocal = line.endswith(b(' local'))
             if taglocal:
                 line = line[:-6]
-            name, rev = line.rsplit(' ', 1)
-            rev, node = rev.split(':')
+            name, rev = line.rsplit(b(' '), 1)
+            rev, node = rev.split(b(':'))
             t.append((name.rstrip(), int(rev), node, taglocal))
         return t
 
@@ -1462,14 +1464,14 @@
         '''
         if not isinstance(revs, (list, tuple)):
             revs = [revs]
-        args = util.cmdbuilder('phase', secret=secret, draft=draft,
+        args = util.cmdbuilder(b('phase'), secret=secret, draft=draft,
                                public=public, force=force,
                                hidden=self.hidden, *revs)
         out = self.rawcommand(args)
         if draft or public or secret:
             return
         else:
-            output = [i.split(': ')for i in out.strip().split('\n')]
+            output = [i.split(b(': '))for i in out.strip().split(b('\n'))]
             return [(int(num), phase) for (num, phase) in output]
 
     def summary(self, remote=False):
@@ -1486,65 +1488,65 @@
 
             unparsed entries will be of them form key : value
         """
-        args = cmdbuilder('summary', remote=remote, hidden=self.hidden)
+        args = cmdbuilder(b('summary'), remote=remote, hidden=self.hidden)
 
         out = self.rawcommand(args).splitlines()
 
         d = {}
         while out:
             line = out.pop(0)
-            name, value = line.split(': ', 1)
+            name, value = line.split(b(': '), 1)
 
-            if name == 'parent':
-                parent, tags = value.split(' ', 1)
-                rev, node = parent.split(':')
+            if name == b('parent'):
+                parent, tags = value.split(b(' '), 1)
+                rev, node = parent.split(b(':'))
 
                 if tags:
-                    tags = tags.replace(' (empty repository)', '')
+                    tags = tags.replace(b(' (empty repository)'), b(''))
                 else:
                     tags = None
 
                 value = d.get(name, [])
 
-                if rev == '-1':
+                if rev == b('-1'):
                     value.append((int(rev), node, tags, None))
                 else:
                     message = out.pop(0)[1:]
                     value.append((int(rev), node, tags, message))
-            elif name == 'branch':
+            elif name == b('branch'):
                 pass
-            elif name == 'commit':
-                value = value == '(clean)'
-            elif name == 'update':
-                if value == '(current)':
+            elif name == b('commit'):
+                value = value == b('(clean)')
+            elif name == b('update'):
+                if value == b('(current)'):
                     value = 0
                 else:
-                    value = int(value.split(' ', 1)[0])
-            elif remote and name == 'remote':
-                if value == '(synced)':
+                    value = int(value.split(b(' '), 1)[0])
+            elif remote and name == b('remote'):
+                if value == b('(synced)'):
                     value = 0, 0, 0, 0
                 else:
                     inc = incb = out_ = outb = 0
 
-                    for v in value.split(', '):
-                        count, v = v.split(' ', 1)
-                        if v == 'outgoing':
+                    for v in value.split(b(', ')):
+                        count, v = v.split(b(' '), 1)
+                        if v == b('outgoing'):
                             out_ = int(count)
-                        elif v.endswith('incoming'):
+                        elif v.endswith(b('incoming')):
                             inc = int(count)
-                        elif v == 'incoming bookmarks':
+                        elif v == b('incoming bookmarks'):
                             incb = int(count)
-                        elif v == 'outgoing bookmarks':
+                        elif v == b('outgoing bookmarks'):
                             outb = int(count)
 
                     value = inc, incb, out_, outb
-            elif name == 'mq':
+            elif name == b('mq'):
                 applied = unapplied = 0
-                for v in value.split(', '):
-                    count, v = v.split(' ', 1)
-                    if v == 'applied':
+                for v in value.split(b(', ')):
+                    count, v = v.split(b(' '), 1)
+                    if v == b('applied'):
                         applied = int(count)
-                    elif v == 'unapplied':
+                    elif v == b('unapplied'):
                         unapplied = int(count)
                 value = applied, unapplied
 
@@ -1558,10 +1560,10 @@
         changeset most recently added to the repository (and therefore the most
         recently changed head).
         """
-        args = cmdbuilder('tip', template=templates.changeset,
+        args = cmdbuilder(b('tip'), template=templates.changeset,
                           hidden=self.hidden)
         out = self.rawcommand(args)
-        out = out.split('\0')
+        out = out.split(b('\0'))
 
         return self._parserevs(out)[0]
 
@@ -1579,7 +1581,7 @@
         if clean and check:
             raise ValueError('clean and check cannot both be True')
 
-        args = cmdbuilder('update', r=rev, C=clean, c=check, d=date,
+        args = cmdbuilder(b('update'), r=rev, C=clean, c=check, d=date,
                           hidden=self.hidden)
 
         def eh(ret, out, err):
@@ -1591,7 +1593,8 @@
 
         out = self.rawcommand(args, eh=eh)
 
-        m = re.search(r'^(\d+).+, (\d+).+, (\d+).+, (\d+)', out, re.MULTILINE)
+        m = re.search(b(r'^(\d+).+, (\d+).+, (\d+).+, (\d+)'), out,
+                      re.MULTILINE)
         return tuple(map(int, list(m.groups())))
 
     @property
@@ -1601,8 +1604,8 @@
         1, '+4-3095db9f5c2c')
         """
         if self._version is None:
-            v = self.rawcommand(cmdbuilder('version', q=True))
-            v = list(re.match(r'.*?(\d+)\.(\d+)\.?(\d+)?(\+[0-9a-f-]+)?',
+            v = self.rawcommand(cmdbuilder(b('version'), q=True))
+            v = list(re.match(b(r'.*?(\d+)\.(\d+)\.?(\d+)?(\+[0-9a-f-]+)?'),
                               v).groups())
 
             for i in range(3):