Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

random.sample raises "IndexError: pop from empty list" when both "population" and "counts" are empty #130285

Closed
Dominik1123 opened this issue Feb 18, 2025 · 4 comments
Assignees
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@Dominik1123
Copy link
Contributor

Dominik1123 commented Feb 18, 2025

Bug report

Bug description:

I just encountered the situation where I used random.sample but both the population and counts arguments were empty (my algorithm had nothing left to choose from). So, basically this situation:

>>> random.sample([], 1, counts=[])
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    random.sample([], 1, counts=[])
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
  File "/path/to/lib/python3.14/random.py", line 424, in sample
    total = cum_counts.pop()
IndexError: pop from empty list

Instead of the IndexError, I expected a ValueError, similar to the following situations:

>>> random.sample([], 1)
Traceback (most recent call last):
  File "<python-input-2>", line 1, in <module>
    random.sample([], 1)
    ~~~~~~~~~~~~~^^^^^^^
  File "/path/to/lib/python3.14/random.py", line 434, in sample
    raise ValueError("Sample larger than population or is negative")
ValueError: Sample larger than population or is negative
>>> 
>>> random.sample([1], 2, counts=[1])
Traceback (most recent call last):
  File "<python-input-3>", line 1, in <module>
    random.sample([1], 2, counts=[1])
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
  File "/path/to/lib/python3.14/random.py", line 429, in sample
    selections = self.sample(range(total), k=k)
  File "/path/to/lib/python3.14/random.py", line 434, in sample
    raise ValueError("Sample larger than population or is negative")
ValueError: Sample larger than population or is negative

The docs mention that

If the sample size is larger than the population size, a ValueError is raised.

In addition, I would expect the following to work:

>>> random.sample([], 0, counts=[])
Traceback (most recent call last):
  File "<python-input-4>", line 1, in <module>
    random.sample([], 0, counts=[])
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
  File "/path/to/lib/python3.14/random.py", line 424, in sample
    total = cum_counts.pop()
IndexError: pop from empty list

similar to how it works when counts is not specified:

>>> random.sample([], 0)
[]

Not sure though what CPython's backwards-compatibility policy has to say here, since changing the exception type – or, in the second case, removing the exception altogether – might actually break someone's code...


Tested with:

Python 3.14.0a5 (main, Feb 12 2025, 14:51:40) [Clang 19.1.6 ] on linux
cpython-3.14.0a5-linux-x86_64-gnu

CPython versions tested on:

3.14

Operating systems tested on:

Linux

Linked PRs

@Dominik1123 Dominik1123 added the type-bug An unexpected behavior, bug, or error label Feb 18, 2025
@rhettinger rhettinger self-assigned this Feb 18, 2025
@rhettinger
Copy link
Contributor

Neither of these cases was tested or intended behavior, so it would be reasonable to fix them both. I'll work on a PR soonish. Thanks for the report.

Because of the possibility of breaking code, I'm -0 on backporting the edit.

@Dominik1123
Copy link
Contributor Author

Somewhat related is the situation when k=0 and all counts are zero:

>>> random.sample('abc', k=0, counts=[0,0,0])
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    random.sample('abc', k=0, counts=[0,0,0])
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/path/to/lib/python3.14/random.py", line 428, in sample
    raise ValueError('Total of counts must be greater than zero')
ValueError: Total of counts must be greater than zero

According to the docs:

Repeated elements can be specified one at a time or with the optional keyword-only counts parameter. For example, sample(['red', 'blue'], counts=[4, 2], k=5) is equivalent to sample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5).

So, extrapolating this to zero counts, this would be random.sample('abc', k=0, counts=[0,0,0]) is equivalent to random.sample([], k=0) which, however, returns [].

@StanFromIreland
Copy link
Contributor

StanFromIreland commented Feb 18, 2025

I propose we do

cum_counts = list(_accumulate(counts))

if not cum_counts:
    if k == 0:
        return []
    else:
        raise ValueError("Sample larger than population or is negative")

if len(cum_counts) != n:

And add tests, what do you think @rhettinger ? I see you are planning to do this

@Dominik1123
Copy link
Contributor Author

What about (random.py#L424)

total = cum_counts.pop() if cum_counts else 0
if not isinstance(total, int):
    raise TypeError('Counts must be integers')
if total < 0:
    raise ValueError('Total of counts must be non-negative')

That would also address the random.sample('abc', k=0, counts=[0,0,0]) == random.sample([], k=0) case.

If total == 0 and k > 0 this also wouldn't change the type of exception as it would become ValueError("Sample larger than population or is negative") instead.

rhettinger added a commit to rhettinger/cpython that referenced this issue Feb 19, 2025
@picnixz picnixz added the stdlib Python modules in the Lib dir label Feb 21, 2025
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Feb 21, 2025
…e() (pythongh-130291)

(cherry picked from commit 286c517)

Co-authored-by: Raymond Hettinger <rhettinger@users.noreply.github.com>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Feb 21, 2025
…e() (pythongh-130291)

(cherry picked from commit 286c517)

Co-authored-by: Raymond Hettinger <rhettinger@users.noreply.github.com>
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

4 participants