sigima 0.0.1.dev0__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sigima/__init__.py +142 -2
- sigima/client/__init__.py +105 -0
- sigima/client/base.py +780 -0
- sigima/client/remote.py +469 -0
- sigima/client/stub.py +814 -0
- sigima/client/utils.py +90 -0
- sigima/config.py +444 -0
- sigima/data/logo/Sigima.svg +135 -0
- sigima/data/tests/annotations.json +798 -0
- sigima/data/tests/curve_fitting/exponential_fit.txt +511 -0
- sigima/data/tests/curve_fitting/gaussian_fit.txt +100 -0
- sigima/data/tests/curve_fitting/piecewiseexponential_fit.txt +1022 -0
- sigima/data/tests/curve_fitting/polynomial_fit.txt +100 -0
- sigima/data/tests/curve_fitting/twohalfgaussian_fit.txt +1000 -0
- sigima/data/tests/curve_formats/bandwidth.txt +201 -0
- sigima/data/tests/curve_formats/boxcar.npy +0 -0
- sigima/data/tests/curve_formats/datetime.txt +1001 -0
- sigima/data/tests/curve_formats/dynamic_parameters.txt +4000 -0
- sigima/data/tests/curve_formats/fw1e2.txt +301 -0
- sigima/data/tests/curve_formats/fwhm.txt +319 -0
- sigima/data/tests/curve_formats/multiple_curves.csv +29 -0
- sigima/data/tests/curve_formats/noised_saw.mat +0 -0
- sigima/data/tests/curve_formats/oscilloscope.csv +111 -0
- sigima/data/tests/curve_formats/other/other2/recursive2.txt +5 -0
- sigima/data/tests/curve_formats/other/recursive1.txt +5 -0
- sigima/data/tests/curve_formats/paracetamol.npy +0 -0
- sigima/data/tests/curve_formats/paracetamol.txt +1010 -0
- sigima/data/tests/curve_formats/paracetamol_dx_dy.csv +1000 -0
- sigima/data/tests/curve_formats/paracetamol_dy.csv +1001 -0
- sigima/data/tests/curve_formats/pulse1.npy +0 -0
- sigima/data/tests/curve_formats/pulse2.npy +0 -0
- sigima/data/tests/curve_formats/simple.txt +5 -0
- sigima/data/tests/curve_formats/spectrum.mca +2139 -0
- sigima/data/tests/curve_formats/square2.npy +0 -0
- sigima/data/tests/curve_formats/step.npy +0 -0
- sigima/data/tests/fabry-perot1.jpg +0 -0
- sigima/data/tests/fabry-perot2.jpg +0 -0
- sigima/data/tests/flower.npy +0 -0
- sigima/data/tests/image_formats/NF 180338201.scor-data +11003 -0
- sigima/data/tests/image_formats/binary_image.npy +0 -0
- sigima/data/tests/image_formats/binary_image.png +0 -0
- sigima/data/tests/image_formats/centroid_test.npy +0 -0
- sigima/data/tests/image_formats/coordinated_text/complex_image.txt +10011 -0
- sigima/data/tests/image_formats/coordinated_text/complex_ref_image.txt +10010 -0
- sigima/data/tests/image_formats/coordinated_text/image.txt +15 -0
- sigima/data/tests/image_formats/coordinated_text/image2.txt +14 -0
- sigima/data/tests/image_formats/coordinated_text/image_no_unit_no_label.txt +14 -0
- sigima/data/tests/image_formats/coordinated_text/image_with_nan.txt +15 -0
- sigima/data/tests/image_formats/coordinated_text/image_with_unit.txt +14 -0
- sigima/data/tests/image_formats/fiber.csv +480 -0
- sigima/data/tests/image_formats/fiber.jpg +0 -0
- sigima/data/tests/image_formats/fiber.png +0 -0
- sigima/data/tests/image_formats/fiber.txt +480 -0
- sigima/data/tests/image_formats/gaussian_spot_with_noise.npy +0 -0
- sigima/data/tests/image_formats/mr-brain.dcm +0 -0
- sigima/data/tests/image_formats/noised_gaussian.mat +0 -0
- sigima/data/tests/image_formats/sif_reader/nd_lum_image_no_glue.sif +0 -0
- sigima/data/tests/image_formats/sif_reader/raman1.sif +0 -0
- sigima/data/tests/image_formats/tiling.txt +10 -0
- sigima/data/tests/image_formats/uint16.tiff +0 -0
- sigima/data/tests/image_formats/uint8.tiff +0 -0
- sigima/data/tests/laser_beam/TEM00_z_13.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_18.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_23.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_30.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_35.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_40.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_45.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_50.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_55.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_60.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_65.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_70.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_75.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_80.jpg +0 -0
- sigima/enums.py +195 -0
- sigima/io/__init__.py +123 -0
- sigima/io/base.py +311 -0
- sigima/io/common/__init__.py +5 -0
- sigima/io/common/basename.py +164 -0
- sigima/io/common/converters.py +189 -0
- sigima/io/common/objmeta.py +181 -0
- sigima/io/common/textreader.py +58 -0
- sigima/io/convenience.py +157 -0
- sigima/io/enums.py +17 -0
- sigima/io/ftlab.py +395 -0
- sigima/io/image/__init__.py +9 -0
- sigima/io/image/base.py +177 -0
- sigima/io/image/formats.py +1016 -0
- sigima/io/image/funcs.py +414 -0
- sigima/io/signal/__init__.py +9 -0
- sigima/io/signal/base.py +129 -0
- sigima/io/signal/formats.py +290 -0
- sigima/io/signal/funcs.py +723 -0
- sigima/objects/__init__.py +260 -0
- sigima/objects/base.py +937 -0
- sigima/objects/image/__init__.py +88 -0
- sigima/objects/image/creation.py +556 -0
- sigima/objects/image/object.py +524 -0
- sigima/objects/image/roi.py +904 -0
- sigima/objects/scalar/__init__.py +57 -0
- sigima/objects/scalar/common.py +215 -0
- sigima/objects/scalar/geometry.py +502 -0
- sigima/objects/scalar/table.py +784 -0
- sigima/objects/shape.py +290 -0
- sigima/objects/signal/__init__.py +133 -0
- sigima/objects/signal/constants.py +27 -0
- sigima/objects/signal/creation.py +1428 -0
- sigima/objects/signal/object.py +444 -0
- sigima/objects/signal/roi.py +274 -0
- sigima/params.py +405 -0
- sigima/proc/__init__.py +96 -0
- sigima/proc/base.py +381 -0
- sigima/proc/decorator.py +330 -0
- sigima/proc/image/__init__.py +513 -0
- sigima/proc/image/arithmetic.py +335 -0
- sigima/proc/image/base.py +260 -0
- sigima/proc/image/detection.py +519 -0
- sigima/proc/image/edges.py +329 -0
- sigima/proc/image/exposure.py +406 -0
- sigima/proc/image/extraction.py +458 -0
- sigima/proc/image/filtering.py +219 -0
- sigima/proc/image/fourier.py +147 -0
- sigima/proc/image/geometry.py +661 -0
- sigima/proc/image/mathops.py +340 -0
- sigima/proc/image/measurement.py +195 -0
- sigima/proc/image/morphology.py +155 -0
- sigima/proc/image/noise.py +107 -0
- sigima/proc/image/preprocessing.py +182 -0
- sigima/proc/image/restoration.py +235 -0
- sigima/proc/image/threshold.py +217 -0
- sigima/proc/image/transformations.py +393 -0
- sigima/proc/signal/__init__.py +376 -0
- sigima/proc/signal/analysis.py +206 -0
- sigima/proc/signal/arithmetic.py +551 -0
- sigima/proc/signal/base.py +262 -0
- sigima/proc/signal/extraction.py +60 -0
- sigima/proc/signal/features.py +310 -0
- sigima/proc/signal/filtering.py +484 -0
- sigima/proc/signal/fitting.py +276 -0
- sigima/proc/signal/fourier.py +259 -0
- sigima/proc/signal/mathops.py +420 -0
- sigima/proc/signal/processing.py +580 -0
- sigima/proc/signal/stability.py +175 -0
- sigima/proc/title_formatting.py +227 -0
- sigima/proc/validation.py +272 -0
- sigima/tests/__init__.py +7 -0
- sigima/tests/common/__init__.py +0 -0
- sigima/tests/common/arithmeticparam_unit_test.py +26 -0
- sigima/tests/common/basename_unit_test.py +126 -0
- sigima/tests/common/client_unit_test.py +412 -0
- sigima/tests/common/converters_unit_test.py +77 -0
- sigima/tests/common/decorator_unit_test.py +176 -0
- sigima/tests/common/examples_unit_test.py +104 -0
- sigima/tests/common/kernel_normalization_unit_test.py +242 -0
- sigima/tests/common/roi_basic_unit_test.py +73 -0
- sigima/tests/common/roi_geometry_unit_test.py +171 -0
- sigima/tests/common/scalar_builder_unit_test.py +142 -0
- sigima/tests/common/scalar_unit_test.py +991 -0
- sigima/tests/common/shape_unit_test.py +183 -0
- sigima/tests/common/stat_unit_test.py +138 -0
- sigima/tests/common/title_formatting_unit_test.py +338 -0
- sigima/tests/common/tools_coordinates_unit_test.py +60 -0
- sigima/tests/common/transformations_unit_test.py +178 -0
- sigima/tests/common/validation_unit_test.py +205 -0
- sigima/tests/conftest.py +129 -0
- sigima/tests/data.py +998 -0
- sigima/tests/env.py +280 -0
- sigima/tests/guiutils.py +163 -0
- sigima/tests/helpers.py +532 -0
- sigima/tests/image/__init__.py +28 -0
- sigima/tests/image/binning_unit_test.py +128 -0
- sigima/tests/image/blob_detection_unit_test.py +312 -0
- sigima/tests/image/centroid_unit_test.py +170 -0
- sigima/tests/image/check_2d_array_unit_test.py +63 -0
- sigima/tests/image/contour_unit_test.py +172 -0
- sigima/tests/image/convolution_unit_test.py +178 -0
- sigima/tests/image/datatype_unit_test.py +67 -0
- sigima/tests/image/edges_unit_test.py +155 -0
- sigima/tests/image/enclosingcircle_unit_test.py +88 -0
- sigima/tests/image/exposure_unit_test.py +223 -0
- sigima/tests/image/fft2d_unit_test.py +189 -0
- sigima/tests/image/filtering_unit_test.py +166 -0
- sigima/tests/image/geometry_unit_test.py +654 -0
- sigima/tests/image/hough_circle_unit_test.py +147 -0
- sigima/tests/image/imageobj_unit_test.py +737 -0
- sigima/tests/image/morphology_unit_test.py +71 -0
- sigima/tests/image/noise_unit_test.py +57 -0
- sigima/tests/image/offset_correction_unit_test.py +72 -0
- sigima/tests/image/operation_unit_test.py +518 -0
- sigima/tests/image/peak2d_limits_unit_test.py +41 -0
- sigima/tests/image/peak2d_unit_test.py +133 -0
- sigima/tests/image/profile_unit_test.py +159 -0
- sigima/tests/image/projections_unit_test.py +121 -0
- sigima/tests/image/restoration_unit_test.py +141 -0
- sigima/tests/image/roi2dparam_unit_test.py +53 -0
- sigima/tests/image/roi_advanced_unit_test.py +588 -0
- sigima/tests/image/roi_grid_unit_test.py +279 -0
- sigima/tests/image/spectrum2d_unit_test.py +40 -0
- sigima/tests/image/threshold_unit_test.py +91 -0
- sigima/tests/io/__init__.py +0 -0
- sigima/tests/io/addnewformat_unit_test.py +125 -0
- sigima/tests/io/convenience_funcs_unit_test.py +470 -0
- sigima/tests/io/coordinated_text_format_unit_test.py +495 -0
- sigima/tests/io/datetime_csv_unit_test.py +198 -0
- sigima/tests/io/imageio_formats_test.py +41 -0
- sigima/tests/io/ioregistry_unit_test.py +69 -0
- sigima/tests/io/objmeta_unit_test.py +87 -0
- sigima/tests/io/readobj_unit_test.py +130 -0
- sigima/tests/io/readwriteobj_unit_test.py +67 -0
- sigima/tests/signal/__init__.py +0 -0
- sigima/tests/signal/analysis_unit_test.py +135 -0
- sigima/tests/signal/check_1d_arrays_unit_test.py +169 -0
- sigima/tests/signal/convolution_unit_test.py +404 -0
- sigima/tests/signal/datetime_unit_test.py +176 -0
- sigima/tests/signal/fft1d_unit_test.py +303 -0
- sigima/tests/signal/filters_unit_test.py +403 -0
- sigima/tests/signal/fitting_unit_test.py +929 -0
- sigima/tests/signal/fwhm_unit_test.py +111 -0
- sigima/tests/signal/noise_unit_test.py +128 -0
- sigima/tests/signal/offset_correction_unit_test.py +34 -0
- sigima/tests/signal/operation_unit_test.py +489 -0
- sigima/tests/signal/peakdetection_unit_test.py +145 -0
- sigima/tests/signal/processing_unit_test.py +657 -0
- sigima/tests/signal/pulse/__init__.py +112 -0
- sigima/tests/signal/pulse/crossing_times_unit_test.py +123 -0
- sigima/tests/signal/pulse/plateau_detection_unit_test.py +102 -0
- sigima/tests/signal/pulse/pulse_unit_test.py +1824 -0
- sigima/tests/signal/roi_advanced_unit_test.py +392 -0
- sigima/tests/signal/signalobj_unit_test.py +603 -0
- sigima/tests/signal/stability_unit_test.py +431 -0
- sigima/tests/signal/uncertainty_unit_test.py +611 -0
- sigima/tests/vistools.py +1030 -0
- sigima/tools/__init__.py +59 -0
- sigima/tools/checks.py +290 -0
- sigima/tools/coordinates.py +308 -0
- sigima/tools/datatypes.py +26 -0
- sigima/tools/image/__init__.py +97 -0
- sigima/tools/image/detection.py +451 -0
- sigima/tools/image/exposure.py +77 -0
- sigima/tools/image/extraction.py +48 -0
- sigima/tools/image/fourier.py +260 -0
- sigima/tools/image/geometry.py +190 -0
- sigima/tools/image/preprocessing.py +165 -0
- sigima/tools/signal/__init__.py +86 -0
- sigima/tools/signal/dynamic.py +254 -0
- sigima/tools/signal/features.py +135 -0
- sigima/tools/signal/filtering.py +171 -0
- sigima/tools/signal/fitting.py +1171 -0
- sigima/tools/signal/fourier.py +466 -0
- sigima/tools/signal/interpolation.py +70 -0
- sigima/tools/signal/peakdetection.py +126 -0
- sigima/tools/signal/pulse.py +1626 -0
- sigima/tools/signal/scaling.py +50 -0
- sigima/tools/signal/stability.py +258 -0
- sigima/tools/signal/windowing.py +90 -0
- sigima/worker.py +79 -0
- sigima-1.0.0.dist-info/METADATA +233 -0
- sigima-1.0.0.dist-info/RECORD +262 -0
- {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/licenses/LICENSE +29 -29
- sigima-0.0.1.dev0.dist-info/METADATA +0 -60
- sigima-0.0.1.dev0.dist-info/RECORD +0 -6
- {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/WHEEL +0 -0
- {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/top_level.txt +0 -0
sigima/io/image/base.py
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Image I/O registry
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import abc
|
|
10
|
+
import os.path as osp
|
|
11
|
+
from typing import Sequence
|
|
12
|
+
|
|
13
|
+
import numpy as np
|
|
14
|
+
|
|
15
|
+
from sigima.config import _
|
|
16
|
+
from sigima.io.base import BaseIORegistry, FormatBase
|
|
17
|
+
from sigima.objects.image import ImageObj, create_image
|
|
18
|
+
from sigima.worker import CallbackWorkerProtocol
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ImageIORegistry(BaseIORegistry):
|
|
22
|
+
"""Metaclass for registering image I/O handler classes"""
|
|
23
|
+
|
|
24
|
+
REGISTRY_INFO: str = _("Image I/O formats")
|
|
25
|
+
|
|
26
|
+
_io_format_instances: list[ImageFormatBase] = []
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ImageFormatBaseMeta(ImageIORegistry, abc.ABCMeta):
|
|
30
|
+
"""Mixed metaclass to avoid conflicts"""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ImageFormatBase(abc.ABC, FormatBase, metaclass=ImageFormatBaseMeta):
|
|
34
|
+
"""Base image format object.
|
|
35
|
+
|
|
36
|
+
This class is used to define the interface for image I/O formats.
|
|
37
|
+
It is an abstract base class that defines the methods that must be
|
|
38
|
+
implemented by any image format class.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
@abc.abstractmethod
|
|
42
|
+
def read(
|
|
43
|
+
self, filename: str, worker: CallbackWorkerProtocol | None = None
|
|
44
|
+
) -> Sequence[ImageObj]:
|
|
45
|
+
"""Read list of image objects from file
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
filename: File name
|
|
49
|
+
worker: Callback worker object
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
List of image objects
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
@abc.abstractmethod
|
|
56
|
+
def write(self, filename: str, obj: ImageObj) -> None:
|
|
57
|
+
"""Write data to file
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
filename: file name
|
|
61
|
+
obj: native object (signal or image)
|
|
62
|
+
|
|
63
|
+
Raises:
|
|
64
|
+
NotImplementedError: if format is not supported
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class SingleImageFormatBase(ImageFormatBase):
|
|
69
|
+
"""Base image format object for single image (e.g., TIFF, PNG, etc.)."""
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def create_object(filename: str, index: int | None = None) -> ImageObj:
|
|
73
|
+
"""Create empty object
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
filename: File name
|
|
77
|
+
index: Index of object in file
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Image object
|
|
81
|
+
"""
|
|
82
|
+
name = osp.basename(filename)
|
|
83
|
+
if index is not None:
|
|
84
|
+
name += f" {index:02d}"
|
|
85
|
+
return create_image(name, metadata={"source": filename})
|
|
86
|
+
|
|
87
|
+
def read(
|
|
88
|
+
self, filename: str, worker: CallbackWorkerProtocol | None = None
|
|
89
|
+
) -> list[ImageObj]:
|
|
90
|
+
"""Read list of image objects from file
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
filename: File name
|
|
94
|
+
worker: Callback worker object
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
List of image objects
|
|
98
|
+
"""
|
|
99
|
+
# Default implementation covers the case of a single image:
|
|
100
|
+
obj = self.create_object(filename)
|
|
101
|
+
obj.data = self.read_data(filename)
|
|
102
|
+
unique_values = np.unique(obj.data)
|
|
103
|
+
if len(unique_values) == 2:
|
|
104
|
+
# Binary image: set LUT range to unique values
|
|
105
|
+
obj.zscalemin, obj.zscalemax = unique_values.tolist()
|
|
106
|
+
return [obj]
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
@abc.abstractmethod
|
|
110
|
+
def read_data(filename: str) -> np.ndarray:
|
|
111
|
+
"""Read data and return it
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
filename: File name
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Image array data
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
def write(self, filename: str, obj: ImageObj) -> None:
|
|
121
|
+
"""Write data to file
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
filename: file name
|
|
125
|
+
obj: native object (signal or image)
|
|
126
|
+
|
|
127
|
+
Raises:
|
|
128
|
+
NotImplementedError: if format is not supported
|
|
129
|
+
"""
|
|
130
|
+
data = obj.data
|
|
131
|
+
self.write_data(filename, data)
|
|
132
|
+
|
|
133
|
+
@staticmethod
|
|
134
|
+
def write_data(filename: str, data: np.ndarray) -> None:
|
|
135
|
+
"""Write data to file
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
filename: File name
|
|
139
|
+
data: Image array data
|
|
140
|
+
"""
|
|
141
|
+
raise NotImplementedError(f"Writing to {filename} is not supported")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class MultipleImagesFormatBase(SingleImageFormatBase):
|
|
145
|
+
"""Base image format object for multiple images (e.g., SIF or SPE).
|
|
146
|
+
|
|
147
|
+
Works with read function that returns a NumPy array of 3 dimensions, where
|
|
148
|
+
the first dimension is the number of images.
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
def read(
|
|
152
|
+
self, filename: str, worker: CallbackWorkerProtocol | None = None
|
|
153
|
+
) -> list[ImageObj]:
|
|
154
|
+
"""Read list of image objects from file
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
filename: File name
|
|
158
|
+
worker: Callback worker object
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
List of image objects
|
|
162
|
+
"""
|
|
163
|
+
data = self.read_data(filename)
|
|
164
|
+
if len(data.shape) == 3:
|
|
165
|
+
objlist = []
|
|
166
|
+
for idx in range(data.shape[0]):
|
|
167
|
+
obj = self.create_object(filename, index=idx)
|
|
168
|
+
obj.data = data[idx, ::]
|
|
169
|
+
objlist.append(obj)
|
|
170
|
+
if worker is not None:
|
|
171
|
+
worker.set_progress((idx + 1) / data.shape[0])
|
|
172
|
+
if worker.was_canceled():
|
|
173
|
+
break
|
|
174
|
+
return objlist
|
|
175
|
+
obj = self.create_object(filename)
|
|
176
|
+
obj.data = data
|
|
177
|
+
return [obj]
|