From d8788cc994f64730bb2e5f6c7818b5cd9f86c756 Mon Sep 17 00:00:00 2001 From: Mike Gouline <1960272+gouline@users.noreply.github.com> Date: Tue, 20 Feb 2024 11:50:16 +1100 Subject: [PATCH] Wildcard support in filters (#233) --- Makefile | 2 +- README.md | 4 ++-- dbtmetabase/format.py | 16 +++++++++++++--- tests/test_format.py | 9 +++++++++ 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index ee21a27..068fca0 100644 --- a/Makefile +++ b/Makefile @@ -77,7 +77,7 @@ sandbox-models: --metabase-username $$MB_USER \ --metabase-password $$MB_PASSWORD \ --metabase-database $$POSTGRES_DB \ - --include-schemas "public",other \ + --include-schemas "pub*",other \ --http-header x-dummy-key dummy-value \ --order-fields \ --verbose ) diff --git a/README.md b/README.md index 673aa3c..cb6e9a3 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ dbt-metabase exposures \ --metabase-username user@example.com \ --metabase-password Password123 \ --output-path models/ \ - --exclude-collections temporary + --exclude-collections "temp*" ``` Once the execution completes, check your output path for exposures files containing descriptions, creator details and links for Metabase questions and dashboards: @@ -295,7 +295,7 @@ c.export_models( # Extracting exposures c.extract_exposures( output_path=".", - collection_filter=Filter(exclude=["temporary"]), + collection_filter=Filter(exclude=["temp*"]), ) ``` diff --git a/dbtmetabase/format.py b/dbtmetabase/format.py index 7ef2b29..862a715 100644 --- a/dbtmetabase/format.py +++ b/dbtmetabase/format.py @@ -1,5 +1,6 @@ from __future__ import annotations +import fnmatch import logging import re from logging.handlers import RotatingFileHandler @@ -29,9 +30,18 @@ def __init__( def match(self, item: str) -> bool: item = self._norm_item(item) - included = not self.include or item in self.include - excluded = self.exclude and item in self.exclude - return included and not excluded + + for exclude in self.exclude: + if fnmatch.fnmatch(item, exclude): + return False + + if self.include: + for include in self.include: + if fnmatch.fnmatch(item, include): + return True + return False + + return True @staticmethod def _norm_arg(arg: Optional[Sequence[str]]) -> Sequence[str]: diff --git a/tests/test_format.py b/tests/test_format.py index b24d172..9b48af6 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -27,6 +27,15 @@ def test_filter(self): self.assertTrue(Filter(include="alpha").match("Alpha")) self.assertFalse(Filter(exclude="alpha").match("Alpha")) + def test_filter_wildcard(self): + self.assertTrue(Filter(include="stg_*").match("stg_orders")) + self.assertTrue(Filter(include="STG_*").match("stg_ORDERS")) + self.assertFalse(Filter(include="stg_*").match("orders")) + self.assertTrue(Filter(include="order?").match("orders")) + self.assertFalse(Filter(include="order?").match("ordersz")) + self.assertTrue(Filter(include="*orders", exclude="stg_*").match("_orders")) + self.assertFalse(Filter(include="*orders", exclude="stg_*").match("stg_orders")) + def test_null_value(self): self.assertIsNotNone(NullValue) self.assertFalse(NullValue)