Patchwork [4,of,4,RFC] pycompat: patch (del|get|has|set)attr to accept bytes on Python 3

login
register
mail settings
Submitter Yuya Nishihara
Date Aug. 14, 2016, 9:33 a.m.
Message ID <2a300f882c077fa01404.1471167228@mimosa>
Download mbox | patch
Permalink /patch/16279/
State Changes Requested
Headers show

Comments

Yuya Nishihara - Aug. 14, 2016, 9:33 a.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1471146681 -32400
#      Sun Aug 14 12:51:21 2016 +0900
# Node ID 2a300f882c077fa014046db96b545f6aff771d32
# Parent  d53bd633898ec6edafccea9f798d314699faf90a
pycompat: patch (del|get|has|set)attr to accept bytes on Python 3

getattr() and setattr() are widely used in our code. We wouldn't probably
want to rewrite every single call of getattr/setattr. delattr() and hasattr()
aren't that important, but they are functions of the same kind.

Another option would be util.(get|set)attr.
Gregory Szorc - Aug. 14, 2016, 4:27 p.m.
On Sun, Aug 14, 2016 at 2:33 AM, Yuya Nishihara <yuya@tcha.org> wrote:

> # HG changeset patch
> # User Yuya Nishihara <yuya@tcha.org>
> # Date 1471146681 -32400
> #      Sun Aug 14 12:51:21 2016 +0900
> # Node ID 2a300f882c077fa014046db96b545f6aff771d32
> # Parent  d53bd633898ec6edafccea9f798d314699faf90a
> pycompat: patch (del|get|has|set)attr to accept bytes on Python 3
>
> getattr() and setattr() are widely used in our code. We wouldn't probably
> want to rewrite every single call of getattr/setattr. delattr() and
> hasattr()
> aren't that important, but they are functions of the same kind.
>
> Another option would be util.(get|set)attr.
>

I'm generally opposed to modifying the behavior of stdlib functionality
because, well, it's modifying the stdlib. Extensions may load
packages/modules that rely on the default behavior, perhaps in subtle ways.
I would prefer proxy functions (possibly in util.py) over modifying the
standard library.


>
> diff --git a/mercurial/pycompat.py b/mercurial/pycompat.py
> --- a/mercurial/pycompat.py
> +++ b/mercurial/pycompat.py
> @@ -31,8 +31,27 @@ else:
>
>  if sys.version_info[0] >= 3:
>      import builtins
> +    import functools
>      builtins.xrange = range
>
> +    def _wrapattrfunc(f):
> +        try:
> +            # avoid useless wrapping on reload
> +            f.__wrapped__
> +            return f
> +        except AttributeError:
> +            pass
> +        @functools.wraps(f)
> +        def w(object, name, *args):
> +            if isinstance(name, bytes):
> +                name = name.decode('utf-8')
> +            return f(object, name, *args)
> +        return w
> +    builtins.delattr = _wrapattrfunc(builtins.delattr)
> +    builtins.getattr = _wrapattrfunc(builtins.getattr)
> +    builtins.hasattr = _wrapattrfunc(builtins.hasattr)
> +    builtins.setattr = _wrapattrfunc(builtins.setattr)
> +
>  stringio = io.StringIO
>  empty = _queue.Empty
>  queue = _queue.Queue
> diff --git a/tests/test-check-py3-compat.t b/tests/test-check-py3-compat.t
> --- a/tests/test-check-py3-compat.t
> +++ b/tests/test-check-py3-compat.t
> @@ -122,48 +122,48 @@
>    mercurial/hook.py: error importing: <TypeError> str expected, not bytes
> (error at i18n.py:*) (glob)
>    mercurial/httpconnection.py: error importing: <TypeError> str expected,
> not bytes (error at i18n.py:*) (glob)
>    mercurial/httppeer.py: error importing: <TypeError> str expected, not
> bytes (error at i18n.py:*) (glob)
> -  mercurial/keepalive.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/localrepo.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/lock.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/mail.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/manifest.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/match.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/mdiff.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/merge.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/minirst.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/namespaces.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/obsolete.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/patch.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/pathutil.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/peer.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/pushkey.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/pvec.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/registrar.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/repair.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/repoview.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/revlog.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/revset.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/scmutil.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/scmwindows.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/similar.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/simplemerge.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/sshpeer.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/sshserver.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/sslutil.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/statichttprepo.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/store.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/streamclone.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/subrepo.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/tagmerge.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/tags.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/templatefilters.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/templatekw.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/templater.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/transaction.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/ui.py: error importing: <TypeError> getattr(): attribute name
> must be string (error at util.py:*) (glob)
> -  mercurial/unionrepo.py: error importing: <TypeError> getattr():
> attribute name must be string (error at util.py:*) (glob)
> -  mercurial/url.py: error importing: <TypeError> getattr(): attribute
> name must be string (error at util.py:*) (glob)
> -  mercurial/verify.py: error importing: <TypeError> attribute name must
> be string, not 'bytes' (error at mdiff.py:*) (glob)
> +  mercurial/keepalive.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/localrepo.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/lock.py: error importing: <TypeError> __slots__ items must be
> strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/mail.py: error importing: <TypeError> __slots__ items must be
> strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/manifest.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/match.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/mdiff.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/merge.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/minirst.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/namespaces.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/obsolete.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/patch.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/pathutil.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/peer.py: error importing: <TypeError> __slots__ items must be
> strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/pushkey.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/pvec.py: error importing: <TypeError> __slots__ items must be
> strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/registrar.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/repair.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/repoview.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/revlog.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/revset.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/scmutil.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/scmwindows.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/similar.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/simplemerge.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/sshpeer.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/sshserver.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/sslutil.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/statichttprepo.py: error importing: <TypeError> __slots__
> items must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/store.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/streamclone.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/subrepo.py: error importing: <TypeError> __slots__ items must
> be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/tagmerge.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/tags.py: error importing: <TypeError> __slots__ items must be
> strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/templatefilters.py: error importing: <TypeError> __slots__
> items must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/templatekw.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/templater.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/transaction.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/ui.py: error importing: <TypeError> __slots__ items must be
> strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/unionrepo.py: error importing: <TypeError> __slots__ items
> must be strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/url.py: error importing: <TypeError> __slots__ items must be
> strings, not 'bytes' (error at util.py:*) (glob)
> +  mercurial/verify.py: error importing module: <TypeError> unorderable
> types: str() >= tuple() (line *) (glob)
>    mercurial/win32.py: error importing module: <ImportError> No module
> named 'msvcrt' (line *) (glob)
>    mercurial/windows.py: error importing module: <ImportError> No module
> named 'msvcrt' (line *) (glob)
>    mercurial/wireproto.py: error importing module: <TypeError> unorderable
> types: str() >= tuple() (line *) (glob)
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>
Yuya Nishihara - Aug. 15, 2016, 9:52 a.m.
On Sun, 14 Aug 2016 09:27:16 -0700, Gregory Szorc wrote:
> On Sun, Aug 14, 2016 at 2:33 AM, Yuya Nishihara <yuya@tcha.org> wrote:
> > # HG changeset patch
> > # User Yuya Nishihara <yuya@tcha.org>
> > # Date 1471146681 -32400
> > #      Sun Aug 14 12:51:21 2016 +0900
> > # Node ID 2a300f882c077fa014046db96b545f6aff771d32
> > # Parent  d53bd633898ec6edafccea9f798d314699faf90a
> > pycompat: patch (del|get|has|set)attr to accept bytes on Python 3
> >
> > getattr() and setattr() are widely used in our code. We wouldn't probably
> > want to rewrite every single call of getattr/setattr. delattr() and
> > hasattr()
> > aren't that important, but they are functions of the same kind.
> >
> > Another option would be util.(get|set)attr.
> 
> I'm generally opposed to modifying the behavior of stdlib functionality
> because, well, it's modifying the stdlib. Extensions may load
> packages/modules that rely on the default behavior, perhaps in subtle ways.
> I would prefer proxy functions (possibly in util.py) over modifying the
> standard library.

Maybe we can insert "from mercurial.pycompat import xrange, getattr, ..."
by our Py3k importer, which should be better than hacking builtins and we
can avoid bulk rewrites.
Gregory Szorc - Aug. 15, 2016, 4:17 p.m.
> On Aug 15, 2016, at 02:52, Yuya Nishihara <yuya@tcha.org> wrote:
> 
>> On Sun, 14 Aug 2016 09:27:16 -0700, Gregory Szorc wrote:
>>> On Sun, Aug 14, 2016 at 2:33 AM, Yuya Nishihara <yuya@tcha.org> wrote:
>>> # HG changeset patch
>>> # User Yuya Nishihara <yuya@tcha.org>
>>> # Date 1471146681 -32400
>>> #      Sun Aug 14 12:51:21 2016 +0900
>>> # Node ID 2a300f882c077fa014046db96b545f6aff771d32
>>> # Parent  d53bd633898ec6edafccea9f798d314699faf90a
>>> pycompat: patch (del|get|has|set)attr to accept bytes on Python 3
>>> 
>>> getattr() and setattr() are widely used in our code. We wouldn't probably
>>> want to rewrite every single call of getattr/setattr. delattr() and
>>> hasattr()
>>> aren't that important, but they are functions of the same kind.
>>> 
>>> Another option would be util.(get|set)attr.
>> 
>> I'm generally opposed to modifying the behavior of stdlib functionality
>> because, well, it's modifying the stdlib. Extensions may load
>> packages/modules that rely on the default behavior, perhaps in subtle ways.
>> I would prefer proxy functions (possibly in util.py) over modifying the
>> standard library.
> 
> Maybe we can insert "from mercurial.pycompat import xrange, getattr, ..."
> by our Py3k importer, which should be better than hacking builtins and we
> can avoid bulk rewrites.

My initial reaction is I really like this idea!
timeless - Aug. 16, 2016, 8:37 p.m.
me too

On Mon, Aug 15, 2016 at 12:17 PM, Gregory Szorc <gregory.szorc@gmail.com> wrote:
>
>
>> On Aug 15, 2016, at 02:52, Yuya Nishihara <yuya@tcha.org> wrote:
>>
>>> On Sun, 14 Aug 2016 09:27:16 -0700, Gregory Szorc wrote:
>>>> On Sun, Aug 14, 2016 at 2:33 AM, Yuya Nishihara <yuya@tcha.org> wrote:
>>>> # HG changeset patch
>>>> # User Yuya Nishihara <yuya@tcha.org>
>>>> # Date 1471146681 -32400
>>>> #      Sun Aug 14 12:51:21 2016 +0900
>>>> # Node ID 2a300f882c077fa014046db96b545f6aff771d32
>>>> # Parent  d53bd633898ec6edafccea9f798d314699faf90a
>>>> pycompat: patch (del|get|has|set)attr to accept bytes on Python 3
>>>>
>>>> getattr() and setattr() are widely used in our code. We wouldn't probably
>>>> want to rewrite every single call of getattr/setattr. delattr() and
>>>> hasattr()
>>>> aren't that important, but they are functions of the same kind.
>>>>
>>>> Another option would be util.(get|set)attr.
>>>
>>> I'm generally opposed to modifying the behavior of stdlib functionality
>>> because, well, it's modifying the stdlib. Extensions may load
>>> packages/modules that rely on the default behavior, perhaps in subtle ways.
>>> I would prefer proxy functions (possibly in util.py) over modifying the
>>> standard library.
>>
>> Maybe we can insert "from mercurial.pycompat import xrange, getattr, ..."
>> by our Py3k importer, which should be better than hacking builtins and we
>> can avoid bulk rewrites.
>
> My initial reaction is I really like this idea!
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

Patch

diff --git a/mercurial/pycompat.py b/mercurial/pycompat.py
--- a/mercurial/pycompat.py
+++ b/mercurial/pycompat.py
@@ -31,8 +31,27 @@  else:
 
 if sys.version_info[0] >= 3:
     import builtins
+    import functools
     builtins.xrange = range
 
+    def _wrapattrfunc(f):
+        try:
+            # avoid useless wrapping on reload
+            f.__wrapped__
+            return f
+        except AttributeError:
+            pass
+        @functools.wraps(f)
+        def w(object, name, *args):
+            if isinstance(name, bytes):
+                name = name.decode('utf-8')
+            return f(object, name, *args)
+        return w
+    builtins.delattr = _wrapattrfunc(builtins.delattr)
+    builtins.getattr = _wrapattrfunc(builtins.getattr)
+    builtins.hasattr = _wrapattrfunc(builtins.hasattr)
+    builtins.setattr = _wrapattrfunc(builtins.setattr)
+
 stringio = io.StringIO
 empty = _queue.Empty
 queue = _queue.Queue
diff --git a/tests/test-check-py3-compat.t b/tests/test-check-py3-compat.t
--- a/tests/test-check-py3-compat.t
+++ b/tests/test-check-py3-compat.t
@@ -122,48 +122,48 @@ 
   mercurial/hook.py: error importing: <TypeError> str expected, not bytes (error at i18n.py:*) (glob)
   mercurial/httpconnection.py: error importing: <TypeError> str expected, not bytes (error at i18n.py:*) (glob)
   mercurial/httppeer.py: error importing: <TypeError> str expected, not bytes (error at i18n.py:*) (glob)
-  mercurial/keepalive.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/localrepo.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/lock.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/mail.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/manifest.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/match.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/mdiff.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/merge.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/minirst.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/namespaces.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/obsolete.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/patch.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/pathutil.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/peer.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/pushkey.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/pvec.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/registrar.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/repair.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/repoview.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/revlog.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/revset.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/scmutil.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/scmwindows.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/similar.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/simplemerge.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/sshpeer.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/sshserver.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/sslutil.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/statichttprepo.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/store.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/streamclone.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/subrepo.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/tagmerge.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/tags.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/templatefilters.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/templatekw.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/templater.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/transaction.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/ui.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/unionrepo.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/url.py: error importing: <TypeError> getattr(): attribute name must be string (error at util.py:*) (glob)
-  mercurial/verify.py: error importing: <TypeError> attribute name must be string, not 'bytes' (error at mdiff.py:*) (glob)
+  mercurial/keepalive.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/localrepo.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/lock.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/mail.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/manifest.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/match.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/mdiff.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/merge.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/minirst.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/namespaces.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/obsolete.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/patch.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/pathutil.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/peer.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/pushkey.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/pvec.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/registrar.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/repair.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/repoview.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/revlog.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/revset.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/scmutil.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/scmwindows.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/similar.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/simplemerge.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/sshpeer.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/sshserver.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/sslutil.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/statichttprepo.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/store.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/streamclone.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/subrepo.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/tagmerge.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/tags.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/templatefilters.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/templatekw.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/templater.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/transaction.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/ui.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/unionrepo.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/url.py: error importing: <TypeError> __slots__ items must be strings, not 'bytes' (error at util.py:*) (glob)
+  mercurial/verify.py: error importing module: <TypeError> unorderable types: str() >= tuple() (line *) (glob)
   mercurial/win32.py: error importing module: <ImportError> No module named 'msvcrt' (line *) (glob)
   mercurial/windows.py: error importing module: <ImportError> No module named 'msvcrt' (line *) (glob)
   mercurial/wireproto.py: error importing module: <TypeError> unorderable types: str() >= tuple() (line *) (glob)