Skip to content
New issue

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

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

Already on GitHub? Sign in 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 <[email protected]>
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 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in 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