Changeset 3415
- Timestamp:
- 07/21/06 15:48:17 (2 years ago)
- Files:
-
- django/trunk/django/contrib/admin/media/css/changelists.css (modified) (1 diff)
- django/trunk/django/contrib/admin/media/css/forms.css (modified) (1 diff)
- django/trunk/django/contrib/admin/media/css/global.css (modified) (3 diffs)
- django/trunk/django/contrib/admin/media/css/layout.css (modified) (2 diffs)
- django/trunk/django/contrib/admin/media/css/rtl.css (modified) (1 diff)
- django/trunk/django/contrib/admin/media/js/admin/CollapsedFieldsets.js (modified) (1 diff)
- django/trunk/django/contrib/admin/templates/admin_doc/index.html (modified) (1 diff)
- django/trunk/django/contrib/admin/templates/admin_doc/missing_docutils.html (modified) (1 diff)
- django/trunk/django/contrib/admin/templates/admin/login.html (modified) (1 diff)
- django/trunk/django/contrib/comments/models.py (modified) (1 diff)
- django/trunk/django/dispatch/dispatcher.py (modified) (3 diffs)
- django/trunk/django/dispatch/errors.py (modified) (1 diff)
- django/trunk/django/dispatch/license.txt (modified) (1 diff)
- django/trunk/django/dispatch/robustapply.py (modified) (1 diff)
- django/trunk/django/dispatch/robust.py (modified) (1 diff)
- django/trunk/django/dispatch/saferef.py (modified) (1 diff)
- django/trunk/django/template/defaultfilters.py (modified) (1 diff)
- django/trunk/docs/admin_css.txt (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/contrib/admin/media/css/changelists.css
r3064 r3415 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; } django/trunk/django/contrib/admin/media/css/forms.css
r2809 r3415 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 */ django/trunk/django/contrib/admin/media/css/global.css
r3084 r3415 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 … … 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; } … … 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; } django/trunk/django/contrib/admin/media/css/layout.css
r3065 r3415 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 */ … … 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; } django/trunk/django/contrib/admin/media/css/rtl.css
r3121 r3415 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;} django/trunk/django/contrib/admin/media/js/admin/CollapsedFieldsets.js
r3114 r3415 4 4 5 5 function findForm(node) { 6 // returns the node of the form containing the given node7 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 it22 // doesn't have any errors. (Collapsing shouldn't apply in the case23 // 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" link61 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" link70 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 django/trunk/django/contrib/admin/templates/admin_doc/index.html
r2809 r3415 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> django/trunk/django/contrib/admin/templates/admin_doc/missing_docutils.html
r2809 r3415 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 django/trunk/django/contrib/admin/templates/admin/login.html
r3121 r3415 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> </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> </label><input type="submit" value="{% trans 'Log in' %}" /> 26 </div> 27 27 </form> 28 28 django/trunk/django/contrib/comments/models.py
r2848 r3415 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): django/trunk/django/dispatch/dispatcher.py
r2809 r3415 7 7 Module attributes of note: 8 8 9 Any -- Singleton used to signal either "Any Sender" or10 "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 represent16 weak references to receivers, and thus must be de-17 referenced on retrieval to retrieve the callable18 object19 connections -- { senderkey (id) : { signal : [receivers...]}}20 senders -- { senderkey (id) : weakref(sender) }21 used for cleaning up sender references on sender22 deletion23 sendersBack -- { receiverkey (id) : [senderkey (id)...] }24 used for cleaning up receiver references on receiver25 deletion, (considerably speeds up the cleanup process26 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 … … 35 35 36 36 try: 37 True37 True 38 38 except NameError: 39 True = 1==140 False = 1==039 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"49 50 The Any object can be used with connect, disconnect,51 send, or sendExact to signal that the parameter given52 Any should react to all senders/signals, not just53 a particular sender/signal.54 """48 """Singleton used to signal either "Any Sender" or "Any Signal" 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 """ 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 sender61 of a message is not specified (as distinct from being62 "any sender"). Registering callbacks for Anonymous63 will only receive messages sent without senders. Sending64 with anonymous will only send messages to those receivers65 registered for Any or Anonymous.66 67 Note:68 The default sender for connect is Any, while the69 default sender for send is Anonymous. This has70 the effect that if you do not specify any senders71 in either function then all messages are routed72 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 … … 83 83 84 84 def connect(receiver, signal=Any, sender=Any, weak=True): 85 """Connect receiver to sender for signal86 87 receiver -- a callable Python object which is to receive88 messages/signals/events. Receivers must be hashable89 objects.90 91 if weak is True, then receiver must be weak-referencable92 (more precisely saferef.safeRef() must be able to create93 a reference to the receiver).94 95 Receivers are fairly flexible in their specification,96 as the machinery in the robustApply module takes care97 of most of the details regarding figuring out appropriate98 subsets of the sent arguments to apply to a given99 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 as105 receivers, though some use might be found for the106 facility whereby a higher-level library passes in107 pre-weakrefed receiver references.108 109 signal -- the signal to which the receiver should respond110 111 if Any, receiver will receive any signal from the112 indicated sender (which might also be Any, but is not113 necessarily Any).114 115 Otherwise must be a hashable Python object other than116 None (DispatcherError raised on None).117 118 sender -- the sender to which the receiver should respond119 120 if Any, receiver will receive the indicated signals121 from any sender.122 123 if Anonymous, receiver will only receive indicated124 signals from send/sendExact which do not specify a125 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 receiver130 By default, the module will attempt to use weak131 references to the receiver objects. If this parameter132 is false, then strong references will be used.133 134 returns None, may raise DispatcherTypeError135 """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 means153 # they won't be automatically cleaned up, but that's too bad.154 try:155 weakSender = weakref.ref(sender, remove)156 senders[senderkey] = weakSender157 except:158 pass159 160 receiverID = id(receiver)161 # get current set, remove any current references to162 # this receiver in the set, including back-references163 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 pass176 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 signal183 184 receiver -- the registered receiver to disconnect185 signal -- the registered signal to disconnect186 sender -- the registered sender to disconnect187 weak -- the weakref state to disconnect188 189 disconnect reverses the process of connect,190 the semantics for the individual elements are191 logically equivalent to a tuple of192 (receiver, signal, sender, weak) used as a key193 to be deleted from the internal routing tables.194 (The actual process is slightly more complex195 but the semantics are basically the same).196 197 Note:198 Using disconnect is not required to cleanup199 routing when an object is deleted, the framework200 will remove routes for deleted objects201 automatically. It's only necessary to disconnect202 if you want to stop routing to a live object.203 204 returns None, may raise DispatcherTypeError or205 DispatcherKeyError206 """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 sender221 )222 )223 try:224 # also removes from receivers225 _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 sender232 )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 tables238 239 This utility function allows you to retrieve the240 raw list of receivers from the connections table241 for the given sender and signal pair.242 243 Note:244 there is no guarantee that this is the actual list245 stored in the connections table, so the value246 should be treated as a simple iterable/truth value247 rather than, for instance a list to which you248 might append new records.249 250 Normally you would use liveReceivers( getReceivers( ...))251 to retrieve the actual receiver objects as an iterable252 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( ...)) 2
