Hello ! I think that I found a bug in the markup.escape function.
The bug
textual.markup.escape is documented as escaping text "so that it won't be interpreted as markup", but it leaves an outer [ unescaped when the bracketed region contains a nested [ before its closing ]. The "escaped" string then raises MarkupError when passed to to_content / Content.from_markup.
Real-world trigger: machine-generated strings like Pydantic v2 validation errors, e.g.
[type=value_error, input_value={'questions[0].header': ...}, input_type=dict].
MRE (Textual 8.2.7)
from textual.markup import escape, to_content
s = "[type=x, v={'a[0]'}]" # nested '[' inside an outer '[...]'
e = escape(s)
print(e == s) # True -> escape did nothing
to_content(e) # MarkupError: Expected markup value (found "={'a[0]'}]").
Cause
The escape pattern (\*)([[a-z#/@][^[]*?]) requires the tag-like segment to close with ] and forbids any [ in between ([^[]). An outer bracket containing a nested [ never matches, so it isn't escaped.
Hello ! I think that I found a bug in the markup.escape function.
The bug
textual.markup.escapeis documented as escaping text "so that it won't be interpreted as markup", but it leaves an outer[unescaped when the bracketed region contains a nested[before its closing]. The "escaped" string then raisesMarkupErrorwhen passed toto_content/Content.from_markup.Real-world trigger: machine-generated strings like Pydantic v2 validation errors, e.g.
[type=value_error, input_value={'questions[0].header': ...}, input_type=dict].MRE (Textual 8.2.7)
Cause
The escape pattern (\*)([[a-z#/@][^[]*?]) requires the tag-like segment to close with ] and forbids any [ in between ([^[]). An outer bracket containing a nested [ never matches, so it isn't escaped.