Skip to content

Commit 919dffa

Browse files
committed
Bugfixing module_renderer.py
1 parent da62d38 commit 919dffa

7 files changed

Lines changed: 140 additions & 94 deletions

module_renderer.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,20 +81,26 @@ def _render_module(
8181
and self.partial_render_choice.module is not None
8282
and self.partial_render_choice.module.module_name == plain_module.module_name
8383
)
84-
render_range = self.partial_render_choice.render_range if is_partial_render_choice_module else render_range
84+
85+
if is_partial_render_choice_module:
86+
if not force_render:
87+
render_range = self.partial_render_choice.render_range
88+
else:
89+
render_range = None
90+
8591
if render_range is not None:
8692
plain_module.ensure_previous_frid_commits_exist(render_range, self.args.render_conformance_tests)
8793

8894
has_any_required_module_changed = False
8995
if not self.args.render_machine_graph and plain_module.required_modules and not is_partial_render_choice_module:
9096
console.debug(f"Analyzing required modules of module {plain_module.module_name}...")
9197
for required_module in plain_module.required_modules:
92-
has_any_required_module_changed, rendering_failed = self._render_module(
98+
has_module_changed, rendering_failed = self._render_module(
9399
required_module,
94100
None,
95101
self.args.force_render,
96102
)
97-
103+
has_any_required_module_changed |= has_module_changed
98104
if rendering_failed:
99105
return False, True
100106

@@ -145,6 +151,18 @@ def _render_module(
145151
return True, False
146152

147153
def render_module(self) -> None:
154+
if self.partial_render_choice is not None and self.partial_render_choice.wipe_later_modules:
155+
later_module = False
156+
all_modules = self.plain_module.all_required_modules + [self.plain_module]
157+
for module in all_modules:
158+
if module.module_name == self.partial_render_choice.module.module_name:
159+
later_module = True
160+
continue
161+
162+
if later_module:
163+
console.info(f"Wiping module {module.module_name}...")
164+
module.wipe_module()
165+
148166
self.loaded_modules = list[PlainModule]()
149167
_, rendering_failed = self._render_module(self.plain_module, self.render_range, True)
150168
if not rendering_failed:

partial_rendering.py

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class PartialRenderChoice:
1919
module: PlainModule | None = None
2020
render_range: list[str] | None = None
2121
msg: str | None = None
22+
wipe_later_modules: bool = False
2223

2324

2425
def spec_change(plain_module: PlainModule) -> PlainModule | None:
@@ -72,7 +73,7 @@ def detect_partial_rendering(plain_module: PlainModule) -> PartialRender | None:
7273
sc = spec_change(plain_module)
7374
cc = code_change(plain_module)
7475
all_required_modules = plain_module.all_required_modules
75-
last_rendered_module_name, last_rendered_frid = plain_module.get_module_last_rendered_functionality()
76+
last_rendered_module_name, last_rendered_frid = plain_module.get_module_render_status()
7677
if last_rendered_module_name is None and last_rendered_frid is None:
7778
return None
7879

@@ -84,16 +85,17 @@ def detect_partial_rendering(plain_module: PlainModule) -> PartialRender | None:
8485
module = plain_module
8586
else:
8687
return None
87-
88-
module = None
89-
for required_module in all_required_modules:
90-
if required_module.module_name == last_rendered_module_name:
91-
module = required_module
92-
93-
if module is None:
94-
raise ModuleDoesNotExistError(
95-
f"Last rendered module {last_rendered_module_name} not found in {[rmodule.module_name for rmodule in all_required_modules]}"
96-
)
88+
else:
89+
found_module: PlainModule | None = None
90+
for required_module in all_required_modules:
91+
if required_module.module_name == last_rendered_module_name:
92+
found_module = required_module
93+
94+
if found_module is None:
95+
raise ModuleDoesNotExistError(
96+
f"Last rendered module {last_rendered_module_name} not found in {[rmodule.module_name for rmodule in all_required_modules]}"
97+
)
98+
module = found_module
9799

98100
pr = PartialRender(
99101
last_render_module=module,
@@ -122,33 +124,47 @@ def detect_partial_rendering(plain_module: PlainModule) -> PartialRender | None:
122124
def get_choices(plain_module: PlainModule, partial_render: PartialRender) -> dict[str, PartialRenderChoice]:
123125
choices = dict[str, PartialRenderChoice]()
124126
choice_idx = 1
125-
if not partial_render.last_render_module.is_module_fully_rendered():
127+
128+
if partial_render.last_render_module.is_initial_module():
126129
choices[str(choice_idx)] = PartialRenderChoice(
127130
module=partial_render.last_render_module,
128131
render_range=None,
129132
msg=f"Start from module [#5593FF]{partial_render.last_render_module.module_name}[/]",
133+
wipe_later_modules=True,
130134
)
131135
choice_idx += 1
132-
if not partial_render.last_render_module.is_initial_module():
133-
if not partial_render.last_render_frid:
134-
raise ValueError("Last render FRID is not set for a non-initial module")
135136

136-
next_frid, next_module = plain_module.get_next_frid(
137-
partial_render.last_render_frid, partial_render.last_render_module.module_name
138-
)
139-
render_range = plain_spec.get_render_range_from(next_frid, next_module.plain_source)
140-
msg = "Continue from"
141-
if next_frid != plain_spec.get_first_frid(next_module.plain_source):
142-
msg += f" functionality [#5593FF]{next_frid}[/]"
143-
else:
144-
msg += f" module [#5593FF]{next_module.module_name}[/]"
145-
146-
choices[str(choice_idx)] = PartialRenderChoice(
147-
module=next_module,
148-
render_range=render_range,
149-
msg=msg,
150-
)
151-
choice_idx += 1
137+
elif not partial_render.last_render_module.is_module_fully_rendered():
138+
if not partial_render.last_render_frid:
139+
raise ValueError("Last render FRID is not set for a non-initial module")
140+
141+
next_frid, next_module = plain_module.get_next_frid(
142+
partial_render.last_render_frid, partial_render.last_render_module.module_name
143+
)
144+
render_range = plain_spec.get_render_range_from(next_frid, next_module.plain_source)
145+
msg = "Continue from"
146+
if next_frid != plain_spec.get_first_frid(next_module.plain_source):
147+
msg += f" functionality [#5593FF]{next_frid}[/]"
148+
else:
149+
msg += f" module [#5593FF]{next_module.module_name}[/]"
150+
151+
choices[str(choice_idx)] = PartialRenderChoice(
152+
module=next_module,
153+
render_range=render_range,
154+
msg=msg,
155+
)
156+
choice_idx += 1
157+
158+
else:
159+
next_module = plain_module.get_next_module(partial_render.last_render_module.module_name)
160+
if next_module is None:
161+
next_module = partial_render.last_render_module
162+
163+
choices[str(choice_idx)] = PartialRenderChoice(
164+
module=next_module,
165+
msg=f"Start from module [#5593FF]{next_module.module_name}[/]",
166+
)
167+
choice_idx += 1
152168

153169
if partial_render.change:
154170
all_affected_modules = list[str]()
@@ -163,6 +179,7 @@ def get_choices(plain_module: PlainModule, partial_render: PartialRender) -> dic
163179
module=partial_render.change,
164180
render_range=None,
165181
msg=f"Re-render all affected modules ([#5593FF]{', '.join(all_affected_modules)}[/])",
182+
wipe_later_modules=True,
166183
)
167184
choice_idx += 1
168185

@@ -174,6 +191,7 @@ def get_choices(plain_module: PlainModule, partial_render: PartialRender) -> dic
174191
module=first_module,
175192
render_range=None,
176193
msg=f"Re-render from first module ([#5593FF]{first_module.module_name}[/])",
194+
wipe_later_modules=True,
177195
)
178196
choice_idx += 1
179197

plain2code.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,8 @@ def render(args, run_state: RunState, event_bus: EventBus): # noqa: C901
202202
# Last choice is Quit, first choice is the only other actionable choice
203203
partial_render_choice = choices[list(choices.keys())[0]]
204204

205-
# We can't have both partial render choice and render range
206-
assert not (partial_render_choice is not None and render_range is not None)
205+
if partial_render_choice is not None and render_range is not None:
206+
raise Exception("Partial rendering and render range cannot be used together")
207207

208208
module_renderer = ModuleRenderer(
209209
codeplainAPI,

plain_modules.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
import json
44
import os
5+
import shutil
56
from functools import cached_property
67

78
from git.exc import NoSuchPathError
89

910
import git_utils
1011
import plain_file
1112
import plain_spec
13+
from plain2code_console import console
1214
from plain2code_exceptions import MissingPreviousFunctionalitiesError, ModuleDoesNotExistError
1315
from render_machine.implementation_code_helpers import ImplementationCodeHelpers
1416

@@ -68,7 +70,7 @@ def module_build_folder(self):
6870
def get_codeplain_folder(self):
6971
return os.path.join(self.module_build_folder, CODEPLAIN_METADATA_FOLDER)
7072

71-
def get_module_last_rendered_functionality(self) -> tuple[str | None, str | None]:
73+
def get_module_render_status(self) -> tuple[str | None, str | None]:
7274
if len(self.required_modules) == 0:
7375
return git_utils.get_last_rendered_functionality(self.module_build_folder)
7476

@@ -77,7 +79,7 @@ def get_module_last_rendered_functionality(self) -> tuple[str | None, str | None
7779
return module_name, frid
7880

7981
for module in reversed(self.required_modules):
80-
last_rendered_module_name, last_rendered_frid = module.get_module_last_rendered_functionality()
82+
last_rendered_module_name, last_rendered_frid = module.get_module_render_status()
8183
if last_rendered_module_name is not None:
8284
return last_rendered_module_name, last_rendered_frid
8385

@@ -162,19 +164,12 @@ def get_hashes(self) -> dict[str, str]:
162164
hashes["required_modules_code_hash"] = self.required_modules[-1].get_module_code_hash()
163165
return hashes
164166

165-
def save_module_metadata(self, only_hashes: bool = False):
167+
def save_module_metadata(self):
166168
codeplain_folder = self.get_codeplain_folder()
167169
os.makedirs(codeplain_folder, exist_ok=True)
168170

169171
module_metadata = self.get_hashes()
170-
171172
metadata_path = self.module_metadata_path()
172-
173-
if only_hashes:
174-
with open(metadata_path, "w", encoding="utf-8") as f:
175-
json.dump(module_metadata, f, indent=4)
176-
return
177-
178173
module_metadata[MODULE_FUNCTIONALITIES] = self._get_module_functional_requirements()
179174

180175
required_modules_functionalities = {}
@@ -277,10 +272,7 @@ def ensure_previous_frid_commits_exist(self, render_range: list[str], render_con
277272
for prev_frid in previous_frids:
278273
self._ensure_frid_commit_exists(prev_frid, first_render_frid, render_conformance_tests)
279274

280-
def get_module_by_name(self, module_name: str) -> PlainModule:
281-
if self.module_name == module_name:
282-
return self
283-
275+
def get_required_module_by_name(self, module_name: str) -> PlainModule:
284276
for module in self.all_required_modules:
285277
if module.module_name == module_name:
286278
return module
@@ -294,16 +286,22 @@ def get_next_module(self, module_name: str) -> PlainModule:
294286
return all_modules[idx + 1]
295287

296288
if module_name == self.module_name:
297-
return self
289+
return None
298290

299291
raise ModuleDoesNotExistError(f"Module {module_name} does not exist")
300292

301293
def get_next_frid(self, frid: str, module_name: str) -> tuple[str, PlainModule]:
302-
module = self.get_module_by_name(module_name)
294+
if module_name != self.module_name:
295+
module = self.get_required_module_by_name(module_name)
296+
else:
297+
module = self
298+
303299
next_frid = plain_spec.get_next_frid(module.plain_source, frid)
304300

305301
if next_frid is None:
306302
next_module = self.get_next_module(module_name)
303+
if next_module is None:
304+
next_module = self
307305
return plain_spec.get_first_frid(next_module.plain_source), next_module
308306

309307
return next_frid, module
@@ -335,3 +333,12 @@ def is_initial_module(self) -> bool:
335333
return True
336334

337335
return False
336+
337+
def wipe_module(self) -> None:
338+
if os.path.exists(self.module_build_folder):
339+
console.warning(f"Wiping module {self.module_build_folder}...")
340+
shutil.rmtree(self.module_build_folder)
341+
342+
if os.path.exists(self.module_conformance_tests_folder):
343+
console.warning(f"Wiping conformance tests for module {self.module_conformance_tests_folder}...")
344+
shutil.rmtree(self.module_conformance_tests_folder)

tests/test_partial_rendering.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,11 @@
66
under test relies on: ``module_name``, ``required_modules``,
77
``all_required_modules``, ``load_module_metadata``, ``get_module_source_hash``,
88
``get_module_code_hash`` and (for ``detect_partial_rendering``)
9-
``get_module_last_rendered_functionality``.
9+
``get_module_render_status``.
1010
"""
1111

1212
import pytest
1313

14-
# Import ``plain_file`` first — it pulls in ``file_utils`` which transitively
15-
# imports ``plain_modules``; starting the import graph at ``plain_file``
16-
# sidesteps a circular-import failure that occurs when tests import
17-
# ``partial_rendering`` (and therefore ``plain_modules``) first.
18-
import plain_file # noqa: F401
1914
from partial_rendering import (
2015
PartialRender,
2116
code_change,
@@ -61,7 +56,7 @@ def get_module_source_hash(self):
6156
def get_module_code_hash(self):
6257
return self._code_hash
6358

64-
def get_module_last_rendered_functionality(self):
59+
def get_module_render_status(self):
6560
return self._last_rendered
6661

6762

@@ -260,7 +255,7 @@ def test_detect_partial_rendering_raises_when_last_rendered_module_unknown():
260255
def test_detect_partial_rendering_spec_change_on_earlier_module_wins():
261256
"""A spec change on an earlier (required) module is reported via
262257
``change``/``change_type``; ``last_render_module`` and ``last_render_frid``
263-
remain the ones reported by ``get_module_last_rendered_functionality``."""
258+
remain the ones reported by ``get_module_render_status``."""
264259
root, middle, leaf = _build_fresh_tree(last_rendered=("middle", "1"))
265260
leaf._metadata = {"source_hash": "stale-leaf"} # leaf's spec changed
266261

0 commit comments

Comments
 (0)