summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlya Etingof <etingof@gmail.com>2018-12-25 11:19:34 +0100
committerIlya Etingof <etingof@gmail.com>2018-12-25 11:19:34 +0100
commit59de44ed981c9b3645bcfecc813d68f9d963a0a0 (patch)
tree17569590f8df060e7fa1adb11261e071bfd1d441
parent6a850eaf0144cd8a6a90805e626b3666acb7de83 (diff)
downloadpysnmp-git-59de44ed981c9b3645bcfecc813d68f9d963a0a0.tar.gz
Fix possible duplicate key condition in `OrderedDict`
Also, updated thr `.update` and `__init__` methods signatures to match `dict` interface. Implementation details renewed.
-rw-r--r--CHANGES.txt4
-rw-r--r--pysnmp/smi/indices.py73
2 files changed, 40 insertions, 37 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 2f9166e7..24ea285a 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,5 @@
-Revision 4.4.7, released 2018-11-XX
+Revision 4.4.7, released 2018-12-XX
-----------------------------------
- Exposed ASN.1 `Null` type through `rfc1902` module for convenience.
@@ -9,6 +9,8 @@ Revision 4.4.7, released 2018-11-XX
are different even if just timeout/retries options differ
- Fixed hlapi LCD configurator to include `contextName`. Prior to this fix
sending SNMPv3 TRAP with non-default `contextName` would fail.
+- Fixed possible duplicate key occurrence in the `OrderedDict` following
+ a race condition
Revision 4.4.6, released 2018-09-13
-----------------------------------
diff --git a/pysnmp/smi/indices.py b/pysnmp/smi/indices.py
index 00d95a63..7e15a8cd 100644
--- a/pysnmp/smi/indices.py
+++ b/pysnmp/smi/indices.py
@@ -10,36 +10,26 @@ from bisect import bisect
class OrderedDict(dict):
"""Ordered dictionary used for indices"""
- def __init__(self, **kwargs):
+ def __init__(self, *args, **kwargs):
self.__keys = []
self.__dirty = True
super(OrderedDict, self).__init__()
+ if args:
+ self.update(*args)
if kwargs:
- self.update(kwargs)
+ self.update(**kwargs)
def __setitem__(self, key, value):
- if key not in self:
- self.__keys.append(key)
super(OrderedDict, self).__setitem__(key, value)
- self.__dirty = True
-
- def __repr__(self):
- if self.__dirty:
- self.__order()
- return super(OrderedDict, self).__repr__()
-
- def __str__(self):
- if self.__dirty:
- self.__order()
- return super(OrderedDict, self).__str__()
+ if key not in self.__keys:
+ self.__keys.append(key)
+ self.__dirty = True
def __delitem__(self, key):
- if super(OrderedDict, self).__contains__(key):
- self.__keys.remove(key)
super(OrderedDict, self).__delitem__(key)
- self.__dirty = True
-
- __delattr__ = __delitem__
+ if key in self.__keys:
+ self.__keys.remove(key)
+ self.__dirty = True
def clear(self):
super(OrderedDict, self).clear()
@@ -61,30 +51,43 @@ class OrderedDict(dict):
self.__order()
return [(k, self[k]) for k in self.__keys]
- def update(self, d):
- [self.__setitem__(k, v) for k, v in d.items()]
+ def update(self, *args, **kwargs):
+ if args:
+ iterable = args[0]
+ if hasattr(iterable, 'keys'):
+ for k in iterable:
+ self[k] = iterable[k]
+ else:
+ for k, v in iterable:
+ self[k] = v
+
+ if kwargs:
+ for k in kwargs:
+ self[k] = kwargs[k]
def sortingFun(self, keys):
keys.sort()
def __order(self):
self.sortingFun(self.__keys)
- d = {}
- for k in self.__keys:
- d[len(k)] = 1
- l = list(d.keys())
- l.sort(reverse=True)
- self.__keysLens = tuple(l)
+ self.__keysLens = sorted(set(len(k) for k in self.__keys), reverse=True)
self.__dirty = False
def nextKey(self, key):
- keys = list(self.keys())
- if key in self:
+ if self.__dirty:
+ self.__order()
+
+ keys = self.__keys
+
+ if key in keys:
nextIdx = keys.index(key) + 1
+
else:
nextIdx = bisect(keys, key)
+
if nextIdx < len(keys):
return keys[nextIdx]
+
else:
raise KeyError(key)
@@ -97,24 +100,22 @@ class OrderedDict(dict):
class OidOrderedDict(OrderedDict):
"""OID-ordered dictionary used for indices"""
- def __init__(self, **kwargs):
+ def __init__(self, *args, **kwargs):
self.__keysCache = {}
- OrderedDict.__init__(self, **kwargs)
+ OrderedDict.__init__(self, *args, **kwargs)
def __setitem__(self, key, value):
+ OrderedDict.__setitem__(self, key, value)
if key not in self.__keysCache:
if isinstance(key, tuple):
self.__keysCache[key] = key
else:
self.__keysCache[key] = [int(x) for x in key.split('.') if x]
- OrderedDict.__setitem__(self, key, value)
def __delitem__(self, key):
+ OrderedDict.__delitem__(self, key)
if key in self.__keysCache:
del self.__keysCache[key]
- OrderedDict.__delitem__(self, key)
-
- __delattr__ = __delitem__
def sortingFun(self, keys):
keys.sort(key=lambda k, d=self.__keysCache: d[k])