diff --git a/slugify/slugify.py b/slugify/slugify.py index 27df54b..0bc9fe9 100644 --- a/slugify/slugify.py +++ b/slugify/slugify.py @@ -142,6 +142,8 @@ def _modern_slugify( raise TypeError(f"max_length must be an int, not {type(max_length).__name__}") if not isinstance(separator, str): raise TypeError(f"separator must be str, not {type(separator).__name__}") + if regex_pattern is not None and not isinstance(regex_pattern, (str, re.Pattern)): + raise TypeError(f"regex_pattern must be str, re.Pattern or None, not {type(regex_pattern).__name__}") if not isinstance(text, str): if not isinstance(text, (bytes, bytearray)): raise TypeError(f'text must be str, bytes or bytearray, not {type(text).__name__}') diff --git a/tests/test_modern_unicode.py b/tests/test_modern_unicode.py new file mode 100644 index 0000000..9aff03c --- /dev/null +++ b/tests/test_modern_unicode.py @@ -0,0 +1,23 @@ +"""Modern algorithm up-front argument type validation. + +The modern algorithm validates caller-supplied arguments at the top of +``_modern_slugify`` so a misuse fails with a clear, argument-specific message +instead of a cryptic error raised deep in the pipeline. These tests cover the +``regex_pattern`` argument alongside the existing ``max_length``/``separator`` +guards. +""" +import re + +import pytest + +from slugify import slugify + + +def test_regex_pattern_type_is_validated_up_front(): + with pytest.raises(TypeError, match='regex_pattern'): + slugify('abc', algorithm='modern', regex_pattern=123) + + +def test_regex_pattern_accepts_str_and_compiled_pattern(): + assert slugify('a b', algorithm='modern', regex_pattern=r'[^-a-z]+') == 'a-b' + assert slugify('a b', algorithm='modern', regex_pattern=re.compile(r'[^-a-z]+')) == 'a-b'