(df: nw.DataFrame)
| 1871 | |
| 1872 | |
| 1873 | def _check_dataframe_all_leaves(df: nw.DataFrame) -> None: |
| 1874 | cols = df.columns |
| 1875 | df_sorted = df.sort(by=cols, descending=False, nulls_last=True) |
| 1876 | null_mask = df_sorted.select(nw.all().is_null()) |
| 1877 | df_sorted = df_sorted.select(nw.all().cast(nw.String())) |
| 1878 | null_indices_mask = null_mask.select( |
| 1879 | null_mask=nw.any_horizontal(nw.all()) |
| 1880 | ).get_column("null_mask") |
| 1881 | |
| 1882 | null_mask_filtered = null_mask.filter(null_indices_mask) |
| 1883 | if not null_mask_filtered.is_empty(): |
| 1884 | for col_idx in range(1, null_mask_filtered.shape[1]): |
| 1885 | # For each row, if a True value is encountered, then check that |
| 1886 | # all values in subsequent columns are also True |
| 1887 | null_entries_with_non_null_children = ( |
| 1888 | ~null_mask_filtered[:, col_idx] & null_mask_filtered[:, col_idx - 1] |
| 1889 | ) |
| 1890 | if nw.to_py_scalar(null_entries_with_non_null_children.any()): |
| 1891 | row_idx = null_entries_with_non_null_children.to_list().index(True) |
| 1892 | raise ValueError( |
| 1893 | "None entries cannot have not-None children", |
| 1894 | df_sorted.row(row_idx), |
| 1895 | ) |
| 1896 | |
| 1897 | fill_series = nw.new_series( |
| 1898 | name="fill_value", |
| 1899 | values=[""] * len(df_sorted), |
| 1900 | dtype=nw.String(), |
| 1901 | native_namespace=nw.get_native_namespace(df_sorted), |
| 1902 | ) |
| 1903 | df_sorted = df_sorted.with_columns( |
| 1904 | **{ |
| 1905 | c: df_sorted.get_column(c).zip_with(~null_mask.get_column(c), fill_series) |
| 1906 | for c in cols |
| 1907 | } |
| 1908 | ) |
| 1909 | |
| 1910 | # Conversion to list is due to python native vs pyarrow scalars |
| 1911 | row_strings = ( |
| 1912 | df_sorted.select( |
| 1913 | row_strings=nw.concat_str(cols, separator="", ignore_nulls=False) |
| 1914 | ) |
| 1915 | .get_column("row_strings") |
| 1916 | .to_list() |
| 1917 | ) |
| 1918 | |
| 1919 | null_indices = set(null_indices_mask.arg_true().to_list()) |
| 1920 | for i, (current_row, next_row) in enumerate( |
| 1921 | zip(row_strings[:-1], row_strings[1:]), start=1 |
| 1922 | ): |
| 1923 | if (next_row in current_row) and (i in null_indices): |
| 1924 | raise ValueError( |
| 1925 | "Non-leaves rows are not permitted in the dataframe \n", |
| 1926 | df_sorted.row(i), |
| 1927 | "is not a leaf.", |
| 1928 | ) |
| 1929 | |
| 1930 |
no test coverage detected