A short preview should not end with half of “universe.” Yet textwrap.shorten("hello universe", width=7, placeholder="") produces hello u on the Python versions tested here. If your contract is to retain only complete whitespace-separated words, set both break_long_words=False and break_on_hyphens=False. Then decide what should happen when even the first word cannot fit. An empty result can be correct under that contract.
Reproduce the partial word before changing punctuation
This fixture contains no punctuation. It separates the observed output from a guess that commas, periods, or Unicode punctuation caused the cut. Run it with the same interpreter that runs your application.
from textwrap import shorten
text = "hello universe"
assert shorten(text, width=7, placeholder="") == "hello u"
assert shorten(
text, width=7, placeholder="",
break_long_words=False,
break_on_hyphens=False,
) == "hello"
print("partial-word and complete-word cases passed")The historical Python issue linked in the sources reports this kind of surprise. It establishes a real reader problem, not present-day search volume or a promise of traffic. The examples on this page were independently executed on Python 3.11.6, 3.13.2, and 3.14.3. They describe those observed cases rather than claiming every possible input has been tested.
Test the hyphen boundary separately
Disabling long-word splitting does not express a policy about hyphens. In this fixture, alpha- is a possible retained chunk when the placeholder needs the rest of the budget. Keeping the whole hyphenated token requires the second option too.
from textwrap import shorten
text = "alpha-beta gamma"
assert shorten(
text, width=12, break_long_words=False,
) == "alpha- [...]"
assert shorten(
text, width=12,
break_long_words=False,
break_on_hyphens=False,
) == "[...]"
print("hyphen boundary cases passed")Use a product example to choose the behavior. For a preview of a human sentence, preserving alpha-beta may be preferable to retaining alpha-. For an identifier, preserving spelling may be mandatory. In both cases, showing only the marker can be more honest than displaying a fragment that looks like a complete value. Do not silently replace an identifier with its preview in a stored record or a lookup key.
Decide what the placeholder means
Reserve space for the marker in your example expectations. A marker is part of the output, so a preview budget is not simply a budget for the retained words. The following cases deliberately exercise the empty result, marker-only result, exact fit, and invalid marker budget.
from textwrap import shorten
def preview(text, width, marker="..."):
return shorten(
text, width=width, placeholder=marker,
break_long_words=False,
break_on_hyphens=False,
)
assert preview("universe", 7, "") == ""
assert preview("universe", 7) == "..."
assert preview("hello world", 8) == "hello..."
assert preview("hello world", 11) == "hello world"
try:
preview("hello world", 2)
except ValueError:
pass
else:
raise AssertionError("expected an invalid placeholder budget")
print("placeholder policy cases passed")For an application that must always show meaningful text, define the fallback separately: a generic label, the original value in a detail view, or a different preview contract. Do not remove the complete-word requirement in an exception handler without making that change visible to callers. The preview helper is deliberately small and uses the library's validation; it is not a universal policy for user interfaces.
Check whitespace normalization before blaming a flag
The official reference states that shorten normalizes whitespace before wrapping. Its whitespace-related wrapping switches cannot preserve the original layout at that point. This local fixture is useful when a multiline log, tab-delimited value, or pasted paragraph seems to lose formatting.
from textwrap import shorten
text = " alpha\t beta\n gamma "
expected = "alpha beta gamma"
assert shorten(text, width=80) == expected
assert shorten(
text, width=80,
replace_whitespace=False,
expand_tabs=False,
) == expected
assert text == " alpha\t beta\n gamma "
print("normalized preview; original input unchanged")Keep the original value when formatting matters. A preview can be a derived display field while the original remains available for export or investigation. Our test checks that distinction explicitly: the returned value changes and the input variable still contains tabs and a newline. It does not test byte-for-byte file round trips, terminal column alignment, or rendering in a proportional font.
Match the test to the actual output contract
Add the smallest relevant cases to the caller's checks: ordinary words, one oversized first token, a hyphenated token, normalized whitespace, and a width smaller than the chosen marker. The assertions above provide reproducible examples. Replace their sample strings with representative application values before relying on them as acceptance criteria.
A Python string-length budget also does not establish visual pixel width, language-model token count, or a guarantee about user-perceived character boundaries. If the requirement is “fit this card,” inspect the rendered card with its actual font and language. If the requirement is “keep the original log layout,” a normalized single-line preview is a different output. State which contract you need before selecting a truncation tool.
For this guide, the acceptance condition is narrower: complete whitespace-separated tokens, hyphenated tokens retained as units, a specified marker, and explicit handling of a token that cannot fit. All displayed code is self-contained and uses only the standard library. No package installation or external request is needed to reproduce it.