Skip to content

Commit 3490190

Browse files
Obsolete utils.OrderedDict: replace with built-in collections.OrderedDict (#367)
* replace internal `OrderedDict` with `collections` version * handle API removals: use deprecation metadata: display reason to user
1 parent aaa1311 commit 3490190

File tree

4 files changed

+33
-174
lines changed

4 files changed

+33
-174
lines changed

src/PyPop/_deprecations.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,14 @@
124124
"reason": "Lowercased for PEP8 compliance.",
125125
"changed": "1.4.0",
126126
},
127+
"PyPop.Utils.OrderedDict": {
128+
"removed": "1.4.0",
129+
"reason": "Obsolete, replaced with :class:`collections.OrderedDict`",
130+
},
131+
"PyPop.Utils.Index": {
132+
"removed": "1.4.0",
133+
"reason": "Obsolete, replaced with :class:`collections.OrderedDict` with it's own ``Index`` class",
134+
},
127135
"PyPop.GUIApp": {
128136
"removed": "1.4.0",
129137
"reason": "Obsolete, never fully implemented a full ``wxPython`` UI. Replaced by built-in Tkinter file-picker",
@@ -153,10 +161,15 @@ def __init__(self, mapping):
153161
self.mapping = mapping
154162

155163
def find_spec(self, fullname, _path, _target=None):
156-
if fullname in self.mapping:
157-
info = self.mapping[fullname]
164+
if fullname not in self.mapping:
165+
return None
166+
167+
info = self.mapping[fullname]
168+
reason = info.get("reason", "")
169+
170+
# ---- Case 1: renamed module ----
171+
if "new" in info:
158172
new_name = info["new"]
159-
reason = info.get("reason", "")
160173

161174
# Import the replacement module
162175
module = importlib.import_module(new_name)
@@ -178,4 +191,14 @@ def find_spec(self, fullname, _path, _target=None):
178191
# Return the spec for the module so import machinery can continue
179192
return module.__spec__
180193

194+
# ---- Case 2: removed module ----
195+
if "removed" in info:
196+
removed_in = info["removed"]
197+
198+
msg = f"Module '{fullname}' was removed in PyPop {removed_in}."
199+
if reason:
200+
msg += f" {reason}"
201+
202+
raise ModuleNotFoundError(msg)
203+
181204
return None

src/PyPop/parsers.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,10 @@
4646
"""
4747

4848
import operator
49+
from collections import OrderedDict
4950

5051
from PyPop import logger
51-
from PyPop.utils import OrderedDict, StringMatrix, getStreamType
52+
from PyPop.utils import StringMatrix, getStreamType
5253

5354

5455
class ParseFile:
@@ -210,7 +211,7 @@ def _mapFields(self, line, fieldList):
210211
# and inserting `HLA-A', or `DQB1_1' and `DQB1_2' should
211212
# both be inserted at `DQB1'
212213

213-
if assoc.has_key(key):
214+
if key in assoc:
214215
assoc[key] = assoc[key], i
215216
else:
216217
assoc[key] = i
@@ -465,10 +466,10 @@ def _genDataStructures(self):
465466
self.totalLocusCount = len(self.alleleMap)
466467

467468
# freeze the list of locusKeys in a particular order
468-
self.locusKeys = self.alleleMap.keys()
469+
self.locusKeys = list(self.alleleMap.keys())
469470

470471
# freeze list of non-allel data
471-
self.extraKeys = self.nonAlleleMap.keys()
472+
self.extraKeys = list(self.nonAlleleMap.keys())
472473

473474
# create an empty-list of lists to store all the row data
474475
# self.individualsList = [[] for line in range(0, self.totalIndivCount)]
@@ -634,7 +635,7 @@ def _genDataStructures(self):
634635
logger.debug("sampleMap keys: %s", self.sampleMap.keys())
635636
logger.debug("sampleMap values: %s", self.sampleMap.values())
636637

637-
self.locusName = self.sampleMap.keys()[0]
638+
self.locusName = next(iter(self.sampleMap))
638639

639640
# turn this into a pseudo-genotype data matrix
640641

src/PyPop/utils.py

Lines changed: 0 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -782,171 +782,6 @@ def __getitem__(self, group):
782782
return self.li[idx : idx + self.size]
783783

784784

785-
class OrderedDict:
786-
"""A dictionary class with **ordered** pairs.
787-
788-
.. deprecated:: 1.3.1
789-
790-
Will be removed in a later release, to be replaced by internal
791-
Python version
792-
793-
"""
794-
795-
__version__ = "1.1"
796-
797-
def __init__(self, hash=None):
798-
"""Creates an ordered dict."""
799-
if hash is None:
800-
hash = []
801-
self.__hash = {}
802-
self.KEYS = []
803-
804-
while hash:
805-
k, v, hash = hash[0], hash[1], hash[2:]
806-
self.__hash[k] = v
807-
self.KEYS.append(k)
808-
809-
def __addval__(self, key, value):
810-
"""Internal function to add/change key-value pair (at end)."""
811-
try:
812-
self.KEYS.index(key)
813-
except Exception:
814-
self.__hash[key] = value
815-
self.KEYS.append(key)
816-
else:
817-
self.__hash[key] = value
818-
819-
def __setitem__(self, i, hash):
820-
"""Adds key-value pairs (existing keys not moved)."""
821-
if type(i) is type(Index()):
822-
del self.__hash[self.KEYS[i.i]]
823-
if len(hash) != 1:
824-
self.KEYS[i.i], hash = hash[0], hash[1:]
825-
self.__hash[self.KEYS[i.i]] = hash[0]
826-
else:
827-
self.__addval__(i, hash)
828-
829-
def __getitem__(self, key):
830-
"""Returns value of given key."""
831-
if type(key) is type(Index()):
832-
key = self.KEYS[key.i]
833-
return [key, self.__hash[key]]
834-
return self.__hash[key]
835-
836-
def __len__(self):
837-
"""Returns the number of pairs in the dict."""
838-
return len(self.KEYS)
839-
840-
def index(self, key):
841-
"""Returns position of key in dict."""
842-
return self.KEYS.index(key)
843-
844-
def keys(self):
845-
"""Returns list of keys in dict."""
846-
return self.KEYS
847-
848-
def values(self):
849-
"""Returns list of values in dict."""
850-
ret = []
851-
for key in self.KEYS:
852-
ret.append(self.__hash[key])
853-
return ret
854-
855-
def items(self):
856-
"""Returns list of tuples of keys and values."""
857-
ret = []
858-
for key in self.KEYS:
859-
ret.append((key, self.__hash[key]))
860-
return ret
861-
862-
def insert(self, i, key, value):
863-
"""Inserts a key-value pair at a given index."""
864-
InsertError = "Duplicate key entry"
865-
if key in self.__hash:
866-
raise InsertError
867-
self.KEYS.insert(i, key)
868-
self.__hash[key] = value
869-
870-
def remove(self, i):
871-
"""Removes a key-value pair from the dict."""
872-
del self.__hash[i]
873-
self.KEYS.remove(i)
874-
875-
def __delitem__(self, i):
876-
"""Removes a key-value pair from the dict."""
877-
if type(i) is not type(Index()):
878-
i = Index(self.KEYS.index(i))
879-
del self.__hash[self.KEYS[i.i]]
880-
del self.KEYS[i.i]
881-
882-
def reverse(self):
883-
"""Reverses the order of the key-value pairs."""
884-
self.KEYS.reverse()
885-
886-
def sort(self, cmp=0):
887-
"""Sorts the dict (allows for sort algorithm)."""
888-
if cmp:
889-
self.KEYS.sort(cmp)
890-
else:
891-
self.KEYS.sort()
892-
893-
def clear(self):
894-
"""Clears all the entries in the dict."""
895-
self.__hash = {}
896-
self.KEYS = []
897-
898-
def copy(self):
899-
"""Makes copy of dict, also of OrderdDict class."""
900-
hash = OrderedDict()
901-
hash.KEYS = self.KEYS[:]
902-
hash.__hash = self.__hash.copy()
903-
return hash
904-
905-
def get(self, key):
906-
"""Returns the value of a key."""
907-
return self.__hash[key]
908-
909-
def has_key(self, key):
910-
"""Looks for existence of key in dict."""
911-
return key in self.__hash
912-
913-
def update(self, dict):
914-
"""Updates entries in a dict based on another."""
915-
self.__hash.update(dict)
916-
917-
def count(self, key):
918-
"""Finds occurrences of a key in a dict (0/1)."""
919-
return key in self.__hash
920-
921-
def __getslice__(self, i, j):
922-
"""Returns an OrderedDict of key-value pairs from a dict."""
923-
ret = []
924-
for x in range(i, j):
925-
ret.append(self.KEYS[x])
926-
ret.append(self.__hash[self.KEYS[x]])
927-
return OrderedDict(ret)
928-
929-
def __setslice__(self, i, j, hash):
930-
"""Sets a slice of elements from the dict."""
931-
hash = list(hash)
932-
for x in range(i, j):
933-
k, v, hash = hash[0], hash[1], hash[2:]
934-
self.__setitem__(Index(x), [k, v])
935-
936-
937-
class Index:
938-
"""Returns an Index object for :class:`OrderedDict`.
939-
940-
.. deprecated:: 1.3.1
941-
942-
Will be removed in a later release, to be replaced by internal
943-
Python version
944-
"""
945-
946-
def __init__(self, i=0):
947-
self.i = i
948-
949-
950785
### global FUNCTIONS start here
951786

952787

website/helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ def parse_ver(v):
292292

293293
elif status == "removed":
294294
lines.append(f".. versionremoved:: {version}")
295-
lines.append(INDENT + "The following modules were removed:")
295+
lines.append(INDENT + "The following modules or classes were removed:")
296296
lines.append("")
297297
for old, new, reason in sorted(items):
298298
lines.append(f"{BULLET_PREFIX}:mod:`{old}`")

0 commit comments

Comments
 (0)