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

71 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-09-21 04:50 -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 

8from contextlib import suppress 

9from uuid import UUID 

10 

11from acb.adapters import AdapterStatus 

12from acb.debug import debug 

13from acb.depends import depends 

14 

15from ._base import SitemapBase, SitemapBaseSettings 

16from .core import BaseSitemap, SitemapApp 

17 

18 

19class NativeSitemapSettings(SitemapBaseSettings): 

20 pass 

21 

22 

23class NativeSitemap(BaseSitemap[str], SitemapBase): 

24 sitemap: SitemapApp | None = None 

25 

26 @depends.inject 

27 def items(self) -> list[str]: 

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[:] 

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 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 elif segments == 2: 

87 return 0.6 

88 else: 

89 return 0.4 

90 

91 async def init(self) -> None: 

92 if not self.config.domain: 

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

94 raise ValueError(msg) 

95 self.sitemap = SitemapApp( 

96 self, 

97 domain=self.config.domain, 

98 cache_ttl=self.config.cache_ttl, 

99 ) 

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

101 

102 

103Sitemap = NativeSitemap 

104 

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

106MODULE_STATUS = AdapterStatus.STABLE 

107 

108with suppress(Exception): 

109 depends.set(Sitemap)