diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b6b098da..875c6f5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: echo $CONDA/bin >> $GITHUB_PATH - name: Install dependencies run: | - pip install behave pytest tabulate pyparsing sqlalchemy numpy pydantic pydot sqlalchemy_utils django python-dotenv deprecated pandas + pip install behave pytest tabulate pyparsing sqlalchemy numpy pydantic pydot sqlalchemy_utils django python-dotenv deprecated pandas pyspellchecker wget -O /tmp/ifcopenshell_python.zip https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-`python3 -c 'import sys;print("".join(map(str, sys.version_info[0:2])))'`-v0.8.0-90ae709-linux64.zip mkdir -p `python3 -c 'import site; print(site.getusersitepackages())'` unzip -d `python3 -c 'import site; print(site.getusersitepackages())'` /tmp/ifcopenshell_python.zip diff --git a/features/IFC101_Only-official-ifc-versions-allowed.feature b/features/IFC101_Only-official-ifc-versions-allowed.feature index ea82cb86..82a84e46 100644 --- a/features/IFC101_Only-official-ifc-versions-allowed.feature +++ b/features/IFC101_Only-official-ifc-versions-allowed.feature @@ -3,7 +3,7 @@ @W00030 Feature: IFC101 - Only official IFC versions allowed -This rule verifies that the IFC model has a schema identifier corresponding to any of the official versions released by buildingSMART. +The rule verifies that the IFC model has a schema identifier corresponding to any of the official versions released by buildingSMART. Specifically, IFC2x3 TC1 (version 2.3.0.1), IFC4 ADD2 TC1 (version 4.0.2.1), or IFC4.3 ADD2 (version 4.3.2.0). Scenario: Verifying Current Schema Identifier for IFC version diff --git a/features/IFC102_Absence-of-deprecated-entities.feature b/features/IFC102_Absence-of-deprecated-entities.feature index b25fbdb2..aa8a9e65 100644 --- a/features/IFC102_Absence-of-deprecated-entities.feature +++ b/features/IFC102_Absence-of-deprecated-entities.feature @@ -4,7 +4,7 @@ @implementer-agreement Feature: IFC102 - Absence of deprecated entities -This rule verifies that the IFC model does not have deprecated entities, attributes or enumerators. +The rule verifies that the IFC model does not have deprecated entities, attributes or enumerators. By definition, a deprecated entity shall not be exported by applications. Complying interpreters shall still be able to import deprecated definitions. IFC2X3: https://standards.buildingsmart.org/IFC/RELEASE/IFC2x3/TC1/HTML/deprecated_constructs.htm diff --git a/features/rule_creation_protocol/protocol.py b/features/rule_creation_protocol/protocol.py index c06b23a1..7fbe0a1a 100644 --- a/features/rule_creation_protocol/protocol.py +++ b/features/rule_creation_protocol/protocol.py @@ -4,6 +4,7 @@ from pydantic import model_validator, field_validator, Field, ValidationError from pyparsing import Word, alphas, nums, Literal, Combine, StringEnd, alphanums, ParseException import pyparsing +from spellchecker import SpellChecker from .validation_helper import ValidatorHelper, ParsePattern @@ -178,14 +179,54 @@ def validate_ifc_input(cls, value): @field_validator('description') def validate_description(cls, value=list) -> list: - """must include a description of the rule that start with "The rule verifies ...""" # allow for comma's - if not any(value.startswith(f"{prefix} rule verifies{optional_comma}") for prefix in ("This", "The") for optional_comma in ("", ",")): + """ + Validates that the description starts with 'The rule verifies ...'. + Captures cases where an incorrect prefix is used or the format is entirely incorrect. + """ + valid_prefix = "The" + invalid_prefix = "This" + + valid_start = any(value.startswith(f"{prefix} rule verifies{optional_comma}") + for prefix in [valid_prefix, invalid_prefix] + for optional_comma in ("", ",")) + + incorrect_prefix_start = any(value.startswith(f"{prefix} rule verifies{optional_comma}") + for prefix in (invalid_prefix,) + for optional_comma in ("", ",")) + + if incorrect_prefix_start: raise ProtocolError( value=value, - message=f"The description must start with 'The rule verifies', it now starts with {value}" + message=f"The description starts with an incorrect prefix '{invalid_prefix}'. It should start with 'The rule verifies'." ) - return value + if not valid_start: + spell = SpellChecker() + misspelled_words = spell.unknown(value.split()[:4]) + if misspelled_words: + corrections = {word: spell.correction(word) for word in misspelled_words} + corrected_string = ' '.join([corrections.get(word, word) for word in value.split()]) + corrected_valid_start = any(corrected_string.startswith(f"{prefix} rule verifies{optional_comma}") + for prefix in [valid_prefix] + for optional_comma in ("", ",")) + + message = f"The feature description contains spelling errors. Here are the incorrect words and their suggested corrections: {corrections}." + + if not corrected_valid_start: + message += f" Additionally, after corrections, the description still does not start with 'The rule verifies'. It starts with '{' '.join(corrected_string.split()[:4])}'." + + raise ProtocolError( + value=value, + message=message + ) + else: + raise ProtocolError( + value=value, + message=f"The description must start with 'The rule verifies', but it now starts with '{' '.join(value.split()[:4])}'." + ) + + return value + @field_validator('steps') def validate_steps(cls, value): """Check only correct keywords are applied: 'Given', 'Then', 'And'"""