Patchwork [2,of,2] py3: add utility to forward __str__() to __bytes__()

login
register
mail settings
Submitter Yuya Nishihara
Date June 24, 2017, 5:56 a.m.
Message ID <ce96efec81121eab1c8e.1498283810@mimosa>
Download mbox | patch
Permalink /patch/21664/
State Accepted
Headers show

Comments

Yuya Nishihara - June 24, 2017, 5:56 a.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1498279684 -32400
#      Sat Jun 24 13:48:04 2017 +0900
# Node ID ce96efec81121eab1c8ee3ff223a924530322400
# Parent  24c0a9a7fa865cc6ff6f1a5b183bffe8a220dda6
py3: add utility to forward __str__() to __bytes__()

It calls unifromlocal() instead of sysstr() because __bytes__() may contain
locale-dependent values such as paths.
via Mercurial-devel - June 24, 2017, 7:08 a.m.
On Fri, Jun 23, 2017 at 10:56 PM, Yuya Nishihara <yuya@tcha.org> wrote:
> # HG changeset patch
> # User Yuya Nishihara <yuya@tcha.org>
> # Date 1498279684 -32400
> #      Sat Jun 24 13:48:04 2017 +0900
> # Node ID ce96efec81121eab1c8ee3ff223a924530322400
> # Parent  24c0a9a7fa865cc6ff6f1a5b183bffe8a220dda6
> py3: add utility to forward __str__() to __bytes__()

Queued, thanks.

Maybe I could use this for *matcher.__repr__ too.
Yuya Nishihara - June 24, 2017, 7:40 a.m.
On Sat, 24 Jun 2017 00:08:44 -0700, Martin von Zweigbergk wrote:
> On Fri, Jun 23, 2017 at 10:56 PM, Yuya Nishihara <yuya@tcha.org> wrote:
> > # HG changeset patch
> > # User Yuya Nishihara <yuya@tcha.org>
> > # Date 1498279684 -32400
> > #      Sat Jun 24 13:48:04 2017 +0900
> > # Node ID ce96efec81121eab1c8ee3ff223a924530322400
> > # Parent  24c0a9a7fa865cc6ff6f1a5b183bffe8a220dda6
> > py3: add utility to forward __str__() to __bytes__()
> 
> Queued, thanks.
> 
> Maybe I could use this for *matcher.__repr__ too.

Perhaps. It can be used as a decorator.

I have no concrete idea how to convert repr() back to bytes, though.

Patch

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -65,15 +65,11 @@  class basectx(object):
 
         return o
 
-    def __str__(self):
-        r = short(self.node())
-        if pycompat.ispy3:
-            return r.decode('ascii')
-        return r
-
     def __bytes__(self):
         return short(self.node())
 
+    __str__ = encoding.strmethod(__bytes__)
+
     def __int__(self):
         return self.rev()
 
@@ -710,17 +706,13 @@  class basefilectx(object):
 
     __bool__ = __nonzero__
 
-    def __str__(self):
+    def __bytes__(self):
         try:
             return "%s@%s" % (self.path(), self._changectx)
         except error.LookupError:
             return "%s@???" % self.path()
 
-    def __bytes__(self):
-        try:
-            return "%s@%s" % (self.path(), self._changectx)
-        except error.LookupError:
-            return "%s@???" % self.path()
+    __str__ = encoding.strmethod(__bytes__)
 
     def __repr__(self):
         return "<%s %s>" % (type(self).__name__, str(self))
@@ -1306,12 +1298,11 @@  class committablectx(basectx):
         if self._extra['branch'] == '':
             self._extra['branch'] = 'default'
 
-    def __str__(self):
-        return str(self._parents[0]) + r"+"
-
     def __bytes__(self):
         return bytes(self._parents[0]) + "+"
 
+    __str__ = encoding.strmethod(__bytes__)
+
     def __nonzero__(self):
         return True
 
diff --git a/mercurial/encoding.py b/mercurial/encoding.py
--- a/mercurial/encoding.py
+++ b/mercurial/encoding.py
@@ -177,15 +177,24 @@  def unifromlocal(s):
     """Convert a byte string of local encoding to a unicode string"""
     return fromlocal(s).decode('utf-8')
 
+def unimethod(bytesfunc):
+    """Create a proxy method that forwards __unicode__() and __str__() of
+    Python 3 to __bytes__()"""
+    def unifunc(obj):
+        return unifromlocal(bytesfunc(obj))
+    return unifunc
+
 # converter functions between native str and byte string. use these if the
 # character encoding is not aware (e.g. exception message) or is known to
 # be locale dependent (e.g. date formatting.)
 if pycompat.ispy3:
     strtolocal = unitolocal
     strfromlocal = unifromlocal
+    strmethod = unimethod
 else:
     strtolocal = pycompat.identity
     strfromlocal = pycompat.identity
+    strmethod = pycompat.identity
 
 if not _nativeenviron:
     # now encoding and helper functions are available, recreate the environ
diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -2740,7 +2740,7 @@  class url(object):
                 attrs.append('%s: %r' % (a, v))
         return '<url %s>' % ', '.join(attrs)
 
-    def __str__(self):
+    def __bytes__(self):
         r"""Join the URL's components back into a URL string.
 
         Examples:
@@ -2774,9 +2774,6 @@  class url(object):
         >>> print url(r'file:///D:\data\hg')
         file:///D:\data\hg
         """
-        return encoding.strfromlocal(self.__bytes__())
-
-    def __bytes__(self):
         if self._localpath:
             s = self.path
             if self.scheme == 'bundle':
@@ -2820,6 +2817,8 @@  class url(object):
             s += '#' + urlreq.quote(self.fragment, safe=self._safepchars)
         return s
 
+    __str__ = encoding.strmethod(__bytes__)
+
     def authinfo(self):
         user, passwd = self.user, self.passwd
         try: