Coverage for netbox/configuration.py: 84%

50 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-10 18:35 +0000

1## Generic Parts 

2# These functions are providing the functionality to load 

3# arbitrary configuration files. 

4# 

5# They can be imported by other code (see `ldap_config.py` for an example). 

6 

7import importlib.util 

8import sys 

9from os import scandir 

10from os.path import abspath, isfile 

11 

12 

13def _filename(f): 

14 return f.name 

15 

16 

17def _import(module_name, path, loaded_configurations): 

18 spec = importlib.util.spec_from_file_location('', path) 

19 module = importlib.util.module_from_spec(spec) 

20 spec.loader.exec_module(module) 

21 sys.modules[module_name] = module 

22 

23 loaded_configurations.insert(0, module) 

24 

25 print(f"🧬 loaded config '{path}'") 

26 

27 

28def read_configurations(config_module, config_dir, main_config): 

29 loaded_configurations = [] 

30 

31 main_config_path = abspath(f'{config_dir}/{main_config}.py') 

32 if isfile(main_config_path): 32 ↛ 35line 32 didn't jump to line 35 because the condition on line 32 was always true

33 _import(f'{config_module}.{main_config}', main_config_path, loaded_configurations) 

34 else: 

35 print(f"⚠️ Main configuration '{main_config_path}' not found.") 

36 

37 with scandir(config_dir) as it: 

38 for f in sorted(it, key=_filename): 

39 if not f.is_file(): 

40 continue 

41 

42 if f.name.startswith('__'): 42 ↛ 43line 42 didn't jump to line 43 because the condition on line 42 was never true

43 continue 

44 

45 if not f.name.endswith('.py'): 45 ↛ 46line 45 didn't jump to line 46 because the condition on line 45 was never true

46 continue 

47 

48 if f.name == f'{main_config}.py': 

49 continue 

50 

51 if f.name == f'{config_dir}.py': 51 ↛ 52line 51 didn't jump to line 52 because the condition on line 51 was never true

52 continue 

53 

54 module_name = f'{config_module}.{f.name[: -len(".py")]}'.replace('.', '_') 

55 _import(module_name, f.path, loaded_configurations) 

56 

57 if len(loaded_configurations) == 0: 57 ↛ 58line 57 didn't jump to line 58 because the condition on line 57 was never true

58 print(f"‼️ No configuration files found in '{config_dir}'.") 

59 raise ImportError(f"No configuration files found in '{config_dir}'.") 

60 

61 return loaded_configurations 

62 

63 

64## Specific Parts 

65# This section's code actually loads the various configuration files 

66# into the module with the given name. 

67# It contains the logic to resolve arbitrary configuration options by 

68# levaraging dynamic programming using `__getattr__`. 

69 

70 

71_loaded_configurations = read_configurations( 

72 config_dir='/etc/netbox/config/', 

73 config_module='netbox.configuration', 

74 main_config='configuration', 

75) 

76 

77 

78def __getattr__(name): 

79 for config in _loaded_configurations: 

80 try: 

81 return getattr(config, name) 

82 except: 

83 pass 

84 raise AttributeError 

85 

86 

87def __dir__(): 

88 names = [] 

89 for config in _loaded_configurations: 

90 names.extend(config.__dir__()) 

91 return names