pandas-dev/pandas · error · NotImplementedError

contains not implemented with

Error message

contains not implemented with {flags=}

What it means

NotImplementedError raised in _str_contains of the ArrowStringArray mixin when the flags argument is non-zero. The pyarrow match_substring / match_substring_regex APIs only expose an ignore_case toggle, so general re flags (re.IGNORECASE, re.MULTILINE, etc.) cannot be forwarded.

Solutions

  1. For case-insensitive matching use case=False (the supported pyarrow toggle): s.str.contains('x', case=False).
  2. Embed the flag in the regex pattern itself, e.g. s.str.contains('(?i)x').
  3. Cast to object dtype to keep using arbitrary flags: s.astype(object).str.contains('x', flags=re.IGNORECASE).

Example fix

# before (pa_series is dtype str[pyarrow])
pa_series.str.contains('x', flags=re.IGNORECASE)
# after
pa_series.str.contains('x', case=False)
Defensive patterns

Strategy: validation

Validate before calling

def safe_contains(s, pat, case=True, flags=0, **kw):
    if flags and 'pyarrow' in str(s.dtype):
        # fold common case-insensitive flag into case=False; otherwise cast
        import re
        if flags == re.IGNORECASE:
            return s.str.contains(pat, case=False, **kw)
        s = s.astype(object)
    return s.str.contains(pat, case=case, flags=flags, **kw)

Type guard

def contains_needs_object(s, flags) -> bool:
    return bool(flags) and 'pyarrow' in str(s.dtype)

Try / catch

try:
    s.str.contains(pat, flags=flags)
except NotImplementedError as e:
    if 'contains not implemented' in str(e):
        s.astype(object).str.contains(pat, flags=flags)
    else:
        raise

Prevention

When it happens

Trigger: On a pyarrow-backed string Series: s.str.contains('x', flags=re.IGNORECASE); s.str.contains('^a', flags=re.M).

Common situations: Enabling pyarrow strings and reusing existing contains calls that passed re flags on object dtype; trying to do case-insensitive matching via flags instead of case=False.

Related errors


AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11). Data as JSON: /api/errors/917dfccbd9f0edf5. Report an issue: GitHub.

Appendix: source

Thrown at pandas/core/arrays/_arrow_string_mixins.py:407

    def _str_istitle(self):
        result = pc.utf8_is_title(self._pa_array)
        return self._convert_bool_result(result)

    def _str_isupper(self):
        result = pc.utf8_is_upper(self._pa_array)
        return self._convert_bool_result(result)

    def _str_contains(
        self,
        pat,
        case: bool = True,
        flags: int = 0,
        na: Scalar | lib.NoDefault = lib.no_default,
        regex: bool = True,
    ):
        if flags:
            raise NotImplementedError(f"contains not implemented with {flags=}")

        if regex:
            pa_contains = pc.match_substring_regex
        else:
            pa_contains = pc.match_substring
        result = pa_contains(self._pa_array, pat, ignore_case=not case)
        return self._convert_bool_result(result, na=na, method_name="contains")

    def _str_match(
        self,
        pat: str | re.Pattern,
        case: bool = True,
        flags: int = 0,
        na: Scalar | lib.NoDefault = lib.no_default,
    ):
        if isinstance(pat, re.Pattern):
            # GH#63108 the accessor pre-compiles `pat` whenever the user passes
            #  `flags`, so unwrap it here; pyarrow only supports IGNORECASE,

View on GitHub (pinned to 3b7651241d)