prompt-toolkit / prompt-toolkit/python-prompt-toolkit

Memory usage over time (many prompts via inquirerpy)

Open
#1,610 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
10.6k
Forks
815
PR merge metrics
No merged PRs in 30d

Description

Hi,
thanks a lot for this useful package.

Originally raised on inquirerpy (a prompt-toolkit wrapper); author advised to submit here instead:

I'm building an interactive app (with inquirerpy, not using asyncio) involving large lists and jumping back and forth instantiating new prompts on the way; it is intended to run for a while.
I noticed memory usage keeps growing and very little being released over time.

Am I right in assuming on event.app.exit() the prompt should exit and tear down entirely? Is there anything else I can/should do to reset/clean up?

Python 3.10.2 on windows (tags/v3.10.2:a58ebcc, Jan 17 2022, 13:59:55) [MSC v.1929 32 bit (Intel)]
inquirerpy==0.3.3
prompt-toolkit==3.0.28

Here's a simple demo to highlight the issue:

import time, random
from InquirerPy import inquirer
from pynput.keyboard import Key, Controller
from mem_top import mem_top

def makeChoices():
	for i in range(1000):
		words = "The value that should be presented to the user prior/after selection of the choice. This value is optional, if not provided, it will fallback to the string representation of value.".split()
		random.shuffle(words) # not needed to reproduce
		yield " ".join(words)

def getChoices():
	choices = []
	for choice in makeChoices(): choices.append(choice)
	return choices

def _prompt(i):
	inquirer.select(message="Testmem prompt" if i > 0 else "Press enter to start test", choices=getChoices(),
		default=None, show_cursor=False).execute()
	if (i < 100): # this runs in the next iteration
		for i in range(1000):
			keyboard.press(Key.down)
			keyboard.release(Key.down)
		keyboard.press(Key.enter)
		keyboard.release(Key.enter)

keyboard = Controller()

i = -1
while i < 100:
	i += 1
	time.sleep(0.5)
	_prompt(i)

print(mem_top())

"""
refs:
9093    <class 'prompt_toolkit.filters.base._AndCache'> {(~Condition(<function is_done at 0x03BE0FA0>), Condition(<function BaseComplexPrompt.__init__.<loca...
4001    <class 'prompt_toolkit.formatted_text.base.FormattedText'> FormattedText([('class:pointer', '❯'), ('class:marker', ' '), ('[SetCursorPosition]', ''), ('class:p...

types:
202428   <class 'dict'>
169534   <class 'prompt_toolkit.key_binding.key_bindings.Binding'>
155551   <class 'tuple'>
118098   <class 'list'>
59785    <class 'function'>
35636    <class 'frozenset'>
34023    <class 'prompt_toolkit.styles.base.Attrs'>
27188    <class 'cell'>
8699     <class 'collections.deque'>
8389     <class 'prompt_toolkit.cache.SimpleCache'>
"""

By the way, a feasible workaround is using multiprocessing for the prompts, however I'd prefer keeping things elegant and snappy.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the supplied Python 3.10 demo with inquirerpy and prompt-toolkit 3.0.28, then inspect the lifecycle around inquirer.select(...).execute() and event.app.exit(). Use the listed retained types and references as leads for determining what survives each prompt; done means identifying the retention cause and confirming memory is released or documenting the required cleanup.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
cli, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.