diff --git a/__init__.py b/__init__.py
index 37cddc6..5964921 100644
--- a/__init__.py
+++ b/__init__.py
@@ -13,6 +13,8 @@ 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
+from .modules.numpy_wrapper.numpy_float_create import NumpyFloatCreate
+from .modules.numpy_wrapper.numpy_int_create import NumpyIntCreate
from .modules.pandas_wrapper.pandas_add import PandasAdd
from .modules.pandas_wrapper.pandas_add_scalar_float import PandasAddScalarFloat
from .modules.pandas_wrapper.pandas_add_scalar_int import PandasAddScalarInt
@@ -28,6 +30,7 @@ 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_from_numpy import PandasCreateFromNumpy
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
@@ -105,12 +108,17 @@ from .modules.pandas_wrapper.pandas_sum import PandasSum
from .modules.pandas_wrapper.pandas_summary import PandasSummary
from .modules.pandas_wrapper.pandas_tan import PandasTan
from .modules.pandas_wrapper.pandas_to_datetime import PandasToDatetime
+from .modules.pandas_wrapper.pandas_to_numpy import PandasToNumpy
from .modules.pandas_wrapper.pandas_to_string import PandasToString
from .modules.pandas_wrapper.pandas_transpose import PandasTranspose
from .modules.pandas_wrapper.pandas_var import PandasVar
from .modules.pandas_wrapper.pandas_vertical_concat import PandasVerticalConcat
from .modules.pandas_wrapper.pandas_vertical_split import PandasVerticalSplit
from .modules.pandas_wrapper.pandas_xs import PandasXs
+from .modules.pytorch_wrapper.pt_float_create import PtFloatCreate
+from .modules.pytorch_wrapper.pt_from_numpy import PtFromNumpy
+from .modules.pytorch_wrapper.pt_int_create import PtIntCreate
+from .modules.pytorch_wrapper.pt_to_numpy import PtToNumpy
from .modules.seaborn_wrapper.sns_bar import SNSBar
from .modules.seaborn_wrapper.sns_histogram import SNSHistogram
from .modules.seaborn_wrapper.sns_line import SNSLine
@@ -134,6 +142,8 @@ NODE_CLASS_MAPPINGS: Dict[str, Type[T]] = {
"MPLBar": MPLBar,
"MPLLine": MPLLine,
"MPLScatter": MPLScatter,
+ "NumpyFloatCreate": NumpyFloatCreate,
+ "NumpyIntCreate": NumpyIntCreate,
"PandasAdd": PandasAdd,
"PandasAddScalarFloat": PandasAddScalarFloat,
"PandasAddScalarInt": PandasAddScalarInt,
@@ -149,6 +159,7 @@ NODE_CLASS_MAPPINGS: Dict[str, Type[T]] = {
"PandasCreate": PandasCreate,
"PandasCreateFromDict": PandasCreateFromDict,
"PandasCreateFromMultipleDict": PandasCreateFromMultipleDict,
+ "PandasCreateFromNumpy": PandasCreateFromNumpy,
"PandasCreateSeriesFromDict": PandasCreateSeriesFromDict,
"PandasCreateWithIndex": PandasCreateWithIndex,
"PandasCummax": PandasCummax,
@@ -226,12 +237,17 @@ NODE_CLASS_MAPPINGS: Dict[str, Type[T]] = {
"PandasSummary": PandasSummary,
"PandasTan": PandasTan,
"PandasToDatetime": PandasToDatetime,
+ "PandasToNumpy": PandasToNumpy,
"PandasToString": PandasToString,
"PandasTranspose": PandasTranspose,
"PandasVar": PandasVar,
"PandasVerticalConcat": PandasVerticalConcat,
"PandasVerticalSplit": PandasVerticalSplit,
"PandasXs": PandasXs,
+ "PtFloatCreate": PtFloatCreate,
+ "PtFromNumpy": PtFromNumpy,
+ "PtIntCreate": PtIntCreate,
+ "PtToNumpy": PtToNumpy,
"PyKvFloatCreate": PyKvFloatCreate,
"PyKvIntCreate": PyKvIntCreate,
"PyKvStringCreate": PyKvStringCreate,
@@ -258,6 +274,8 @@ NODE_DISPLAY_NAME_MAPPINGS: Dict[str, str] = {
"MPLBar": "MPL Bar Chart",
"MPLLine": "MPL Line Plot",
"MPLScatter": "MPL Scatter Plot",
+ "NumpyFloatCreate": "Numpy Float Create",
+ "NumpyIntCreate": "Numpy Int Create",
"PandasAdd": "Pandas Add",
"PandasAddScalarFloat": "Pandas Add Scalar Float",
"PandasAddScalarInt": "Pandas Add Scalar Int",
@@ -273,6 +291,7 @@ NODE_DISPLAY_NAME_MAPPINGS: Dict[str, str] = {
"PandasCreate": "Pandas Create",
"PandasCreateFromDict": "Pandas Create From Dict",
"PandasCreateFromMultipleDict": "Pandas Create From Multiple Dict",
+ "PandasCreateFromNumpy": "Pandas Create From Numpy",
"PandasCreateSeriesFromDict": "Pandas Create Series From Dict",
"PandasCreateWithIndex": "Pandas Create With Index",
"PandasCummax": "Pandas Cummax",
@@ -350,12 +369,17 @@ NODE_DISPLAY_NAME_MAPPINGS: Dict[str, str] = {
"PandasSummary": "Pandas Summary",
"PandasTan": "Pandas Tan",
"PandasToDatetime": "Pandas To Datetime",
+ "PandasToNumpy": "Pandas To Numpy",
"PandasToString": "Pandas To String",
"PandasTranspose": "Pandas Transpose",
"PandasVar": "Pandas Var",
"PandasVerticalConcat": "Pandas Vertical Concat",
"PandasVerticalSplit": "Pandas Vertical Split",
"PandasXs": "Pandas Xs",
+ "PtFloatCreate": "Pt Float Create",
+ "PtFromNumpy": "Pt From Numpy",
+ "PtIntCreate": "Pt Int Create",
+ "PtToNumpy": "Pt To Numpy",
"PyKvFloatCreate": "Py Kv Float Create",
"PyKvIntCreate": "Py Kv Int Create",
"PyKvStringCreate": "Py Kv String Create",
diff --git a/dev/scripts/run_tests.sh b/dev/scripts/run_tests.sh
index 1bc4915..cd29541 100755
--- a/dev/scripts/run_tests.sh
+++ b/dev/scripts/run_tests.sh
@@ -3,6 +3,9 @@
# ```
# dev/scripts/run_tests.sh
# ````
+# If you add a new test file, make sure that the directory contains an empty
+# __init__.py. Otherwise, unittest won't be able to find the directory and
+# the tests in the directory will be skipped.
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 f838250..e8de662 100644
--- a/docs/reference/node_reference.md
+++ b/docs/reference/node_reference.md
@@ -61,6 +61,7 @@
| [Pandas As Float](pandas_as_float.md) | Converts all cells in a pandas DataFrame to float type. |
| [Pandas As Int](pandas_as_int.md) | Converts all cells in a pandas DataFrame to integer type. |
| [Pandas As String](pandas_as_string.md) | Converts all cells in a pandas DataFrame to string type. |
+| [Pandas To Numpy](pandas_to_numpy.md) | Converts a pandas DataFrame to Numpy ndarray. |
## DataFrame information
| Node | Description |
| --- | --- |
@@ -94,6 +95,7 @@
| [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 From Numpy](pandas_create_from_numpy.md) | Creates a pandas DataFrame from a NumPy ndarray. |
| [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. |
@@ -111,6 +113,11 @@
| [Pandas Log](pandas_log.md) | Applying the natural logarithm function to a pandas DataFrame and converting non-numeric values to NaN. |
| [Pandas Sin](pandas_sin.md) | Applies the sine function to a pandas DataFrame and converting non-numeric values to NaN. |
| [Pandas Tan](pandas_tan.md) | Applies the tangent function to a pandas DataFrame and converting non-numeric values to NaN. |
+## Numpy
+| Node | Description |
+| --- | --- |
+| [Numpy Float Create](numpy_float_create.md) | Creates a NumPy ndarray with 32-bit floating point precision |
+| [Numpy Int Create](numpy_int_create.md) | Creates a NumPy ndarray with 32-bit integer |
## Plot
| Node | Description |
| --- | --- |
@@ -121,6 +128,13 @@
| [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. |
+## PyTorch wrapper
+| Node | Description |
+| --- | --- |
+| [Pt Float Create](pt_float_create.md) | Creates a PyTorch tensor with 32-bit floating point precision |
+| [Pt From Numpy](pt_from_numpy.md) | Converts a NumPy ndarray to a PyTorch tensor while preserving its data type. |
+| [Pt Int Create](pt_int_create.md) | Creates a PyTorch tensor with 32-bit integer |
+| [Pt To Numpy](pt_to_numpy.md) | Converts PyTorch tensor to NumPy ndarray. |
## Python wrapper
| Node | Description |
| --- | --- |
diff --git a/docs/reference/numpy_float_create.md b/docs/reference/numpy_float_create.md
new file mode 100644
index 0000000..61152d5
--- /dev/null
+++ b/docs/reference/numpy_float_create.md
@@ -0,0 +1,18 @@
+# Numpy Float Create
+Creates a NumPy ndarray with 32-bit floating point precision
+using values entered in the text field.
+
+## Input
+| Name | Data type |
+|---|---|
+| data | String |
+
+## Output
+| Data type |
+|---|
+| Ndarray |
+
+
+Category: Numpy
+
+ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved.
diff --git a/docs/reference/numpy_int_create.md b/docs/reference/numpy_int_create.md
new file mode 100644
index 0000000..d53aceb
--- /dev/null
+++ b/docs/reference/numpy_int_create.md
@@ -0,0 +1,18 @@
+# Numpy Int Create
+Creates a NumPy ndarray with 32-bit integer
+using values entered in the text field.
+
+## Input
+| Name | Data type |
+|---|---|
+| data | String |
+
+## Output
+| Data type |
+|---|
+| Ndarray |
+
+
+Category: Numpy
+
+ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved.
diff --git a/docs/reference/pandas_create_from_numpy.md b/docs/reference/pandas_create_from_numpy.md
new file mode 100644
index 0000000..13cd86a
--- /dev/null
+++ b/docs/reference/pandas_create_from_numpy.md
@@ -0,0 +1,17 @@
+# Pandas Create From Numpy
+Creates a pandas DataFrame from a NumPy ndarray.
+
+## Input
+| Name | Data type |
+|---|---|
+| data | Ndarray |
+
+## 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_to_numpy.md b/docs/reference/pandas_to_numpy.md
new file mode 100644
index 0000000..a265537
--- /dev/null
+++ b/docs/reference/pandas_to_numpy.md
@@ -0,0 +1,17 @@
+# Pandas To Numpy
+Converts a pandas DataFrame to Numpy ndarray.
+
+## Input
+| Name | Data type |
+|---|---|
+| dataframe | DataFrame |
+
+## Output
+| Data type |
+|---|
+| Ndrray |
+
+
+Category: Data type conversion
+
+ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved.
diff --git a/docs/reference/pt_float_create.md b/docs/reference/pt_float_create.md
new file mode 100644
index 0000000..a9f9b85
--- /dev/null
+++ b/docs/reference/pt_float_create.md
@@ -0,0 +1,18 @@
+# Pt Float Create
+Creates a PyTorch tensor with 32-bit floating point precision
+using values entered in the text field.
+
+## Input
+| Name | Data type |
+|---|---|
+| data | String |
+
+## Output
+| Data type |
+|---|
+| Tensor |
+
+
+Category: PyTorch wrapper
+
+ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved.
diff --git a/docs/reference/pt_from_numpy.md b/docs/reference/pt_from_numpy.md
new file mode 100644
index 0000000..77db3d5
--- /dev/null
+++ b/docs/reference/pt_from_numpy.md
@@ -0,0 +1,17 @@
+# Pt From Numpy
+Converts a NumPy ndarray to a PyTorch tensor while preserving its data type.
+
+## Input
+| Name | Data type |
+|---|---|
+| array | Ndarray |
+
+## Output
+| Data type |
+|---|
+| Tensor |
+
+
+Category: PyTorch wrapper
+
+ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved.
diff --git a/docs/reference/pt_int_create.md b/docs/reference/pt_int_create.md
new file mode 100644
index 0000000..ffb9681
--- /dev/null
+++ b/docs/reference/pt_int_create.md
@@ -0,0 +1,18 @@
+# Pt Int Create
+Creates a PyTorch tensor with 32-bit integer
+using values entered in the text field.
+
+## Input
+| Name | Data type |
+|---|---|
+| data | String |
+
+## Output
+| Data type |
+|---|
+| Tensor |
+
+
+Category: PyTorch wrapper
+
+ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved.
diff --git a/docs/reference/pt_to_numpy.md b/docs/reference/pt_to_numpy.md
new file mode 100644
index 0000000..be9698a
--- /dev/null
+++ b/docs/reference/pt_to_numpy.md
@@ -0,0 +1,17 @@
+# Pt To Numpy
+Converts PyTorch tensor to NumPy ndarray.
+
+## Input
+| Name | Data type |
+|---|---|
+| tens | Tensor |
+
+## Output
+| Data type |
+|---|
+| Ndarray |
+
+
+Category: PyTorch wrapper
+
+ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved.
diff --git a/modules/numpy_wrapper/numpy_float_create.py b/modules/numpy_wrapper/numpy_float_create.py
new file mode 100644
index 0000000..657003a
--- /dev/null
+++ b/modules/numpy_wrapper/numpy_float_create.py
@@ -0,0 +1,47 @@
+from typing import Any, Dict
+import numpy as np
+import ast
+
+
+class NumpyFloatCreate:
+ """
+ Creates a NumPy ndarray with 32-bit floating point precision
+ using values entered in the text field.
+
+ category: Numpy
+ """
+
+ @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": ("STRING", {"multiline": True}),
+ }
+ }
+
+ RETURN_TYPES: tuple = ("NDARRAY",)
+ FUNCTION: str = "f"
+ CATEGORY: str = "Numpy wrapper"
+
+ def f(self, data: str) -> tuple:
+ """
+ Creates a Numpy ndarray using values entered in the text field.
+
+ Args:
+ data (str): String value in the text field.
+
+ Returns:
+ tuple: A tuple containing a the DataFrame.
+ """
+ # Convert string to Python list
+ list_data = ast.literal_eval(data)
+
+ # Convert list to NumPy array
+ array = np.array(list_data, dtype=np.float32)
+ return (array,)
diff --git a/modules/numpy_wrapper/numpy_int_create.py b/modules/numpy_wrapper/numpy_int_create.py
new file mode 100644
index 0000000..6f11fd3
--- /dev/null
+++ b/modules/numpy_wrapper/numpy_int_create.py
@@ -0,0 +1,48 @@
+from typing import Any, Dict
+import numpy as np
+import ast
+
+
+class NumpyIntCreate:
+ """
+ Creates a NumPy ndarray with 32-bit integer
+ using values entered in the text field.
+
+ category: Numpy
+ """
+
+ @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": ("STRING", {"multiline": True}),
+ }
+ }
+
+ RETURN_TYPES: tuple = ("NDARRAY",)
+ FUNCTION: str = "f"
+ CATEGORY: str = "Numpy wrapper"
+
+ def f(self, data: str) -> tuple:
+ """
+ Creates a NumPy ndarray with 32-bit integer using values
+ entered in the text field.
+
+ Args:
+ data (str): String value in the text field.
+
+ Returns:
+ tuple: A tuple containing the NumPy ndarray.
+ """
+ # Convert string to Python list
+ list_data = ast.literal_eval(data)
+
+ # Convert list to NumPy int32 array
+ array = np.array(list_data, dtype=np.int32)
+ return (array,)
diff --git a/modules/pandas_wrapper/pandas_create_from_numpy.py b/modules/pandas_wrapper/pandas_create_from_numpy.py
new file mode 100644
index 0000000..9c3c3eb
--- /dev/null
+++ b/modules/pandas_wrapper/pandas_create_from_numpy.py
@@ -0,0 +1,48 @@
+from typing import Any, Dict
+import pandas as pd
+import numpy as np
+
+
+class PandasCreateFromNumpy:
+ """
+ Creates a pandas DataFrame from a NumPy ndarray.
+
+ 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": ("NDARRAY", {}),
+ }
+ }
+
+ RETURN_TYPES: tuple = ("DATAFRAME",)
+ FUNCTION: str = "f"
+ CATEGORY: str = "Data Analysis"
+
+ def f(self, data: np.ndarray) -> tuple:
+ """
+ Creates a pandas DataFrame from a NumPy ndarray.
+
+ Args:
+ data (np.ndarray): A NumPy array.
+
+ Returns:
+ tuple: A tuple containing the DataFrame.
+
+ Raises:
+ ValueError: If the array is not rank 1 or rank 2.
+ """
+ if len(data.shape) not in [1, 2]:
+ raise ValueError("Only rank 1 and rank 2 arrays are supported.")
+
+ return (pd.DataFrame(data),)
+
diff --git a/modules/pandas_wrapper/pandas_to_numpy.py b/modules/pandas_wrapper/pandas_to_numpy.py
new file mode 100644
index 0000000..fa56e25
--- /dev/null
+++ b/modules/pandas_wrapper/pandas_to_numpy.py
@@ -0,0 +1,41 @@
+from typing import Any, Dict
+import pandas as pd
+
+class PandasToNumpy:
+ """
+ Converts a pandas DataFrame to Numpy ndarray.
+
+ category: Data type conversion
+ """
+
+ @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": {
+ "dataframe": ("DATAFRAME", {}),
+ }
+ }
+
+ RETURN_TYPES: tuple = ("NDARRAY",)
+ FUNCTION: str = "f"
+ CATEGORY: str = "Data Analysis"
+
+ def f(self, dataframe: pd.DataFrame) -> tuple:
+ """
+ Converts a pandas DataFrame to a NumPy ndarray.
+
+ Args:
+ dataframe (DataFrame): The DataFrame.
+
+ Returns:
+ tuple: A tuple containing the NumPy representation of the DataFrame.
+ """
+ if not isinstance(dataframe, pd.DataFrame):
+ raise TypeError("PandasToNumpy expects pd.DataFrame.")
+ return (dataframe.to_numpy(),)
diff --git a/modules/pytorch_wrapper/pt_float_create.py b/modules/pytorch_wrapper/pt_float_create.py
new file mode 100644
index 0000000..48672fe
--- /dev/null
+++ b/modules/pytorch_wrapper/pt_float_create.py
@@ -0,0 +1,47 @@
+from typing import Any, Dict
+import torch
+import ast
+
+
+class PtFloatCreate:
+ """
+ Creates a PyTorch tensor with 32-bit floating point precision
+ using values entered in the text field.
+
+ category: PyTorch wrapper
+ """
+
+ @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": ("STRING", {"multiline": True}),
+ }
+ }
+
+ RETURN_TYPES: tuple = ("TENSOR",)
+ FUNCTION: str = "f"
+ CATEGORY: str = "PyTorch wrapper"
+
+ def f(self, data: str) -> tuple:
+ """
+ Creates a PyTorch tensor using values entered in the text field.
+
+ Args:
+ data (str): String value in the text field.
+
+ Returns:
+ tuple: A tuple containing the tensor.
+ """
+ # Convert string to Python list
+ list_data = ast.literal_eval(data)
+
+ # Convert list to PyTorch tensor
+ tensor = torch.tensor(list_data, dtype=torch.float32)
+ return (tensor,)
diff --git a/modules/pytorch_wrapper/pt_from_numpy.py b/modules/pytorch_wrapper/pt_from_numpy.py
new file mode 100644
index 0000000..3ea0b91
--- /dev/null
+++ b/modules/pytorch_wrapper/pt_from_numpy.py
@@ -0,0 +1,42 @@
+from typing import Any, Dict, Tuple
+import numpy as np
+import torch
+
+
+class PtFromNumpy:
+ """
+ Converts a NumPy ndarray to a PyTorch tensor while preserving its data type.
+
+ category: PyTorch wrapper
+ """
+
+ @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": {
+ "array": ("NDARRAY", {}),
+ }
+ }
+
+ RETURN_TYPES: tuple = ("TENSOR",)
+ FUNCTION: str = "f"
+ CATEGORY: str = "PyTorch wrapper"
+
+ def f(self, array: np.ndarray) -> Tuple[torch.Tensor]:
+ """
+ Converts a NumPy ndarray to a PyTorch tensor while preserving its data type.
+
+ Args:
+ array (np.ndarray): NumPy ndarray.
+
+ Returns:
+ tuple: A tuple containing the PyTorch tensor.
+ """
+ tens = torch.tensor(array, dtype=torch.from_numpy(array).dtype)
+ return (tens,)
diff --git a/modules/pytorch_wrapper/pt_int_create.py b/modules/pytorch_wrapper/pt_int_create.py
new file mode 100644
index 0000000..6739ad0
--- /dev/null
+++ b/modules/pytorch_wrapper/pt_int_create.py
@@ -0,0 +1,47 @@
+from typing import Any, Dict
+import torch
+import ast
+
+
+class PtIntCreate:
+ """
+ Creates a PyTorch tensor with 32-bit integer
+ using values entered in the text field.
+
+ category: PyTorch wrapper
+ """
+
+ @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": ("STRING", {"multiline": True}),
+ }
+ }
+
+ RETURN_TYPES: tuple = ("TENSOR",)
+ FUNCTION: str = "f"
+ CATEGORY: str = "PyTorch wrapper"
+
+ def f(self, data: str) -> tuple:
+ """
+ Creates a PyTorch tensor using values entered in the text field.
+
+ Args:
+ data (str): String value in the text field.
+
+ Returns:
+ tuple: A tuple containing the tensor.
+ """
+ # Convert string to Python list
+ list_data = ast.literal_eval(data)
+
+ # Convert list to PyTorch tensor
+ tensor = torch.tensor(list_data, dtype=torch.int32)
+ return (tensor,)
diff --git a/modules/pytorch_wrapper/pt_to_numpy.py b/modules/pytorch_wrapper/pt_to_numpy.py
new file mode 100644
index 0000000..f5ff4fc
--- /dev/null
+++ b/modules/pytorch_wrapper/pt_to_numpy.py
@@ -0,0 +1,41 @@
+from typing import Any, Dict
+import torch
+
+
+class PtToNumpy:
+ """
+ Converts PyTorch tensor to NumPy ndarray.
+
+ category: PyTorch wrapper
+ """
+
+ @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": {
+ "tens": ("TENSOR", {}),
+ }
+ }
+
+ RETURN_TYPES: tuple = ("NDARRAY",)
+ FUNCTION: str = "f"
+ CATEGORY: str = "PyTorch wrapper"
+
+ def f(self, tens: torch.Tensor) -> tuple:
+ """
+ Converts PyTorch tensor to NumPy ndarray.
+
+ Args:
+ tens (torch.Tensor): PyTorch Tensor
+
+ Returns:
+ tuple: A tuple containing the ndarray.
+ """
+ array = tens.cpu().detach().numpy()
+ return (array,)
diff --git a/pyproject.toml b/pyproject.toml
index 4457378..de52c99 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.2"
+version = "1.3.0"
license = {file = "LICENSE"}
[project.urls]
diff --git a/tests/numpy_wrapper/__init__.py b/tests/numpy_wrapper/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/numpy_wrapper/numpy_float_create_test.py b/tests/numpy_wrapper/numpy_float_create_test.py
new file mode 100644
index 0000000..15d69ce
--- /dev/null
+++ b/tests/numpy_wrapper/numpy_float_create_test.py
@@ -0,0 +1,66 @@
+import os
+import sys
+import unittest
+import numpy as np
+
+
+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 numpy_wrapper.numpy_float_create import NumpyFloatCreate
+
+class TestNumpyFloatCreate(unittest.TestCase):
+ def setUp(self):
+ """Set up test data."""
+ self.node = NumpyFloatCreate()
+
+ # Test cases covering rank 0 (scalar) to rank 5 tensors
+ self.test_cases = [
+ # Rank 0 (scalar)
+ ("12345", np.array(12345, dtype=np.float32)),
+ ("12345.6", np.array(12345.6, dtype=np.float32)),
+
+ # Rank 1 (1D array)
+ ("[1, 2, 3]", np.array([1, 2, 3], dtype=np.float32)),
+ ("[1.1, 2.2, 3.3]", np.array([1.1, 2.2, 3.3], dtype=np.float32)),
+
+ # Rank 2 (2D matrix)
+ ("[[1, 2, 3], [4, 5, 6]]", np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32)),
+ ("[[1.1, 2.2], [3.3, 4.4]]", np.array([[1.1, 2.2], [3.3, 4.4]], dtype=np.float32)),
+
+ # Rank 3 (3D tensor)
+ ("[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]",
+ np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]], dtype=np.float32)),
+
+ # Rank 4 (4D tensor)
+ ("[[[[1, 2], [3, 4]]], [[[5, 6], [7, 8]]]]",
+ np.array([[[[1, 2], [3, 4]]], [[[5, 6], [7, 8]]]], dtype=np.float32)),
+
+ # Rank 5 (5D tensor)
+ ("[[[[[1], [2]], [[3], [4]]]], [[[[5], [6]], [[7], [8]]]]]",
+ np.array([[[[[1], [2]], [[3], [4]]]], [[[[5], [6]], [[7], [8]]]]], dtype=np.float32)),
+ ]
+
+ def test_create_ndarray(self):
+ """Test NumPy ndarray creation from various structured inputs."""
+ for data_str, expected_array in self.test_cases:
+ with self.subTest(data=data_str):
+ retval = self.node.f(data_str)[0]
+
+ # Ensure the returned value is a NumPy array
+ self.assertTrue(isinstance(retval, np.ndarray), f"Expected ndarray, got {type(retval)}")
+
+ # Ensure the dtype is float32
+ self.assertEqual(retval.dtype, np.float32, f"Dtype mismatch for input: {data_str}")
+
+ # Ensure the shape matches
+ self.assertEqual(retval.shape, expected_array.shape,
+ f"Shape mismatch for input: {data_str} (Expected {expected_array.shape}, got {retval.shape})")
+
+ # Ensure values match
+ np.testing.assert_array_equal(retval, expected_array,
+ f"Value mismatch for input: {data_str}")
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/numpy_wrapper/numpy_int_create_test.py b/tests/numpy_wrapper/numpy_int_create_test.py
new file mode 100644
index 0000000..022d4eb
--- /dev/null
+++ b/tests/numpy_wrapper/numpy_int_create_test.py
@@ -0,0 +1,63 @@
+import os
+import sys
+import unittest
+import numpy as np
+
+
+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 numpy_wrapper.numpy_int_create import NumpyIntCreate
+
+class TestNumpyIntCreate(unittest.TestCase):
+ def setUp(self):
+ """Set up test data."""
+ self.node = NumpyIntCreate()
+
+ # Test cases covering rank 0 (scalar) to rank 5 tensors
+ self.test_cases = [
+ # Rank 0 (scalar)
+ ("12345", np.array(12345, dtype=np.int32)),
+
+ # Rank 1 (1D array)
+ ("[1, 2, 3]", np.array([1, 2, 3], dtype=np.int32)),
+
+ # Rank 2 (2D matrix)
+ ("[[1, 2, 3], [4, 5, 6]]", np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32)),
+
+ # Rank 3 (3D tensor)
+ ("[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]",
+ np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]], dtype=np.int32)),
+
+ # Rank 4 (4D tensor)
+ ("[[[[1, 2], [3, 4]]], [[[5, 6], [7, 8]]]]",
+ np.array([[[[1, 2], [3, 4]]], [[[5, 6], [7, 8]]]], dtype=np.int32)),
+
+ # Rank 5 (5D tensor)
+ ("[[[[[1], [2]], [[3], [4]]]], [[[[5], [6]], [[7], [8]]]]]",
+ np.array([[[[[1], [2]], [[3], [4]]]], [[[[5], [6]], [[7], [8]]]]], dtype=np.int32)),
+ ]
+
+ def test_create_ndarray(self):
+ """Test NumPy int32 ndarray creation from various structured inputs."""
+ for data_str, expected_array in self.test_cases:
+ with self.subTest(data=data_str):
+ retval = self.node.f(data_str)[0]
+
+ # Ensure the returned value is a NumPy array
+ self.assertTrue(isinstance(retval, np.ndarray), f"Expected ndarray, got {type(retval)}")
+
+ # Ensure the dtype is int32
+ self.assertEqual(retval.dtype, np.int32, f"Dtype mismatch for input: {data_str}")
+
+ # Ensure the shape matches
+ self.assertEqual(retval.shape, expected_array.shape,
+ f"Shape mismatch for input: {data_str} (Expected {expected_array.shape}, got {retval.shape})")
+
+ # Ensure values match
+ np.testing.assert_array_equal(retval, expected_array,
+ f"Value mismatch for input: {data_str}")
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/pandas_wrapper/pandas_create_from_numpy_test.py b/tests/pandas_wrapper/pandas_create_from_numpy_test.py
new file mode 100644
index 0000000..a4fa173
--- /dev/null
+++ b/tests/pandas_wrapper/pandas_create_from_numpy_test.py
@@ -0,0 +1,61 @@
+import os
+import sys
+import unittest
+import numpy as np
+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_numpy import PandasCreateFromNumpy
+
+class TestPandasCreateFromNumpy(unittest.TestCase):
+ def setUp(self):
+ """Set up test data."""
+ self.node = PandasCreateFromNumpy()
+
+ self.test_cases = [
+ # Rank 0
+ (np.array(42), ValueError),
+ (np.array(3.14), ValueError),
+ (np.array("hello"), ValueError),
+ (np.array(True), ValueError),
+
+ # Rank 1
+ (np.array([1, 2, 3]), pd.DataFrame([1, 2, 3])),
+ (np.array([1.1, 2.2, 3.3]), pd.DataFrame([1.1, 2.2, 3.3])),
+ (np.array(["a", "b", "c"]), pd.DataFrame(["a", "b", "c"])),
+ (np.array([True, False, True]), pd.DataFrame([True, False, True])),
+
+ # Rank 2
+ (np.array([[1, 2], [3, 4]]), pd.DataFrame([[1, 2], [3, 4]])),
+ (np.array([[1.1, 2.2], [3.3, 4.4]]), pd.DataFrame([[1.1, 2.2], [3.3, 4.4]])),
+ (np.array([["a", "b"], ["c", "d"]]), pd.DataFrame([["a", "b"], ["c", "d"]])),
+ (np.array([[True, False], [False, True]]), pd.DataFrame([[True, False], [False, True]])),
+
+ # Rank 3 (Invalid)
+ (np.array([[[1, 2], [3, 4]]]), ValueError),
+ (np.array([[["x", "y"], ["z", "w"]]]), ValueError),
+
+ # Rank 4 (Invalid)
+ (np.random.rand(2, 2, 2, 2), ValueError)
+ ]
+
+ def test_create_dataframe(self):
+ """Test DataFrame creation from various NumPy arrays."""
+ for data, expected in self.test_cases:
+ with self.subTest(data=data):
+ if isinstance(expected, type) and issubclass(expected, Exception):
+ with self.assertRaises(expected):
+ self.node.f(data)
+ else:
+ retval = self.node.f(data)[0]
+
+ # Test if DataFrame structure matches
+ self.assertTrue(isinstance(retval, pd.DataFrame))
+
+ # Test if data matches
+ pd.testing.assert_frame_equal(retval, expected)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/pandas_wrapper/pandas_create_to_numpy_test.py b/tests/pandas_wrapper/pandas_create_to_numpy_test.py
new file mode 100644
index 0000000..f8e2a36
--- /dev/null
+++ b/tests/pandas_wrapper/pandas_create_to_numpy_test.py
@@ -0,0 +1,53 @@
+import os
+import sys
+import unittest
+import numpy as np
+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_to_numpy import PandasToNumpy
+
+class TestPandasToNumpy(unittest.TestCase):
+ def setUp(self):
+ """Set up test data."""
+ self.node = PandasToNumpy()
+
+ self.test_cases = [
+ # Rank 1
+ (pd.DataFrame([1, 2, 3]), np.array([[1], [2], [3]])),
+ (pd.DataFrame([1.1, 2.2, 3.3]), np.array([[1.1], [2.2], [3.3]])),
+ (pd.DataFrame(["a", "b", "c"]), np.array([["a"], ["b"], ["c"]], dtype=object)),
+ (pd.DataFrame([True, False, True]), np.array([[True], [False], [True]])),
+
+ # Rank 2
+ (pd.DataFrame([[1, 2], [3, 4]]), np.array([[1, 2], [3, 4]])),
+ (pd.DataFrame([[1.1, 2.2], [3.3, 4.4]]), np.array([[1.1, 2.2], [3.3, 4.4]])),
+ (pd.DataFrame([["a", "b"], ["c", "d"]]), np.array([["a", "b"], ["c", "d"]], dtype=object)),
+ (pd.DataFrame([[True, False], [False, True]]), np.array([[True, False], [False, True]])),
+
+ # Invalid cases
+ (None, TypeError),
+ ("not a DataFrame", TypeError),
+ (np.array([[1, 2], [3, 4]]), TypeError)
+ ]
+
+ def test_dataframe_to_numpy(self):
+ """Test NumPy array conversion from various Pandas DataFrames."""
+ for dataframe, expected in self.test_cases:
+ with self.subTest(dataframe=dataframe):
+ if isinstance(expected, type) and issubclass(expected, Exception):
+ with self.assertRaises(expected):
+ self.node.f(dataframe)
+ else:
+ retval = self.node.f(dataframe)[0]
+
+ # Ensure the return type is a NumPy array
+ self.assertTrue(isinstance(retval, np.ndarray))
+
+ # Check array equality
+ np.testing.assert_array_equal(retval, expected)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/pytorch_wrapper/__init__.py b/tests/pytorch_wrapper/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/pytorch_wrapper/pt_float_create_test.py b/tests/pytorch_wrapper/pt_float_create_test.py
new file mode 100644
index 0000000..f5acb08
--- /dev/null
+++ b/tests/pytorch_wrapper/pt_float_create_test.py
@@ -0,0 +1,65 @@
+import os
+import sys
+import unittest
+import torch
+
+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 pytorch_wrapper.pt_float_create import PtFloatCreate
+
+class TestPtFloatCreate(unittest.TestCase):
+ def setUp(self):
+ """Set up test data."""
+ self.node = PtFloatCreate()
+
+ # Test cases covering rank 0 (scalar) to rank 5 tensors
+ self.test_cases = [
+ # Rank 0 (scalar)
+ ("12345", torch.tensor(12345, dtype=torch.float32)),
+ ("12345.6", torch.tensor(12345.6, dtype=torch.float32)),
+
+ # Rank 1 (1D array)
+ ("[1, 2, 3]", torch.tensor([1, 2, 3], dtype=torch.float32)),
+ ("[1.1, 2.2, 3.3]", torch.tensor([1.1, 2.2, 3.3], dtype=torch.float32)),
+
+ # Rank 2 (2D matrix)
+ ("[[1, 2, 3], [4, 5, 6]]", torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.float32)),
+ ("[[1.1, 2.2], [3.3, 4.4]]", torch.tensor([[1.1, 2.2], [3.3, 4.4]], dtype=torch.float32)),
+
+ # Rank 3 (3D tensor)
+ ("[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]",
+ torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]], dtype=torch.float32)),
+
+ # Rank 4 (4D tensor)
+ ("[[[[1, 2], [3, 4]]], [[[5, 6], [7, 8]]]]",
+ torch.tensor([[[[1, 2], [3, 4]]], [[[5, 6], [7, 8]]]], dtype=torch.float32)),
+
+ # Rank 5 (5D tensor)
+ ("[[[[[1], [2]], [[3], [4]]]], [[[[5], [6]], [[7], [8]]]]]",
+ torch.tensor([[[[[1], [2]], [[3], [4]]]], [[[[5], [6]], [[7], [8]]]]], dtype=torch.float32)),
+ ]
+
+ def test_create_tensor(self):
+ """Test PyTorch tensor creation from various structured inputs."""
+ for data_str, expected_tensor in self.test_cases:
+ with self.subTest(data=data_str):
+ retval = self.node.f(data_str)[0]
+
+ # Ensure the returned value is a PyTorch tensor
+ self.assertTrue(isinstance(retval, torch.Tensor), f"Expected tensor, got {type(retval)}")
+
+ # Ensure the dtype is float32
+ self.assertEqual(retval.dtype, torch.float32, f"Dtype mismatch for input: {data_str}")
+
+ # Ensure the shape matches
+ self.assertEqual(retval.shape, expected_tensor.shape,
+ f"Shape mismatch for input: {data_str} (Expected {expected_tensor.shape}, got {retval.shape})")
+
+ # Ensure values match
+ torch.testing.assert_close(retval, expected_tensor,
+ msg=f"Value mismatch for input: {data_str}")
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/pytorch_wrapper/pt_from_numpy_test.py b/tests/pytorch_wrapper/pt_from_numpy_test.py
new file mode 100644
index 0000000..49e6642
--- /dev/null
+++ b/tests/pytorch_wrapper/pt_from_numpy_test.py
@@ -0,0 +1,65 @@
+import os
+import sys
+import unittest
+import torch
+import numpy as np
+
+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 pytorch_wrapper.pt_from_numpy import PtFromNumpy
+
+
+class TestPtFromNumpy(unittest.TestCase):
+ def setUp(self):
+ """Set up test data."""
+ self.node = PtFromNumpy()
+
+ # Test cases covering rank 0 (scalar) to rank 3 tensors
+ self.test_cases = [
+ # Rank 0 (scalar) int32
+ (np.array(12345, dtype=np.int32), torch.tensor(12345, dtype=torch.int32)),
+ # Rank 0 (scalar) float32
+ (np.array(12345.6, dtype=np.float32), torch.tensor(12345.6, dtype=torch.float32)),
+
+ # Rank 1 (1D array) int32
+ (np.array([1, 2, 3], dtype=np.int32), torch.tensor([1, 2, 3], dtype=torch.int32)),
+ # Rank 1 (1D array) float32
+ (np.array([1.1, 2.2, 3.3], dtype=np.float32), torch.tensor([1.1, 2.2, 3.3], dtype=torch.float32)),
+
+ # Rank 2 (2D matrix) int32
+ (np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32), torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int32)),
+ # Rank 2 (2D matrix) float32
+ (np.array([[1.1, 2.2], [3.3, 4.4]], dtype=np.float32), torch.tensor([[1.1, 2.2], [3.3, 4.4]], dtype=torch.float32)),
+
+ # Rank 3 (3D tensor) int32
+ (np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]], dtype=np.int32),
+ torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]], dtype=torch.int32)),
+ # Rank 3 (3D tensor) float32
+ (np.array([[[1.1, 2.2], [3.3, 4.4]], [[5.5, 6.6], [7.7, 8.8]]], dtype=np.float32),
+ torch.tensor([[[1.1, 2.2], [3.3, 4.4]], [[5.5, 6.6], [7.7, 8.8]]], dtype=torch.float32)),
+ ]
+
+ def test_convert_numpy_to_tensor(self):
+ """Test conversion of NumPy ndarray to PyTorch tensor."""
+ for np_array, expected_tensor in self.test_cases:
+ with self.subTest(data=np_array):
+ retval = self.node.f(np_array)[0]
+
+ # Ensure the returned value is a PyTorch tensor
+ self.assertTrue(isinstance(retval, torch.Tensor), f"Expected tensor, got {type(retval)}")
+
+ # Ensure the dtype matches
+ self.assertEqual(retval.dtype, expected_tensor.dtype, f"Dtype mismatch for input: {np_array}")
+
+ # Ensure the shape matches
+ self.assertEqual(retval.shape, expected_tensor.shape,
+ f"Shape mismatch for input: {np_array} (Expected {expected_tensor.shape}, got {retval.shape})")
+
+ # Ensure values match
+ torch.testing.assert_close(retval, expected_tensor,
+ msg=f"Value mismatch for input: {np_array}")
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/pytorch_wrapper/pt_int_create_test.py b/tests/pytorch_wrapper/pt_int_create_test.py
new file mode 100644
index 0000000..d77df2e
--- /dev/null
+++ b/tests/pytorch_wrapper/pt_int_create_test.py
@@ -0,0 +1,62 @@
+import os
+import sys
+import unittest
+import torch
+
+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 pytorch_wrapper.pt_int_create import PtIntCreate
+
+class TestPtIntCreate(unittest.TestCase):
+ def setUp(self):
+ """Set up test data."""
+ self.node = PtIntCreate()
+
+ # Test cases covering rank 0 (scalar) to rank 5 tensors
+ self.test_cases = [
+ # Rank 0 (scalar)
+ ("12345", torch.tensor(12345, dtype=torch.int32)),
+
+ # Rank 1 (1D array)
+ ("[1, 2, 3]", torch.tensor([1, 2, 3], dtype=torch.int32)),
+
+ # Rank 2 (2D matrix)
+ ("[[1, 2, 3], [4, 5, 6]]", torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int32)),
+
+ # Rank 3 (3D tensor)
+ ("[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]",
+ torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]], dtype=torch.int32)),
+
+ # Rank 4 (4D tensor)
+ ("[[[[1, 2], [3, 4]]], [[[5, 6], [7, 8]]]]",
+ torch.tensor([[[[1, 2], [3, 4]]], [[[5, 6], [7, 8]]]], dtype=torch.int32)),
+
+ # Rank 5 (5D tensor)
+ ("[[[[[1], [2]], [[3], [4]]]], [[[[5], [6]], [[7], [8]]]]]",
+ torch.tensor([[[[[1], [2]], [[3], [4]]]], [[[[5], [6]], [[7], [8]]]]], dtype=torch.int32)),
+ ]
+
+ def test_create_tensor(self):
+ """Test PyTorch tensor creation from various structured inputs."""
+ for data_str, expected_tensor in self.test_cases:
+ with self.subTest(data=data_str):
+ retval = self.node.f(data_str)[0]
+
+ # Ensure the returned value is a PyTorch tensor
+ self.assertTrue(isinstance(retval, torch.Tensor), f"Expected tensor, got {type(retval)}")
+
+ # Ensure the dtype is int32
+ self.assertEqual(retval.dtype, torch.int32, f"Dtype mismatch for input: {data_str}")
+
+ # Ensure the shape matches
+ self.assertEqual(retval.shape, expected_tensor.shape,
+ f"Shape mismatch for input: {data_str} (Expected {expected_tensor.shape}, got {retval.shape})")
+
+ # Ensure values match
+ torch.testing.assert_close(retval, expected_tensor,
+ msg=f"Value mismatch for input: {data_str}")
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/pytorch_wrapper/pt_to_numpy_test.py b/tests/pytorch_wrapper/pt_to_numpy_test.py
new file mode 100644
index 0000000..be55c92
--- /dev/null
+++ b/tests/pytorch_wrapper/pt_to_numpy_test.py
@@ -0,0 +1,64 @@
+import os
+import sys
+import unittest
+import torch
+import numpy as np
+
+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 pytorch_wrapper.pt_to_numpy import PtToNumpy
+
+class TestPtToNumpy(unittest.TestCase):
+ def setUp(self):
+ """Set up test data."""
+ self.node = PtToNumpy()
+
+ # Test cases covering rank 0 (scalar) to rank 5 tensors
+ self.test_cases = [
+ # Rank 0 (scalar) int32
+ (torch.tensor(12345, dtype=torch.int32), np.array(12345, dtype=np.int32)),
+ # Rank 0 (scalar) float32
+ (torch.tensor(12345.6, dtype=torch.float32), np.array(12345.6, dtype=np.float32)),
+
+ # Rank 1 (1D array) int32
+ (torch.tensor([1, 2, 3], dtype=torch.int32), np.array([1, 2, 3], dtype=np.int32)),
+ # Rank 1 (1D array) float32
+ (torch.tensor([1.1, 2.2, 3.3], dtype=torch.float32), np.array([1.1, 2.2, 3.3], dtype=np.float32)),
+
+ # Rank 2 (2D matrix) int32
+ (torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.int32), np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32)),
+ # Rank 2 (2D matrix) float32
+ (torch.tensor([[1.1, 2.2], [3.3, 4.4]], dtype=torch.float32), np.array([[1.1, 2.2], [3.3, 4.4]], dtype=np.float32)),
+
+ # Rank 3 (3D tensor) int32
+ (torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]], dtype=torch.int32),
+ np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]], dtype=np.int32)),
+ # Rank 3 (3D tensor) float32
+ (torch.tensor([[[1.1, 2.2], [3.3, 4.4]], [[5.5, 6.6], [7.7, 8.8]]], dtype=torch.float32),
+ np.array([[[1.1, 2.2], [3.3, 4.4]], [[5.5, 6.6], [7.7, 8.8]]], dtype=np.float32)),
+ ]
+
+ def test_convert_tensor_to_numpy(self):
+ """Test conversion of PyTorch tensor to NumPy ndarray."""
+ for torch_tensor, expected_array in self.test_cases:
+ with self.subTest(data=torch_tensor):
+ retval = self.node.f(torch_tensor)[0]
+
+ # Ensure the returned value is a NumPy array
+ self.assertTrue(isinstance(retval, np.ndarray), f"Expected ndarray, got {type(retval)}")
+
+ # Ensure the dtype matches
+ self.assertEqual(retval.dtype, expected_array.dtype, f"Dtype mismatch for input: {torch_tensor}")
+
+ # Ensure the shape matches
+ self.assertEqual(retval.shape, expected_array.shape,
+ f"Shape mismatch for input: {torch_tensor} (Expected {expected_array.shape}, got {retval.shape})")
+
+ # Ensure values match
+ np.testing.assert_array_equal(retval, expected_array,
+ f"Value mismatch for input: {torch_tensor}")
+
+if __name__ == "__main__":
+ unittest.main()