# Path: wikitextparser/_spans.py
# ATTRS_MATCH = regex_compile(
#     # Leading space is not required at the start of the attribute string.
#     ATTRS_PATTERN.replace(b'++', b'*+', 1),
# ).match
# 
# Path: wikitextparser/_tag.py
# class SubWikiTextWithAttrs(SubWikiText):
# 
#     """Define a class for SubWikiText objects that have attributes.
# 
#     Any class that is going to inherit from SubWikiTextWithAttrs should provide
#     _attrs_match property. Note that matching should be done on shadow.
#     It's usually a good idea to cache the _attrs_match property.
#     """
# 
#     __slots__ = '_attrs_match'
# 
#     @property
#     def attrs(self) -> Dict[str, str]:
#         """Return self attributes as a dictionary."""
#         spans = self._attrs_match.spans
#         string = self.string
#         return dict(zip(
#             (string[s:e] for s, e in spans('attr_name')),
#             (string[s:e] for s, e in spans('attr_value')),
#         ))
# 
#     def has_attr(self, attr_name: str) -> bool:
#         """Return True if self contains an attribute with the given name."""
#         string = self.string
#         return attr_name in (
#             string[s:e] for s, e in self._attrs_match.spans('attr_name')
#         )
# 
#     def get_attr(self, attr_name: str) -> Optional[str]:
#         """Return the value of the last attribute with the given name.
# 
#         Return None if the attr_name does not exist in self.
#         If there are already multiple attributes with the given name, only
#         return the value of the last one.
#         Return an empty string if the mentioned name is an empty attribute.
#         """
#         spans = self._attrs_match.spans
#         string = self.string
#         for i, (s, e) in enumerate(reversed(spans('attr_name'))):
#             if string[s:e] == attr_name:
#                 s, e = spans('attr_value')[-i - 1]
#                 return string[s:e]
#         return None
# 
#     def set_attr(self, attr_name: str, attr_value: str) -> None:
#         """Set the value for the given attribute name.
# 
#         If there are already multiple attributes with the given name, only
#         set the value for the last one.
#         If attr_value == '', use the implicit empty attribute syntax.
#         """
#         match = self._attrs_match
#         string = self.string
#         for i, (s, e) in enumerate(reversed(match.spans('attr_name'))):
#             if string[s:e] == attr_name:
#                 vs, ve = match.spans('attr_value')[-i - 1]
#                 q = 1 if match.string[ve] in b'"\'' else 0
#                 self[vs - q:ve + q] = '"{}"'.format(attr_value)
#                 return
#         # The attr_name is new, add a new attribute.
#         fmt = ' {}="{}"' if attr_value else ' {}'
#         self.insert(
#             match.end('attr_insert'),
#             fmt.format(attr_name, attr_value)
#         )
#         return
# 
#     def del_attr(self, attr_name: str) -> None:
#         """Delete all the attributes with the given name.
# 
#         Pass if the attr_name is not found in self.
#         """
#         match = self._attrs_match
#         string = self.string
#         # Must be done in reversed order because the spans
#         # change after each deletion.
#         for i, (s, e) in enumerate(reversed(match.spans('attr_name'))):
#             if string[s:e] == attr_name:
#                 start, stop = match.spans('attr')[-i - 1]
#                 del self[start:stop]


from typing import Dict, List, Match, MutableSequence, Union
from regex import DOTALL, VERBOSE, compile as regex_compile
from ._spans import ATTRS_MATCH
from ._tag import SubWikiTextWithAttrs
        self[s - offset:e - offset] = new_value

    @property
    def _attrs_match(self):
        """Return the match object for attributes."""
        cache, cache_string = self._attrs_match_cache
        string = self.string
        if cache_string == string:
            return cache
        s, e = self._match.span('attrs')
        attrs_match = ATTRS_MATCH(self._shadow, s, e)
        self._attrs_match_cache = attrs_match, string
        return attrs_match

    def set_attr(self, attr_name: str, attr_value: str) -> None:
        """Set the value for the given attribute name.

        If there are already multiple attributes with that name, only
        set the value for the last one.
        If attr_value == '', use the implicit empty attribute syntax.
        """
        # Note: The set_attr method of the parent class cannot be used instead
        # of this method because a cell could be without any attrs placeholder
        # which means the appropriate piping should be added around attrs by
        # this method. Also ATTRS_MATCH does not have any 'start' group.
        cell_match = self._match
        shadow = cell_match.string
        attrs_start, attrs_end = cell_match.span('attrs')
        if attrs_start != -1:
            encoded_attr_name = attr_name.encode()

# Path: wikitextparser/_spans.py
# ATTRS_MATCH = regex_compile(
#     # Leading space is not required at the start of the attribute string.
#     ATTRS_PATTERN.replace(b'++', b'*+', 1),
# ).match
# 
# Path: wikitextparser/_tag.py
# class SubWikiTextWithAttrs(SubWikiText):
# 
#     """Define a class for SubWikiText objects that have attributes.
# 
#     Any class that is going to inherit from SubWikiTextWithAttrs should provide
#     _attrs_match property. Note that matching should be done on shadow.
#     It's usually a good idea to cache the _attrs_match property.
#     """
# 
#     __slots__ = '_attrs_match'
# 
#     @property
#     def attrs(self) -> Dict[str, str]:
#         """Return self attributes as a dictionary."""
#         spans = self._attrs_match.spans
#         string = self.string
#         return dict(zip(
#             (string[s:e] for s, e in spans('attr_name')),
#             (string[s:e] for s, e in spans('attr_value')),
#         ))
# 
#     def has_attr(self, attr_name: str) -> bool:
#         """Return True if self contains an attribute with the given name."""
#         string = self.string
#         return attr_name in (
#             string[s:e] for s, e in self._attrs_match.spans('attr_name')
#         )
# 
#     def get_attr(self, attr_name: str) -> Optional[str]:
#         """Return the value of the last attribute with the given name.
# 
#         Return None if the attr_name does not exist in self.
#         If there are already multiple attributes with the given name, only
#         return the value of the last one.
#         Return an empty string if the mentioned name is an empty attribute.
#         """
#         spans = self._attrs_match.spans
#         string = self.string
#         for i, (s, e) in enumerate(reversed(spans('attr_name'))):
#             if string[s:e] == attr_name:
#                 s, e = spans('attr_value')[-i - 1]
#                 return string[s:e]
#         return None
# 
#     def set_attr(self, attr_name: str, attr_value: str) -> None:
#         """Set the value for the given attribute name.
# 
#         If there are already multiple attributes with the given name, only
#         set the value for the last one.
#         If attr_value == '', use the implicit empty attribute syntax.
#         """
#         match = self._attrs_match
#         string = self.string
#         for i, (s, e) in enumerate(reversed(match.spans('attr_name'))):
#             if string[s:e] == attr_name:
#                 vs, ve = match.spans('attr_value')[-i - 1]
#                 q = 1 if match.string[ve] in b'"\'' else 0
#                 self[vs - q:ve + q] = '"{}"'.format(attr_value)
#                 return
#         # The attr_name is new, add a new attribute.
#         fmt = ' {}="{}"' if attr_value else ' {}'
#         self.insert(
#             match.end('attr_insert'),
#             fmt.format(attr_name, attr_value)
#         )
#         return
# 
#     def del_attr(self, attr_name: str) -> None:
#         """Delete all the attributes with the given name.
# 
#         Pass if the attr_name is not found in self.
#         """
#         match = self._attrs_match
#         string = self.string
#         # Must be done in reversed order because the spans
#         # change after each deletion.
#         for i, (s, e) in enumerate(reversed(match.spans('attr_name'))):
#             if string[s:e] == attr_name:
#                 start, stop = match.spans('attr')[-i - 1]
#                 del self[start:stop]


# Path: wikitextparser/_cell.py
from typing import Dict, List, Match, MutableSequence, Union
from regex import DOTALL, VERBOSE, compile as regex_compile
from ._spans import ATTRS_MATCH
from ._tag import SubWikiTextWithAttrs

        self[s - offset:e - offset] = new_value

    @property
    def _attrs_match(self):
        """Return the match object for attributes."""
        cache, cache_string = self._attrs_match_cache
        string = self.string
        if cache_string == string:
            return cache
        s, e = self._match.span('attrs')
        attrs_match = ATTRS_MATCH(self._shadow, s, e)
        self._attrs_match_cache = attrs_match, string
        return attrs_match

    def set_attr(self, attr_name: str, attr_value: str) -> None:
        """Set the value for the given attribute name.

        If there are already multiple attributes with that name, only
        set the value for the last one.
        If attr_value == '', use the implicit empty attribute syntax.
        """
        # Note: The set_attr method of the parent class cannot be used instead
        # of this method because a cell could be without any attrs placeholder
        # which means the appropriate piping should be added around attrs by
        # this method. Also ATTRS_MATCH does not have any 'start' group.
        cell_match = self._match
        shadow = cell_match.string
        attrs_start, attrs_end = cell_match.span('attrs')
        if attrs_start != -1:
            encoded_attr_name = attr_name.encode()

            attrs_m = ATTRS_MATCH(shadow, attrs_start, attrs_end)