From 1e27b57dbc8c1b758e37a531487813aef2d111ca Mon Sep 17 00:00:00 2001 From: masklinn Date: Sat, 19 Dec 2020 05:33:36 +0100 Subject: [PATCH] bpo-42470: Do not warn on sequences which are also sets in random.sample() (GH-23665) --- Lib/random.py | 13 +++++++------ Lib/test/test_random.py | 18 +++++++++++++++++- .../2020-12-06-12-00-00.bpo-42470.iqtC4L.rst | 1 + 3 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-06-12-00-00.bpo-42470.iqtC4L.rst diff --git a/Lib/random.py b/Lib/random.py index 139e8a40bb2..66433baa8cc 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -424,13 +424,14 @@ class Random(_random.Random): # too many calls to _randbelow(), making them slower and # causing them to eat more entropy than necessary. - if isinstance(population, _Set): - _warn('Sampling from a set deprecated\n' - 'since Python 3.9 and will be removed in a subsequent version.', - DeprecationWarning, 2) - population = tuple(population) if not isinstance(population, _Sequence): - raise TypeError("Population must be a sequence. For dicts or sets, use sorted(d).") + if isinstance(population, _Set): + _warn('Sampling from a set deprecated\n' + 'since Python 3.9 and will be removed in a subsequent version.', + DeprecationWarning, 2) + population = tuple(population) + else: + raise TypeError("Population must be a sequence. For dicts or sets, use sorted(d).") n = len(population) if counts is not None: cum_counts = list(_accumulate(counts)) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index 0c1fdeec991..327bfa3bbda 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -11,7 +11,7 @@ from functools import partial from math import log, exp, pi, fsum, sin, factorial from test import support from fractions import Fraction -from collections import Counter +from collections import abc, Counter class TestBasicOps: # Superclass with tests common to all generators. @@ -163,6 +163,22 @@ class TestBasicOps: population = {10, 20, 30, 40, 50, 60, 70} self.gen.sample(population, k=5) + def test_sample_on_seqsets(self): + class SeqSet(abc.Sequence, abc.Set): + def __init__(self, items): + self._items = items + + def __len__(self): + return len(self._items) + + def __getitem__(self, index): + return self._items[index] + + population = SeqSet([2, 4, 1, 3]) + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + self.gen.sample(population, k=2) + def test_sample_with_counts(self): sample = self.gen.sample diff --git a/Misc/NEWS.d/next/Library/2020-12-06-12-00-00.bpo-42470.iqtC4L.rst b/Misc/NEWS.d/next/Library/2020-12-06-12-00-00.bpo-42470.iqtC4L.rst new file mode 100644 index 00000000000..cd2edb65d7a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-06-12-00-00.bpo-42470.iqtC4L.rst @@ -0,0 +1 @@ +:func:`random.sample` no longer warns on a sequence which is also a set.