List Converter — Python source
Transform a list between separators (newline, comma, space, pipe, semicolon, tab) with trim, dedupe, sort, and empty-removal options. Runs entirely in your browser, with a shareable link.
This is the Python implementation — the same logic the interactive tool runs, in a shareable, citable form.
"""list-converter — convert lists between separators (newline/comma/space/pipe/...).
Language: Python (3.9+, standard library only)
Source: CosmoDev polyglot showcase port of the List Converter tool, ported from
cli/list-converter/list-converter.go (the Go CLI twin), which is itself
the lock-step mirror of src/lib/list-converter.ts (the canonical
TypeScript implementation).
License: display source — part of CosmoDev's polyglot tool pages.
Design goals:
- Pure + deterministic; never raises.
- Functionally equivalent to the Go twin: same inputs -> same outputs.
- Self-contained: stdlib only (no pip packages).
Pipeline: split on the "from" separator -> (trim each item) -> (drop empties)
-> (dedup, optionally case-insensitive, first occurrence wins) -> (stable sort,
optionally case-insensitive) -> join with the "to" separator. ``Separator`` and
``ListOptions`` mirror the Go types exactly; defaults are from=newline,
to=comma (the TS ``resolveSep`` fallbacks).
"""
from __future__ import annotations
from dataclasses import dataclass
from enum import Enum
from typing import List, Optional
__all__ = ["Separator", "ListOptions", "convert", "convert_default"]
class Separator(Enum):
"""A built-in list separator. Mirrors the Go twin's ``Separator`` enum;
the default ``NEWLINE`` matches the TS ``from`` default."""
NEWLINE = "\n"
COMMA = ","
SPACE = " "
PIPE = "|"
SEMICOLON = ";"
TAB = "\t"
@classmethod
def from_name(cls, name: str) -> "Separator":
"""Resolve by the TS-style lowercase name (``"comma"``, ``"newline"``
...). Falls back to treating ``name`` as a literal separator string —
but since this port mirrors the enum-only Go twin, callers normally
pass the enum directly. Provided for API symmetry with the TS source."""
lookup = {
"newline": cls.NEWLINE,
"comma": cls.COMMA,
"space": cls.SPACE,
"pipe": cls.PIPE,
"semicolon": cls.SEMICOLON,
"tab": cls.TAB,
}
return lookup[name] if name in lookup else cls(name)
@dataclass
class ListOptions:
"""Options mirror the Go twin's ``Options`` struct.
Every field defaults to the TS default, so callers can construct the object
incrementally with keyword args (a dataclass gives that for free and keeps
the option set self-documenting).
"""
from_: Separator = Separator.NEWLINE
"""Source separator. (Trailing underscore avoids the ``from`` keyword.)"""
to: Separator = Separator.COMMA
"""Target separator."""
trim: bool = False
"""``str.strip()`` each split item (runs before ``remove_empty``)."""
remove_empty: bool = False
"""Drop items equal to ``""`` (after ``trim`` if enabled)."""
unique: bool = False
"""Keep the first occurrence of each item, dropping later duplicates."""
sort: bool = False
"""Stable-sort the items ascending."""
case_insensitive: bool = False
"""When set, ``unique``/``sort`` compare lowercased keys but keep original
casing in the output. Mirrors Go's ``CaseInsensitive`` flag."""
def convert(input: str, options: Optional[ListOptions] = None) -> str:
"""Convert a list between separators. Never raises; an empty ``input``
simply yields a one-item list joined back together (mirroring Go's
``strings.Split("", sep) == [""]``)."""
if options is None:
options = ListOptions()
items: List[str] = input.split(options.from_.value)
if options.trim:
items = [s.strip() for s in items]
if options.remove_empty:
items = [s for s in items if s != ""]
if options.unique:
# Keyed by the (optionally lowercased) value; the first-seen item
# survives with its original casing. dict preserves insertion order
# and dedups by key, so one pass gives us both properties.
seen: dict[str, str] = {}
for s in items:
key = s.lower() if options.case_insensitive else s
if key not in seen:
seen[key] = s
items = list(seen.values())
if options.sort:
# sorted() is stable; key lowercases only for comparison when
# case_insensitive is set, leaving the stored values untouched.
items = sorted(
items,
key=lambda s: s.lower() if options.case_insensitive else s,
)
return options.to.value.join(items)
def convert_default(input: str) -> str:
"""Convenience wrapper using default options — the common "newline list to
a comma list" case (matches the tool's default From/To)."""
return convert(input, ListOptions())
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →