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

Gregory Szorc gregory.szorc at gmail.com
Sun Aug 14 12:27:16 EDT 2016


On Sun, Aug 14, 2016 at 2:33 AM, Yuya Nishihara <yuya at tcha.org> wrote:

> # HG changeset patch
> # User Yuya Nishihara <yuya at 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 at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.mercurial-scm.org/pipermail/mercurial-devel/attachments/20160814/81c4a68c/attachment.html>


More information about the Mercurial-devel mailing list