Skip to content

Commit

Permalink
docs: api-completeness
Browse files Browse the repository at this point in the history
  • Loading branch information
FBruzzesi committed Jul 15, 2024
1 parent a5276cd commit 2f3a7e2
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 0 deletions.
14 changes: 14 additions & 0 deletions utils/api-completeness.md.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# API Completeness

Narwhals has two different level of support for libraries: "full" and "interchange".

Libraries for which we have full support we intend to support the whole Narwhals API, however this is a work in progress.

In the following table it is possible to check which method is implemented for which backend.

!!! info

- "pandas-like" means pandas, cuDF and Modin
- Polars supports all the methods (by design)

{{ backend_table }}
109 changes: 109 additions & 0 deletions utils/generate_backend_completeness.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
from __future__ import annotations

import importlib
import inspect
from pathlib import Path
from typing import Any
from typing import Final

import polars as pl
from jinja2 import Template

TEMPLATE_PATH: Final[Path] = Path("utils") / "api-completeness.md.jinja"
DESTINATION_PATH: Final[Path] = Path("docs") / "api-reference" / "api-completeness.md"


MODULES = ["dataframe", "series", "expression"]
EXCLUDE_CLASSES = {"BaseFrame"}


def get_class_methods(kls: type[Any]) -> list[str]:
return [m[0] for m in inspect.getmembers(kls) if not m[0].startswith("_")]


def get_backend_completeness_table() -> str:
results = []

for module_name in MODULES:
nw_namespace = f"narwhals.{module_name}"
sub_module_name = module_name if module_name != "expression" else "expr"

narwhals_module_ = importlib.import_module(nw_namespace)
classes_ = inspect.getmembers(
narwhals_module_,
predicate=lambda c: inspect.isclass(c) and c.__module__ == nw_namespace, # noqa: B023, not imported classes
)

for nw_class_name, nw_class in classes_:
if nw_class_name in EXCLUDE_CLASSES:
continue

if nw_class_name == "LazyFrame":
backend_class_name = "DataFrame"
else:
backend_class_name = nw_class_name

arrow_class_name = f"Arrow{backend_class_name}"
arrow_module_ = importlib.import_module(f"narwhals._arrow.{sub_module_name}")
arrow_class = inspect.getmembers(
arrow_module_,
predicate=lambda c: inspect.isclass(c) and c.__name__ == arrow_class_name, # noqa: B023
)

pandas_class_name = f"PandasLike{backend_class_name}"
pandas_module_ = importlib.import_module(
f"narwhals._pandas_like.{sub_module_name}"
)
pandas_class = inspect.getmembers(
pandas_module_,
predicate=lambda c: inspect.isclass(c)
and c.__name__ == pandas_class_name, # noqa: B023
)

nw_methods = get_class_methods(nw_class)
arrow_methods = get_class_methods(arrow_class[0][1]) if arrow_class else []
pandas_methods = get_class_methods(pandas_class[0][1]) if pandas_class else []

narhwals = pl.DataFrame(
{"class": nw_class_name, "backend": "narwhals", "method": nw_methods}
)
arrow = pl.DataFrame(
{"class": nw_class_name, "backend": "arrow", "method": arrow_methods}
)
pandas = pl.DataFrame(
{
"class": nw_class_name,
"backend": "pandas-like",
"method": pandas_methods,
}
)

results.extend([narhwals, pandas, arrow])

results = (
pl.concat(results) # noqa: PD010
.with_columns(supported=pl.lit(":white_check_mark:"))
.pivot(on="backend", values="supported", index=["class", "method"])
.filter(pl.col("narwhals").is_not_null())
.drop("narwhals")
.fill_null(":x:")
.sort("class", "method")
)

with pl.Config(
tbl_formatting="ASCII_MARKDOWN",
tbl_hide_column_data_types=True,
tbl_hide_dataframe_shape=True,
set_tbl_rows=results.shape[0],
):
return str(results)


if __name__ == "__main__":
backend_table = get_backend_completeness_table()

with TEMPLATE_PATH.open(mode="r") as stream:
template = Template(stream.read()).render({"backend_table": backend_table})

with DESTINATION_PATH.open(mode="w") as destination:
destination.write(template)

0 comments on commit 2f3a7e2

Please sign in to comment.