Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Part 3 of pedant day: replaced all tabs in Django with spaces. Python…

… the way Guido intended it, baby!

git-svn-id: http://code.djangoproject.com/svn/django/trunk@3415 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 1687b025dc2a03e9ef111b8fd3db63fce48b77b7 1 parent a926046
Jacob Kaplan-Moss authored July 21, 2006
4  django/contrib/admin/media/css/changelists.css
@@ -42,9 +42,9 @@
42 42
 
43 43
 /* PAGINATOR */
44 44
 .paginator { font-size:11px; padding-top:10px; padding-bottom:10px; line-height:22px; margin:0; border-top:1px solid #ddd; }
45  
-.paginator a:link, .paginator a:visited	{ padding:2px 6px; border:solid 1px #ccc; background:white; text-decoration:none; }
  45
+.paginator a:link, .paginator a:visited { padding:2px 6px; border:solid 1px #ccc; background:white; text-decoration:none; }
46 46
 .paginator a.showall { padding:0 !important; border:none !important; }
47 47
 .paginator a.showall:hover { color:#036 !important; background:transparent !important; }
48  
-.paginator .end	{ border-width:2px !important; margin-right:6px; }
  48
+.paginator .end { border-width:2px !important; margin-right:6px; }
49 49
 .paginator .this-page { padding:2px 6px; font-weight:bold; font-size:13px; vertical-align:top; }
50 50
 .paginator a:hover { color:white; background:#5b80b2; border-color:#036; }
4  django/contrib/admin/media/css/forms.css
@@ -7,10 +7,10 @@
7 7
 form .form-row p { padding-left:0; font-size:11px; }
8 8
 
9 9
 /* FORM LABELS */
10  
-form h4	{ margin:0 !important; padding:0 !important; border:none !important; }
  10
+form h4 { margin:0 !important; padding:0 !important; border:none !important; }
11 11
 label { font-weight:normal !important; color:#666; font-size:12px; }
12 12
 label.inline { margin-left:20px; }
13  
-.required label, label.required	{ font-weight:bold !important; color:#333 !important; }
  13
+.required label, label.required { font-weight:bold !important; color:#333 !important; }
14 14
 
15 15
 /* RADIO BUTTONS */
16 16
 form ul.radiolist li { list-style-type:none; }
6  django/contrib/admin/media/css/global.css
@@ -31,7 +31,7 @@ fieldset { margin:0; padding:0; }
31 31
 blockquote { font-size:11px; color:#777; margin-left:2px; padding-left:10px; border-left:5px solid #ddd; }
32 32
 code, pre { font-family:"Bitstream Vera Sans Mono", Monaco, "Courier New", Courier, monospace; background:inherit; color:#666; font-size:11px; }
33 33
 pre.literal-block { margin:10px; background:#eee; padding:6px 8px; }
34  
-code strong	{ color:#930; }
  34
+code strong { color:#930; }
35 35
 hr { clear:both; color:#eee; background-color:#eee; height:1px; border:none; margin:0; padding:0; font-size:1px; line-height:1px; }
36 36
 
37 37
 /* TEXT STYLES & MODIFIERS */
@@ -81,7 +81,7 @@ table.orderable tbody tr td:first-child { padding-left:14px; background-image:ur
81 81
 table.orderable-initalized .order-cell, body>tr>td.order-cell { display:none; }
82 82
 
83 83
 /* FORM DEFAULTS */
84  
-input, textarea, select	{ margin:2px 0; padding:2px 3px; vertical-align:middle; font-family:"Lucida Grande", Verdana, Arial, sans-serif; font-weight:normal; font-size:11px; }
  84
+input, textarea, select { margin:2px 0; padding:2px 3px; vertical-align:middle; font-family:"Lucida Grande", Verdana, Arial, sans-serif; font-weight:normal; font-size:11px; }
85 85
 textarea { vertical-align:top !important; }
86 86
 input[type=text], input[type=password], textarea, select, .vTextField { border:1px solid #ccc; }
87 87
 
@@ -92,7 +92,7 @@ input[type=submit].default, .submit-row input.default { border:2px solid #5b80b2
92 92
 input[type=submit].default:active { background-image:url(../img/admin/default-bg-reverse.gif); background-position:top; }
93 93
 
94 94
 /* MODULES */
95  
-.module	{ border:1px solid #ccc; margin-bottom:5px; background:white; }
  95
+.module { border:1px solid #ccc; margin-bottom:5px; background:white; }
96 96
 .module p, .module ul, .module h3, .module h4, .module dl, .module pre { padding-left:10px; padding-right:10px; }
97 97
 .module blockquote { margin-left:12px; }
98 98
 .module ul, .module ol { margin-left:1.5em; }
8  django/contrib/admin/media/css/layout.css
@@ -4,7 +4,7 @@
4 4
 #header { width:100%; }
5 5
 #content-main { float:left; width:100%; }
6 6
 #content-related { float:right; width:18em; position:relative; margin-right:-19em; }
7  
-#footer	{ clear:both; padding:10px; }
  7
+#footer { clear:both; padding:10px; }
8 8
 
9 9
 /*  COLUMN TYPES  */
10 10
 .colMS { margin-right:20em !important; }
@@ -16,14 +16,14 @@
16 16
 .dashboard #content { width:500px; }
17 17
 
18 18
 /*  HEADER  */
19  
-#header	{ background:#417690; color:#ffc; overflow:hidden; }
  19
+#header { background:#417690; color:#ffc; overflow:hidden; }
20 20
 #header a:link, #header a:visited { color:white; }
21 21
 #header a:hover { text-decoration:underline; }
22 22
 #branding h1 { padding:0 10px; font-size:18px; margin:8px 0; font-weight:normal; color:#f4f379; }
23 23
 #branding h2 { padding:0 10px; font-size:14px; margin:-8px 0 8px 0; font-weight:normal; color:#ffc; }
24  
-#user-tools	{ position:absolute; top:0; right:0; padding:1.2em 10px; font-size:11px; text-align:right; }
  24
+#user-tools { position:absolute; top:0; right:0; padding:1.2em 10px; font-size:11px; text-align:right; }
25 25
 
26 26
 /* SIDEBAR */
27 27
 #content-related h3 { font-size:12px; color:#666; margin-bottom:3px; }
28 28
 #content-related h4 { font-size:11px; }
29  
-#content-related .module h2	{ background:#eee url(../img/admin/nav-bg.gif) bottom left repeat-x; color:#666; }
  29
+#content-related .module h2 { background:#eee url(../img/admin/nav-bg.gif) bottom left repeat-x; color:#666; }
2  django/contrib/admin/media/css/rtl.css
@@ -16,7 +16,7 @@ th { text-align: right; }
16 16
 
17 17
 
18 18
 /* layout styles */
19  
-#user-tools	{ right:auto; left:0; text-align:left; }
  19
+#user-tools { right:auto; left:0; text-align:left; }
20 20
 div.breadcrumbs { text-align:right; }
21 21
 #content-main { float:right;}
22 22
 #content-related { float:left; margin-left:-19em; margin-right:auto;}
144  django/contrib/admin/media/js/admin/CollapsedFieldsets.js
@@ -3,83 +3,83 @@
3 3
 // link when the fieldset is visible.
4 4
 
5 5
 function findForm(node) {
6  
-	// returns the node of the form containing the given node
7  
-	if (node.tagName.toLowerCase() != 'form') {
8  
-		return findForm(node.parentNode);
9  
-	}
10  
-	return node;
  6
+    // returns the node of the form containing the given node
  7
+    if (node.tagName.toLowerCase() != 'form') {
  8
+        return findForm(node.parentNode);
  9
+    }
  10
+    return node;
11 11
 }
12 12
 
13 13
 var CollapsedFieldsets = {
14  
-	collapse_re: /\bcollapse\b/,   // Class of fieldsets that should be dealt with.
15  
-	collapsed_re: /\bcollapsed\b/, // Class that fieldsets get when they're hidden.
16  
-	collapsed_class: 'collapsed',
17  
-	init: function() {
18  
-		var fieldsets = document.getElementsByTagName('fieldset');
19  
-		var collapsed_seen = false;
20  
-		for (var i = 0, fs; fs = fieldsets[i]; i++) {
21  
-			// Collapse this fieldset if it has the correct class, and if it
22  
-			// doesn't have any errors. (Collapsing shouldn't apply in the case
23  
-			// of error messages.)
24  
-			if (fs.className.match(CollapsedFieldsets.collapse_re) && !CollapsedFieldsets.fieldset_has_errors(fs)) {
25  
-				collapsed_seen = true;
26  
-				// Give it an additional class, used by CSS to hide it.
27  
-				fs.className += ' ' + CollapsedFieldsets.collapsed_class;
28  
-				// (<a id="fieldsetcollapser3" class="collapse-toggle" href="#">Show</a>)
29  
-				var collapse_link = document.createElement('a');
30  
-				collapse_link.className = 'collapse-toggle';
31  
-				collapse_link.id = 'fieldsetcollapser' + i;
32  
-				collapse_link.onclick = new Function('CollapsedFieldsets.show('+i+'); return false;');
33  
-				collapse_link.href = '#';
34  
-				collapse_link.innerHTML = gettext('Show');
35  
-				var h2 = fs.getElementsByTagName('h2')[0];
36  
-				h2.appendChild(document.createTextNode(' ('));
37  
-				h2.appendChild(collapse_link);
38  
-				h2.appendChild(document.createTextNode(')'));
39  
-			}
40  
-		}
41  
-		if (collapsed_seen) {
42  
-			// Expand all collapsed fieldsets when form is submitted.
43  
-			addEvent(findForm(document.getElementsByTagName('fieldset')[0]), 'submit', function() { CollapsedFieldsets.uncollapse_all(); });
44  
-		}
45  
-	},
46  
-	fieldset_has_errors: function(fs) {
47  
-		// Returns true if any fields in the fieldset have validation errors.
48  
-		var divs = fs.getElementsByTagName('div');
49  
-		for (var i=0; i<divs.length; i++) {
50  
-			if (divs[i].className.match(/\berror\b/)) {
51  
-				return true;
52  
-			}
53  
-		}
54  
-		return false;
55  
-	},
56  
-	show: function(fieldset_index) {
57  
-		var fs = document.getElementsByTagName('fieldset')[fieldset_index];
58  
-		// Remove the class name that causes the "display: none".
59  
-		fs.className = fs.className.replace(CollapsedFieldsets.collapsed_re, '');
60  
-		// Toggle the "Show" link to a "Hide" link
61  
-		var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index);
62  
-		collapse_link.onclick = new Function('CollapsedFieldsets.hide('+fieldset_index+'); return false;');
63  
-		collapse_link.innerHTML = gettext('Hide');
64  
-	},
65  
-	hide: function(fieldset_index) {
66  
-		var fs = document.getElementsByTagName('fieldset')[fieldset_index];
67  
-		// Add the class name that causes the "display: none".
68  
-		fs.className += ' ' + CollapsedFieldsets.collapsed_class;
69  
-		// Toggle the "Hide" link to a "Show" link
70  
-		var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index);
  14
+    collapse_re: /\bcollapse\b/,   // Class of fieldsets that should be dealt with.
  15
+    collapsed_re: /\bcollapsed\b/, // Class that fieldsets get when they're hidden.
  16
+    collapsed_class: 'collapsed',
  17
+    init: function() {
  18
+        var fieldsets = document.getElementsByTagName('fieldset');
  19
+        var collapsed_seen = false;
  20
+        for (var i = 0, fs; fs = fieldsets[i]; i++) {
  21
+            // Collapse this fieldset if it has the correct class, and if it
  22
+            // doesn't have any errors. (Collapsing shouldn't apply in the case
  23
+            // of error messages.)
  24
+            if (fs.className.match(CollapsedFieldsets.collapse_re) && !CollapsedFieldsets.fieldset_has_errors(fs)) {
  25
+                collapsed_seen = true;
  26
+                // Give it an additional class, used by CSS to hide it.
  27
+                fs.className += ' ' + CollapsedFieldsets.collapsed_class;
  28
+                // (<a id="fieldsetcollapser3" class="collapse-toggle" href="#">Show</a>)
  29
+                var collapse_link = document.createElement('a');
  30
+                collapse_link.className = 'collapse-toggle';
  31
+                collapse_link.id = 'fieldsetcollapser' + i;
  32
+                collapse_link.onclick = new Function('CollapsedFieldsets.show('+i+'); return false;');
  33
+                collapse_link.href = '#';
  34
+                collapse_link.innerHTML = gettext('Show');
  35
+                var h2 = fs.getElementsByTagName('h2')[0];
  36
+                h2.appendChild(document.createTextNode(' ('));
  37
+                h2.appendChild(collapse_link);
  38
+                h2.appendChild(document.createTextNode(')'));
  39
+            }
  40
+        }
  41
+        if (collapsed_seen) {
  42
+            // Expand all collapsed fieldsets when form is submitted.
  43
+            addEvent(findForm(document.getElementsByTagName('fieldset')[0]), 'submit', function() { CollapsedFieldsets.uncollapse_all(); });
  44
+        }
  45
+    },
  46
+    fieldset_has_errors: function(fs) {
  47
+        // Returns true if any fields in the fieldset have validation errors.
  48
+        var divs = fs.getElementsByTagName('div');
  49
+        for (var i=0; i<divs.length; i++) {
  50
+            if (divs[i].className.match(/\berror\b/)) {
  51
+                return true;
  52
+            }
  53
+        }
  54
+        return false;
  55
+    },
  56
+    show: function(fieldset_index) {
  57
+        var fs = document.getElementsByTagName('fieldset')[fieldset_index];
  58
+        // Remove the class name that causes the "display: none".
  59
+        fs.className = fs.className.replace(CollapsedFieldsets.collapsed_re, '');
  60
+        // Toggle the "Show" link to a "Hide" link
  61
+        var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index);
  62
+        collapse_link.onclick = new Function('CollapsedFieldsets.hide('+fieldset_index+'); return false;');
  63
+        collapse_link.innerHTML = gettext('Hide');
  64
+    },
  65
+    hide: function(fieldset_index) {
  66
+        var fs = document.getElementsByTagName('fieldset')[fieldset_index];
  67
+        // Add the class name that causes the "display: none".
  68
+        fs.className += ' ' + CollapsedFieldsets.collapsed_class;
  69
+        // Toggle the "Hide" link to a "Show" link
  70
+        var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index);
71 71
         collapse_link.onclick = new Function('CollapsedFieldsets.show('+fieldset_index+'); return false;');
72  
-		collapse_link.innerHTML = gettext('Show');
73  
-	},
  72
+        collapse_link.innerHTML = gettext('Show');
  73
+    },
74 74
 
75  
-	uncollapse_all: function() {
76  
-		var fieldsets = document.getElementsByTagName('fieldset');
77  
-		for (var i=0; i<fieldsets.length; i++) {
78  
-			if (fieldsets[i].className.match(CollapsedFieldsets.collapsed_re)) {
79  
-				CollapsedFieldsets.show(i);
80  
-			}
81  
-		}
82  
-	}
  75
+    uncollapse_all: function() {
  76
+        var fieldsets = document.getElementsByTagName('fieldset');
  77
+        for (var i=0; i<fieldsets.length; i++) {
  78
+            if (fieldsets[i].className.match(CollapsedFieldsets.collapsed_re)) {
  79
+                CollapsedFieldsets.show(i);
  80
+            }
  81
+        }
  82
+    }
83 83
 }
84 84
 
85 85
 addEvent(window, 'load', CollapsedFieldsets.init);
22  django/contrib/admin/templates/admin/login.html
@@ -13,17 +13,17 @@
13 13
 {% endif %}
14 14
 <div id="content-main">
15 15
 <form action="{{ app_path }}" method="post" id="login-form">
16  
-	<div class="form-row">
17  
-		<label for="id_username">{% trans 'Username:' %}</label> <input type="text" name="username" id="id_username" />
18  
-	</div>
19  
-	<div class="form-row">
20  
-		<label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" />
21  
-		<input type="hidden" name="this_is_the_login_form" value="1" />
22  
-		<input type="hidden" name="post_data" value="{{ post_data }}" /> {% comment %}<span class="help">{% trans 'Have you <a href="/password_reset/">forgotten your password</a>?' %}</span>{% endcomment %}
23  
-	</div>
24  
-	<div class="submit-row">
25  
-		<label>&nbsp;</label><input type="submit" value="{% trans 'Log in' %}" />
26  
-	</div>
  16
+  <div class="form-row">
  17
+    <label for="id_username">{% trans 'Username:' %}</label> <input type="text" name="username" id="id_username" />
  18
+  </div>
  19
+  <div class="form-row">
  20
+    <label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" />
  21
+    <input type="hidden" name="this_is_the_login_form" value="1" />
  22
+    <input type="hidden" name="post_data" value="{{ post_data }}" /> {% comment %}<span class="help">{% trans 'Have you <a href="/password_reset/">forgotten your password</a>?' %}</span>{% endcomment %}
  23
+  </div>
  24
+  <div class="submit-row">
  25
+    <label>&nbsp;</label><input type="submit" value="{% trans 'Log in' %}" />
  26
+  </div>
27 27
 </form>
28 28
 
29 29
 <script type="text/javascript">
16  django/contrib/admin/templates/admin_doc/index.html
@@ -9,17 +9,17 @@
9 9
 <h1>Documentation</h1>
10 10
 
11 11
 <div id="content-main">
12  
-	<h3><a href="tags/">Tags</a></h3>
13  
-	<p>List of all the template tags and their functions.</p>
  12
+  <h3><a href="tags/">Tags</a></h3>
  13
+  <p>List of all the template tags and their functions.</p>
14 14
 
15  
-	<h3><a href="filters/">Filters</a></h3>
16  
-	<p>Filters are actions which can be applied to variables in a template to alter the output.</p>
  15
+  <h3><a href="filters/">Filters</a></h3>
  16
+  <p>Filters are actions which can be applied to variables in a template to alter the output.</p>
17 17
 
18  
-	<h3><a href="models/">Models</a></h3>
19  
-	<p>Models are descriptions of all the objects in the system and their associated fields. Each model has a list of fields which can be accessed as template variables.</p>
  18
+  <h3><a href="models/">Models</a></h3>
  19
+  <p>Models are descriptions of all the objects in the system and their associated fields. Each model has a list of fields which can be accessed as template variables.</p>
20 20
 
21  
-	<h3><a href="views/">Views</a></h3>
22  
-	<p>Each page on the public site is generated by a view. The view defines which template is used to generate the page and which objects are available to that template.</p>
  21
+  <h3><a href="views/">Views</a></h3>
  22
+  <p>Each page on the public site is generated by a view. The view defines which template is used to generate the page and which objects are available to that template.</p>
23 23
 
24 24
     <h3><a href="bookmarklets/">Bookmarklets</a></h3>
25 25
     <p>Tools for your browser to quickly access admin functionality.</p>
4  django/contrib/admin/templates/admin_doc/missing_docutils.html
@@ -9,9 +9,9 @@
9 9
 <h1>Documentation</h1>
10 10
 
11 11
 <div id="content-main">
12  
-	<h3>The admin documentation system requires Python's <a href="http://docutils.sf.net/">docutils</a> library.</h3>
  12
+  <h3>The admin documentation system requires Python's <a href="http://docutils.sf.net/">docutils</a> library.</h3>
13 13
 
14  
-	<p>Please ask your administrators to install <a href="http://docutils.sf.net/">docutils</a>.</p>
  14
+  <p>Please ask your administrators to install <a href="http://docutils.sf.net/">docutils</a>.</p>
15 15
 </div>
16 16
 
17 17
 {% endblock %}
2  django/contrib/comments/models.py
@@ -51,7 +51,7 @@ def get_list_with_karma(self, **kwargs):
51 51
         extra_kwargs.setdefault('select', {})
52 52
         extra_kwargs['select']['_karma_total_good'] = 'SELECT COUNT(*) FROM comments_karmascore, comments_comment WHERE comments_karmascore.comment_id=comments_comment.id AND score=1'
53 53
         extra_kwargs['select']['_karma_total_bad'] = 'SELECT COUNT(*) FROM comments_karmascore, comments_comment WHERE comments_karmascore.comment_id=comments_comment.id AND score=-1'
54  
-	return self.filter(**kwargs).extra(**extra_kwargs)
  54
+        return self.filter(**kwargs).extra(**extra_kwargs)
55 55
 
56 56
     def user_is_moderator(self, user):
57 57
         if user.is_superuser:
862  django/dispatch/dispatcher.py
@@ -6,24 +6,24 @@
6 6
 
7 7
 Module attributes of note:
8 8
 
9  
-	Any -- Singleton used to signal either "Any Sender" or
10  
-		"Any Signal".  See documentation of the _Any class.
11  
-	Anonymous -- Singleton used to signal "Anonymous Sender"
12  
-		See documentation of the _Anonymous class.
  9
+    Any -- Singleton used to signal either "Any Sender" or
  10
+        "Any Signal".  See documentation of the _Any class.
  11
+    Anonymous -- Singleton used to signal "Anonymous Sender"
  12
+        See documentation of the _Anonymous class.
13 13
 
14 14
 Internal attributes:
15  
-	WEAKREF_TYPES -- tuple of types/classes which represent
16  
-		weak references to receivers, and thus must be de-
17  
-		referenced on retrieval to retrieve the callable
18  
-		object
19  
-	connections -- { senderkey (id) : { signal : [receivers...]}}
20  
-	senders -- { senderkey (id) : weakref(sender) }
21  
-		used for cleaning up sender references on sender
22  
-		deletion
23  
-	sendersBack -- { receiverkey (id) : [senderkey (id)...] }
24  
-		used for cleaning up receiver references on receiver
25  
-		deletion, (considerably speeds up the cleanup process
26  
-		vs. the original code.)
  15
+    WEAKREF_TYPES -- tuple of types/classes which represent
  16
+        weak references to receivers, and thus must be de-
  17
+        referenced on retrieval to retrieve the callable
  18
+        object
  19
+    connections -- { senderkey (id) : { signal : [receivers...]}}
  20
+    senders -- { senderkey (id) : weakref(sender) }
  21
+        used for cleaning up sender references on sender
  22
+        deletion
  23
+    sendersBack -- { receiverkey (id) : [senderkey (id)...] }
  24
+        used for cleaning up receiver references on receiver
  25
+        deletion, (considerably speeds up the cleanup process
  26
+        vs. the original code.)
27 27
 """
28 28
 from __future__ import generators
29 29
 import types, weakref
@@ -34,44 +34,44 @@
34 34
 __version__ = "$Revision: 1.9 $"[11:-2]
35 35
 
36 36
 try:
37  
-	True
  37
+    True
38 38
 except NameError:
39  
-	True = 1==1
40  
-	False = 1==0
  39
+    True = 1==1
  40
+    False = 1==0
41 41
 
42 42
 class _Parameter:
43  
-	"""Used to represent default parameter values."""
44  
-	def __repr__(self):
45  
-		return self.__class__.__name__
  43
+    """Used to represent default parameter values."""
  44
+    def __repr__(self):
  45
+        return self.__class__.__name__
46 46
 
47 47
 class _Any(_Parameter):
48  
-	"""Singleton used to signal either "Any Sender" or "Any Signal"
  48
+    """Singleton used to signal either "Any Sender" or "Any Signal"
49 49
 
50  
-	The Any object can be used with connect, disconnect,
51  
-	send, or sendExact to signal that the parameter given
52  
-	Any should react to all senders/signals, not just
53  
-	a particular sender/signal.
54  
-	"""
  50
+    The Any object can be used with connect, disconnect,
  51
+    send, or sendExact to signal that the parameter given
  52
+    Any should react to all senders/signals, not just
  53
+    a particular sender/signal.
  54
+    """
55 55
 Any = _Any()
56 56
 
57 57
 class _Anonymous(_Parameter):
58  
-	"""Singleton used to signal "Anonymous Sender"
59  
-
60  
-	The Anonymous object is used to signal that the sender
61  
-	of a message is not specified (as distinct from being
62  
-	"any sender").  Registering callbacks for Anonymous
63  
-	will only receive messages sent without senders.  Sending
64  
-	with anonymous will only send messages to those receivers
65  
-	registered for Any or Anonymous.
66  
-
67  
-	Note:
68  
-		The default sender for connect is Any, while the
69  
-		default sender for send is Anonymous.  This has
70  
-		the effect that if you do not specify any senders
71  
-		in either function then all messages are routed
72  
-		as though there was a single sender (Anonymous)
73  
-		being used everywhere.
74  
-	"""
  58
+    """Singleton used to signal "Anonymous Sender"
  59
+
  60
+    The Anonymous object is used to signal that the sender
  61
+    of a message is not specified (as distinct from being
  62
+    "any sender").  Registering callbacks for Anonymous
  63
+    will only receive messages sent without senders.  Sending
  64
+    with anonymous will only send messages to those receivers
  65
+    registered for Any or Anonymous.
  66
+
  67
+    Note:
  68
+        The default sender for connect is Any, while the
  69
+        default sender for send is Anonymous.  This has
  70
+        the effect that if you do not specify any senders
  71
+        in either function then all messages are routed
  72
+        as though there was a single sender (Anonymous)
  73
+        being used everywhere.
  74
+    """
75 75
 Anonymous = _Anonymous()
76 76
 
77 77
 WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref)
@@ -82,416 +82,416 @@ class _Anonymous(_Parameter):
82 82
 
83 83
 
84 84
 def connect(receiver, signal=Any, sender=Any, weak=True):
85  
-	"""Connect receiver to sender for signal
86  
-
87  
-	receiver -- a callable Python object which is to receive
88  
-		messages/signals/events.  Receivers must be hashable
89  
-		objects.
90  
-
91  
-		if weak is True, then receiver must be weak-referencable
92  
-		(more precisely saferef.safeRef() must be able to create
93  
-		a reference to the receiver).
94  
-	
95  
-		Receivers are fairly flexible in their specification,
96  
-		as the machinery in the robustApply module takes care
97  
-		of most of the details regarding figuring out appropriate
98  
-		subsets of the sent arguments to apply to a given
99  
-		receiver.
100  
-
101  
-		Note:
102  
-			if receiver is itself a weak reference (a callable),
103  
-			it will be de-referenced by the system's machinery,
104  
-			so *generally* weak references are not suitable as
105  
-			receivers, though some use might be found for the
106  
-			facility whereby a higher-level library passes in
107  
-			pre-weakrefed receiver references.
108  
-
109  
-	signal -- the signal to which the receiver should respond
110  
-	
111  
-		if Any, receiver will receive any signal from the
112  
-		indicated sender (which might also be Any, but is not
113  
-		necessarily Any).
114  
-		
115  
-		Otherwise must be a hashable Python object other than
116  
-		None (DispatcherError raised on None).
117  
-		
118  
-	sender -- the sender to which the receiver should respond
119  
-	
120  
-		if Any, receiver will receive the indicated signals
121  
-		from any sender.
122  
-		
123  
-		if Anonymous, receiver will only receive indicated
124  
-		signals from send/sendExact which do not specify a
125  
-		sender, or specify Anonymous explicitly as the sender.
126  
-
127  
-		Otherwise can be any python object.
128  
-		
129  
-	weak -- whether to use weak references to the receiver
130  
-		By default, the module will attempt to use weak
131  
-		references to the receiver objects.  If this parameter
132  
-		is false, then strong references will be used.
133  
-
134  
-	returns None, may raise DispatcherTypeError
135  
-	"""
136  
-	if signal is None:
137  
-		raise errors.DispatcherTypeError(
138  
-			'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender)
139  
-		)
140  
-	if weak:
141  
-		receiver = saferef.safeRef(receiver, onDelete=_removeReceiver)
142  
-	senderkey = id(sender)
143  
-	if connections.has_key(senderkey):
144  
-		signals = connections[senderkey]
145  
-	else:
146  
-		connections[senderkey] = signals = {}
147  
-	# Keep track of senders for cleanup.
148  
-	# Is Anonymous something we want to clean up?
149  
-	if sender not in (None, Anonymous, Any):
150  
-		def remove(object, senderkey=senderkey):
151  
-			_removeSender(senderkey=senderkey)
152  
-		# Skip objects that can not be weakly referenced, which means
153  
-		# they won't be automatically cleaned up, but that's too bad.
154  
-		try:
155  
-			weakSender = weakref.ref(sender, remove)
156  
-			senders[senderkey] = weakSender
157  
-		except:
158  
-			pass
159  
-		
160  
-	receiverID = id(receiver)
161  
-	# get current set, remove any current references to
162  
-	# this receiver in the set, including back-references
163  
-	if signals.has_key(signal):
164  
-		receivers = signals[signal]
165  
-		_removeOldBackRefs(senderkey, signal, receiver, receivers)
166  
-	else:
167  
-		receivers = signals[signal] = []
168  
-	try:
169  
-		current = sendersBack.get( receiverID )
170  
-		if current is None:
171  
-			sendersBack[ receiverID ] = current = []
172  
-		if senderkey not in current:
173  
-			current.append(senderkey)
174  
-	except:
175  
-		pass
176  
-
177  
-	receivers.append(receiver)
  85
+    """Connect receiver to sender for signal
  86
+
  87
+    receiver -- a callable Python object which is to receive
  88
+        messages/signals/events.  Receivers must be hashable
  89
+        objects.
  90
+
  91
+        if weak is True, then receiver must be weak-referencable
  92
+        (more precisely saferef.safeRef() must be able to create
  93
+        a reference to the receiver).
  94
+    
  95
+        Receivers are fairly flexible in their specification,
  96
+        as the machinery in the robustApply module takes care
  97
+        of most of the details regarding figuring out appropriate
  98
+        subsets of the sent arguments to apply to a given
  99
+        receiver.
  100
+
  101
+        Note:
  102
+            if receiver is itself a weak reference (a callable),
  103
+            it will be de-referenced by the system's machinery,
  104
+            so *generally* weak references are not suitable as
  105
+            receivers, though some use might be found for the
  106
+            facility whereby a higher-level library passes in
  107
+            pre-weakrefed receiver references.
  108
+
  109
+    signal -- the signal to which the receiver should respond
  110
+    
  111
+        if Any, receiver will receive any signal from the
  112
+        indicated sender (which might also be Any, but is not
  113
+        necessarily Any).
  114
+        
  115
+        Otherwise must be a hashable Python object other than
  116
+        None (DispatcherError raised on None).
  117
+        
  118
+    sender -- the sender to which the receiver should respond
  119
+    
  120
+        if Any, receiver will receive the indicated signals
  121
+        from any sender.
  122
+        
  123
+        if Anonymous, receiver will only receive indicated
  124
+        signals from send/sendExact which do not specify a
  125
+        sender, or specify Anonymous explicitly as the sender.
  126
+
  127
+        Otherwise can be any python object.
  128
+        
  129
+    weak -- whether to use weak references to the receiver
  130
+        By default, the module will attempt to use weak
  131
+        references to the receiver objects.  If this parameter
  132
+        is false, then strong references will be used.
  133
+
  134
+    returns None, may raise DispatcherTypeError
  135
+    """
  136
+    if signal is None:
  137
+        raise errors.DispatcherTypeError(
  138
+            'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender)
  139
+        )
  140
+    if weak:
  141
+        receiver = saferef.safeRef(receiver, onDelete=_removeReceiver)
  142
+    senderkey = id(sender)
  143
+    if connections.has_key(senderkey):
  144
+        signals = connections[senderkey]
  145
+    else:
  146
+        connections[senderkey] = signals = {}
  147
+    # Keep track of senders for cleanup.
  148
+    # Is Anonymous something we want to clean up?
  149
+    if sender not in (None, Anonymous, Any):
  150
+        def remove(object, senderkey=senderkey):
  151
+            _removeSender(senderkey=senderkey)
  152
+        # Skip objects that can not be weakly referenced, which means
  153
+        # they won't be automatically cleaned up, but that's too bad.
  154
+        try:
  155
+            weakSender = weakref.ref(sender, remove)
  156
+            senders[senderkey] = weakSender
  157
+        except:
  158
+            pass
  159
+        
  160
+    receiverID = id(receiver)
  161
+    # get current set, remove any current references to
  162
+    # this receiver in the set, including back-references
  163
+    if signals.has_key(signal):
  164
+        receivers = signals[signal]
  165
+        _removeOldBackRefs(senderkey, signal, receiver, receivers)
  166
+    else:
  167
+        receivers = signals[signal] = []
  168
+    try:
  169
+        current = sendersBack.get( receiverID )
  170
+        if current is None:
  171
+            sendersBack[ receiverID ] = current = []
  172
+        if senderkey not in current:
  173
+            current.append(senderkey)
  174
+    except:
  175
+        pass
  176
+
  177
+    receivers.append(receiver)
178 178
 
179 179
 
180 180
 
181 181
 def disconnect(receiver, signal=Any, sender=Any, weak=True):
182  
-	"""Disconnect receiver from sender for signal
183  
-
184  
-	receiver -- the registered receiver to disconnect
185  
-	signal -- the registered signal to disconnect
186  
-	sender -- the registered sender to disconnect
187  
-	weak -- the weakref state to disconnect
188  
-
189  
-	disconnect reverses the process of connect,
190  
-	the semantics for the individual elements are
191  
-	logically equivalent to a tuple of
192  
-	(receiver, signal, sender, weak) used as a key
193  
-	to be deleted from the internal routing tables.
194  
-	(The actual process is slightly more complex
195  
-	but the semantics are basically the same).
196  
-
197  
-	Note:
198  
-		Using disconnect is not required to cleanup
199  
-		routing when an object is deleted, the framework
200  
-		will remove routes for deleted objects
201  
-		automatically.  It's only necessary to disconnect
202  
-		if you want to stop routing to a live object.
203  
-		
204  
-	returns None, may raise DispatcherTypeError or
205  
-		DispatcherKeyError
206  
-	"""
207  
-	if signal is None:
208  
-		raise errors.DispatcherTypeError(
209  
-			'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender)
210  
-		)
211  
-	if weak: receiver = saferef.safeRef(receiver)
212  
-	senderkey = id(sender)
213  
-	try:
214  
-		signals = connections[senderkey]
215  
-		receivers = signals[signal]
216  
-	except KeyError:
217  
-		raise errors.DispatcherKeyError(
218  
-			"""No receivers found for signal %r from sender %r""" %(
219  
-				signal,
220  
-				sender
221  
-			)
222  
-		)
223  
-	try:
224  
-		# also removes from receivers
225  
-		_removeOldBackRefs(senderkey, signal, receiver, receivers)
226  
-	except ValueError:
227  
-		raise errors.DispatcherKeyError(
228  
-			"""No connection to receiver %s for signal %s from sender %s""" %(
229  
-				receiver,
230  
-				signal,
231  
-				sender
232  
-			)
233  
-		)
234  
-	_cleanupConnections(senderkey, signal)
  182
+    """Disconnect receiver from sender for signal
  183
+
  184
+    receiver -- the registered receiver to disconnect
  185
+    signal -- the registered signal to disconnect
  186
+    sender -- the registered sender to disconnect
  187
+    weak -- the weakref state to disconnect
  188
+
  189
+    disconnect reverses the process of connect,
  190
+    the semantics for the individual elements are
  191
+    logically equivalent to a tuple of
  192
+    (receiver, signal, sender, weak) used as a key
  193
+    to be deleted from the internal routing tables.
  194
+    (The actual process is slightly more complex
  195
+    but the semantics are basically the same).
  196
+
  197
+    Note:
  198
+        Using disconnect is not required to cleanup
  199
+        routing when an object is deleted, the framework
  200
+        will remove routes for deleted objects
  201
+        automatically.  It's only necessary to disconnect
  202
+        if you want to stop routing to a live object.
  203
+        
  204
+    returns None, may raise DispatcherTypeError or
  205
+        DispatcherKeyError
  206
+    """
  207
+    if signal is None:
  208
+        raise errors.DispatcherTypeError(
  209
+            'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender)
  210
+        )
  211
+    if weak: receiver = saferef.safeRef(receiver)
  212
+    senderkey = id(sender)
  213
+    try:
  214
+        signals = connections[senderkey]
  215
+        receivers = signals[signal]
  216
+    except KeyError:
  217
+        raise errors.DispatcherKeyError(
  218
+            """No receivers found for signal %r from sender %r""" %(
  219
+                signal,
  220
+                sender
  221
+            )
  222
+        )
  223
+    try:
  224
+        # also removes from receivers
  225
+        _removeOldBackRefs(senderkey, signal, receiver, receivers)
  226
+    except ValueError:
  227
+        raise errors.DispatcherKeyError(
  228
+            """No connection to receiver %s for signal %s from sender %s""" %(
  229
+                receiver,
  230
+                signal,
  231
+                sender
  232
+            )
  233
+        )
  234
+    _cleanupConnections(senderkey, signal)
235 235
 
236 236
 def getReceivers( sender = Any, signal = Any ):
237  
-	"""Get list of receivers from global tables
238  
-
239  
-	This utility function allows you to retrieve the
240  
-	raw list of receivers from the connections table
241  
-	for the given sender and signal pair.
242  
-
243  
-	Note:
244  
-		there is no guarantee that this is the actual list
245  
-		stored in the connections table, so the value
246  
-		should be treated as a simple iterable/truth value
247  
-		rather than, for instance a list to which you
248  
-		might append new records.
249  
-
250  
-	Normally you would use liveReceivers( getReceivers( ...))
251  
-	to retrieve the actual receiver objects as an iterable
252  
-	object.
253  
-	"""
254  
-	try:
255  
-		return connections[id(sender)][signal]
256  
-	except KeyError:
257  
-		return []
  237
+    """Get list of receivers from global tables
  238
+
  239
+    This utility function allows you to retrieve the
  240
+    raw list of receivers from the connections table
  241
+    for the given sender and signal pair.
  242
+
  243
+    Note:
  244
+        there is no guarantee that this is the actual list
  245
+        stored in the connections table, so the value
  246
+        should be treated as a simple iterable/truth value
  247
+        rather than, for instance a list to which you
  248
+        might append new records.
  249
+
  250
+    Normally you would use liveReceivers( getReceivers( ...))
  251
+    to retrieve the actual receiver objects as an iterable
  252
+    object.
  253
+    """
  254
+    try:
  255
+        return connections[id(sender)][signal]
  256
+    except KeyError:
  257
+        return []
258 258
 
259 259
 def liveReceivers(receivers):
260  
-	"""Filter sequence of receivers to get resolved, live receivers
  260
+    """Filter sequence of receivers to get resolved, live receivers
261 261
 
262  
-	This is a generator which will iterate over
263  
-	the passed sequence, checking for weak references
264  
-	and resolving them, then returning all live
265  
-	receivers.
266  
-	"""
267  
-	for receiver in receivers:
268  
-		if isinstance( receiver, WEAKREF_TYPES):
269  
-			# Dereference the weak reference.
270  
-			receiver = receiver()
271  
-			if receiver is not None:
272  
-				yield receiver
273  
-		else:
274  
-			yield receiver
  262
+    This is a generator which will iterate over
  263
+    the passed sequence, checking for weak references
  264
+    and resolving them, then returning all live
  265
+    receivers.
  266
+    """
  267
+    for receiver in receivers:
  268
+        if isinstance( receiver, WEAKREF_TYPES):
  269
+            # Dereference the weak reference.
  270
+            receiver = receiver()
  271
+            if receiver is not None:
  272
+                yield receiver
  273
+        else:
  274
+            yield receiver
275 275
 
276 276
 
277 277
 
278 278
 def getAllReceivers( sender = Any, signal = Any ):
279  
-	"""Get list of all receivers from global tables
280  
-
281  
-	This gets all receivers which should receive
282  
-	the given signal from sender, each receiver should
283  
-	be produced only once by the resulting generator
284  
-	"""
285  
-	receivers = {}
286  
-	for set in (
287  
-		# Get receivers that receive *this* signal from *this* sender.
288  
-		getReceivers( sender, signal ),
289  
-		# Add receivers that receive *any* signal from *this* sender.
290  
-		getReceivers( sender, Any ),
291  
-		# Add receivers that receive *this* signal from *any* sender.
292  
-		getReceivers( Any, signal ),
293  
-		# Add receivers that receive *any* signal from *any* sender.
294  
-		getReceivers( Any, Any ),
295  
-	):
296  
-		for receiver in set:
297  
-			if receiver: # filter out dead instance-method weakrefs
298  
-				try:
299  
-					if not receivers.has_key( receiver ):
300  
-						receivers[receiver] = 1
301  
-						yield receiver
302  
-				except TypeError:
303  
-					# dead weakrefs raise TypeError on hash...
304  
-					pass
  279
+    """Get list of all receivers from global tables
  280
+
  281
+    This gets all receivers which should receive
  282
+    the given signal from sender, each receiver should
  283
+    be produced only once by the resulting generator
  284
+    """
  285
+    receivers = {}
  286
+    for set in (
  287
+        # Get receivers that receive *this* signal from *this* sender.
  288
+        getReceivers( sender, signal ),
  289
+        # Add receivers that receive *any* signal from *this* sender.
  290
+        getReceivers( sender, Any ),
  291
+        # Add receivers that receive *this* signal from *any* sender.
  292
+        getReceivers( Any, signal ),
  293
+        # Add receivers that receive *any* signal from *any* sender.
  294
+        getReceivers( Any, Any ),
  295
+    ):
  296
+        for receiver in set:
  297
+            if receiver: # filter out dead instance-method weakrefs
  298
+                try:
  299
+                    if not receivers.has_key( receiver ):
  300
+                        receivers[receiver] = 1
  301
+                        yield receiver
  302
+                except TypeError:
  303
+                    # dead weakrefs raise TypeError on hash...
  304
+                    pass
305 305
 
306 306
 def send(signal=Any, sender=Anonymous, *arguments, **named):
307  
-	"""Send signal from sender to all connected receivers.
308  
-	
309  
-	signal -- (hashable) signal value, see connect for details
310  
-
311  
-	sender -- the sender of the signal
312  
-	
313  
-		if Any, only receivers registered for Any will receive
314  
-		the message.
315  
-
316  
-		if Anonymous, only receivers registered to receive
317  
-		messages from Anonymous or Any will receive the message
318  
-
319  
-		Otherwise can be any python object (normally one
320  
-		registered with a connect if you actually want
321  
-		something to occur).
322  
-
323  
-	arguments -- positional arguments which will be passed to
324  
-		*all* receivers. Note that this may raise TypeErrors
325  
-		if the receivers do not allow the particular arguments.
326  
-		Note also that arguments are applied before named
327  
-		arguments, so they should be used with care.
328  
-
329  
-	named -- named arguments which will be filtered according
330  
-		to the parameters of the receivers to only provide those
331  
-		acceptable to the receiver.
332  
-
333  
-	Return a list of tuple pairs [(receiver, response), ... ]
334  
-
335  
-	if any receiver raises an error, the error propagates back
336  
-	through send, terminating the dispatch loop, so it is quite
337  
-	possible to not have all receivers called if a raises an
338  
-	error.
339  
-	"""
340  
-	# Call each receiver with whatever arguments it can accept.
341  
-	# Return a list of tuple pairs [(receiver, response), ... ].
342  
-	responses = []
343  
-	for receiver in liveReceivers(getAllReceivers(sender, signal)):
344  
-		response = robustapply.robustApply(
345  
-			receiver,
346  
-			signal=signal,
347  
-			sender=sender,
348  
-			*arguments,
349  
-			**named
350  
-		)
351  
-		responses.append((receiver, response))
352  
-	return responses
  307
+    """Send signal from sender to all connected receivers.
  308
+    
  309
+    signal -- (hashable) signal value, see connect for details
  310
+
  311
+    sender -- the sender of the signal
  312
+    
  313
+        if Any, only receivers registered for Any will receive
  314
+        the message.
  315
+
  316
+        if Anonymous, only receivers registered to receive
  317
+        messages from Anonymous or Any will receive the message
  318
+
  319
+        Otherwise can be any python object (normally one
  320
+        registered with a connect if you actually want
  321
+        something to occur).
  322
+
  323
+    arguments -- positional arguments which will be passed to
  324
+        *all* receivers. Note that this may raise TypeErrors
  325
+        if the receivers do not allow the particular arguments.
  326
+        Note also that arguments are applied before named
  327
+        arguments, so they should be used with care.
  328
+
  329
+    named -- named arguments which will be filtered according
  330
+        to the parameters of the receivers to only provide those
  331
+        acceptable to the receiver.
  332
+
  333
+    Return a list of tuple pairs [(receiver, response), ... ]
  334
+
  335
+    if any receiver raises an error, the error propagates back
  336
+    through send, terminating the dispatch loop, so it is quite
  337
+    possible to not have all receivers called if a raises an
  338
+    error.
  339
+    """
  340
+    # Call each receiver with whatever arguments it can accept.
  341
+    # Return a list of tuple pairs [(receiver, response), ... ].
  342
+    responses = []
  343
+    for receiver in liveReceivers(getAllReceivers(sender, signal)):
  344
+        response = robustapply.robustApply(
  345
+            receiver,
  346
+            signal=signal,
  347
+            sender=sender,
  348
+            *arguments,
  349
+            **named
  350
+        )
  351
+        responses.append((receiver, response))
  352
+    return responses
353 353
 def sendExact( signal=Any, sender=Anonymous, *arguments, **named ):
354  
-	"""Send signal only to those receivers registered for exact message
355  
-
356  
-	sendExact allows for avoiding Any/Anonymous registered
357  
-	handlers, sending only to those receivers explicitly
358  
-	registered for a particular signal on a particular
359  
-	sender.
360  
-	"""
361  
-	responses = []
362  
-	for receiver in liveReceivers(getReceivers(sender, signal)):
363  
-		response = robustapply.robustApply(
364  
-			receiver,
365  
-			signal=signal,
366  
-			sender=sender,
367  
-			*arguments,
368  
-			**named
369  
-		)
370  
-		responses.append((receiver, response))
371  
-	return responses
372  
-	
  354
+    """Send signal only to those receivers registered for exact message
  355
+
  356
+    sendExact allows for avoiding Any/Anonymous registered
  357
+    handlers, sending only to those receivers explicitly
  358
+    registered for a particular signal on a particular
  359
+    sender.
  360
+    """
  361
+    responses = []
  362
+    for receiver in liveReceivers(getReceivers(sender, signal)):
  363
+        response = robustapply.robustApply(
  364
+            receiver,
  365
+            signal=signal,
  366
+            sender=sender,
  367
+            *arguments,
  368
+            **named
  369
+        )
  370
+        responses.append((receiver, response))
  371
+    return responses
  372
+    
373 373
 
374 374
 def _removeReceiver(receiver):
375  
-	"""Remove receiver from connections."""
376  
-	if not sendersBack:
377  
-		# During module cleanup the mapping will be replaced with None
378  
-		return False
379  
-	backKey = id(receiver)
380  
-	for senderkey in sendersBack.get(backKey,()):
381  
-		try:
382  
-			signals = connections[senderkey].keys()
383  
-		except KeyError,err:
384  
-			pass
385  
-		else:
386  
-			for signal in signals:
387  
-				try:
388  
-					receivers = connections[senderkey][signal]
389  
-				except KeyError:
390  
-					pass
391  
-				else:
392  
-					try:
393  
-						receivers.remove( receiver )
394  
-					except Exception, err:
395  
-						pass
396  
-				_cleanupConnections(senderkey, signal)
397  
-	try:
398  
-		del sendersBack[ backKey ]
399  
-	except KeyError:
400  
-		pass
401  
-			
  375
+    """Remove receiver from connections."""
  376
+    if not sendersBack:
  377
+        # During module cleanup the mapping will be replaced with None
  378
+        return False
  379
+    backKey = id(receiver)
  380
+    for senderkey in sendersBack.get(backKey,()):
  381
+        try:
  382
+            signals = connections[senderkey].keys()
  383
+        except KeyError,err:
  384
+            pass
  385
+        else:
  386
+            for signal in signals:
  387
+                try:
  388
+                    receivers = connections[senderkey][signal]
  389
+                except KeyError:
  390
+                    pass
  391
+                else:
  392
+                    try:
  393
+                        receivers.remove( receiver )
  394
+                    except Exception, err:
  395
+                        pass
  396
+                _cleanupConnections(senderkey, signal)
  397
+    try:
  398
+        del sendersBack[ backKey ]
  399
+    except KeyError:
  400
+        pass
  401
+            
402 402
 def _cleanupConnections(senderkey, signal):
403  
-	"""Delete any empty signals for senderkey. Delete senderkey if empty."""
404  
-	try:
405  
-		receivers = connections[senderkey][signal]
406  
-	except:
407  
-		pass
408  
-	else:
409  
-		if not receivers:
410  
-			# No more connected receivers. Therefore, remove the signal.
411  
-			try:
412  
-				signals = connections[senderkey]
413  
-			except KeyError:
414  
-				pass
415  
-			else:
416  
-				del signals[signal]
417  
-				if not signals:
418  
-					# No more signal connections. Therefore, remove the sender.
419  
-					_removeSender(senderkey)
  403
+    """Delete any empty signals for senderkey. Delete senderkey if empty."""
  404
+    try:
  405
+        receivers = connections[senderkey][signal]
  406
+    except:
  407
+        pass
  408
+    else:
  409
+        if not receivers:
  410
+            # No more connected receivers. Therefore, remove the signal.
  411
+            try:
  412
+                signals = connections[senderkey]
  413
+            except KeyError:
  414
+                pass
  415
+            else:
  416
+                del signals[signal]
  417
+                if not signals:
  418
+                    # No more signal connections. Therefore, remove the sender.
  419
+                    _removeSender(senderkey)
420 420
 
421 421
 def _removeSender(senderkey):
422  
-	"""Remove senderkey from connections."""
423  
-	_removeBackrefs(senderkey)
424  
-	try:
425  
-		del connections[senderkey]
426  
-	except KeyError:
427  
-		pass
428