Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion src/data_profiling/profile_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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())
Expand All @@ -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")
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
68 changes: 68 additions & 0 deletions tests/issues/test_issue1680.py
Original file line number Diff line number Diff line change
@@ -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