|
5 | 5 | the user is only required to create a ModelBuilder object using the |
6 | 6 | AbstractModel and call the `build_model` method. |
7 | 7 | """ |
| 8 | +from warnings import warn |
8 | 9 | import textwrap |
9 | 10 | import black |
10 | 11 | import json |
11 | 12 | from pathlib import Path |
12 | 13 | from typing import Union |
13 | 14 |
|
14 | 15 | from pysd.translators.structures.abstract_model import\ |
15 | | - AbstractComponent, AbstractElement, AbstractModel, AbstractSection |
| 16 | + AbstractComponent, AbstractElement, AbstractControlElement,\ |
| 17 | + AbstractModel, AbstractSection |
16 | 18 |
|
17 | 19 | from . import python_expressions_builder as vs |
18 | 20 | from .namespace import NamespaceManager |
@@ -142,34 +144,88 @@ def _process_views_tree(self, view_name: str, |
142 | 144 | view_content = { |
143 | 145 | self.namespace.cleanspace[var] for var in view_content |
144 | 146 | } |
145 | | - # Get subview elements |
146 | | - subview_elems = [ |
147 | | - element for element in self.elements_remaining |
148 | | - if element.identifier in view_content |
| 147 | + |
| 148 | + # Get subview elements (ordered) |
| 149 | + subview_elems = sorted( |
| 150 | + [ |
| 151 | + element for element in self.elements_remaining |
| 152 | + if element.identifier in view_content |
| 153 | + and not element.control_var |
| 154 | + ], |
| 155 | + key=lambda x: x.identifier) |
| 156 | + |
| 157 | + # Get the names of the elements and include their |
| 158 | + # information in the elements_added dictionary |
| 159 | + subview_elems_names = [ |
| 160 | + element.identifier for element in subview_elems |
149 | 161 | ] |
| 162 | + view_path = ".".join(view_name.parts[1:]) |
| 163 | + self.elements_added.update({ |
| 164 | + var: view_path for var in subview_elems_names |
| 165 | + }) |
| 166 | + |
| 167 | + if len(view_content) != len(subview_elems_names): |
| 168 | + # Some elements from the view where not added |
| 169 | + for var in view_content.difference(subview_elems_names): |
| 170 | + original_name = self.namespace.get_original_name(var) |
| 171 | + if var in self.elements_added: |
| 172 | + # Element already added in another view |
| 173 | + warn( |
| 174 | + f"Variable '{original_name}' is declared as " |
| 175 | + f"a workbench variable in '{view_path}' but " |
| 176 | + "it has been already added in " |
| 177 | + f"'{self.elements_added[var]}'." |
| 178 | + ) |
| 179 | + else: |
| 180 | + # Element is a control variable |
| 181 | + warn( |
| 182 | + f"Control variable '{original_name}' is " |
| 183 | + "declared as a workbench variable in " |
| 184 | + f"'{view_path}'. As it is a control " |
| 185 | + "variable, this declaration will be ignored " |
| 186 | + "and added to the main module only." |
| 187 | + ) |
| 188 | + |
150 | 189 | # Remove elements from remaining ones |
151 | 190 | [ |
152 | 191 | self.elements_remaining.remove(element) |
153 | 192 | for element in subview_elems |
154 | 193 | ] |
155 | | - # Build the module |
156 | | - self._build_separate_module(subview_elems, view_name, wdir) |
157 | | - return sorted(view_content) |
| 194 | + |
| 195 | + if subview_elems: |
| 196 | + # Build the module (only when they are variables) |
| 197 | + self._build_separate_module(subview_elems, view_name, wdir) |
| 198 | + |
| 199 | + return list(subview_elems_names) |
158 | 200 | else: |
159 | 201 | # The current view has subviews |
160 | | - wdir = wdir.joinpath(view_name) |
161 | | - wdir.mkdir(exist_ok=True) |
162 | | - return { |
163 | | - subview_name: |
164 | | - self._process_views_tree(subview_name, subview_content, wdir) |
| 202 | + (wdir / view_name).mkdir(exist_ok=True) |
| 203 | + subviews = { |
| 204 | + subview_name: self._process_views_tree( |
| 205 | + view_name / subview_name, subview_content, wdir) |
165 | 206 | for subview_name, subview_content in view_content.items() |
166 | 207 | } |
| 208 | + # Avoid includying empty views to the dictionary |
| 209 | + return { |
| 210 | + subview_name: subview_content |
| 211 | + for subview_name, subview_content in subviews.items() |
| 212 | + if subview_content |
| 213 | + } |
167 | 214 |
|
168 | 215 | def _build_modular(self, elements_per_view: dict) -> None: |
169 | 216 | """ Build modular section """ |
170 | 217 | self.elements_remaining = self.elements.copy() |
| 218 | + self.elements_added = {} |
171 | 219 | elements_per_view = self._process_views_tree( |
172 | | - "modules_" + self.model_name, elements_per_view, self.root) |
| 220 | + Path("modules_" + self.model_name), elements_per_view, self.root) |
| 221 | + |
| 222 | + for element in self.elements_remaining: |
| 223 | + if not element.control_var: |
| 224 | + warn( |
| 225 | + f"Variable '{element.name}' is not declared as a " |
| 226 | + "workbench variable in any view. It will be added to " |
| 227 | + "the main module." |
| 228 | + ) |
173 | 229 | # Building main file using the build function |
174 | 230 | self._build_main_module(self.elements_remaining) |
175 | 231 |
|
@@ -211,15 +267,15 @@ def _build_separate_module(self, elements: list, module_name: str, |
211 | 267 | Translated using PySD version %(version)s |
212 | 268 | """ |
213 | 269 | ''' % { |
214 | | - "module_name": module_name, |
| 270 | + "module_name": ".".join(module_name.parts[1:]), |
215 | 271 | "version": __version__, |
216 | 272 | }) |
217 | 273 | funcs = self._generate_functions(elements) |
218 | 274 | text += funcs |
219 | 275 | text = black.format_file_contents( |
220 | 276 | text, fast=True, mode=black.FileMode()) |
221 | 277 |
|
222 | | - outfile_name = module_dir.joinpath(module_name + ".py") |
| 278 | + outfile_name = module_dir / module_name.with_suffix(".py") |
223 | 279 |
|
224 | 280 | with outfile_name.open("w", encoding="UTF-8") as out: |
225 | 281 | out.write(text) |
@@ -478,6 +534,7 @@ class ElementBuilder: |
478 | 534 | def __init__(self, abstract_element: AbstractElement, |
479 | 535 | section: SectionBuilder): |
480 | 536 | self.__dict__ = abstract_element.__dict__.copy() |
| 537 | + self.control_var = isinstance(abstract_element, AbstractControlElement) |
481 | 538 | # Set element type and subtype to None |
482 | 539 | self.type = None |
483 | 540 | self.subtype = None |
|
0 commit comments