plain-parser 0.1.2.dev3__py3-none-any.whl → 0.1.2.dev4__py3-none-any.whl

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/loaders.py CHANGED
@@ -36,6 +36,20 @@ def open_from(dirs, file_name):
36
36
  return None
37
37
 
38
38
 
39
+ def resolve_linked_resource(dirs, file_name):
40
+ """Return the first existing path for file_name across dirs, or None if not found.
41
+
42
+ Mirrors the search order used by open_from so that validating a linked resource and
43
+ loading it can never disagree.
44
+ """
45
+ for dir in dirs:
46
+ full_file_name = os.path.join(dir, file_name)
47
+ if os.path.exists(full_file_name):
48
+ return full_file_name
49
+
50
+ return None
51
+
52
+
39
53
  def load_linked_resources(template_dirs: list[str], resources_list, module_name: str):
40
54
  linked_resources = {}
41
55
 
@@ -88,7 +88,7 @@ def remove_quotes(token):
88
88
  token.children = tuple(new_children)
89
89
 
90
90
 
91
- def check_section_for_linked_resources(section):
91
+ def check_section_for_linked_resources(section, template_dirs):
92
92
  linked_resources = []
93
93
  for link in traverse(section, klass=Link):
94
94
  parsed_url = urlparse(link.node.target)
@@ -97,11 +97,19 @@ def check_section_for_linked_resources(section):
97
97
  f"Plain syntax error: Only relative links are allowed (text: {link.node.children[0].content}, target: {link.node.target})."
98
98
  )
99
99
 
100
- if not os.path.exists(link.node.target):
101
- raise PlainSyntaxError(f"Plain syntax error: Link {link.node.target} does not exist.")
100
+ resolved_target = loaders.resolve_linked_resource(template_dirs, link.node.target)
101
+ if resolved_target is None:
102
+ searched_dirs = "\n".join(f" {position}. {dir}" for position, dir in enumerate(template_dirs, start=1))
103
+ raise PlainSyntaxError(
104
+ f"Plain syntax error: Link {link.node.target} does not exist. "
105
+ f"Linked resources are looked up relative to the following directories "
106
+ f"(highest to lowest precedence):\n{searched_dirs}"
107
+ )
102
108
 
103
- if not os.path.isfile(link.node.target):
104
- raise PlainSyntaxError(f"Plain syntax error: Link {link.node.target} must be a file.")
109
+ if not os.path.isfile(resolved_target):
110
+ raise PlainSyntaxError(
111
+ f"Plain syntax error: Link {link.node.target} must be a file (resolved to {resolved_target})."
112
+ )
105
113
 
106
114
  if len(link.node.children) != 1:
107
115
  raise PlainSyntaxError(f"Plain syntax error: Link must have text specified (link: {link.node.target}).")
@@ -120,15 +128,15 @@ def check_section_for_linked_resources(section):
120
128
  section.linked_resources = linked_resources
121
129
 
122
130
 
123
- def check_for_linked_resources(plain_source):
131
+ def check_for_linked_resources(plain_source, template_dirs):
124
132
  for specification_heading in plain_spec.ALLOWED_SPECIFICATION_HEADINGS:
125
133
  if specification_heading in plain_source and hasattr(plain_source[specification_heading], "children"):
126
134
  for requirement in plain_source[specification_heading].children:
127
- check_section_for_linked_resources(requirement)
135
+ check_section_for_linked_resources(requirement, template_dirs)
128
136
 
129
137
  if hasattr(requirement, plain_spec.ACCEPTANCE_TESTS):
130
138
  for acceptance_test in requirement.acceptance_tests:
131
- check_section_for_linked_resources(acceptance_test)
139
+ check_section_for_linked_resources(acceptance_test, template_dirs)
132
140
 
133
141
 
134
142
  def process_section_code_variables(section, code_variables):
@@ -756,7 +764,7 @@ def process_required_modules(
756
764
  )
757
765
 
758
766
  marshalled_plain_source = validate_and_marshall_module(
759
- plain_file_parse_result, module_name, ancestor_exported_definitions, code_variables
767
+ plain_file_parse_result, module_name, ancestor_exported_definitions, code_variables, template_dirs
760
768
  )
761
769
  if module_name not in (chain_module_name for chain_module_name, _ in chain):
762
770
  chain.append((module_name, marshalled_plain_source))
@@ -793,6 +801,7 @@ def validate_and_marshall_module(
793
801
  module_name: str,
794
802
  exported_definitions: list[mistletoe.block_token.token],
795
803
  code_variables: dict,
804
+ template_dirs: list[str],
796
805
  ) -> dict:
797
806
  """Every check a module must pass after parsing, and its marshalled plain source tree."""
798
807
  if len(plain_file_parse_result.required_concepts) > 0:
@@ -826,7 +835,7 @@ def validate_and_marshall_module(
826
835
 
827
836
  process_acceptance_tests(plain_file_parse_result.plain_source)
828
837
 
829
- check_for_linked_resources(plain_file_parse_result.plain_source)
838
+ check_for_linked_resources(plain_file_parse_result.plain_source, template_dirs)
830
839
 
831
840
  marshalled_plain_source = marshall_plain_source(plain_file_parse_result.plain_source)
832
841
 
@@ -881,7 +890,7 @@ def _parse_module(
881
890
  )
882
891
 
883
892
  marshalled_plain_source = validate_and_marshall_module(
884
- plain_file_parse_result, module_name, exported_definitions, code_variables
893
+ plain_file_parse_result, module_name, exported_definitions, code_variables, template_dirs
885
894
  )
886
895
 
887
896
  return module_name, marshalled_plain_source, plain_file_parse_result.required_modules, chain
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: plain-parser
3
- Version: 0.1.2.dev3
3
+ Version: 0.1.2.dev4
4
4
  Summary: Parser for ***plain specification files
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -3,11 +3,11 @@ plain_parser/cli.py,sha256=oJL_23l_K3ZWpJLRROGjFo2UOsJv7uUoP0RbfL8oit4,4682
3
3
  plain_parser/concept_utils.py,sha256=BJzddKxrwg2KbV-58R74ihIJKcv-CGA4B5NZyhOixQ8,8100
4
4
  plain_parser/exceptions.py,sha256=WcHK5g9K6bsE-ZZBKWl0lZtiMTQ6fif8-zdEx9qjmRw,795
5
5
  plain_parser/liquid_nodes.py,sha256=CYmujdPJMK9hLjfFPmnSoKL3Ps4sb-2OOhH-fZUssis,3917
6
- plain_parser/loaders.py,sha256=5drZ7OOPJQjEitjWL5W5NfJ0CUatxKHU1UOwm_xhKKE,3850
7
- plain_parser/plain_file.py,sha256=cddrat_XLi72q00ZRAANjwIMMXrQnEUYdKaT8qo-y1s,39206
6
+ plain_parser/loaders.py,sha256=eQbQ3bUzcTxj2FeKbNd8nAtInWwiLYbVbRSYkvebLxw,4286
7
+ plain_parser/plain_file.py,sha256=wI6NFbEQ5VeUKtqVv0rIbHNHdN2skQeaViVDalRONwc,39785
8
8
  plain_parser/plain_spec.py,sha256=31mLXDldi9zOXT9aK3QhD2mbxbph4ArFU_qgWYd2nwc,15309
9
- plain_parser-0.1.2.dev3.dist-info/METADATA,sha256=uh3mnC3PCi-4onNg4qrFD3sb_pvhIAyOUHTboAGH3xo,2681
10
- plain_parser-0.1.2.dev3.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
11
- plain_parser-0.1.2.dev3.dist-info/entry_points.txt,sha256=pA31GGUyYrmZSpH1CuSzhjrv8pX5ac5HI5hFop1B4eI,55
12
- plain_parser-0.1.2.dev3.dist-info/licenses/LICENSE,sha256=QClWKncxgRjNUVOW8Axi7zK9HtsMdJEtUSMA4LEe8fo,1071
13
- plain_parser-0.1.2.dev3.dist-info/RECORD,,
9
+ plain_parser-0.1.2.dev4.dist-info/METADATA,sha256=eQwOQvOgxL5suXwe95ZU309v06PgOhJhGibCQUng5x0,2681
10
+ plain_parser-0.1.2.dev4.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
11
+ plain_parser-0.1.2.dev4.dist-info/entry_points.txt,sha256=pA31GGUyYrmZSpH1CuSzhjrv8pX5ac5HI5hFop1B4eI,55
12
+ plain_parser-0.1.2.dev4.dist-info/licenses/LICENSE,sha256=QClWKncxgRjNUVOW8Axi7zK9HtsMdJEtUSMA4LEe8fo,1071
13
+ plain_parser-0.1.2.dev4.dist-info/RECORD,,