<commit_before>from __future__ import print_function

import functools
import gc
import inspect
import sys

from nose.twistedtools import deferred
from twisted.internet.defer import inlineCallbacks, DebugInfo, setDebugging

from spinoff.actor import Actor, Node
from spinoff.actor.events import Events
from spinoff.actor.remoting import HubWithNoRemoting
from spinoff.util.async import _process_idle_calls, _idle_calls
from spinoff.util.testing import ErrorCollector, Unclean
from spinoff.util.logging import dbg


def TestNode():
    return Node(hub=HubWithNoRemoting())


def wrap_globals(globals):
    """Ensures that errors in actors during tests don't go unnoticed."""

    def wrap(fn):
        if inspect.isgeneratorfunction(fn):
            fn = inlineCallbacks(fn)

        @functools.wraps(fn)
        @deferred(timeout=fn.timeout if hasattr(fn, 'timeout') else 1.0)
        @inlineCallbacks
        def ret():
            # dbg("\n============================================\n")

            import spinoff.actor._actor
            spinoff.actor._actor.TESTING = True

            Actor.reset_flags(debug=True)

            # TODO: once the above TODO (fresh Node for each test fn) is complete, consider making Events non-global by
            # having each Node have its own Events instance.
            Events.reset()

            with ErrorCollector():
                # setDebugging(1)
                try:
                    yield fn()
                finally:
                    # dbg("TESTWRAP: ------------------------- cleaning up after %s" % (fn.__name__,))

                    # yield Node.stop_all()

                    if _idle_calls:
                        # dbg("TESTWRAP: processing all remaining scheduled calls...")
                        _process_idle_calls()
                        # dbg("TESTWRAP: ...scheduled calls done.")

                    if '__pypy__' not in sys.builtin_module_names:
                        gc.collect()
                        for trash in gc.garbage[:]:
                            if isinstance(trash, DebugInfo):
                                # dbg("DEBUGINFO: __del__")
                                if trash.failResult is not None:
                                    exc = Unclean(repr(trash.failResult.value) + '\n' + str(trash._getDebugTracebacks()))
                                    trash.__dict__.clear()
                                    raise exc
                                gc.garbage.remove(trash)

                        assert not gc.garbage, "Memory leak detected"

                        # if gc.garbage:
                        #     dbg("GARGABE: detected after %s:" % (fn.__name__,), len(gc.garbage))
                        #     import objgraph as ob
                        #     import os

                        #     def dump_chain(g_):
                        #         def calling_test(x):
                        #             if not isframework(x):
                        #                 return None
                        #         import spinoff
                        #         isframework = lambda x: type(x).__module__.startswith(spinoff.__name__)
                        #         ob.show_backrefs([g_], filename='backrefs.png', max_depth=100, highlight=isframework)

                        #     for gen in gc.garbage:
                        #         dump_chain(gen)
                        #         dbg("   TESTWRAP: mem-debuggin", gen)
                        #         import pdb; pdb.set_trace()
                        #         os.remove('backrefs.png')

                        # to avoid the above assertion from being included as part of any tracebacks from the test
                        # function--the last line of a context managed block is included in tracebacks originating
                        # from context managers.
                        pass

        return ret<commit_msg>Refactored s.u.a.wrap_globals in a way that avoids yields in finally-blocks<commit_after>from __future__ import print_function

import functools
import gc
import inspect
import sys

from nose.twistedtools import deferred
from twisted.internet.defer import inlineCallbacks, DebugInfo, setDebugging

from spinoff.actor import Actor, Node
from spinoff.actor.events import Events
from spinoff.actor.remoting import HubWithNoRemoting
from spinoff.util.async import _process_idle_calls, deferred_with
from spinoff.util.testing import ErrorCollector, Unclean


def TestNode():
    return Node(hub=HubWithNoRemoting())


def wrap_globals(globals):
    """Ensures that errors in actors during tests don't go unnoticed."""

    def wrap(fn):
        if inspect.isgeneratorfunction(fn):
            fn = inlineCallbacks(fn)

        @functools.wraps(fn)
        @deferred(timeout=fn.timeout if hasattr(fn, 'timeout') else 1.0)
        def ret():
            # dbg("\n============================================\n")

            import spinoff.actor._actor
            spinoff.actor._actor.TESTING = True

            Actor.reset_flags(debug=True)

            # TODO: once the above TODO (fresh Node for each test fn) is complete, consider making Events non-global by
            # having each Node have its own Events instance.
            Events.reset()

            def check_memleaks():
                if '__pypy__' not in sys.builtin_module_names:
                    gc.collect()
                    for trash in gc.garbage[:]:
                        if isinstance(trash, DebugInfo):
                            # dbg("DEBUGINFO: __del__")
                            if trash.failResult is not None:
                                exc = Unclean(repr(trash.failResult.value) + '\n' + str(trash._getDebugTracebacks()))
                                trash.__dict__.clear()
                                raise exc
                            gc.garbage.remove(trash)

                    assert not gc.garbage, "Memory leak detected: %r" % (gc.garbage,)

                    # if gc.garbage:
                    #     dbg("GARGABE: detected after %s:" % (fn.__name__,), len(gc.garbage))
                    #     import objgraph as ob
                    #     import os

                    #     def dump_chain(g_):
                    #         def calling_test(x):
                    #             if not isframework(x):
                    #                 return None
                    #         import spinoff
                    #         isframework = lambda x: type(x).__module__.startswith(spinoff.__name__)
                    #         ob.show_backrefs([g_], filename='backrefs.png', max_depth=100, highlight=isframework)

                    #     for gen in gc.garbage:
                    #         dump_chain(gen)
                    #         dbg("   TESTWRAP: mem-debuggin", gen)
                    #         import pdb; pdb.set_trace()
                    #         os.remove('backrefs.png')

            return (
                deferred_with(ErrorCollector(), fn)
                .addBoth(lambda result: Node.stop_all().addCallback(lambda _: result))
                .addBoth(lambda result: (_process_idle_calls(), result)[-1])
                .addBoth(lambda result: (check_memleaks(), result)[-1])
            )

        return ret
{'fraction_non_alphanumeric': 0.09547325102880659, 'fraction_numerical': 0.0017832647462277093, 'mean_word_length': 1.4376462721497827, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5071889', 'n_tokens_mistral': 1897, 'n_tokens_neox': 1793, 'n_words': 475}