adieyal / sd-dynamic-prompts

A custom script for AUTOMATIC1111/stable-diffusion-webui to implement a tiny template language for random prompt generation
MIT License
2.03k stars 262 forks source link

RuntimeError: generator raised StopIteration on template evaluation (w/ wildcards) #542

Open alkomio opened 1 year ago

alkomio commented 1 year ago

Ahoy. I encounter this exception very regularly (probably due to the fact that I am using a lot of wildcards. Unfortunately this error results in any template in the prompt to not being replaced at all, meaning the generation starts with every single template option / wildcard filename and a flock of wild curly brackets in the prompt. Here is a stacktrace. More details below that.

Stacktrace:

Traceback (most recent call last):
      File "F:\stable-diffusion-webui\modules\scripts.py", line 474, in process
        script.process(p, *script_args)
      File "F:\stable-diffusion-webui\extensions\sd-dynamic-prompts\sd_dynamic_prompts\dynamic_prompting.py", line 478, in process
        all_prompts, all_negative_prompts = generate_prompts(
      File "F:\stable-diffusion-webui\extensions\sd-dynamic-prompts\sd_dynamic_prompts\helpers.py", line 93, in generate_prompts
        all_prompts = prompt_generator.generate(prompt, num_prompts, seeds=seeds) or [""]
      File "F:\stable-diffusion-webui\venv\lib\site-packages\dynamicprompts\generators\randomprompt.py", line 71, in generate
        prompts.append(next(iter(gen)))
      File "F:\stable-diffusion-webui\venv\lib\site-packages\dynamicprompts\sampling_context.py", line 128, in <genexpr>
        gen = (squash_whitespace(p) for p in gen)
      File "F:\stable-diffusion-webui\venv\lib\site-packages\dynamicprompts\samplers\base.py", line 75, in _get_sequence
        yield rotate_and_join(sub_generators, separator=command.separator)
      File "F:\stable-diffusion-webui\venv\lib\site-packages\dynamicprompts\utils.py", line 43, in rotate_and_join
        return separator.join(rotate_all(generators))
      File "F:\stable-diffusion-webui\venv\lib\site-packages\dynamicprompts\utils.py", line 35, in rotate_all
        return [next(gen) for gen in generators]
      File "F:\stable-diffusion-webui\venv\lib\site-packages\dynamicprompts\utils.py", line 35, in <listcomp>
        return [next(gen) for gen in generators]
      File "F:\stable-diffusion-webui\venv\lib\site-packages\dynamicprompts\samplers\random.py", line 99, in _get_variant
        yield rotate_and_join(
      File "F:\stable-diffusion-webui\venv\lib\site-packages\dynamicprompts\utils.py", line 43, in rotate_and_join
        return separator.join(rotate_all(generators))
      File "F:\stable-diffusion-webui\venv\lib\site-packages\dynamicprompts\utils.py", line 35, in rotate_all
        return [next(gen) for gen in generators]
      File "F:\stable-diffusion-webui\venv\lib\site-packages\dynamicprompts\utils.py", line 35, in <listcomp>
        return [next(gen) for gen in generators]
      File "F:\stable-diffusion-webui\venv\lib\site-packages\dynamicprompts\samplers\random.py", line 72, in _get_variant
        yield from self._get_variant(wildcard_variant, context)
      File "F:\stable-diffusion-webui\venv\lib\site-packages\dynamicprompts\samplers\random.py", line 74, in _get_variant
        yield from context.generator_from_command(
    RuntimeError: generator raised StopIteration

I did a bit of research (but keep in mind that I never touched python in my life) and apparently this is raised due to a change that was introduced 2018 in Python 3.7: PEP 479 is enabled for all code in Python 3.7, meaning that StopIteration exceptions raised directly or indirectly in coroutines and generators are transformed into RuntimeError exceptions. (Contributed by Yury Selivanov in bpo-32670.) Before that, a StopIteration exception raised by a generator - indicating that it has reached the end of it's life - was silently ignored. This also means that downgrading Python results in the templates not being evaluated as well, it just happens silently. Checking the "Automatically purge wildcard cache on every generation." option does not prevent this exception from happening even on 1x1 generations, so this is unfortunately not a possible workaround.

If any critical information is missing please inquire :)

narukaze132 commented 1 year ago

I'm getting the same issue. The thing is, I'm pretty sure this program hasn't existed for that long, so I don't think this error has been silently swallowed before this point.

Anyway, I did figure out the problem. The "rotate_all" function is trying to get the next entry from each of the generators, but not all of the generators have more entries to return (perhaps the length of each wildcard file plays a role here?), and so the next() function raises a StopIteration. Fortunately, there's a trivial fix: provide a default value for the next() function to return if the generator doesn't have any more values. In this case, an empty string will suffice.

I'll be submitting a pull request with the fix as soon as I've had the time to sort out some issues with my Git setup.