##// END OF EJS Templates
py3: factor out byterepr() which returns an asciified value on py3
py3: factor out byterepr() which returns an asciified value on py3

File last commit:

r36279:b44fac3a default
r36279:b44fac3a default
Show More
pycompat.py
353 lines | 10.7 KiB | text/x-python | PythonLexer
timeless
pycompat: add empty and queue to handle py3 divergence...
r28818 # pycompat.py - portability shim for python 3
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
"""Mercurial portability shim for python 3.
This contains aliases to hide python version-specific details from the core.
"""
from __future__ import absolute_import
Pulkit Goyal
py3: make a bytes version of getopt.getopt()...
r30578 import getopt
Augie Fackler
py3: introduce and use pycompat.getargspec...
r36196 import inspect
Pulkit Goyal
py3: add a bytes version of os.name...
r30302 import os
Pulkit Goyal
py3: have a bytes version of shlex.split()...
r30678 import shlex
Pulkit Goyal
pycompat: make pycompat demandimport friendly...
r29584 import sys
Yuya Nishihara
pycompat: provide 'ispy3' constant...
r30030 ispy3 = (sys.version_info[0] >= 3)
Yuya Nishihara
util: fix sortdict.update() to call __setitem__() on PyPy (issue5639)...
r33628 ispypy = (r'__pypy__' in sys.builtin_module_names)
Yuya Nishihara
pycompat: provide 'ispy3' constant...
r30030
if not ispy3:
Gregory Szorc
util: make cookielib module available...
r31934 import cookielib
Pulkit Goyal
py3: conditionalize cPickle import by adding in util...
r29324 import cPickle as pickle
Pulkit Goyal
py3: conditionalize httplib import...
r29455 import httplib
Pulkit Goyal
pycompat: make pycompat demandimport friendly...
r29584 import Queue as _queue
Pulkit Goyal
py3: conditionalize SocketServer import...
r29433 import SocketServer as socketserver
Pulkit Goyal
py3: conditionalize xmlrpclib import...
r29432 import xmlrpclib
Pulkit Goyal
pycompat: make pycompat demandimport friendly...
r29584 else:
Gregory Szorc
pycompat: import correct cookie module on Python 3...
r31942 import http.cookiejar as cookielib
Pulkit Goyal
pycompat: make pycompat demandimport friendly...
r29584 import http.client as httplib
import pickle
import queue as _queue
import socketserver
Pulkit Goyal
py3: conditionalize xmlrpclib import...
r29432 import xmlrpc.client as xmlrpclib
Pulkit Goyal
py3: conditionalize the urlparse import...
r29431
Pulkit Goyal
pycompat: move the queue related definitions below queue import...
r32865 empty = _queue.Empty
queue = _queue.Queue
Yuya Nishihara
pycompat: introduce identity function as a compat stub...
r31774 def identity(a):
return a
Yuya Nishihara
pycompat: provide 'ispy3' constant...
r30030 if ispy3:
Yuya Nishihara
py3: move xrange alias next to import lines...
r29797 import builtins
Yuya Nishihara
py3: provide (del|get|has|set)attr wrappers that accepts bytes...
r29799 import functools
Yuya Nishihara
pycompat: move imports of cStringIO/io to where they are used...
r31372 import io
Martin von Zweigbergk
py3: optimize py3 compat.bytechr using Struct.pack...
r31424 import struct
Yuya Nishihara
pycompat: move imports of cStringIO/io to where they are used...
r31372
Martijn Pieters
py3: add an os.fsencode backport to ease path handling
r30119 fsencode = os.fsencode
Pulkit Goyal
py3: add os.fsdecode() as pycompat.fsdecode()...
r30300 fsdecode = os.fsdecode
Yuya Nishihara
pycompat: provide bytes os.linesep
r31775 oslinesep = os.linesep.encode('ascii')
Pulkit Goyal
py3: add a bytes version of os.name...
r30302 osname = os.name.encode('ascii')
Pulkit Goyal
py3: have pycompat.ospathsep and pycompat.ossep...
r30303 ospathsep = os.pathsep.encode('ascii')
ossep = os.sep.encode('ascii')
Pulkit Goyal
py3: have a bytes version of os.altsep...
r30623 osaltsep = os.altsep
if osaltsep:
osaltsep = osaltsep.encode('ascii')
Pulkit Goyal
py3: add os.getcwdb() to have bytes path...
r30500 # os.getcwd() on Python 3 returns string, but it has os.getcwdb() which
# returns bytes.
getcwd = os.getcwdb
Pulkit Goyal
py3: have a bytes version of sys.platform...
r30624 sysplatform = sys.platform.encode('ascii')
Pulkit Goyal
py3: have bytes version of sys.executable...
r30668 sysexecutable = sys.executable
if sysexecutable:
sysexecutable = os.fsencode(sysexecutable)
Pulkit Goyal
pycompat: default to BytesIO instead of StringIO
r31359 stringio = io.BytesIO
Augie Fackler
pycompat: add maplist alias for old map behavior
r31501 maplist = lambda *args: list(map(*args))
Pulkit Goyal
py3: introduce pycompat.ziplist as zip is a generator on Python 3...
r35406 ziplist = lambda *args: list(zip(*args))
Yuya Nishihara
py3: select input or raw_input by pycompat...
r33853 rawinput = input
Augie Fackler
py3: introduce and use pycompat.getargspec...
r36196 getargspec = inspect.getfullargspec
Yuya Nishihara
py3: document why os.fsencode() can be used to get back bytes argv...
r30334
Yuya Nishihara
py3: provide bytes stdin/out/err through util module...
r30472 # TODO: .buffer might not exist if std streams were replaced; we'll need
# a silly wrapper to make a bytes stream backed by a unicode one.
stdin = sys.stdin.buffer
stdout = sys.stdout.buffer
stderr = sys.stderr.buffer
Yuya Nishihara
py3: document why os.fsencode() can be used to get back bytes argv...
r30334 # Since Python 3 converts argv to wchar_t type by Py_DecodeLocale() on Unix,
# we can use os.fsencode() to get back bytes argv.
#
# https://hg.python.org/cpython/file/v3.5.1/Programs/python.c#l55
#
# TODO: On Windows, the native argv is wchar_t, so we'll need a different
# workaround to simulate the Python 2 (i.e. ANSI Win32 API) behavior.
Augie Fackler
pycompat: verify sys.argv exists before forwarding it (issue5493)...
r31277 if getattr(sys, 'argv', None) is not None:
sysargv = list(map(os.fsencode, sys.argv))
Yuya Nishihara
py3: move xrange alias next to import lines...
r29797
Martin von Zweigbergk
py3: optimize py3 compat.bytechr using Struct.pack...
r31424 bytechr = struct.Struct('>B').pack
Yuya Nishihara
py3: factor out byterepr() which returns an asciified value on py3
r36279 byterepr = b'%r'.__mod__
Yuya Nishihara
py3: factor out bytechr() function...
r31253
Yuya Nishihara
pycompat: add bytestr wrapper which mostly acts as a Python 2 str...
r31439 class bytestr(bytes):
"""A bytes which mostly acts as a Python 2 str
>>> bytestr(), bytestr(bytearray(b'foo')), bytestr(u'ascii'), bytestr(1)
Yuya Nishihara
py3: always drop b'' prefix from repr() of bytestr...
r35921 ('', 'foo', 'ascii', '1')
Yuya Nishihara
pycompat: add bytestr wrapper which mostly acts as a Python 2 str...
r31439 >>> s = bytestr(b'foo')
>>> assert s is bytestr(s)
Yuya Nishihara
pycompat: try __bytes__() to convert object to bytestr...
r32450 __bytes__() should be called if provided:
>>> class bytesable(object):
... def __bytes__(self):
... return b'bytes'
>>> bytestr(bytesable())
Yuya Nishihara
py3: always drop b'' prefix from repr() of bytestr...
r35921 'bytes'
Yuya Nishihara
pycompat: try __bytes__() to convert object to bytestr...
r32450
Yuya Nishihara
pycompat: add bytestr wrapper which mostly acts as a Python 2 str...
r31439 There's no implicit conversion from non-ascii str as its encoding is
unknown:
>>> bytestr(chr(0x80)) # doctest: +ELLIPSIS
Traceback (most recent call last):
...
UnicodeEncodeError: ...
Comparison between bytestr and bytes should work:
>>> assert bytestr(b'foo') == b'foo'
>>> assert b'foo' == bytestr(b'foo')
>>> assert b'f' in bytestr(b'foo')
>>> assert bytestr(b'f') in b'foo'
Sliced elements should be bytes, not integer:
>>> s[1], s[:2]
(b'o', b'fo')
>>> list(s), list(reversed(s))
([b'f', b'o', b'o'], [b'o', b'o', b'f'])
As bytestr type isn't propagated across operations, you need to cast
bytes to bytestr explicitly:
>>> s = bytestr(b'foo').upper()
>>> t = bytestr(s)
>>> s[0], t[0]
(70, b'F')
Be careful to not pass a bytestr object to a function which expects
bytearray-like behavior.
>>> t = bytes(t) # cast to bytes
>>> assert type(t) is bytes
"""
def __new__(cls, s=b''):
if isinstance(s, bytestr):
return s
Yuya Nishihara
pycompat: try __bytes__() to convert object to bytestr...
r32450 if (not isinstance(s, (bytes, bytearray))
and not hasattr(s, u'__bytes__')): # hasattr-py3-only
Yuya Nishihara
pycompat: add bytestr wrapper which mostly acts as a Python 2 str...
r31439 s = str(s).encode(u'ascii')
return bytes.__new__(cls, s)
def __getitem__(self, key):
s = bytes.__getitem__(self, key)
if not isinstance(s, bytes):
s = bytechr(s)
return s
def __iter__(self):
return iterbytestr(bytes.__iter__(self))
Yuya Nishihara
py3: always drop b'' prefix from repr() of bytestr...
r35921 def __repr__(self):
return bytes.__repr__(self)[1:] # drop b''
Yuya Nishihara
pycompat: add helper to iterate each char in bytes
r31382 def iterbytestr(s):
"""Iterate bytes as if it were a str object of Python 2"""
Martin von Zweigbergk
py3: make py3 compat.iterbytestr simpler and faster...
r31425 return map(bytechr, s)
Yuya Nishihara
pycompat: add helper to iterate each char in bytes
r31382
Yuya Nishihara
py3: drop b'' from repr() of smartset...
r35922 def maybebytestr(s):
"""Promote bytes to bytestr"""
if isinstance(s, bytes):
return bytestr(s)
return s
Yuya Nishihara
py3: have registrar process docstrings in bytes...
r31820 def sysbytes(s):
"""Convert an internal str (e.g. keyword, __doc__) back to bytes
This never raises UnicodeEncodeError, but only ASCII characters
can be round-trip by sysstr(sysbytes(s)).
"""
return s.encode(u'utf-8')
Yuya Nishihara
pycompat: extract function that converts attribute or encoding name to str...
r30032 def sysstr(s):
"""Return a keyword str to be passed to Python functions such as
getattr() and str.encode()
This never raises UnicodeDecodeError. Non-ascii characters are
considered invalid and mapped to arbitrary but unique code points
such that 'sysstr(a) != sysstr(b)' for all 'a != b'.
"""
if isinstance(s, builtins.str):
return s
return s.decode(u'latin-1')
Pulkit Goyal
py3: add a new strurl() which will convert a bytes url to str
r32859 def strurl(url):
"""Converts a bytes url back to str"""
return url.decode(u'ascii')
Pulkit Goyal
py3: add a new bytesurl() to convert a str url into bytes
r32860 def bytesurl(url):
"""Converts a str url to bytes by encoding in ascii"""
return url.encode(u'ascii')
Yuya Nishihara
pycompat: extract helper to raise exception with traceback...
r32186 def raisewithtb(exc, tb):
"""Raise exception with the given traceback"""
raise exc.with_traceback(tb)
Yuya Nishihara
py3: convert __doc__ back to bytes in help.py...
r32615 def getdoc(obj):
"""Get docstring as bytes; may be None so gettext() won't confuse it
with _('')"""
doc = getattr(obj, u'__doc__', None)
if doc is None:
return doc
return sysbytes(doc)
Yuya Nishihara
py3: provide (del|get|has|set)attr wrappers that accepts bytes...
r29799 def _wrapattrfunc(f):
@functools.wraps(f)
def w(object, name, *args):
Yuya Nishihara
pycompat: extract function that converts attribute or encoding name to str...
r30032 return f(object, sysstr(name), *args)
Yuya Nishihara
py3: provide (del|get|has|set)attr wrappers that accepts bytes...
r29799 return w
Yuya Nishihara
py3: import builtin wrappers automagically by code transformer...
r29800 # these wrappers are automagically imported by hgloader
Yuya Nishihara
py3: provide (del|get|has|set)attr wrappers that accepts bytes...
r29799 delattr = _wrapattrfunc(builtins.delattr)
getattr = _wrapattrfunc(builtins.getattr)
hasattr = _wrapattrfunc(builtins.hasattr)
setattr = _wrapattrfunc(builtins.setattr)
Yuya Nishihara
py3: import builtin wrappers automagically by code transformer...
r29800 xrange = builtins.range
Pulkit Goyal
py3: add pycompat.unicode and add it to importer...
r31843 unicode = str
Yuya Nishihara
py3: provide (del|get|has|set)attr wrappers that accepts bytes...
r29799
Pulkit Goyal
py3: add pycompat.open and replace open() calls...
r31149 def open(name, mode='r', buffering=-1):
return builtins.open(name, sysstr(mode), buffering)
Yuya Nishihara
fancyopts: use getopt.gnu_getopt()...
r35226 def _getoptbwrapper(orig, args, shortlist, namelist):
Pulkit Goyal
pycompat: move multiline comments above a function to function doc...
r32864 """
Takes bytes arguments, converts them to unicode, pass them to
getopt.getopt(), convert the returned values back to bytes and then
return them for Python 3 compatibility as getopt.getopt() don't accepts
bytes on Python 3.
"""
Pulkit Goyal
py3: make a bytes version of getopt.getopt()...
r30578 args = [a.decode('latin-1') for a in args]
shortlist = shortlist.decode('latin-1')
namelist = [a.decode('latin-1') for a in namelist]
Yuya Nishihara
fancyopts: use getopt.gnu_getopt()...
r35226 opts, args = orig(args, shortlist, namelist)
Pulkit Goyal
py3: make a bytes version of getopt.getopt()...
r30578 opts = [(a[0].encode('latin-1'), a[1].encode('latin-1'))
for a in opts]
args = [a.encode('latin-1') for a in args]
return opts, args
Pulkit Goyal
py3: utility functions to convert keys of kwargs to bytes/unicodes...
r30579 def strkwargs(dic):
Pulkit Goyal
pycompat: move multiline comments above a function to function doc...
r32864 """
Converts the keys of a python dictonary to str i.e. unicodes so that
they can be passed as keyword arguments as dictonaries with bytes keys
can't be passed as keyword arguments to functions on Python 3.
"""
Pulkit Goyal
py3: utility functions to convert keys of kwargs to bytes/unicodes...
r30579 dic = dict((k.decode('latin-1'), v) for k, v in dic.iteritems())
return dic
def byteskwargs(dic):
Pulkit Goyal
pycompat: move multiline comments above a function to function doc...
r32864 """
Converts keys of python dictonaries to bytes as they were converted to
str to pass that dictonary as a keyword argument on Python 3.
"""
Pulkit Goyal
py3: utility functions to convert keys of kwargs to bytes/unicodes...
r30579 dic = dict((k.encode('latin-1'), v) for k, v in dic.iteritems())
return dic
Pulkit Goyal
py3: have a bytes version of shlex.split()...
r30678 # TODO: handle shlex.shlex().
def shlexsplit(s):
Pulkit Goyal
pycompat: move multiline comments above a function to function doc...
r32864 """
Takes bytes argument, convert it to str i.e. unicodes, pass that into
shlex.split(), convert the returned value to bytes and return that for
Python 3 compatibility as shelx.split() don't accept bytes on Python 3.
"""
Pulkit Goyal
py3: have a bytes version of shlex.split()...
r30678 ret = shlex.split(s.decode('latin-1'))
return [a.encode('latin-1') for a in ret]
Gregory Szorc
py3: use email parser that operates on bytes...
r36062 def emailparser(*args, **kwargs):
import email.parser
return email.parser.BytesParser(*args, **kwargs)
Yuya Nishihara
pycompat: extract function that converts attribute or encoding name to str...
r30032 else:
Yuya Nishihara
pycompat: move imports of cStringIO/io to where they are used...
r31372 import cStringIO
Yuya Nishihara
py3: factor out bytechr() function...
r31253 bytechr = chr
Yuya Nishihara
py3: factor out byterepr() which returns an asciified value on py3
r36279 byterepr = repr
Yuya Nishihara
pycompat: add bytestr wrapper which mostly acts as a Python 2 str...
r31439 bytestr = str
Yuya Nishihara
pycompat: add helper to iterate each char in bytes
r31382 iterbytestr = iter
Yuya Nishihara
py3: drop b'' from repr() of smartset...
r35922 maybebytestr = identity
Yuya Nishihara
py3: have registrar process docstrings in bytes...
r31820 sysbytes = identity
Yuya Nishihara
pycompat: introduce identity function as a compat stub...
r31774 sysstr = identity
Pulkit Goyal
py3: add a new strurl() which will convert a bytes url to str
r32859 strurl = identity
Pulkit Goyal
py3: add a new bytesurl() to convert a str url into bytes
r32860 bytesurl = identity
Yuya Nishihara
pycompat: extract function that converts attribute or encoding name to str...
r30032
Yuya Nishihara
pycompat: extract helper to raise exception with traceback...
r32186 # this can't be parsed on Python 3
exec('def raisewithtb(exc, tb):\n'
' raise exc, None, tb\n')
Martijn Pieters
pycompat: only accept a bytestring filepath in Python 2
r30133 def fsencode(filename):
Pulkit Goyal
pycompat: move multiline comments above a function to function doc...
r32864 """
Partial backport from os.py in Python 3, which only accepts bytes.
In Python 2, our paths should only ever be bytes, a unicode path
indicates a bug.
"""
Martijn Pieters
pycompat: only accept a bytestring filepath in Python 2
r30133 if isinstance(filename, str):
return filename
Martijn Pieters
py3: add an os.fsencode backport to ease path handling
r30119 else:
Martijn Pieters
pycompat: only accept a bytestring filepath in Python 2
r30133 raise TypeError(
"expect str, not %s" % type(filename).__name__)
Martijn Pieters
py3: add an os.fsencode backport to ease path handling
r30119
Pulkit Goyal
py3: add os.fsdecode() as pycompat.fsdecode()...
r30300 # In Python 2, fsdecode() has a very chance to receive bytes. So it's
# better not to touch Python 2 part as it's already working fine.
Yuya Nishihara
pycompat: introduce identity function as a compat stub...
r31774 fsdecode = identity
Pulkit Goyal
py3: add os.fsdecode() as pycompat.fsdecode()...
r30300
Yuya Nishihara
py3: convert __doc__ back to bytes in help.py...
r32615 def getdoc(obj):
return getattr(obj, '__doc__', None)
Yuya Nishihara
fancyopts: use getopt.gnu_getopt()...
r35226 def _getoptbwrapper(orig, args, shortlist, namelist):
return orig(args, shortlist, namelist)
Pulkit Goyal
py3: make a bytes version of getopt.getopt()...
r30578
Yuya Nishihara
pycompat: introduce identity function as a compat stub...
r31774 strkwargs = identity
byteskwargs = identity
Pulkit Goyal
py3: utility functions to convert keys of kwargs to bytes/unicodes...
r30579
Yuya Nishihara
pycompat: provide bytes os.linesep
r31775 oslinesep = os.linesep
Pulkit Goyal
py3: add a bytes version of os.name...
r30302 osname = os.name
Pulkit Goyal
py3: have pycompat.ospathsep and pycompat.ossep...
r30303 ospathsep = os.pathsep
ossep = os.sep
Pulkit Goyal
py3: have a bytes version of os.altsep...
r30623 osaltsep = os.altsep
Yuya Nishihara
py3: provide bytes stdin/out/err through util module...
r30472 stdin = sys.stdin
stdout = sys.stdout
stderr = sys.stderr
Augie Fackler
pycompat: verify sys.argv exists before forwarding it (issue5493)...
r31277 if getattr(sys, 'argv', None) is not None:
sysargv = sys.argv
Pulkit Goyal
py3: have a bytes version of sys.platform...
r30624 sysplatform = sys.platform
Pulkit Goyal
py3: add os.getcwdb() to have bytes path...
r30500 getcwd = os.getcwd
Pulkit Goyal
py3: have bytes version of sys.executable...
r30668 sysexecutable = sys.executable
Pulkit Goyal
py3: have a bytes version of shlex.split()...
r30678 shlexsplit = shlex.split
Yuya Nishihara
pycompat: move imports of cStringIO/io to where they are used...
r31372 stringio = cStringIO.StringIO
Augie Fackler
pycompat: add maplist alias for old map behavior
r31501 maplist = map
Pulkit Goyal
py3: introduce pycompat.ziplist as zip is a generator on Python 3...
r35406 ziplist = zip
Yuya Nishihara
py3: select input or raw_input by pycompat...
r33853 rawinput = raw_input
Augie Fackler
py3: introduce and use pycompat.getargspec...
r36196 getargspec = inspect.getargspec
Jun Wu
selectors2: do not use platform.system()...
r34640
Gregory Szorc
py3: use email parser that operates on bytes...
r36062 def emailparser(*args, **kwargs):
import email.parser
return email.parser.Parser(*args, **kwargs)
Jun Wu
selectors2: do not use platform.system()...
r34640 isjython = sysplatform.startswith('java')
Jun Wu
pycompat: define operating system constants...
r34645
isdarwin = sysplatform == 'darwin'
isposix = osname == 'posix'
iswindows = osname == 'nt'
Yuya Nishihara
fancyopts: use getopt.gnu_getopt()...
r35226
def getoptb(args, shortlist, namelist):
return _getoptbwrapper(getopt.getopt, args, shortlist, namelist)
def gnugetoptb(args, shortlist, namelist):
return _getoptbwrapper(getopt.gnu_getopt, args, shortlist, namelist)