From 5be2652de024e8900339e2a83c99f354f4b39620 Mon Sep 17 00:00:00 2001 From: Chris Trevino <chtrevin@microsoft.com> Date: Mon, 24 Jun 2024 15:45:44 -0700 Subject: [PATCH 1/3] add reactive dataflow library --- .../datashaper/datashaper/verbs/__init__.py | 4 +- .../datashaper/datashaper/verbs/aggregate.py | 19 +- python/datashaper/datashaper/verbs/bin.py | 27 ++- .../datashaper/datashaper/verbs/binarize.py | 4 +- python/datashaper/datashaper/verbs/boolean.py | 4 +- python/datashaper/datashaper/verbs/concat.py | 4 +- python/datashaper/datashaper/verbs/convert.py | 4 +- python/datashaper/datashaper/verbs/copy.py | 4 +- .../datashaper/verbs/decorators/__init__.py | 6 +- .../verbs/decorators/copy_input_tables.py | 42 ++++ .../datashaper/verbs/decorators/inputs.py | 51 ----- .../datashaper/verbs/decorators/verb.py | 46 ----- .../{outputs.py => wrap_verb_result.py} | 2 +- python/datashaper/datashaper/verbs/dedupe.py | 7 +- python/datashaper/datashaper/verbs/derive.py | 4 +- .../datashaper/verbs/destructure.py | 4 +- .../datashaper/datashaper/verbs/difference.py | 4 +- python/datashaper/datashaper/verbs/drop.py | 4 +- .../datashaper/verbs/engine/verb_manager.py | 51 ----- python/datashaper/datashaper/verbs/erase.py | 4 +- python/datashaper/datashaper/verbs/fill.py | 4 +- python/datashaper/datashaper/verbs/fold.py | 4 +- python/datashaper/datashaper/verbs/groupby.py | 4 +- python/datashaper/datashaper/verbs/impute.py | 4 +- .../datashaper/datashaper/verbs/intersect.py | 4 +- python/datashaper/datashaper/verbs/join.py | 4 +- python/datashaper/datashaper/verbs/lookup.py | 4 +- python/datashaper/datashaper/verbs/merge.py | 4 +- python/datashaper/datashaper/verbs/onehot.py | 4 +- python/datashaper/datashaper/verbs/orderby.py | 4 +- python/datashaper/datashaper/verbs/pivot.py | 4 +- python/datashaper/datashaper/verbs/print.py | 4 +- python/datashaper/datashaper/verbs/recode.py | 4 +- python/datashaper/datashaper/verbs/rename.py | 4 +- python/datashaper/datashaper/verbs/rollup.py | 4 +- python/datashaper/datashaper/verbs/sample.py | 4 +- python/datashaper/datashaper/verbs/select.py | 4 +- .../datashaper/datashaper/verbs/snapshot.py | 4 +- python/datashaper/datashaper/verbs/spread.py | 4 +- .../datashaper/verbs/strings/lower.py | 4 +- .../datashaper/verbs/strings/replace.py | 4 +- .../datashaper/verbs/strings/upper.py | 4 +- python/datashaper/datashaper/verbs/unfold.py | 4 +- python/datashaper/datashaper/verbs/ungroup.py | 4 +- python/datashaper/datashaper/verbs/unhot.py | 4 +- python/datashaper/datashaper/verbs/union.py | 4 +- python/datashaper/datashaper/verbs/unorder.py | 4 +- python/datashaper/datashaper/verbs/unroll.py | 7 +- python/datashaper/datashaper/verbs/window.py | 4 +- .../datashaper/datashaper/verbs/workflow.py | 4 +- python/datashaper/poetry.lock | 184 +++++++++++++++++- python/datashaper/pyproject.toml | 1 + 52 files changed, 350 insertions(+), 253 deletions(-) create mode 100644 python/datashaper/datashaper/verbs/decorators/copy_input_tables.py delete mode 100644 python/datashaper/datashaper/verbs/decorators/inputs.py delete mode 100644 python/datashaper/datashaper/verbs/decorators/verb.py rename python/datashaper/datashaper/verbs/decorators/{outputs.py => wrap_verb_result.py} (98%) delete mode 100644 python/datashaper/datashaper/verbs/engine/verb_manager.py diff --git a/python/datashaper/datashaper/verbs/__init__.py b/python/datashaper/datashaper/verbs/__init__.py index ef9653341..ac006263e 100644 --- a/python/datashaper/datashaper/verbs/__init__.py +++ b/python/datashaper/datashaper/verbs/__init__.py @@ -16,9 +16,9 @@ OutputMode, ParallelizationMode, inputs, - outputs, parallel_verb, verb, + wrap_verb_result, ) from .dedupe import dedupe from .derive import derive @@ -145,7 +145,7 @@ # Decorators "verb", "inputs", - "outputs", + "wrap_verb_result", "parallel_verb", "OutputMode", "ParallelizationMode", diff --git a/python/datashaper/datashaper/verbs/aggregate.py b/python/datashaper/datashaper/verbs/aggregate.py index 711458f4f..8d07d29d9 100644 --- a/python/datashaper/datashaper/verbs/aggregate.py +++ b/python/datashaper/datashaper/verbs/aggregate.py @@ -8,22 +8,28 @@ from typing import Any, cast import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb + +from datashaper.constants import DEFAULT_INPUT_NAME from .decorators import ( OutputMode, - inputs, - outputs, - verb, + wrap_verb_result, ) from .types import FieldAggregateOperation @verb( name="aggregate", - immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="groupby", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="operation", required=True), + ], adapters=[ - inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def aggregate( @@ -32,7 +38,6 @@ def aggregate( groupby: list[str], column: str, operation: FieldAggregateOperation, - **_kwargs: Any, ) -> pd.DataFrame: """Aggregate verb implementation.""" result = cast( diff --git a/python/datashaper/datashaper/verbs/bin.py b/python/datashaper/datashaper/verbs/bin.py index db3eda3be..0879206d5 100644 --- a/python/datashaper/datashaper/verbs/bin.py +++ b/python/datashaper/datashaper/verbs/bin.py @@ -8,13 +8,11 @@ import numpy as np import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import ( - OutputMode, - inputs, - outputs, - verb, -) +from datashaper.constants import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result from .types import BinStrategy @@ -79,9 +77,21 @@ def __get_bucket_value( @verb( name="bin", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="strategy", required=True), + ConfigPort(name="min", required=False), + ConfigPort(name="max", required=False), + ConfigPort(name="fixedcount", required=False), + ConfigPort(name="fixedwidth", required=False), + ConfigPort(name="clamped", required=False), + ConfigPort(name="printRange", required=False), + ], adapters=[ - inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + copy_input_tables("table"), + wrap_verb_result(mode=OutputMode.Table), ], ) def bin( # noqa A001 - use ds verb name @@ -95,7 +105,6 @@ def bin( # noqa A001 - use ds verb name fixedwidth: int | None = None, clamped: bool | None = False, printRange: bool | None = False, # noqa: N803 - **_kwargs: Any, ) -> pd.DataFrame: """Bin verb implementation.""" bin_strategy = BinStrategy(strategy) diff --git a/python/datashaper/datashaper/verbs/binarize.py b/python/datashaper/datashaper/verbs/binarize.py index 65b78b0ee..d05741cec 100644 --- a/python/datashaper/datashaper/verbs/binarize.py +++ b/python/datashaper/datashaper/verbs/binarize.py @@ -8,7 +8,7 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result from .filter import filter, get_comparison_operator from .types import ( ComparisonStrategy, @@ -21,7 +21,7 @@ name="binarize", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def binarize( diff --git a/python/datashaper/datashaper/verbs/boolean.py b/python/datashaper/datashaper/verbs/boolean.py index b8df11bab..4941e5394 100644 --- a/python/datashaper/datashaper/verbs/boolean.py +++ b/python/datashaper/datashaper/verbs/boolean.py @@ -8,7 +8,7 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result from .filter import boolean_function_map from .types import BooleanLogicalOperator @@ -17,7 +17,7 @@ name="boolean", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def boolean( diff --git a/python/datashaper/datashaper/verbs/concat.py b/python/datashaper/datashaper/verbs/concat.py index 7332b3554..760b8d3f9 100644 --- a/python/datashaper/datashaper/verbs/concat.py +++ b/python/datashaper/datashaper/verbs/concat.py @@ -8,7 +8,7 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( @@ -16,7 +16,7 @@ immutable_input=True, adapters=[ inputs(default_input_argname="table", variadic_input_argname="others"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def concat( diff --git a/python/datashaper/datashaper/verbs/convert.py b/python/datashaper/datashaper/verbs/convert.py index 031284512..c26a77428 100644 --- a/python/datashaper/datashaper/verbs/convert.py +++ b/python/datashaper/datashaper/verbs/convert.py @@ -13,7 +13,7 @@ import pandas as pd from pandas.api.types import is_bool_dtype, is_datetime64_any_dtype, is_numeric_dtype -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result from .types import ParseType @@ -118,7 +118,7 @@ def convert_value(value: Any) -> list: name="convert", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def convert( diff --git a/python/datashaper/datashaper/verbs/copy.py b/python/datashaper/datashaper/verbs/copy.py index 3494fd7b1..4517e2c04 100644 --- a/python/datashaper/datashaper/verbs/copy.py +++ b/python/datashaper/datashaper/verbs/copy.py @@ -8,14 +8,14 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="copy", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def copy( diff --git a/python/datashaper/datashaper/verbs/decorators/__init__.py b/python/datashaper/datashaper/verbs/decorators/__init__.py index 22f38f2c8..647159e82 100644 --- a/python/datashaper/datashaper/verbs/decorators/__init__.py +++ b/python/datashaper/datashaper/verbs/decorators/__init__.py @@ -1,18 +1,20 @@ """Datashaper Function Decorators.""" from .apply_decorators import apply_decorators +from .copy_input_tables import copy_input_tables from .inputs import inputs -from .outputs import OutputMode, outputs from .parallel_verb import ParallelizationMode, new_row, parallel_verb from .verb import verb +from .wrap_verb_result import OutputMode, wrap_verb_result __all__ = [ "new_row", "verb", + "copy_input_tables", "parallel_verb", "ParallelizationMode", "inputs", "apply_decorators", - "outputs", + "wrap_verb_result", "OutputMode", ] diff --git a/python/datashaper/datashaper/verbs/decorators/copy_input_tables.py b/python/datashaper/datashaper/verbs/decorators/copy_input_tables.py new file mode 100644 index 000000000..a2d67a9b7 --- /dev/null +++ b/python/datashaper/datashaper/verbs/decorators/copy_input_tables.py @@ -0,0 +1,42 @@ +# +# Copyright (c) Microsoft. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project. +# +"""Verb inputs decorator.""" + +from collections.abc import Callable +from typing import Any, ParamSpec, TypeVar, cast + +import pandas as pd + +from datashaper.verbs.engine import VerbInput + +T = TypeVar("T") +P = ParamSpec("P") + + +def copy_input_tables( + *names: str, +) -> Callable[[Callable[P, T]], Callable[[VerbInput], T]]: + """Decorate an execution function with input conditions. + + Args: + required (list[str] | None): The list of required input names. Defaults to None. If present, the function will only execute if all required inputs are present. + """ + + def wrap_executor_function( + fn: Callable[P, T], + ) -> Callable[[VerbInput], T]: + def wrapped_fn(*args: P.args, **kwargs: P.kwargs) -> T: + fn_args: dict[str, Any] = { + **kwargs, + } + for name in names: + if name not in fn_args: + raise ValueError + fn_args[name] = cast(pd.DataFrame, fn_args[name].copy()) + return fn(*args, **fn_args) + + return wrapped_fn + + return wrap_executor_function diff --git a/python/datashaper/datashaper/verbs/decorators/inputs.py b/python/datashaper/datashaper/verbs/decorators/inputs.py deleted file mode 100644 index 75fe6b88c..000000000 --- a/python/datashaper/datashaper/verbs/decorators/inputs.py +++ /dev/null @@ -1,51 +0,0 @@ -# -# Copyright (c) Microsoft. All rights reserved. -# Licensed under the MIT license. See LICENSE file in the project. -# -"""Verb inputs decorator.""" - -from collections.abc import Callable -from typing import Any, ParamSpec, TypeVar - -from datashaper.verbs.engine import VerbInput - -T = TypeVar("T") -P = ParamSpec("P") - - -def inputs( - input_argnames: dict[str, str] | None = None, - default_input_argname: str | None = None, - variadic_input_argname: str | None = None, - input_dict_argname: str | None = None, -) -> Callable[[Callable[P, T]], Callable[[VerbInput], T]]: - """Decorate an execution function with input conditions. - - Args: - required (list[str] | None): The list of required input names. Defaults to None. If present, the function will only execute if all required inputs are present. - """ - - def wrap_executor_function( - fn: Callable[P, T], - ) -> Callable[[VerbInput], T]: - def wrapped_fn(input: VerbInput, *args: P.args, **kwargs: P.kwargs) -> T: - fn_args: dict[str, Any] = { - v: input.get_named_input(k) for k, v in (input_argnames or {}).items() - } - if default_input_argname is not None: - fn_args[default_input_argname] = input.get_input() - if variadic_input_argname is not None: - fn_args[variadic_input_argname] = input.get_others() - if input_dict_argname is not None: - fn_args[input_dict_argname] = input.get_named_inputs() - - for k, v in kwargs.items(): - if k not in fn_args: - fn_args[k] = v - - # Use named_args as needed - return fn(*args, **fn_args) - - return wrapped_fn - - return wrap_executor_function diff --git a/python/datashaper/datashaper/verbs/decorators/verb.py b/python/datashaper/datashaper/verbs/decorators/verb.py deleted file mode 100644 index 7970f0d7b..000000000 --- a/python/datashaper/datashaper/verbs/decorators/verb.py +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright (c) Microsoft. All rights reserved. -# Licensed under the MIT license. See LICENSE file in the project. -# -"""Verb decorators and manager.""" - -import logging -from collections.abc import Callable -from typing import Any, cast - -from datashaper.verbs.engine import ( - VerbDetails, - VerbManager, - VerbResult, -) - -from .apply_decorators import apply_decorators - -log = logging.getLogger(__name__) - - -def verb( - name: str, - override: bool = False, - immutable_input: bool = False, - adapters: list[Callable[[Callable], Callable]] | None = None, - registry: VerbManager | None = None, - **_kwargs: Any, -) -> Callable: - """Apply a decorator for registering a verb.""" - registry = registry or VerbManager.get() - - def registered_verb(verb_function: Callable) -> Callable[..., VerbResult]: - fn = verb_function - if adapters: - fn = apply_decorators(adapters, fn) - fn = cast(Callable[..., VerbResult], fn) - verb = VerbDetails( - name=name, - func=fn, - treats_input_tables_as_immutable=immutable_input, - ) - registry.register(verb, override) - return verb_function - - return registered_verb diff --git a/python/datashaper/datashaper/verbs/decorators/outputs.py b/python/datashaper/datashaper/verbs/decorators/wrap_verb_result.py similarity index 98% rename from python/datashaper/datashaper/verbs/decorators/outputs.py rename to python/datashaper/datashaper/verbs/decorators/wrap_verb_result.py index e9dcbcae5..0755a01a4 100644 --- a/python/datashaper/datashaper/verbs/decorators/outputs.py +++ b/python/datashaper/datashaper/verbs/decorators/wrap_verb_result.py @@ -23,7 +23,7 @@ class OutputMode(str, Enum): P = ParamSpec("P") -def outputs( +def wrap_verb_result( mode: OutputMode, output_names: list[str] | None = None, ) -> Callable[[Callable[..., Any]], Callable[..., VerbResult]]: diff --git a/python/datashaper/datashaper/verbs/dedupe.py b/python/datashaper/datashaper/verbs/dedupe.py index 40c7869c0..e1d43b432 100644 --- a/python/datashaper/datashaper/verbs/dedupe.py +++ b/python/datashaper/datashaper/verbs/dedupe.py @@ -8,13 +8,16 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="dedupe", immutable_input=True, - adapters=[inputs(default_input_argname="table"), outputs(mode=OutputMode.Table)], + adapters=[ + inputs(default_input_argname="table"), + wrap_verb_result(mode=OutputMode.Table), + ], ) def dedupe( table: pd.DataFrame, columns: list[str] | None = None, **_kwargs: Any diff --git a/python/datashaper/datashaper/verbs/derive.py b/python/datashaper/datashaper/verbs/derive.py index 8c187854b..e2c5154ab 100644 --- a/python/datashaper/datashaper/verbs/derive.py +++ b/python/datashaper/datashaper/verbs/derive.py @@ -13,7 +13,7 @@ from datashaper.errors import VerbOperationNotSupportedError -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result from .types import MathOperator @@ -42,7 +42,7 @@ def __concatenate(col1: pd.Series, col2: pd.Series) -> pd.Series: name="derive", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def derive( diff --git a/python/datashaper/datashaper/verbs/destructure.py b/python/datashaper/datashaper/verbs/destructure.py index 17bac8cce..94aad05d2 100644 --- a/python/datashaper/datashaper/verbs/destructure.py +++ b/python/datashaper/datashaper/verbs/destructure.py @@ -9,14 +9,14 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="destructure", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def destructure( diff --git a/python/datashaper/datashaper/verbs/difference.py b/python/datashaper/datashaper/verbs/difference.py index 791f82c63..8e10a642d 100644 --- a/python/datashaper/datashaper/verbs/difference.py +++ b/python/datashaper/datashaper/verbs/difference.py @@ -8,14 +8,14 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="difference", adapters=[ inputs(default_input_argname="table", variadic_input_argname="others"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def difference( diff --git a/python/datashaper/datashaper/verbs/drop.py b/python/datashaper/datashaper/verbs/drop.py index 0130bfae4..e9741f5fe 100644 --- a/python/datashaper/datashaper/verbs/drop.py +++ b/python/datashaper/datashaper/verbs/drop.py @@ -8,14 +8,14 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="drop", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def drop(table: pd.DataFrame, columns: list[str], **_kwargs: Any) -> pd.DataFrame: diff --git a/python/datashaper/datashaper/verbs/engine/verb_manager.py b/python/datashaper/datashaper/verbs/engine/verb_manager.py deleted file mode 100644 index 6bb4a4aae..000000000 --- a/python/datashaper/datashaper/verbs/engine/verb_manager.py +++ /dev/null @@ -1,51 +0,0 @@ -# -# Copyright (c) Microsoft. All rights reserved. -# Licensed under the MIT license. See LICENSE file in the project. -# -"""Verb decorators and manager.""" - -from collections.abc import Callable -from dataclasses import dataclass, field -from functools import cache - -from datashaper.errors import VerbAlreadyRegisteredError - -from .types import VerbDetails - - -@dataclass -class VerbManager: - """Manages the verbs and their functions.""" - - _verbs: dict[str, VerbDetails] = field(default_factory=dict) - - def __getitem__(self, verb: str) -> VerbDetails | None: - """Get a verb by name.""" - return self.get_verb(verb) - - def __contains__(self, verb: str) -> bool: - """Check if a verb is registered.""" - return verb in self._verbs - - def register_verbs( - self, verbs: dict[str, Callable], override_existing: bool = False - ) -> None: - """Register verbs.""" - for name, func in verbs.items(): - self.register(VerbDetails(name=name, func=func), override_existing) - - def register(self, verb: VerbDetails, override_existing: bool = False) -> None: - """Register a verb.""" - if not override_existing and verb.name in self._verbs: - raise VerbAlreadyRegisteredError(verb.name) - self._verbs.update({verb.name: verb}) - - def get_verb(self, verb: str) -> VerbDetails | None: - """Get a verb by name.""" - return self._verbs.get(verb) - - @classmethod - @cache - def get(cls) -> "VerbManager": - """Get the verb manager.""" - return cls() diff --git a/python/datashaper/datashaper/verbs/erase.py b/python/datashaper/datashaper/verbs/erase.py index df76ee393..d2e22eb4d 100644 --- a/python/datashaper/datashaper/verbs/erase.py +++ b/python/datashaper/datashaper/verbs/erase.py @@ -8,14 +8,14 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="erase", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def erase( diff --git a/python/datashaper/datashaper/verbs/fill.py b/python/datashaper/datashaper/verbs/fill.py index 64ad91b33..5613bf766 100644 --- a/python/datashaper/datashaper/verbs/fill.py +++ b/python/datashaper/datashaper/verbs/fill.py @@ -8,14 +8,14 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="fill", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def fill( diff --git a/python/datashaper/datashaper/verbs/fold.py b/python/datashaper/datashaper/verbs/fold.py index 355406d86..6570662de 100644 --- a/python/datashaper/datashaper/verbs/fold.py +++ b/python/datashaper/datashaper/verbs/fold.py @@ -8,14 +8,14 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="fold", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def fold( diff --git a/python/datashaper/datashaper/verbs/groupby.py b/python/datashaper/datashaper/verbs/groupby.py index 8aca2960e..b2877fa0b 100644 --- a/python/datashaper/datashaper/verbs/groupby.py +++ b/python/datashaper/datashaper/verbs/groupby.py @@ -9,14 +9,14 @@ import pandas as pd from pandas.core.groupby import DataFrameGroupBy -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="groupby", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def groupby( diff --git a/python/datashaper/datashaper/verbs/impute.py b/python/datashaper/datashaper/verbs/impute.py index d448f1b58..95a342e82 100644 --- a/python/datashaper/datashaper/verbs/impute.py +++ b/python/datashaper/datashaper/verbs/impute.py @@ -8,14 +8,14 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="impute", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def impute( diff --git a/python/datashaper/datashaper/verbs/intersect.py b/python/datashaper/datashaper/verbs/intersect.py index 978c0216d..55cba4bc3 100644 --- a/python/datashaper/datashaper/verbs/intersect.py +++ b/python/datashaper/datashaper/verbs/intersect.py @@ -8,7 +8,7 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( @@ -16,7 +16,7 @@ immutable_input=True, adapters=[ inputs(default_input_argname="table", variadic_input_argname="others"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def intersect( diff --git a/python/datashaper/datashaper/verbs/join.py b/python/datashaper/datashaper/verbs/join.py index f9241650d..1068e7a54 100644 --- a/python/datashaper/datashaper/verbs/join.py +++ b/python/datashaper/datashaper/verbs/join.py @@ -9,7 +9,7 @@ import pandas as pd from pandas._typing import MergeHow, Suffixes -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result from .types import JoinStrategy __strategy_mapping: dict[JoinStrategy, MergeHow] = { @@ -51,7 +51,7 @@ def __clean_result( immutable_input=True, adapters=[ inputs(default_input_argname="table", input_argnames={"other": "other"}), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def join( diff --git a/python/datashaper/datashaper/verbs/lookup.py b/python/datashaper/datashaper/verbs/lookup.py index df5f9b0aa..fb8df5154 100644 --- a/python/datashaper/datashaper/verbs/lookup.py +++ b/python/datashaper/datashaper/verbs/lookup.py @@ -8,7 +8,7 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( @@ -16,7 +16,7 @@ immutable_input=True, adapters=[ inputs(default_input_argname="table", input_argnames={"other": "other"}), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def lookup( diff --git a/python/datashaper/datashaper/verbs/merge.py b/python/datashaper/datashaper/verbs/merge.py index 022a4438a..92d962165 100644 --- a/python/datashaper/datashaper/verbs/merge.py +++ b/python/datashaper/datashaper/verbs/merge.py @@ -11,7 +11,7 @@ import pandas as pd from pandas.api.types import is_bool -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result from .types import MergeStrategy @@ -19,7 +19,7 @@ name="merge", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def merge( diff --git a/python/datashaper/datashaper/verbs/onehot.py b/python/datashaper/datashaper/verbs/onehot.py index a89c03e60..f4c1fd75b 100644 --- a/python/datashaper/datashaper/verbs/onehot.py +++ b/python/datashaper/datashaper/verbs/onehot.py @@ -9,14 +9,14 @@ import numpy as np import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="onehot", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def onehot( diff --git a/python/datashaper/datashaper/verbs/orderby.py b/python/datashaper/datashaper/verbs/orderby.py index d450082db..07237e29e 100644 --- a/python/datashaper/datashaper/verbs/orderby.py +++ b/python/datashaper/datashaper/verbs/orderby.py @@ -8,7 +8,7 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result from .types import OrderByInstruction, SortDirection @@ -16,7 +16,7 @@ name="orderby", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def orderby(table: pd.DataFrame, orders: list[dict], **_kwargs: Any) -> pd.DataFrame: diff --git a/python/datashaper/datashaper/verbs/pivot.py b/python/datashaper/datashaper/verbs/pivot.py index 8381023be..ed332265b 100644 --- a/python/datashaper/datashaper/verbs/pivot.py +++ b/python/datashaper/datashaper/verbs/pivot.py @@ -9,7 +9,7 @@ import pandas as pd from .aggregate import aggregate_operation_mapping -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result from .types import FieldAggregateOperation @@ -18,7 +18,7 @@ immutable_input=True, adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def pivot( diff --git a/python/datashaper/datashaper/verbs/print.py b/python/datashaper/datashaper/verbs/print.py index a26a3b0d6..ed05b4103 100644 --- a/python/datashaper/datashaper/verbs/print.py +++ b/python/datashaper/datashaper/verbs/print.py @@ -8,7 +8,7 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result raw_print = print @@ -18,7 +18,7 @@ immutable_input=True, adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def print( # noqa A001 - use ds verb name diff --git a/python/datashaper/datashaper/verbs/recode.py b/python/datashaper/datashaper/verbs/recode.py index 4972ab78f..ed90d9507 100644 --- a/python/datashaper/datashaper/verbs/recode.py +++ b/python/datashaper/datashaper/verbs/recode.py @@ -8,7 +8,7 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result class RecodeMap(dict): @@ -23,7 +23,7 @@ def __missing__(self, key: str): name="recode", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def recode( diff --git a/python/datashaper/datashaper/verbs/rename.py b/python/datashaper/datashaper/verbs/rename.py index b64eabc1f..5ada8118d 100644 --- a/python/datashaper/datashaper/verbs/rename.py +++ b/python/datashaper/datashaper/verbs/rename.py @@ -8,14 +8,14 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="rename", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def rename( diff --git a/python/datashaper/datashaper/verbs/rollup.py b/python/datashaper/datashaper/verbs/rollup.py index 80ba2b37d..e26e2edbf 100644 --- a/python/datashaper/datashaper/verbs/rollup.py +++ b/python/datashaper/datashaper/verbs/rollup.py @@ -10,7 +10,7 @@ import pandas as pd from .aggregate import aggregate_operation_mapping -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result from .types import FieldAggregateOperation @@ -19,7 +19,7 @@ immutable_input=True, adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def rollup( diff --git a/python/datashaper/datashaper/verbs/sample.py b/python/datashaper/datashaper/verbs/sample.py index 0c54ef30c..48f9facde 100644 --- a/python/datashaper/datashaper/verbs/sample.py +++ b/python/datashaper/datashaper/verbs/sample.py @@ -8,7 +8,7 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( @@ -16,7 +16,7 @@ immutable_input=True, adapters=[ inputs(default_input_argname="table"), - outputs( + wrap_verb_result( mode=OutputMode.Tuple, output_names=["remainder"], ), diff --git a/python/datashaper/datashaper/verbs/select.py b/python/datashaper/datashaper/verbs/select.py index 31118fbe3..fe032a170 100644 --- a/python/datashaper/datashaper/verbs/select.py +++ b/python/datashaper/datashaper/verbs/select.py @@ -8,7 +8,7 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( @@ -16,7 +16,7 @@ immutable_input=True, adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def select(table: pd.DataFrame, columns: list[str], **_kwargs: Any) -> pd.DataFrame: diff --git a/python/datashaper/datashaper/verbs/snapshot.py b/python/datashaper/datashaper/verbs/snapshot.py index 679c8e733..ccf2bf9aa 100644 --- a/python/datashaper/datashaper/verbs/snapshot.py +++ b/python/datashaper/datashaper/verbs/snapshot.py @@ -8,7 +8,7 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result from .types import FileFormat @@ -17,7 +17,7 @@ immutable_input=True, adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def snapshot( diff --git a/python/datashaper/datashaper/verbs/spread.py b/python/datashaper/datashaper/verbs/spread.py index a2d6acf40..7fefe36b1 100644 --- a/python/datashaper/datashaper/verbs/spread.py +++ b/python/datashaper/datashaper/verbs/spread.py @@ -8,14 +8,14 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="spread", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def spread( diff --git a/python/datashaper/datashaper/verbs/strings/lower.py b/python/datashaper/datashaper/verbs/strings/lower.py index ccc8ff99e..0177b8f13 100644 --- a/python/datashaper/datashaper/verbs/strings/lower.py +++ b/python/datashaper/datashaper/verbs/strings/lower.py @@ -10,8 +10,8 @@ OutputMode, apply_decorators, inputs, - outputs, verb, + wrap_verb_result, ) @@ -25,7 +25,7 @@ def lower(table: pd.DataFrame, column: str, to: str, **_kwargs: dict) -> pd.Data [ verb(name="strings.lower"), inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], lower, ) diff --git a/python/datashaper/datashaper/verbs/strings/replace.py b/python/datashaper/datashaper/verbs/strings/replace.py index e460ed874..200693eb8 100644 --- a/python/datashaper/datashaper/verbs/strings/replace.py +++ b/python/datashaper/datashaper/verbs/strings/replace.py @@ -12,8 +12,8 @@ OutputMode, apply_decorators, inputs, - outputs, verb, + wrap_verb_result, ) @@ -38,7 +38,7 @@ def replace( [ verb(name="strings.replace"), inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], replace, ) diff --git a/python/datashaper/datashaper/verbs/strings/upper.py b/python/datashaper/datashaper/verbs/strings/upper.py index a22acd5e7..4fff10895 100644 --- a/python/datashaper/datashaper/verbs/strings/upper.py +++ b/python/datashaper/datashaper/verbs/strings/upper.py @@ -10,8 +10,8 @@ OutputMode, apply_decorators, inputs, - outputs, verb, + wrap_verb_result, ) @@ -25,7 +25,7 @@ def upper(table: pd.DataFrame, column: str, to: str, **_kwargs: dict) -> pd.Data [ verb(name="strings.upper"), inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], upper, ) diff --git a/python/datashaper/datashaper/verbs/unfold.py b/python/datashaper/datashaper/verbs/unfold.py index 8934afd23..c920355db 100644 --- a/python/datashaper/datashaper/verbs/unfold.py +++ b/python/datashaper/datashaper/verbs/unfold.py @@ -9,14 +9,14 @@ import numpy as np import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="unfold", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def unfold(table: pd.DataFrame, key: str, value: str, **_kwargs: Any) -> pd.DataFrame: diff --git a/python/datashaper/datashaper/verbs/ungroup.py b/python/datashaper/datashaper/verbs/ungroup.py index f21b32007..eafa750d7 100644 --- a/python/datashaper/datashaper/verbs/ungroup.py +++ b/python/datashaper/datashaper/verbs/ungroup.py @@ -8,7 +8,7 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( @@ -16,7 +16,7 @@ immutable_input=True, adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def ungroup(table: pd.DataFrame, **_kwargs: Any) -> pd.DataFrame: diff --git a/python/datashaper/datashaper/verbs/unhot.py b/python/datashaper/datashaper/verbs/unhot.py index 8323b0683..391813b24 100644 --- a/python/datashaper/datashaper/verbs/unhot.py +++ b/python/datashaper/datashaper/verbs/unhot.py @@ -4,14 +4,14 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="unhot", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def unhot( diff --git a/python/datashaper/datashaper/verbs/union.py b/python/datashaper/datashaper/verbs/union.py index 0e3765c56..d28158747 100644 --- a/python/datashaper/datashaper/verbs/union.py +++ b/python/datashaper/datashaper/verbs/union.py @@ -8,7 +8,7 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( @@ -16,7 +16,7 @@ immutable_input=True, adapters=[ inputs(default_input_argname="table", variadic_input_argname="others"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def union( diff --git a/python/datashaper/datashaper/verbs/unorder.py b/python/datashaper/datashaper/verbs/unorder.py index b3ef05c9e..437ad12cd 100644 --- a/python/datashaper/datashaper/verbs/unorder.py +++ b/python/datashaper/datashaper/verbs/unorder.py @@ -8,7 +8,7 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( @@ -16,7 +16,7 @@ immutable_input=True, adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def unorder(table: pd.DataFrame, **_kwargs: Any) -> pd.DataFrame: diff --git a/python/datashaper/datashaper/verbs/unroll.py b/python/datashaper/datashaper/verbs/unroll.py index cf075843e..388af7575 100644 --- a/python/datashaper/datashaper/verbs/unroll.py +++ b/python/datashaper/datashaper/verbs/unroll.py @@ -8,13 +8,16 @@ import pandas as pd -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result @verb( name="unroll", immutable_input=True, - adapters=[inputs(default_input_argname="table"), outputs(mode=OutputMode.Table)], + adapters=[ + inputs(default_input_argname="table"), + wrap_verb_result(mode=OutputMode.Table), + ], ) def unroll(table: pd.DataFrame, column: str, **_kwargs: Any) -> pd.DataFrame: """Unroll a column.""" diff --git a/python/datashaper/datashaper/verbs/window.py b/python/datashaper/datashaper/verbs/window.py index f9a55742f..5dab18593 100644 --- a/python/datashaper/datashaper/verbs/window.py +++ b/python/datashaper/datashaper/verbs/window.py @@ -11,7 +11,7 @@ import pandas as pd from pandas.core.groupby import DataFrameGroupBy -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result from .types import WindowFunction @@ -61,7 +61,7 @@ def _get_window_indexer( name="window", adapters=[ inputs(default_input_argname="table"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) def window( diff --git a/python/datashaper/datashaper/verbs/workflow.py b/python/datashaper/datashaper/verbs/workflow.py index 2d7fd55f5..71efa4558 100644 --- a/python/datashaper/datashaper/verbs/workflow.py +++ b/python/datashaper/datashaper/verbs/workflow.py @@ -6,7 +6,7 @@ from datashaper.constants import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, outputs, verb +from .decorators import OutputMode, inputs, verb, wrap_verb_result from .types import Table @@ -14,7 +14,7 @@ name="workflow", adapters=[ inputs(default_input_argname="table", input_dict_argname="tables"), - outputs(mode=OutputMode.Table), + wrap_verb_result(mode=OutputMode.Table), ], ) async def workflow( diff --git a/python/datashaper/poetry.lock b/python/datashaper/poetry.lock index eb07e0f78..e7b43b674 100644 --- a/python/datashaper/poetry.lock +++ b/python/datashaper/poetry.lock @@ -1,4 +1,15 @@ -# This file is automatically @generated by Poetry 1.5.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] [[package]] name = "attrs" @@ -298,6 +309,24 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] +[[package]] +name = "networkx" +version = "3.3" +description = "Python package for creating and manipulating graphs and networks" +optional = false +python-versions = ">=3.10" +files = [ + {file = "networkx-3.3-py3-none-any.whl", hash = "sha256:28575580c6ebdaf4505b22c6256a2b9de86b316dc63ba9e93abde3d78dfdbcf2"}, + {file = "networkx-3.3.tar.gz", hash = "sha256:0c127d8b2f4865f59ae9cb8aafcd60b5c70f3241ebd66f7defad7c4ab90126c9"}, +] + +[package.extras] +default = ["matplotlib (>=3.6)", "numpy (>=1.23)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"] +developer = ["changelist (==0.5)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] +doc = ["myst-nb (>=1.0)", "numpydoc (>=1.7)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"] +extra = ["lxml (>=4.6)", "pydot (>=2.0)", "pygraphviz (>=1.12)", "sympy (>=1.10)"] +test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] + [[package]] name = "nodeenv" version = "1.8.0" @@ -532,6 +561,116 @@ files = [ [package.dependencies] numpy = ">=1.16.6,<2" +[[package]] +name = "pydantic" +version = "2.7.4" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic-2.7.4-py3-none-any.whl", hash = "sha256:ee8538d41ccb9c0a9ad3e0e5f07bf15ed8015b481ced539a1759d8cc89ae90d0"}, + {file = "pydantic-2.7.4.tar.gz", hash = "sha256:0c84efd9548d545f63ac0060c1e4d39bb9b14db8b3c0652338aecc07b5adec52"}, +] + +[package.dependencies] +annotated-types = ">=0.4.0" +pydantic-core = "2.18.4" +typing-extensions = ">=4.6.1" + +[package.extras] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.18.4" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.18.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4"}, + {file = "pydantic_core-2.18.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb"}, + {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c"}, + {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e"}, + {file = "pydantic_core-2.18.4-cp310-none-win32.whl", hash = "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc"}, + {file = "pydantic_core-2.18.4-cp310-none-win_amd64.whl", hash = "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0"}, + {file = "pydantic_core-2.18.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d"}, + {file = "pydantic_core-2.18.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951"}, + {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2"}, + {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9"}, + {file = "pydantic_core-2.18.4-cp311-none-win32.whl", hash = "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558"}, + {file = "pydantic_core-2.18.4-cp311-none-win_amd64.whl", hash = "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b"}, + {file = "pydantic_core-2.18.4-cp311-none-win_arm64.whl", hash = "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805"}, + {file = "pydantic_core-2.18.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2"}, + {file = "pydantic_core-2.18.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9"}, + {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c"}, + {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8"}, + {file = "pydantic_core-2.18.4-cp312-none-win32.whl", hash = "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07"}, + {file = "pydantic_core-2.18.4-cp312-none-win_amd64.whl", hash = "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a"}, + {file = "pydantic_core-2.18.4-cp312-none-win_arm64.whl", hash = "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f"}, + {file = "pydantic_core-2.18.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2"}, + {file = "pydantic_core-2.18.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057"}, + {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b"}, + {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af"}, + {file = "pydantic_core-2.18.4-cp38-none-win32.whl", hash = "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2"}, + {file = "pydantic_core-2.18.4-cp38-none-win_amd64.whl", hash = "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443"}, + {file = "pydantic_core-2.18.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528"}, + {file = "pydantic_core-2.18.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23"}, + {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b"}, + {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a"}, + {file = "pydantic_core-2.18.4-cp39-none-win32.whl", hash = "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d"}, + {file = "pydantic_core-2.18.4-cp39-none-win_amd64.whl", hash = "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9"}, + {file = "pydantic_core-2.18.4.tar.gz", hash = "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + [[package]] name = "pyright" version = "1.1.350" @@ -633,6 +772,36 @@ files = [ {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] +[[package]] +name = "reactivedataflow" +version = "0.1.0" +description = "Reactive Dataflow Graphs" +optional = false +python-versions = "<4.0,>=3.10" +files = [ + {file = "reactivedataflow-0.1.0-py3-none-any.whl", hash = "sha256:65eb577a461001b407202b3985327a6eccdb49f3921e7be087c7d1325c049351"}, + {file = "reactivedataflow-0.1.0.tar.gz", hash = "sha256:d88dab401fab8eae92492c083782eba511cd8fbd8798712cd6efd5376ac0a9ed"}, +] + +[package.dependencies] +networkx = ">=3.3,<4.0" +pydantic = ">=2.7.4,<3.0.0" +reactivex = ">=4.0.4,<5.0.0" + +[[package]] +name = "reactivex" +version = "4.0.4" +description = "ReactiveX (Rx) for Python" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "reactivex-4.0.4-py3-none-any.whl", hash = "sha256:0004796c420bd9e68aad8e65627d85a8e13f293de76656165dffbcb3a0e3fb6a"}, + {file = "reactivex-4.0.4.tar.gz", hash = "sha256:e912e6591022ab9176df8348a653fe8c8fa7a301f26f9931c9d8c78a650e04e8"}, +] + +[package.dependencies] +typing-extensions = ">=4.1.1,<5.0.0" + [[package]] name = "referencing" version = "0.33.0" @@ -847,6 +1016,17 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + [[package]] name = "tzdata" version = "2024.1" @@ -861,4 +1041,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.10,<4" -content-hash = "26c3d35b236837b75919dfac79fb6ccf5d16038145a3e6e5d40fba3088783bce" +content-hash = "95074890cfe3bd9c2e91276983f0b33527af68e4345ece6753297d6df882ed87" diff --git a/python/datashaper/pyproject.toml b/python/datashaper/pyproject.toml index d762df4c0..72ef96b8f 100644 --- a/python/datashaper/pyproject.toml +++ b/python/datashaper/pyproject.toml @@ -17,6 +17,7 @@ pyarrow = "^15.0.0" diskcache = "^5.6.3" dacite = "^1.8.1" +reactivedataflow = "^0.1.0" [tool.poetry.group.dev.dependencies] codespell = "^2.2.6" poethepoet = "^0.24.4" From f82903506b2e07ce477a7572b089ad0a03a66f05 Mon Sep 17 00:00:00 2001 From: Chris Trevino <chtrevin@microsoft.com> Date: Mon, 24 Jun 2024 15:48:41 -0700 Subject: [PATCH 2/3] add binarize --- python/datashaper/datashaper/verbs/bin.py | 12 ++++++------ python/datashaper/datashaper/verbs/binarize.py | 15 +++++++++++++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/python/datashaper/datashaper/verbs/bin.py b/python/datashaper/datashaper/verbs/bin.py index 0879206d5..88618ca4c 100644 --- a/python/datashaper/datashaper/verbs/bin.py +++ b/python/datashaper/datashaper/verbs/bin.py @@ -82,12 +82,12 @@ def __get_bucket_value( ConfigPort(name="to", required=True), ConfigPort(name="column", required=True), ConfigPort(name="strategy", required=True), - ConfigPort(name="min", required=False), - ConfigPort(name="max", required=False), - ConfigPort(name="fixedcount", required=False), - ConfigPort(name="fixedwidth", required=False), - ConfigPort(name="clamped", required=False), - ConfigPort(name="printRange", required=False), + ConfigPort(name="min"), + ConfigPort(name="max"), + ConfigPort(name="fixedcount"), + ConfigPort(name="fixedwidth"), + ConfigPort(name="clamped"), + ConfigPort(name="printRange"), ], adapters=[ copy_input_tables("table"), diff --git a/python/datashaper/datashaper/verbs/binarize.py b/python/datashaper/datashaper/verbs/binarize.py index d05741cec..e020867ff 100644 --- a/python/datashaper/datashaper/verbs/binarize.py +++ b/python/datashaper/datashaper/verbs/binarize.py @@ -7,8 +7,11 @@ from typing import Any, cast import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper.constants import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result from .filter import filter, get_comparison_operator from .types import ( ComparisonStrategy, @@ -19,8 +22,16 @@ @verb( name="binarize", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="value", required=True), + ConfigPort(name="strategy"), + ConfigPort(name="operator"), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) From bb6e0fae72be54ccc8a14ea1c6b0812333ca460b Mon Sep 17 00:00:00 2001 From: Chris Trevino <chtrevin@microsoft.com> Date: Mon, 24 Jun 2024 16:25:54 -0700 Subject: [PATCH 3/3] add reactiveworkflow annotations to verbs --- python/datashaper/datashaper/__init__.py | 6 ---- .../datashaper/datashaper/verbs/__init__.py | 6 ---- .../datashaper/datashaper/verbs/aggregate.py | 2 +- python/datashaper/datashaper/verbs/boolean.py | 13 ++++++-- python/datashaper/datashaper/verbs/concat.py | 16 +++++---- python/datashaper/datashaper/verbs/convert.py | 17 ++++++++-- python/datashaper/datashaper/verbs/copy.py | 15 ++++++--- .../datashaper/verbs/decorators/__init__.py | 4 --- python/datashaper/datashaper/verbs/dedupe.py | 17 +++++----- python/datashaper/datashaper/verbs/derive.py | 15 ++++++--- .../datashaper/verbs/destructure.py | 14 ++++++-- .../datashaper/datashaper/verbs/difference.py | 17 ++++++---- python/datashaper/datashaper/verbs/drop.py | 15 ++++++--- .../datashaper/verbs/engine/__init__.py | 2 -- python/datashaper/datashaper/verbs/erase.py | 18 ++++++---- python/datashaper/datashaper/verbs/fill.py | 18 ++++++---- python/datashaper/datashaper/verbs/fold.py | 13 ++++++-- python/datashaper/datashaper/verbs/groupby.py | 18 +++++----- python/datashaper/datashaper/verbs/impute.py | 18 ++++++---- .../datashaper/datashaper/verbs/intersect.py | 15 ++++++--- python/datashaper/datashaper/verbs/join.py | 15 ++++++--- python/datashaper/datashaper/verbs/lookup.py | 21 +++++++----- python/datashaper/datashaper/verbs/merge.py | 16 +++++++-- python/datashaper/datashaper/verbs/onehot.py | 16 ++++++--- python/datashaper/datashaper/verbs/orderby.py | 15 ++++++--- python/datashaper/datashaper/verbs/pivot.py | 18 ++++++---- python/datashaper/datashaper/verbs/print.py | 15 +++++---- python/datashaper/datashaper/verbs/recode.py | 17 +++++++--- python/datashaper/datashaper/verbs/rename.py | 17 ++++++---- python/datashaper/datashaper/verbs/rollup.py | 18 ++++++---- python/datashaper/datashaper/verbs/sample.py | 14 ++++++-- python/datashaper/datashaper/verbs/select.py | 15 ++++++--- .../datashaper/datashaper/verbs/snapshot.py | 17 ++++++---- python/datashaper/datashaper/verbs/spread.py | 14 ++++++-- .../datashaper/verbs/strings/lower.py | 30 +++++++++-------- .../datashaper/verbs/strings/replace.py | 33 +++++++++++-------- .../datashaper/verbs/strings/upper.py | 30 +++++++++-------- python/datashaper/datashaper/verbs/unfold.py | 16 ++++++--- python/datashaper/datashaper/verbs/ungroup.py | 14 ++++---- python/datashaper/datashaper/verbs/unhot.py | 14 ++++++-- python/datashaper/datashaper/verbs/union.py | 18 +++++----- python/datashaper/datashaper/verbs/unorder.py | 14 ++++---- python/datashaper/datashaper/verbs/unroll.py | 15 +++++---- python/datashaper/datashaper/verbs/window.py | 15 ++++++--- .../datashaper/datashaper/verbs/workflow.py | 9 +++-- .../datashaper/workflow/workflow.py | 2 +- python/datashaper/pyproject.toml | 2 +- 47 files changed, 443 insertions(+), 256 deletions(-) diff --git a/python/datashaper/datashaper/__init__.py b/python/datashaper/datashaper/__init__.py index b757ed4e0..07879cc58 100644 --- a/python/datashaper/datashaper/__init__.py +++ b/python/datashaper/datashaper/__init__.py @@ -51,13 +51,10 @@ VerbCallbacks, VerbDetails, VerbInput, - VerbManager, VerbResult, WindowFunction, - inputs, load_verbs, parallel_verb, - verb, ) from .workflow import ( DEFAULT_INPUT_NAME, @@ -114,10 +111,7 @@ "Bin", "Category", "VerbInput", - "VerbManager", "load_verbs", - "verb", - "inputs", "parallel_verb", "ParallelizationMode", "VerbDetails", diff --git a/python/datashaper/datashaper/verbs/__init__.py b/python/datashaper/datashaper/verbs/__init__.py index ac006263e..e512651dc 100644 --- a/python/datashaper/datashaper/verbs/__init__.py +++ b/python/datashaper/datashaper/verbs/__init__.py @@ -15,9 +15,7 @@ from .decorators import ( OutputMode, ParallelizationMode, - inputs, parallel_verb, - verb, wrap_verb_result, ) from .dedupe import dedupe @@ -28,7 +26,6 @@ from .engine import ( VerbDetails, VerbInput, - VerbManager, VerbResult, load_verbs, ) @@ -140,11 +137,8 @@ "replace", # Verb Authoring "VerbInput", - "VerbManager", "load_verbs", # Decorators - "verb", - "inputs", "wrap_verb_result", "parallel_verb", "OutputMode", diff --git a/python/datashaper/datashaper/verbs/aggregate.py b/python/datashaper/datashaper/verbs/aggregate.py index 8d07d29d9..b1e8263b6 100644 --- a/python/datashaper/datashaper/verbs/aggregate.py +++ b/python/datashaper/datashaper/verbs/aggregate.py @@ -5,7 +5,7 @@ """Aggregate verb implementation.""" from functools import reduce -from typing import Any, cast +from typing import cast import pandas as pd from reactivedataflow import ConfigPort, InputPort, verb diff --git a/python/datashaper/datashaper/verbs/boolean.py b/python/datashaper/datashaper/verbs/boolean.py index 4941e5394..e3f0bde65 100644 --- a/python/datashaper/datashaper/verbs/boolean.py +++ b/python/datashaper/datashaper/verbs/boolean.py @@ -7,16 +7,25 @@ from typing import Any import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper.constants import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result from .filter import boolean_function_map from .types import BooleanLogicalOperator @verb( name="boolean", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="columns", required=True), + ConfigPort(name="operator", required=True), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) diff --git a/python/datashaper/datashaper/verbs/concat.py b/python/datashaper/datashaper/verbs/concat.py index 760b8d3f9..dd1cec70f 100644 --- a/python/datashaper/datashaper/verbs/concat.py +++ b/python/datashaper/datashaper/verbs/concat.py @@ -4,23 +4,25 @@ # """Concat verb implementation.""" -from typing import Any - import pandas as pd +from reactivedataflow import ArrayInputPort, InputPort, verb + +from datashaper.constants import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, wrap_verb_result @verb( name="concat", immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ArrayInputPort(name="others", required=True), + ], adapters=[ - inputs(default_input_argname="table", variadic_input_argname="others"), wrap_verb_result(mode=OutputMode.Table), ], ) -def concat( - table: pd.DataFrame, others: list[pd.DataFrame], **_kwargs: Any -) -> pd.DataFrame: +def concat(table: pd.DataFrame, others: list[pd.DataFrame]) -> pd.DataFrame: """Concat verb implementation.""" return pd.concat([table] + others, ignore_index=True) diff --git a/python/datashaper/datashaper/verbs/convert.py b/python/datashaper/datashaper/verbs/convert.py index c26a77428..90f2fda5d 100644 --- a/python/datashaper/datashaper/verbs/convert.py +++ b/python/datashaper/datashaper/verbs/convert.py @@ -12,8 +12,11 @@ import numpy as np import pandas as pd from pandas.api.types import is_bool_dtype, is_datetime64_any_dtype, is_numeric_dtype +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result from .types import ParseType @@ -116,8 +119,17 @@ def convert_value(value: Any) -> list: @verb( name="convert", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="type", required=True), + ConfigPort(name="radix"), + ConfigPort(name="delimiter"), + ConfigPort(name="formatPattern"), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) @@ -129,7 +141,6 @@ def convert( radix: int | None = None, delimiter: str | None = ",", formatPattern: str = "%Y-%m-%d", # noqa: N803 - **_kwargs: Any, ) -> pd.DataFrame: """Convert verb implementation.""" parse_type = ParseType(type) diff --git a/python/datashaper/datashaper/verbs/copy.py b/python/datashaper/datashaper/verbs/copy.py index 4517e2c04..7708a3006 100644 --- a/python/datashaper/datashaper/verbs/copy.py +++ b/python/datashaper/datashaper/verbs/copy.py @@ -4,17 +4,23 @@ # """Copy verb implementation.""" -from typing import Any - import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb + +from datashaper import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="copy", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="column", required=True), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) @@ -22,7 +28,6 @@ def copy( table: pd.DataFrame, to: str, column: str, - **_kwargs: Any, ) -> pd.DataFrame: """Copy verb implementation.""" table[to] = table[column] diff --git a/python/datashaper/datashaper/verbs/decorators/__init__.py b/python/datashaper/datashaper/verbs/decorators/__init__.py index 647159e82..ec965f9e7 100644 --- a/python/datashaper/datashaper/verbs/decorators/__init__.py +++ b/python/datashaper/datashaper/verbs/decorators/__init__.py @@ -2,18 +2,14 @@ from .apply_decorators import apply_decorators from .copy_input_tables import copy_input_tables -from .inputs import inputs from .parallel_verb import ParallelizationMode, new_row, parallel_verb -from .verb import verb from .wrap_verb_result import OutputMode, wrap_verb_result __all__ = [ "new_row", - "verb", "copy_input_tables", "parallel_verb", "ParallelizationMode", - "inputs", "apply_decorators", "wrap_verb_result", "OutputMode", diff --git a/python/datashaper/datashaper/verbs/dedupe.py b/python/datashaper/datashaper/verbs/dedupe.py index e1d43b432..f85eb94b5 100644 --- a/python/datashaper/datashaper/verbs/dedupe.py +++ b/python/datashaper/datashaper/verbs/dedupe.py @@ -4,23 +4,24 @@ # """Dedupe verb implementation.""" -from typing import Any - import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb + +from datashaper import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, wrap_verb_result @verb( name="dedupe", - immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="columns", required=False), + ], adapters=[ - inputs(default_input_argname="table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def dedupe( - table: pd.DataFrame, columns: list[str] | None = None, **_kwargs: Any -) -> pd.DataFrame: +def dedupe(table: pd.DataFrame, columns: list[str] | None = None) -> pd.DataFrame: """Dedupe verb implementation.""" return table.drop_duplicates(columns) diff --git a/python/datashaper/datashaper/verbs/derive.py b/python/datashaper/datashaper/verbs/derive.py index e2c5154ab..b51913f5e 100644 --- a/python/datashaper/datashaper/verbs/derive.py +++ b/python/datashaper/datashaper/verbs/derive.py @@ -5,15 +5,16 @@ """Derive verb implementation.""" from collections.abc import Callable -from typing import Any import numpy as np import pandas as pd from pandas.api.types import is_numeric_dtype +from reactivedataflow import ConfigPort, InputPort, verb +from datashaper import DEFAULT_INPUT_NAME from datashaper.errors import VerbOperationNotSupportedError -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, copy_input_tables, wrap_verb_result from .types import MathOperator @@ -40,8 +41,15 @@ def __concatenate(col1: pd.Series, col2: pd.Series) -> pd.Series: @verb( name="derive", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="column1", required=True), + ConfigPort(name="column2", required=True), + ConfigPort(name="operator", required=True), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) @@ -51,7 +59,6 @@ def derive( column1: str, column2: str, operator: str, - **_kwargs: Any, ) -> pd.DataFrame: """Derive verb implementation.""" math_operator = MathOperator(operator) diff --git a/python/datashaper/datashaper/verbs/destructure.py b/python/datashaper/datashaper/verbs/destructure.py index 94aad05d2..3e8d296d3 100644 --- a/python/datashaper/datashaper/verbs/destructure.py +++ b/python/datashaper/datashaper/verbs/destructure.py @@ -8,14 +8,23 @@ from typing import Any import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="destructure", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="keys", required=False), + ConfigPort(name="preserveSource"), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) @@ -24,7 +33,6 @@ def destructure( column: str, keys: list[str], preserveSource: bool = False, # noqa: N803 - **_kwargs: Any, ) -> pd.DataFrame: """Destructure verb implementation.""" results = [] diff --git a/python/datashaper/datashaper/verbs/difference.py b/python/datashaper/datashaper/verbs/difference.py index 8e10a642d..49bace212 100644 --- a/python/datashaper/datashaper/verbs/difference.py +++ b/python/datashaper/datashaper/verbs/difference.py @@ -4,23 +4,28 @@ # """Difference verb implementation.""" -from typing import Any, cast +from typing import cast import pandas as pd +from reactivedataflow import ArrayInputPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="difference", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ArrayInputPort(name="others", required=True), + ], adapters=[ - inputs(default_input_argname="table", variadic_input_argname="others"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def difference( - table: pd.DataFrame, others: list[pd.DataFrame], **_kwargs: Any -) -> pd.DataFrame: +def difference(table: pd.DataFrame, others: list[pd.DataFrame]) -> pd.DataFrame: """Difference verb implementation.""" output = table.merge(pd.concat(others), how="left", indicator=True) output = output[output["_merge"] == "left_only"] diff --git a/python/datashaper/datashaper/verbs/drop.py b/python/datashaper/datashaper/verbs/drop.py index e9741f5fe..054d6b1df 100644 --- a/python/datashaper/datashaper/verbs/drop.py +++ b/python/datashaper/datashaper/verbs/drop.py @@ -4,20 +4,25 @@ # """Drop verb implementation.""" -from typing import Any - import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb + +from datashaper import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="drop", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="columns", required=True), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def drop(table: pd.DataFrame, columns: list[str], **_kwargs: Any) -> pd.DataFrame: +def drop(table: pd.DataFrame, columns: list[str]) -> pd.DataFrame: """Drop verb implementation.""" return table.drop(columns=columns) diff --git a/python/datashaper/datashaper/verbs/engine/__init__.py b/python/datashaper/datashaper/verbs/engine/__init__.py index f5019bfd5..5c453a3b8 100644 --- a/python/datashaper/datashaper/verbs/engine/__init__.py +++ b/python/datashaper/datashaper/verbs/engine/__init__.py @@ -6,7 +6,6 @@ from .load_verbs import load_verbs from .types import VerbDetails, VerbResult from .verb_input import VerbInput -from .verb_manager import VerbManager # Load core verbs into VerbManager mod = sys.modules[__name__] @@ -15,7 +14,6 @@ __all__ = [ "VerbInput", - "VerbManager", "create_verb_result", "load_verbs", "VerbResult", diff --git a/python/datashaper/datashaper/verbs/erase.py b/python/datashaper/datashaper/verbs/erase.py index d2e22eb4d..790a712ed 100644 --- a/python/datashaper/datashaper/verbs/erase.py +++ b/python/datashaper/datashaper/verbs/erase.py @@ -4,23 +4,27 @@ # """Erase verb implementation.""" -from typing import Any - import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb + +from datashaper import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="erase", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="value", required=True), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def erase( - table: pd.DataFrame, column: str, value: str | float, **_kwargs: Any -) -> pd.DataFrame: +def erase(table: pd.DataFrame, column: str, value: str | float) -> pd.DataFrame: """Erase verb implementation.""" table[column] = table[column].apply( lambda df_value: None if df_value == value else df_value diff --git a/python/datashaper/datashaper/verbs/fill.py b/python/datashaper/datashaper/verbs/fill.py index 5613bf766..747d5ed1f 100644 --- a/python/datashaper/datashaper/verbs/fill.py +++ b/python/datashaper/datashaper/verbs/fill.py @@ -4,23 +4,27 @@ # """Fill verb implementation.""" -from typing import Any - import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb + +from datashaper import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="fill", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="value", required=True), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def fill( - table: pd.DataFrame, to: str, value: str | float | bool, **_kwargs: Any -) -> pd.DataFrame: +def fill(table: pd.DataFrame, to: str, value: str | float | bool) -> pd.DataFrame: """Fill verb implementation.""" table[to] = value return table diff --git a/python/datashaper/datashaper/verbs/fold.py b/python/datashaper/datashaper/verbs/fold.py index 6570662de..8471b48b9 100644 --- a/python/datashaper/datashaper/verbs/fold.py +++ b/python/datashaper/datashaper/verbs/fold.py @@ -7,14 +7,23 @@ from typing import Any, cast import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="fold", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="columns", required=True), + ConfigPort(name="preserveSource"), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) diff --git a/python/datashaper/datashaper/verbs/groupby.py b/python/datashaper/datashaper/verbs/groupby.py index b2877fa0b..3b6a9716b 100644 --- a/python/datashaper/datashaper/verbs/groupby.py +++ b/python/datashaper/datashaper/verbs/groupby.py @@ -3,24 +3,26 @@ # Licensed under the MIT license. See LICENSE file in the project. # """Groupby verb implementation.""" - -from typing import Any - import pandas as pd from pandas.core.groupby import DataFrameGroupBy +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="groupby", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="columns", required=True), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def groupby( - table: pd.DataFrame, columns: list[str], **_kwargs: Any -) -> DataFrameGroupBy: +def groupby(table: pd.DataFrame, columns: list[str]) -> DataFrameGroupBy: """Groupby verb implementation.""" return table.groupby(by=columns) diff --git a/python/datashaper/datashaper/verbs/impute.py b/python/datashaper/datashaper/verbs/impute.py index 95a342e82..120344960 100644 --- a/python/datashaper/datashaper/verbs/impute.py +++ b/python/datashaper/datashaper/verbs/impute.py @@ -4,23 +4,29 @@ # """Impute verb implementation.""" -from typing import Any, cast +from typing import cast import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="impute", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="value", required=True), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def impute( - table: pd.DataFrame, column: str, value: str | float | bool, **_kwargs: Any -) -> pd.DataFrame: +def impute(table: pd.DataFrame, column: str, value: str | float | bool) -> pd.DataFrame: """Impute verb implementation.""" table[column] = cast(pd.Series, table[column].fillna(value)) return table diff --git a/python/datashaper/datashaper/verbs/intersect.py b/python/datashaper/datashaper/verbs/intersect.py index 55cba4bc3..603d3b126 100644 --- a/python/datashaper/datashaper/verbs/intersect.py +++ b/python/datashaper/datashaper/verbs/intersect.py @@ -7,21 +7,26 @@ from typing import cast import pandas as pd +from reactivedataflow import ArrayInputPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="intersect", immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ArrayInputPort(name="others", required=True), + ], adapters=[ - inputs(default_input_argname="table", variadic_input_argname="others"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def intersect( - table: pd.DataFrame, others: list[pd.DataFrame], **_kwargs: dict -) -> pd.DataFrame: +def intersect(table: pd.DataFrame, others: list[pd.DataFrame]) -> pd.DataFrame: """Intersect verb implementation.""" output = table.merge(pd.concat(others), how="left", indicator=True) output = output[output["_merge"] == "both"] diff --git a/python/datashaper/datashaper/verbs/join.py b/python/datashaper/datashaper/verbs/join.py index 1068e7a54..88c5f4fa1 100644 --- a/python/datashaper/datashaper/verbs/join.py +++ b/python/datashaper/datashaper/verbs/join.py @@ -4,12 +4,15 @@ # """Join verb implementation.""" -from typing import Any, cast +from typing import cast import pandas as pd from pandas._typing import MergeHow, Suffixes +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, wrap_verb_result from .types import JoinStrategy __strategy_mapping: dict[JoinStrategy, MergeHow] = { @@ -49,8 +52,13 @@ def __clean_result( @verb( name="join", immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + InputPort(name="other", required=True), + ConfigPort(name="on"), + ConfigPort(name="strategy"), + ], adapters=[ - inputs(default_input_argname="table", input_argnames={"other": "other"}), wrap_verb_result(mode=OutputMode.Table), ], ) @@ -59,7 +67,6 @@ def join( other: pd.DataFrame, on: list[str] | None = None, strategy: str = "inner", - **_kwargs: Any, ) -> pd.DataFrame: """Join verb implementation.""" join_strategy = JoinStrategy(strategy) diff --git a/python/datashaper/datashaper/verbs/lookup.py b/python/datashaper/datashaper/verbs/lookup.py index fb8df5154..b6dc2b81e 100644 --- a/python/datashaper/datashaper/verbs/lookup.py +++ b/python/datashaper/datashaper/verbs/lookup.py @@ -4,27 +4,30 @@ # """Lookup verb implementation.""" -from typing import Any, cast +from typing import cast import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, wrap_verb_result @verb( name="lookup", - immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + InputPort(name="other", required=True), + ConfigPort(name="columns", required=True), + ConfigPort(name="on"), + ], adapters=[ - inputs(default_input_argname="table", input_argnames={"other": "other"}), wrap_verb_result(mode=OutputMode.Table), ], ) def lookup( - table: pd.DataFrame, - other: pd.DataFrame, - columns: list[str], - on: list[str] | None = None, - **_kwargs: Any, + table: pd.DataFrame, other: pd.DataFrame, columns: list[str], on: list[str] | None ) -> pd.DataFrame: """Lookup verb implementation.""" if on is not None and len(on) > 1: diff --git a/python/datashaper/datashaper/verbs/merge.py b/python/datashaper/datashaper/verbs/merge.py index 92d962165..0a7ad676f 100644 --- a/python/datashaper/datashaper/verbs/merge.py +++ b/python/datashaper/datashaper/verbs/merge.py @@ -10,15 +10,26 @@ import pandas as pd from pandas.api.types import is_bool +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result from .types import MergeStrategy @verb( name="merge", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="columns", required=True), + ConfigPort(name="strategy", required=True), + ConfigPort(name="delimiter"), + ConfigPort(name="preserveSource"), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) @@ -29,7 +40,6 @@ def merge( strategy: str, delimiter: str = "", preserveSource: bool = False, # noqa: N803 - **_kwargs: Any, ) -> pd.DataFrame: """Merge verb implementation.""" merge_strategy = MergeStrategy(strategy) diff --git a/python/datashaper/datashaper/verbs/onehot.py b/python/datashaper/datashaper/verbs/onehot.py index f4c1fd75b..1bd4dc0fe 100644 --- a/python/datashaper/datashaper/verbs/onehot.py +++ b/python/datashaper/datashaper/verbs/onehot.py @@ -4,18 +4,25 @@ # """Onehot verb implementation.""" -from typing import Any - import numpy as np import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb + +from datashaper import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="onehot", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="prefix"), + ConfigPort(name="preserveSource"), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) @@ -24,7 +31,6 @@ def onehot( column: str, prefix: str = "", preserveSource: bool = False, # noqa: N803 - **_kwargs: Any, ) -> pd.DataFrame: """Onehot verb implementation.""" table[column] = table[column].astype("category") diff --git a/python/datashaper/datashaper/verbs/orderby.py b/python/datashaper/datashaper/verbs/orderby.py index 07237e29e..de4d7421e 100644 --- a/python/datashaper/datashaper/verbs/orderby.py +++ b/python/datashaper/datashaper/verbs/orderby.py @@ -4,22 +4,27 @@ # """Orderby verb implementation.""" -from typing import Any - import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb + +from datashaper import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, copy_input_tables, wrap_verb_result from .types import OrderByInstruction, SortDirection @verb( name="orderby", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="orders", required=True), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def orderby(table: pd.DataFrame, orders: list[dict], **_kwargs: Any) -> pd.DataFrame: +def orderby(table: pd.DataFrame, orders: list[dict]) -> pd.DataFrame: """Orderby verb implementation.""" orders_instructions = [ OrderByInstruction( diff --git a/python/datashaper/datashaper/verbs/pivot.py b/python/datashaper/datashaper/verbs/pivot.py index ed332265b..b4cc64c58 100644 --- a/python/datashaper/datashaper/verbs/pivot.py +++ b/python/datashaper/datashaper/verbs/pivot.py @@ -4,26 +4,30 @@ # """Pivot verb implementation.""" -from typing import Any import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb + +from datashaper import DEFAULT_INPUT_NAME from .aggregate import aggregate_operation_mapping -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, wrap_verb_result from .types import FieldAggregateOperation @verb( name="pivot", - immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="key", required=True), + ConfigPort(name="value", required=True), + ConfigPort(name="operation", required=True), + ], adapters=[ - inputs(default_input_argname="table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def pivot( - table: pd.DataFrame, key: str, value: str, operation: str, **_kwargs: Any -) -> pd.DataFrame: +def pivot(table: pd.DataFrame, key: str, value: str, operation: str) -> pd.DataFrame: """Pivot verb implementation.""" aggregate_operation = FieldAggregateOperation(operation) return table.pivot_table( diff --git a/python/datashaper/datashaper/verbs/print.py b/python/datashaper/datashaper/verbs/print.py index ed05b4103..35edf54df 100644 --- a/python/datashaper/datashaper/verbs/print.py +++ b/python/datashaper/datashaper/verbs/print.py @@ -4,25 +4,28 @@ # """Print verb implementation.""" -from typing import Any - import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb + +from datashaper import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, wrap_verb_result raw_print = print @verb( name="print", - immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="message", required=True), + ], adapters=[ - inputs(default_input_argname="table"), wrap_verb_result(mode=OutputMode.Table), ], ) def print( # noqa A001 - use ds verb name - table: pd.DataFrame, message: str, limit: int = 10, **_kwargs: Any + table: pd.DataFrame, message: str, limit: int = 10 ) -> pd.DataFrame: """Print verb implementation.""" # TODO(Chris): should we use a logger for these instead of prints? diff --git a/python/datashaper/datashaper/verbs/recode.py b/python/datashaper/datashaper/verbs/recode.py index ed90d9507..b4e39c789 100644 --- a/python/datashaper/datashaper/verbs/recode.py +++ b/python/datashaper/datashaper/verbs/recode.py @@ -7,8 +7,11 @@ from typing import Any, cast import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result class RecodeMap(dict): @@ -21,14 +24,18 @@ def __missing__(self, key: str): @verb( name="recode", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="mapping", required=True), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def recode( - table: pd.DataFrame, to: str, column: str, mapping: dict, **_kwargs: Any -) -> pd.DataFrame: +def recode(table: pd.DataFrame, to: str, column: str, mapping: dict) -> pd.DataFrame: """Recode verb implementation.""" mapping = RecodeMap(mapping) table[to] = table[column].map(cast(Any, mapping)) diff --git a/python/datashaper/datashaper/verbs/rename.py b/python/datashaper/datashaper/verbs/rename.py index 5ada8118d..a5d29841e 100644 --- a/python/datashaper/datashaper/verbs/rename.py +++ b/python/datashaper/datashaper/verbs/rename.py @@ -4,22 +4,25 @@ # """Rename verb implementation.""" -from typing import Any - import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb + +from datashaper import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="rename", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="columns", required=True), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def rename( - table: pd.DataFrame, columns: dict[str, str], **_kwargs: Any -) -> pd.DataFrame: +def rename(table: pd.DataFrame, columns: dict[str, str]) -> pd.DataFrame: """Rename verb implementation.""" return table.rename(columns=columns) diff --git a/python/datashaper/datashaper/verbs/rollup.py b/python/datashaper/datashaper/verbs/rollup.py index e26e2edbf..9ca8b3dae 100644 --- a/python/datashaper/datashaper/verbs/rollup.py +++ b/python/datashaper/datashaper/verbs/rollup.py @@ -5,26 +5,30 @@ """Rollup verb implementation.""" from collections.abc import Iterable -from typing import Any import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb + +from datashaper import DEFAULT_INPUT_NAME from .aggregate import aggregate_operation_mapping -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, wrap_verb_result from .types import FieldAggregateOperation @verb( name="rollup", - immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="operation", required=True), + ], adapters=[ - inputs(default_input_argname="table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def rollup( - table: pd.DataFrame, column: str, to: str, operation: str, **_kwargs: Any -) -> pd.DataFrame: +def rollup(table: pd.DataFrame, column: str, to: str, operation: str) -> pd.DataFrame: """Rollup verb implementation.""" aggregate_operation = FieldAggregateOperation(operation) diff --git a/python/datashaper/datashaper/verbs/sample.py b/python/datashaper/datashaper/verbs/sample.py index 48f9facde..badaac700 100644 --- a/python/datashaper/datashaper/verbs/sample.py +++ b/python/datashaper/datashaper/verbs/sample.py @@ -7,15 +7,23 @@ from typing import Any, cast import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, wrap_verb_result @verb( name="sample", - immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="size"), + ConfigPort(name="proportion"), + ConfigPort(name="seed"), + ConfigPort(name="emitRemainder"), + ], adapters=[ - inputs(default_input_argname="table"), wrap_verb_result( mode=OutputMode.Tuple, output_names=["remainder"], diff --git a/python/datashaper/datashaper/verbs/select.py b/python/datashaper/datashaper/verbs/select.py index fe032a170..126b57537 100644 --- a/python/datashaper/datashaper/verbs/select.py +++ b/python/datashaper/datashaper/verbs/select.py @@ -4,21 +4,26 @@ # """Select verb implementation.""" -from typing import Any, cast +from typing import cast import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, wrap_verb_result @verb( name="select", - immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="columns", required=True), + ], adapters=[ - inputs(default_input_argname="table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def select(table: pd.DataFrame, columns: list[str], **_kwargs: Any) -> pd.DataFrame: +def select(table: pd.DataFrame, columns: list[str]) -> pd.DataFrame: """Select verb implementation.""" return cast(pd.DataFrame, table[columns]) diff --git a/python/datashaper/datashaper/verbs/snapshot.py b/python/datashaper/datashaper/verbs/snapshot.py index ccf2bf9aa..950d3e149 100644 --- a/python/datashaper/datashaper/verbs/snapshot.py +++ b/python/datashaper/datashaper/verbs/snapshot.py @@ -4,25 +4,28 @@ # """Snapshot verb implementation.""" -from typing import Any import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, wrap_verb_result from .types import FileFormat @verb( name="snapshot", - immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="name", required=True), + ConfigPort(name="file_type", required=True), + ], adapters=[ - inputs(default_input_argname="table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def snapshot( - table: pd.DataFrame, name: str, file_type: FileFormat, **_kwargs: Any -) -> pd.DataFrame: +def snapshot(table: pd.DataFrame, name: str, file_type: FileFormat) -> pd.DataFrame: """Snapshot verb implementation.""" file_name = "./" + name + "." + file_type diff --git a/python/datashaper/datashaper/verbs/spread.py b/python/datashaper/datashaper/verbs/spread.py index 7fefe36b1..34c7a39bd 100644 --- a/python/datashaper/datashaper/verbs/spread.py +++ b/python/datashaper/datashaper/verbs/spread.py @@ -7,14 +7,23 @@ from typing import Any, cast import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="spread", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="to"), + ConfigPort(name="preserveSource"), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) @@ -23,7 +32,6 @@ def spread( column: str, to: str | list[str] | None = None, preserveSource: bool = False, # noqa: N803 - **_kwargs: Any, ) -> pd.DataFrame: """Spread verb implementation.""" output = _spread(table, column, to) diff --git a/python/datashaper/datashaper/verbs/strings/lower.py b/python/datashaper/datashaper/verbs/strings/lower.py index 0177b8f13..4a41e82e5 100644 --- a/python/datashaper/datashaper/verbs/strings/lower.py +++ b/python/datashaper/datashaper/verbs/strings/lower.py @@ -5,27 +5,29 @@ """Lower verb implementation.""" import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb +from datashaper.constants import DEFAULT_INPUT_NAME from datashaper.verbs.decorators import ( OutputMode, - apply_decorators, - inputs, - verb, + copy_input_tables, wrap_verb_result, ) -def lower(table: pd.DataFrame, column: str, to: str, **_kwargs: dict) -> pd.DataFrame: - """Transform a column by applying a string-lowercase.""" - table[to] = table[column].str.lower() - return table - - -apply_decorators( - [ - verb(name="strings.lower"), - inputs(default_input_argname="table"), +@verb( + name="strings.lower", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="to", required=True), + ], + adapters=[ + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], - lower, ) +def lower(table: pd.DataFrame, column: str, to: str) -> pd.DataFrame: + """Transform a column by applying a string-lowercase.""" + table[to] = table[column].str.lower() + return table diff --git a/python/datashaper/datashaper/verbs/strings/replace.py b/python/datashaper/datashaper/verbs/strings/replace.py index 200693eb8..9ceb04608 100644 --- a/python/datashaper/datashaper/verbs/strings/replace.py +++ b/python/datashaper/datashaper/verbs/strings/replace.py @@ -7,16 +7,32 @@ import re import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb +from datashaper.constants import DEFAULT_INPUT_NAME from datashaper.verbs.decorators import ( OutputMode, - apply_decorators, - inputs, - verb, + copy_input_tables, wrap_verb_result, ) +@verb( + name="strings.replace", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="pattern", required=True), + ConfigPort(name="replacement", required=True), + ConfigPort(name="globalMatch"), + ConfigPort(name="caseInsensitive"), + ], + adapters=[ + copy_input_tables("table"), + wrap_verb_result(mode=OutputMode.Table), + ], +) def replace( table: pd.DataFrame, column: str, @@ -25,20 +41,9 @@ def replace( replacement: str, globalMatch: bool = False, # noqa: N803 caseInsensitive: bool = False, # noqa: N803 - **_kwargs: dict, ) -> pd.DataFrame: """Replace verb implementation.""" n = 0 if globalMatch else 1 pat = re.compile(pattern, flags=re.IGNORECASE if caseInsensitive else 0) table[to] = table[column].apply(lambda x: pat.sub(replacement, x, count=n)) return table - - -apply_decorators( - [ - verb(name="strings.replace"), - inputs(default_input_argname="table"), - wrap_verb_result(mode=OutputMode.Table), - ], - replace, -) diff --git a/python/datashaper/datashaper/verbs/strings/upper.py b/python/datashaper/datashaper/verbs/strings/upper.py index 4fff10895..af95d4f6e 100644 --- a/python/datashaper/datashaper/verbs/strings/upper.py +++ b/python/datashaper/datashaper/verbs/strings/upper.py @@ -5,27 +5,29 @@ """Upper verb implementation.""" import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb +from datashaper.constants import DEFAULT_INPUT_NAME from datashaper.verbs.decorators import ( OutputMode, - apply_decorators, - inputs, - verb, + copy_input_tables, wrap_verb_result, ) -def upper(table: pd.DataFrame, column: str, to: str, **_kwargs: dict) -> pd.DataFrame: - """Upper verb implementation.""" - table[to] = table[column].str.upper() - return table - - -apply_decorators( - [ - verb(name="strings.upper"), - inputs(default_input_argname="table"), +@verb( + name="strings.upper", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="to", required=True), + ], + adapters=[ + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], - upper, ) +def upper(table: pd.DataFrame, column: str, to: str) -> pd.DataFrame: + """Upper verb implementation.""" + table[to] = table[column].str.upper() + return table diff --git a/python/datashaper/datashaper/verbs/unfold.py b/python/datashaper/datashaper/verbs/unfold.py index c920355db..995d96a22 100644 --- a/python/datashaper/datashaper/verbs/unfold.py +++ b/python/datashaper/datashaper/verbs/unfold.py @@ -4,22 +4,30 @@ # """Unfold verb implementation.""" -from typing import Any, cast +from typing import cast import numpy as np import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="unfold", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="key", required=True), + ConfigPort(name="value", required=True), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def unfold(table: pd.DataFrame, key: str, value: str, **_kwargs: Any) -> pd.DataFrame: +def unfold(table: pd.DataFrame, key: str, value: str) -> pd.DataFrame: """Unfold verb implementation.""" columns = len(table[key].unique()) diff --git a/python/datashaper/datashaper/verbs/ungroup.py b/python/datashaper/datashaper/verbs/ungroup.py index eafa750d7..82d80ff89 100644 --- a/python/datashaper/datashaper/verbs/ungroup.py +++ b/python/datashaper/datashaper/verbs/ungroup.py @@ -4,21 +4,23 @@ # """Ungroup verb implementation.""" -from typing import Any - import pandas as pd +from reactivedataflow import InputPort, verb + +from datashaper import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, wrap_verb_result @verb( name="ungroup", - immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ], adapters=[ - inputs(default_input_argname="table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def ungroup(table: pd.DataFrame, **_kwargs: Any) -> pd.DataFrame: +def ungroup(table: pd.DataFrame) -> pd.DataFrame: """Ungroup verb implementation.""" return table.obj diff --git a/python/datashaper/datashaper/verbs/unhot.py b/python/datashaper/datashaper/verbs/unhot.py index 391813b24..b4b7aea50 100644 --- a/python/datashaper/datashaper/verbs/unhot.py +++ b/python/datashaper/datashaper/verbs/unhot.py @@ -3,14 +3,24 @@ from typing import Any, cast import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result @verb( name="unhot", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="columns", required=True), + ConfigPort(name="preserveSource"), + ConfigPort(name="prefix"), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) diff --git a/python/datashaper/datashaper/verbs/union.py b/python/datashaper/datashaper/verbs/union.py index d28158747..3c9df2ae5 100644 --- a/python/datashaper/datashaper/verbs/union.py +++ b/python/datashaper/datashaper/verbs/union.py @@ -3,24 +3,24 @@ # Licensed under the MIT license. See LICENSE file in the project. # """Union verb implementation.""" - -from typing import Any - import pandas as pd +from reactivedataflow import ArrayInputPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, wrap_verb_result @verb( name="union", - immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ArrayInputPort(name="others", parameter="others", required=True), + ], adapters=[ - inputs(default_input_argname="table", variadic_input_argname="others"), wrap_verb_result(mode=OutputMode.Table), ], ) -def union( - table: pd.DataFrame, others: list[pd.DataFrame], **_kwargs: Any -) -> pd.DataFrame: +def union(table: pd.DataFrame, others: list[pd.DataFrame]) -> pd.DataFrame: """Union verb implementation.""" return pd.concat([table, *others], ignore_index=True).drop_duplicates() diff --git a/python/datashaper/datashaper/verbs/unorder.py b/python/datashaper/datashaper/verbs/unorder.py index 437ad12cd..e288ea68e 100644 --- a/python/datashaper/datashaper/verbs/unorder.py +++ b/python/datashaper/datashaper/verbs/unorder.py @@ -4,21 +4,23 @@ # """Unorder verb implementation.""" -from typing import Any - import pandas as pd +from reactivedataflow import InputPort, verb + +from datashaper import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, wrap_verb_result @verb( name="unorder", - immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ], adapters=[ - inputs(default_input_argname="table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def unorder(table: pd.DataFrame, **_kwargs: Any) -> pd.DataFrame: +def unorder(table: pd.DataFrame) -> pd.DataFrame: """Unorder verb implementation.""" return table.sort_index() diff --git a/python/datashaper/datashaper/verbs/unroll.py b/python/datashaper/datashaper/verbs/unroll.py index 388af7575..df2d3b28a 100644 --- a/python/datashaper/datashaper/verbs/unroll.py +++ b/python/datashaper/datashaper/verbs/unroll.py @@ -4,21 +4,24 @@ # """Unroll verb implementation.""" -from typing import Any - import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb + +from datashaper import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, wrap_verb_result @verb( name="unroll", - immutable_input=True, + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="column", required=True), + ], adapters=[ - inputs(default_input_argname="table"), wrap_verb_result(mode=OutputMode.Table), ], ) -def unroll(table: pd.DataFrame, column: str, **_kwargs: Any) -> pd.DataFrame: +def unroll(table: pd.DataFrame, column: str) -> pd.DataFrame: """Unroll a column.""" return table.explode(column).reset_index(drop=True) diff --git a/python/datashaper/datashaper/verbs/window.py b/python/datashaper/datashaper/verbs/window.py index 5dab18593..e046dc1a4 100644 --- a/python/datashaper/datashaper/verbs/window.py +++ b/python/datashaper/datashaper/verbs/window.py @@ -4,14 +4,16 @@ # """Window verb implementation.""" -from typing import Any from uuid import uuid4 import numpy as np import pandas as pd from pandas.core.groupby import DataFrameGroupBy +from reactivedataflow import ConfigPort, InputPort, verb -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from datashaper import DEFAULT_INPUT_NAME + +from .decorators import OutputMode, copy_input_tables, wrap_verb_result from .types import WindowFunction @@ -59,8 +61,14 @@ def _get_window_indexer( @verb( name="window", + ports=[ + InputPort(name=DEFAULT_INPUT_NAME, parameter="table", required=True), + ConfigPort(name="column", required=True), + ConfigPort(name="to", required=True), + ConfigPort(name="operation", required=True), + ], adapters=[ - inputs(default_input_argname="table"), + copy_input_tables("table"), wrap_verb_result(mode=OutputMode.Table), ], ) @@ -69,7 +77,6 @@ def window( column: str, to: str, operation: str, - **_kwargs: Any, ) -> pd.DataFrame | DataFrameGroupBy: """Apply a window function to a column in a table.""" window_operation = WindowFunction(operation) diff --git a/python/datashaper/datashaper/verbs/workflow.py b/python/datashaper/datashaper/verbs/workflow.py index 71efa4558..bd50964a2 100644 --- a/python/datashaper/datashaper/verbs/workflow.py +++ b/python/datashaper/datashaper/verbs/workflow.py @@ -3,17 +3,22 @@ from typing import Any import pandas as pd +from reactivedataflow import ConfigPort, InputPort, verb from datashaper.constants import DEFAULT_INPUT_NAME -from .decorators import OutputMode, inputs, verb, wrap_verb_result +from .decorators import OutputMode, wrap_verb_result from .types import Table @verb( name="workflow", + ports=[ + ConfigPort(name="workflow", required=True), + ConfigPort(name="workflow_instance", required=True), + ], + # TODO: add support for multiple input tables adapters=[ - inputs(default_input_argname="table", input_dict_argname="tables"), wrap_verb_result(mode=OutputMode.Table), ], ) diff --git a/python/datashaper/datashaper/workflow/workflow.py b/python/datashaper/datashaper/workflow/workflow.py index 53821665f..602c4776e 100644 --- a/python/datashaper/datashaper/workflow/workflow.py +++ b/python/datashaper/datashaper/workflow/workflow.py @@ -29,7 +29,7 @@ ) from datashaper.tables import InMemoryTableStore, TableStore from datashaper.utils.progress import Progress -from datashaper.verbs import Table, VerbDetails, VerbInput, VerbManager, VerbResult +from datashaper.verbs import Table, VerbDetails, VerbInput, VerbResult from datashaper.verbs.types import TableContainer from .callbacks import ( diff --git a/python/datashaper/pyproject.toml b/python/datashaper/pyproject.toml index 72ef96b8f..e555f81fe 100644 --- a/python/datashaper/pyproject.toml +++ b/python/datashaper/pyproject.toml @@ -16,8 +16,8 @@ jsonschema = "^4.21.1" pyarrow = "^15.0.0" diskcache = "^5.6.3" dacite = "^1.8.1" - reactivedataflow = "^0.1.0" + [tool.poetry.group.dev.dependencies] codespell = "^2.2.6" poethepoet = "^0.24.4"