Skip to content

Commit 5f103a0

Browse files
Improve errors for modules without functionality
Distinguish two cases when a module has no functionality to render: - No ***functional specs*** header at all: raise the new non-syntax MissingFunctionalitiesError with a clear, actionable message instead of the misleading 'was required but does not contain functional requirements' PlainSyntaxError. - Empty ***functional specs*** section: raise a PlainSyntaxError naming the empty section, instead of silently rendering zero functionalities or reporting a misleading 'no implementation reqs' error. Modules with at least one functionality still flow through the existing implementation-reqs validation.
1 parent 6c0af01 commit 5f103a0

6 files changed

Lines changed: 62 additions & 4 deletions

File tree

plain2code.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
InvalidAPIKey,
2929
InvalidFridArgument,
3030
MissingAPIKey,
31+
MissingFunctionalitiesError,
3132
MissingPreviousFunctionalitiesError,
3233
MissingResource,
3334
ModuleDoesNotExistError,
@@ -65,6 +66,7 @@
6566
MissingResource,
6667
TemplateNotFoundError,
6768
PlainSyntaxError,
69+
MissingFunctionalitiesError,
6870
MissingPreviousFunctionalitiesError,
6971
MissingAPIKey,
7072
InvalidAPIKey,

plain2code_exceptions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ class MissingPreviousFunctionalitiesError(Exception):
7878
pass
7979

8080

81+
class MissingFunctionalitiesError(Exception):
82+
"""Raised when a module to be rendered has no functionalities specified at all."""
83+
84+
pass
85+
86+
8187
class NetworkConnectionError(Exception):
8288
"""Raised when there is a network connectivity issue with the API server."""
8389

plain_file.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717
import concept_utils
1818
import file_utils
1919
import plain_spec
20-
from plain2code_exceptions import ModuleDoesNotExistError, PlainSyntaxError, UnsupportedBase64Content
20+
from plain2code_exceptions import (
21+
MissingFunctionalitiesError,
22+
ModuleDoesNotExistError,
23+
PlainSyntaxError,
24+
UnsupportedBase64Content,
25+
)
2126
from plain2code_nodes import Plain2CodeIncludeTag, Plain2CodeLoaderMixin
2227
from plain2code_utils import find_large_base64_blob
2328

@@ -726,11 +731,25 @@ def plain_file_parser( # noqa: C901
726731
f"Plain syntax error: Not all required concepts were defined. {missing_required_concepts_msg}."
727732
)
728733

729-
if not check_if_functional_requirements_are_specified(plain_file_parse_result.plain_source, []):
734+
fr_section = plain_file_parse_result.plain_source.get(plain_spec.FUNCTIONAL_REQUIREMENTS)
735+
736+
if fr_section is None:
737+
# Case 1: no ***functional specs*** header at all. Not a syntax error.
738+
raise MissingFunctionalitiesError(
739+
f"Module {module_name} does not have any functionality specified. "
740+
f"At least one functionality is required for rendering."
741+
)
742+
743+
if len(fr_section.children) == 0:
744+
# Case 2: ***functional specs*** header present but empty. Treated as a syntax error.
730745
raise PlainSyntaxError(
731-
f"Plain syntax error: Module '{module_name}' was required but does not contain functional requirements."
746+
f"Plain syntax error: Module '{module_name}' has an empty "
747+
f"'{plain_spec.FUNCTIONAL_REQUIREMENTS}' section. At least one functionality must be specified."
732748
)
733749

750+
# Functionalities exist: keep the existing "functionality with no implementation reqs specified" check.
751+
check_if_functional_requirements_are_specified(plain_file_parse_result.plain_source, [])
752+
734753
exported_definitions = process_required_modules(
735754
plain_file_parse_result.required_modules,
736755
code_variables={},
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
***implementation reqs***
2+
- Some requirement
3+
4+
***functional specs***
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
***definitions***
2+
- Test definition
3+
4+
***implementation reqs***
5+
- Some requirement

tests/test_plainfileparser.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import file_utils
1010
import plain_file
1111
import plain_spec
12-
from plain2code_exceptions import PlainSyntaxError
12+
from plain2code_exceptions import MissingFunctionalitiesError, PlainSyntaxError
1313

1414

1515
def test_regular_plain_source(get_test_data_path):
@@ -195,6 +195,28 @@ def test_without_non_functional_requirement(get_test_data_path):
195195
)
196196

197197

198+
def test_no_functional_specs_section(get_test_data_path):
199+
with pytest.raises(
200+
MissingFunctionalitiesError,
201+
match="does not have any functionality specified",
202+
):
203+
plain_file.plain_file_parser(
204+
"no_functional_specs_section.plain",
205+
[get_test_data_path("data/plainfile")],
206+
)
207+
208+
209+
def test_empty_functional_specs_section(get_test_data_path):
210+
with pytest.raises(
211+
PlainSyntaxError,
212+
match=re.escape("has an empty 'functional specs' section"),
213+
):
214+
plain_file.plain_file_parser(
215+
"empty_functional_specs_section.plain",
216+
[get_test_data_path("data/plainfile")],
217+
)
218+
219+
198220
def test_indented_include_tags():
199221
plain_source = """# Main
200222

0 commit comments

Comments
 (0)