Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/scrapy/utils/trackref.py: 38%

39 statements  

« prev     ^ index     » next       coverage.py v7.4.1, created at 2024-02-07 06:38 +0000

1"""This module provides some functions and classes to record and report 

2references to live object instances. 

3 

4If you want live objects for a particular class to be tracked, you only have to 

5subclass from object_ref (instead of object). 

6 

7About performance: This library has a minimal performance impact when enabled, 

8and no performance penalty at all when disabled (as object_ref becomes just an 

9alias to object in that case). 

10""" 

11 

12from collections import defaultdict 

13from operator import itemgetter 

14from time import time 

15from typing import TYPE_CHECKING, Any, DefaultDict, Iterable 

16from weakref import WeakKeyDictionary 

17 

18if TYPE_CHECKING: 

19 # typing.Self requires Python 3.11 

20 from typing_extensions import Self 

21 

22 

23NoneType = type(None) 

24live_refs: DefaultDict[type, WeakKeyDictionary] = defaultdict(WeakKeyDictionary) 

25 

26 

27class object_ref: 

28 """Inherit from this class to a keep a record of live instances""" 

29 

30 __slots__ = () 

31 

32 def __new__(cls, *args: Any, **kwargs: Any) -> "Self": 

33 obj = object.__new__(cls) 

34 live_refs[cls][obj] = time() 

35 return obj 

36 

37 

38# using Any as it's hard to type type(None) 

39def format_live_refs(ignore: Any = NoneType) -> str: 

40 """Return a tabular representation of tracked objects""" 

41 s = "Live References\n\n" 

42 now = time() 

43 for cls, wdict in sorted(live_refs.items(), key=lambda x: x[0].__name__): 

44 if not wdict: 

45 continue 

46 if issubclass(cls, ignore): 

47 continue 

48 oldest = min(wdict.values()) 

49 s += f"{cls.__name__:<30} {len(wdict):6} oldest: {int(now - oldest)}s ago\n" 

50 return s 

51 

52 

53def print_live_refs(*a: Any, **kw: Any) -> None: 

54 """Print tracked objects""" 

55 print(format_live_refs(*a, **kw)) 

56 

57 

58def get_oldest(class_name: str) -> Any: 

59 """Get the oldest object for a specific class name""" 

60 for cls, wdict in live_refs.items(): 

61 if cls.__name__ == class_name: 

62 if not wdict: 

63 break 

64 return min(wdict.items(), key=itemgetter(1))[0] 

65 

66 

67def iter_all(class_name: str) -> Iterable[Any]: 

68 """Iterate over all objects of the same class by its class name""" 

69 for cls, wdict in live_refs.items(): 

70 if cls.__name__ == class_name: 

71 return wdict.keys() 

72 return []