test_move.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. # -*- coding: utf-8 -*-
  2. import sys
  3. from uuid import uuid4
  4. import pytest
  5. from pandas.compat import PY3, intern
  6. from pandas.util._move import BadMove, move_into_mutable_buffer, stolenbuf
  7. def test_cannot_create_instance_of_stolen_buffer():
  8. # Stolen buffers need to be created through the smart constructor
  9. # "move_into_mutable_buffer," which has a bunch of checks in it.
  10. msg = "cannot create 'pandas.util._move.stolenbuf' instances"
  11. with pytest.raises(TypeError, match=msg):
  12. stolenbuf()
  13. def test_more_than_one_ref():
  14. # Test case for when we try to use "move_into_mutable_buffer"
  15. # when the object being moved has other references.
  16. b = b"testing"
  17. with pytest.raises(BadMove, match="testing") as e:
  18. def handle_success(type_, value, tb):
  19. assert value.args[0] is b
  20. return type(e).handle_success(e, type_, value, tb) # super
  21. e.handle_success = handle_success
  22. move_into_mutable_buffer(b)
  23. def test_exactly_one_ref():
  24. # Test case for when the object being moved has exactly one reference.
  25. b = b"testing"
  26. # We need to pass an expression on the stack to ensure that there are
  27. # not extra references hanging around. We cannot rewrite this test as
  28. # buf = b[:-3]
  29. # as_stolen_buf = move_into_mutable_buffer(buf)
  30. # because then we would have more than one reference to buf.
  31. as_stolen_buf = move_into_mutable_buffer(b[:-3])
  32. # Materialize as byte-array to show that it is mutable.
  33. assert bytearray(as_stolen_buf) == b"test"
  34. @pytest.mark.skipif(PY3, reason="bytes objects cannot be interned in PY3")
  35. def test_interned():
  36. salt = uuid4().hex
  37. def make_string():
  38. # We need to actually create a new string so that it has refcount
  39. # one. We use a uuid so that we know the string could not already
  40. # be in the intern table.
  41. return "".join(("testing: ", salt))
  42. # This should work, the string has one reference on the stack.
  43. move_into_mutable_buffer(make_string())
  44. refcount = [None] # nonlocal
  45. def ref_capture(ob):
  46. # Subtract two because those are the references owned by this frame:
  47. # 1. The local variables of this stack frame.
  48. # 2. The python data stack of this stack frame.
  49. refcount[0] = sys.getrefcount(ob) - 2
  50. return ob
  51. with pytest.raises(BadMove, match="testing"):
  52. # If we intern the string, it will still have one reference. Now,
  53. # it is in the intern table, so if other people intern the same
  54. # string while the mutable buffer holds the first string they will
  55. # be the same instance.
  56. move_into_mutable_buffer(ref_capture(intern(make_string()))) # noqa
  57. assert refcount[0] == 1