File: pycompat.rst

package info (click to toggle)
ipython 5.8.0-1%2Bdeb10u1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 9,600 kB
  • sloc: python: 34,423; makefile: 174; sh: 143
file content (233 lines) | stat: -rw-r--r-- 7,432 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
Writing code for Python 2 and 3
===============================

.. module:: IPython.utils.py3compat
   :synopsis: Python 2 & 3 compatibility helpers

.. data:: PY3

   Boolean indicating whether we're currently in Python 3.

Iterators
---------

Many built in functions and methods in Python 2 come in pairs, one
returning a list, and one returning an iterator (e.g. :func:`range` and
:func:`python:xrange`). In Python 3, there is usually only the iterator form,
but it has the name which gives a list in Python 2 (e.g. :func:`range`).

The way to write compatible code depends on what you need:

* A list, e.g. for serialisation, or to test if something is in it.
* Iteration, but it will never be used for very many items, so efficiency
  isn't especially important.
* Iteration over many items, where efficiency is important.

================  =================  =======================
list              iteration (small)  iteration(large)
================  =================  =======================
list(range(n))    range(n)           py3compat.xrange(n)
list(map(f, it))  map(f, it)         --
list(zip(a, b))   zip(a, b)          --
list(d.items())   d.items()          py3compat.iteritems(d)
list(d.values())  d.values()         py3compat.itervalues(d)
================  =================  =======================

Iterating over a dictionary yields its keys, so there is rarely a need
to use :meth:`dict.keys` or :meth:`dict.iterkeys`.

Avoid using :func:`map` to cause function side effects. This is more
clearly written with a simple for loop.

.. data:: xrange

   A reference to ``range`` on Python 3, and :func:`python:xrange` on Python 2.

.. function:: iteritems(d)
              itervalues(d)

   Iterate over (key, value) pairs of a dictionary, or just over values.
   ``iterkeys`` is not defined: iterating over the dictionary yields its keys.

Changed standard library locations
----------------------------------

Several parts of the standard library have been renamed and moved. This
is a short list of things that we're using. A couple of them have names
in :mod:`IPython.utils.py3compat`, so you don't need both
imports in each module that uses them.

==================  ============  ===========
Python 2            Python 3      py3compat
==================  ============  ===========
:func:`raw_input`   input         input
:mod:`__builtin__`  builtins      builtin_mod
:mod:`StringIO`     io
:mod:`Queue`        queue
:mod:`cPickle`      pickle
:mod:`thread`       _thread
:mod:`copy_reg`     copyreg
:mod:`urlparse`     urllib.parse
:mod:`repr`         reprlib
:mod:`Tkinter`      tkinter
:mod:`Cookie`       http.cookie
:mod:`_winreg`      winreg
==================  ============  ===========

Be careful with StringIO: :class:`io.StringIO` is available in Python 2.7,
but it behaves differently from :class:`StringIO.StringIO`, and much of
our code assumes the use of the latter on Python 2. So a try/except on
the import may cause problems.

.. function:: input

   Behaves like :func:`python:raw_input` on Python 2.

.. data:: builtin_mod
          builtin_mod_name

   A reference to the module containing builtins, and its name as a string.

Unicode
-------

Always be explicit about what is text (unicode) and what is bytes.
*Encoding* goes from unicode to bytes, and *decoding* goes from bytes
to unicode.

To open files for reading or writing text, use :func:`io.open`, which is
the Python 3 builtin ``open`` function, available on Python 2 as well.
We almost always need to specify the encoding parameter, because the
default is platform dependent.

We have several helper functions for converting between string types. They all
use the encoding from :func:`IPython.utils.encoding.getdefaultencoding` by default,
and the ``errors='replace'`` option to do best-effort conversions for the user's
system.

.. function:: unicode_to_str(u, encoding=None)
              str_to_unicode(s, encoding=None)

   Convert between unicode and the native str type. No-ops on Python 3.

.. function:: str_to_bytes(s, encoding=None)
              bytes_to_str(u, encoding=None)

   Convert between bytes and the native str type. No-ops on Python 2.

.. function:: cast_unicode(s, encoding=None)
              cast_bytes(s, encoding=None)

   Convert strings to unicode/bytes when they may be of either type.

.. function:: cast_unicode_py2(s, encoding=None)
              cast_bytes_py2(s, encoding=None)

   Convert strings to unicode/bytes when they may be of either type on Python 2,
   but return them unaltered on Python 3 (where string types are more
   predictable).

.. data:: unicode_type

   A reference to ``str`` on Python 3, and to ``unicode`` on Python 2.

.. data:: string_types

   A tuple for isinstance checks: ``(str,)`` on Python 3, ``(str, unicode)`` on
   Python 2.

Relative imports
----------------

::

    # This makes Python 2 behave like Python 3:
    from __future__ import absolute_import
    
    import io  # Imports the standard library io module
    from . import io  # Import the io module from the package
                      # containing the current module
    from .io import foo  # foo from the io module next to this module
    from IPython.utils import io  # This still works

Print function
--------------

::

    # Support the print function on Python 2:
    from __future__ import print_function
    
    print(a, b)
    print(foo, file=sys.stderr)
    print(bar, baz, sep='\t', end='')

Metaclasses
-----------

The syntax for declaring a class with a metaclass is different in
Python 2 and 3. A helper function works for most cases:

.. function:: with_metaclass

   Create a base class with a metaclass. Copied from the six library.

   Used like this::

       class FormatterABC(with_metaclass(abc.ABCMeta, object)):
           ...

Combining inheritance between Qt and the traitlets system, however, does
not work with this. Instead, we do this::

    class QtKernelClientMixin(MetaQObjectHasTraits('NewBase', (HasTraits, SuperQObject), {})): 
        ...

This gives the new class a metaclass of :class:`~IPython.qt.util.MetaQObjectHasTraits`,
and the parent classes :class:`~traitlets.HasTraits` and
:class:`~IPython.qt.util.SuperQObject`.


Doctests
--------

.. function:: doctest_refactor_print(func_or_str)

   Refactors print statements in doctests in Python 3 only. Accepts a string
   or a function, so it can be used as a decorator.

.. function:: u_format(func_or_str)

   Handle doctests written with ``{u}'abcþ'``, replacing the ``{u}`` with ``u``
   for Python 2, and removing it for Python 3.

   Accepts a string or a function, so it can be used as a decorator.

Execfile
--------

.. function:: execfile(fname, glob, loc=None)

   Equivalent to the Python 2 :func:`python:execfile` builtin. We redefine it in
   Python 2 to better handle non-ascii filenames.

Miscellaneous
-------------

.. autofunction:: safe_unicode

.. function:: isidentifier(s, dotted=False)

   Checks whether the string s is a valid identifier in this version of Python.
   In Python 3, non-ascii characters are allowed. If ``dotted`` is True, it
   allows dots (i.e. attribute access) in the string.

.. function:: getcwd()

   Return the current working directory as unicode, like :func:`os.getcwdu` on
   Python 2.

.. function:: MethodType

   Constructor for :class:`types.MethodType` that takes two arguments, like
   the real constructor on Python 3.