From 4a0d561d8f76618c62366e3c40ac3aeb5c32b099 Mon Sep 17 00:00:00 2001 From: HowToSD Date: Mon, 24 Feb 2025 15:52:50 -0800 Subject: [PATCH] Added Py Kv Float/Int/String nodes. Added Pandas Create From Dict, Pandas Create From Multiple Dict, Pandas Create Series From Dict nodes. --- __init__.py | 18 ++++ dev/scripts/run_tests.sh | 9 ++ docs/reference/node_reference.md | 9 ++ docs/reference/pandas_create_from_dict.md | 17 ++++ .../pandas_create_from_multiple_dict.md | 32 +++++++ .../pandas_create_series_from_dict.md | 17 ++++ docs/reference/py_kv_float_create.md | 18 ++++ docs/reference/py_kv_int_create.md | 18 ++++ docs/reference/py_kv_string_create.md | 18 ++++ docs/reference/sns_histogram.md | 1 + modules/cda/py_kv_float_create.py | 42 +++++++++ modules/cda/py_kv_int_create.py | 42 +++++++++ modules/cda/py_kv_string_create.py | 41 ++++++++ modules/cda/utils.py | 30 ++++++ .../pandas_wrapper/pandas_create_from_dict.py | 52 ++++++++++ .../pandas_create_from_multiple_dict.py | 94 +++++++++++++++++++ .../pandas_create_series_from_dict.py | 60 ++++++++++++ modules/pandas_wrapper/pandas_load_csv.py | 4 + .../pandas_load_csv_with_encoding.py | 4 + .../pandas_load_csv_with_index.py | 4 + modules/pandas_wrapper/pandas_load_html.py | 4 + modules/pandas_wrapper/pandas_load_json.py | 7 ++ pyproject.toml | 2 +- tests/__init__.py | 0 tests/cda/__init__.py | 0 tests/cda/py_kev_float_create_test.py | 27 ++++++ tests/cda/py_kev_int_create_test.py | 28 ++++++ tests/cda/py_kev_string_create_test.py | 27 ++++++ tests/cda/utils_test.py | 40 ++++++++ tests/pandas_wrapper/__init__.py | 0 .../pandas_create_from_dict_test.py | 46 +++++++++ .../pandas_create_from_multiple_dict_test.py | 78 +++++++++++++++ .../pandas_create_series_from_dict_test.py | 76 +++++++++++++++ .../pandas_iloc_rows_slice_dataframe_test.py | 2 +- tests/pandas_wrapper/pandas_melt_test.py | 2 +- tests/pandas_wrapper/pandas_pivot_test.py | 2 +- .../pandas_wrapper/pandas_to_datetime_test.py | 2 +- .../pandas_wrapper/pandas_to_strftime_test.py | 2 +- ...utils_column_labels_string_to_list_test.py | 2 +- ...ma_separated_labels_string_to_list_test.py | 2 +- .../utils_flatten_list_tuple_unique_test.py | 2 +- tests/pandas_wrapper/utils_index_json_test.py | 2 +- .../pandas_wrapper/utils_series_json_test.py | 3 +- 43 files changed, 874 insertions(+), 12 deletions(-) create mode 100755 dev/scripts/run_tests.sh create mode 100644 docs/reference/pandas_create_from_dict.md create mode 100644 docs/reference/pandas_create_from_multiple_dict.md create mode 100644 docs/reference/pandas_create_series_from_dict.md create mode 100644 docs/reference/py_kv_float_create.md create mode 100644 docs/reference/py_kv_int_create.md create mode 100644 docs/reference/py_kv_string_create.md create mode 100644 modules/cda/py_kv_float_create.py create mode 100644 modules/cda/py_kv_int_create.py create mode 100644 modules/cda/py_kv_string_create.py create mode 100644 modules/cda/utils.py create mode 100644 modules/pandas_wrapper/pandas_create_from_dict.py create mode 100644 modules/pandas_wrapper/pandas_create_from_multiple_dict.py create mode 100644 modules/pandas_wrapper/pandas_create_series_from_dict.py create mode 100644 tests/__init__.py create mode 100644 tests/cda/__init__.py create mode 100644 tests/cda/py_kev_float_create_test.py create mode 100644 tests/cda/py_kev_int_create_test.py create mode 100644 tests/cda/py_kev_string_create_test.py create mode 100644 tests/cda/utils_test.py create mode 100644 tests/pandas_wrapper/__init__.py create mode 100644 tests/pandas_wrapper/pandas_create_from_dict_test.py create mode 100644 tests/pandas_wrapper/pandas_create_from_multiple_dict_test.py create mode 100644 tests/pandas_wrapper/pandas_create_series_from_dict_test.py diff --git a/__init__.py b/__init__.py index acea2cf..37cddc6 100644 --- a/__init__.py +++ b/__init__.py @@ -7,6 +7,9 @@ from .modules.cda.cda_show_float import CDAShowFloat from .modules.cda.cda_show_int import CDAShowInt from .modules.cda.cda_string_create import CDAStringCreate from .modules.cda.cda_text_create import CDATextCreate +from .modules.cda.py_kv_float_create import PyKvFloatCreate +from .modules.cda.py_kv_int_create import PyKvIntCreate +from .modules.cda.py_kv_string_create import PyKvStringCreate from .modules.matplotlib.mpl_bar import MPLBar from .modules.matplotlib.mpl_line import MPLLine from .modules.matplotlib.mpl_scatter import MPLScatter @@ -23,6 +26,9 @@ from .modules.pandas_wrapper.pandas_cos import PandasCos from .modules.pandas_wrapper.pandas_count import PandasCount from .modules.pandas_wrapper.pandas_cov import PandasCov from .modules.pandas_wrapper.pandas_create import PandasCreate +from .modules.pandas_wrapper.pandas_create_from_dict import PandasCreateFromDict +from .modules.pandas_wrapper.pandas_create_from_multiple_dict import PandasCreateFromMultipleDict +from .modules.pandas_wrapper.pandas_create_series_from_dict import PandasCreateSeriesFromDict from .modules.pandas_wrapper.pandas_create_with_index import PandasCreateWithIndex from .modules.pandas_wrapper.pandas_cummax import PandasCummax from .modules.pandas_wrapper.pandas_cummin import PandasCummin @@ -141,6 +147,9 @@ NODE_CLASS_MAPPINGS: Dict[str, Type[T]] = { "PandasCount": PandasCount, "PandasCov": PandasCov, "PandasCreate": PandasCreate, + "PandasCreateFromDict": PandasCreateFromDict, + "PandasCreateFromMultipleDict": PandasCreateFromMultipleDict, + "PandasCreateSeriesFromDict": PandasCreateSeriesFromDict, "PandasCreateWithIndex": PandasCreateWithIndex, "PandasCummax": PandasCummax, "PandasCummin": PandasCummin, @@ -223,6 +232,9 @@ NODE_CLASS_MAPPINGS: Dict[str, Type[T]] = { "PandasVerticalConcat": PandasVerticalConcat, "PandasVerticalSplit": PandasVerticalSplit, "PandasXs": PandasXs, + "PyKvFloatCreate": PyKvFloatCreate, + "PyKvIntCreate": PyKvIntCreate, + "PyKvStringCreate": PyKvStringCreate, "SNSBar": SNSBar, "SNSHistogram": SNSHistogram, "SNSLine": SNSLine, @@ -259,6 +271,9 @@ NODE_DISPLAY_NAME_MAPPINGS: Dict[str, str] = { "PandasCount": "Pandas Count", "PandasCov": "Pandas Cov", "PandasCreate": "Pandas Create", + "PandasCreateFromDict": "Pandas Create From Dict", + "PandasCreateFromMultipleDict": "Pandas Create From Multiple Dict", + "PandasCreateSeriesFromDict": "Pandas Create Series From Dict", "PandasCreateWithIndex": "Pandas Create With Index", "PandasCummax": "Pandas Cummax", "PandasCummin": "Pandas Cummin", @@ -341,6 +356,9 @@ NODE_DISPLAY_NAME_MAPPINGS: Dict[str, str] = { "PandasVerticalConcat": "Pandas Vertical Concat", "PandasVerticalSplit": "Pandas Vertical Split", "PandasXs": "Pandas Xs", + "PyKvFloatCreate": "Py Kv Float Create", + "PyKvIntCreate": "Py Kv Int Create", + "PyKvStringCreate": "Py Kv String Create", "SNSBar": "SNS Bar Chart", "SNSHistogram": "SNS Histogram", "SNSLine": "SNS Line Plot", diff --git a/dev/scripts/run_tests.sh b/dev/scripts/run_tests.sh new file mode 100755 index 0000000..1bc4915 --- /dev/null +++ b/dev/scripts/run_tests.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# Run this command on project root +# ``` +# dev/scripts/run_tests.sh +# ```` +export PYTHONPATH=modules:$PYTHONPATH +echo $PYTHONPATH +python -m unittest discover -s tests -p "*_test.py" -t . + diff --git a/docs/reference/node_reference.md b/docs/reference/node_reference.md index 4b4c78f..f838250 100644 --- a/docs/reference/node_reference.md +++ b/docs/reference/node_reference.md @@ -92,6 +92,9 @@ | [CDA String Create](cda_string_create.md) | Creates a Python String using a value entered in a single-line text field. | | [CDA Text Create](cda_text_create.md) | Creates a Python String using a value entered in a multi-line text field. | | [Pandas Create](pandas_create.md) | Creates a pandas DataFrame using values entered in the text field. | +| [Pandas Create From Dict](pandas_create_from_dict.md) | Creates a pandas DataFrame from a Python dictionary. | +| [Pandas Create From Multiple Dict](pandas_create_from_multiple_dict.md) | Creates a pandas DataFrame from multiple Python dictionaries. | +| [Pandas Create Series From Dict](pandas_create_series_from_dict.md) | Creates a Pandas Series from a Python dictionary. | | [Pandas Create With Index](pandas_create_with_index.md) | Creates a pandas DataFrame using values entered in the text field. Input data is assumed to have an index. | | [Pandas Load CSV](pandas_load_csv.md) | Loads CSV files into a pandas DataFrame. | | [Pandas Load CSV With Encoding](pandas_load_csv_with_encoding.md) | Loads CSV files into a pandas DataFrame. | @@ -118,6 +121,12 @@ | [SNS Histogram](sns_histogram.md) | Generates a histogram from a Pandas DataFrame using Seaborn. | | [SNS Line Plot](sns_line.md) | Generates a line plot from a pandas DataFrame using Seaborn. | | [SNS Scatter Plot](sns_scatter.md) | Generates a scatter plot from a pandas DataFrame using Seaborn. | +## Python wrapper +| Node | Description | +| --- | --- | +| [Py Kv Float Create](py_kv_float_create.md) | Creates a Python dictionary with a string key and a float value. | +| [Py Kv Int Create](py_kv_int_create.md) | Creates a Python dictionary with an string key and an integer value. | +| [Py Kv String Create](py_kv_string_create.md) | Creates a Python dictionary with a string key and a string value. | ## Summary statistics | Node | Description | | --- | --- | diff --git a/docs/reference/pandas_create_from_dict.md b/docs/reference/pandas_create_from_dict.md new file mode 100644 index 0000000..d53872d --- /dev/null +++ b/docs/reference/pandas_create_from_dict.md @@ -0,0 +1,17 @@ +# Pandas Create From Dict +Creates a pandas DataFrame from a Python dictionary. + +## Input +| Name | Data type | +|---|---| +| data | Pydict | + +## Output +| Data type | +|---| +| DataFrame | + +
+Category: IO + +ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved. diff --git a/docs/reference/pandas_create_from_multiple_dict.md b/docs/reference/pandas_create_from_multiple_dict.md new file mode 100644 index 0000000..7f4bf69 --- /dev/null +++ b/docs/reference/pandas_create_from_multiple_dict.md @@ -0,0 +1,32 @@ +# Pandas Create From Multiple Dict +Creates a pandas DataFrame from multiple Python dictionaries. + +Use this node to create a DataFrame from below nodes: +* Py Kv Float Create +* Py Kv Int Create +* Py Kv String Create +Each of above can be used to set a column name and the value for the column. + +## Input +| Name | Data type | +|---|---| +| dict1 | Pydict | +| dict2 | Pydict | +| dict3 | Pydict | +| dict4 | Pydict | +| dict5 | Pydict | +| dict6 | Pydict | +| dict7 | Pydict | +| dict8 | Pydict | +| dict9 | Pydict | +| dict10 | Pydict | + +## Output +| Data type | +|---| +| DataFrame | + +
+Category: IO + +ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved. diff --git a/docs/reference/pandas_create_series_from_dict.md b/docs/reference/pandas_create_series_from_dict.md new file mode 100644 index 0000000..dba478e --- /dev/null +++ b/docs/reference/pandas_create_series_from_dict.md @@ -0,0 +1,17 @@ +# Pandas Create Series From Dict +Creates a Pandas Series from a Python dictionary. + +## Input +| Name | Data type | +|---|---| +| data | Pydict | + +## Output +| Data type | +|---| +| Series | + +
+Category: IO + +ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved. diff --git a/docs/reference/py_kv_float_create.md b/docs/reference/py_kv_float_create.md new file mode 100644 index 0000000..1a679d6 --- /dev/null +++ b/docs/reference/py_kv_float_create.md @@ -0,0 +1,18 @@ +# Py Kv Float Create +Creates a Python dictionary with a string key and a float value. + +## Input +| Name | Data type | +|---|---| +| key | String | +| value | Float | + +## Output +| Data type | +|---| +| Pydict | + +
+Category: Python wrapper + +ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved. diff --git a/docs/reference/py_kv_int_create.md b/docs/reference/py_kv_int_create.md new file mode 100644 index 0000000..1099bfd --- /dev/null +++ b/docs/reference/py_kv_int_create.md @@ -0,0 +1,18 @@ +# Py Kv Int Create +Creates a Python dictionary with an string key and an integer value. + +## Input +| Name | Data type | +|---|---| +| key | String | +| value | Int | + +## Output +| Data type | +|---| +| Pydict | + +
+Category: Python wrapper + +ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved. diff --git a/docs/reference/py_kv_string_create.md b/docs/reference/py_kv_string_create.md new file mode 100644 index 0000000..6c6f641 --- /dev/null +++ b/docs/reference/py_kv_string_create.md @@ -0,0 +1,18 @@ +# Py Kv String Create +Creates a Python dictionary with a string key and a string value. + +## Input +| Name | Data type | +|---|---| +| key | String | +| value | String | + +## Output +| Data type | +|---| +| Pydict | + +
+Category: Python wrapper + +ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved. diff --git a/docs/reference/sns_histogram.md b/docs/reference/sns_histogram.md index fa0ad71..a9e158e 100644 --- a/docs/reference/sns_histogram.md +++ b/docs/reference/sns_histogram.md @@ -1,6 +1,7 @@ # SNS Histogram Generates a histogram from a Pandas DataFrame using Seaborn. +Currently, plotting multiple series of data is not supported. For style and palette parameters, refer to [SNS Line Plot documentation](sns_line.md). ## Output diff --git a/modules/cda/py_kv_float_create.py b/modules/cda/py_kv_float_create.py new file mode 100644 index 0000000..3fa1fc7 --- /dev/null +++ b/modules/cda/py_kv_float_create.py @@ -0,0 +1,42 @@ +from typing import Any, Dict + + +class PyKvFloatCreate: + """ + Creates a Python dictionary with a string key and a float value. + + category: Python wrapper + """ + + @classmethod + def INPUT_TYPES(cls) -> Dict[str, Any]: + """ + Defines the input types for the `create` function. + + Returns: + Dict[str, Any]: A dictionary specifying required input types. + """ + return { + "required": { + "key": ("STRING", {"multiline": False}), + "value": ("FLOAT", {"default": 0, "min": -2**63, "max": 2**63, "step": 0.00000001}) + } + } + + RETURN_TYPES: tuple = ("PYDICT",) + FUNCTION: str = "f" + CATEGORY: str = "Data Analysis" + + def f(self, key: str, value: float) -> tuple: + """ + Creates a Python dictionary with a string key and a float value. + + Args: + key (str): String key for the dictionary. + value (float): Float value for the dictionary. + + Returns: + tuple: A tuple containing the dictionary. + """ + return ({key:value},) + \ No newline at end of file diff --git a/modules/cda/py_kv_int_create.py b/modules/cda/py_kv_int_create.py new file mode 100644 index 0000000..7dfcbfd --- /dev/null +++ b/modules/cda/py_kv_int_create.py @@ -0,0 +1,42 @@ +from typing import Any, Dict + + +class PyKvIntCreate: + """ + Creates a Python dictionary with an string key and an integer value. + + category: Python wrapper + """ + + @classmethod + def INPUT_TYPES(cls) -> Dict[str, Any]: + """ + Defines the input types for the `create` function. + + Returns: + Dict[str, Any]: A dictionary specifying required input types. + """ + return { + "required": { + "key": ("STRING", {"multiline": False}), + "value": ("INT", {"default": 0, "min": -2**31, "max": 2**31}) + } + } + + RETURN_TYPES: tuple = ("PYDICT",) + FUNCTION: str = "f" + CATEGORY: str = "Data Analysis" + + def f(self, key: str, value: int) -> tuple: + """ + Creates a Python dictionary with an string key and an integer value. + + Args: + key (str): String key for the dictionary. + value (int): Integer value for the dictionary. + + Returns: + tuple: A tuple containing the dictionary. + """ + return ({key:value},) + \ No newline at end of file diff --git a/modules/cda/py_kv_string_create.py b/modules/cda/py_kv_string_create.py new file mode 100644 index 0000000..0e939a3 --- /dev/null +++ b/modules/cda/py_kv_string_create.py @@ -0,0 +1,41 @@ +from typing import Any, Dict + + +class PyKvStringCreate: + """ + Creates a Python dictionary with a string key and a string value. + + category: Python wrapper + """ + + @classmethod + def INPUT_TYPES(cls) -> Dict[str, Any]: + """ + Defines the input types for the `create` function. + + Returns: + Dict[str, Any]: A dictionary specifying required input types. + """ + return { + "required": { + "key": ("STRING", {"multiline": False}), + "value": ("STRING", {"multiline": True}) + } + } + + RETURN_TYPES: tuple = ("PYDICT",) + FUNCTION: str = "f" + CATEGORY: str = "Data Analysis" + + def f(self, key: str, value: float) -> tuple: + """ + Creates a Python dictionary with a string key and a string value. + + Args: + key (str): String key for the dictionary. + value (str): String value for the dictionary. + + Returns: + tuple: A tuple containing the dictionary. + """ + return ({key:value},) diff --git a/modules/cda/utils.py b/modules/cda/utils.py new file mode 100644 index 0000000..9979c3b --- /dev/null +++ b/modules/cda/utils.py @@ -0,0 +1,30 @@ +from typing import Dict, Any + +def python_dict_first_value_len(d: Dict[Any, Any]) -> int: + r""" + Computes the length of the first value in a dictionary. + + - If the first value is a `list`, returns its length. + - If the first value is a `dict`, returns the number of keys in the dictionary. + - Otherwise, returns `1` for scalar values. + + Args: + d (Dict[Any, Any]): A dictionary where the first value's length will be computed. + + Returns: + int: The computed length based on the type of the first value. + + Raises: + ValueError: If `d` is `None` or empty. + """ + if not d: + raise ValueError("Input dictionary is None or empty.") + + first_value = next(iter(d.values())) # Get the first value + + if isinstance(first_value, list): + return len(first_value) + elif isinstance(first_value, dict): + return len(first_value.keys()) # Return the number of keys in the dictionary + else: + return 1 # Scalar case (int, float, str, etc.) diff --git a/modules/pandas_wrapper/pandas_create_from_dict.py b/modules/pandas_wrapper/pandas_create_from_dict.py new file mode 100644 index 0000000..a385b18 --- /dev/null +++ b/modules/pandas_wrapper/pandas_create_from_dict.py @@ -0,0 +1,52 @@ +import os +import sys +from typing import Any, Dict +import pandas as pd + +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) +MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") +sys.path.append(MODULE_ROOT) +from cda.utils import python_dict_first_value_len + +class PandasCreateFromDict: + """ + Creates a pandas DataFrame from a Python dictionary. + + category: IO + """ + + @classmethod + def INPUT_TYPES(cls) -> Dict[str, Any]: + """ + Defines the input types for the `create` function. + + Returns: + Dict[str, Any]: A dictionary specifying required input types. + """ + return { + "required": { + "data": ("PYDICT", {}), + } + } + + RETURN_TYPES: tuple = ("DATAFRAME",) + FUNCTION: str = "f" + CATEGORY: str = "Data Analysis" + + def f(self, data: Dict) -> tuple: + """ + Creates a pandas DataFrame from a Python dictionary. + + Args: + data (Dict): A Python dictionary. + + Returns: + tuple: A tuple containing a the DataFrame. + """ + if not data: + df = pd.DataFrame() # Return an empty DataFrame if no data is provided. + else: + value_length = python_dict_first_value_len(data) + df = pd.DataFrame(data, index=list(range(value_length))) + + return (df,) diff --git a/modules/pandas_wrapper/pandas_create_from_multiple_dict.py b/modules/pandas_wrapper/pandas_create_from_multiple_dict.py new file mode 100644 index 0000000..91e90b8 --- /dev/null +++ b/modules/pandas_wrapper/pandas_create_from_multiple_dict.py @@ -0,0 +1,94 @@ +import os +import sys +from typing import Any, Dict +import pandas as pd + +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) +MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") +sys.path.append(MODULE_ROOT) +from cda.utils import python_dict_first_value_len + +class PandasCreateFromMultipleDict: + """ + Creates a pandas DataFrame from multiple Python dictionaries. + + Use this node to create a DataFrame from below nodes: + * Py Kv Float Create + * Py Kv Int Create + * Py Kv String Create + Each of above can be used to set a column name and the value for the column. + + category: IO + """ + + @classmethod + def INPUT_TYPES(cls) -> Dict[str, Any]: + """ + Defines the input types for the `create` function. + + Returns: + Dict[str, Any]: A dictionary specifying required input types. + """ + return { + "required": { + "dict1": ("PYDICT", {}), + "dict2": ("PYDICT", {}), + }, + "optional":{ + "dict3": ("PYDICT", {}), + "dict4": ("PYDICT", {}), + "dict5": ("PYDICT", {}), + "dict6": ("PYDICT", {}), + "dict7": ("PYDICT", {}), + "dict8": ("PYDICT", {}), + "dict9": ("PYDICT", {}), + "dict10": ("PYDICT", {}) + } + } + + RETURN_TYPES: tuple = ("DATAFRAME",) + FUNCTION: str = "f" + CATEGORY: str = "Data Analysis" + + def f(self, + dict1: Dict, + dict2: Dict, + dict3: Dict=None, + dict4: Dict=None, + dict5: Dict=None, + dict6: Dict=None, + dict7: Dict=None, + dict8: Dict=None, + dict9: Dict=None, + dict10: Dict=None + ) -> tuple: + """ + Creates a pandas DataFrame from a Python dictionary. + + Args: + dict1, 2, ... ,10 (Dict): A Python dictionary. + + Returns: + tuple: A tuple containing a the DataFrame. + """ + dict_list = [d for d in (dict1, dict2, dict3, dict4, dict5, dict6, dict7, dict8, dict9, dict10) if d] + + if dict_list[0] is None or dict_list[1] is None: + raise ValueError("Either or both of the first two dictionaries are None.") + + if not dict_list[0] or not dict_list[1]: + # Return an empty DataFrame if an empty dict is provided for the first dictionary + # or the second dictionary. + df = pd.DataFrame() + else: + expected_length = python_dict_first_value_len(dict_list[0]) + + for d in dict_list[1:]: + if expected_length != python_dict_first_value_len(d): + raise ValueError("Length of the value elements are not the same.") + + merged_dict = {} + for d in dict_list: + merged_dict.update(d) + df = pd.DataFrame(merged_dict, index=list(range(expected_length))) + return (df,) diff --git a/modules/pandas_wrapper/pandas_create_series_from_dict.py b/modules/pandas_wrapper/pandas_create_series_from_dict.py new file mode 100644 index 0000000..b723a40 --- /dev/null +++ b/modules/pandas_wrapper/pandas_create_series_from_dict.py @@ -0,0 +1,60 @@ +import os +import sys +from typing import Dict, Any, Tuple +import pandas as pd + +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) +MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") +sys.path.append(MODULE_ROOT) +from cda.utils import python_dict_first_value_len + +class PandasCreateSeriesFromDict: + """ + Creates a Pandas Series from a Python dictionary. + + category: IO + """ + @classmethod + def INPUT_TYPES(cls) -> Dict[str, Any]: + """ + Defines the input types for the function. + + Returns: + Dict[str, Any]: A dictionary specifying required input types. + """ + return { + "required": { + "data": ("PYDICT", {}), + } + } + + RETURN_TYPES: tuple = ("PDSERIES",) + FUNCTION: str = "f" + CATEGORY: str = "Data Analysis" + + def f(self, data: Dict[Any, Any]) -> Tuple[pd.Series]: + """ + Creates a Pandas Series from a Python dictionary. + + Args: + data (Dict[Any, Any]): A dictionary with exactly one key-value pair. + + Returns: + Tuple[pd.Series]: A tuple containing a Pandas Series. + + Raises: + ValueError: If the dictionary does not have exactly one key-value pair, + or if the value is not a scalar. + """ + if not isinstance(data, dict): + raise ValueError("Input must be a dictionary.") + + if len(data) == 0: + return (pd.Series(),) + else: + for v in iter(data.values()): + if isinstance(v, (list, dict, set, tuple)): + raise ValueError("Value must be a scalar.") + + return (pd.Series(data),) + diff --git a/modules/pandas_wrapper/pandas_load_csv.py b/modules/pandas_wrapper/pandas_load_csv.py index 82a122c..17fbbf1 100644 --- a/modules/pandas_wrapper/pandas_load_csv.py +++ b/modules/pandas_wrapper/pandas_load_csv.py @@ -29,6 +29,10 @@ class PandasLoadCSV: FUNCTION: str = "load_csv" CATEGORY: str = "Data Analysis" + @classmethod + def IS_CHANGED(cls, **kw): + return float("NaN") + def load_csv(self, file_path: str) -> tuple: """ Loads a CSV file into a pandas DataFrame. diff --git a/modules/pandas_wrapper/pandas_load_csv_with_encoding.py b/modules/pandas_wrapper/pandas_load_csv_with_encoding.py index b577290..20b602a 100644 --- a/modules/pandas_wrapper/pandas_load_csv_with_encoding.py +++ b/modules/pandas_wrapper/pandas_load_csv_with_encoding.py @@ -30,6 +30,10 @@ class PandasLoadCSVWithEncoding: FUNCTION: str = "load_csv" CATEGORY: str = "Data Analysis" + @classmethod + def IS_CHANGED(cls, **kw): + return float("NaN") + def load_csv(self, file_path: str, encoding: str) -> tuple: """ Loads a CSV file into a pandas DataFrame. Allows specifying the file encoding to support formats other than UTF-8. diff --git a/modules/pandas_wrapper/pandas_load_csv_with_index.py b/modules/pandas_wrapper/pandas_load_csv_with_index.py index 8e2b10b..1d84785 100644 --- a/modules/pandas_wrapper/pandas_load_csv_with_index.py +++ b/modules/pandas_wrapper/pandas_load_csv_with_index.py @@ -31,6 +31,10 @@ class PandasLoadCSVWithIndex: FUNCTION: str = "load_csv" CATEGORY: str = "Data Analysis" + @classmethod + def IS_CHANGED(cls, **kw): + return float("NaN") + def load_csv(self, file_path: str, index_col: int=0) -> tuple: """ Loads a CSV file into a pandas DataFrame. diff --git a/modules/pandas_wrapper/pandas_load_html.py b/modules/pandas_wrapper/pandas_load_html.py index 33e0023..d69609c 100644 --- a/modules/pandas_wrapper/pandas_load_html.py +++ b/modules/pandas_wrapper/pandas_load_html.py @@ -43,6 +43,10 @@ class PandasLoadHTML: FUNCTION: str = "f" CATEGORY: str = "Data Analysis" + @classmethod + def IS_CHANGED(cls, **kw): + return float("NaN") + def f(self, file_path: str) -> tuple: """ Loads an HTML file into a pandas DataFrame. diff --git a/modules/pandas_wrapper/pandas_load_json.py b/modules/pandas_wrapper/pandas_load_json.py index a1f9c78..2655277 100644 --- a/modules/pandas_wrapper/pandas_load_json.py +++ b/modules/pandas_wrapper/pandas_load_json.py @@ -29,6 +29,13 @@ class PandasLoadJSON: FUNCTION: str = "load_json" CATEGORY: str = "Data Analysis" + # Mark this class to always execute. + # Refer to + # https://docs.comfy.org/custom-nodes/backend/server_overview + @classmethod + def IS_CHANGED(cls, **kw): + return float("NaN") + def load_json(self, file_path: str) -> tuple: """ Loads a JSON file into a pandas DataFrame. diff --git a/pyproject.toml b/pyproject.toml index a8eb900..4457378 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "data-analysis" description = "Data analysis custom modules for ComfyUI - Use Pandas & Matplotlib within ComfyUI" -version = "1.2.1" +version = "1.2.2" license = {file = "LICENSE"} [project.urls] diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/cda/__init__.py b/tests/cda/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/cda/py_kev_float_create_test.py b/tests/cda/py_kev_float_create_test.py new file mode 100644 index 0000000..a273f77 --- /dev/null +++ b/tests/cda/py_kev_float_create_test.py @@ -0,0 +1,27 @@ +import os +import sys +import unittest + + +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) +MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") +sys.path.append(MODULE_ROOT) +from cda.py_kv_float_create import PyKvFloatCreate + +class TestPyKvFloatCreat(unittest.TestCase): + def setUp(self): + """Set up test data.""" + self.node = PyKvFloatCreate() + self.data = [ + {"key": "a", "value": 1.2345678} + ] + + def test_create_key_value_pair(self): + """Test key-value pair creation.""" + retval = self.node.f(key=self.data[0]["key"], value=self.data[0]["value"])[0] + self.assertEqual({self.data[0]["key"]: self.data[0]["value"]}, retval) + + +if __name__ == "__main__": + unittest.main() + diff --git a/tests/cda/py_kev_int_create_test.py b/tests/cda/py_kev_int_create_test.py new file mode 100644 index 0000000..c0524f7 --- /dev/null +++ b/tests/cda/py_kev_int_create_test.py @@ -0,0 +1,28 @@ +import os +import sys +import unittest + + +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) +MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") +sys.path.append(MODULE_ROOT) + +from cda.py_kv_int_create import PyKvIntCreate + +class TestPyKvIntCreat(unittest.TestCase): + def setUp(self): + """Set up test data.""" + self.node = PyKvIntCreate() + self.data = [ + {"key": "a", "value": 12345678} + ] + + def test_create_key_value_pair(self): + """Test key-value pair creation.""" + retval = self.node.f(key=self.data[0]["key"], value=self.data[0]["value"])[0] + self.assertEqual({self.data[0]["key"]: self.data[0]["value"]}, retval) + + +if __name__ == "__main__": + unittest.main() + diff --git a/tests/cda/py_kev_string_create_test.py b/tests/cda/py_kev_string_create_test.py new file mode 100644 index 0000000..ee91b58 --- /dev/null +++ b/tests/cda/py_kev_string_create_test.py @@ -0,0 +1,27 @@ +import os +import sys +import unittest + + +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) +MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") +sys.path.append(MODULE_ROOT) +from cda.py_kv_string_create import PyKvStringCreate + +class TestPyKvStringCreat(unittest.TestCase): + def setUp(self): + """Set up test data.""" + self.node = PyKvStringCreate() + self.data = [ + {"key": "a", "value": "apple"} + ] + + def test_create_key_value_pair(self): + """Test key-value pair creation.""" + retval = self.node.f(key=self.data[0]["key"], value=self.data[0]["value"])[0] + self.assertEqual({self.data[0]["key"]: self.data[0]["value"]}, retval) + + +if __name__ == "__main__": + unittest.main() + diff --git a/tests/cda/utils_test.py b/tests/cda/utils_test.py new file mode 100644 index 0000000..55ce80b --- /dev/null +++ b/tests/cda/utils_test.py @@ -0,0 +1,40 @@ +import os +import sys +import unittest + +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) +MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") +sys.path.append(MODULE_ROOT) + +from cda.utils import python_dict_first_value_len + +class TestUtils(unittest.TestCase): + def test_python_dict_first_value_len(self): + """Test python_dict_first_value_len with various input cases.""" + + test_cases = [ + ({"a": [1, 2, 3]}, 3, "List case"), + ({"a": {"x": 1, "y": 2}}, 2, "Dict case"), + ({"a": 42}, 1, "Integer case"), + ({"a": 3.14}, 1, "Float case"), + ({"a": "hello"}, 1, "String case"), + ({"a": True}, 1, "Boolean case"), + ({"a": None}, 1, "None as value case"), + ({"a": [], "b": "extra"}, 0, "Empty list case"), + ({"a": {}}, 0, "Empty dict case"), + ] + + for data, expected, desc in test_cases: + with self.subTest(msg=desc, data=data): + self.assertEqual(python_dict_first_value_len(data), expected) + + # Test ValueError for None input + with self.assertRaises(ValueError, msg="None input case"): + python_dict_first_value_len(None) + + # Test ValueError for empty dictionary + with self.assertRaises(ValueError, msg="Empty dictionary case"): + python_dict_first_value_len({}) + +if __name__ == "__main__": + unittest.main() diff --git a/tests/pandas_wrapper/__init__.py b/tests/pandas_wrapper/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/pandas_wrapper/pandas_create_from_dict_test.py b/tests/pandas_wrapper/pandas_create_from_dict_test.py new file mode 100644 index 0000000..8b704c7 --- /dev/null +++ b/tests/pandas_wrapper/pandas_create_from_dict_test.py @@ -0,0 +1,46 @@ +import os +import sys +import unittest +import pandas as pd + +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) +MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") +sys.path.append(MODULE_ROOT) +from pandas_wrapper.pandas_create_from_dict import PandasCreateFromDict + +class TestPandasCreateFromDict(unittest.TestCase): + def setUp(self): + """Set up test data.""" + self.node = PandasCreateFromDict() + self.test_cases = [ + ({"a": 12345}, pd.DataFrame({"a": [12345]}, index=[0])), + ({"a": 12345.6}, pd.DataFrame({"a": [12345.6]}, index=[0])), + ({"a": "apple"}, pd.DataFrame({"a": ["apple"]}, index=[0])), + ({"a": [12345, 6789]}, pd.DataFrame({"a": [12345, 6789]}, index=[0, 1])), + ({"a": [12345.6, 7890.1]}, pd.DataFrame({"a": [12345.6, 7890.1]}, index=[0, 1])), + ({"a": ["apple", "banana"]}, pd.DataFrame({"a": ["apple", "banana"]}, index=[0, 1])), + ({"a": 123, "b": 456}, pd.DataFrame({"a": [123], "b": [456]}, index=[0])), + ({"a": 12.3, "b": 45.6}, pd.DataFrame({"a": [12.3], "b": [45.6]}, index=[0])), + ({"a": "foo", "b": "bar"}, pd.DataFrame({"a": ["foo"], "b": ["bar"]}, index=[0])), + ({"a": [1, 2], "b": [3, 4]}, pd.DataFrame({"a": [1, 2], "b": [3, 4]}, index=[0, 1])), + ({"a": [1.1, 2.2], "b": [3.3, 4.4]}, pd.DataFrame({"a": [1.1, 2.2], "b": [3.3, 4.4]}, index=[0, 1])), + ({"a": ["x", "y"], "b": ["z", "w"]}, pd.DataFrame({"a": ["x", "y"], "b": ["z", "w"]}, index=[0, 1])) + ] + + def test_create_dataframe(self): + """Test DataFrame creation from various dictionary inputs.""" + for data, expected_df in self.test_cases: + with self.subTest(data=data): + retval = self.node.f(data)[0] + + # Test if DataFrame structure matches + self.assertTrue(isinstance(retval, pd.DataFrame)) + + # Test if index matches + self.assertTrue(retval.index.equals(expected_df.index), f"Index mismatch for input: {data}") + + # Test if data matches + pd.testing.assert_frame_equal(retval, expected_df) + +if __name__ == "__main__": + unittest.main() diff --git a/tests/pandas_wrapper/pandas_create_from_multiple_dict_test.py b/tests/pandas_wrapper/pandas_create_from_multiple_dict_test.py new file mode 100644 index 0000000..5aa9eba --- /dev/null +++ b/tests/pandas_wrapper/pandas_create_from_multiple_dict_test.py @@ -0,0 +1,78 @@ +import os +import sys +import unittest +import pandas as pd + +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) +MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") +sys.path.append(MODULE_ROOT) + +from pandas_wrapper.pandas_create_from_multiple_dict import PandasCreateFromMultipleDict + +class TestPandasCreateFromMultipleDict(unittest.TestCase): + def setUp(self): + """Set up test data.""" + self.node = PandasCreateFromMultipleDict() + + # Valid test cases with at least two dictionaries + self.test_cases = [ + ({"a": [12345]}, {"b": [67890]}, pd.DataFrame({"a": [12345], "b": [67890]}, index=[0])), + ({"a": [12345.6]}, {"b": [7890.1]}, pd.DataFrame({"a": [12345.6], "b": [7890.1]}, index=[0])), + ({"a": ["apple"]}, {"b": ["banana"]}, pd.DataFrame({"a": ["apple"], "b": ["banana"]}, index=[0])), + ({"a": [12345, 6789]}, {"b": [1111, 2222]}, pd.DataFrame({"a": [12345, 6789], "b": [1111, 2222]}, index=[0, 1])), + ({"a": [123, 456]}, {"b": [789, 101]}, pd.DataFrame({"a": [123, 456], "b": [789, 101]}, index=[0, 1])), + ] + + # Case where all 10 dictionaries are passed + self.all_dicts_case = ( + {"a": [1, 2]}, {"b": [3, 4]}, {"c": [5, 6]}, {"d": [7, 8]}, {"e": [9, 10]}, + {"f": [11, 12]}, {"g": [13, 14]}, {"h": [15, 16]}, {"i": [17, 18]}, {"j": [19, 20]}, + pd.DataFrame({ + "a": [1, 2], "b": [3, 4], "c": [5, 6], "d": [7, 8], "e": [9, 10], + "f": [11, 12], "g": [13, 14], "h": [15, 16], "i": [17, 18], "j": [19, 20] + }, index=[0, 1]) + ) + + # Failure cases where first dictionary's value length differs from second's + self.length_mismatch_cases = [ + ({"a": [1, 2]}, {"b": [3]}, "Length of the value elements are not the same."), + ({"x": [10]}, {"y": [20, 30]}, "Length of the value elements are not the same."), + ] + + def test_create_dataframe(self): + """Test DataFrame creation from valid dictionary inputs.""" + for data1, data2, expected_df in self.test_cases: + with self.subTest(data1=data1, data2=data2): + retval = self.node.f(data1, data2)[0] # Pass at least two dictionaries + + # Test if DataFrame structure matches + self.assertTrue(isinstance(retval, pd.DataFrame)) + + # Test if index matches + self.assertTrue(retval.index.equals(expected_df.index), f"Index mismatch for input: {data1}, {data2}") + + # Test if data matches + pd.testing.assert_frame_equal(retval, expected_df) + + def test_all_dicts(self): + """Test case where all 10 dictionaries are provided.""" + data1, data2, data3, data4, data5, data6, data7, data8, data9, data10, expected_df = self.all_dicts_case + retval = self.node.f(data1, data2, data3, data4, data5, data6, data7, data8, data9, data10)[0] + pd.testing.assert_frame_equal(retval, expected_df) + + def test_no_dict_failure(self): + """Test failure when no dictionaries are passed.""" + with self.assertRaises(TypeError): + self.node.f() # No arguments should raise TypeError + + def test_length_mismatch_failure(self): + """Test failure when first dictionary's value length differs from second's.""" + for data1, data2, error_message in self.length_mismatch_cases: + with self.subTest(data1=data1, data2=data2): + with self.assertRaises(ValueError) as context: + self.node.f(data1, data2) + self.assertEqual(str(context.exception), error_message) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/pandas_wrapper/pandas_create_series_from_dict_test.py b/tests/pandas_wrapper/pandas_create_series_from_dict_test.py new file mode 100644 index 0000000..c0b2ba6 --- /dev/null +++ b/tests/pandas_wrapper/pandas_create_series_from_dict_test.py @@ -0,0 +1,76 @@ +import os +import sys +import unittest +import pandas as pd + +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) +MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") +sys.path.append(MODULE_ROOT) +from pandas_wrapper.pandas_create_series_from_dict import PandasCreateSeriesFromDict + +class TestPandasCreateSeriesFromDict(unittest.TestCase): + def setUp(self): + """Set up test data.""" + self.node = PandasCreateSeriesFromDict() + self.valid_test_cases = [ + # Empty dict + ({}, pd.Series({})), + + # Single key-value pairs + ({"a": 12345}, pd.Series({"a": 12345})), + ({"a": 12345.6}, pd.Series({"a": 12345.6})), + ({"a": "apple"}, pd.Series({"a": "apple"})), + ({"a": True}, pd.Series({"a": True})), + ({"a": None}, pd.Series({"a": None})), # None should be treated as a valid value + + # Multiple key-value pairs + ({"a": 123, "b": 456}, pd.Series({"a": 123, "b": 456})), + ({"x": 1.5, "y": 3.2, "z": -7.8}, pd.Series({"x": 1.5, "y": 3.2, "z": -7.8})), + ({"name": "Alice", "age": 30, "city": "NYC"}, pd.Series({"name": "Alice", "age": 30, "city": "NYC"})), + ({"flag": False, "score": 99, "pi": 3.14159}, pd.Series({"flag": False, "score": 99, "pi": 3.14159})), + ] + + self.invalid_test_cases = [ + # Non-dictionary inputs + None, + [], + (), + "string", + 1234, + 56.78, + {1, 2, 3}, # Set + [{"a": 1}], # List containing a dict + + # Dictionaries with non-scalar values + {"a": [12345, 6789]}, # List value + {"a": {"key": "value"}}, # Dict value + {"a": (1, 2)}, # Tuple value + {"a": {1, 2}}, # Set value + + # Mixed valid and invalid values + {"a": 123, "b": [456, 789]}, # One scalar, one list + {"x": 1.5, "y": {"nested": "dict"}}, # One scalar, one dict + {"flag": False, "data": (3, 4)}, # One scalar, one tuple + ] + + def test_create_series(self): + """Test Series creation from dictionaries with multiple key-value pairs.""" + for data, expected_series in self.valid_test_cases: + with self.subTest(data=data): + retval = self.node.f(data)[0] + + # Test if output is a Pandas Series + self.assertTrue(isinstance(retval, pd.Series), f"Expected Series, got {type(retval)}") + + # Test if Series matches expected output + pd.testing.assert_series_equal(retval, expected_series) + + def test_invalid_inputs(self): + """Test that invalid inputs raise ValueError.""" + for data in self.invalid_test_cases: + with self.subTest(data=data): + with self.assertRaises(ValueError): + self.node.f(data) + +if __name__ == "__main__": + unittest.main() diff --git a/tests/pandas_wrapper/pandas_iloc_rows_slice_dataframe_test.py b/tests/pandas_wrapper/pandas_iloc_rows_slice_dataframe_test.py index f80d00b..e7f758d 100644 --- a/tests/pandas_wrapper/pandas_iloc_rows_slice_dataframe_test.py +++ b/tests/pandas_wrapper/pandas_iloc_rows_slice_dataframe_test.py @@ -3,7 +3,7 @@ import sys import unittest import pandas as pd -PROJECT_ROOT = os.path.realpath(os.path.join(__file__, "..", "..", "..")) +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") sys.path.append(MODULE_ROOT) diff --git a/tests/pandas_wrapper/pandas_melt_test.py b/tests/pandas_wrapper/pandas_melt_test.py index ba223a3..1a6669f 100644 --- a/tests/pandas_wrapper/pandas_melt_test.py +++ b/tests/pandas_wrapper/pandas_melt_test.py @@ -3,7 +3,7 @@ import sys import unittest import pandas as pd -PROJECT_ROOT = os.path.realpath(os.path.join(__file__, "..", "..", "..")) +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") sys.path.append(MODULE_ROOT) diff --git a/tests/pandas_wrapper/pandas_pivot_test.py b/tests/pandas_wrapper/pandas_pivot_test.py index 9cda5d4..bd336f5 100644 --- a/tests/pandas_wrapper/pandas_pivot_test.py +++ b/tests/pandas_wrapper/pandas_pivot_test.py @@ -3,7 +3,7 @@ import sys import unittest import pandas as pd -PROJECT_ROOT = os.path.realpath(os.path.join(__file__, "..", "..", "..")) +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") sys.path.append(MODULE_ROOT) diff --git a/tests/pandas_wrapper/pandas_to_datetime_test.py b/tests/pandas_wrapper/pandas_to_datetime_test.py index a007a75..b08e885 100644 --- a/tests/pandas_wrapper/pandas_to_datetime_test.py +++ b/tests/pandas_wrapper/pandas_to_datetime_test.py @@ -4,7 +4,7 @@ import unittest import pandas as pd import pandas.api.types as ptypes -PROJECT_ROOT = os.path.realpath(os.path.join(__file__, "..", "..", "..")) +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") sys.path.append(MODULE_ROOT) print(MODULE_ROOT) diff --git a/tests/pandas_wrapper/pandas_to_strftime_test.py b/tests/pandas_wrapper/pandas_to_strftime_test.py index 8c0a0de..b374c87 100644 --- a/tests/pandas_wrapper/pandas_to_strftime_test.py +++ b/tests/pandas_wrapper/pandas_to_strftime_test.py @@ -4,7 +4,7 @@ import unittest import pandas as pd import pandas.api.types as ptypes -PROJECT_ROOT = os.path.realpath(os.path.join(__file__, "..", "..", "..")) +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") sys.path.append(MODULE_ROOT) print(MODULE_ROOT) diff --git a/tests/pandas_wrapper/utils_column_labels_string_to_list_test.py b/tests/pandas_wrapper/utils_column_labels_string_to_list_test.py index 36106c8..da67259 100644 --- a/tests/pandas_wrapper/utils_column_labels_string_to_list_test.py +++ b/tests/pandas_wrapper/utils_column_labels_string_to_list_test.py @@ -4,7 +4,7 @@ import unittest import pandas as pd from typing import List, Union -PROJECT_ROOT = os.path.realpath(os.path.join(__file__, "..", "..", "..")) +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") sys.path.append(MODULE_ROOT) diff --git a/tests/pandas_wrapper/utils_comma_separated_labels_string_to_list_test.py b/tests/pandas_wrapper/utils_comma_separated_labels_string_to_list_test.py index 67e51eb..c62fa39 100644 --- a/tests/pandas_wrapper/utils_comma_separated_labels_string_to_list_test.py +++ b/tests/pandas_wrapper/utils_comma_separated_labels_string_to_list_test.py @@ -3,7 +3,7 @@ import sys import unittest from typing import List -PROJECT_ROOT = os.path.realpath(os.path.join(__file__, "..", "..", "..")) +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") sys.path.append(MODULE_ROOT) diff --git a/tests/pandas_wrapper/utils_flatten_list_tuple_unique_test.py b/tests/pandas_wrapper/utils_flatten_list_tuple_unique_test.py index 495ee8e..d609cd0 100644 --- a/tests/pandas_wrapper/utils_flatten_list_tuple_unique_test.py +++ b/tests/pandas_wrapper/utils_flatten_list_tuple_unique_test.py @@ -3,7 +3,7 @@ import sys import unittest from typing import Any, List, Tuple, Union, Set -PROJECT_ROOT = os.path.realpath(os.path.join(__file__, "..", "..", "..")) +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") sys.path.append(MODULE_ROOT) diff --git a/tests/pandas_wrapper/utils_index_json_test.py b/tests/pandas_wrapper/utils_index_json_test.py index ad81d68..d4b7e92 100644 --- a/tests/pandas_wrapper/utils_index_json_test.py +++ b/tests/pandas_wrapper/utils_index_json_test.py @@ -5,7 +5,7 @@ import json import numpy as np import pandas as pd -PROJECT_ROOT = os.path.realpath(os.path.join(__file__, "..", "..", "..")) +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") sys.path.append(MODULE_ROOT) print(MODULE_ROOT) diff --git a/tests/pandas_wrapper/utils_series_json_test.py b/tests/pandas_wrapper/utils_series_json_test.py index 08faf87..7a2f923 100644 --- a/tests/pandas_wrapper/utils_series_json_test.py +++ b/tests/pandas_wrapper/utils_series_json_test.py @@ -5,10 +5,9 @@ import json import numpy as np import pandas as pd -PROJECT_ROOT = os.path.realpath(os.path.join(__file__, "..", "..", "..")) +PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules") sys.path.append(MODULE_ROOT) -print(MODULE_ROOT) from pandas_wrapper.utils import series_to_jsons from pandas_wrapper.utils import jsons_to_series