From 263ebf1d386299f3eefd1eeb943a63c1029f0cce Mon Sep 17 00:00:00 2001 From: quant Date: Sat, 20 Jun 2026 22:02:41 +0500 Subject: [PATCH] feat: exclude selected fields from json output --- src/data_profiling/profile_report.py | 26 ++++++++++- tests/issues/test_issue1680.py | 68 ++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 tests/issues/test_issue1680.py diff --git a/src/data_profiling/profile_report.py b/src/data_profiling/profile_report.py index 8d68b8775..f973d9da1 100644 --- a/src/data_profiling/profile_report.py +++ b/src/data_profiling/profile_report.py @@ -73,6 +73,7 @@ def __init__( sortby: Optional[str] = None, sensitive: bool = False, explorative: bool = False, + excluded_fields: list[str] | None = None, sample: Optional[dict] = None, config_file: Optional[Union[Path, str]] = None, lazy: bool = True, @@ -97,6 +98,7 @@ def __init__( Only available for pd.DataFrame sort_by: ignored if ts_mode=False. Order the dataset by a provided column. sensitive: hides the values for categorical and text variables for report privacy + excluded_fields: excludes selected fields from JSON generation config_file: a config file (.yml), mutually exclusive with `minimal` lazy: compute when needed sample: optional dict(name="Sample title", caption="Caption", data=pd.DataFrame()) @@ -110,6 +112,8 @@ def __init__( self._df_type = type(df) + self.excluded_fields = excluded_fields + if config_file or minimal: if not config_file: config_file = get_config("config_minimal.yaml") @@ -453,7 +457,11 @@ def encode_it(o: Any) -> Any: if is_dataclass(o): o = asdict(o) if isinstance(o, dict): - return {encode_it(k): encode_it(v) for k, v in o.items()} + return { + encode_it(k): encode_it(v) + for k, v in o.items() + if (self.excluded_fields is None or k not in self.excluded_fields) + } else: if isinstance(o, (bool, int, float, str)): return o @@ -502,6 +510,22 @@ def to_json(self) -> str: Returns: JSON string + + To disable fields for output, pass a list with + of fields to exclude. + Example: + from data_profiling import ProfileReport + import pandas as pd + + df = pd.DataFrame(np.random.rand(7, 3), columns=["a", "b", "c"]) + fields = ["value_counts_without_nan", + "value_counts_index_sorted", "n_var"] + profile = ProfileReport( + df, title="Data Profiling Report", + excluded_fields=fields + ) + report_json = profile.to_json() + """ return self.json diff --git a/tests/issues/test_issue1680.py b/tests/issues/test_issue1680.py new file mode 100644 index 000000000..14ae96c70 --- /dev/null +++ b/tests/issues/test_issue1680.py @@ -0,0 +1,68 @@ +""" +Test for issue 1680. + +https://github.com/Data-Centric-AI-Community/fg-data-profiling/issues/1680 +""" +import json + +import numpy as np +import pandas as pd +import pytest +from typeguard import TypeCheckError + +from data_profiling import ProfileReport + + +@pytest.fixture +def data(): + """Create a dataframe.""" + np.random.seed(42) + + return pd.DataFrame(np.random.rand(7, 3), columns=["a", "b", "c"]) + + +def test_empty_df(data): + """Check if the data frame is empty.""" + if not len(data): + raise ValueError("Check the dataframe it is empty") + + +# Checking excluded fields +def test_excluded_fields(data): + """Check if there are excluded fields in the json.""" + test_empty_df(data) + + excluded_fields = [ + "value_counts_without_nan", + "value_counts_index_sorted", + "n_var", + "mean", + "sum", + "mad", + ] + + report = ProfileReport(data, excluded_fields=excluded_fields) + report_json = report.to_json() + data_json = json.loads(report_json) + + def check_no_key(dict_recursion): + for key, value in dict_recursion.items(): + if key in excluded_fields: + description = f"The field: {key} " f"that was excluded is present." + raise ValueError(description) + if isinstance(value, dict): + check_no_key(value) + + check_no_key(data_json) + + +@pytest.mark.parametrize("invalid_value", [12345, "abcde", {}, True]) +def test_invalid_excluded_fields(data, invalid_value): + """ + Validate excluded_fields types. + + Checks that passing invalid types + to excluded_fields causes a type error. + """ + with pytest.raises(TypeCheckError): + ProfileReport(data, excluded_fields=invalid_value) # type: ignore # noqa