Skip to content

Commit fa3d84b

Browse files
committed
Merge pull request scrapy#1420 from scrapy/py3-trackrefs
PY3: port scrapy.utils.trackref
2 parents 666ebfa + 8738521 commit fa3d84b

File tree

2 files changed

+93
-10
lines changed

2 files changed

+93
-10
lines changed

scrapy/utils/trackref.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,17 @@
1010
"""
1111

1212
from __future__ import print_function
13-
import weakref, os, six
14-
from collections import defaultdict
13+
import weakref
1514
from time import time
1615
from operator import itemgetter
16+
from collections import defaultdict
17+
import six
1718

18-
NoneType = type(None)
1919

20+
NoneType = type(None)
2021
live_refs = defaultdict(weakref.WeakKeyDictionary)
2122

23+
2224
class object_ref(object):
2325
"""Inherit from this class (instead of object) to a keep a record of live
2426
instances"""
@@ -30,29 +32,40 @@ def __new__(cls, *args, **kwargs):
3032
live_refs[cls][obj] = time()
3133
return obj
3234

35+
3336
def format_live_refs(ignore=NoneType):
34-
s = "Live References" + os.linesep + os.linesep
37+
"""Return a tabular representation of tracked objects"""
38+
s = "Live References\n\n"
3539
now = time()
36-
for cls, wdict in six.iteritems(live_refs):
40+
for cls, wdict in sorted(six.iteritems(live_refs),
41+
key=lambda x: x[0].__name__):
3742
if not wdict:
3843
continue
3944
if issubclass(cls, ignore):
4045
continue
41-
oldest = min(wdict.itervalues())
42-
s += "%-30s %6d oldest: %ds ago" % (cls.__name__, len(wdict), \
43-
now-oldest) + os.linesep
46+
oldest = min(six.itervalues(wdict))
47+
s += "%-30s %6d oldest: %ds ago\n" % (
48+
cls.__name__, len(wdict), now - oldest
49+
)
4450
return s
4551

52+
4653
def print_live_refs(*a, **kw):
54+
"""Print tracked objects"""
4755
print(format_live_refs(*a, **kw))
4856

57+
4958
def get_oldest(class_name):
59+
"""Get the oldest object for a specific class name"""
5060
for cls, wdict in six.iteritems(live_refs):
5161
if cls.__name__ == class_name:
52-
if wdict:
53-
return min(six.iteritems(wdict), key=itemgetter(1))[0]
62+
if not wdict:
63+
break
64+
return min(six.iteritems(wdict), key=itemgetter(1))[0]
65+
5466

5567
def iter_all(class_name):
68+
"""Iterate over all objects of the same class by its class name"""
5669
for cls, wdict in six.iteritems(live_refs):
5770
if cls.__name__ == class_name:
5871
return six.iterkeys(wdict)

tests/test_utils_trackref.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import six
2+
import unittest
3+
from scrapy.utils import trackref
4+
from tests import mock
5+
6+
7+
class Foo(trackref.object_ref):
8+
pass
9+
10+
11+
class Bar(trackref.object_ref):
12+
pass
13+
14+
15+
class TrackrefTestCase(unittest.TestCase):
16+
17+
def setUp(self):
18+
trackref.live_refs.clear()
19+
20+
def test_format_live_refs(self):
21+
o1 = Foo() # NOQA
22+
o2 = Bar() # NOQA
23+
o3 = Foo() # NOQA
24+
self.assertEqual(
25+
trackref.format_live_refs(),
26+
'''\
27+
Live References
28+
29+
Bar 1 oldest: 0s ago
30+
Foo 2 oldest: 0s ago
31+
''')
32+
33+
self.assertEqual(
34+
trackref.format_live_refs(ignore=Foo),
35+
'''\
36+
Live References
37+
38+
Bar 1 oldest: 0s ago
39+
''')
40+
41+
@mock.patch('sys.stdout', new_callable=six.StringIO)
42+
def test_print_live_refs_empty(self, stdout):
43+
trackref.print_live_refs()
44+
self.assertEqual(stdout.getvalue(), 'Live References\n\n\n')
45+
46+
@mock.patch('sys.stdout', new_callable=six.StringIO)
47+
def test_print_live_refs_with_objects(self, stdout):
48+
o1 = Foo() # NOQA
49+
trackref.print_live_refs()
50+
self.assertEqual(stdout.getvalue(), '''\
51+
Live References
52+
53+
Foo 1 oldest: 0s ago\n\n''')
54+
55+
def test_get_oldest(self):
56+
o1 = Foo() # NOQA
57+
o2 = Bar() # NOQA
58+
o3 = Foo() # NOQA
59+
self.assertIs(trackref.get_oldest('Foo'), o1)
60+
self.assertIs(trackref.get_oldest('Bar'), o2)
61+
self.assertIsNone(trackref.get_oldest('XXX'))
62+
63+
def test_iter_all(self):
64+
o1 = Foo() # NOQA
65+
o2 = Bar() # NOQA
66+
o3 = Foo() # NOQA
67+
self.assertEqual(
68+
set(trackref.iter_all('Foo')),
69+
{o1, o3},
70+
)

0 commit comments

Comments
 (0)