Coverage for Users / vladimirpavlov / PycharmProjects / parameterizable / src / mixinforge / parameterizable_mixin.py: 100%

34 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-01 16:37 -0600

1"""Basic infrastructure for parameterizable classes. 

2 

3This module provides functionality for working with parameterizable classes: 

4classes that have (hyper)parameters which define an object's configuration, 

5but not its internal contents or data. Such parameters are typically 

6passed to the __init__ method. 

7 

8The module provides an API for getting parameter values from an object, 

9and for converting the parameters to and from a portable dictionary 

10(a dictionary with sorted str keys that only contains 

11basic types and portable sub-dictionaries). 

12""" 

13import inspect 

14from typing import Any 

15 

16from .dict_sorter import sort_dict_by_keys 

17from .json_processor import loadjs,dumpjs, JsonSerializedObject 

18 

19 

20class ParameterizableMixin: 

21 """Base class for parameterizable classes. 

22 

23 Classes deriving from this base expose a stable set of configuration 

24 parameters that define their behavior. Subclasses implement get_params 

25 to return these parameters, which can then be serialized to and from 

26 a portable JSON representation. 

27 

28 Note: 

29 This class is intended to be subclassed. The default implementation of 

30 get_params returns an empty mapping. 

31 """ 

32 

33 

34 def get_params(self) -> dict[str, Any]: 

35 """Return this instance's configuration parameters. 

36 

37 Parameters define the object's configuration but not its internal 

38 contents or data. They are typically passed to __init__ at creation time. 

39 

40 Returns: 

41 A mapping of parameter names to values. 

42 

43 Note: 

44 Subclasses should override this method to return their specific 

45 parameters. The default implementation returns an empty dictionary. 

46 """ 

47 params = dict() 

48 return params 

49 

50 

51 def get_jsparams(self) -> JsonSerializedObject: 

52 """Return this instance's parameters encoded as JSON. 

53 

54 Returns: 

55 JSON string produced by dumpjs. 

56 """ 

57 return dumpjs(self.get_params()) 

58 

59 

60 @classmethod 

61 def get_default_params(cls) -> dict[str, Any]: 

62 """Get the default parameters of the class as a dictionary. 

63 

64 Default values are taken from keyword parameters of __init__ and 

65 returned as a key-sorted dictionary. Subclasses may override if default 

66 computation requires custom logic. 

67 

68 Returns: 

69 The class's default parameters sorted by key. 

70 """ 

71 signature = inspect.signature(cls.__init__) 

72 # Skip the first parameter (self/cls) 

73 params_to_consider = list(signature.parameters.values())[1:] 

74 params = { 

75 p.name: p.default 

76 for p in params_to_consider 

77 if p.default is not inspect.Parameter.empty 

78 } 

79 sorted_params = sort_dict_by_keys(params) 

80 return sorted_params 

81 

82 

83 @classmethod 

84 def get_default_jsparams(cls) -> JsonSerializedObject: 

85 """Return default constructor parameters encoded as JSON. 

86 

87 Returns: 

88 JSON string with default parameters. 

89 """ 

90 return dumpjs(cls.get_default_params()) 

91 

92 

93 @property 

94 def essential_param_names(self) -> set[str]: 

95 """Names of parameters that define the object's core identity and behavior. 

96  

97 Essential parameters are those that fundamentally define an object's behavior 

98 or identity - for example, the maximum number of trees in a random forest 

99 or the maximum depth of a decision tree. 

100  

101 These parameters are typically immutable throughout the object's lifetime. 

102  

103 Note: 

104 Subclasses should override this property to specify which parameters are 

105 essential. The default implementation considers all parameters essential. 

106  

107 Returns: 

108 Names of essential parameters. 

109 """ 

110 return set(self.get_params().keys()) 

111 

112 

113 @property 

114 def auxiliary_param_names(self) -> set[str]: 

115 """Names of the object's auxiliary parameters. 

116 

117 Auxiliary parameters are parameters that do not fundamentally impact the 

118 object's behavior or identity. These might include settings like logging 

119 verbosity, debug flags, or probability thresholds for consistency checks. 

120 

121 Returns: 

122 Set of auxiliary parameter names. 

123 """ 

124 return set(self.get_params().keys()) - self.essential_param_names 

125 

126 

127 def get_essential_params(self) -> dict[str, Any]: 

128 """Return only the essential parameters. 

129 

130 Returns: 

131 Mapping of essential parameter names to values. 

132 """ 

133 return {k: v for k, v in self.get_params().items() 

134 if k in self.essential_param_names} 

135 

136 

137 def get_essential_jsparams(self) -> JsonSerializedObject: 

138 """Return essential parameters encoded as JSON. 

139 

140 Returns: 

141 JSON string with essential parameters. 

142 """ 

143 return dumpjs(self.get_essential_params()) 

144 

145 

146 def get_auxiliary_params(self) -> dict[str, Any]: 

147 """Return only the auxiliary parameters. 

148 

149 Returns: 

150 Mapping of auxiliary parameter names to values. 

151 """ 

152 return {k: v for k, v in self.get_params().items() 

153 if k in self.auxiliary_param_names} 

154 

155 

156 def get_auxiliary_jsparams(self) -> JsonSerializedObject: 

157 """Return auxiliary parameters encoded as JSON. 

158 

159 Returns: 

160 JSON string with auxiliary parameters. 

161 """ 

162 return dumpjs(self.get_auxiliary_params())