Coverage for fastblocks/adapters/sitemap/native.py: 0%

71 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-10-09 00:47 -0700

1"""FastBlocks Native Sitemap Adapter. 

2 

3Automatic route-based sitemap generation using FastBlocks routing system 

4with enhanced caching, filtering, and debugging capabilities. 

5""" 

6 

7import re 

8import typing as t 

9from contextlib import suppress 

10from uuid import UUID 

11 

12from acb.adapters import AdapterStatus 

13from acb.debug import debug 

14from acb.depends import depends 

15 

16from ._base import SitemapBase, SitemapBaseSettings 

17from .core import BaseSitemap, SitemapApp 

18 

19 

20class NativeSitemapSettings(SitemapBaseSettings): 

21 pass 

22 

23 

24class NativeSitemap(BaseSitemap[str], SitemapBase): # type: ignore[override] 

25 sitemap: SitemapApp | None = None 

26 

27 def items(self) -> t.Any: 

28 try: 

29 routes_adapter = depends.get("routes") 

30 if not hasattr(routes_adapter, "routes"): 

31 debug("NativeSitemap: No routes adapter found") 

32 return [] 

33 route_paths = [r.path for r in routes_adapter.routes] 

34 debug(f"NativeSitemap: Found {len(route_paths)} routes") 

35 filtered_paths = self._filter_routes(route_paths) 

36 debug(f"NativeSitemap: Filtered to {len(filtered_paths)} routes") 

37 

38 return filtered_paths 

39 except Exception as e: 

40 debug(f"NativeSitemap: Error getting routes: {e}") 

41 return [] 

42 

43 def _filter_routes(self, routes: list[str]) -> list[str]: 

44 strategy_options = self.config.strategy_options 

45 include_patterns = strategy_options.get("include_patterns", []) 

46 exclude_patterns = strategy_options.get("exclude_patterns", []) 

47 filtered = routes.copy() 

48 for pattern in exclude_patterns: 

49 try: 

50 regex = re.compile( 

51 pattern 

52 ) # REGEX OK: Dynamic user patterns for route filtering 

53 filtered = [ 

54 r for r in filtered if not regex.match(r) 

55 ] # REGEX OK: Pattern matching for route filtering 

56 except re.error as e: 

57 debug(f"NativeSitemap: Invalid exclude pattern '{pattern}': {e}") 

58 if include_patterns: 

59 included = [] 

60 for pattern in include_patterns: 

61 try: 

62 regex = re.compile( 

63 pattern 

64 ) # REGEX OK: Dynamic user patterns for route filtering 

65 included.extend( 

66 [r for r in filtered if regex.match(r)] 

67 ) # REGEX OK: Pattern matching for route filtering 

68 except re.error as e: 

69 debug(f"NativeSitemap: Invalid include pattern '{pattern}': {e}") 

70 filtered = list(set(included)) 

71 

72 return filtered 

73 

74 def location(self, item: str) -> str: 

75 return item 

76 

77 def changefreq(self, item: str) -> str: 

78 return t.cast(str, self.config.change_freq) 

79 

80 def priority(self, item: str) -> float: 

81 if item == "/": 

82 return 1.0 

83 segments = len([s for s in item.split("/") if s]) 

84 if segments == 1: 

85 return 0.8 

86 if segments == 2: 

87 return 0.6 

88 return 0.4 

89 

90 async def init(self) -> None: 

91 if not self.config.domain: 

92 msg = "domain must be set in sitemap settings" 

93 raise ValueError(msg) 

94 self.sitemap = SitemapApp( 

95 self, 

96 domain=self.config.domain, 

97 cache_ttl=self.config.cache_ttl, 

98 ) 

99 debug(f"NativeSitemap: Initialized with domain={self.config.domain}") 

100 

101 

102Sitemap = NativeSitemap 

103 

104MODULE_ID = UUID("01937d86-9f7f-7081-d342-6789012345f0") 

105MODULE_STATUS = AdapterStatus.STABLE 

106 

107with suppress(Exception): 

108 depends.set(Sitemap)