diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0be03f6..bae7de2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -32,9 +32,9 @@ jobs: outputs: wheel-distribution: ${{ steps.wheel-distribution.outputs.path }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: {fetch-depth: 0} # deep clone for setuptools-scm - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 id: setup-python with: {python-version: "3.11"} - name: Run static analysis and format checkers @@ -49,7 +49,7 @@ jobs: - name: Store the distribution files for use in other stages # `tests` and `publish` will use the same pre-built distributions, # so we make sure to release the exact same package that was tested - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: python-distribution-files path: dist/ @@ -60,7 +60,7 @@ jobs: strategy: matrix: python: - - "3.7" # oldest Python supported by PSF + - "3.8" # oldest Python supported by PSF - "3.11" # newest Python that is stable platform: - ubuntu-latest @@ -68,13 +68,13 @@ jobs: - windows-latest runs-on: ${{ matrix.platform }} steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 id: setup-python with: python-version: ${{ matrix.python }} - name: Retrieve pre-built distribution files - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: {name: python-distribution-files, path: dist/} - name: Run tests run: >- @@ -108,11 +108,11 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: {python-version: "3.11"} - name: Retrieve pre-built distribution files - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: {name: python-distribution-files, path: dist/} # - name: Publish Package (TEST) # env: diff --git a/setup.cfg b/setup.cfg index f4cc25b..9e3f07e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -54,7 +54,7 @@ package_dir = =src # Require a min/specific Python version (comma-separated conditions) -python_requires = >=3.6 +python_requires = >=3.8 # Add here dependencies of your project (line-separated), e.g. requests>=2.2,<3.0. # Version specifiers like >=2.2,<3.0 avoid problems due to API changes in @@ -64,7 +64,7 @@ install_requires = importlib-metadata; python_version<"3.8" pandas>=0.24.0 scipy - numpy + numpy<2.0.0 matplotlib diff --git a/src/pysubgroup/subgroup_description.py b/src/pysubgroup/subgroup_description.py index 072319d..c5e61b3 100644 --- a/src/pysubgroup/subgroup_description.py +++ b/src/pysubgroup/subgroup_description.py @@ -239,7 +239,10 @@ def from_str(s): try: attribute_value = float(attribute_value) except ValueError: - pass + try: + attribute_value = ps.str_to_bool(attribute_value) + except ValueError: + pass return ps.EqualitySelector(attribute_name, attribute_value) diff --git a/src/pysubgroup/utils.py b/src/pysubgroup/utils.py index 51c45ea..4be5fc9 100644 --- a/src/pysubgroup/utils.py +++ b/src/pysubgroup/utils.py @@ -15,6 +15,16 @@ from .algorithms import SubgroupDiscoveryTask +def str_to_bool(s): + s = s.lower() + if s in ["y", "yes", "t", "true", "on", "1"]: + return True + elif s in ["n", "no", "f", "false", "off", "0"]: + return False + + raise ValueError(f"'{s}' is not a valid string representation of a boolean value") + + def minimum_required_quality(result, task): if len(result) < task.result_set_size: return task.min_quality diff --git a/tests/test_subgroup_description.py b/tests/test_subgroup_description.py index 8aaee2a..be00c8b 100644 --- a/tests/test_subgroup_description.py +++ b/tests/test_subgroup_description.py @@ -134,10 +134,15 @@ def test_remove_target_attributes(self): self.assertEqual(selectors[1:], bin_sel) def test_EqualitySelector_from_str(self): - selector1 = ps.EqualitySelector.from_str("A=='hello'") - selector2 = ps.EqualitySelector("A", "hello") - self.assertEqual(selector1, selector2) - self.assertIs(selector1, selector2) + def test_str(s, attribute_name, attribute_value): + selector = ps.EqualitySelector.from_str(s) + _selector = ps.EqualitySelector(attribute_name, attribute_value) + self.assertEqual(selector, _selector) + self.assertIs(selector, _selector) + + test_str("A=='hello'", "A", "hello") + test_str("A==True", "A", True) + test_str("A==False", "A", False) def test_IntervalSelector_from_str(self): def test_str(s, attribute_name, lb, ub):