Skip to content

Commit 862e33e

Browse files
committed
Add functionality to validate data section only
1 parent 63a2b91 commit 862e33e

File tree

3 files changed

+83
-9
lines changed

3 files changed

+83
-9
lines changed

__init__.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -333,14 +333,19 @@ def parse(
333333
with_progress=False,
334334
with_tree=True,
335335
with_header=False,
336-
only_header=False
336+
only_header=False,
337+
validate_data_only=False
337338
):
339+
if validate_data_only: # Used by the Validation Service to validate only the data section of an IFC file, ignoring the header.
340+
only_header = False
341+
with_header = False
342+
with_tree= False
338343
if filename:
339344
assert not filecontent
340345
filecontent = builtins.open(filename, encoding=None).read()
341346

342347
if only_header:
343-
assert with_header, "'only_header=True' requires 'with_header=True'"
348+
with_header = True
344349

345350
# Match and remove the comments
346351
p = r"/\*[\s\S]*?\*/"
@@ -407,8 +412,20 @@ def replace_fn(match):
407412

408413
NT = type("NullTransformer", (Transformer,), methods)
409414
transformer = {"transformer": NT()}
410-
411-
parser = Lark(grammar, parser="lalr", start="file", **transformer)
415+
416+
if validate_data_only:
417+
match = re.search(
418+
r"DATA\s*;(.*?)ENDSEC\s*;",
419+
filecontent_wo_comments,
420+
flags=re.DOTALL | re.IGNORECASE,
421+
)
422+
if not match:
423+
raise ValidationError("No DATA section found in file")
424+
filecontent_wo_comments = f"DATA;{match.group(1)}ENDSEC;"
425+
start_rule = "data_section"
426+
else:# Parse entire file (header + data)
427+
start_rule = "file"
428+
parser = Lark(grammar, parser="lalr", start=start_rule, **transformer)
412429

413430
try:
414431
ast = parser.parse(filecontent_wo_comments)

__main__.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,33 @@
66
args = [x for x in sys.argv[1:] if not x.startswith("-")]
77
flags = [x for x in sys.argv[1:] if x.startswith("-")]
88

9-
fn = args[0]
9+
filename = args[0]
1010
start_time = time.time()
11+
12+
with_progress = "--progress" in flags
13+
json_output = "--json" in flags
14+
only_header = "--header-only" in flags
15+
validate_data_only = "--data-only" in flags
16+
17+
18+
# Sanity check: can't use both at once
19+
if only_header and validate_data_only:
20+
print("Cannot use both --header-only and --data-only at the same time", file=sys.stderr)
21+
sys.exit(2)
1122

1223
try:
13-
parse(filename=fn, with_progress="--progress" in flags, with_tree=False)
14-
if "--json" not in flags:
24+
parse(
25+
filename=filename,
26+
with_progress=with_progress,
27+
with_tree=False,
28+
only_header=only_header,
29+
validate_data_only=validate_data_only,
30+
)
31+
if not json_output:
1532
print("Valid", file=sys.stderr)
1633
exit(0)
1734
except ValidationError as exc:
18-
if "--json" not in flags:
35+
if not json_output:
1936
print(exc, file=sys.stderr)
2037
else:
2138
import sys

test_parser.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,44 @@ def test_file_mvd_attr():
105105
assert f.mvd.Remark['SomeKey'] == 'SomeValue'
106106
assert len(f.mvd.comments) == 2
107107
assert all(v in vars(f.header).keys() for v in ['file_description', 'file_name', 'file_schema'])
108-
assert len(f.header.file_name) == 7
108+
assert len(f.header.file_name) == 7
109+
110+
111+
@pytest.mark.parametrize("filename", [
112+
'fixtures/fail_invalid_header_entity.ifc',
113+
'fixtures/fail_no_header.ifc',
114+
])
115+
def test_invalid_headers_(filename):
116+
# error in header; with_header should raise an error
117+
with pytest.raises(ValidationError):
118+
parse(filename=filename, with_tree=False, only_header=True, with_header=True)
119+
120+
@pytest.mark.parametrize("filename", [
121+
'fixtures/fail_duplicate_id.ifc',
122+
'fixtures/fail_double_comma.ifc',
123+
'fixtures/fail_double_semi.ifc'
124+
])
125+
def test_valid_headers(filename):
126+
# error in body; with_header should not raise an error
127+
with nullcontext():
128+
parse(filename=filename, with_tree=False, only_header=True, with_header=True)
129+
130+
131+
@pytest.mark.parametrize("filename", [
132+
'fixtures/fail_invalid_header_entity.ifc',
133+
'fixtures/fail_no_header.ifc',
134+
])
135+
def test_invalid_headers_(filename):
136+
# error in header; validate_data_only should not raise an error
137+
with nullcontext():
138+
parse(filename=filename, validate_data_only=True)
139+
140+
@pytest.mark.parametrize("filename", [
141+
'fixtures/fail_duplicate_id.ifc',
142+
'fixtures/fail_double_comma.ifc',
143+
'fixtures/fail_double_semi.ifc'
144+
])
145+
def test_valid_headers(filename):
146+
# error in body; validate_data_only should raise an error
147+
with pytest.raises(ValidationError):
148+
parse(filename=filename, validate_data_only=True)

0 commit comments

Comments
 (0)