• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 # 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 
21 import operator
22 import sys
23 import types
24 import unittest
25 
26 import py
27 
28 import six
29 
30 
31 def 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 
39 def test_import_module():
40     from logging import handlers
41     m = six._import_module("logging.handlers")
42     assert m is handlers
43 
44 
45 def 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 
52 def 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 
58 def 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 
68 def test_text_type():
69     assert type(six.u("hi")) is six.text_type
70 
71 
72 def test_binary_type():
73     assert type(six.b("hi")) is six.binary_type
74 
75 
76 def 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 
88 def 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 
99 try:
100     import _tkinter
101 except ImportError:
102     have_tkinter = False
103 else:
104     have_tkinter = True
105 
106 have_gdbm = True
107 try:
108     import gdbm
109 except 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])
117 def 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])
143 def 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])
156 def 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])
165 def 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])
174 def 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])
183 def 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 
190 def 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 
197 def 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 
204 def 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 
210 def 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 
217 def 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 
223 def 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 
230 def test_map():
231     from six.moves import map
232     assert six.advance_iterator(map(lambda x: x + 1, range(2))) == 1
233 
234 
235 def test_getoutput():
236     from six.moves import getoutput
237     output = getoutput('echo "foo"')
238     assert output == 'foo'
239 
240 
241 def 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)")
247 def 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 
255 class 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 
327 def 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 
334 def 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 
343 def 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 
352 def 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 
362 def 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 
370 def 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 
376 def test_get_function_globals():
377     def f():
378         pass
379     assert six.get_function_globals(f) is globals()
380 
381 
382 def 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+")
421 def 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 
437 def 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 
447 def 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 
458 def 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 
474 def 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 
485 def 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 
499 if 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 
513 else:
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 
528 def test_u_escapes():
529     s = six.u("\u1234")
530     assert len(s) == 1
531 
532 
533 def test_unichr():
534     assert six.u("\u1234") == six.unichr(0x1234)
535     assert type(six.u("\u1234")) is type(six.unichr(0x1234))
536 
537 
538 def test_int2byte():
539     assert six.int2byte(3) == six.b("\x03")
540     py.test.raises(Exception, six.int2byte, 256)
541 
542 
543 def 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 
549 def test_bytesindex():
550     assert six.indexbytes(six.b("hello"), 3) == ord("l")
551 
552 
553 def 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 
560 def test_StringIO():
561     fp = six.StringIO()
562     fp.write(six.u("hello"))
563     assert fp.getvalue() == six.u("hello")
564 
565 
566 def test_BytesIO():
567     fp = six.BytesIO()
568     fp.write(six.b("hello"))
569     assert fp.getvalue() == six.b("hello")
570 
571 
572 def 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 
590 def 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 
632 def 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 
653 def 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)")
693 def 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 
710 def 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 
716 def 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)")
748 def 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 
775 def 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 
805 def 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))")
879 def 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)")
891 def 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)")
903 def 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 
916 def 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")
935