plain-parser 0.1.2.dev4__tar.gz → 0.1.2.dev5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/PKG-INFO +1 -1
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/src/plain_parser/concept_utils.py +2 -2
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/src/plain_parser/loaders.py +19 -4
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/src/plain_parser/plain_file.py +8 -6
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/src/plain_parser/plain_spec.py +1 -1
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/concept_validation_noconcepts.plain +0 -1
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/concept_validation_redefinition.plain +0 -1
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/required_concepts_example.plain +1 -1
- plain_parser-0.1.2.dev5/tests/data/templates/malformed_tag.plain +4 -0
- plain_parser-0.1.2.dev5/tests/data/templates/unterminated_output.plain +3 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/test_loaders.py +45 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/test_plainfileparser.py +11 -3
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/.flake8 +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/.github/workflows/lint-and-test.yml +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/.github/workflows/publish-dev-to-pypi.yml +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/.github/workflows/publish-to-pypi.yml +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/.gitignore +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/LICENSE +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/README.md +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/pyproject.toml +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/src/plain_parser/__init__.py +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/src/plain_parser/cli.py +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/src/plain_parser/exceptions.py +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/src/plain_parser/liquid_nodes.py +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/__init__.py +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/conftest.py +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/acceptance_test_binary_resource.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/acceptance_test_resource.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/base64_resource.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/binary.bin +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/binary_resource.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/code_variable_conflict.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/code_variable_template.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/missing_resource.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/not_plain.md +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/notes.md +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/requires_binary_resource_base.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/requires_binary_resource_top.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/subdir/nested.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/undefined_concept.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/valid.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/circular_imports_1.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/circular_imports_2.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/circular_imports_main.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/diamond_import_1.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/diamond_import_2.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/diamond_import_common.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/diamond_imports_main.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/import_with_functionalities.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/imports_module_with_functionalities.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/non_existent_import.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfile/add_new_task_modal_specification.yaml +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfile/duplicate_specification_heading.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfile/empty_functional_specs_section.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfile/invalid_specification_order.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfile/missing_non_functional_requirements.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfile/no_functional_specs_section.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfile/plain_source_with_absolute_link.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfile/plain_source_with_missing_link.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfile/plain_source_with_url_link.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfile/task_list_ui_specification.yaml +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfile/task_manager_with_reference_links.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfile/without_non_functional_requirement.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/concept_validation_acceptance_tests.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/concept_validation_acceptance_tests_nondefined.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/concept_validation_defined_nondefined.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/concept_validation_defined_nondefined_2.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/concept_validation_definition.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/concept_validation_nonconcept.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/concept_validation_nondefined.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/concept_validation_several_concepts.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/concept_validation_valid.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/cyclic_definitions.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_base.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_defaults_exported.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_example.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_imported_exported.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_inherited_reexported.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_malformed.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_missing_definition.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_missing_definition_example.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_multiple_per_bullet.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_multiple_per_bullet_undefined.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_nested.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_nested_example.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_no_definitions.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_not_declared.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_not_declared_example.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_transitive_example.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_transitive_l1.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/exported_concepts_transitive_l2.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/plain_file_parser_with_comments.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/plain_file_with_comments_indented.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/regular_plain_source.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/required_concepts.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/required_concepts_defs.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/required_concepts_l1.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/required_concepts_l2.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/required_concepts_missing.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/required_concepts_module.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/required_concepts_partial.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/required_concepts_partial_duplicate.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/requires_without_definitions_example.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/topological_sort.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/plainfileparser/topological_sort_not_referenced.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/chain_base.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/chain_fork_top.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/chain_middle.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/chain_top.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/circular_requires_main.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/circular_requires_sub.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/diamond_requires_1.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/diamond_requires_2.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/diamond_requires_common.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/diamond_requires_main.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/independent_requires_1.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/independent_requires_2.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/independent_requires_main.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/invalid_ancestor_base.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/invalid_ancestor_top.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/non_existent_require.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/normal_requires_1.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/normal_requires_2.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/normal_requires_common.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/normal_requires_main.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/sample_base64_image.txt +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/simple.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/templates/block_level_include.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/templates/code_variables.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/templates/header.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/templates/implement.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/templates/implement_2.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/templates/template_include.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/templates/test_hardest_problem.plain +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/test_cli.py +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/test_exceptions.py +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/test_imports.py +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/test_plainfile.py +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/test_plainspec.py +0 -0
- {plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/test_requires.py +0 -0
|
@@ -200,14 +200,14 @@ def sort_definitions(definitions: list[dict]) -> list[dict]:
|
|
|
200
200
|
concept_graph.add_node(node)
|
|
201
201
|
|
|
202
202
|
if not nx.is_directed_acyclic_graph(concept_graph):
|
|
203
|
-
msg = "Found cycles in the concept graph. Cycles are not allowed."
|
|
203
|
+
msg = "Found cycles in the concept graph. Cycles are not allowed. "
|
|
204
204
|
all_cycles = list(nx.simple_cycles(concept_graph))
|
|
205
205
|
|
|
206
206
|
for cycle in all_cycles:
|
|
207
207
|
cyclic_definitions = []
|
|
208
208
|
cyclic_definitions.append(concept_definitions[cycle[0]]["markdown"])
|
|
209
209
|
cyclic_definitions.append(concept_definitions[cycle[1]]["markdown"])
|
|
210
|
-
msg += "Cyclic
|
|
210
|
+
msg += "Cyclic definitions:\n"
|
|
211
211
|
msg += "\n".join(cyclic_definitions)
|
|
212
212
|
msg += "\n"
|
|
213
213
|
|
|
@@ -3,10 +3,10 @@ import re
|
|
|
3
3
|
from typing import Optional
|
|
4
4
|
|
|
5
5
|
from liquid2 import Environment, FileSystemLoader, StrictUndefined
|
|
6
|
-
from liquid2.exceptions import UndefinedError
|
|
6
|
+
from liquid2.exceptions import LiquidSyntaxError, UndefinedError
|
|
7
7
|
|
|
8
8
|
from plain_parser import plain_spec
|
|
9
|
-
from plain_parser.exceptions import UnsupportedBase64Content, UnsupportedResourceType
|
|
9
|
+
from plain_parser.exceptions import PlainSyntaxError, UnsupportedBase64Content, UnsupportedResourceType
|
|
10
10
|
from plain_parser.liquid_nodes import Plain2CodeIncludeTag, Plain2CodeLoaderMixin
|
|
11
11
|
|
|
12
12
|
MAX_BASE64_BLOB_LENGTH = 8192
|
|
@@ -95,7 +95,20 @@ class TrackingFileSystemLoader(Plain2CodeLoaderMixin, FileSystemLoader):
|
|
|
95
95
|
return source
|
|
96
96
|
|
|
97
97
|
|
|
98
|
-
def
|
|
98
|
+
def liquid_error_message(error: LiquidSyntaxError) -> str:
|
|
99
|
+
# Built from attributes: str() of some liquid2 syntax errors (e.g. an unterminated `{{ x`) raises ValueError.
|
|
100
|
+
template_name = error.template_name or None
|
|
101
|
+
token = error.token
|
|
102
|
+
if token is None or token.start < 0:
|
|
103
|
+
where = f" in {template_name}" if template_name else ""
|
|
104
|
+
else:
|
|
105
|
+
line = token.source[: token.start].count("\n") + 1
|
|
106
|
+
column = token.start - (token.source.rfind("\n", 0, token.start) + 1)
|
|
107
|
+
where = f" at {template_name}:{line}:{column}" if template_name else f" at {line}:{column}"
|
|
108
|
+
return f"Plain syntax error: Invalid Liquid{where}: {error.message}"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def get_loaded_templates(source_path, plain_source, template_name=None):
|
|
99
112
|
# Render the plain source with Liquid templating engine
|
|
100
113
|
# to identify the templates that are being loaded
|
|
101
114
|
|
|
@@ -106,9 +119,11 @@ def get_loaded_templates(source_path, plain_source):
|
|
|
106
119
|
liquid_env.filters["code_variable"] = plain_spec.code_variable_liquid_filter
|
|
107
120
|
liquid_env.filters["prohibited_chars"] = plain_spec.prohibited_chars_liquid_filter
|
|
108
121
|
|
|
109
|
-
plain_source_template = liquid_env.from_string(plain_source)
|
|
110
122
|
try:
|
|
123
|
+
plain_source_template = liquid_env.from_string(plain_source, name=template_name or "")
|
|
111
124
|
plain_source = plain_source_template.render()
|
|
125
|
+
except LiquidSyntaxError as e:
|
|
126
|
+
raise PlainSyntaxError(liquid_error_message(e))
|
|
112
127
|
except UndefinedError as e:
|
|
113
128
|
raise Exception(f"Undefined liquid variable: {str(e)}")
|
|
114
129
|
|
|
@@ -240,7 +240,7 @@ def _is_acceptance_test_heading(token) -> tuple[bool, str | None]:
|
|
|
240
240
|
content = strong_children[0].content.strip()
|
|
241
241
|
if content == plain_spec.ACCEPTANCE_TEST_HEADING:
|
|
242
242
|
return True, None
|
|
243
|
-
problem = f"Syntax error at line {token.line_number}: Invalid acceptance test heading (`{content}`). Expected: `{plain_spec.ACCEPTANCE_TEST_HEADING}
|
|
243
|
+
problem = f"Syntax error at line {token.line_number}: Invalid acceptance test heading (`{content}`). Expected: `{plain_spec.ACCEPTANCE_TEST_HEADING}`."
|
|
244
244
|
return False, problem
|
|
245
245
|
|
|
246
246
|
|
|
@@ -508,6 +508,7 @@ def parse_plain_source( # noqa: C901
|
|
|
508
508
|
template_dirs: list[str],
|
|
509
509
|
imported_modules: list[str],
|
|
510
510
|
modules_trace: list[str],
|
|
511
|
+
module_name: str | None = None,
|
|
511
512
|
) -> PlainFileParseResult:
|
|
512
513
|
plain_source_text = normalize_line_endings(plain_source_text)
|
|
513
514
|
|
|
@@ -527,7 +528,7 @@ def parse_plain_source( # noqa: C901
|
|
|
527
528
|
else:
|
|
528
529
|
required_concepts = list[str]()
|
|
529
530
|
|
|
530
|
-
[_, loaded_templates] = loaders.get_loaded_templates(template_dirs, plain_source_text)
|
|
531
|
+
[_, loaded_templates] = loaders.get_loaded_templates(template_dirs, plain_source_text, module_name)
|
|
531
532
|
|
|
532
533
|
plain_source_content = restore_stripped_lines(plain_source_text, plain_source_obj.content)
|
|
533
534
|
|
|
@@ -585,7 +586,7 @@ def parse_plain_source( # noqa: C901
|
|
|
585
586
|
|
|
586
587
|
if specification_heading == plain_spec.DEFINITIONS and current_specification_heading is not None:
|
|
587
588
|
raise PlainSyntaxError(
|
|
588
|
-
f"Plain syntax error: Syntax error at line {token.line_number}: Definitions specification must be the first specification in the section
|
|
589
|
+
f"Plain syntax error: Syntax error at line {token.line_number}: Definitions specification must be the first specification in the section (`{token_text}`)"
|
|
589
590
|
)
|
|
590
591
|
|
|
591
592
|
current_specification_heading = specification_heading
|
|
@@ -602,7 +603,7 @@ def parse_plain_source( # noqa: C901
|
|
|
602
603
|
|
|
603
604
|
else:
|
|
604
605
|
raise PlainSyntaxError(
|
|
605
|
-
f"Plain syntax error: Syntax error at line {token.line_number}: Invalid source structure
|
|
606
|
+
f"Plain syntax error: Syntax error at line {token.line_number}: Invalid source structure (`{token_text}`)"
|
|
606
607
|
)
|
|
607
608
|
|
|
608
609
|
# Acceptance tests are only allowed nested under functional specs. Reject them when
|
|
@@ -681,8 +682,8 @@ def read_module_plain_source(module_name: str, template_dirs: list[str]) -> str:
|
|
|
681
682
|
if blob is not None:
|
|
682
683
|
raise UnsupportedBase64Content(
|
|
683
684
|
f"Module '{module_name}' contains a base64-encoded blob ({len(blob)} characters) "
|
|
684
|
-
"inlined in the specification. This is not supported."
|
|
685
|
-
"Remove the base64 data from the .plain file or if necessary,"
|
|
685
|
+
"inlined in the specification. This is not supported. "
|
|
686
|
+
"Remove the base64 data from the .plain file or if necessary, "
|
|
686
687
|
"include the binary file path in the specification."
|
|
687
688
|
)
|
|
688
689
|
|
|
@@ -704,6 +705,7 @@ def parse_plain_file(
|
|
|
704
705
|
template_dirs,
|
|
705
706
|
imported_modules,
|
|
706
707
|
modules_trace + [module_name],
|
|
708
|
+
module_name=module_name,
|
|
707
709
|
)
|
|
708
710
|
|
|
709
711
|
|
|
@@ -126,7 +126,7 @@ def collect_linked_resources(
|
|
|
126
126
|
):
|
|
127
127
|
|
|
128
128
|
if not isinstance(plain_source_tree, dict):
|
|
129
|
-
raise ValueError("
|
|
129
|
+
raise ValueError("plain_source_tree must be a dictionary.")
|
|
130
130
|
|
|
131
131
|
if frid is not None:
|
|
132
132
|
functional_requirements = get_frids(plain_source_tree)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import re
|
|
2
3
|
import tempfile
|
|
3
4
|
|
|
4
5
|
import pytest
|
|
@@ -137,3 +138,47 @@ def test_resolve_linked_resource_directory_in_first_dir_shadows_file_in_second()
|
|
|
137
138
|
f.write("x")
|
|
138
139
|
|
|
139
140
|
assert resolve_linked_resource([first, second], "notes.md") == os.path.join(first, "notes.md")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _load_template_fixture(name):
|
|
144
|
+
path = os.path.join(os.path.dirname(__file__), "data", "templates", f"{name}.plain")
|
|
145
|
+
with open(path, encoding="utf-8") as f:
|
|
146
|
+
return os.path.dirname(path), f.read()
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def test_get_loaded_templates_malformed_tag_raises_plain_syntax_error():
|
|
150
|
+
from plain_parser.exceptions import PlainSyntaxError
|
|
151
|
+
from plain_parser.loaders import get_loaded_templates
|
|
152
|
+
|
|
153
|
+
directory, source = _load_template_fixture("malformed_tag")
|
|
154
|
+
|
|
155
|
+
with pytest.raises(
|
|
156
|
+
PlainSyntaxError,
|
|
157
|
+
match=re.escape("Plain syntax error: Invalid Liquid at malformed_tag:3:0: "),
|
|
158
|
+
):
|
|
159
|
+
get_loaded_templates([directory], source, "malformed_tag")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_get_loaded_templates_unterminated_output_raises_plain_syntax_error():
|
|
163
|
+
from plain_parser.exceptions import PlainSyntaxError
|
|
164
|
+
from plain_parser.loaders import get_loaded_templates
|
|
165
|
+
|
|
166
|
+
directory, source = _load_template_fixture("unterminated_output")
|
|
167
|
+
|
|
168
|
+
with pytest.raises(
|
|
169
|
+
PlainSyntaxError,
|
|
170
|
+
match=re.escape("Plain syntax error: Invalid Liquid at unterminated_output:4:0: "),
|
|
171
|
+
):
|
|
172
|
+
get_loaded_templates([directory], source, "unterminated_output")
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def test_liquid_error_message_without_position():
|
|
176
|
+
from liquid2.exceptions import LiquidSyntaxError
|
|
177
|
+
|
|
178
|
+
from plain_parser.loaders import liquid_error_message
|
|
179
|
+
|
|
180
|
+
error = LiquidSyntaxError("missing expression", token=None, template_name="header")
|
|
181
|
+
assert liquid_error_message(error) == "Plain syntax error: Invalid Liquid in header: missing expression"
|
|
182
|
+
|
|
183
|
+
error = LiquidSyntaxError("missing expression", token=None)
|
|
184
|
+
assert liquid_error_message(error) == "Plain syntax error: Invalid Liquid: missing expression"
|
|
@@ -62,7 +62,7 @@ code block
|
|
|
62
62
|
"""
|
|
63
63
|
with pytest.raises(
|
|
64
64
|
Exception,
|
|
65
|
-
match=re.escape("Syntax error at line 3: Invalid source structure
|
|
65
|
+
match=re.escape("Syntax error at line 3: Invalid source structure (`code block`)"),
|
|
66
66
|
):
|
|
67
67
|
plain_file.parse_plain_source(plain_source, {}, [], [], [])
|
|
68
68
|
|
|
@@ -602,7 +602,7 @@ def test_concept_validation_definitions(get_test_data_path):
|
|
|
602
602
|
[get_test_data_path("data/plainfileparser")],
|
|
603
603
|
)
|
|
604
604
|
|
|
605
|
-
with pytest.raises(PlainSyntaxError):
|
|
605
|
+
with pytest.raises(PlainSyntaxError, match=re.escape("Invalid definition specification text")):
|
|
606
606
|
plain_file.plain_file_parser(
|
|
607
607
|
"concept_validation_noconcepts.plain",
|
|
608
608
|
[get_test_data_path("data/plainfileparser")],
|
|
@@ -635,7 +635,7 @@ def test_concept_validation_usage(get_test_data_path):
|
|
|
635
635
|
|
|
636
636
|
|
|
637
637
|
def test_concept_validation_redefinition(get_test_data_path):
|
|
638
|
-
with pytest.raises(PlainSyntaxError):
|
|
638
|
+
with pytest.raises(PlainSyntaxError, match=re.escape("Concepts were defined multiple times")):
|
|
639
639
|
plain_file.plain_file_parser(
|
|
640
640
|
"concept_validation_redefinition.plain",
|
|
641
641
|
[get_test_data_path("data/plainfileparser")],
|
|
@@ -771,3 +771,11 @@ def test_topological_sort(get_test_data_path):
|
|
|
771
771
|
{"markdown": "- :Concept4: is a concept that depends on the :Concept3: concept."},
|
|
772
772
|
{"markdown": "- :Concept6: is a concept that depends on the :Concept1: and :Concept4: concepts."},
|
|
773
773
|
]
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
def test_liquid_syntax_error_names_module(get_test_data_path):
|
|
777
|
+
with pytest.raises(
|
|
778
|
+
PlainSyntaxError,
|
|
779
|
+
match=re.escape("Plain syntax error: Invalid Liquid at unterminated_output:4:0: "),
|
|
780
|
+
):
|
|
781
|
+
plain_file.plain_file_parser("unterminated_output.plain", [get_test_data_path("data/templates")])
|
|
File without changes
|
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/.github/workflows/publish-dev-to-pypi.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/acceptance_test_resource.plain
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/code_variable_conflict.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/cli/code_variable_template.plain
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/circular_imports_1.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/circular_imports_2.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/circular_imports_main.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/diamond_import_1.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/diamond_import_2.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/diamond_import_common.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/diamond_imports_main.plain
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/imports/non_existent_import.plain
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/chain_fork_top.plain
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/circular_requires_main.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/circular_requires_sub.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/diamond_requires_1.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/diamond_requires_2.plain
RENAMED
|
File without changes
|
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/diamond_requires_main.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/independent_requires_1.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/independent_requires_2.plain
RENAMED
|
File without changes
|
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/invalid_ancestor_base.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/invalid_ancestor_top.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/non_existent_require.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/normal_requires_1.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/normal_requires_2.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/normal_requires_common.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/requires/normal_requires_main.plain
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/templates/block_level_include.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/templates/code_variables.plain
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/templates/template_include.plain
RENAMED
|
File without changes
|
{plain_parser-0.1.2.dev4 → plain_parser-0.1.2.dev5}/tests/data/templates/test_hardest_problem.plain
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|