Compare commits

...

4 Commits

Author SHA1 Message Date
Jonathon Broughton 38d2073dbb Refactor footgun (#57)
build and deploy Speckle functions / publish-automate-function-version (push) Has been cancelled
- Added traceback import for better error logging.
- Enhanced exception handling to include traceback details.
- Commented out non-integer rule number checks for now.
2025-02-21 13:21:08 +00:00
Jonathon Broughton 091a272185 Add new predicates for value checks (#54)
build and deploy Speckle functions / publish-automate-function-version (push) Has been cancelled
- Removed "matches" and "not equal" predicates.
- Added "not equal to" and "does not contain" predicates.
- Introduced a method to check if a parameter value does not contain a substring.
2025-02-20 18:30:05 +00:00
Jonathon Broughton 0e95f3998a Update rules.py (#53)
build and deploy Speckle functions / publish-automate-function-version (push) Has been cancelled
2025-02-20 17:32:29 +00:00
Jonathon Broughton 05a5383060 Add 'contains' predicate method (#52)
- Introduced a new predicate for checking if a parameter value contains a substring.
- Added the corresponding method to handle the logic and error management.
2025-02-20 17:22:02 +00:00
4 changed files with 80 additions and 7 deletions
+3 -2
View File
@@ -5,15 +5,16 @@ from src.rules import PropertyRules
# Mapping of input predicates to the corresponding methods in PropertyRules
PREDICATE_METHOD_MAP = {
"exists": PropertyRules.has_parameter.__name__,
"matches": PropertyRules.is_parameter_value.__name__,
"greater than": PropertyRules.is_parameter_value_greater_than.__name__,
"less than": PropertyRules.is_parameter_value_less_than.__name__,
"in range": PropertyRules.is_parameter_value_in_range.__name__,
"in list": PropertyRules.is_parameter_value_in_list.__name__,
"equal to": PropertyRules.is_equal_value.__name__,
"not equal to": PropertyRules.is_not_equal_value.__name__,
"is true": PropertyRules.is_parameter_value_true.__name__,
"is false": PropertyRules.is_parameter_value_false.__name__,
"is like": PropertyRules.is_parameter_value_like.__name__,
"identical to": PropertyRules.is_identical_value.__name__,
"not equal": PropertyRules.is_not_equal_value.__name__,
"contains": PropertyRules.is_parameter_value_containing.__name__,
"does not contain": PropertyRules.is_parameter_value_not_containing.__name__,
}
+40
View File
@@ -60,6 +60,46 @@ class Rules:
class PropertyRules:
"""A collection of rules for processing parameters in Speckle objects."""
@staticmethod
def is_parameter_value_not_containing(speckle_object: Base, parameter_name: str, substring: str) -> bool:
"""Checks if parameter value does not contain the given substring.
Args:
speckle_object: The Speckle object to check
parameter_name: Name of the parameter to check
substring: The substring to look for
Returns:
bool: True if the parameter value does not contain the substring
"""
# Invert the result of contains check
return not PropertyRules.is_parameter_value_containing(speckle_object, parameter_name, substring)
@staticmethod
def is_parameter_value_containing(speckle_object: Base, parameter_name: str, substring: str) -> bool:
"""Checks if parameter value contains the given substring.
Args:
speckle_object: The Speckle object to check
parameter_name: Name of the parameter to check
substring: The substring to look for
Returns:
bool: True if the parameter value contains the substring
"""
parameter_value = PropertyRules.get_parameter_value(speckle_object, parameter_name)
if parameter_value is None:
return False
# Convert both to strings for comparison
try:
parameter_str = str(parameter_value).lower()
substring_str = str(substring).lower()
return substring_str in parameter_str
except (TypeError, ValueError) as e:
print(f"Error in is_parameter_value_contains: {e}")
return False
@staticmethod
def normalize_path(path: str) -> str:
"""Remove technical path prefixes like 'properties' and 'parameters'."""
+8 -5
View File
@@ -1,5 +1,7 @@
"""Module for reading and processing rules from a cloud hosted TSV file."""
import traceback
import pandas as pd
from pandas import DataFrame
from pandas.core.groupby import DataFrameGroupBy
@@ -76,10 +78,10 @@ def validate_rule_numbers(df: DataFrame) -> list[str]:
if df["Rule Number"].isna().any():
messages.append("Warning: Some rules are missing rule numbers")
# Check for non-integer rule numbers
non_int_mask = df["Rule Number"].apply(lambda x: not pd.isna(x) and not float(x).is_integer())
if non_int_mask.any():
messages.append("Warning: Some rule numbers are not integers")
# # Check for non-integer rule numbers
# non_int_mask = df["Rule Number"].apply(lambda x: not pd.isna(x) and not float(x).is_integer())
# if non_int_mask.any():
# messages.append("Warning: Some rule numbers are not integers")
# Check for duplicate rule numbers in WHERE rows
where_rules = df[df["Logic"].str.upper() == "WHERE"]["Rule Number"]
@@ -120,7 +122,8 @@ def read_rules_from_spreadsheet(url: str) -> tuple[DataFrameGroupBy, list[str]]
return grouped_rules, messages
except Exception as e:
return None, [f"Failed to read the TSV from the URL: {str(e)}"]
traceback.print_exc()
return None, [f"Failed to read the TSV from the URL: {str(e)}:{e.with_traceback(None)}"]
def convert_mixed_columns(df: DataFrame) -> DataFrame:
+29
View File
@@ -386,3 +386,32 @@ class TestParameterHandling:
"""Test handling of numeric strings in both wall versions."""
wall_instance = request.getfixturevalue(wall) # Retrieve fixture dynamically
assert PropertyRules.is_equal_value(wall_instance, attribute, expected_value)
@pytest.mark.parametrize(
"param_name, substring, expected_result",
[
("speckle_type", "Revit", True), # Test basic substring match
("speckle_type", "revit", True), # Test case-insensitive
("speckle_type", "NotPresent", False), # Test no match
("speckle_type", "", True), # Test empty string
("non_existent", "anything", False), # Test non-existent parameter
],
)
def test_parameter_value_contains(self, test_objects, param_name, substring, expected_result):
"""Test substring matching on parameter values."""
v2_obj, _ = test_objects
assert PropertyRules.is_parameter_value_containing(v2_obj, param_name, substring) == expected_result
@pytest.mark.parametrize(
"param_name, substring, expected_result",
[
("speckle_type", "Revit", False), # Should fail as it does contain Revit
("speckle_type", "NotPresent", True), # Should pass as it doesn't contain
("speckle_type", "", False), # Should fail as empty string is contained
("non_existent", "anything", True), # Should pass as non-existent can't contain
],
)
def test_parameter_value_not_contains(self, test_objects, param_name, substring, expected_result):
"""Test negative substring matching on parameter values."""
v2_obj, _ = test_objects
assert PropertyRules.is_parameter_value_not_containing(v2_obj, param_name, substring) == expected_result