Coverage for /home/benjarobin/Bootlin/projects/Schneider-Electric-Senux/sbom-cve-check/src/sbom_cve_check/sbom/registry.py: 97%

35 statements  

« prev     ^ index     » next       coverage.py v7.11.1, created at 2025-11-28 15:37 +0100

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

2# SPDX-License-Identifier: GPL-2.0-only 

3 

4import pathlib 

5from collections.abc import Callable, Iterable 

6from typing import TypeVar 

7 

8from ..utils.class_utils import Singleton 

9from ..utils.plugin import import_builtin_plugin 

10from .sbom_base import Sbom 

11 

12_SbomT = TypeVar("_SbomT", bound=Sbom) 

13 

14 

15class SbomTypeRegistry(metaclass=Singleton): 

16 def __init__(self) -> None: 

17 self._sbom_types: dict[str, type[Sbom]] = {} 

18 

19 def register_type(self, type_name: str, sbom_type: type[Sbom]) -> None: 

20 assert type_name not in self._sbom_types 

21 self._sbom_types[type_name] = sbom_type 

22 

23 @property 

24 def type_names(self) -> Iterable[str]: 

25 return self._sbom_types.keys() 

26 

27 def create(self, type_name: str | None, path: pathlib.Path) -> Sbom: 

28 if type_name is None: 

29 # Try to autodetect SBOM type from the file extension 

30 for name, sbom_type in self._sbom_types.items(): 

31 if sbom_type.can_handle_sbom(path): 

32 type_name = name 

33 break 

34 else: 

35 raise ValueError(f"Can not autodetect SBOM format: {path.name}") 

36 

37 cls_sbom: type[Sbom] = self._sbom_types[type_name] 

38 return cls_sbom(path) 

39 

40 

41def register_sbom(name: str) -> Callable[[type[_SbomT]], type[_SbomT]]: 

42 def decorator(cls: type[_SbomT]) -> type[_SbomT]: 

43 SbomTypeRegistry().register_type(name, cls) 

44 return cls 

45 

46 return decorator 

47 

48 

49def __register_builtin_types() -> None: 

50 modules = [".sbom_spdx2", ".sbom_spdx3"] 

51 for mod in modules: 

52 import_builtin_plugin(__package__, mod) 

53 

54 

55__register_builtin_types()