Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""":mod:`wand.compat` --- Compatibility layer 

2~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

3 

4This module provides several subtle things to support 

5multiple Python versions (2.6, 2.7, 3.3+) and VM implementations 

6(CPython, PyPy). 

7 

8""" 

9import collections 

10try: 

11 import collections.abc 

12except ImportError: 

13 pass 

14import contextlib 

15import io 

16import sys 

17import types 

18 

19__all__ = ('PY3', 'abc', 'binary', 'binary_type', 'encode_filename', 

20 'file_types', 'nested', 'string_type', 'text', 'text_type', 

21 'xrange') 

22 

23 

24#: (:class:`bool`) Whether it is Python 3.x or not. 

25PY3 = sys.version_info >= (3,) 

26 

27#: (:class:`module`) Module containing abstract base classes. 

28#: :mod:`collections` in Python 2 and :mod:`collections.abc` in Python 3. 

29abc = collections.abc if PY3 else collections 

30 

31#: (:class:`type`) Type for representing binary data. :class:`str` in Python 2 

32#: and :class:`bytes` in Python 3. 

33binary_type = bytes if PY3 else str 

34 

35#: (:class:`type`) Type for text data. :class:`basestring` in Python 2 

36#: and :class:`str` in Python 3. 

37string_type = str if PY3 else basestring # noqa 

38 

39#: (:class:`type`) Type for representing Unicode textual data. 

40#: :class:`unicode` in Python 2 and :class:`str` in Python 3. 

41text_type = str if PY3 else unicode # noqa 

42 

43 

44def binary(string, var=None): 

45 """Makes ``string`` to :class:`str` in Python 2. 

46 Makes ``string`` to :class:`bytes` in Python 3. 

47 

48 :param string: a string to cast it to :data:`binary_type` 

49 :type string: :class:`bytes`, :class:`str`, :class:`unicode` 

50 :param var: an optional variable name to be used for error message 

51 :type var: :class:`str` 

52 

53 """ 

54 if isinstance(string, text_type): 

55 return string.encode() 

56 elif isinstance(string, binary_type): 

57 return string 

58 if var: 

59 raise TypeError('{0} must be a string, not {1!r}'.format(var, string)) 

60 raise TypeError('expected a string, not ' + repr(string)) 

61 

62 

63if PY3: 

64 def text(string): 

65 if isinstance(string, bytes): 

66 return string.decode('utf-8') 

67 return string 

68else: 

69 def text(string): 

70 """Makes ``string`` to :class:`str` in Python 3. 

71 Does nothing in Python 2. 

72 

73 :param string: a string to cast it to :data:`text_type` 

74 :type string: :class:`bytes`, :class:`str`, :class:`unicode` 

75 

76 """ 

77 return string 

78 

79 

80#: The :func:`xrange()` function. Alias for :func:`range()` in Python 3. 

81xrange = range if PY3 else xrange # noqa 

82 

83 

84#: (:class:`type`, :class:`tuple`) Types for file objects that have 

85#: ``fileno()``. 

86file_types = io.RawIOBase if PY3 else (io.RawIOBase, types.FileType) 

87 

88 

89def encode_filename(filename): 

90 """If ``filename`` is a :data:`text_type`, encode it to 

91 :data:`binary_type` according to filesystem's default encoding. 

92 

93 .. versionchanged:: 0.5.3 

94 Added support for PEP-519 https://github.com/emcconville/wand/pull/339 

95 """ 

96 if hasattr(filename, "__fspath__"): # PEP 519 

97 filename = filename.__fspath__() 

98 if isinstance(filename, text_type): 

99 return filename.encode(sys.getfilesystemencoding()) 

100 return filename 

101 

102 

103try: 

104 nested = contextlib.nested 

105except AttributeError: 

106 # http://hg.python.org/cpython/file/v2.7.6/Lib/contextlib.py#l88 

107 @contextlib.contextmanager 

108 def nested(*managers): 

109 exits = [] 

110 vars = [] 

111 exc = (None, None, None) 

112 try: 

113 for mgr in managers: 

114 exit = mgr.__exit__ 

115 enter = mgr.__enter__ 

116 vars.append(enter()) 

117 exits.append(exit) 

118 yield vars 

119 except: # noqa: E722 

120 exc = sys.exc_info() 

121 finally: 

122 while exits: 

123 exit = exits.pop() 

124 try: 

125 if exit(*exc): 

126 exc = (None, None, None) 

127 except: # noqa: E722 

128 exc = sys.exc_info() 

129 if exc != (None, None, None): 

130 # PEP 3109 

131 e = exc[0](exc[1]) 

132 e.__traceback__ = e[2] 

133 raise e