##// END OF EJS Templates
move @annotate to py3compat
MinRK -
Show More
@@ -1,12 +1,12 b''
1 from .widget import Widget, DOMWidget, CallbackDispatcher
1 from .widget import Widget, DOMWidget, CallbackDispatcher
2
2
3 from .widget_bool import CheckboxWidget, ToggleButtonWidget
3 from .widget_bool import CheckboxWidget, ToggleButtonWidget
4 from .widget_button import ButtonWidget
4 from .widget_button import ButtonWidget
5 from .widget_container import ContainerWidget, PopupWidget
5 from .widget_container import ContainerWidget, PopupWidget
6 from .widget_float import FloatTextWidget, BoundedFloatTextWidget, FloatSliderWidget, FloatProgressWidget
6 from .widget_float import FloatTextWidget, BoundedFloatTextWidget, FloatSliderWidget, FloatProgressWidget
7 from .widget_image import ImageWidget
7 from .widget_image import ImageWidget
8 from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, IntProgressWidget
8 from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, IntProgressWidget
9 from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget
9 from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget
10 from .widget_selectioncontainer import TabWidget, AccordionWidget
10 from .widget_selectioncontainer import TabWidget, AccordionWidget
11 from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget
11 from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget
12 from .interaction import interact, interactive, annotate, const
12 from .interaction import interact, interactive, const
@@ -1,262 +1,248 b''
1 """Interact with functions using widgets."""
1 """Interact with functions using widgets."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
4 # Copyright (c) 2013, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from __future__ import print_function
15 from __future__ import print_function
16
16
17 try: # Python >= 3.3
17 try: # Python >= 3.3
18 from inspect import signature, Parameter
18 from inspect import signature, Parameter
19 except ImportError:
19 except ImportError:
20 from IPython.utils.signatures import signature, Parameter
20 from IPython.utils.signatures import signature, Parameter
21 from inspect import getcallargs
21 from inspect import getcallargs
22
22
23 from IPython.html.widgets import (Widget, TextWidget,
23 from IPython.html.widgets import (Widget, TextWidget,
24 FloatSliderWidget, IntSliderWidget, CheckboxWidget, DropdownWidget,
24 FloatSliderWidget, IntSliderWidget, CheckboxWidget, DropdownWidget,
25 ContainerWidget, DOMWidget)
25 ContainerWidget, DOMWidget)
26 from IPython.display import display, clear_output
26 from IPython.display import display, clear_output
27 from IPython.utils.py3compat import string_types, unicode_type
27 from IPython.utils.py3compat import string_types, unicode_type
28 from IPython.utils.traitlets import HasTraits, Any, Unicode
28 from IPython.utils.traitlets import HasTraits, Any, Unicode
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # Classes and Functions
31 # Classes and Functions
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34
34
35 def _matches(o, pattern):
35 def _matches(o, pattern):
36 """Match a pattern of types in a sequence."""
36 """Match a pattern of types in a sequence."""
37 if not len(o) == len(pattern):
37 if not len(o) == len(pattern):
38 return False
38 return False
39 comps = zip(o,pattern)
39 comps = zip(o,pattern)
40 return all(isinstance(obj,kind) for obj,kind in comps)
40 return all(isinstance(obj,kind) for obj,kind in comps)
41
41
42
42
43 def _get_min_max_value(min, max, value):
43 def _get_min_max_value(min, max, value):
44 """Return min, max, value given input values with possible None."""
44 """Return min, max, value given input values with possible None."""
45 if value is None:
45 if value is None:
46 if not max > min:
46 if not max > min:
47 raise ValueError('max must be greater than min: (min={0}, max={1})'.format(min, max))
47 raise ValueError('max must be greater than min: (min={0}, max={1})'.format(min, max))
48 value = min + abs(min-max)/2
48 value = min + abs(min-max)/2
49 value = type(min)(value)
49 value = type(min)(value)
50 elif min is None and max is None:
50 elif min is None and max is None:
51 if value == 0.0:
51 if value == 0.0:
52 min, max, value = 0.0, 1.0, 0.5
52 min, max, value = 0.0, 1.0, 0.5
53 elif value == 0:
53 elif value == 0:
54 min, max, value = 0, 1, 0
54 min, max, value = 0, 1, 0
55 elif isinstance(value, float):
55 elif isinstance(value, float):
56 min, max = (-value, 3.0*value) if value > 0 else (3.0*value, -value)
56 min, max = (-value, 3.0*value) if value > 0 else (3.0*value, -value)
57 elif isinstance(value, int):
57 elif isinstance(value, int):
58 min, max = (-value, 3*value) if value > 0 else (3*value, -value)
58 min, max = (-value, 3*value) if value > 0 else (3*value, -value)
59 else:
59 else:
60 raise TypeError('expected a number, got: %r' % value)
60 raise TypeError('expected a number, got: %r' % value)
61 else:
61 else:
62 raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value))
62 raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value))
63 return min, max, value
63 return min, max, value
64
64
65 def _widget_abbrev_single_value(o):
65 def _widget_abbrev_single_value(o):
66 """Make widgets from single values, which can be used written as parameter defaults."""
66 """Make widgets from single values, which can be used written as parameter defaults."""
67 if isinstance(o, string_types):
67 if isinstance(o, string_types):
68 return TextWidget(value=unicode_type(o))
68 return TextWidget(value=unicode_type(o))
69 elif isinstance(o, dict):
69 elif isinstance(o, dict):
70 # get a single value in a Python 2+3 way:
70 # get a single value in a Python 2+3 way:
71 value = next(iter(o.values()))
71 value = next(iter(o.values()))
72 return DropdownWidget(value=value, values=o)
72 return DropdownWidget(value=value, values=o)
73 elif isinstance(o, bool):
73 elif isinstance(o, bool):
74 return CheckboxWidget(value=o)
74 return CheckboxWidget(value=o)
75 elif isinstance(o, float):
75 elif isinstance(o, float):
76 min, max, value = _get_min_max_value(None, None, o)
76 min, max, value = _get_min_max_value(None, None, o)
77 return FloatSliderWidget(value=o, min=min, max=max)
77 return FloatSliderWidget(value=o, min=min, max=max)
78 elif isinstance(o, int):
78 elif isinstance(o, int):
79 min, max, value = _get_min_max_value(None, None, o)
79 min, max, value = _get_min_max_value(None, None, o)
80 return IntSliderWidget(value=o, min=min, max=max)
80 return IntSliderWidget(value=o, min=min, max=max)
81 else:
81 else:
82 return None
82 return None
83
83
84 def _widget_abbrev(o):
84 def _widget_abbrev(o):
85 """Make widgets from abbreviations: single values, lists or tuples."""
85 """Make widgets from abbreviations: single values, lists or tuples."""
86 if isinstance(o, (list, tuple)):
86 if isinstance(o, (list, tuple)):
87 if _matches(o, (int, int)):
87 if _matches(o, (int, int)):
88 min, max, value = _get_min_max_value(o[0], o[1], None)
88 min, max, value = _get_min_max_value(o[0], o[1], None)
89 return IntSliderWidget(value=value, min=min, max=max)
89 return IntSliderWidget(value=value, min=min, max=max)
90 elif _matches(o, (int, int, int)):
90 elif _matches(o, (int, int, int)):
91 min, max, value = _get_min_max_value(o[0], o[1], None)
91 min, max, value = _get_min_max_value(o[0], o[1], None)
92 return IntSliderWidget(value=value, min=min, max=max, step=o[2])
92 return IntSliderWidget(value=value, min=min, max=max, step=o[2])
93 elif _matches(o, (float, float)):
93 elif _matches(o, (float, float)):
94 min, max, value = _get_min_max_value(o[0], o[1], None)
94 min, max, value = _get_min_max_value(o[0], o[1], None)
95 return FloatSliderWidget(value=value, min=min, max=max)
95 return FloatSliderWidget(value=value, min=min, max=max)
96 elif _matches(o, (float, float, float)):
96 elif _matches(o, (float, float, float)):
97 min, max, value = _get_min_max_value(o[0], o[1], None)
97 min, max, value = _get_min_max_value(o[0], o[1], None)
98 return FloatSliderWidget(value=value, min=min, max=max, step=o[2])
98 return FloatSliderWidget(value=value, min=min, max=max, step=o[2])
99 elif _matches(o, (float, float, int)):
99 elif _matches(o, (float, float, int)):
100 min, max, value = _get_min_max_value(o[0], o[1], None)
100 min, max, value = _get_min_max_value(o[0], o[1], None)
101 return FloatSliderWidget(value=value, min=min, max=max, step=float(o[2]))
101 return FloatSliderWidget(value=value, min=min, max=max, step=float(o[2]))
102 elif all(isinstance(x, string_types) for x in o):
102 elif all(isinstance(x, string_types) for x in o):
103 return DropdownWidget(value=unicode_type(o[0]),
103 return DropdownWidget(value=unicode_type(o[0]),
104 values=[unicode_type(k) for k in o])
104 values=[unicode_type(k) for k in o])
105 else:
105 else:
106 return _widget_abbrev_single_value(o)
106 return _widget_abbrev_single_value(o)
107
107
108 def _widget_from_abbrev(abbrev):
108 def _widget_from_abbrev(abbrev):
109 """Build a Widget intstance given an abbreviation or Widget."""
109 """Build a Widget intstance given an abbreviation or Widget."""
110 if isinstance(abbrev, Widget) or isinstance(abbrev, const):
110 if isinstance(abbrev, Widget) or isinstance(abbrev, const):
111 return abbrev
111 return abbrev
112
112
113 widget = _widget_abbrev(abbrev)
113 widget = _widget_abbrev(abbrev)
114 if widget is None:
114 if widget is None:
115 raise ValueError("%r cannot be transformed to a Widget" % abbrev)
115 raise ValueError("%r cannot be transformed to a Widget" % abbrev)
116 return widget
116 return widget
117
117
118 def _yield_abbreviations_for_parameter(param, kwargs):
118 def _yield_abbreviations_for_parameter(param, kwargs):
119 """Get an abbreviation for a function parameter."""
119 """Get an abbreviation for a function parameter."""
120 name = param.name
120 name = param.name
121 kind = param.kind
121 kind = param.kind
122 ann = param.annotation
122 ann = param.annotation
123 default = param.default
123 default = param.default
124 empty = Parameter.empty
124 empty = Parameter.empty
125 not_found = (None, None)
125 not_found = (None, None)
126 if kind == Parameter.POSITIONAL_OR_KEYWORD:
126 if kind == Parameter.POSITIONAL_OR_KEYWORD:
127 if name in kwargs:
127 if name in kwargs:
128 yield name, kwargs.pop(name)
128 yield name, kwargs.pop(name)
129 elif ann is not empty:
129 elif ann is not empty:
130 if default is empty:
130 if default is empty:
131 yield name, ann
131 yield name, ann
132 else:
132 else:
133 yield name, ann
133 yield name, ann
134 elif default is not empty:
134 elif default is not empty:
135 yield name, default
135 yield name, default
136 else:
136 else:
137 yield not_found
137 yield not_found
138 elif kind == Parameter.KEYWORD_ONLY:
138 elif kind == Parameter.KEYWORD_ONLY:
139 if name in kwargs:
139 if name in kwargs:
140 yield name, kwargs.pop(name)
140 yield name, kwargs.pop(name)
141 elif ann is not empty:
141 elif ann is not empty:
142 yield name, ann
142 yield name, ann
143 elif default is not empty:
143 elif default is not empty:
144 yield name, default
144 yield name, default
145 else:
145 else:
146 yield not_found
146 yield not_found
147 elif kind == Parameter.VAR_KEYWORD:
147 elif kind == Parameter.VAR_KEYWORD:
148 # In this case name=kwargs and we yield the items in kwargs with their keys.
148 # In this case name=kwargs and we yield the items in kwargs with their keys.
149 for k, v in kwargs.copy().items():
149 for k, v in kwargs.copy().items():
150 kwargs.pop(k)
150 kwargs.pop(k)
151 yield k, v
151 yield k, v
152
152
153 def _find_abbreviations(f, kwargs):
153 def _find_abbreviations(f, kwargs):
154 """Find the abbreviations for a function and kwargs passed to interact."""
154 """Find the abbreviations for a function and kwargs passed to interact."""
155 new_kwargs = []
155 new_kwargs = []
156 for param in signature(f).parameters.values():
156 for param in signature(f).parameters.values():
157 for name, value in _yield_abbreviations_for_parameter(param, kwargs):
157 for name, value in _yield_abbreviations_for_parameter(param, kwargs):
158 if value is None:
158 if value is None:
159 raise ValueError('cannot find widget or abbreviation for argument: {!r}'.format(name))
159 raise ValueError('cannot find widget or abbreviation for argument: {!r}'.format(name))
160 new_kwargs.append((name, value))
160 new_kwargs.append((name, value))
161 return new_kwargs
161 return new_kwargs
162
162
163 def _widgets_from_abbreviations(seq):
163 def _widgets_from_abbreviations(seq):
164 """Given a sequence of (name, abbrev) tuples, return a sequence of Widgets."""
164 """Given a sequence of (name, abbrev) tuples, return a sequence of Widgets."""
165 result = []
165 result = []
166 for name, abbrev in seq:
166 for name, abbrev in seq:
167 widget = _widget_from_abbrev(abbrev)
167 widget = _widget_from_abbrev(abbrev)
168 widget.description = name
168 widget.description = name
169 result.append(widget)
169 result.append(widget)
170 return result
170 return result
171
171
172 def interactive(__interact_f, **kwargs):
172 def interactive(__interact_f, **kwargs):
173 """Build a group of widgets to interact with a function."""
173 """Build a group of widgets to interact with a function."""
174 f = __interact_f
174 f = __interact_f
175 co = kwargs.pop('clear_output', True)
175 co = kwargs.pop('clear_output', True)
176 kwargs_widgets = []
176 kwargs_widgets = []
177 container = ContainerWidget()
177 container = ContainerWidget()
178 container.result = None
178 container.result = None
179 container.args = []
179 container.args = []
180 container.kwargs = dict()
180 container.kwargs = dict()
181 kwargs = kwargs.copy()
181 kwargs = kwargs.copy()
182
182
183 new_kwargs = _find_abbreviations(f, kwargs)
183 new_kwargs = _find_abbreviations(f, kwargs)
184 # Before we proceed, let's make sure that the user has passed a set of args+kwargs
184 # Before we proceed, let's make sure that the user has passed a set of args+kwargs
185 # that will lead to a valid call of the function. This protects against unspecified
185 # that will lead to a valid call of the function. This protects against unspecified
186 # and doubly-specified arguments.
186 # and doubly-specified arguments.
187 getcallargs(f, **{n:v for n,v in new_kwargs})
187 getcallargs(f, **{n:v for n,v in new_kwargs})
188 # Now build the widgets from the abbreviations.
188 # Now build the widgets from the abbreviations.
189 kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs))
189 kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs))
190 kwargs_widgets.extend(_widgets_from_abbreviations(sorted(kwargs.items(), key = lambda x: x[0])))
190 kwargs_widgets.extend(_widgets_from_abbreviations(sorted(kwargs.items(), key = lambda x: x[0])))
191
191
192 # This has to be done as an assignment, not using container.children.append,
192 # This has to be done as an assignment, not using container.children.append,
193 # so that traitlets notices the update. We skip any objects (such as const) that
193 # so that traitlets notices the update. We skip any objects (such as const) that
194 # are not DOMWidgets.
194 # are not DOMWidgets.
195 c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)]
195 c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)]
196 container.children = c
196 container.children = c
197
197
198 # Build the callback
198 # Build the callback
199 def call_f(name, old, new):
199 def call_f(name, old, new):
200 container.args = []
200 container.args = []
201 for widget in kwargs_widgets:
201 for widget in kwargs_widgets:
202 value = widget.value
202 value = widget.value
203 container.kwargs[widget.description] = value
203 container.kwargs[widget.description] = value
204 if co:
204 if co:
205 clear_output(wait=True)
205 clear_output(wait=True)
206 container.result = f(*container.args, **container.kwargs)
206 container.result = f(*container.args, **container.kwargs)
207
207
208 # Wire up the widgets
208 # Wire up the widgets
209 for widget in kwargs_widgets:
209 for widget in kwargs_widgets:
210 widget.on_trait_change(call_f, 'value')
210 widget.on_trait_change(call_f, 'value')
211
211
212 container.on_displayed(lambda _: call_f(None, None, None))
212 container.on_displayed(lambda _: call_f(None, None, None))
213
213
214 return container
214 return container
215
215
216 def interact(__interact_f=None, **kwargs):
216 def interact(__interact_f=None, **kwargs):
217 """interact(f, **kwargs)
217 """interact(f, **kwargs)
218
218
219 Interact with a function using widgets."""
219 Interact with a function using widgets."""
220 # positional arg support in: https://gist.github.com/8851331
220 # positional arg support in: https://gist.github.com/8851331
221 if __interact_f is not None:
221 if __interact_f is not None:
222 # This branch handles the cases:
222 # This branch handles the cases:
223 # 1. interact(f, **kwargs)
223 # 1. interact(f, **kwargs)
224 # 2. @interact
224 # 2. @interact
225 # def f(*args, **kwargs):
225 # def f(*args, **kwargs):
226 # ...
226 # ...
227 f = __interact_f
227 f = __interact_f
228 w = interactive(f, **kwargs)
228 w = interactive(f, **kwargs)
229 f.widget = w
229 f.widget = w
230 display(w)
230 display(w)
231 else:
231 else:
232 # This branch handles the case:
232 # This branch handles the case:
233 # @interact(a=30, b=40)
233 # @interact(a=30, b=40)
234 # def f(*args, **kwargs):
234 # def f(*args, **kwargs):
235 # ...
235 # ...
236 def dec(f):
236 def dec(f):
237 w = interactive(f, **kwargs)
237 w = interactive(f, **kwargs)
238 f.widget = w
238 f.widget = w
239 display(w)
239 display(w)
240 return f
240 return f
241 return dec
241 return dec
242
242
243 class const(HasTraits):
243 class const(HasTraits):
244 """A pseudo-widget whose value is constant and never client synced."""
244 """A pseudo-widget whose value is constant and never client synced."""
245 value = Any(help="Any Python object")
245 value = Any(help="Any Python object")
246 description = Unicode('', help="Any Python object")
246 description = Unicode('', help="Any Python object")
247 def __init__(self, value, **kwargs):
247 def __init__(self, value, **kwargs):
248 super(const, self).__init__(value=value, **kwargs)
248 super(const, self).__init__(value=value, **kwargs)
249
250 def annotate(**kwargs):
251 """Python 3 compatible function annotation for Python 2."""
252 if not kwargs:
253 raise ValueError('annotations must be provided as keyword arguments')
254 def dec(f):
255 if hasattr(f, '__annotations__'):
256 for k, v in kwargs.items():
257 f.__annotations__[k] = v
258 else:
259 f.__annotations__ = kwargs
260 return f
261 return dec
262
@@ -1,249 +1,264 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Compatibility tricks for Python 3. Mainly to do with unicode."""
2 """Compatibility tricks for Python 3. Mainly to do with unicode."""
3 import functools
3 import functools
4 import os
4 import os
5 import sys
5 import sys
6 import re
6 import re
7 import types
7 import types
8
8
9 from .encoding import DEFAULT_ENCODING
9 from .encoding import DEFAULT_ENCODING
10
10
11 orig_open = open
11 orig_open = open
12
12
13 def no_code(x, encoding=None):
13 def no_code(x, encoding=None):
14 return x
14 return x
15
15
16 def decode(s, encoding=None):
16 def decode(s, encoding=None):
17 encoding = encoding or DEFAULT_ENCODING
17 encoding = encoding or DEFAULT_ENCODING
18 return s.decode(encoding, "replace")
18 return s.decode(encoding, "replace")
19
19
20 def encode(u, encoding=None):
20 def encode(u, encoding=None):
21 encoding = encoding or DEFAULT_ENCODING
21 encoding = encoding or DEFAULT_ENCODING
22 return u.encode(encoding, "replace")
22 return u.encode(encoding, "replace")
23
23
24
24
25 def cast_unicode(s, encoding=None):
25 def cast_unicode(s, encoding=None):
26 if isinstance(s, bytes):
26 if isinstance(s, bytes):
27 return decode(s, encoding)
27 return decode(s, encoding)
28 return s
28 return s
29
29
30 def cast_bytes(s, encoding=None):
30 def cast_bytes(s, encoding=None):
31 if not isinstance(s, bytes):
31 if not isinstance(s, bytes):
32 return encode(s, encoding)
32 return encode(s, encoding)
33 return s
33 return s
34
34
35 def _modify_str_or_docstring(str_change_func):
35 def _modify_str_or_docstring(str_change_func):
36 @functools.wraps(str_change_func)
36 @functools.wraps(str_change_func)
37 def wrapper(func_or_str):
37 def wrapper(func_or_str):
38 if isinstance(func_or_str, string_types):
38 if isinstance(func_or_str, string_types):
39 func = None
39 func = None
40 doc = func_or_str
40 doc = func_or_str
41 else:
41 else:
42 func = func_or_str
42 func = func_or_str
43 doc = func.__doc__
43 doc = func.__doc__
44
44
45 doc = str_change_func(doc)
45 doc = str_change_func(doc)
46
46
47 if func:
47 if func:
48 func.__doc__ = doc
48 func.__doc__ = doc
49 return func
49 return func
50 return doc
50 return doc
51 return wrapper
51 return wrapper
52
52
53 def safe_unicode(e):
53 def safe_unicode(e):
54 """unicode(e) with various fallbacks. Used for exceptions, which may not be
54 """unicode(e) with various fallbacks. Used for exceptions, which may not be
55 safe to call unicode() on.
55 safe to call unicode() on.
56 """
56 """
57 try:
57 try:
58 return unicode_type(e)
58 return unicode_type(e)
59 except UnicodeError:
59 except UnicodeError:
60 pass
60 pass
61
61
62 try:
62 try:
63 return str_to_unicode(str(e))
63 return str_to_unicode(str(e))
64 except UnicodeError:
64 except UnicodeError:
65 pass
65 pass
66
66
67 try:
67 try:
68 return str_to_unicode(repr(e))
68 return str_to_unicode(repr(e))
69 except UnicodeError:
69 except UnicodeError:
70 pass
70 pass
71
71
72 return u'Unrecoverably corrupt evalue'
72 return u'Unrecoverably corrupt evalue'
73
73
74 if sys.version_info[0] >= 3:
74 if sys.version_info[0] >= 3:
75 PY3 = True
75 PY3 = True
76
76
77 # keep reference to builtin_mod because the kernel overrides that value
77 # keep reference to builtin_mod because the kernel overrides that value
78 # to forward requests to a frontend.
78 # to forward requests to a frontend.
79 def input(prompt=''):
79 def input(prompt=''):
80 return builtin_mod.input(prompt)
80 return builtin_mod.input(prompt)
81
81
82 builtin_mod_name = "builtins"
82 builtin_mod_name = "builtins"
83 import builtins as builtin_mod
83 import builtins as builtin_mod
84
84
85 str_to_unicode = no_code
85 str_to_unicode = no_code
86 unicode_to_str = no_code
86 unicode_to_str = no_code
87 str_to_bytes = encode
87 str_to_bytes = encode
88 bytes_to_str = decode
88 bytes_to_str = decode
89 cast_bytes_py2 = no_code
89 cast_bytes_py2 = no_code
90 cast_unicode_py2 = no_code
90 cast_unicode_py2 = no_code
91
91
92 string_types = (str,)
92 string_types = (str,)
93 unicode_type = str
93 unicode_type = str
94
94
95 def isidentifier(s, dotted=False):
95 def isidentifier(s, dotted=False):
96 if dotted:
96 if dotted:
97 return all(isidentifier(a) for a in s.split("."))
97 return all(isidentifier(a) for a in s.split("."))
98 return s.isidentifier()
98 return s.isidentifier()
99
99
100 open = orig_open
100 open = orig_open
101 xrange = range
101 xrange = range
102 def iteritems(d): return iter(d.items())
102 def iteritems(d): return iter(d.items())
103 def itervalues(d): return iter(d.values())
103 def itervalues(d): return iter(d.values())
104 getcwd = os.getcwd
104 getcwd = os.getcwd
105
105
106 MethodType = types.MethodType
106 MethodType = types.MethodType
107
107
108 def execfile(fname, glob, loc=None):
108 def execfile(fname, glob, loc=None):
109 loc = loc if (loc is not None) else glob
109 loc = loc if (loc is not None) else glob
110 with open(fname, 'rb') as f:
110 with open(fname, 'rb') as f:
111 exec(compile(f.read(), fname, 'exec'), glob, loc)
111 exec(compile(f.read(), fname, 'exec'), glob, loc)
112
112
113 # Refactor print statements in doctests.
113 # Refactor print statements in doctests.
114 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
114 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
115 def _print_statement_sub(match):
115 def _print_statement_sub(match):
116 expr = match.groups('expr')
116 expr = match.groups('expr')
117 return "print(%s)" % expr
117 return "print(%s)" % expr
118
118
119 @_modify_str_or_docstring
119 @_modify_str_or_docstring
120 def doctest_refactor_print(doc):
120 def doctest_refactor_print(doc):
121 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
121 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
122 unfortunately doesn't pick up on our doctests.
122 unfortunately doesn't pick up on our doctests.
123
123
124 Can accept a string or a function, so it can be used as a decorator."""
124 Can accept a string or a function, so it can be used as a decorator."""
125 return _print_statement_re.sub(_print_statement_sub, doc)
125 return _print_statement_re.sub(_print_statement_sub, doc)
126
126
127 # Abstract u'abc' syntax:
127 # Abstract u'abc' syntax:
128 @_modify_str_or_docstring
128 @_modify_str_or_docstring
129 def u_format(s):
129 def u_format(s):
130 """"{u}'abc'" --> "'abc'" (Python 3)
130 """"{u}'abc'" --> "'abc'" (Python 3)
131
131
132 Accepts a string or a function, so it can be used as a decorator."""
132 Accepts a string or a function, so it can be used as a decorator."""
133 return s.format(u='')
133 return s.format(u='')
134
134
135 else:
135 else:
136 PY3 = False
136 PY3 = False
137
137
138 # keep reference to builtin_mod because the kernel overrides that value
138 # keep reference to builtin_mod because the kernel overrides that value
139 # to forward requests to a frontend.
139 # to forward requests to a frontend.
140 def input(prompt=''):
140 def input(prompt=''):
141 return builtin_mod.raw_input(prompt)
141 return builtin_mod.raw_input(prompt)
142
142
143 builtin_mod_name = "__builtin__"
143 builtin_mod_name = "__builtin__"
144 import __builtin__ as builtin_mod
144 import __builtin__ as builtin_mod
145
145
146 str_to_unicode = decode
146 str_to_unicode = decode
147 unicode_to_str = encode
147 unicode_to_str = encode
148 str_to_bytes = no_code
148 str_to_bytes = no_code
149 bytes_to_str = no_code
149 bytes_to_str = no_code
150 cast_bytes_py2 = cast_bytes
150 cast_bytes_py2 = cast_bytes
151 cast_unicode_py2 = cast_unicode
151 cast_unicode_py2 = cast_unicode
152
152
153 string_types = (str, unicode)
153 string_types = (str, unicode)
154 unicode_type = unicode
154 unicode_type = unicode
155
155
156 import re
156 import re
157 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
157 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
158 def isidentifier(s, dotted=False):
158 def isidentifier(s, dotted=False):
159 if dotted:
159 if dotted:
160 return all(isidentifier(a) for a in s.split("."))
160 return all(isidentifier(a) for a in s.split("."))
161 return bool(_name_re.match(s))
161 return bool(_name_re.match(s))
162
162
163 class open(object):
163 class open(object):
164 """Wrapper providing key part of Python 3 open() interface."""
164 """Wrapper providing key part of Python 3 open() interface."""
165 def __init__(self, fname, mode="r", encoding="utf-8"):
165 def __init__(self, fname, mode="r", encoding="utf-8"):
166 self.f = orig_open(fname, mode)
166 self.f = orig_open(fname, mode)
167 self.enc = encoding
167 self.enc = encoding
168
168
169 def write(self, s):
169 def write(self, s):
170 return self.f.write(s.encode(self.enc))
170 return self.f.write(s.encode(self.enc))
171
171
172 def read(self, size=-1):
172 def read(self, size=-1):
173 return self.f.read(size).decode(self.enc)
173 return self.f.read(size).decode(self.enc)
174
174
175 def close(self):
175 def close(self):
176 return self.f.close()
176 return self.f.close()
177
177
178 def __enter__(self):
178 def __enter__(self):
179 return self
179 return self
180
180
181 def __exit__(self, etype, value, traceback):
181 def __exit__(self, etype, value, traceback):
182 self.f.close()
182 self.f.close()
183
183
184 xrange = xrange
184 xrange = xrange
185 def iteritems(d): return d.iteritems()
185 def iteritems(d): return d.iteritems()
186 def itervalues(d): return d.itervalues()
186 def itervalues(d): return d.itervalues()
187 getcwd = os.getcwdu
187 getcwd = os.getcwdu
188
188
189 def MethodType(func, instance):
189 def MethodType(func, instance):
190 return types.MethodType(func, instance, type(instance))
190 return types.MethodType(func, instance, type(instance))
191
191
192 def doctest_refactor_print(func_or_str):
192 def doctest_refactor_print(func_or_str):
193 return func_or_str
193 return func_or_str
194
194
195
195
196 # Abstract u'abc' syntax:
196 # Abstract u'abc' syntax:
197 @_modify_str_or_docstring
197 @_modify_str_or_docstring
198 def u_format(s):
198 def u_format(s):
199 """"{u}'abc'" --> "u'abc'" (Python 2)
199 """"{u}'abc'" --> "u'abc'" (Python 2)
200
200
201 Accepts a string or a function, so it can be used as a decorator."""
201 Accepts a string or a function, so it can be used as a decorator."""
202 return s.format(u='u')
202 return s.format(u='u')
203
203
204 if sys.platform == 'win32':
204 if sys.platform == 'win32':
205 def execfile(fname, glob=None, loc=None):
205 def execfile(fname, glob=None, loc=None):
206 loc = loc if (loc is not None) else glob
206 loc = loc if (loc is not None) else glob
207 # The rstrip() is necessary b/c trailing whitespace in files will
207 # The rstrip() is necessary b/c trailing whitespace in files will
208 # cause an IndentationError in Python 2.6 (this was fixed in 2.7,
208 # cause an IndentationError in Python 2.6 (this was fixed in 2.7,
209 # but we still support 2.6). See issue 1027.
209 # but we still support 2.6). See issue 1027.
210 scripttext = builtin_mod.open(fname).read().rstrip() + '\n'
210 scripttext = builtin_mod.open(fname).read().rstrip() + '\n'
211 # compile converts unicode filename to str assuming
211 # compile converts unicode filename to str assuming
212 # ascii. Let's do the conversion before calling compile
212 # ascii. Let's do the conversion before calling compile
213 if isinstance(fname, unicode):
213 if isinstance(fname, unicode):
214 filename = unicode_to_str(fname)
214 filename = unicode_to_str(fname)
215 else:
215 else:
216 filename = fname
216 filename = fname
217 exec(compile(scripttext, filename, 'exec'), glob, loc)
217 exec(compile(scripttext, filename, 'exec'), glob, loc)
218 else:
218 else:
219 def execfile(fname, *where):
219 def execfile(fname, *where):
220 if isinstance(fname, unicode):
220 if isinstance(fname, unicode):
221 filename = fname.encode(sys.getfilesystemencoding())
221 filename = fname.encode(sys.getfilesystemencoding())
222 else:
222 else:
223 filename = fname
223 filename = fname
224 builtin_mod.execfile(filename, *where)
224 builtin_mod.execfile(filename, *where)
225
225
226
227 def annotate(**kwargs):
228 """Python 3 compatible function annotation for Python 2."""
229 if not kwargs:
230 raise ValueError('annotations must be provided as keyword arguments')
231 def dec(f):
232 if hasattr(f, '__annotations__'):
233 for k, v in kwargs.items():
234 f.__annotations__[k] = v
235 else:
236 f.__annotations__ = kwargs
237 return f
238 return dec
239
240
226 # Parts below taken from six:
241 # Parts below taken from six:
227 # Copyright (c) 2010-2013 Benjamin Peterson
242 # Copyright (c) 2010-2013 Benjamin Peterson
228 #
243 #
229 # Permission is hereby granted, free of charge, to any person obtaining a copy
244 # Permission is hereby granted, free of charge, to any person obtaining a copy
230 # of this software and associated documentation files (the "Software"), to deal
245 # of this software and associated documentation files (the "Software"), to deal
231 # in the Software without restriction, including without limitation the rights
246 # in the Software without restriction, including without limitation the rights
232 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
247 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
233 # copies of the Software, and to permit persons to whom the Software is
248 # copies of the Software, and to permit persons to whom the Software is
234 # furnished to do so, subject to the following conditions:
249 # furnished to do so, subject to the following conditions:
235 #
250 #
236 # The above copyright notice and this permission notice shall be included in all
251 # The above copyright notice and this permission notice shall be included in all
237 # copies or substantial portions of the Software.
252 # copies or substantial portions of the Software.
238 #
253 #
239 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
254 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
240 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
255 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
241 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
256 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
242 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
257 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
243 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
258 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
244 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
259 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
245 # SOFTWARE.
260 # SOFTWARE.
246
261
247 def with_metaclass(meta, *bases):
262 def with_metaclass(meta, *bases):
248 """Create a base class with a metaclass."""
263 """Create a base class with a metaclass."""
249 return meta("_NewBase", bases, {})
264 return meta("_NewBase", bases, {})
General Comments 0
You need to be logged in to leave comments. Login now