Q: Is my method right for gargabe collecting circular referenced objects? When I was playing with my newly created html module, I used weakref module to overcome the circular reference problem. Everything seems to be fine for me! but I am not sure about the way I followed and not sure about the Scope class below. I tried to have a smallest working example (Here is a link for full code). Html class is just for creating html output with python objects. The example below does not do that for simplicity, of course.
# encoding: utf-8
from __future__ import print_function, unicode_literals
import weakref


class Scope(object):
    def __init__(self):
        self.ref_holder = set()

    def add(self, obj):
        self.ref_holder.add(obj)

    def __enter__(self):
        return self

    def __exit__(self, *args, **kwargs):
        self.ref_holder = None


class Html(object):
    def __init__(self, parent=None, tag="", scope=None):
        self.scope = scope
        if parent is None:
            self.parent = None
        elif type(parent) != weakref.CallableProxyType:
            self.parent = weakref.proxy(parent)
            if self.scope:
                self.scope.add(parent)
            elif parent.scope:
                parent.scope.add(self)
        else:
            self.parent = parent
        self.tag = tag
        if self.scope:
            self.scope.add(self)
        self.children = []

    def append(self, html):
        if isinstance(html, basestring):
            html = Html(tag=html)
            return self.append(html)
        elif isinstance(html, self.__class__):
            self.children.append(html)
            return html
        else:
            raise Exception("Unknown type")

    def __unicode__(self):
        return 'Html "{tag}" children = {children}'.format(tag=self.tag,
                                            children=list(map(str, self.children)))

    def __str__(self):
        return self.__unicode__()

if __name__ == "__main__":
    with Scope() as scope:
        test_form = Html(tag="form", scope=scope)
        test_form.append(Html(tag="label"))
        test_input = Html(tag="input")
        test_form.append(test_input)
        print(test_form)

Here are my concerns and I will appreciate your guidance:
I call reference holder class as Scope. It just holds the references to objects even if they are not assigned to any variable so Html object is not garbage collected (note: some objects can change parent/child relation ship and therefore there is not left any strong reference to object, in the real code).
I could simply hold the object references in a list and delete it after that but using with statement seems nicer. Is the class name Scope right for this task and the way I hold references is right? Is there a good way to hold the objects' strong references created on the fly different than my method?
I believe setting the Scope.ref_holder variable to None after exiting with statement, frees all the strong references and then gc collects them. I tested this by disabling gc and calling gc.collect then no object exists as unreacable, am I right to assume this method assures there is no leakage?

EDIT


*

*I added the link for full source code.

*Code is compliant with Python 2.7

A: I think the point here is that you are using __exit__ matched with with in Python.
Basically it should not happen like this. In __enter__ you are returning the self, the __exit__ should remove all the references. Are you sure that you don't have any exception in the middle? Due to exception __exit__ may return false and your garbage collection may not be complete. 
However to answer your question, I can tell you that the way you are making it None in the __exit__ method is forceful garbage cleaning & I think it completely depends on the OS. If self.ref_holder is somehow liked with addressed of those objects, they may be cleaned properly. 
Try to do del self.ref_holder rather. Assure more powerful cleanup.

A: Perhaps a bit OT: why explicit class for scope?
How about something simpler instead?
@contextlib.contextmanager
def scope():
    rv = set()
    try:
        yield rv
    finally:
        pass
        # if you must be explicit or 
        # if you want side-effect in leaked scopes
        rv.clear()

