Skip to content

Commit ba3e8e2

Browse files
author
Jordan Adler
committed
Merge in pending v0.16.x changes
2 parents 0d12a9f + 581e3ce commit ba3e8e2

File tree

6 files changed

+188
-12
lines changed

6 files changed

+188
-12
lines changed

docs/compatible_idioms.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ Iterable dict values:
512512
.. code:: python
513513
514514
# Python 2 and 3: option 2
515-
from builtins import itervalues
515+
from future.utils import itervalues
516516
# or
517517
from six import itervalues
518518

docs/notebooks/Writing Python 2-3 compatible code.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1129,7 +1129,7 @@
11291129
"outputs": [],
11301130
"source": [
11311131
"# Python 2 and 3: option 2\n",
1132-
"from builtins import itervalues\n",
1132+
"from future.utils import itervalues\n",
11331133
"# or\n",
11341134
"from six import itervalues\n",
11351135
"\n",

docs/whatsnew.rst

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@ What's New
55

66
.. _whats-new-0.16.x:
77

8-
What's new in version 0.16.0 (2016-09-22)
8+
What's new in version 0.16.1 (unreleased)
9+
=========================================
10+
11+
This is a minor bug-fix release:
12+
13+
- Fix `from collections import ChainMap` after install_aliases() (issue #226)
14+
15+
16+
What's new in version 0.16.0 (2016-10-27)
917
==========================================
1018

1119
This release removes the ``configparser`` package as an alias for
@@ -26,18 +34,18 @@ effect on your system.
2634
This releases also fixes these bugs:
2735

2836
- Fix ``newbytes`` constructor bug. (Issue #163)
29-
- Fix semantics of `bool()` with `newobject`. (Issue #211)
30-
- Fix `standard_library.install_aliases()` on PyPy. (Issue #205)
31-
- Fix assertRaises for `pow` and `compile` on Python 3.5. (Issue #183)
32-
- Fix return argument of `future.utils.ensure_new_type` if conversion to
37+
- Fix semantics of ``bool()`` with ``newobject``. (Issue #211)
38+
- Fix ``standard_library.install_aliases()`` on PyPy. (Issue #205)
39+
- Fix assertRaises for ``pow`` and ``compile``` on Python 3.5. (Issue #183)
40+
- Fix return argument of ``future.utils.ensure_new_type`` if conversion to
3341
new type does not exist. (Issue #185)
34-
- Add missing `cmp_to_key` for Py2.6. (Issue #189)
35-
- Allow the `old_div` fixer to be disabled. (Issue #190)
42+
- Add missing ``cmp_to_key`` for Py2.6. (Issue #189)
43+
- Allow the ``old_div`` fixer to be disabled. (Issue #190)
3644
- Improve compatibility with Google App Engine. (Issue #231)
37-
- Add some missing imports to the `tkinter` and `tkinter.filedialog`
45+
- Add some missing imports to the ``tkinter`` and ``tkinter.filedialog``
3846
package namespaces. (Issues #212 and #233)
39-
- Fix ``raise_from`` on PY3 when the exception cannot be recreated from
40-
its repr. (Issues #213 and #235, fix provided by Varriount)
47+
- More complete implementation of ``raise_from`` on PY3. (Issues #141,
48+
#213 and #235, fix provided by Varriount)
4149

4250

4351
What's new in version 0.15.2 (2015-09-11)

src/future/standard_library/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@
180180
MOVES = [('collections', 'UserList', 'UserList', 'UserList'),
181181
('collections', 'UserDict', 'UserDict', 'UserDict'),
182182
('collections', 'UserString','UserString', 'UserString'),
183+
('collections', 'ChainMap', 'future.backports.misc', 'ChainMap'),
183184
('itertools', 'filterfalse','itertools', 'ifilterfalse'),
184185
('itertools', 'zip_longest','itertools', 'izip_longest'),
185186
('sys', 'intern','__builtin__', 'intern'),

tests/test_future/test_chainmap.py

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
"""
2+
Tests for the future.standard_library module
3+
"""
4+
5+
from __future__ import absolute_import, print_function
6+
from future import standard_library
7+
from future import utils
8+
from future.tests.base import unittest, CodeHandler, expectedFailurePY2
9+
10+
import sys
11+
import tempfile
12+
import os
13+
import copy
14+
import textwrap
15+
from subprocess import CalledProcessError
16+
17+
18+
class TestChainMap(CodeHandler):
19+
20+
def setUp(self):
21+
self.interpreter = sys.executable
22+
standard_library.install_aliases()
23+
super(TestChainMap, self).setUp()
24+
25+
def tearDown(self):
26+
# standard_library.remove_hooks()
27+
pass
28+
29+
@staticmethod
30+
def simple_cm():
31+
from collections import ChainMap
32+
c = ChainMap()
33+
c['one'] = 1
34+
c['two'] = 2
35+
36+
cc = c.new_child()
37+
cc['one'] = 'one'
38+
39+
return c, cc
40+
41+
42+
def test_repr(self):
43+
c, cc = TestChainMap.simple_cm()
44+
45+
order1 = "ChainMap({'one': 'one'}, {'one': 1, 'two': 2})"
46+
order2 = "ChainMap({'one': 'one'}, {'two': 2, 'one': 1})"
47+
assert repr(cc) in [order1, order2]
48+
49+
50+
def test_recursive_repr(self):
51+
"""
52+
Test for degnerative recursive cases. Very unlikely in
53+
ChainMaps. But all must bow before the god of testing coverage.
54+
"""
55+
from collections import ChainMap
56+
c = ChainMap()
57+
c['one'] = c
58+
assert repr(c) == "ChainMap({'one': ...})"
59+
60+
61+
def test_get(self):
62+
c, cc = TestChainMap.simple_cm()
63+
64+
assert cc.get('two') == 2
65+
assert cc.get('three') == None
66+
assert cc.get('three', 'notthree') == 'notthree'
67+
68+
69+
def test_bool(self):
70+
from collections import ChainMap
71+
c = ChainMap()
72+
assert not(bool(c))
73+
74+
c['one'] = 1
75+
c['two'] = 2
76+
assert bool(c)
77+
78+
cc = c.new_child()
79+
cc['one'] = 'one'
80+
assert cc
81+
82+
83+
def test_fromkeys(self):
84+
from collections import ChainMap
85+
keys = 'a b c'.split()
86+
c = ChainMap.fromkeys(keys)
87+
assert len(c) == 3
88+
assert c['a'] == None
89+
assert c['b'] == None
90+
assert c['c'] == None
91+
92+
93+
def test_copy(self):
94+
c, cc = TestChainMap.simple_cm()
95+
new_cc = cc.copy()
96+
assert new_cc is not cc
97+
assert sorted(new_cc.items()) == sorted(cc.items())
98+
99+
100+
def test_parents(self):
101+
c, cc = TestChainMap.simple_cm()
102+
103+
new_c = cc.parents
104+
assert c is not new_c
105+
assert len(new_c) == 2
106+
assert new_c['one'] == c['one']
107+
assert new_c['two'] == c['two']
108+
109+
110+
def test_delitem(self):
111+
c, cc = TestChainMap.simple_cm()
112+
113+
with self.assertRaises(KeyError):
114+
del cc['two']
115+
116+
del cc['one']
117+
assert len(cc) == 2
118+
assert cc['one'] == 1
119+
assert cc['two'] == 2
120+
121+
122+
def test_popitem(self):
123+
c, cc = TestChainMap.simple_cm()
124+
125+
assert cc.popitem() == ('one', 'one')
126+
127+
with self.assertRaises(KeyError):
128+
cc.popitem()
129+
130+
131+
def test_pop(self):
132+
c, cc = TestChainMap.simple_cm()
133+
134+
assert cc.pop('one') == 'one'
135+
136+
with self.assertRaises(KeyError):
137+
cc.pop('two')
138+
139+
assert len(cc) == 2
140+
141+
142+
def test_clear(self):
143+
c, cc = TestChainMap.simple_cm()
144+
145+
cc.clear()
146+
assert len(cc) == 2
147+
assert cc['one'] == 1
148+
assert cc['two'] == 2
149+
150+
151+
def test_missing(self):
152+
153+
c, cc = TestChainMap.simple_cm()
154+
155+
with self.assertRaises(KeyError):
156+
cc['clown']
157+
158+
159+
if __name__ == '__main__':
160+
unittest.main()

tests/test_future/test_standard_library.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,13 @@ def test_itertools_zip_longest(self):
247247
self.assertEqual(list(zip_longest(a, b)),
248248
[(1, 2), (2, 4), (None, 6)])
249249

250+
def test_ChainMap(self):
251+
"""
252+
Tests whether collections.ChainMap is available.
253+
"""
254+
from collections import ChainMap
255+
cm = ChainMap()
256+
250257
@unittest.expectedFailure
251258
@unittest.skipIf(utils.PY3, 'generic import tests are for Py2 only')
252259
def test_import_failure_from_module(self):

0 commit comments

Comments
 (0)