blob: 43e7426dea1241bbd371d2f24f63f510427a519f [file] [log] [blame]
Keun Soo Yim3b10a5a2017-12-22 19:03:44 -08001# Copyright (c) 2010-2017 Benjamin Peterson
2#
3# Permission is hereby granted, free of charge, to any person obtaining a copy
4# of this software and associated documentation files (the "Software"), to deal
5# in the Software without restriction, including without limitation the rights
6# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7# copies of the Software, and to permit persons to whom the Software is
8# furnished to do so, subject to the following conditions:
9#
10# The above copyright notice and this permission notice shall be included in all
11# copies or substantial portions of the Software.
12#
13# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19# SOFTWARE.
20
21import operator
22import sys
23import types
24import unittest
25
26import py
27
28import six
29
30
31def test_add_doc():
32 def f():
33 """Icky doc"""
34 pass
35 six._add_doc(f, """New doc""")
36 assert f.__doc__ == "New doc"
37
38
39def test_import_module():
40 from logging import handlers
41 m = six._import_module("logging.handlers")
42 assert m is handlers
43
44
45def test_integer_types():
46 assert isinstance(1, six.integer_types)
47 assert isinstance(-1, six.integer_types)
48 assert isinstance(six.MAXSIZE + 23, six.integer_types)
49 assert not isinstance(.1, six.integer_types)
50
51
52def test_string_types():
53 assert isinstance("hi", six.string_types)
54 assert isinstance(six.u("hi"), six.string_types)
55 assert issubclass(six.text_type, six.string_types)
56
57
58def test_class_types():
59 class X:
60 pass
61 class Y(object):
62 pass
63 assert isinstance(X, six.class_types)
64 assert isinstance(Y, six.class_types)
65 assert not isinstance(X(), six.class_types)
66
67
68def test_text_type():
69 assert type(six.u("hi")) is six.text_type
70
71
72def test_binary_type():
73 assert type(six.b("hi")) is six.binary_type
74
75
76def test_MAXSIZE():
77 try:
78 # This shouldn't raise an overflow error.
79 six.MAXSIZE.__index__()
80 except AttributeError:
81 # Before Python 2.6.
82 pass
83 py.test.raises(
84 (ValueError, OverflowError),
85 operator.mul, [None], six.MAXSIZE + 1)
86
87
88def test_lazy():
89 if six.PY3:
90 html_name = "html.parser"
91 else:
92 html_name = "HTMLParser"
93 assert html_name not in sys.modules
94 mod = six.moves.html_parser
95 assert sys.modules[html_name] is mod
96 assert "htmlparser" not in six._MovedItems.__dict__
97
98
99try:
100 import _tkinter
101except ImportError:
102 have_tkinter = False
103else:
104 have_tkinter = True
105
106have_gdbm = True
107try:
108 import gdbm
109except ImportError:
110 try:
111 import dbm.gnu
112 except ImportError:
113 have_gdbm = False
114
115@py.test.mark.parametrize("item_name",
116 [item.name for item in six._moved_attributes])
117def test_move_items(item_name):
118 """Ensure that everything loads correctly."""
119 try:
120 item = getattr(six.moves, item_name)
121 if isinstance(item, types.ModuleType):
122 __import__("six.moves." + item_name)
123 except AttributeError:
124 if item_name == "zip_longest" and sys.version_info < (2, 6):
125 py.test.skip("zip_longest only available on 2.6+")
126 except ImportError:
127 if item_name == "winreg" and not sys.platform.startswith("win"):
128 py.test.skip("Windows only module")
129 if item_name.startswith("tkinter"):
130 if not have_tkinter:
131 py.test.skip("requires tkinter")
132 if item_name == "tkinter_ttk" and sys.version_info[:2] <= (2, 6):
133 py.test.skip("ttk only available on 2.7+")
134 if item_name.startswith("dbm_gnu") and not have_gdbm:
135 py.test.skip("requires gdbm")
136 raise
137 if sys.version_info[:2] >= (2, 6):
138 assert item_name in dir(six.moves)
139
140
141@py.test.mark.parametrize("item_name",
142 [item.name for item in six._urllib_parse_moved_attributes])
143def test_move_items_urllib_parse(item_name):
144 """Ensure that everything loads correctly."""
145 if item_name == "ParseResult" and sys.version_info < (2, 5):
146 py.test.skip("ParseResult is only found on 2.5+")
147 if item_name in ("parse_qs", "parse_qsl") and sys.version_info < (2, 6):
148 py.test.skip("parse_qs[l] is new in 2.6")
149 if sys.version_info[:2] >= (2, 6):
150 assert item_name in dir(six.moves.urllib.parse)
151 getattr(six.moves.urllib.parse, item_name)
152
153
154@py.test.mark.parametrize("item_name",
155 [item.name for item in six._urllib_error_moved_attributes])
156def test_move_items_urllib_error(item_name):
157 """Ensure that everything loads correctly."""
158 if sys.version_info[:2] >= (2, 6):
159 assert item_name in dir(six.moves.urllib.error)
160 getattr(six.moves.urllib.error, item_name)
161
162
163@py.test.mark.parametrize("item_name",
164 [item.name for item in six._urllib_request_moved_attributes])
165def test_move_items_urllib_request(item_name):
166 """Ensure that everything loads correctly."""
167 if sys.version_info[:2] >= (2, 6):
168 assert item_name in dir(six.moves.urllib.request)
169 getattr(six.moves.urllib.request, item_name)
170
171
172@py.test.mark.parametrize("item_name",
173 [item.name for item in six._urllib_response_moved_attributes])
174def test_move_items_urllib_response(item_name):
175 """Ensure that everything loads correctly."""
176 if sys.version_info[:2] >= (2, 6):
177 assert item_name in dir(six.moves.urllib.response)
178 getattr(six.moves.urllib.response, item_name)
179
180
181@py.test.mark.parametrize("item_name",
182 [item.name for item in six._urllib_robotparser_moved_attributes])
183def test_move_items_urllib_robotparser(item_name):
184 """Ensure that everything loads correctly."""
185 if sys.version_info[:2] >= (2, 6):
186 assert item_name in dir(six.moves.urllib.robotparser)
187 getattr(six.moves.urllib.robotparser, item_name)
188
189
190def test_import_moves_error_1():
191 from six.moves.urllib.parse import urljoin
192 from six import moves
193 # In 1.4.1: AttributeError: 'Module_six_moves_urllib_parse' object has no attribute 'urljoin'
194 assert moves.urllib.parse.urljoin
195
196
197def test_import_moves_error_2():
198 from six import moves
199 assert moves.urllib.parse.urljoin
200 # In 1.4.1: ImportError: cannot import name urljoin
201 from six.moves.urllib.parse import urljoin
202
203
204def test_import_moves_error_3():
205 from six.moves.urllib.parse import urljoin
206 # In 1.4.1: ImportError: cannot import name urljoin
207 from six.moves.urllib_parse import urljoin
208
209
210def test_from_imports():
211 from six.moves.queue import Queue
212 assert isinstance(Queue, six.class_types)
213 from six.moves.configparser import ConfigParser
214 assert isinstance(ConfigParser, six.class_types)
215
216
217def test_filter():
218 from six.moves import filter
219 f = filter(lambda x: x % 2, range(10))
220 assert six.advance_iterator(f) == 1
221
222
223def test_filter_false():
224 from six.moves import filterfalse
225 f = filterfalse(lambda x: x % 3, range(10))
226 assert six.advance_iterator(f) == 0
227 assert six.advance_iterator(f) == 3
228 assert six.advance_iterator(f) == 6
229
230def test_map():
231 from six.moves import map
232 assert six.advance_iterator(map(lambda x: x + 1, range(2))) == 1
233
234
235def test_getoutput():
236 from six.moves import getoutput
237 output = getoutput('echo "foo"')
238 assert output == 'foo'
239
240
241def test_zip():
242 from six.moves import zip
243 assert six.advance_iterator(zip(range(2), range(2))) == (0, 0)
244
245
246@py.test.mark.skipif("sys.version_info < (2, 6)")
247def test_zip_longest():
248 from six.moves import zip_longest
249 it = zip_longest(range(2), range(1))
250
251 assert six.advance_iterator(it) == (0, 0)
252 assert six.advance_iterator(it) == (1, None)
253
254
255class TestCustomizedMoves:
256
257 def teardown_method(self, meth):
258 try:
259 del six._MovedItems.spam
260 except AttributeError:
261 pass
262 try:
263 del six.moves.__dict__["spam"]
264 except KeyError:
265 pass
266
267
268 def test_moved_attribute(self):
269 attr = six.MovedAttribute("spam", "foo", "bar")
270 if six.PY3:
271 assert attr.mod == "bar"
272 else:
273 assert attr.mod == "foo"
274 assert attr.attr == "spam"
275 attr = six.MovedAttribute("spam", "foo", "bar", "lemma")
276 assert attr.attr == "lemma"
277 attr = six.MovedAttribute("spam", "foo", "bar", "lemma", "theorm")
278 if six.PY3:
279 assert attr.attr == "theorm"
280 else:
281 assert attr.attr == "lemma"
282
283
284 def test_moved_module(self):
285 attr = six.MovedModule("spam", "foo")
286 if six.PY3:
287 assert attr.mod == "spam"
288 else:
289 assert attr.mod == "foo"
290 attr = six.MovedModule("spam", "foo", "bar")
291 if six.PY3:
292 assert attr.mod == "bar"
293 else:
294 assert attr.mod == "foo"
295
296
297 def test_custom_move_module(self):
298 attr = six.MovedModule("spam", "six", "six")
299 six.add_move(attr)
300 six.remove_move("spam")
301 assert not hasattr(six.moves, "spam")
302 attr = six.MovedModule("spam", "six", "six")
303 six.add_move(attr)
304 from six.moves import spam
305 assert spam is six
306 six.remove_move("spam")
307 assert not hasattr(six.moves, "spam")
308
309
310 def test_custom_move_attribute(self):
311 attr = six.MovedAttribute("spam", "six", "six", "u", "u")
312 six.add_move(attr)
313 six.remove_move("spam")
314 assert not hasattr(six.moves, "spam")
315 attr = six.MovedAttribute("spam", "six", "six", "u", "u")
316 six.add_move(attr)
317 from six.moves import spam
318 assert spam is six.u
319 six.remove_move("spam")
320 assert not hasattr(six.moves, "spam")
321
322
323 def test_empty_remove(self):
324 py.test.raises(AttributeError, six.remove_move, "eggs")
325
326
327def test_get_unbound_function():
328 class X(object):
329 def m(self):
330 pass
331 assert six.get_unbound_function(X.m) is X.__dict__["m"]
332
333
334def test_get_method_self():
335 class X(object):
336 def m(self):
337 pass
338 x = X()
339 assert six.get_method_self(x.m) is x
340 py.test.raises(AttributeError, six.get_method_self, 42)
341
342
343def test_get_method_function():
344 class X(object):
345 def m(self):
346 pass
347 x = X()
348 assert six.get_method_function(x.m) is X.__dict__["m"]
349 py.test.raises(AttributeError, six.get_method_function, hasattr)
350
351
352def test_get_function_closure():
353 def f():
354 x = 42
355 def g():
356 return x
357 return g
358 cell = six.get_function_closure(f())[0]
359 assert type(cell).__name__ == "cell"
360
361
362def test_get_function_code():
363 def f():
364 pass
365 assert isinstance(six.get_function_code(f), types.CodeType)
366 if not hasattr(sys, "pypy_version_info"):
367 py.test.raises(AttributeError, six.get_function_code, hasattr)
368
369
370def test_get_function_defaults():
371 def f(x, y=3, b=4):
372 pass
373 assert six.get_function_defaults(f) == (3, 4)
374
375
376def test_get_function_globals():
377 def f():
378 pass
379 assert six.get_function_globals(f) is globals()
380
381
382def test_dictionary_iterators(monkeypatch):
383 def stock_method_name(iterwhat):
384 """Given a method suffix like "lists" or "values", return the name
385 of the dict method that delivers those on the version of Python
386 we're running in."""
387 if six.PY3:
388 return iterwhat
389 return 'iter' + iterwhat
390
391 class MyDict(dict):
392 if not six.PY3:
393 def lists(self, **kw):
394 return [1, 2, 3]
395 def iterlists(self, **kw):
396 return iter([1, 2, 3])
397 f = MyDict.iterlists
398 del MyDict.iterlists
399 setattr(MyDict, stock_method_name('lists'), f)
400
401 d = MyDict(zip(range(10), reversed(range(10))))
402 for name in "keys", "values", "items", "lists":
403 meth = getattr(six, "iter" + name)
404 it = meth(d)
405 assert not isinstance(it, list)
406 assert list(it) == list(getattr(d, name)())
407 py.test.raises(StopIteration, six.advance_iterator, it)
408 record = []
409 def with_kw(*args, **kw):
410 record.append(kw["kw"])
411 return old(*args)
412 old = getattr(MyDict, stock_method_name(name))
413 monkeypatch.setattr(MyDict, stock_method_name(name), with_kw)
414 meth(d, kw=42)
415 assert record == [42]
416 monkeypatch.undo()
417
418
419@py.test.mark.skipif("sys.version_info[:2] < (2, 7)",
420 reason="view methods on dictionaries only available on 2.7+")
421def test_dictionary_views():
422 def stock_method_name(viewwhat):
423 """Given a method suffix like "keys" or "values", return the name
424 of the dict method that delivers those on the version of Python
425 we're running in."""
426 if six.PY3:
427 return viewwhat
428 return 'view' + viewwhat
429
430 d = dict(zip(range(10), (range(11, 20))))
431 for name in "keys", "values", "items":
432 meth = getattr(six, "view" + name)
433 view = meth(d)
434 assert set(view) == set(getattr(d, name)())
435
436
437def test_advance_iterator():
438 assert six.next is six.advance_iterator
439 l = [1, 2]
440 it = iter(l)
441 assert six.next(it) == 1
442 assert six.next(it) == 2
443 py.test.raises(StopIteration, six.next, it)
444 py.test.raises(StopIteration, six.next, it)
445
446
447def test_iterator():
448 class myiter(six.Iterator):
449 def __next__(self):
450 return 13
451 assert six.advance_iterator(myiter()) == 13
452 class myitersub(myiter):
453 def __next__(self):
454 return 14
455 assert six.advance_iterator(myitersub()) == 14
456
457
458def test_callable():
459 class X:
460 def __call__(self):
461 pass
462 def method(self):
463 pass
464 assert six.callable(X)
465 assert six.callable(X())
466 assert six.callable(test_callable)
467 assert six.callable(hasattr)
468 assert six.callable(X.method)
469 assert six.callable(X().method)
470 assert not six.callable(4)
471 assert not six.callable("string")
472
473
474def test_create_bound_method():
475 class X(object):
476 pass
477 def f(self):
478 return self
479 x = X()
480 b = six.create_bound_method(f, x)
481 assert isinstance(b, types.MethodType)
482 assert b() is x
483
484
485def test_create_unbound_method():
486 class X(object):
487 pass
488
489 def f(self):
490 return self
491 u = six.create_unbound_method(f, X)
492 py.test.raises(TypeError, u)
493 if six.PY2:
494 assert isinstance(u, types.MethodType)
495 x = X()
496 assert f(x) is x
497
498
499if six.PY3:
500
501 def test_b():
502 data = six.b("\xff")
503 assert isinstance(data, bytes)
504 assert len(data) == 1
505 assert data == bytes([255])
506
507
508 def test_u():
509 s = six.u("hi \u0439 \U00000439 \\ \\\\ \n")
510 assert isinstance(s, str)
511 assert s == "hi \u0439 \U00000439 \\ \\\\ \n"
512
513else:
514
515 def test_b():
516 data = six.b("\xff")
517 assert isinstance(data, str)
518 assert len(data) == 1
519 assert data == "\xff"
520
521
522 def test_u():
523 s = six.u("hi \u0439 \U00000439 \\ \\\\ \n")
524 assert isinstance(s, unicode)
525 assert s == "hi \xd0\xb9 \xd0\xb9 \\ \\\\ \n".decode("utf8")
526
527
528def test_u_escapes():
529 s = six.u("\u1234")
530 assert len(s) == 1
531
532
533def test_unichr():
534 assert six.u("\u1234") == six.unichr(0x1234)
535 assert type(six.u("\u1234")) is type(six.unichr(0x1234))
536
537
538def test_int2byte():
539 assert six.int2byte(3) == six.b("\x03")
540 py.test.raises(Exception, six.int2byte, 256)
541
542
543def test_byte2int():
544 assert six.byte2int(six.b("\x03")) == 3
545 assert six.byte2int(six.b("\x03\x04")) == 3
546 py.test.raises(IndexError, six.byte2int, six.b(""))
547
548
549def test_bytesindex():
550 assert six.indexbytes(six.b("hello"), 3) == ord("l")
551
552
553def test_bytesiter():
554 it = six.iterbytes(six.b("hi"))
555 assert six.next(it) == ord("h")
556 assert six.next(it) == ord("i")
557 py.test.raises(StopIteration, six.next, it)
558
559
560def test_StringIO():
561 fp = six.StringIO()
562 fp.write(six.u("hello"))
563 assert fp.getvalue() == six.u("hello")
564
565
566def test_BytesIO():
567 fp = six.BytesIO()
568 fp.write(six.b("hello"))
569 assert fp.getvalue() == six.b("hello")
570
571
572def test_exec_():
573 def f():
574 l = []
575 six.exec_("l.append(1)")
576 assert l == [1]
577 f()
578 ns = {}
579 six.exec_("x = 42", ns)
580 assert ns["x"] == 42
581 glob = {}
582 loc = {}
583 six.exec_("global y; y = 42; x = 12", glob, loc)
584 assert glob["y"] == 42
585 assert "x" not in glob
586 assert loc["x"] == 12
587 assert "y" not in loc
588
589
590def test_reraise():
591 def get_next(tb):
592 if six.PY3:
593 return tb.tb_next.tb_next
594 else:
595 return tb.tb_next
596 e = Exception("blah")
597 try:
598 raise e
599 except Exception:
600 tp, val, tb = sys.exc_info()
601 try:
602 six.reraise(tp, val, tb)
603 except Exception:
604 tp2, value2, tb2 = sys.exc_info()
605 assert tp2 is Exception
606 assert value2 is e
607 assert tb is get_next(tb2)
608 try:
609 six.reraise(tp, val)
610 except Exception:
611 tp2, value2, tb2 = sys.exc_info()
612 assert tp2 is Exception
613 assert value2 is e
614 assert tb2 is not tb
615 try:
616 six.reraise(tp, val, tb2)
617 except Exception:
618 tp2, value2, tb3 = sys.exc_info()
619 assert tp2 is Exception
620 assert value2 is e
621 assert get_next(tb3) is tb2
622 try:
623 six.reraise(tp, None, tb)
624 except Exception:
625 tp2, value2, tb2 = sys.exc_info()
626 assert tp2 is Exception
627 assert value2 is not val
628 assert isinstance(value2, Exception)
629 assert tb is get_next(tb2)
630
631
632def test_raise_from():
633 try:
634 try:
635 raise Exception("blah")
636 except Exception:
637 ctx = sys.exc_info()[1]
638 f = Exception("foo")
639 six.raise_from(f, None)
640 except Exception:
641 tp, val, tb = sys.exc_info()
642 if sys.version_info[:2] > (3, 0):
643 # We should have done a raise f from None equivalent.
644 assert val.__cause__ is None
645 assert val.__context__ is ctx
646 if sys.version_info[:2] >= (3, 3):
647 # And that should suppress the context on the exception.
648 assert val.__suppress_context__
649 # For all versions the outer exception should have raised successfully.
650 assert str(val) == "foo"
651
652
653def test_print_():
654 save = sys.stdout
655 out = sys.stdout = six.moves.StringIO()
656 try:
657 six.print_("Hello,", "person!")
658 finally:
659 sys.stdout = save
660 assert out.getvalue() == "Hello, person!\n"
661 out = six.StringIO()
662 six.print_("Hello,", "person!", file=out)
663 assert out.getvalue() == "Hello, person!\n"
664 out = six.StringIO()
665 six.print_("Hello,", "person!", file=out, end="")
666 assert out.getvalue() == "Hello, person!"
667 out = six.StringIO()
668 six.print_("Hello,", "person!", file=out, sep="X")
669 assert out.getvalue() == "Hello,Xperson!\n"
670 out = six.StringIO()
671 six.print_(six.u("Hello,"), six.u("person!"), file=out)
672 result = out.getvalue()
673 assert isinstance(result, six.text_type)
674 assert result == six.u("Hello, person!\n")
675 six.print_("Hello", file=None) # This works.
676 out = six.StringIO()
677 six.print_(None, file=out)
678 assert out.getvalue() == "None\n"
679 class FlushableStringIO(six.StringIO):
680 def __init__(self):
681 six.StringIO.__init__(self)
682 self.flushed = False
683 def flush(self):
684 self.flushed = True
685 out = FlushableStringIO()
686 six.print_("Hello", file=out)
687 assert not out.flushed
688 six.print_("Hello", file=out, flush=True)
689 assert out.flushed
690
691
692@py.test.mark.skipif("sys.version_info[:2] >= (2, 6)")
693def test_print_encoding(monkeypatch):
694 # Fool the type checking in print_.
695 monkeypatch.setattr(six, "file", six.BytesIO, raising=False)
696 out = six.BytesIO()
697 out.encoding = "utf-8"
698 out.errors = None
699 six.print_(six.u("\u053c"), end="", file=out)
700 assert out.getvalue() == six.b("\xd4\xbc")
701 out = six.BytesIO()
702 out.encoding = "ascii"
703 out.errors = "strict"
704 py.test.raises(UnicodeEncodeError, six.print_, six.u("\u053c"), file=out)
705 out.errors = "backslashreplace"
706 six.print_(six.u("\u053c"), end="", file=out)
707 assert out.getvalue() == six.b("\\u053c")
708
709
710def test_print_exceptions():
711 py.test.raises(TypeError, six.print_, x=3)
712 py.test.raises(TypeError, six.print_, end=3)
713 py.test.raises(TypeError, six.print_, sep=42)
714
715
716def test_with_metaclass():
717 class Meta(type):
718 pass
719 class X(six.with_metaclass(Meta)):
720 pass
721 assert type(X) is Meta
722 assert issubclass(X, object)
723 class Base(object):
724 pass
725 class X(six.with_metaclass(Meta, Base)):
726 pass
727 assert type(X) is Meta
728 assert issubclass(X, Base)
729 class Base2(object):
730 pass
731 class X(six.with_metaclass(Meta, Base, Base2)):
732 pass
733 assert type(X) is Meta
734 assert issubclass(X, Base)
735 assert issubclass(X, Base2)
736 assert X.__mro__ == (X, Base, Base2, object)
737 class X(six.with_metaclass(Meta)):
738 pass
739 class MetaSub(Meta):
740 pass
741 class Y(six.with_metaclass(MetaSub, X)):
742 pass
743 assert type(Y) is MetaSub
744 assert Y.__mro__ == (Y, X, object)
745
746
747@py.test.mark.skipif("sys.version_info[:2] < (3, 0)")
748def test_with_metaclass_prepare():
749 """Test that with_metaclass causes Meta.__prepare__ to be called with the correct arguments."""
750
751 class MyDict(dict):
752 pass
753
754 class Meta(type):
755
756 @classmethod
757 def __prepare__(cls, name, bases):
758 namespace = MyDict(super().__prepare__(name, bases), cls=cls, bases=bases)
759 namespace['namespace'] = namespace
760 return namespace
761
762 class Base(object):
763 pass
764
765 bases = (Base,)
766
767 class X(six.with_metaclass(Meta, *bases)):
768 pass
769
770 assert getattr(X, 'cls', type) is Meta
771 assert getattr(X, 'bases', ()) == bases
772 assert isinstance(getattr(X, 'namespace', {}), MyDict)
773
774
775def test_wraps():
776 def f(g):
777 @six.wraps(g)
778 def w():
779 return 42
780 return w
781 def k():
782 pass
783 original_k = k
784 k = f(f(k))
785 assert hasattr(k, '__wrapped__')
786 k = k.__wrapped__
787 assert hasattr(k, '__wrapped__')
788 k = k.__wrapped__
789 assert k is original_k
790 assert not hasattr(k, '__wrapped__')
791
792 def f(g, assign, update):
793 def w():
794 return 42
795 w.glue = {"foo" : "bar"}
796 return six.wraps(g, assign, update)(w)
797 k.glue = {"melon" : "egg"}
798 k.turnip = 43
799 k = f(k, ["turnip"], ["glue"])
800 assert k.__name__ == "w"
801 assert k.turnip == 43
802 assert k.glue == {"melon" : "egg", "foo" : "bar"}
803
804
805def test_add_metaclass():
806 class Meta(type):
807 pass
808 class X:
809 "success"
810 X = six.add_metaclass(Meta)(X)
811 assert type(X) is Meta
812 assert issubclass(X, object)
813 assert X.__module__ == __name__
814 assert X.__doc__ == "success"
815 class Base(object):
816 pass
817 class X(Base):
818 pass
819 X = six.add_metaclass(Meta)(X)
820 assert type(X) is Meta
821 assert issubclass(X, Base)
822 class Base2(object):
823 pass
824 class X(Base, Base2):
825 pass
826 X = six.add_metaclass(Meta)(X)
827 assert type(X) is Meta
828 assert issubclass(X, Base)
829 assert issubclass(X, Base2)
830
831 # Test a second-generation subclass of a type.
832 class Meta1(type):
833 m1 = "m1"
834 class Meta2(Meta1):
835 m2 = "m2"
836 class Base:
837 b = "b"
838 Base = six.add_metaclass(Meta1)(Base)
839 class X(Base):
840 x = "x"
841 X = six.add_metaclass(Meta2)(X)
842 assert type(X) is Meta2
843 assert issubclass(X, Base)
844 assert type(Base) is Meta1
845 assert "__dict__" not in vars(X)
846 instance = X()
847 instance.attr = "test"
848 assert vars(instance) == {"attr": "test"}
849 assert instance.b == Base.b
850 assert instance.x == X.x
851
852 # Test a class with slots.
853 class MySlots(object):
854 __slots__ = ["a", "b"]
855 MySlots = six.add_metaclass(Meta1)(MySlots)
856
857 assert MySlots.__slots__ == ["a", "b"]
858 instance = MySlots()
859 instance.a = "foo"
860 py.test.raises(AttributeError, setattr, instance, "c", "baz")
861
862 # Test a class with string for slots.
863 class MyStringSlots(object):
864 __slots__ = "ab"
865 MyStringSlots = six.add_metaclass(Meta1)(MyStringSlots)
866 assert MyStringSlots.__slots__ == "ab"
867 instance = MyStringSlots()
868 instance.ab = "foo"
869 py.test.raises(AttributeError, setattr, instance, "a", "baz")
870 py.test.raises(AttributeError, setattr, instance, "b", "baz")
871
872 class MySlotsWeakref(object):
873 __slots__ = "__weakref__",
874 MySlotsWeakref = six.add_metaclass(Meta)(MySlotsWeakref)
875 assert type(MySlotsWeakref) is Meta
876
877
878@py.test.mark.skipif("sys.version_info[:2] < (2, 7) or sys.version_info[:2] in ((3, 0), (3, 1))")
879def test_assertCountEqual():
880 class TestAssertCountEqual(unittest.TestCase):
881 def test(self):
882 with self.assertRaises(AssertionError):
883 six.assertCountEqual(self, (1, 2), [3, 4, 5])
884
885 six.assertCountEqual(self, (1, 2), [2, 1])
886
887 TestAssertCountEqual('test').test()
888
889
890@py.test.mark.skipif("sys.version_info[:2] < (2, 7)")
891def test_assertRegex():
892 class TestAssertRegex(unittest.TestCase):
893 def test(self):
894 with self.assertRaises(AssertionError):
895 six.assertRegex(self, 'test', r'^a')
896
897 six.assertRegex(self, 'test', r'^t')
898
899 TestAssertRegex('test').test()
900
901
902@py.test.mark.skipif("sys.version_info[:2] < (2, 7)")
903def test_assertRaisesRegex():
904 class TestAssertRaisesRegex(unittest.TestCase):
905 def test(self):
906 with six.assertRaisesRegex(self, AssertionError, '^Foo'):
907 raise AssertionError('Foo')
908
909 with self.assertRaises(AssertionError):
910 with six.assertRaisesRegex(self, AssertionError, r'^Foo'):
911 raise AssertionError('Bar')
912
913 TestAssertRaisesRegex('test').test()
914
915
916def test_python_2_unicode_compatible():
917 @six.python_2_unicode_compatible
918 class MyTest(object):
919 def __str__(self):
920 return six.u('hello')
921
922 def __bytes__(self):
923 return six.b('hello')
924
925 my_test = MyTest()
926
927 if six.PY2:
928 assert str(my_test) == six.b("hello")
929 assert unicode(my_test) == six.u("hello")
930 elif six.PY3:
931 assert bytes(my_test) == six.b("hello")
932 assert str(my_test) == six.u("hello")
933
934 assert getattr(six.moves.builtins, 'bytes', str)(my_test) == six.b("hello")