Checkbox does not stay checked when using random number for key

Hi,

I am running my app locally for now, and seem to be having trouble with the checkbox staying checked.
Working version:
It works well when I use a range of numbers for keys but since I am looping multiple times in my original code, I eventually will hit the duplicate widget ID error.

widget_id = (i for i in range(2))
for i in range(2):
   st.checkbox(f"Download latest {i}", key = next(widget_id))

Non working version:
To avoid that, I used a random number generator for the key. Now, the checkbox does not stay checked at all, throwing off the flow of my code.

def infinite_random_number(start:int=0, end:int=10):
    while True:
        yield random.randint(0,10)
widget_id = infinite_random_number()
for i in range(2):
    st.checkbox(f"Download latest {i}", key = next(widget_id))

All this was to avoid duplicate widget id error. I tried generating numbers in a large range but I ran out of unique keys looks like after some runs.
I searched through forums, etc. for solutions but seemed to settle on this which is causing this behavior.

Alternatively, if there is a good solution out there for doing multiple runs and not get duplicate widget id, I am open to that too.

Streamlit version:1.36.0
Python version:3.12

Thanks,
Anu

That is expected, a different key means a different widget with different state.

How do you hit the duplicate widget error using ranges? Your example does not show that. Ranges don’t have duplicates.

Thanks for the response.
This is my original code snippet.
I am trying to reproduce the problem now with this and am not able to (lot of experiments in the middle might have reset widget id values) but when I keep killing and restarting app multiple times, at some point, I hit the error. I cannot keep streamlit running since it is a shared test machine and I cannot block it for only this. I am thinking, that every restart the key gets assigned a new key and at some point, it hits duplicates. The other part was it seemed to be stuck at the first index for some reason.

#init to avoid out of index range error
input_latest_firmware = [i for i in range(5)]
input_customized_firmware = [i for i in range(5)]
version_filter = [i for i in range(5)]
input_customized_firmware_path = [i for i in range(5)]

firmware_types = ['fw_type1','fw_type2','fw_type3','fw_type4']    
widget_id = (i for i in range(10_000))
 
#customized firmware will provide options to filter by version or a custom path to copy from
    for i,type in enumerate(firmware_types, start =0):
        input_latest_firmware[i] = st.checkbox(f"Download latest {type} firmware",key = next(widget_id))
        input_customized_firmware[i] = st.checkbox(f"Customized {type} firmware", key = next(widget_id))
        if input_customized_firmware[i]:
            version_filter[i] = st.text_input(f"Requested {type} Version, use format x.x.x.xx: ")
            st.write(" OR ")
            input_customized_firmware_path[i] = st.text_input(f"Enter local path of {type} firmware hex file: ")
    download_ready = st.button("Download", key = next(widget_id))

The other thing I have been thinking of to get around with streamlit to continue to run is having a docker image with streamlit running all the time. The image is launched by user when required. I am relatively new to docker too so not sure if this is a fanciful thinking. I know I am going off on a tangent, but the duplicate widget id issue has been real and ate away a lot of my time, than me spending time on actually working on my app.

Thanks,
Anu

The only way I think this code can create duplicated keys is if there are duplicated firmware types. For example, if you have this:

firmware_types = ['fw_type1','fw_type1','fw_type3','fw_type4']

And you select “Customized fw_type1 firmware” twice, then duplicated text input widgets will be created. The way you generate the keys is irrelevant, since you are not assigning keys to these widgets.

I see. I do allow the users to pick between latest and customized between runs.
Run1:
fw_type1 could be with latest firmware checkbox and then press download.
Run2:
fw_type1 could be customized firmware checkbox and press download.
But they do have different keys depending on which one, latest or customized, because of the iterator.
Am I understanding this correctly.

I don’t understand what you mean here. I don’t think you can create duplicated widgets this way. I already told you how to trigger the error and why it happens.