Skip to content

Commit 02b2a70

Browse files
authored
Add derived gauges (census-instrumentation#498)
Add derived gauge classes and WeakMethod backport.
1 parent 73c45ec commit 02b2a70

File tree

7 files changed

+556
-63
lines changed

7 files changed

+556
-63
lines changed

opencensus/common/backports.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Copyright 2019, OpenCensus Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import six
16+
import weakref
17+
18+
19+
class WeakMethod(weakref.ref): # pragma: NO COVER
20+
"""
21+
A custom `weakref.ref` subclass which simulates a weak reference to
22+
a bound method, working around the lifetime problem of bound methods.
23+
24+
This is a copy of the WeakMethod class that ships with weakref in the
25+
python 3.7 standard library, adapted to work in 2.6. See:
26+
https://github.com/python/cpython/blob/a31f4cc881992e84d351957bd9ac1a92f882fa39/Lib/weakref.py#L36-L87
27+
""" # noqa
28+
29+
__slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__"
30+
31+
def __new__(cls, meth, callback=None):
32+
try:
33+
obj = meth.__self__
34+
func = meth.__func__
35+
except AttributeError:
36+
error = TypeError("argument should be a bound method, not {}"
37+
.format(type(meth)))
38+
six.raise_from(error, None)
39+
40+
def _cb(arg):
41+
# The self-weakref trick is needed to avoid creating a reference
42+
# cycle.
43+
self = self_wr()
44+
if self._alive:
45+
self._alive = False
46+
if callback is not None:
47+
callback(self)
48+
self = weakref.ref.__new__(cls, obj, _cb)
49+
self._func_ref = weakref.ref(func, _cb)
50+
self._meth_type = type(meth)
51+
self._alive = True
52+
self_wr = weakref.ref(self)
53+
return self
54+
55+
def __call__(self):
56+
obj = super(WeakMethod, self).__call__()
57+
func = self._func_ref()
58+
if obj is None or func is None:
59+
return None
60+
return self._meth_type(func, obj)
61+
62+
def __eq__(self, other):
63+
if isinstance(other, WeakMethod):
64+
if not self._alive or not other._alive:
65+
return self is other
66+
return (weakref.ref.__eq__(self, other)
67+
and self._func_ref == other._func_ref)
68+
return False
69+
70+
def __ne__(self, other):
71+
if isinstance(other, WeakMethod):
72+
if not self._alive or not other._alive:
73+
return self is not other
74+
return (weakref.ref.__ne__(self, other)
75+
or self._func_ref != other._func_ref)
76+
return True
77+
78+
__hash__ = weakref.ref.__hash__

opencensus/common/utils.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,14 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
try:
16+
from weakref import WeakMethod
17+
except ImportError:
18+
from opencensus.common.backports import WeakMethod
19+
1520
import calendar
1621
import datetime
22+
import weakref
1723

1824
UTF8 = 'utf-8'
1925

@@ -103,3 +109,16 @@ def window(ible, length):
103109
yield elts
104110
else:
105111
break
112+
113+
114+
def get_weakref(func):
115+
"""Get a weak reference to bound or unbound `func`.
116+
117+
If `func` is unbound (i.e. has no __self__ attr) get a weakref.ref,
118+
otherwise get a wrapper that simulates weakref.ref.
119+
"""
120+
if func is None:
121+
raise ValueError
122+
if not hasattr(func, '__self__'):
123+
return weakref.ref(func)
124+
return WeakMethod(func)

0 commit comments

Comments
 (0)