Skip to content

Upgrading MarkupSafe 2 to 3

Breaking2.1.5 → 3.0.4Breaking2Platform2Deprecated2Changed3Fixed3Other9

BreakingUpgrade verdict

2 breaking changes and 2 platform requirement changes.

  • Several text-manipulation methods on the safe string type no longer escape the text you pass in, so the result may contain unescaped markup.
  • Updates Markup method signatures to match str signatures, using positional-only arguments.
  • The library now works on the newest Python version, including a special build that runs without the global interpreter lock.
  • If you are still on Python 3.7 or 3.8, you cannot use this version and must upgrade Python first.
Top 5 of 6 that need code or config changes

Python requirement changed in 3.0.0: >=3.7 → >=3.9.

Breaking2
Some str methods on Markup no longer escape their argument: strip, lstrip, rstrip, removeprefix, removesuffix, partition, and rpartition; replace only escapes its new argument.
Markupstriplstriprstripremoveprefixremovesuffixpartitionrpartition
Updates Markup method signatures to match str signatures, using positional-only arguments.
Markup
Platform2
Adds support for Python 3.13 and its experimental free-threaded build.
Drops support for Python 3.7 and 3.8.
Deprecated2
__version__ now raises DeprecationWarning instead of UserWarning.
__version__
Deprecates the __version__ attribute in favor of feature detection or importlib.metadata.version("markupsafe").
__version__importlib.metadata.version()

Generated by DepDelta from published Python source. Not mixed with prose notes.

  • removed: class HasHTML(te.Protocol)
  • removed: export escape
  • removed: export escape_silent
  • removed: export soft_str
  • removed: field Markup.capitalize
  • removed: field Markup.casefold
  • removed: field Markup.center
  • removed: field Markup.expandtabs
  • removed: field Markup.ljust
  • removed: field Markup.lower
  • removed: field Markup.lstrip
  • removed: field Markup.removeprefix
  • removed: field Markup.removesuffix
  • removed: field Markup.replace
  • removed: field Markup.rjust
  • removed: field Markup.rstrip
  • removed: field Markup.strip
  • removed: field Markup.swapcase
  • removed: field Markup.title
  • removed: field Markup.translate
  • removed: field Markup.upper
  • removed: field Markup.zfill
  • changed: constructor EscapeFormatter(escape: t.Callable[[t.Any], Markup]) -> None → constructor EscapeFormatter(escape: _TPEscape) -> None
  • changed: method Markup.format_map(map: t.Mapping[str, t.Any]) -> te.Self → method Markup.format_map(mapping: cabc.Mapping[str, t.Any], /) -> te.Self
  • changed: method Markup.join(seq: t.Iterable[t.Union[str, HasHTML]]) -> te.Self → method Markup.join(iterable: cabc.Iterable[str | _HasHTML], /) -> te.Self
  • changed: method Markup.partition(sep: str) -> t.Tuple[te.Self, te.Self, te.Self] → method Markup.partition(sep: str, /) -> tuple[te.Self, te.Self, te.Self]
  • changed: method Markup.rpartition(sep: str) -> t.Tuple[te.Self, te.Self, te.Self] → method Markup.rpartition(sep: str, /) -> tuple[te.Self, te.Self, te.Self]
  • changed: method Markup.rsplit(sep: t.Optional[str]=…, maxsplit: int=…) -> t.List[te.Self] → method Markup.rsplit(sep: str | None=…, maxsplit: t.SupportsIndex=…) -> list[te.Self]
  • changed: method Markup.split(sep: t.Optional[str]=…, maxsplit: int=…) -> t.List[te.Self] → method Markup.split(sep: str | None=…, maxsplit: t.SupportsIndex=…) -> list[te.Self]
  • changed: method Markup.splitlines(keepends: bool=…) -> t.List[te.Self] → method Markup.splitlines(keepends: bool=…) -> list[te.Self]
  • changed: static method Markup.escape(s: t.Any) -> te.Self → static method Markup.escape(s: t.Any, /) -> te.Self
  • added: function escape(s: t.Any, /) -> Markup
  • added: function escape_silent(s: t.Any | None, /) -> Markup
  • added: function soft_str(s: t.Any, /) -> str
  • added: method Markup.capitalize() -> te.Self
  • added: method Markup.casefold() -> te.Self
  • added: method Markup.center(width: t.SupportsIndex, fillchar: str=…, /) -> te.Self
  • added: method Markup.expandtabs(tabsize: t.SupportsIndex=…) -> te.Self
  • added: method Markup.ljust(width: t.SupportsIndex, fillchar: str=…, /) -> te.Self
  • added: method Markup.lower() -> te.Self
  • added: method Markup.lstrip(chars: str | None=…, /) -> te.Self
  • added: method Markup.removeprefix(prefix: str, /) -> te.Self
  • added: method Markup.removesuffix(suffix: str) -> te.Self
  • added: method Markup.replace(old: str, new: str, count: t.SupportsIndex=…, /) -> te.Self
  • added: method Markup.rjust(width: t.SupportsIndex, fillchar: str=…, /) -> te.Self
  • added: method Markup.rstrip(chars: str | None=…, /) -> te.Self
  • added: method Markup.strip(chars: str | None=…, /) -> te.Self
  • added: method Markup.swapcase() -> te.Self
  • added: method Markup.title() -> te.Self
  • added: method Markup.translate(table: cabc.Mapping[int, str | int | None], /) -> str
  • added: method Markup.upper() -> te.Self
  • added: method Markup.zfill(width: t.SupportsIndex, /) -> te.Self