ListOutputParser (list_parser.py)
On this page
class output_parser.list_parser.ListOutputParser(BaseOutputParser)
Overview
Extracts a numbered, lettered, or bulleted list from raw text, returning a clean List[str]. Falls back to a comma-split heuristic if no explicit list markers are found. Depends only on base_parser.py and the standard library (re).
Constructor
ListOutputParser(
min_items: int = 0,
max_items: Optional[int] = None,
item_transform: Optional[Callable[[str], str]] = None,
)
Raises (at construction): ValueError("min_items must be >= 0") if negative; ValueError("max_items must be >= min_items") if max_items is set and less than min_items.
Class-level patterns
_NUMBERED_RE = re.compile(r"^\s*[\(\[]?\s*(?:\d+|[a-zA-Z])\s*[\.\)\]]\s+(.+)$")
_BULLET_RE = re.compile(r"^\s*[*\-–—•◦▪▸▷→›»]\s+(.+)$")
_SKIP_RE = re.compile(
r"^(here\s+(is|are)|the\s+(following|items?|list)|summary[:\s]|"
r"result[s]?[:\s]|output[:\s]|note[:\s]|example[:\s])", re.IGNORECASE)
_NUMBERED_RE matches numbered (1., 2)) and lettered (a., b)) items, optionally bracketed ((1), [a]). _BULLET_RE matches a broad set of bullet glyphs. _SKIP_RE identifies intro/outro lines to exclude from the comma-split fallback pass (not from the primary numbered/bulleted extraction — those patterns are specific enough not to need a skip list).
Public Methods
parse
def parse(self, text: str) -> List[str]
Raises:
ParsingError("Cannot parse empty text", ...)for empty input.ParsingError("No list items found. Expected a numbered or bulleted list.", ...)if extraction yields nothing.ParsingError(f"Found {n} item(s), but minimum required is {min_items}.", ...)if the count is belowmin_items(checked afteritem_transform).ParsingError(f"Found {n} item(s), but maximum allowed is {max_items}.", ...)if abovemax_items.
Algorithm (_extract_list_items, two-pass):
- Pass 1: iterates every line; for each non-empty line, tries
_match_list_item— first against_NUMBERED_RE, then_BULLET_RE. If any line matches, that pass's results are returned immediately (comma-fallback is skipped entirely if even one numbered/bulleted item was found). - Pass 2 (fallback, only reached if Pass 1 found nothing): scans lines for one that (a) isn't empty, (b) doesn't match
_SKIP_RE, (c) contains a comma, and (d) is under 500 characters. On the first such line, splits on,, strips each part, and returns the split if it yields ≥2 non-empty parts — from the first qualifying line only (does not aggregate across multiple lines).
Complexity: O(n) in text length — single or double line-by-line pass, no backtracking-heavy regex.
Thread Safety: Safe to share across threads — all patterns are class-level compiled regexes (shared, immutable), instance state is read-only config.
Side Effects: None beyond raising exceptions.
parser = ListOutputParser()
text = '''
Here are the steps:
1. Install dependencies
2. Configure settings
3. Run the application
'''
result = parser.parse(text)
# ['Install dependencies', 'Configure settings', 'Run the application']
get_format_instructions
Returns a numbered-list format instruction, appending min_items/max_items constraints if set, plus a 3-item numbered example.
Private Helpers
_extract_list_items(text) -> List[str]— see Algorithm above._match_list_item(line) -> Optional[str]— tries numbered then bulleted regex against a single stripped line; returns the captured content group, orNone.
Examples
# Basic — numbered
ListOutputParser().parse("1. First\n2. Second\n3. Third")
# ['First', 'Second', 'Third']
# Intermediate — bulleted, mixed glyphs
ListOutputParser().parse("- Alpha\n• Beta\n* Gamma")
# ['Alpha', 'Beta', 'Gamma']
# Advanced — item_transform + bounds
parser = ListOutputParser(min_items=2, max_items=5, item_transform=str.lower)
parser.parse("1. FOO\n2. BAR")
# ['foo', 'bar']
# Error handling — below min_items
parser = ListOutputParser(min_items=5)
try:
parser.parse("1. Only one item")
except ParsingError as e:
print(str(e)) # "Found 1 item(s), but minimum required is 5."
# Production usage — comma-fallback
parser = ListOutputParser()
parser.parse("The colors are: red, green, blue, yellow")
# ['red', 'green', 'blue', 'yellow'] -- via comma-split fallback since no numbered/bulleted markers present
Best Practices
- Set
min_itemswhen your prompt asks for "at least N items" so a truncated LLM response is caught as a parse error rather than silently accepted with fewer items. - Be aware that mixing numbered and bulleted markers in the same text still works (Pass 1 tries both patterns per line independently), but a text that's entirely comma-separated prose relies on the less-precise Pass 2 fallback — prefer explicit list-formatting instructions in your prompt when possible.
Common Mistakes
- Assuming the comma-fallback aggregates across multiple lines — it only returns items from the first line that qualifies (has a comma, isn't skip-listed, under 500 chars, and comma-split yields ≥2 parts). If your comma-separated content spans multiple lines, this fallback will not merge them.
- Expecting
_SKIP_REto filter the primary numbered/bulleted extraction — it's only consulted during the Pass 2 fallback. An intro line like"Here are the items: 1. thing"on a single physical line won't be an issue (the numbered regex requires the marker at line-start after optional whitespace), but a genuinely skip-worthy standalone header line will never suppress a legitimately-matching numbered/bulleted line elsewhere in the text — it isn't meant to.
Related APIs
BaseOutputParser,ParsingErrorOutputParser— the orchestrator's internal_parse_listimplements a similar but distinct algorithm (single combined regex per style, comma fallback with no skip-line filtering).
Version History
Not determinable from source.