From d19d915f213bd15eca53ffda32349fb6abbb2725 Mon Sep 17 00:00:00 2001 From: Michael Chase <3686226+reallistic@users.noreply.github.com> Date: Tue, 9 Jun 2020 21:21:32 -0700 Subject: [PATCH 1/2] Cleanup some dead code in the collector. add Pyloot.stop to the README and other minor fixes. --- README.md | 16 +++++++++++++--- pyloot/__init__.py | 8 ++++++++ pyloot/collector.py | 27 +++++---------------------- setup.py | 2 +- 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index be801f7..c3a09d4 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,16 @@ Otherwise, threading.Thread is used. """ loot.start() +""" +Stop running the collector background thread. + +NOTE: This does not do a "final" collection. +To ensure objects were collected in a short lived execution, call collect_objects(). + +:param blocking: When true, wait until the thread has died +""" +loot.stop() + """ Return a WSGI compatible application serving the PyLoot remote backend and and the website. @@ -76,7 +86,7 @@ app = DispatcherMiddleware(app, { # Embedded code from pyloot import PyLoot ... -pyloot = PyLoot(host="127.0.0.1", port=8030) +pyloot = PyLoot(host="127.0.0.1", port=8000) ... ``` ```shell script @@ -86,7 +96,7 @@ usage: pyloot [-h HOST] [-p PORT] [--help] optional arguments: -h HOST, --host HOST Host to listen on. (Default: 0.0.0.0) --p PORT, --port PORT Port to listen on. (Default: 8030) +-p PORT, --port PORT Port to listen on. (Default: 8000) --help show this help message and exit ``` @@ -111,7 +121,7 @@ app.mount("/_pyloot", WSGIMiddleware(pyloot_wrapper)) # Screenshots ### View history of object counts by object group: -![history screenshot](https://raw.githubusercontent.com/reallistic/pyloot/master/docs/historypage.png) +![history screenshot](https://raw.githubusercontent.com/reallistic/pyloot/master/docs/history.png) ### Modify history page size ![history screenshot](https://raw.githubusercontent.com/reallistic/pyloot/master/docs/history-pageLimit.png) diff --git a/pyloot/__init__.py b/pyloot/__init__.py index ce38df6..3312ce7 100644 --- a/pyloot/__init__.py +++ b/pyloot/__init__.py @@ -55,6 +55,14 @@ def start(self): logger.debug("Finished starting pyloot looter thread") def stop(self, blocking=False): + """ + Stop running the collector background thread. + + NOTE: This does not do a "final" collection. + To ensure objects were collected in a short lived execution, call collect_objects(). + + :param blocking: When true, wait until the thread has died + """ self._running = False if blocking: self._thread_ended.wait() diff --git a/pyloot/collector.py b/pyloot/collector.py index 5859fe2..98737ca 100644 --- a/pyloot/collector.py +++ b/pyloot/collector.py @@ -39,7 +39,7 @@ def _safe_getattr(obj: object, k: str, default: Any = Exception): try: from zope.interface.ro import C3 - if isinstance(obj, C3) or issubclass(obj, C3): + if isinstance(obj, C3) or issubclass(obj, C3): # type: ignore if k.startswith("ORIG_"): return "__ignored_zope_interface_C3_{}__".format(k) except (ImportError, TypeError): @@ -92,38 +92,21 @@ def _should_include_object(ref: object, ignore_set: Set[int]) -> bool: return True -def get_child_ids(obj: object, ignore_set: Set[int]) -> List[int]: +def get_child_ids(obj: object) -> List[int]: """ Return children of the provided object using gc.get_referents :param obj: The object - :param ignore_set: A set of `id()`s which should be ignored. :return: List of object ids """ return [id(child) for child in gc.get_referents(obj)] -def get_parent_ids(obj: object, ignore_set: Set[int]) -> List[int]: - """ - Return children of the provided object using gc.get_referents - - :param obj: The object - :param ignore_set: A set of `id()`s which should be ignored. - :return: List of object ids - """ - return [ - id(parent) - for parent in gc.get_referrers(obj) - if _should_include_object(parent, ignore_set) - ] - - -def get_data(obj: object, ignore_set: Set[int]) -> ObjectDescriptor: +def get_data(obj: object) -> ObjectDescriptor: """ Return a Object descriptor for the given object :param obj: The object - :param ignore_set: A set of `id()`s which should be ignored. :return: """ obj_type = type(obj) @@ -134,7 +117,7 @@ def get_data(obj: object, ignore_set: Set[int]) -> ObjectDescriptor: id=id(obj), attrs=_safe_get_attrs(obj), parent_ids=[], - child_ids=get_child_ids(obj, ignore_set), + child_ids=get_child_ids(obj), repr=_safe_repr(obj), ) @@ -162,7 +145,7 @@ def get_object_descriptors( objs = [obj for obj in objs if _should_include_object(obj, ignore_set)] ignore_set.add(id(objs)) - results = [get_data(obj, ignore_set) for obj in objs] + results = [get_data(obj) for obj in objs] del objs del ignore_set child_to_parent: Dict[int, Set[int]] = defaultdict(set) diff --git a/setup.py b/setup.py index 579d82c..c6aed41 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="pyloot", - versioning="distance", + versioning="post", setup_requires="setupmeta", author="Michael Chase", description="Multiprocessing compatible memory leak debugger inspired by dozer/dowser", From 390b939fc3ee8d515628167f4d7f90a61ad8a8a3 Mon Sep 17 00:00:00 2001 From: Michael Chase <3686226+reallistic@users.noreply.github.com> Date: Wed, 10 Jun 2020 22:47:02 -0700 Subject: [PATCH 2/2] fix tests --- tests/test_memory.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_memory.py b/tests/test_memory.py index e517a0a..46f32a3 100644 --- a/tests/test_memory.py +++ b/tests/test_memory.py @@ -5,7 +5,7 @@ def test_store_blank_slate(): backend = InMemoryBackend() test_obj = dict(a=1) - obj_descr = collector.get_data(test_obj, set()) + obj_descr = collector.get_data(test_obj) backend.store([obj_descr]) descrs = backend.fetch() @@ -29,7 +29,7 @@ def test_store_blank_slate(): assert history[0].counts == [1, 1] test_obj2 = dict(a=1) - obj_descr2 = collector.get_data(test_obj2, set()) + obj_descr2 = collector.get_data(test_obj2) # new obj should increase data and count backend.store([obj_descr, obj_descr2])