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

Python · 5 lines
ListOutputParser(
    min_items: int = 0,
    max_items: Optional[int] = None,
    item_transform: Optional[Callable[[str], str]] = None,
)
NameRequiredDefaultNotes
min_itemsNo0Enforced after extraction and transform.
max_itemsNoNoneNo upper bound if unset.
item_transformNoNoneApplied to every extracted item string (e.g. str.lower) before the min/max checks.

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

Python · 5 lines
_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

Python
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 below min_items (checked after item_transform).
  • ParsingError(f"Found {n} item(s), but maximum allowed is {max_items}.", ...) if above max_items.

Algorithm (_extract_list_items, two-pass):

  1. 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).
  2. 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.

Python · 9 lines
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, or None.

Examples

Python · 24 lines
# 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_items when 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_RE to 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.
  • BaseOutputParser, ParsingError
  • OutputParser — the orchestrator's internal _parse_list implements a similar but distinct algorithm (single combined regex per style, comma fallback with no skip-line filtering).

Version History

Not determinable from source.

Related pages