|
2 | 2 | import nose
|
3 | 3 |
|
4 | 4 | from collections import OrderedDict
|
| 5 | +import sys |
| 6 | +import unittest |
| 7 | +from uuid import uuid4 |
5 | 8 | from pandas.util._move import move_into_mutable_buffer, BadMove
|
6 | 9 | from pandas.util.decorators import deprecate_kwarg
|
7 | 10 | from pandas.util.validators import (validate_args, validate_kwargs,
|
@@ -325,6 +328,46 @@ def test_exactly_one_ref(self):
|
325 | 328 | # materialize as bytearray to show that it is mutable
|
326 | 329 | self.assertEqual(bytearray(as_stolen_buf), b'test')
|
327 | 330 |
|
| 331 | + @unittest.skipIf( |
| 332 | + sys.version_info[0] > 2, |
| 333 | + 'bytes objects cannot be interned in py3', |
| 334 | + ) |
| 335 | + def test_interned(self): |
| 336 | + salt = uuid4().hex |
| 337 | + |
| 338 | + def make_string(): |
| 339 | + # We need to actually create a new string so that it has refcount |
| 340 | + # one. We use a uuid so that we know the string could not already |
| 341 | + # be in the intern table. |
| 342 | + return ''.join(('testing: ', salt)) |
| 343 | + |
| 344 | + # This should work, the string has one reference on the stack. |
| 345 | + move_into_mutable_buffer(make_string()) |
| 346 | + |
| 347 | + refcount = [None] # nonlocal |
| 348 | + |
| 349 | + def ref_capture(ob): |
| 350 | + # Subtract two because those are the references owned by this |
| 351 | + # frame: |
| 352 | + # 1. The local variables of this stack frame. |
| 353 | + # 2. The python data stack of this stack frame. |
| 354 | + refcount[0] = sys.getrefcount(ob) - 2 |
| 355 | + return ob |
| 356 | + |
| 357 | + with tm.assertRaises(BadMove): |
| 358 | + # If we intern the string it will still have one reference but now |
| 359 | + # it is in the intern table so if other people intern the same |
| 360 | + # string while the mutable buffer holds the first string they will |
| 361 | + # be the same instance. |
| 362 | + move_into_mutable_buffer(ref_capture(intern(make_string()))) # noqa |
| 363 | + |
| 364 | + self.assertEqual( |
| 365 | + refcount[0], |
| 366 | + 1, |
| 367 | + msg='The BadMove was probably raised for refcount reasons instead' |
| 368 | + ' of interning reasons', |
| 369 | + ) |
| 370 | + |
328 | 371 |
|
329 | 372 | def test_numpy_errstate_is_default():
|
330 | 373 | # The defaults since numpy 1.6.0
|
|
0 commit comments