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