Coverage for src/lexigram/web/contributors/discovery.py: 44%

18 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-25 04:37 +0800

1"""Web contributor discovery via entry-points. 

2 

3Discovers and loads web contributors from installed packages via the 

4``lexigram.web.contributors`` entry-point group. Failed contributors 

5are logged but do not halt the discovery process. 

6""" 

7 

8from __future__ import annotations 

9 

10from importlib.metadata import entry_points 

11 

12from lexigram.contracts.web import WebContributorProtocol 

13from lexigram.logging import get_logger 

14 

15logger = get_logger(__name__) 

16 

17ENTRY_POINT_GROUP = "lexigram.web.contributors" 

18 

19 

20def load_web_contributors() -> list[WebContributorProtocol]: 

21 """Load web contributors from entry-points. 

22 

23 Scans the ``lexigram.web.contributors`` entry-point group and loads 

24 each registered contributor class. Failed loads (import errors, 

25 instantiation failures) are logged and skipped without halting 

26 the discovery process. 

27 

28 Returns: 

29 List of successfully loaded and instantiated contributor instances. 

30 

31 Example: 

32 A package registers a contributor via pyproject.toml:: 

33 

34 [project.entry-points."lexigram.web.contributors"] 

35 graphql = "lexigram.graphql.web.contributor:GraphQLWebContributor" 

36 

37 The web provider loads all contributors at startup:: 

38 

39 contributors = load_web_contributors() 

40 for contributor in contributors: 

41 logger.info(f"Loaded contributor: {contributor.contributor_id}") 

42 """ 

43 contributors: list[WebContributorProtocol] = [] 

44 

45 for contributor_entry_point in entry_points(group=ENTRY_POINT_GROUP): 

46 try: 

47 contributor_class = contributor_entry_point.load() 

48 contributor = contributor_class() 

49 except Exception as exc: # noqa: BLE001 

50 logger.warning( 

51 "web.contributor_load_failed", 

52 name=getattr(contributor_entry_point, "name", "<unknown>"), 

53 error=str(exc), 

54 ) 

55 continue 

56 

57 contributors.append(contributor) 

58 

59 return contributors 

60 

61 

62__all__ = ["ENTRY_POINT_GROUP", "load_web_contributors"]