bpo-42163, bpo-42189, bpo-42659: Support uname_tuple._replace (for all but processor) (#23010)

* Add test capturing missed expectation with uname_result._replace.

* bpo-42163: Override uname_result._make to allow uname_result._replace to work (for everything but 'processor'.

* Replace hard-coded length with one derived from the definition.

* Add test capturing missed expectation with copy/deepcopy on namedtuple (bpo-42189).

* bpo-42189: Exclude processor parameter when constructing uname_result.

* In _make, rely on __new__ to strip processor.

* Add blurb.

* iter is not necessary here.

* Rely on num_fields in __new__

* Add test for slices on uname

* Add test for copy and pickle.

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>

* import pickle

* Fix equality test after pickling.

* Simply rely on __reduce__ for pickling.

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
Jason R. Coombs 2020-12-31 14:08:03 -05:00 committed by GitHub
parent dfdca85dfa
commit a6fd0f414c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 2 deletions

View File

@ -769,7 +769,7 @@ class uname_result(
):
"""
A uname_result that's largely compatible with a
simple namedtuple except that 'platform' is
simple namedtuple except that 'processor' is
resolved late and cached to avoid calling "uname"
except when needed.
"""
@ -784,12 +784,25 @@ class uname_result(
(self.processor,)
)
@classmethod
def _make(cls, iterable):
# override factory to affect length check
num_fields = len(cls._fields)
result = cls.__new__(cls, *iterable)
if len(result) != num_fields + 1:
msg = f'Expected {num_fields} arguments, got {len(result)}'
raise TypeError(msg)
return result
def __getitem__(self, key):
return tuple(iter(self))[key]
return tuple(self)[key]
def __len__(self):
return len(tuple(iter(self)))
def __reduce__(self):
return uname_result, tuple(self)[:len(self._fields)]
_uname_cache = None

View File

@ -1,4 +1,6 @@
import os
import copy
import pickle
import platform
import subprocess
import sys
@ -234,6 +236,38 @@ class PlatformTest(unittest.TestCase):
)
self.assertEqual(tuple(res), expected)
def test_uname_replace(self):
res = platform.uname()
new = res._replace(
system='system', node='node', release='release',
version='version', machine='machine')
self.assertEqual(new.system, 'system')
self.assertEqual(new.node, 'node')
self.assertEqual(new.release, 'release')
self.assertEqual(new.version, 'version')
self.assertEqual(new.machine, 'machine')
# processor cannot be replaced
self.assertEqual(new.processor, res.processor)
def test_uname_copy(self):
uname = platform.uname()
self.assertEqual(copy.copy(uname), uname)
self.assertEqual(copy.deepcopy(uname), uname)
def test_uname_pickle(self):
orig = platform.uname()
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
with self.subTest(protocol=proto):
pickled = pickle.dumps(orig, proto)
restored = pickle.loads(pickled)
self.assertEqual(restored, orig)
def test_uname_slices(self):
res = platform.uname()
expected = tuple(res)
self.assertEqual(res[:], expected)
self.assertEqual(res[:5], expected[:5])
@unittest.skipIf(sys.platform in ['win32', 'OpenVMS'], "uname -p not used")
def test_uname_processor(self):
"""

View File

@ -0,0 +1 @@
Restore compatibility for ``uname_result`` around deepcopy and _replace.