Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
grumpy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
grumpy
Commits
8cd8f8de
Commit
8cd8f8de
authored
Dec 22, 2016
by
Dylan Trotter
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use weakref lib from CPython.
parent
b872e4b1
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
464 additions
and
17 deletions
+464
-17
lib/weakref.py
lib/weakref.py
+0
-17
third_party/stdlib/weakref.py
third_party/stdlib/weakref.py
+464
-0
No files found.
lib/weakref.py
deleted
100644 → 0
View file @
b872e4b1
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Weak reference functionality."""
from
__go__.grumpy
import
WeakRefType
as
ref
# pylint: disable=unused-import
third_party/stdlib/weakref.py
0 → 100644
View file @
8cd8f8de
"""Weak reference support for Python.
This module is an implementation of PEP 205:
http://www.python.org/dev/peps/pep-0205/
"""
# Naming convention: Variables named "wr" are weak reference objects;
# they are called this instead of "ref" to avoid name collisions with
# the module-global ref() function imported from _weakref.
import
UserDict
#from _weakref import (
# getweakrefcount,
# getweakrefs,
# ref,
# proxy,
# CallableProxyType,
# ProxyType,
# ReferenceType)
from
__go__.grumpy
import
WeakRefType
as
ReferenceType
ref
=
ReferenceType
import
_weakrefset
WeakSet
=
_weakrefset
.
WeakSet
_IterationGuard
=
_weakrefset
.
_IterationGuard
import
exceptions
ReferenceError
=
exceptions
.
ReferenceError
#ProxyTypes = (ProxyType, CallableProxyType)
#__all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs",
# "WeakKeyDictionary", "ReferenceError", "ReferenceType", "ProxyType",
# "CallableProxyType", "ProxyTypes", "WeakValueDictionary", 'WeakSet']
class
WeakValueDictionary
(
UserDict
.
UserDict
):
"""Mapping class that references values weakly.
Entries in the dictionary will be discarded when no strong
reference to the value exists anymore
"""
# We inherit the constructor without worrying about the input
# dictionary; since it uses our .update() method, we get the right
# checks (if the other dictionary is a WeakValueDictionary,
# objects are unwrapped on the way out, and we always wrap on the
# way in).
def
__init__
(
*
args
,
**
kw
):
if
not
args
:
raise
TypeError
(
"descriptor '__init__' of 'WeakValueDictionary' "
"object needs an argument"
)
self
=
args
[
0
]
args
=
args
[
1
:]
if
len
(
args
)
>
1
:
raise
TypeError
(
'expected at most 1 arguments, got %d'
%
len
(
args
))
def
remove
(
wr
,
selfref
=
ref
(
self
)):
self
=
selfref
()
if
self
is
not
None
:
if
self
.
_iterating
:
self
.
_pending_removals
.
append
(
wr
.
key
)
else
:
del
self
.
data
[
wr
.
key
]
self
.
_remove
=
remove
# A list of keys to be removed
self
.
_pending_removals
=
[]
self
.
_iterating
=
set
()
UserDict
.
UserDict
.
__init__
(
self
,
*
args
,
**
kw
)
def
_commit_removals
(
self
):
l
=
self
.
_pending_removals
d
=
self
.
data
# We shouldn't encounter any KeyError, because this method should
# always be called *before* mutating the dict.
while
l
:
del
d
[
l
.
pop
()]
def
__getitem__
(
self
,
key
):
o
=
self
.
data
[
key
]()
if
o
is
None
:
raise
KeyError
,
key
else
:
return
o
def
__delitem__
(
self
,
key
):
if
self
.
_pending_removals
:
self
.
_commit_removals
()
del
self
.
data
[
key
]
def
__contains__
(
self
,
key
):
try
:
o
=
self
.
data
[
key
]()
except
KeyError
:
return
False
return
o
is
not
None
def
has_key
(
self
,
key
):
try
:
o
=
self
.
data
[
key
]()
except
KeyError
:
return
False
return
o
is
not
None
def
__repr__
(
self
):
return
"<WeakValueDictionary at %s>"
%
id
(
self
)
def
__setitem__
(
self
,
key
,
value
):
if
self
.
_pending_removals
:
self
.
_commit_removals
()
self
.
data
[
key
]
=
KeyedRef
(
value
,
self
.
_remove
,
key
)
def
clear
(
self
):
if
self
.
_pending_removals
:
self
.
_commit_removals
()
self
.
data
.
clear
()
def
copy
(
self
):
new
=
WeakValueDictionary
()
for
key
,
wr
in
self
.
data
.
items
():
o
=
wr
()
if
o
is
not
None
:
new
[
key
]
=
o
return
new
__copy__
=
copy
def
__deepcopy__
(
self
,
memo
):
import
copy
new
=
self
.
__class__
()
for
key
,
wr
in
self
.
data
.
items
():
o
=
wr
()
if
o
is
not
None
:
new
[
copy
.
deepcopy
(
key
,
memo
)]
=
o
return
new
def
get
(
self
,
key
,
default
=
None
):
try
:
wr
=
self
.
data
[
key
]
except
KeyError
:
return
default
else
:
o
=
wr
()
if
o
is
None
:
# This should only happen
return
default
else
:
return
o
def
items
(
self
):
L
=
[]
for
key
,
wr
in
self
.
data
.
items
():
o
=
wr
()
if
o
is
not
None
:
L
.
append
((
key
,
o
))
return
L
def
iteritems
(
self
):
with
_IterationGuard
(
self
):
for
wr
in
self
.
data
.
itervalues
():
value
=
wr
()
if
value
is
not
None
:
yield
wr
.
key
,
value
def
iterkeys
(
self
):
with
_IterationGuard
(
self
):
for
k
in
self
.
data
.
iterkeys
():
yield
k
__iter__
=
iterkeys
def
itervaluerefs
(
self
):
"""Return an iterator that yields the weak references to the values.
The references are not guaranteed to be 'live' at the time
they are used, so the result of calling the references needs
to be checked before being used. This can be used to avoid
creating references that will cause the garbage collector to
keep the values around longer than needed.
"""
with
_IterationGuard
(
self
):
for
wr
in
self
.
data
.
itervalues
():
yield
wr
def
itervalues
(
self
):
with
_IterationGuard
(
self
):
for
wr
in
self
.
data
.
itervalues
():
obj
=
wr
()
if
obj
is
not
None
:
yield
obj
def
popitem
(
self
):
if
self
.
_pending_removals
:
self
.
_commit_removals
()
while
1
:
key
,
wr
=
self
.
data
.
popitem
()
o
=
wr
()
if
o
is
not
None
:
return
key
,
o
def
pop
(
self
,
key
,
*
args
):
if
self
.
_pending_removals
:
self
.
_commit_removals
()
try
:
o
=
self
.
data
.
pop
(
key
)()
except
KeyError
:
if
args
:
return
args
[
0
]
raise
if
o
is
None
:
raise
KeyError
,
key
else
:
return
o
def
setdefault
(
self
,
key
,
default
=
None
):
try
:
wr
=
self
.
data
[
key
]
except
KeyError
:
if
self
.
_pending_removals
:
self
.
_commit_removals
()
self
.
data
[
key
]
=
KeyedRef
(
default
,
self
.
_remove
,
key
)
return
default
else
:
return
wr
()
def
update
(
*
args
,
**
kwargs
):
if
not
args
:
raise
TypeError
(
"descriptor 'update' of 'WeakValueDictionary' "
"object needs an argument"
)
self
=
args
[
0
]
args
=
args
[
1
:]
if
len
(
args
)
>
1
:
raise
TypeError
(
'expected at most 1 arguments, got %d'
%
len
(
args
))
dict
=
args
[
0
]
if
args
else
None
if
self
.
_pending_removals
:
self
.
_commit_removals
()
d
=
self
.
data
if
dict
is
not
None
:
if
not
hasattr
(
dict
,
"items"
):
dict
=
type
({})(
dict
)
for
key
,
o
in
dict
.
items
():
d
[
key
]
=
KeyedRef
(
o
,
self
.
_remove
,
key
)
if
len
(
kwargs
):
self
.
update
(
kwargs
)
def
valuerefs
(
self
):
"""Return a list of weak references to the values.
The references are not guaranteed to be 'live' at the time
they are used, so the result of calling the references needs
to be checked before being used. This can be used to avoid
creating references that will cause the garbage collector to
keep the values around longer than needed.
"""
return
self
.
data
.
values
()
def
values
(
self
):
L
=
[]
for
wr
in
self
.
data
.
values
():
o
=
wr
()
if
o
is
not
None
:
L
.
append
(
o
)
return
L
class
KeyedRef
(
ref
):
"""Specialized reference that includes a key corresponding to the value.
This is used in the WeakValueDictionary to avoid having to create
a function object for each key stored in the mapping. A shared
callback object can use the 'key' attribute of a KeyedRef instead
of getting a reference to the key from an enclosing scope.
"""
__slots__
=
"key"
,
def
__new__
(
type
,
ob
,
callback
,
key
):
self
=
ref
.
__new__
(
type
,
ob
,
callback
)
self
.
key
=
key
return
self
def
__init__
(
self
,
ob
,
callback
,
key
):
super
(
KeyedRef
,
self
).
__init__
(
ob
,
callback
)
class
WeakKeyDictionary
(
UserDict
.
UserDict
):
""" Mapping class that references keys weakly.
Entries in the dictionary will be discarded when there is no
longer a strong reference to the key. This can be used to
associate additional data with an object owned by other parts of
an application without adding attributes to those objects. This
can be especially useful with objects that override attribute
accesses.
"""
def
__init__
(
self
,
dict
=
None
):
self
.
data
=
{}
def
remove
(
k
,
selfref
=
ref
(
self
)):
self
=
selfref
()
if
self
is
not
None
:
if
self
.
_iterating
:
self
.
_pending_removals
.
append
(
k
)
else
:
del
self
.
data
[
k
]
self
.
_remove
=
remove
# A list of dead weakrefs (keys to be removed)
self
.
_pending_removals
=
[]
self
.
_iterating
=
set
()
if
dict
is
not
None
:
self
.
update
(
dict
)
def
_commit_removals
(
self
):
# NOTE: We don't need to call this method before mutating the dict,
# because a dead weakref never compares equal to a live weakref,
# even if they happened to refer to equal objects.
# However, it means keys may already have been removed.
l
=
self
.
_pending_removals
d
=
self
.
data
while
l
:
try
:
del
d
[
l
.
pop
()]
except
KeyError
:
pass
def
__delitem__
(
self
,
key
):
del
self
.
data
[
ref
(
key
)]
def
__getitem__
(
self
,
key
):
return
self
.
data
[
ref
(
key
)]
def
__repr__
(
self
):
return
"<WeakKeyDictionary at %s>"
%
id
(
self
)
def
__setitem__
(
self
,
key
,
value
):
self
.
data
[
ref
(
key
,
self
.
_remove
)]
=
value
def
copy
(
self
):
new
=
WeakKeyDictionary
()
for
key
,
value
in
self
.
data
.
items
():
o
=
key
()
if
o
is
not
None
:
new
[
o
]
=
value
return
new
__copy__
=
copy
def
__deepcopy__
(
self
,
memo
):
import
copy
new
=
self
.
__class__
()
for
key
,
value
in
self
.
data
.
items
():
o
=
key
()
if
o
is
not
None
:
new
[
o
]
=
copy
.
deepcopy
(
value
,
memo
)
return
new
def
get
(
self
,
key
,
default
=
None
):
return
self
.
data
.
get
(
ref
(
key
),
default
)
def
has_key
(
self
,
key
):
try
:
wr
=
ref
(
key
)
except
TypeError
:
return
0
return
wr
in
self
.
data
def
__contains__
(
self
,
key
):
try
:
wr
=
ref
(
key
)
except
TypeError
:
return
0
return
wr
in
self
.
data
def
items
(
self
):
L
=
[]
for
key
,
value
in
self
.
data
.
items
():
o
=
key
()
if
o
is
not
None
:
L
.
append
((
o
,
value
))
return
L
def
iteritems
(
self
):
with
_IterationGuard
(
self
):
for
wr
,
value
in
self
.
data
.
iteritems
():
key
=
wr
()
if
key
is
not
None
:
yield
key
,
value
def
iterkeyrefs
(
self
):
"""Return an iterator that yields the weak references to the keys.
The references are not guaranteed to be 'live' at the time
they are used, so the result of calling the references needs
to be checked before being used. This can be used to avoid
creating references that will cause the garbage collector to
keep the keys around longer than needed.
"""
with
_IterationGuard
(
self
):
for
wr
in
self
.
data
.
iterkeys
():
yield
wr
def
iterkeys
(
self
):
with
_IterationGuard
(
self
):
for
wr
in
self
.
data
.
iterkeys
():
obj
=
wr
()
if
obj
is
not
None
:
yield
obj
__iter__
=
iterkeys
def
itervalues
(
self
):
with
_IterationGuard
(
self
):
for
value
in
self
.
data
.
itervalues
():
yield
value
def
keyrefs
(
self
):
"""Return a list of weak references to the keys.
The references are not guaranteed to be 'live' at the time
they are used, so the result of calling the references needs
to be checked before being used. This can be used to avoid
creating references that will cause the garbage collector to
keep the keys around longer than needed.
"""
return
self
.
data
.
keys
()
def
keys
(
self
):
L
=
[]
for
wr
in
self
.
data
.
keys
():
o
=
wr
()
if
o
is
not
None
:
L
.
append
(
o
)
return
L
def
popitem
(
self
):
while
1
:
key
,
value
=
self
.
data
.
popitem
()
o
=
key
()
if
o
is
not
None
:
return
o
,
value
def
pop
(
self
,
key
,
*
args
):
return
self
.
data
.
pop
(
ref
(
key
),
*
args
)
def
setdefault
(
self
,
key
,
default
=
None
):
return
self
.
data
.
setdefault
(
ref
(
key
,
self
.
_remove
),
default
)
def
update
(
self
,
dict
=
None
,
**
kwargs
):
d
=
self
.
data
if
dict
is
not
None
:
if
not
hasattr
(
dict
,
"items"
):
dict
=
type
({})(
dict
)
for
key
,
value
in
dict
.
items
():
d
[
ref
(
key
,
self
.
_remove
)]
=
value
if
len
(
kwargs
):
self
.
update
(
kwargs
)
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