diff -r dd8f48ff9480 Lib/collections/__init__.py --- a/Lib/collections/__init__.py Tue Apr 14 00:15:42 2015 -0700 +++ b/Lib/collections/__init__.py Wed Apr 15 17:26:43 2015 -0400 @@ -1060,6 +1060,8 @@ def __float__(self): return float(self.data) def __complex__(self): return complex(self.data) def __hash__(self): return hash(self.data) + def __getnewargs__(self): + return (self.data[:],) def __eq__(self, string): if isinstance(string, UserString): @@ -1104,9 +1106,13 @@ __rmul__ = __mul__ def __mod__(self, args): return self.__class__(self.data % args) + def __rmod__(self, format): + return self.__class__(format % args) # the following methods are defined in alphabetical order: def capitalize(self): return self.__class__(self.data.capitalize()) + def casefold(self): + return self.__class__(self.data.casefold()) def center(self, width, *args): return self.__class__(self.data.center(width, *args)) def count(self, sub, start=0, end=_sys.maxsize): @@ -1129,6 +1135,8 @@ return self.data.find(sub, start, end) def format(self, *args, **kwds): return self.data.format(*args, **kwds) + def format_map(self, mapping): + return self.data.format_map(mapping) def index(self, sub, start=0, end=_sys.maxsize): return self.data.index(sub, start, end) def isalpha(self): return self.data.isalpha() @@ -1138,6 +1146,7 @@ def isidentifier(self): return self.data.isidentifier() def islower(self): return self.data.islower() def isnumeric(self): return self.data.isnumeric() + def isprintable(self): return self.data.isprintable() def isspace(self): return self.data.isspace() def istitle(self): return self.data.istitle() def isupper(self): return self.data.isupper() @@ -1146,6 +1155,7 @@ return self.__class__(self.data.ljust(width, *args)) def lower(self): return self.__class__(self.data.lower()) def lstrip(self, chars=None): return self.__class__(self.data.lstrip(chars)) + maketrans = str.maketrans def partition(self, sep): return self.data.partition(sep) def replace(self, old, new, maxsplit=-1): diff -r dd8f48ff9480 Lib/test/test_collections.py --- a/Lib/test/test_collections.py Tue Apr 14 00:15:42 2015 -0700 +++ b/Lib/test/test_collections.py Wed Apr 15 17:26:43 2015 -0400 @@ -11,9 +11,9 @@ import keyword import re import sys -from collections import UserDict from collections import ChainMap from collections import deque +from collections import UserString, UserList, UserDict from collections.abc import Hashable, Iterable, Iterator from collections.abc import Sized, Container, Callable from collections.abc import Set, MutableSet @@ -22,6 +22,26 @@ from collections.abc import ByteString +class TestUserObjects(unittest.TestCase): + def _superset_test(self, a, b): + self.assertGreaterEqual( + set(dir(a)), + set(dir(b)), + '{a} should have all the methods of {b}'.format( + a=a.__name__, + b=b.__name__, + ), + ) + def test_str_protocol(self): + self._superset_test(UserString, str) + + def test_list_protocol(self): + self._superset_test(UserList, list) + + def test_dict_protocol(self): + self._superset_test(UserDict, dict) + + ################################################################################ ### ChainMap (helper class for configparser and the string module) ################################################################################ @@ -1642,7 +1662,8 @@ NamedTupleDocs = doctest.DocTestSuite(module=collections) test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs, TestCounter, TestChainMap, - TestOrderedDict, GeneralMappingTests, SubclassMappingTests] + TestOrderedDict, GeneralMappingTests, SubclassMappingTests, + TestUserObjects] support.run_unittest(*test_classes) support.run_doctest(collections, verbose) diff -r dd8f48ff9480 Misc/NEWS --- a/Misc/NEWS Tue Apr 14 00:15:42 2015 -0700 +++ b/Misc/NEWS Wed Apr 15 17:26:43 2015 -0400 @@ -31,6 +31,8 @@ Library ------- +- Issue #22189: Adds missing methods to collections.UserString. + - Issue #21116: Avoid blowing memory when allocating a multiprocessing shared array that's larger than 50% of the available RAM. Patch by Médéric Boquien.