Skip to content

Commit

Permalink
Merge branch 'main' into add-more-dataframe-backends
Browse files Browse the repository at this point in the history
  • Loading branch information
schloerke authored Oct 10, 2024
2 parents 42b65d1 + bd0ea5c commit c05105d
Show file tree
Hide file tree
Showing 23 changed files with 937 additions and 205 deletions.
16 changes: 16 additions & 0 deletions .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -242,3 +242,19 @@ jobs:
name: "playright-examples-${{ runner.os }}-${{ matrix.python-version }}-results"
path: test-results/
retention-days: 5

test-narwhals-integration:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup py-shiny
id: install
uses: ./.github/py-shiny/setup
- name: Run test commands
env:
UV_SYSTEM_PYTHON: 1
run: |
make narwhals-install-shiny
make narwhals-test-integration
16 changes: 13 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### New features

* Added [narwhals](https://posit-dev.github.io/py-narwhals) support for `@render.data_frame`. This allows for any eager data frame supported by narwhals to be returned from a `@render.data_frame` output method. All internal methods and helper methods leverage the `narwhals` API to be data frame agnostic. (#1570)
* New features for `@render.data_frame`:

* Added [narwhals](https://posit-dev.github.io/py-narwhals) support for `@render.data_frame`. This allows for any eager data frame supported by narwhals to be returned from a `@render.data_frame` output method. All internal methods and helper methods now leverage the `narwhals` API to be data frame agnostic. (#1570)

* Added `.data_patched()` reactive calculation that applies all `.cell_patches()` to `.data()`. (#1719)

* Added `.update_cell_value()` method to programmatically update the contents of a data frame cell. (#1719)

* Added `.update_data()` method to update the rendered data without resetting any user sort or filter. Note, all user edits will be forgotten. (#1719)

* Added [narwhals](https://posit-dev.github.io/py-narwhals) support for `@render.table`. This allows for any eager data frame supported by narwhals to be returned from a `@render.table` output method. (#1570)

### Other changes

Expand All @@ -41,8 +51,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* Added `.expect_class()` and `.expect_multiple()` for `Accordion` in `shiny.playwright.controllers` (#1710)

* Added [narwhals](https://posit-dev.github.io/py-narwhals) support for `@render.table`. This allows for any eager data frame supported by narwhals to be returned from a `@render.table` output method. (#1570)

### Bug fixes

* A few fixes for `ui.Chat()`, including:
Expand All @@ -66,6 +74,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* Fixed bug in `@render.data_frame` where `bool` or `object` columns were not being rendered. (#1570)

* Fixed output controller `OutputDataFrame` in `shiny.playwright.controller` to correctly assert the number of rows in `.expect_nrow()` as the total number of virtual rows, not the number of currently displaying rows. (#1719)


## [1.1.0] - 2024-09-03

Expand Down
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ SUB_FILE:=
PYTEST_BROWSERS:= --browser webkit --browser firefox --browser chromium
PYTEST_DEPLOYS_BROWSERS:= --browser chromium


# Full test path to playwright tests
TEST_FILE:=tests/playwright/$(SUB_FILE)
# Default `make` values that shouldn't be directly used; (Use `TEST_FILE` instead!)
Expand Down Expand Up @@ -247,3 +248,10 @@ upgrade-html-deps: FORCE ## Upgrade Shiny's HTMLDependencies
exit 1; \
fi
@scripts/htmlDependencies.R

narwhals-install-shiny: FORCE
@echo "-------- Install py-shiny ----------"
$(MAKE) ci-install-deps
narwhals-test-integration: FORCE
@echo "-------- Running py-shiny tests ----------"
$(MAKE) test playwright TEST_FILE="tests/playwright/shiny/components/data_frame" PYTEST_BROWSERS="--browser chromium"
2 changes: 2 additions & 0 deletions docs/_quartodoc-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ quartodoc:
renderer:
style: _renderer.py
show_signature_annotations: false
table_style: description-list
sections:
- title: Page containers
desc: Create a user interface page container.
Expand Down Expand Up @@ -357,3 +358,4 @@ quartodoc:
contents:
- name: experimental.ui.card_image
dynamic: false

1 change: 1 addition & 0 deletions docs/_quartodoc-express.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ quartodoc:
renderer:
style: _renderer.py
show_signature_annotations: false
table_style: description-list
sections:
- title: Input components
desc: Gather user input.
Expand Down
40 changes: 8 additions & 32 deletions docs/_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
from griffe import (
Alias,
DocstringAttribute,
DocstringParameter,
DocstringSectionParameters,
DocstringSectionText,
Expr,
ExprName,
Expand All @@ -22,8 +20,8 @@
)
from plum import dispatch
from quartodoc import MdRenderer
from quartodoc.pandoc.blocks import DefinitionList
from quartodoc.renderers.base import convert_rst_link_to_md, sanitize
from quartodoc.renderers.md_renderer import ParamRow

# from quartodoc.ast import preview

Expand Down Expand Up @@ -101,12 +99,12 @@ def render_annotation(self, el: str):
# TODO-future; Can be removed once we use quartodoc 0.3.5
# Related: https://github.com/machow/quartodoc/pull/205
@dispatch
def render(self, el: DocstringAttribute):
row = [
sanitize(el.name),
self.render_annotation(el.annotation),
sanitize(el.description or "", allow_markdown=True),
]
def render(self, el: DocstringAttribute) -> ParamRow:
row = ParamRow(
el.name,
el.description or "",
annotation=self.render_annotation(el.annotation),
)
return row

@dispatch
Expand Down Expand Up @@ -170,28 +168,6 @@ def summarize(self, obj: Union[Object, Alias]) -> str:

return ""

# Consolidate the parameter type info into a single column
@dispatch
def render(self, el: DocstringParameter):
param = f'<span class="parameter-name">{el.name}</span>'
annotation = self.render_annotation(el.annotation)
if annotation:
param = f'{param}<span class="parameter-annotation-sep">:</span> <span class="parameter-annotation">{annotation}</span>'
if el.default:
param = f'{param} <span class="parameter-default-sep">=</span> <span class="parameter-default">{el.default}</span>'

# Wrap everything in a code block to allow for links
param = "<code>" + param + "</code>"

return (param, el.description)

@dispatch
def render(self, el: DocstringSectionParameters):
rows = list(map(self.render, el.value))
# rows is a list of tuples of (<parameter>, <description>)

return str(DefinitionList(rows))

@dispatch
def signature(self, el: Function, source: Optional[Alias] = None):
if el.name == "__call__":
Expand Down Expand Up @@ -279,7 +255,7 @@ def read_file(file: str | Path, root_dir: str | Path | None = None) -> FileConte


def check_if_missing_expected_example(el, converted):
if re.search(r"(^|\n)#{2,6} Examples\n", converted):
if re.search(r"(^|\n)#{2,6} Examples", converted):
# Manually added examples are fine
return

Expand Down
3 changes: 3 additions & 0 deletions js/data-frame/cell-edit-map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ export const useCellEditMap = () => {
cellEditMap,
// setCellEditMap,
setCellEditMapAtLoc,
resetCellEditMap: () => {
setCellEditMap(new Map<string, CellEdit>());
},
} as const;
};

Expand Down
96 changes: 63 additions & 33 deletions js/data-frame/data-update.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,62 @@ export type CellPatchPy = {
// prev: unknown;
};

type SetDataFn = (fn: (draft: unknown[][]) => void) => void;

export function addPatchToData({
setData,
newPatches,
setCellEditMapAtLoc,
}: {
setData: SetDataFn;
newPatches: CellPatch[];
setCellEditMapAtLoc: SetCellEditMapAtLoc;
}): void {
// Update data
setData((draft) => {
newPatches.forEach(({ rowIndex, columnIndex, value }) => {
draft[rowIndex]![columnIndex] = value;
});
});
// Set the new patches in cell edit map info
newPatches.forEach(({ rowIndex, columnIndex, value }) => {
setCellEditMapAtLoc(rowIndex, columnIndex, (obj_draft) => {
obj_draft.value = value;
obj_draft.state = CellStateEnum.EditSuccess;
// Remove save_error if it exists
obj_draft.errorTitle = undefined;
});
});
}

export function cellPatchPyArrToCellPatchArr(
patchesPy: CellPatchPy[]
): CellPatch[] {
const patches: CellPatch[] = patchesPy.map(
(patch: CellPatchPy): CellPatch => {
return {
rowIndex: patch.row_index,
columnIndex: patch.column_index,
value: patch.value,
};
}
);
return patches;
}

export function cellPatchArrToCellPatchPyArr(
patches: CellPatch[]
): CellPatchPy[] {
const patchesPy: CellPatchPy[] = patches.map((patch) => {
return {
row_index: patch.rowIndex,
column_index: patch.columnIndex,
value: patch.value,
};
});
return patchesPy;
}

export function updateCellsData({
patchInfo,
patches,
Expand All @@ -31,20 +87,13 @@ export function updateCellsData({
onSuccess: (values: CellPatch[]) => void;
onError: (err: string) => void;
columns: readonly string[];
setData: (fn: (draft: unknown[][]) => void) => void;
setData: SetDataFn;
setCellEditMapAtLoc: SetCellEditMapAtLoc;
}) {
// // Skip page index reset until after next rerender
// skipAutoResetPageIndex();

const patchesPy: CellPatchPy[] = patches.map((patch) => {
return {
row_index: patch.rowIndex,
column_index: patch.columnIndex,
value: patch.value,
// prev: patch.prev,
};
});
const patchesPy = cellPatchArrToCellPatchPyArr(patches);

makeRequestPromise({
method: patchInfo.key,
Expand All @@ -70,21 +119,7 @@ export function updateCellsData({
}
newPatchesPy = newPatchesPy as CellPatchPy[];

const newPatches: CellPatch[] = newPatchesPy.map(
(patch: CellPatchPy): CellPatch => {
return {
rowIndex: patch.row_index,
columnIndex: patch.column_index,
value: patch.value,
};
}
);

setData((draft) => {
newPatches.forEach(({ rowIndex, columnIndex, value }) => {
draft[rowIndex]![columnIndex] = value;
});
});
const newPatches = cellPatchPyArrToCellPatchArr(newPatchesPy);

// Set the old patches locations back to success state
// This may be overkill, but it guarantees that the incoming patches exit the saving state
Expand All @@ -99,15 +134,10 @@ export function updateCellsData({
obj_draft.errorTitle = undefined;
});
});
// Set the new patches
newPatches.forEach(({ rowIndex, columnIndex, value }) => {
setCellEditMapAtLoc(rowIndex, columnIndex, (obj_draft) => {
obj_draft.value = value;
obj_draft.state = CellStateEnum.EditSuccess;
// Remove save_error if it exists
obj_draft.errorTitle = undefined;
});
});

// Update data and cell edit map with new patches
addPatchToData({ setData, newPatches, setCellEditMapAtLoc });

onSuccess(newPatches);
})
.catch((err: string) => {
Expand Down
Loading

0 comments on commit c05105d

Please sign in to comment.