Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
D
django
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
django
Commits
56ab5f52
Kaydet (Commit)
56ab5f52
authored
Ock 12, 2014
tarafından
Florian Apolloner
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Sade Fark
Merge pull request #2163 from apollo13/signals
Signals
üst
1afe7488
7959aff8
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
360 additions
and
364 deletions
+360
-364
MANIFEST.in
MANIFEST.in
+1
-0
dispatcher.py
django/dispatch/dispatcher.py
+36
-27
license.python.txt
django/dispatch/license.python.txt
+254
-0
saferef.py
django/dispatch/saferef.py
+0
-261
weakref_backports.py
django/dispatch/weakref_backports.py
+69
-0
test_saferef.py
tests/dispatch/tests/test_saferef.py
+0
-76
No files found.
MANIFEST.in
Dosyayı görüntüle @
56ab5f52
...
...
@@ -6,6 +6,7 @@ include MANIFEST.in
include django/contrib/gis/gdal/LICENSE
include django/contrib/gis/geos/LICENSE
include django/dispatch/license.txt
include django/dispatch/license.python.txt
recursive-include docs *
recursive-include scripts *
recursive-include extras *
...
...
django/dispatch/dispatcher.py
Dosyayı görüntüle @
56ab5f52
import
weakref
import
sys
import
threading
import
weakref
from
django.dispatch
import
saferef
from
django.utils.six.moves
import
xrange
WEAKREF_TYPES
=
(
weakref
.
ReferenceType
,
saferef
.
BoundMethodWeakref
)
if
sys
.
version_info
<
(
3
,
4
):
from
.weakref_backports
import
WeakMethod
else
:
from
weakref
import
WeakMethod
def
_make_id
(
target
):
...
...
@@ -57,9 +59,7 @@ class Signal(object):
A function or an instance method which is to receive signals.
Receivers must be hashable objects.
If weak is True, then receiver must be weak-referencable (more
precisely saferef.safeRef() must be able to create a reference
to the receiver).
If weak is True, then receiver must be weak-referencable.
Receivers must be able to accept keyword arguments.
...
...
@@ -105,20 +105,33 @@ class Signal(object):
assert
argspec
[
2
]
is
not
None
,
\
"Signal receivers must accept keyword arguments (**kwargs)."
receiver_id
=
_make_id
(
receiver
)
if
dispatch_uid
:
lookup_key
=
(
dispatch_uid
,
_make_id
(
sender
))
else
:
lookup_key
=
(
_make_id
(
receiver
)
,
_make_id
(
sender
))
lookup_key
=
(
receiver_id
,
_make_id
(
sender
))
if
weak
:
receiver
=
saferef
.
safeRef
(
receiver
,
onDelete
=
self
.
_remove_receiver
)
ref
=
weakref
.
ref
original_receiver
=
receiver
# Check for bound methods
if
hasattr
(
receiver
,
'__self__'
)
and
hasattr
(
receiver
,
'__func__'
):
ref
=
WeakMethod
original_receiver
=
original_receiver
.
__self__
if
sys
.
version_info
>=
(
3
,
4
):
receiver
=
ref
(
receiver
)
weakref
.
finalize
(
original_receiver
,
self
.
_remove_receiver
,
receiver_id
=
receiver_id
)
else
:
receiver
=
ref
(
receiver
,
self
.
_remove_receiver
)
# Use the id of the weakref, since that's what passed to the weakref callback!
receiver_id
=
_make_id
(
receiver
)
with
self
.
lock
:
for
r_key
,
_
in
self
.
receivers
:
for
r_key
,
_
,
_
in
self
.
receivers
:
if
r_key
==
lookup_key
:
break
else
:
self
.
receivers
.
append
((
lookup_key
,
receiver
))
self
.
receivers
.
append
((
lookup_key
,
receiver
,
receiver_id
))
self
.
sender_receivers_cache
.
clear
()
def
disconnect
(
self
,
receiver
=
None
,
sender
=
None
,
weak
=
True
,
dispatch_uid
=
None
):
...
...
@@ -150,7 +163,7 @@ class Signal(object):
with
self
.
lock
:
for
index
in
xrange
(
len
(
self
.
receivers
)):
(
r_key
,
_
)
=
self
.
receivers
[
index
]
(
r_key
,
_
,
_
)
=
self
.
receivers
[
index
]
if
r_key
==
lookup_key
:
del
self
.
receivers
[
index
]
break
...
...
@@ -242,7 +255,7 @@ class Signal(object):
with
self
.
lock
:
senderkey
=
_make_id
(
sender
)
receivers
=
[]
for
(
receiverkey
,
r_senderkey
),
receiver
in
self
.
receivers
:
for
(
receiverkey
,
r_senderkey
),
receiver
,
_
in
self
.
receivers
:
if
r_senderkey
==
NONE_ID
or
r_senderkey
==
senderkey
:
receivers
.
append
(
receiver
)
if
self
.
use_caching
:
...
...
@@ -253,7 +266,7 @@ class Signal(object):
self
.
sender_receivers_cache
[
sender
]
=
receivers
non_weak_receivers
=
[]
for
receiver
in
receivers
:
if
isinstance
(
receiver
,
WEAKREF_TYPES
):
if
isinstance
(
receiver
,
weakref
.
ReferenceType
):
# Dereference the weak reference.
receiver
=
receiver
()
if
receiver
is
not
None
:
...
...
@@ -262,23 +275,19 @@ class Signal(object):
non_weak_receivers
.
append
(
receiver
)
return
non_weak_receivers
def
_remove_receiver
(
self
,
receiver
):
def
_remove_receiver
(
self
,
receiver
=
None
,
receiver_id
=
None
,
_make_id
=
_make_id
):
"""
Remove dead receivers from connections.
"""
`receiver_id` is used by python 3.4 and up. `receiver` is used in older
versions and is the weakref to the receiver (if the connection was defined
as `weak`). We also need to pass on `_make_id` since the original reference
will be None during module shutdown.
"""
with
self
.
lock
:
to_remove
=
[]
for
key
,
connected_receiver
in
self
.
receivers
:
if
connected_receiver
==
receiver
:
to_remove
.
append
(
key
)
for
key
in
to_remove
:
last_idx
=
len
(
self
.
receivers
)
-
1
# enumerate in reverse order so that indexes are valid even
# after we delete some items
for
idx
,
(
r_key
,
_
)
in
enumerate
(
reversed
(
self
.
receivers
)):
if
r_key
==
key
:
del
self
.
receivers
[
last_idx
-
idx
]
if
receiver
is
not
None
:
receiver_id
=
_make_id
(
receiver
)
self
.
receivers
[:]
=
[
val
for
val
in
self
.
receivers
if
val
[
2
]
!=
receiver_id
]
self
.
sender_receivers_cache
.
clear
()
...
...
django/dispatch/license.python.txt
0 → 100644
Dosyayı görüntüle @
56ab5f52
A. HISTORY OF THE SOFTWARE
==========================
Python was created in the early 1990s by Guido van Rossum at Stichting
Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
as a successor of a language called ABC. Guido remains Python's
principal author, although it includes many contributions from others.
In 1995, Guido continued his work on Python at the Corporation for
National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
in Reston, Virginia where he released several versions of the
software.
In May 2000, Guido and the Python core development team moved to
BeOpen.com to form the BeOpen PythonLabs team. In October of the same
year, the PythonLabs team moved to Digital Creations (now Zope
Corporation, see http://www.zope.com). In 2001, the Python Software
Foundation (PSF, see http://www.python.org/psf/) was formed, a
non-profit organization created specifically to own Python-related
Intellectual Property. Zope Corporation is a sponsoring member of
the PSF.
All Python releases are Open Source (see http://www.opensource.org for
the Open Source Definition). Historically, most, but not all, Python
releases have also been GPL-compatible; the table below summarizes
the various releases.
Release Derived Year Owner GPL-
from compatible? (1)
0.9.0 thru 1.2 1991-1995 CWI yes
1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
1.6 1.5.2 2000 CNRI no
2.0 1.6 2000 BeOpen.com no
1.6.1 1.6 2001 CNRI yes (2)
2.1 2.0+1.6.1 2001 PSF no
2.0.1 2.0+1.6.1 2001 PSF yes
2.1.1 2.1+2.0.1 2001 PSF yes
2.1.2 2.1.1 2002 PSF yes
2.1.3 2.1.2 2002 PSF yes
2.2 and above 2.1.1 2001-now PSF yes
Footnotes:
(1) GPL-compatible doesn't mean that we're distributing Python under
the GPL. All Python licenses, unlike the GPL, let you distribute
a modified version without making your changes open source. The
GPL-compatible licenses make it possible to combine Python with
other software that is released under the GPL; the others don't.
(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
because its license has a choice of law clause. According to
CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
is "not incompatible" with the GPL.
Thanks to the many outside volunteers who have worked under Guido's
direction to make these releases possible.
B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
===============================================================
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
--------------------------------------------
1. This LICENSE AGREEMENT is between the Python Software Foundation
("PSF"), and the Individual or Organization ("Licensee") accessing and
otherwise using this software ("Python") in source or binary form and
its associated documentation.
2. Subject to the terms and conditions of this License Agreement, PSF hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
analyze, test, perform and/or display publicly, prepare derivative works,
distribute, and otherwise use Python alone or in any derivative version,
provided, however, that PSF's License Agreement and PSF's notice of copyright,
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011, 2012, 2013, 2014 Python Software Foundation; All Rights Reserved" are retained
in Python alone or in any derivative version prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on
or incorporates Python or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to Python.
4. PSF is making Python available to Licensee on an "AS IS"
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any
relationship of agency, partnership, or joint venture between PSF and
Licensee. This License Agreement does not grant permission to use PSF
trademarks or trade name in a trademark sense to endorse or promote
products or services of Licensee, or any third party.
8. By copying, installing or otherwise using Python, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.
BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
-------------------------------------------
BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
Individual or Organization ("Licensee") accessing and otherwise using
this software in source or binary form and its associated
documentation ("the Software").
2. Subject to the terms and conditions of this BeOpen Python License
Agreement, BeOpen hereby grants Licensee a non-exclusive,
royalty-free, world-wide license to reproduce, analyze, test, perform
and/or display publicly, prepare derivative works, distribute, and
otherwise use the Software alone or in any derivative version,
provided, however, that the BeOpen Python License is retained in the
Software, alone or in any derivative version prepared by Licensee.
3. BeOpen is making the Software available to Licensee on an "AS IS"
basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
5. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
6. This License Agreement shall be governed by and interpreted in all
respects by the law of the State of California, excluding conflict of
law provisions. Nothing in this License Agreement shall be deemed to
create any relationship of agency, partnership, or joint venture
between BeOpen and Licensee. This License Agreement does not grant
permission to use BeOpen trademarks or trade names in a trademark
sense to endorse or promote products or services of Licensee, or any
third party. As an exception, the "BeOpen Python" logos available at
http://www.pythonlabs.com/logos.html may be used according to the
permissions granted on that web page.
7. By copying, installing or otherwise using the software, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.
CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
---------------------------------------
1. This LICENSE AGREEMENT is between the Corporation for National
Research Initiatives, having an office at 1895 Preston White Drive,
Reston, VA 20191 ("CNRI"), and the Individual or Organization
("Licensee") accessing and otherwise using Python 1.6.1 software in
source or binary form and its associated documentation.
2. Subject to the terms and conditions of this License Agreement, CNRI
hereby grants Licensee a nonexclusive, royalty-free, world-wide
license to reproduce, analyze, test, perform and/or display publicly,
prepare derivative works, distribute, and otherwise use Python 1.6.1
alone or in any derivative version, provided, however, that CNRI's
License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
1995-2001 Corporation for National Research Initiatives; All Rights
Reserved" are retained in Python 1.6.1 alone or in any derivative
version prepared by Licensee. Alternately, in lieu of CNRI's License
Agreement, Licensee may substitute the following text (omitting the
quotes): "Python 1.6.1 is made available subject to the terms and
conditions in CNRI's License Agreement. This Agreement together with
Python 1.6.1 may be located on the Internet using the following
unique, persistent identifier (known as a handle): 1895.22/1013. This
Agreement may also be obtained from a proxy server on the Internet
using the following URL: http://hdl.handle.net/1895.22/1013".
3. In the event Licensee prepares a derivative work that is based on
or incorporates Python 1.6.1 or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to Python 1.6.1.
4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
7. This License Agreement shall be governed by the federal
intellectual property law of the United States, including without
limitation the federal copyright law, and, to the extent such
U.S. federal law does not apply, by the law of the Commonwealth of
Virginia, excluding Virginia's conflict of law provisions.
Notwithstanding the foregoing, with regard to derivative works based
on Python 1.6.1 that incorporate non-separable material that was
previously distributed under the GNU General Public License (GPL), the
law of the Commonwealth of Virginia shall govern this License
Agreement only as to issues arising under or with respect to
Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
License Agreement shall be deemed to create any relationship of
agency, partnership, or joint venture between CNRI and Licensee. This
License Agreement does not grant permission to use CNRI trademarks or
trade name in a trademark sense to endorse or promote products or
services of Licensee, or any third party.
8. By clicking on the "ACCEPT" button where indicated, or by copying,
installing or otherwise using Python 1.6.1, Licensee agrees to be
bound by the terms and conditions of this License Agreement.
ACCEPT
CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
--------------------------------------------------
Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
The Netherlands. All rights reserved.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
django/dispatch/saferef.py
deleted
100644 → 0
Dosyayı görüntüle @
1afe7488
"""
"Safe weakrefs", originally from pyDispatcher.
Provides a way to safely weakref any function, including bound methods (which
aren't handled by the core weakref module).
"""
import
traceback
import
weakref
def
safeRef
(
target
,
onDelete
=
None
):
"""Return a *safe* weak reference to a callable target
target -- the object to be weakly referenced, if it's a
bound method reference, will create a BoundMethodWeakref,
otherwise creates a simple weakref.
onDelete -- if provided, will have a hard reference stored
to the callable to be called after the safe reference
goes out of scope with the reference object, (either a
weakref or a BoundMethodWeakref) as argument.
"""
if
hasattr
(
target
,
'__self__'
):
if
target
.
__self__
is
not
None
:
# Turn a bound method into a BoundMethodWeakref instance.
# Keep track of these instances for lookup by disconnect().
assert
hasattr
(
target
,
'__func__'
),
"""safeRef target
%
r has __self__, but no __func__, don't know how to create reference"""
%
(
target
,)
reference
=
get_bound_method_weakref
(
target
=
target
,
onDelete
=
onDelete
)
return
reference
if
callable
(
onDelete
):
return
weakref
.
ref
(
target
,
onDelete
)
else
:
return
weakref
.
ref
(
target
)
class
BoundMethodWeakref
(
object
):
"""'Safe' and reusable weak references to instance methods
BoundMethodWeakref objects provide a mechanism for
referencing a bound method without requiring that the
method object itself (which is normally a transient
object) is kept alive. Instead, the BoundMethodWeakref
object keeps weak references to both the object and the
function which together define the instance method.
Attributes:
key -- the identity key for the reference, calculated
by the class's calculateKey method applied to the
target instance method
deletionMethods -- sequence of callable objects taking
single argument, a reference to this object which
will be called when *either* the target object or
target function is garbage collected (i.e. when
this object becomes invalid). These are specified
as the onDelete parameters of safeRef calls.
weakSelf -- weak reference to the target object
weakFunc -- weak reference to the target function
Class Attributes:
_allInstances -- class attribute pointing to all live
BoundMethodWeakref objects indexed by the class's
calculateKey(target) method applied to the target
objects. This weak value dictionary is used to
short-circuit creation so that multiple references
to the same (object, function) pair produce the
same BoundMethodWeakref instance.
"""
_allInstances
=
weakref
.
WeakValueDictionary
()
def
__new__
(
cls
,
target
,
onDelete
=
None
,
*
arguments
,
**
named
):
"""Create new instance or return current instance
Basically this method of construction allows us to
short-circuit creation of references to already-
referenced instance methods. The key corresponding
to the target is calculated, and if there is already
an existing reference, that is returned, with its
deletionMethods attribute updated. Otherwise the
new instance is created and registered in the table
of already-referenced methods.
"""
key
=
cls
.
calculateKey
(
target
)
current
=
cls
.
_allInstances
.
get
(
key
)
if
current
is
not
None
:
current
.
deletionMethods
.
append
(
onDelete
)
return
current
else
:
base
=
super
(
BoundMethodWeakref
,
cls
)
.
__new__
(
cls
)
cls
.
_allInstances
[
key
]
=
base
base
.
__init__
(
target
,
onDelete
,
*
arguments
,
**
named
)
return
base
def
__init__
(
self
,
target
,
onDelete
=
None
):
"""Return a weak-reference-like instance for a bound method
target -- the instance-method target for the weak
reference, must have __self__ and __func__ attributes
and be reconstructable via:
target.__func__.__get__( target.__self__ )
which is true of built-in instance methods.
onDelete -- optional callback which will be called
when this weak reference ceases to be valid
(i.e. either the object or the function is garbage
collected). Should take a single argument,
which will be passed a pointer to this object.
"""
def
remove
(
weak
,
self
=
self
):
"""Set self.isDead to true when method or instance is destroyed"""
methods
=
self
.
deletionMethods
[:]
del
self
.
deletionMethods
[:]
try
:
del
self
.
__class__
.
_allInstances
[
self
.
key
]
except
KeyError
:
pass
for
function
in
methods
:
try
:
if
callable
(
function
):
function
(
self
)
except
Exception
as
e
:
try
:
traceback
.
print_exc
()
except
AttributeError
:
print
(
'Exception during saferef
%
s cleanup function
%
s:
%
s'
%
(
self
,
function
,
e
)
)
self
.
deletionMethods
=
[
onDelete
]
self
.
key
=
self
.
calculateKey
(
target
)
self
.
weakSelf
=
weakref
.
ref
(
target
.
__self__
,
remove
)
self
.
weakFunc
=
weakref
.
ref
(
target
.
__func__
,
remove
)
self
.
selfName
=
str
(
target
.
__self__
)
self
.
funcName
=
str
(
target
.
__func__
.
__name__
)
@classmethod
def
calculateKey
(
cls
,
target
):
"""Calculate the reference key for this reference
Currently this is a two-tuple of the id()'s of the
target object and the target function respectively.
"""
return
(
id
(
target
.
__self__
),
id
(
target
.
__func__
))
def
__str__
(
self
):
"""Give a friendly representation of the object"""
return
"""
%
s(
%
s.
%
s )"""
%
(
self
.
__class__
.
__name__
,
self
.
selfName
,
self
.
funcName
,
)
__repr__
=
__str__
def
__hash__
(
self
):
return
hash
(
self
.
key
)
def
__bool__
(
self
):
"""Whether we are still a valid reference"""
return
self
()
is
not
None
def
__nonzero__
(
self
):
# Python 2 compatibility
return
type
(
self
)
.
__bool__
(
self
)
def
__eq__
(
self
,
other
):
"""Compare with another reference"""
if
not
isinstance
(
other
,
self
.
__class__
):
return
self
.
__class__
==
type
(
other
)
return
self
.
key
==
other
.
key
def
__call__
(
self
):
"""Return a strong reference to the bound method
If the target cannot be retrieved, then will
return None, otherwise returns a bound instance
method for our object and function.
Note:
You may call this method any number of times,
as it does not invalidate the reference.
"""
target
=
self
.
weakSelf
()
if
target
is
not
None
:
function
=
self
.
weakFunc
()
if
function
is
not
None
:
return
function
.
__get__
(
target
)
return
None
class
BoundNonDescriptorMethodWeakref
(
BoundMethodWeakref
):
"""A specialized BoundMethodWeakref, for platforms where instance methods
are not descriptors.
It assumes that the function name and the target attribute name are the
same, instead of assuming that the function is a descriptor. This approach
is equally fast, but not 100
%
reliable because functions can be stored on an
attribute named differenty than the function's name such as in:
class A: pass
def foo(self): return "foo"
A.bar = foo
But this shouldn't be a common use case. So, on platforms where methods
aren't descriptors (such as Jython) this implementation has the advantage
of working in the most cases.
"""
def
__init__
(
self
,
target
,
onDelete
=
None
):
"""Return a weak-reference-like instance for a bound method
target -- the instance-method target for the weak
reference, must have __self__ and __func__ attributes
and be reconstructable via:
target.__func__.__get__( target.__self__ )
which is true of built-in instance methods.
onDelete -- optional callback which will be called
when this weak reference ceases to be valid
(i.e. either the object or the function is garbage
collected). Should take a single argument,
which will be passed a pointer to this object.
"""
assert
getattr
(
target
.
__self__
,
target
.
__name__
)
==
target
,
\
(
"method
%
s isn't available as the attribute
%
s of
%
s"
%
(
target
,
target
.
__name__
,
target
.
__self__
))
super
(
BoundNonDescriptorMethodWeakref
,
self
)
.
__init__
(
target
,
onDelete
)
def
__call__
(
self
):
"""Return a strong reference to the bound method
If the target cannot be retrieved, then will
return None, otherwise returns a bound instance
method for our object and function.
Note:
You may call this method any number of times,
as it does not invalidate the reference.
"""
target
=
self
.
weakSelf
()
if
target
is
not
None
:
function
=
self
.
weakFunc
()
if
function
is
not
None
:
# Using partial() would be another option, but it erases the
# "signature" of the function. That is, after a function is
# curried, the inspect module can't be used to determine how
# many arguments the function expects, nor what keyword
# arguments it supports, and pydispatcher needs this
# information.
return
getattr
(
target
,
function
.
__name__
)
return
None
def
get_bound_method_weakref
(
target
,
onDelete
):
"""Instantiates the appropiate BoundMethodWeakRef, depending on the details of
the underlying class method implementation"""
if
hasattr
(
target
,
'__get__'
):
# target method is a descriptor, so the default implementation works:
return
BoundMethodWeakref
(
target
=
target
,
onDelete
=
onDelete
)
else
:
# no luck, use the alternative implementation:
return
BoundNonDescriptorMethodWeakref
(
target
=
target
,
onDelete
=
onDelete
)
django/dispatch/weakref_backports.py
0 → 100644
Dosyayı görüntüle @
56ab5f52
"""
weakref_backports is a partial backport of the weakref module for python
versions below 3.4.
Copyright (C) 2013 Python Software Foundation, see license.python.txt for
details.
The following changes were made to the original sources during backporting:
* Added `self` to `super` calls.
* Removed `from None` when raising exceptions.
"""
from
weakref
import
ref
class
WeakMethod
(
ref
):
"""
A custom `weakref.ref` subclass which simulates a weak reference to
a bound method, working around the lifetime problem of bound methods.
"""
__slots__
=
"_func_ref"
,
"_meth_type"
,
"_alive"
,
"__weakref__"
def
__new__
(
cls
,
meth
,
callback
=
None
):
try
:
obj
=
meth
.
__self__
func
=
meth
.
__func__
except
AttributeError
:
raise
TypeError
(
"argument should be a bound method, not {}"
.
format
(
type
(
meth
)))
def
_cb
(
arg
):
# The self-weakref trick is needed to avoid creating a reference
# cycle.
self
=
self_wr
()
if
self
.
_alive
:
self
.
_alive
=
False
if
callback
is
not
None
:
callback
(
self
)
self
=
ref
.
__new__
(
cls
,
obj
,
_cb
)
self
.
_func_ref
=
ref
(
func
,
_cb
)
self
.
_meth_type
=
type
(
meth
)
self
.
_alive
=
True
self_wr
=
ref
(
self
)
return
self
def
__call__
(
self
):
obj
=
super
(
WeakMethod
,
self
)
.
__call__
()
func
=
self
.
_func_ref
()
if
obj
is
None
or
func
is
None
:
return
None
return
self
.
_meth_type
(
func
,
obj
)
def
__eq__
(
self
,
other
):
if
isinstance
(
other
,
WeakMethod
):
if
not
self
.
_alive
or
not
other
.
_alive
:
return
self
is
other
return
ref
.
__eq__
(
self
,
other
)
and
self
.
_func_ref
==
other
.
_func_ref
return
False
def
__ne__
(
self
,
other
):
if
isinstance
(
other
,
WeakMethod
):
if
not
self
.
_alive
or
not
other
.
_alive
:
return
self
is
not
other
return
ref
.
__ne__
(
self
,
other
)
or
self
.
_func_ref
!=
other
.
_func_ref
return
True
__hash__
=
ref
.
__hash__
tests/dispatch/tests/test_saferef.py
deleted
100644 → 0
Dosyayı görüntüle @
1afe7488
import
unittest
from
django.dispatch.saferef
import
safeRef
from
django.utils.six.moves
import
xrange
class
Test1
(
object
):
def
x
(
self
):
pass
def
test2
(
obj
):
pass
class
Test2
(
object
):
def
__call__
(
self
,
obj
):
pass
class
SaferefTests
(
unittest
.
TestCase
):
def
setUp
(
self
):
ts
=
[]
ss
=
[]
for
x
in
xrange
(
5000
):
t
=
Test1
()
ts
.
append
(
t
)
s
=
safeRef
(
t
.
x
,
self
.
_closure
)
ss
.
append
(
s
)
ts
.
append
(
test2
)
ss
.
append
(
safeRef
(
test2
,
self
.
_closure
))
for
x
in
xrange
(
30
):
t
=
Test2
()
ts
.
append
(
t
)
s
=
safeRef
(
t
,
self
.
_closure
)
ss
.
append
(
s
)
self
.
ts
=
ts
self
.
ss
=
ss
self
.
closureCount
=
0
def
tearDown
(
self
):
del
self
.
ts
del
self
.
ss
def
testIn
(
self
):
"""Test the "in" operator for safe references (cmp)"""
for
t
in
self
.
ts
[:
50
]:
self
.
assertTrue
(
safeRef
(
t
.
x
)
in
self
.
ss
)
def
testValid
(
self
):
"""Test that the references are valid (return instance methods)"""
for
s
in
self
.
ss
:
self
.
assertTrue
(
s
())
def
testShortCircuit
(
self
):
"""Test that creation short-circuits to reuse existing references"""
sd
=
{}
for
s
in
self
.
ss
:
sd
[
s
]
=
1
for
t
in
self
.
ts
:
if
hasattr
(
t
,
'x'
):
self
.
assertTrue
(
safeRef
(
t
.
x
)
in
sd
)
else
:
self
.
assertTrue
(
safeRef
(
t
)
in
sd
)
def
testRepresentation
(
self
):
"""Test that the reference object's representation works
XXX Doesn't currently check the results, just that no error
is raised
"""
repr
(
self
.
ss
[
-
1
])
def
_closure
(
self
,
ref
):
"""Dumb utility mechanism to increment deletion counter"""
self
.
closureCount
+=
1
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment