Compare commits

..

4 Commits

Author SHA1 Message Date
Jonathon Broughton cccf3b1dc3 Update developer guide for Checker function
Expanded the developer guide with detailed setup instructions, project overview, and testing procedures. Added sections on test automation environment, integration tests, and TDD workflow for rule development. Included troubleshooting tips and future development ideas to enhance functionality.
2025-02-28 16:00:53 +00:00
Jonathon Broughton 5c93c6861a Update README for Speckle Checker functionality
Expanded the overview of the Speckle Checker, detailing its purpose and how it simplifies validation through spreadsheets. Updated usage instructions to include step-by-step guidance on preparing rule spreadsheets and creating automations. Added sections on rule definition format, supported predicates, and example rules for clarity. Enhanced support information at the end.
2025-02-28 16:00:42 +00:00
Jonathon Broughton 7d3afe4f9f Merge remote-tracking branch 'origin/main' 2025-02-28 15:00:09 +00:00
Jonathon Broughton 997b1049aa Added over the top levels of documentation for future developers 2025-02-28 14:54:46 +00:00
6 changed files with 60 additions and 81 deletions
-1
View File
@@ -44,4 +44,3 @@ jobs:
speckle_function_id: ${{ secrets.SPECKLE_FUNCTION_ID }}
speckle_function_input_schema_file_path: ${{ env.FUNCTION_SCHEMA_FILE_NAME }}
speckle_function_command: 'python -u main.py run'
speckle_function_recommended_memory_mi: 5000
-3
View File
@@ -4,7 +4,4 @@
<option name="sdkName" value="WSL Checker" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="uv (Checker)" project-jdk-type="Python SDK" />
<component name="PythonCompatibilityInspectionAdvertiser">
<option name="version" value="3" />
</component>
</project>
+46 -55
View File
@@ -1,13 +1,14 @@
# Model Checker
# Speckle Checker
Model Checker is an Automate function that validates Speckle objects against configurable rules. This approach provides
a flexible way to implement quality checks and maintain consistent standards across projects.
Speckle Checker is an Automate function that validates Speckle objects against configurable rules defined in a
spreadsheet. This approach provides a flexible way to implement quality checks without coding, making it accessible to
all team members.
## Overview
The Model Checker allows you to:
The Checker function allows you to:
- Define validation rules for your objects
- Define validation rules in a spreadsheet
- Configure severity levels for issues
- Check properties across different types of objects
- Generate reports of validation results
@@ -15,35 +16,39 @@ The Model Checker allows you to:
## Getting Started
### 1. Access the Model Checker Application
### 1. Prepare Your Rule Spreadsheet
1. Go to the [Model Checker Application](https://model-checker.speckle.systems)
2. Sign in with your Speckle account
3. Create and manage your validation rules through the intuitive web interface
1. Access the [template spreadsheet](https://docs.google.com/spreadsheets/d/1hiPSw23eOaqd27QD_YsXvZg9PWm7_XBx/edit) (
make a copy to your drive)
2. Define your rules using the format explained below
3. Publish your rules by clicking "File > Download > Tab-separated values (.tsv)"
4. Upload the TSV file to a hosting service (Google Drive, Dropbox, etc.) and get a public URL
### 2. Create an Automation
1. Go to your workspace project in [Speckle](https://app.speckle.systems/)
1. Go to [Speckle Automate](https://automate.speckle.dev/)
2. Create a new Automation
3. Select the Model Checker function
3. Select the Checker function
4. Configure the function:
- Paste your TSV URL
- Set minimum severity level to report
- Configure other options as needed
5. Save and run your automation
## Rule Definition Format
Rules are defined with the following components:
Rules are defined in a spreadsheet with the following columns:
| Logic | Property Name | Predicate | Value | Message | Report Severity |
|-------|---------------|--------------|-----------|----------------------|-----------------|
| WHERE | category | matches | Walls | Wall thickness check | ERROR |
| CHECK | Width | greater than | 200 | | |
| WHERE | category | matches | Columns | Column height check | WARNING |
| AND | height | in range | 2500,4000 | | |
| Rule Number | Logic | Property Name | Predicate | Value | Message | Report Severity |
|-------------|-------|---------------|--------------|-----------|----------------------|-----------------|
| 1 | WHERE | category | matches | Walls | Wall thickness check | ERROR |
| 1 | AND | Width | greater than | 200 | | |
| 2 | WHERE | category | matches | Columns | Column height check | WARNING |
| 2 | AND | height | in range | 2500,4000 | | |
### Component Explanation
### Column Explanation
- **Rule Number**: Groups conditions that belong to the same rule
- **Logic**: Defines how conditions are combined (WHERE, AND, CHECK)
- **Property Name**: The object property or parameter to check
- **Predicate**: Comparison operation (equals, greater than, etc.)
@@ -53,20 +58,20 @@ Rules are defined with the following components:
### Supported Predicates
| Predicate | Description | Example |
|------------------|-----------------------------|---------------------------------------|
| exists | Checks if a property exists | `height` exists |
| equal to | Exact value match | `width` equal to `300` |
| not equal to | Value doesn't match | `material` not equal to `Concrete` |
| greater than | Value exceeds threshold | `height` greater than `3000` |
| less than | Value below threshold | `thickness` less than `50` |
| in range | Value within bounds | `elevation` in range `0,10000` |
| in list | Value in allowed set | `type` in list `W1,W2,W3` |
| contains | Property contains substring | `name` contains `Beam` |
| does not contain | Property doesn't contain | `name` does not contain `temp` |
| is true | Boolean property is true | `is_structural` is true |
| is false | Boolean property is false | `is_placeholder` is false |
| is like | Loose text matching | `name` is like `Wall` matches `Walls` |
| Predicate | Description | Example |
|------------------|-----------------------------|------------------------------------|
| exists | Checks if a property exists | `height` exists |
| equal to | Exact value match | `width` equal to `300` |
| not equal to | Value doesn't match | `material` not equal to `Concrete` |
| greater than | Value exceeds threshold | `height` greater than `3000` |
| less than | Value below threshold | `thickness` less than `50` |
| in range | Value within bounds | `elevation` in range `0,10000` |
| in list | Value in allowed set | `type` in list `W1,W2,W3` |
| contains | Property contains substring | `name` contains `Beam` |
| does not contain | Property doesn't contain | `name` does not contain `temp` |
| is true | Boolean property is true | `is_structural` is true |
| is false | Boolean property is false | `is_placeholder` is false |
| is like | Pattern matching | `name` is like `^BR\d+$` |
## Rule Logic
@@ -79,7 +84,7 @@ are reported as issues.
## Working with Object Properties
The Model Checker understands properties in Speckle objects regardless of schema:
The Checker understands properties in Speckle objects regardless of schema:
- Direct properties: `category`, `name`, `id`
- Nested properties: `parameters.WIDTH.value`
@@ -90,41 +95,27 @@ The Model Checker understands properties in Speckle objects regardless of schema
### Wall Thickness Check
```
Rule: WHERE category equals "Walls" AND width less than "200"
Message: "Walls must have width of at least 200."
Rule 1: WHERE category equals "Walls" AND width less than "200"
Message: "Wall too thin - minimum thickness is 200mm"
Severity: ERROR
```
### Door Naming Convention
```
Rule: WHERE category equals "Doors" AND name is not like "^D\d{3}$"
Message: "All doors must have a name that follows the format "D" followed by three digits."
Rule 2: WHERE category equals "Doors" AND name is not like "^D\d{3}$"
Message: "Door name must follow pattern D followed by 3 digits"
Severity: WARNING
```
### Structural Column Height Range
```
Rule: WHERE category equals "Columns" AND is_structural is true AND height not in range "2400,4000"
Message: "Structural columns must have a height between 2400 and 4000."
Rule 3: WHERE category equals "Columns" AND is_structural is true AND height not in range "2400,4000"
Message: "Structural column height outside acceptable range (2400-4000mm)"
Severity: ERROR
```
## Support
For issues or questions, please let us know on the [Speckle Community Forum](https://speckle.community/).
### Alternative: TSV File Format
While the Model Checker Application is the recommended way to create and manage rules, you can also create compatible
TSV (Tab-Separated Values) files manually. This can be useful for:
- Programmatically generating rules
- Version controlling rules in a text format
- Integrating with existing workflows
- Creating rules in bulk
The TSV file should follow the same structure as shown in the table above, with columns separated by tabs. The file will
then need to be hosted somewhere and served with MIME-type of `text/tab-separated-values` and the URL used in the
automation configuration.
For issues or questions, please open a GitHub issue or contact your Speckle support representative.
+6 -12
View File
@@ -95,7 +95,7 @@ def evaluate_condition(
Returns:
True if the condition is met, False otherwise
"""
property_name = condition.get("Property Name", condition.get("Property Path"))
property_name = condition["Property Name"]
predicate_key = condition["Predicate"]
value = condition["Value"]
@@ -263,27 +263,21 @@ def apply_rules_to_objects(
rules_processed += 1
# Ensure rule_group has necessary columns
if "Message" not in rule_group.columns or (
"Report Severity" not in rule_group.columns and "Severity" not in rule_group.columns
):
if "Message" not in rule_group.columns or "Report Severity" not in rule_group.columns:
continue # Or raise an exception if these columns are mandatory
pass_objects, fail_objects = process_rule(speckle_objects, rule_group)
# Get the severity level for this rule
rule_severity = get_severity(rule_group.iloc[-1])
rule_severity_level = severity_levels[MinimumSeverity(rule_severity.value)]
# Check if the rule severity level meets the minimum severity level - no point in processing lower severity rules
if rule_severity_level < min_severity_level:
continue
pass_objects, fail_objects = process_rule(speckle_objects, rule_group)
# For passing objects, only attach if we're showing all levels (INFO)
if minimum_severity == MinimumSeverity.INFO:
attach_results(pass_objects, rule_group.iloc[-1], rule_id_str, automate_context, True)
# For failing objects, attach if they meet minimum severity threshold
if len(fail_objects) and rule_severity_level >= min_severity_level:
if rule_severity_level >= min_severity_level:
attach_results(fail_objects, rule_group.iloc[-1], rule_id_str, automate_context, False)
if len(pass_objects) == 0 and len(fail_objects) == 0 and not hide_skipped:
@@ -329,7 +323,7 @@ def get_severity(rule_info: pd.Series) -> SeverityLevel:
Returns:
Appropriate SeverityLevel enum value
"""
severity = rule_info.get("Report Severity") or rule_info.get("Severity") # Extract severity from input data
severity = rule_info.get("Report Severity") # Extract severity from input data
# If severity is None or not a string (e.g., numeric input), default to ERROR
if not isinstance(severity, str):
+6 -6
View File
@@ -64,10 +64,8 @@ def process_rule_numbers(df: DataFrame) -> DataFrame:
# Get slice of rows for this group
group_slice = df.iloc[start_idx:end_idx]
# Try to get rule number from first row, fall back to "Rule #"
group_rule_num = (
group_slice["Rule Number"].iloc[0] if not pd.isna(group_slice["Rule Number"].iloc[0]) else "Rule #"
)
# Try to get rule number from first row
group_rule_num = group_slice["Rule Number"].iloc[0]
if pd.isna(group_rule_num):
# If no rule number, generate next available number
@@ -92,7 +90,8 @@ def process_rule_numbers(df: DataFrame) -> DataFrame:
def validate_rule_numbers(df: DataFrame) -> list[str]:
"""Validate rule numbers and return any warnings or errors.
""" "
Validate rule numbers and return any warnings or errors.
This checks for issues like:
1. Missing rule numbers
@@ -129,7 +128,8 @@ def validate_rule_numbers(df: DataFrame) -> list[str]:
def read_rules_from_spreadsheet(url: str) -> tuple[DataFrameGroupBy, list[str]] | tuple[None, list[str]]:
"""Reads rules from a TSV file at the provided URL, processes them, and returns grouped rules.
""" "
Reads rules from a TSV file at the provided URL, processes them, and returns grouped rules.
This function is the main entry point for rule loading:
1. Reads the TSV file from the provided URL
+2 -4
View File
@@ -30,14 +30,12 @@ class TestFunction:
"""Run an integration test for the automate function."""
automation_context = AutomationContext.initialize(test_automation_run_data, test_automation_token)
default_url: str = (
"https://speckle-model-checker-cedxvz7lzq-ew.a.run.app/r/6hdycwPELyTIT7Ueedh0UsWdJlTBefwSjDlcnd8LXGg/tsv"
)
default_url: str = "https://drive.google.com/uc?export=download&id=1hiPSw23eOaqd27QD_YsXvZg9PWm7_XBx"
automate_sdk = run_function(
automation_context,
automate_function,
FunctionInputs(spreadsheet_url=default_url, minimum_severity=MinimumSeverity.INFO, hide_skipped=True),
FunctionInputs(spreadsheet_url=default_url, minimum_severity=MinimumSeverity.WARNING, hide_skipped=True),
)
assert automate_sdk.run_status == AutomationStatus.SUCCEEDED