Coverage for /usr/lib/python3/dist-packages/gpiozero/compat.py: 21%
103 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-02-10 12:38 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2024-02-10 12:38 +0000
1# vim: set fileencoding=utf-8:
2#
3# GPIO Zero: a library for controlling the Raspberry Pi's GPIO pins
4#
5# Copyright (c) 2016-2021 Dave Jones <dave@waveform.org.uk>
6# Copyright (c) 2019 Ben Nuttall <ben@bennuttall.com>
7# Copyright (c) 2018 Rick Ansell <rick@nbinvincible.org.uk>
8# Copyright (c) 2016 Andrew Scheller <github@loowis.durge.org>
9#
10# SPDX-License-Identifier: BSD-3-Clause
12from __future__ import (
13 unicode_literals,
14 absolute_import,
15 print_function,
16 division,
17 )
18str = type('')
20import math
21import cmath
22import weakref
23import operator
24import functools
26# Handles pre 3.3 versions of Python without collections.abc
27try:
28 from collections.abc import Mapping
29except ImportError:
30 from collections import Mapping
32# Back-ported from python 3.5; see
33# github.com/PythonCHB/close_pep/blob/master/is_close.py for original
34# implementation
35def isclose(a, b, rel_tol=1e-9, abs_tol=0.0):
36 if rel_tol < 0.0 or abs_tol < 0.0:
37 raise ValueError('error tolerances must be non-negative')
38 if a == b: # fast-path for exact equality
39 return True
40 if cmath.isinf(a) or cmath.isinf(b):
41 return False
42 diff = abs(b - a)
43 return (
44 (diff <= abs(rel_tol * b)) or
45 (diff <= abs(rel_tol * a)) or
46 (diff <= abs_tol)
47 )
50# Backported from py3.4
51def mean(data):
52 if iter(data) is data:
53 data = list(data)
54 n = len(data)
55 if not n:
56 raise ValueError('cannot calculate mean of empty data')
57 return sum(data) / n
60# Backported from py3.4
61def median(data):
62 data = sorted(data)
63 n = len(data)
64 if not n:
65 raise ValueError('cannot calculate median of empty data')
66 elif n % 2:
67 return data[n // 2]
68 else:
69 i = n // 2
70 return (data[i - 1] + data[i]) / 2
73# Backported from py3.4
74def mean(data):
75 if iter(data) is data:
76 data = list(data)
77 n = len(data)
78 if n < 1:
79 raise ValueError('mean requires at least one data point')
80 return sum(data) / n
83# Backported from py3.3
84def log2(x):
85 return math.log(x, 2)
88# Copied from the MIT-licensed https://github.com/slezica/python-frozendict
89class frozendict(Mapping):
90 def __init__(self, *args, **kwargs):
91 self.__dict = dict(*args, **kwargs)
92 self.__hash = None
94 def __getitem__(self, key):
95 return self.__dict[key]
97 def copy(self, **add_or_replace):
98 return frozendict(self, **add_or_replace)
100 def __iter__(self):
101 return iter(self.__dict)
103 def __len__(self):
104 return len(self.__dict)
106 def __repr__(self):
107 return '<frozendict %s>' % repr(self.__dict)
109 def __hash__(self):
110 if self.__hash is None:
111 hashes = map(hash, self.items())
112 self.__hash = functools.reduce(operator.xor, hashes, 0)
113 return self.__hash
116# Backported from py3.4
117class WeakMethod(weakref.ref):
118 """
119 A custom `weakref.ref` subclass which simulates a weak reference to
120 a bound method, working around the lifetime problem of bound methods.
121 """
123 __slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__"
125 def __new__(cls, meth, callback=None):
126 try:
127 obj = meth.__self__
128 func = meth.__func__
129 except AttributeError:
130 raise TypeError("argument should be a bound method, not {0}"
131 .format(type(meth)))
132 def _cb(arg):
133 # The self-weakref trick is needed to avoid creating a reference
134 # cycle.
135 self = self_wr()
136 if self._alive:
137 self._alive = False
138 if callback is not None:
139 callback(self)
140 self = weakref.ref.__new__(cls, obj, _cb)
141 self._func_ref = weakref.ref(func, _cb)
142 self._meth_type = type(meth)
143 self._alive = True
144 self_wr = weakref.ref(self)
145 return self
147 def __call__(self):
148 obj = super(WeakMethod, self).__call__()
149 func = self._func_ref()
150 if obj is None or func is None:
151 return None
152 return self._meth_type(func, obj)
154 def __eq__(self, other):
155 if isinstance(other, WeakMethod):
156 if not self._alive or not other._alive:
157 return self is other
158 return weakref.ref.__eq__(self, other) and self._func_ref == other._func_ref
159 return False
161 def __ne__(self, other):
162 if isinstance(other, WeakMethod):
163 if not self._alive or not other._alive:
164 return self is not other
165 return weakref.ref.__ne__(self, other) or self._func_ref != other._func_ref
166 return True
168 __hash__ = weakref.ref.__hash__