Coverage for mcpgateway / utils / create_slug.py: 100%

13 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-02-11 07:10 +0000

1# -*- coding: utf-8 -*- 

2"""Location: ./mcpgateway/utils/create_slug.py 

3Copyright 2025 

4SPDX-License-Identifier: Apache-2.0 

5Authors: Manav Gupta 

6 

7Slug generation utilities for MCP Gateway. 

8This module provides utilities for creating URL-friendly slugs from text. 

9It handles Unicode normalization, special character replacement, and 

10contraction processing to generate clean, readable slugs. 

11""" 

12 

13# Standard 

14import re 

15from unicodedata import normalize 

16 

17# First-Party 

18from mcpgateway.config import settings 

19 

20# Helper regex patterns 

21CONTRACTION_PATTERN = re.compile(r"(\w)[''](\w)") 

22NON_ALPHANUMERIC_PATTERN = re.compile(r"[\W_]+") 

23 

24# Special character replacements that normalize() doesn't handle well 

25SPECIAL_CHAR_MAP = { 

26 "æ": "ae", 

27 "ß": "ss", 

28 "ø": "o", 

29} 

30 

31 

32def slugify(text: str) -> str: 

33 """Make an ASCII slug of text. 

34 

35 Args: 

36 text(str): Input text 

37 

38 Returns: 

39 str: Slugified text 

40 

41 Examples: 

42 Basic slugification: 

43 >>> slugify("Hello World") 

44 'hello-world' 

45 >>> slugify("Test-Case_123") 

46 'test-case-123' 

47 

48 Handle special characters: 

49 >>> slugify("Café & Restaurant") 

50 'cafe-restaurant' 

51 >>> slugify("user@example.com") 

52 'user-example-com' 

53 

54 Handle contractions: 

55 >>> slugify("Don't Stop") 

56 'dont-stop' 

57 >>> slugify("It's Working") 

58 'its-working' 

59 

60 Edge cases: 

61 >>> slugify("") 

62 '' 

63 >>> slugify(" ") 

64 '' 

65 >>> slugify("---test---") 

66 'test' 

67 >>> slugify("Multiple Spaces") 

68 'multiple-spaces' 

69 

70 Unicode normalization: 

71 >>> slugify("Naïve résumé") 

72 'naive-resume' 

73 >>> slugify("Zürich") 

74 'zurich' 

75 """ 

76 # Make lower case and delete apostrophes from contractions 

77 slug = CONTRACTION_PATTERN.sub(r"\1\2", text.lower()) 

78 # Convert runs of non-alphanumeric characters to single hyphens, strip ends 

79 slug = NON_ALPHANUMERIC_PATTERN.sub(settings.gateway_tool_name_separator, slug).strip(settings.gateway_tool_name_separator) 

80 # Replace special characters from the map 

81 for special_char, replacement in SPECIAL_CHAR_MAP.items(): 

82 slug = slug.replace(special_char, replacement) 

83 # Normalize the non-ASCII text to ASCII 

84 slug = normalize("NFKD", slug).encode("ascii", "ignore").decode() 

85 return slug