| Conditions | 23 |
| Total Lines | 134 |
| Code Lines | 81 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like solph.processing.__separate_attrs() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | # -*- coding: utf-8 -*- |
||
| 99 | def __separate_attrs( |
||
| 100 | system, exclude_attrs, get_flows=False, exclude_none=True |
||
| 101 | ): |
||
| 102 | """ |
||
| 103 | Create a dictionary with flow scalars and series. |
||
| 104 | |||
| 105 | The dictionary is structured with flows as tuples and nested dictionaries |
||
| 106 | holding the scalars and series e.g. |
||
| 107 | {(node1, node2): {'scalars': {'attr1': scalar, 'attr2': 'text'}, |
||
| 108 | 'sequences': {'attr1': iterable, 'attr2': iterable}}} |
||
| 109 | |||
| 110 | system: |
||
| 111 | A solved oemof.solph.Model or oemof.solph.Energysystem |
||
| 112 | exclude_attrs: List[str] |
||
| 113 | List of additional attributes which shall be excluded from |
||
| 114 | parameter dict |
||
| 115 | get_flows: bool |
||
| 116 | Whether to include flow values or not |
||
| 117 | exclude_none: bool |
||
| 118 | If set, scalars and sequences containing None values are excluded |
||
| 119 | |||
| 120 | Returns |
||
| 121 | ------- |
||
| 122 | dict |
||
| 123 | """ |
||
| 124 | |||
| 125 | def detect_scalars_and_sequences(com): |
||
| 126 | scalars = {} |
||
| 127 | sequences = {} |
||
| 128 | |||
| 129 | default_exclusions = [ |
||
| 130 | "__", |
||
| 131 | "_", |
||
| 132 | "registry", |
||
| 133 | "inputs", |
||
| 134 | "outputs", |
||
| 135 | "Label", |
||
| 136 | "input", |
||
| 137 | "output", |
||
| 138 | "constraint_group", |
||
| 139 | ] |
||
| 140 | # Must be tuple in order to work with `str.startswith()`: |
||
| 141 | exclusions = tuple(default_exclusions + exclude_attrs) |
||
| 142 | attrs = [ |
||
| 143 | i |
||
| 144 | for i in dir(com) |
||
| 145 | if not (i.startswith(exclusions) or callable(getattr(com, i))) |
||
| 146 | ] |
||
| 147 | |||
| 148 | for a in attrs: |
||
| 149 | attr_value = getattr(com, a) |
||
| 150 | |||
| 151 | # Iterate trough investment and add scalars and sequences with |
||
| 152 | # "investment" prefix to component data: |
||
| 153 | if attr_value.__class__.__name__ == "Investment": |
||
| 154 | invest_data = detect_scalars_and_sequences(attr_value) |
||
| 155 | scalars.update( |
||
| 156 | { |
||
| 157 | "investment_" + str(k): v |
||
| 158 | for k, v in invest_data["scalars"].items() |
||
| 159 | } |
||
| 160 | ) |
||
| 161 | sequences.update( |
||
| 162 | { |
||
| 163 | "investment_" + str(k): v |
||
| 164 | for k, v in invest_data["sequences"].items() |
||
| 165 | } |
||
| 166 | ) |
||
| 167 | continue |
||
| 168 | |||
| 169 | if isinstance(attr_value, str): |
||
| 170 | scalars[a] = attr_value |
||
| 171 | continue |
||
| 172 | |||
| 173 | # If the label is a tuple it is iterable, therefore it should be |
||
| 174 | # converted to a string. Otherwise, it will be a sequence. |
||
| 175 | if a == "label": |
||
| 176 | attr_value = str(attr_value) |
||
| 177 | |||
| 178 | if isinstance(attr_value, abc.Iterable): |
||
| 179 | sequences[a] = attr_value |
||
| 180 | elif isinstance(attr_value, _FakeSequence): |
||
| 181 | scalars[a] = attr_value.value |
||
| 182 | else: |
||
| 183 | scalars[a] = attr_value |
||
| 184 | |||
| 185 | sequences = flatten(sequences) |
||
| 186 | |||
| 187 | com_data = { |
||
| 188 | "scalars": scalars, |
||
| 189 | "sequences": sequences, |
||
| 190 | } |
||
| 191 | move_undetected_scalars(com_data) |
||
| 192 | if exclude_none: |
||
| 193 | remove_nones(com_data) |
||
| 194 | |||
| 195 | com_data = { |
||
| 196 | "scalars": pd.Series(com_data["scalars"]), |
||
| 197 | "sequences": pd.DataFrame(com_data["sequences"]), |
||
| 198 | } |
||
| 199 | return com_data |
||
| 200 | |||
| 201 | def move_undetected_scalars(com): |
||
| 202 | for ckey, value in list(com["sequences"].items()): |
||
| 203 | if isinstance(value, (str, numbers.Number)): |
||
| 204 | com["scalars"][ckey] = value |
||
| 205 | del com["sequences"][ckey] |
||
| 206 | elif isinstance(value, _FakeSequence): |
||
| 207 | com["scalars"][ckey] = value.value |
||
| 208 | del com["sequences"][ckey] |
||
| 209 | elif len(value) == 0: |
||
| 210 | del com["sequences"][ckey] |
||
| 211 | |||
| 212 | def remove_nones(com): |
||
| 213 | for ckey, value in list(com["scalars"].items()): |
||
| 214 | if value is None: |
||
| 215 | del com["scalars"][ckey] |
||
| 216 | for ckey, value in list(com["sequences"].items()): |
||
| 217 | if len(value) == 0 or value[0] is None: |
||
| 218 | del com["sequences"][ckey] |
||
| 219 | |||
| 220 | # Check if system is es or om: |
||
| 221 | if system.__class__.__name__ == "EnergySystem": |
||
| 222 | components = system.flows() if get_flows else system.nodes |
||
| 223 | else: |
||
| 224 | components = system.flows if get_flows else system.es.nodes |
||
| 225 | |||
| 226 | data = {} |
||
| 227 | for com_key in components: |
||
| 228 | component = components[com_key] if get_flows else com_key |
||
| 229 | component_data = detect_scalars_and_sequences(component) |
||
| 230 | comkey = com_key if get_flows else (com_key, None) |
||
| 231 | data[comkey] = component_data |
||
| 232 | return data |
||
| 233 | |||
| 272 |