pipelet 0.0.2__tar.gz → 0.0.3__tar.gz

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.
Files changed (49) hide show
  1. {pipelet-0.0.2 → pipelet-0.0.3}/PKG-INFO +30 -10
  2. {pipelet-0.0.2 → pipelet-0.0.3}/README.md +29 -9
  3. pipelet-0.0.3/pipelet/decarators/__init__.py +3 -0
  4. pipelet-0.0.3/pipelet/decarators/logging_decorator.py +65 -0
  5. pipelet-0.0.3/pipelet/decarators/option_decorator.py +36 -0
  6. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/etl/extract/http/http_extractor.py +0 -4
  7. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/etl/transform/csv/reader.py +0 -2
  8. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/etl/transform/json/reader.py +0 -2
  9. pipelet-0.0.3/pipelet/etl/transform/unzip/__init__.py +3 -0
  10. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/etl/transform/unzip/base.py +2 -5
  11. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/operations/operations.py +85 -7
  12. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/processors/meta.py +2 -0
  13. {pipelet-0.0.2 → pipelet-0.0.3}/pyproject.toml +1 -1
  14. pipelet-0.0.2/pipelet/etl/transform/unzip/__init__.py +0 -3
  15. {pipelet-0.0.2 → pipelet-0.0.3}/LICENSE +0 -0
  16. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/__init__.py +0 -0
  17. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/etl/__init__.py +0 -0
  18. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/etl/extract/__init__.py +0 -0
  19. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/etl/extract/http/__init__.py +0 -0
  20. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/etl/transform/__init__.py +0 -0
  21. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/etl/transform/csv/__init__.py +0 -0
  22. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/etl/transform/json/__init__.py +0 -0
  23. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/exceptions/__init__.py +0 -0
  24. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/exceptions/base.py +0 -0
  25. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/exceptions/csv_processor.py +0 -0
  26. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/exceptions/download_processor.py +0 -0
  27. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/exceptions/file_system.py +0 -0
  28. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/exceptions/unzip_processor.py +0 -0
  29. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/factories/__init__.py +0 -0
  30. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/factories/exceptions_factory.py +0 -0
  31. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/factories/file_system_factory.py +0 -0
  32. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/log/__init__.py +0 -0
  33. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/log/logger.py +0 -0
  34. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/operations/__init__.py +0 -0
  35. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/operations/pipeline.py +0 -0
  36. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/processors/__init__.py +0 -0
  37. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/processors/abc.py +0 -0
  38. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/processors/base.py +0 -0
  39. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/processors/chain_processors/__init__.py +0 -0
  40. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/processors/chain_processors/base.py +0 -0
  41. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/processors/file_system/__init__.py +0 -0
  42. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/processors/file_system/base.py +0 -0
  43. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/processors/file_system/file_system_types.py +0 -0
  44. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/processors/mixins.py +0 -0
  45. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/processors/processor_types.py +0 -0
  46. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/processors/retry_processor.py +0 -0
  47. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/processors/splitter_processor.py +0 -0
  48. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/utils/__init__.py +0 -0
  49. {pipelet-0.0.2 → pipelet-0.0.3}/pipelet/utils/common.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pipelet
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary:
5
5
  Author: Daniel Naumowich
6
6
  Author-email: cskteam4@gmail.com
@@ -69,7 +69,7 @@ A processor for parsing CSV files using the `pandas` library. It supports numero
69
69
  ### 7. **JsonParser**
70
70
  A processor for parsing JSON data from strings or files into Python dictionaries. It supports configuring how numbers, constants (e.g., NaN), and JSON objects are handled with custom functions.
71
71
 
72
- ### 8. **BaseUnzipProcessor**
72
+ ### 8. **UnzipProcessor**
73
73
  A processor for extracting files from `.zip` archives. It supports extracting data into files, managing chunk sizes, and deleting the original archive after processing.
74
74
 
75
75
  ### 9. **RetryProcessor**
@@ -91,7 +91,7 @@ A processor designed to handle transient errors by retrying operations based on
91
91
  from pipelet.processors.http import HttpDataExtractProcessor
92
92
  from pipelet.processors.csv_parser import CsvParser
93
93
  from pipelet.processors.json_parser import JsonParser
94
- from pipelet.processors.unzip import BaseUnzipProcessor
94
+ from pipelet.processors.unzip import UnzipProcessor
95
95
  from pipelet.processors.file_system import AbstractFileSystemManager
96
96
 
97
97
  # Create file system manager
@@ -101,7 +101,7 @@ file_system_manager = AbstractFileSystemManager()
101
101
  http_processor = HttpDataExtractProcessor(file_system_manager)
102
102
  csv_parser = CsvParser(file_system_manager)
103
103
  json_parser = JsonParser(file_system_manager)
104
- unzip_processor = BaseUnzipProcessor(file_system_manager)
104
+ unzip_processor = UnzipProcessor(file_system_manager)
105
105
 
106
106
  # Create processor chain
107
107
  http_processor.set_next(csv_parser).set_next(json_parser).set_next(unzip_processor)
@@ -118,7 +118,7 @@ for output in http_processor.process(input_data):
118
118
  from pipelet.processors.http import HttpDataExtractProcessor
119
119
  from pipelet.processors.csv_parser import CsvParser
120
120
  from pipelet.processors.json_parser import JsonParser
121
- from pipelet.processors.unzip import BaseUnzipProcessor
121
+ from pipelet.processors.unzip import UnzipProcessor
122
122
  from pipelet.processors.file_system import AbstractFileSystemManager
123
123
 
124
124
  # Create file system manager
@@ -128,7 +128,7 @@ file_system_manager = AbstractFileSystemManager()
128
128
  http_processor = HttpDataExtractProcessor(file_system_manager)
129
129
  csv_parser = CsvParser(file_system_manager)
130
130
  json_parser = JsonParser(file_system_manager)
131
- unzip_processor = BaseUnzipProcessor(file_system_manager)
131
+ unzip_processor = UnzipProcessor(file_system_manager)
132
132
 
133
133
  # Create processor chain using `>>`
134
134
  pipeline = http_processor >> csv_parser >> json_parser >> unzip_processor
@@ -147,23 +147,35 @@ from pipelet.processors.file_system import FileModeEnum
147
147
 
148
148
  def main():
149
149
  # Define the pipeline with parallel processing for parsing and unzipping
150
+
150
151
  pipeline = [
151
152
  Op(
152
153
  BaseOpEnum.downloading,
153
154
  kwargs={
154
- "file_system_manager": {...},
155
+ "file_system_manager": {
156
+ "path": ..., # Here can be your custom file system manager (as an example S3)
157
+ "kwargs": {...},
158
+ },
155
159
  "retry_args": {
160
+ "retry_processor": ..., # Here can be your custom retry processor
156
161
  "max_retries": 3,
157
162
  "delay": 1,
158
163
  "delay_step": 1,
159
164
  "retry_with_white_exc": True,
160
165
  },
166
+ "logging_args": {
167
+ "logger": ..., # Here can be your custom logger
168
+ "logging": True, # Logging intup data
169
+ },
161
170
  }
162
171
  ),
163
172
  Op(
164
173
  BaseOpEnum.upzip,
165
174
  kwargs={
166
- "file_system_manager": {...}
175
+ "file_system_manager": {
176
+ "path": ..., # Here can be your custom file system manager (as an example S3)
177
+ "kwargs": {...},
178
+ },
167
179
  }
168
180
  ),
169
181
  OpAny(
@@ -171,13 +183,19 @@ def main():
171
183
  Op(
172
184
  BaseOpEnum.json_parsing,
173
185
  kwargs={
174
- "file_system_manager": {...}
186
+ "file_system_manager": {
187
+ "path": ..., # Here can be your custom file system manager (as an example S3)
188
+ "kwargs": {...},
189
+ },
175
190
  }
176
191
  ),
177
192
  Op(
178
193
  BaseOpEnum.csv_parsing,
179
194
  kwargs={
180
- "file_system_manager": {...},
195
+ "file_system_manager": {
196
+ "path": ..., # Here can be your custom file system manager (as an example S3)
197
+ "kwargs": {...},
198
+ },,
181
199
  "white_exceptions": [
182
200
  TypeError,
183
201
  BaseExceptionsEnum.csv_parsing_error,
@@ -213,8 +231,10 @@ The library is developer-friendly, making it easy to extend and integrate custom
213
231
 
214
232
  ```python
215
233
  from pipelet.processors.base import BaseProcessor
234
+ from pipelet.decorators import logging_decorator
216
235
 
217
236
  class CustomProcessor(BaseProcessor):
237
+ @logging_decorator(custom_logger=...) # If you need this you can use either a custom logger or a default logger
218
238
  def process(self, input_data):
219
239
  # Custom data processing logic
220
240
  yield transformed_data
@@ -49,7 +49,7 @@ A processor for parsing CSV files using the `pandas` library. It supports numero
49
49
  ### 7. **JsonParser**
50
50
  A processor for parsing JSON data from strings or files into Python dictionaries. It supports configuring how numbers, constants (e.g., NaN), and JSON objects are handled with custom functions.
51
51
 
52
- ### 8. **BaseUnzipProcessor**
52
+ ### 8. **UnzipProcessor**
53
53
  A processor for extracting files from `.zip` archives. It supports extracting data into files, managing chunk sizes, and deleting the original archive after processing.
54
54
 
55
55
  ### 9. **RetryProcessor**
@@ -71,7 +71,7 @@ A processor designed to handle transient errors by retrying operations based on
71
71
  from pipelet.processors.http import HttpDataExtractProcessor
72
72
  from pipelet.processors.csv_parser import CsvParser
73
73
  from pipelet.processors.json_parser import JsonParser
74
- from pipelet.processors.unzip import BaseUnzipProcessor
74
+ from pipelet.processors.unzip import UnzipProcessor
75
75
  from pipelet.processors.file_system import AbstractFileSystemManager
76
76
 
77
77
  # Create file system manager
@@ -81,7 +81,7 @@ file_system_manager = AbstractFileSystemManager()
81
81
  http_processor = HttpDataExtractProcessor(file_system_manager)
82
82
  csv_parser = CsvParser(file_system_manager)
83
83
  json_parser = JsonParser(file_system_manager)
84
- unzip_processor = BaseUnzipProcessor(file_system_manager)
84
+ unzip_processor = UnzipProcessor(file_system_manager)
85
85
 
86
86
  # Create processor chain
87
87
  http_processor.set_next(csv_parser).set_next(json_parser).set_next(unzip_processor)
@@ -98,7 +98,7 @@ for output in http_processor.process(input_data):
98
98
  from pipelet.processors.http import HttpDataExtractProcessor
99
99
  from pipelet.processors.csv_parser import CsvParser
100
100
  from pipelet.processors.json_parser import JsonParser
101
- from pipelet.processors.unzip import BaseUnzipProcessor
101
+ from pipelet.processors.unzip import UnzipProcessor
102
102
  from pipelet.processors.file_system import AbstractFileSystemManager
103
103
 
104
104
  # Create file system manager
@@ -108,7 +108,7 @@ file_system_manager = AbstractFileSystemManager()
108
108
  http_processor = HttpDataExtractProcessor(file_system_manager)
109
109
  csv_parser = CsvParser(file_system_manager)
110
110
  json_parser = JsonParser(file_system_manager)
111
- unzip_processor = BaseUnzipProcessor(file_system_manager)
111
+ unzip_processor = UnzipProcessor(file_system_manager)
112
112
 
113
113
  # Create processor chain using `>>`
114
114
  pipeline = http_processor >> csv_parser >> json_parser >> unzip_processor
@@ -127,23 +127,35 @@ from pipelet.processors.file_system import FileModeEnum
127
127
 
128
128
  def main():
129
129
  # Define the pipeline with parallel processing for parsing and unzipping
130
+
130
131
  pipeline = [
131
132
  Op(
132
133
  BaseOpEnum.downloading,
133
134
  kwargs={
134
- "file_system_manager": {...},
135
+ "file_system_manager": {
136
+ "path": ..., # Here can be your custom file system manager (as an example S3)
137
+ "kwargs": {...},
138
+ },
135
139
  "retry_args": {
140
+ "retry_processor": ..., # Here can be your custom retry processor
136
141
  "max_retries": 3,
137
142
  "delay": 1,
138
143
  "delay_step": 1,
139
144
  "retry_with_white_exc": True,
140
145
  },
146
+ "logging_args": {
147
+ "logger": ..., # Here can be your custom logger
148
+ "logging": True, # Logging intup data
149
+ },
141
150
  }
142
151
  ),
143
152
  Op(
144
153
  BaseOpEnum.upzip,
145
154
  kwargs={
146
- "file_system_manager": {...}
155
+ "file_system_manager": {
156
+ "path": ..., # Here can be your custom file system manager (as an example S3)
157
+ "kwargs": {...},
158
+ },
147
159
  }
148
160
  ),
149
161
  OpAny(
@@ -151,13 +163,19 @@ def main():
151
163
  Op(
152
164
  BaseOpEnum.json_parsing,
153
165
  kwargs={
154
- "file_system_manager": {...}
166
+ "file_system_manager": {
167
+ "path": ..., # Here can be your custom file system manager (as an example S3)
168
+ "kwargs": {...},
169
+ },
155
170
  }
156
171
  ),
157
172
  Op(
158
173
  BaseOpEnum.csv_parsing,
159
174
  kwargs={
160
- "file_system_manager": {...},
175
+ "file_system_manager": {
176
+ "path": ..., # Here can be your custom file system manager (as an example S3)
177
+ "kwargs": {...},
178
+ },,
161
179
  "white_exceptions": [
162
180
  TypeError,
163
181
  BaseExceptionsEnum.csv_parsing_error,
@@ -193,8 +211,10 @@ The library is developer-friendly, making it easy to extend and integrate custom
193
211
 
194
212
  ```python
195
213
  from pipelet.processors.base import BaseProcessor
214
+ from pipelet.decorators import logging_decorator
196
215
 
197
216
  class CustomProcessor(BaseProcessor):
217
+ @logging_decorator(custom_logger=...) # If you need this you can use either a custom logger or a default logger
198
218
  def process(self, input_data):
199
219
  # Custom data processing logic
200
220
  yield transformed_data
@@ -0,0 +1,3 @@
1
+ from pipelet.decarators.logging_decorator import logging_decorator
2
+
3
+ __all__ = ("logging_decorator",)
@@ -0,0 +1,65 @@
1
+ from functools import wraps
2
+ from typing import Any, Callable, Generator, Optional, Union
3
+
4
+ from pipelet.decarators.option_decorator import prepare_gen_processor
5
+ from pipelet.log import logger_factory
6
+ from pipelet.processors.base import BaseProcessor
7
+
8
+ default_logger = logger_factory()
9
+
10
+
11
+ def logging_decorator(
12
+ func: Callable[
13
+ ...,
14
+ Generator[Any, Any, Optional[Any]],
15
+ ],
16
+ custom_logger: Optional[Any] = None,
17
+ ) -> Callable[
18
+ ...,
19
+ Generator[Any, Any, Optional[Any]],
20
+ ]:
21
+ """
22
+ A decorator that adds logging functionality to a processor's `process` method.
23
+
24
+ Logs the processor's class name, arguments, and keyword arguments each time
25
+ the `process` method is invoked. Supports generator functions and normalizes
26
+ calls to ensure compatibility with bound and unbound methods.
27
+
28
+ Args:
29
+ func (Callable): The generator function (`process` method) to wrap.
30
+ custom_logger (Optional[Any]): Custom logger to use. Defaults to the global logger.
31
+
32
+ Returns:
33
+ Callable: A wrapped generator function with logging functionality.
34
+
35
+ Example:
36
+ ```
37
+ @logging_decorator
38
+ def process(self, *args, **kwargs):
39
+ yield ...
40
+ ```
41
+ """
42
+ logger_to_use = (
43
+ custom_logger or default_logger
44
+ ) # Используем кастомный логгер, если он передан
45
+
46
+ @wraps(func)
47
+ def wrapper(
48
+ obj: BaseProcessor[Any, Any, Any, Any],
49
+ *args,
50
+ **kwargs,
51
+ ) -> Generator[
52
+ Any,
53
+ Any,
54
+ Union[Any, None],
55
+ ]:
56
+ logger_to_use.info(
57
+ f"Processor: {obj.__class__.__name__}, args: {args}, kwargs: {kwargs}"
58
+ )
59
+ generator = prepare_gen_processor(
60
+ func, obj, *args, **kwargs
61
+ ) # Normalized call
62
+ while True:
63
+ yield next(generator)
64
+
65
+ return wrapper
@@ -0,0 +1,36 @@
1
+ import types
2
+ from typing import Any, Callable, Generator
3
+
4
+ from pipelet.log import logger_factory
5
+ from pipelet.processors.base import BaseProcessor
6
+
7
+ logger = logger_factory()
8
+
9
+
10
+ def prepare_gen_processor(
11
+ func: Callable[..., Generator[Any, Any, Any]],
12
+ obj: BaseProcessor[Any, Any, Any, Any],
13
+ *args,
14
+ **kwargs
15
+ ) -> Generator[Any, Any, Any]:
16
+ """
17
+ A utility function to prepare and execute generator-based processors.
18
+
19
+ This function normalizes the invocation of generator functions or methods.
20
+ If the provided callable `func` is a bound method, it is invoked directly
21
+ with `*args` and `**kwargs`. If `func` is an unbound function, it is
22
+ invoked with `obj` passed as the first argument along with `*args` and `**kwargs`.
23
+
24
+ Args:
25
+ func (Callable): The generator function or method to be executed.
26
+ obj (BaseProcessor): The processor object, passed explicitly for unbound functions.
27
+ *args: Positional arguments to pass to the generator.
28
+ **kwargs: Keyword arguments to pass to the generator.
29
+
30
+ Returns:
31
+ Generator: The generator object produced by executing `func`.
32
+
33
+ """
34
+ if isinstance(func, types.MethodType):
35
+ return func(*args, **kwargs)
36
+ return func(obj, *args, **kwargs)
@@ -102,7 +102,6 @@ class HttpDataExtractProcessor(
102
102
  Yields:
103
103
  PathLike | str: The file name or path of the downloaded file.
104
104
  """
105
- logger.debug(f"Starting download from {input_data}")
106
105
  resp = httpx.get(
107
106
  input_data,
108
107
  params=self._params,
@@ -125,7 +124,6 @@ class HttpDataExtractProcessor(
125
124
  resp.content,
126
125
  )
127
126
 
128
- logger.debug("Download was successful")
129
127
  if self._next is not None:
130
128
  yield from self._next.process(file_name)
131
129
  else:
@@ -218,7 +216,6 @@ class HttpxStreamDownloadProcessor(
218
216
  Yields:
219
217
  PathLike[str] | str: The file path of the downloaded file.
220
218
  """
221
- logger.debug(f"Starting download from {input_data}")
222
219
  with httpx.stream(
223
220
  method=self._method,
224
221
  url=input_data,
@@ -238,7 +235,6 @@ class HttpxStreamDownloadProcessor(
238
235
  if chunk:
239
236
  self._file_system_manager.append_to_file(file_path, chunk)
240
237
 
241
- logger.debug(f"Download was successful: {file_path}")
242
238
  if self._next is not None:
243
239
  yield from self._next.process(file_path)
244
240
  else:
@@ -227,7 +227,6 @@ class CsvParser(
227
227
  Raises:
228
228
  CsvParsingError: If parsing fails.
229
229
  """
230
- logger.debug(f"Start parsing: {input_data}")
231
230
  suffix = Path(input_data).suffix
232
231
  if suffix != ".csv":
233
232
  raise CsvParsingError(
@@ -292,7 +291,6 @@ class CsvParser(
292
291
  yield records
293
292
  if self._auto_delete:
294
293
  self._file_system_manager.delete_file(input_data)
295
- logger.debug(f"Successful parsing: {input_data}")
296
294
 
297
295
  def __str__(self) -> str:
298
296
  return (
@@ -90,12 +90,10 @@ class JsonParser(
90
90
  """
91
91
  # Read content using the file system manager
92
92
  content = self._file_system_manager.read_file(input_data)
93
- logger.debug("Read content from %s", input_data)
94
93
 
95
94
  # Parse the JSON content with custom arguments
96
95
  try:
97
96
  data = json.loads(content, **self._parse_kwargs)
98
- logger.debug(f"JSON {input_data} has parsed successfully")
99
97
  except json.JSONDecodeError as e:
100
98
  logger.error("Failed to parse JSON: %s", e)
101
99
  raise
@@ -0,0 +1,3 @@
1
+ from pipelet.etl.transform.unzip.base import UnzipProcessor
2
+
3
+ __all__ = ("UnzipProcessor",)
@@ -15,7 +15,7 @@ from pipelet.processors.file_system import (
15
15
  logger = logger_factory()
16
16
 
17
17
 
18
- class BaseUnzipProcessor(
18
+ class UnzipProcessor(
19
19
  BaseProcessor[
20
20
  Union[str, PathLike[str]], Union[str, PathLike[str]], None, None
21
21
  ],
@@ -45,7 +45,7 @@ class BaseUnzipProcessor(
45
45
  batch_size: Optional[int] = None,
46
46
  ) -> None:
47
47
  """
48
- Initializes the BaseUnzipProcessor.
48
+ Initializes the UnzipProcessor.
49
49
 
50
50
  Args:
51
51
  file_system_manager (AbstractFileSystemManager): The file system manager for file operations.
@@ -84,7 +84,6 @@ class BaseUnzipProcessor(
84
84
  )
85
85
 
86
86
  file_path = self._file_system_manager.get_path(input_data)
87
- logger.debug(f"Starting to unzip {input_data}")
88
87
 
89
88
  unzip_files: List[Union[str, PathLike[str]]] = []
90
89
  with zipfile.ZipFile(file_path, FileModeEnum.READ) as zip_ref:
@@ -107,8 +106,6 @@ class BaseUnzipProcessor(
107
106
 
108
107
  unzip_files.append(extracted_file_path)
109
108
 
110
- logger.debug("Unzipping was successful")
111
-
112
109
  if self._next is not None:
113
110
  for item in unzip_files:
114
111
  gen = self._next.process(item)
@@ -24,7 +24,7 @@ Classes and Functions:
24
24
  - `BaseOpEnum`: Enum defining paths to processor classes for common operations.
25
25
  - `Op`: Represents a single operation configuration.
26
26
  - `OpAny`, `OpAll`: Define composite operations requiring any or all conditions.
27
- - `prepare_retry_processor`: Wraps a processor with retry logic.
27
+ - `prepare_retry_option`: Wraps a option with retry logic.
28
28
  - `process_op`, `process_op_composite`: Handle individual and composite operation processing.
29
29
  - `get_processor_for_operation`: Dispatch function for retrieving the appropriate processor.
30
30
 
@@ -37,10 +37,12 @@ This framework enables modular, reusable, and extensible ETL workflows by abstra
37
37
  processing logic into well-defined processors and operations.
38
38
  """
39
39
 
40
+ import types
40
41
  from dataclasses import dataclass, field
41
42
  from enum import Enum
42
43
  from typing import Any, Callable, Dict, Generic, List, Type, TypeVar, Union
43
44
 
45
+ from pipelet.decarators.logging_decorator import logging_decorator
44
46
  from pipelet.factories import KEYWORD_FACTORY_MAP
45
47
  from pipelet.log import logger_factory
46
48
  from pipelet.processors import get_processor
@@ -59,11 +61,12 @@ class BaseOpEnum(str, Enum):
59
61
 
60
62
  downloading = "pipelet.etl.extract.http.HttpDataExtractProcessor"
61
63
  stream_downloading = "pipelet.etl.extract.http.HttpxStreamDownloadProcessor"
62
- unzip = "pipelet.etl.transform.unzip.BaseUnzipProcessor"
64
+ unzip = "pipelet.etl.transform.unzip.UnzipProcessor"
63
65
  csv_parsing = "pipelet.etl.transform.csv.CsvParser"
64
66
  json_parsing = "pipelet.etl.transform.json.JsonParser"
65
67
  retrying = "pipelet.processors.retry_processor.RetryProcessor"
66
68
  splitting = "pipelet.processors.splitter_processor.SplitterProcessor"
69
+ logging = "pipelet.processors.logging_processor.LoggingProcessor"
67
70
 
68
71
 
69
72
  T = TypeVar("T", bound="BaseOpComposite")
@@ -75,7 +78,7 @@ class Op:
75
78
  Represents an operation configuration.
76
79
 
77
80
  Attributes:
78
- operation (str): Path to the processor class in "module.ClassName" format.
81
+ operation (str): Path to the processor class in "module.Classmeta_option_decoratorName" format.
79
82
  """
80
83
 
81
84
  operation: str
@@ -115,7 +118,7 @@ class OpAll(BaseOpComposite[Union["OpAny", "OpAll"]]):
115
118
  """
116
119
 
117
120
 
118
- def prepare_retry_processor(
121
+ def prepare_retry_option(
119
122
  processor: BaseProcessor[Any, Any, Any, Any], kwargs: Dict[str, Any]
120
123
  ) -> BaseProcessor[Any, Any, Any, Any]:
121
124
  """
@@ -149,6 +152,79 @@ def prepare_retry_processor(
149
152
  return processor
150
153
 
151
154
 
155
+ def prepare_logging_option(
156
+ processor: BaseProcessor[Any, Any, Any, Any], kwargs: Dict[str, Any]
157
+ ) -> BaseProcessor[Any, Any, Any, Any]:
158
+ """
159
+ Prepares and applies logging functionality to the processor.
160
+
161
+ This function checks for a `logging` flag in the provided `kwargs`. If `logging` is enabled,
162
+ it wraps the `process` method of the processor with the `logging_decorator`.
163
+
164
+ Args:
165
+ processor (BaseProcessor): The processor instance to which logging functionality will be added.
166
+ kwargs (Dict[str, Any]): A dictionary of arguments, including the `logging` flag.
167
+
168
+ Returns:
169
+ BaseProcessor: The processor with logging functionality applied if enabled.
170
+ """
171
+ logging = kwargs.pop("logging", False)
172
+ logger = kwargs.pop("logger", None)
173
+ if logging:
174
+ processor.process = types.MethodType(
175
+ logging_decorator(processor.process, logger), processor
176
+ )
177
+
178
+ return processor
179
+
180
+
181
+ OPTION_TO_HANDLER_MAP: Dict[
182
+ str,
183
+ Callable[
184
+ [BaseProcessor[Any, Any, Any, Any], Dict[str, Any]],
185
+ BaseProcessor[Any, Any, Any, Any],
186
+ ],
187
+ ] = {
188
+ "logging_args": prepare_logging_option,
189
+ "retry_args": prepare_retry_option,
190
+ }
191
+
192
+
193
+ def prepare_additional_options(
194
+ processor: BaseProcessor[Any, Any, Any, Any],
195
+ kwargs: Dict[str, Dict[str, Any]],
196
+ ) -> BaseProcessor[Any, Any, Any, Any]:
197
+ """
198
+ Prepares and applies additional options to the processor.
199
+
200
+ This function processes a dictionary of option names and their associated arguments,
201
+ applying each option to the processor using a corresponding handler function from
202
+ the `OPTION_TO_HANDLER_MAP`.
203
+
204
+ Supported options:
205
+ - `logging_args`: Configures logging functionality.
206
+ - `retry_args`: Configures retry logic.
207
+
208
+ Args:
209
+ processor (BaseProcessor): The processor instance to which additional options will be applied.
210
+ kwargs (Dict[str, Dict[str, Any]]): A dictionary where keys are option names
211
+ and values are their respective argument dictionaries.
212
+
213
+ Returns:
214
+ BaseProcessor: The processor with the additional options applied.
215
+
216
+ Raises:
217
+ KeyError: If an unsupported option name is provided in `kwargs`.
218
+ """
219
+ if kwargs:
220
+ for option_name, option_kwargs in kwargs.items():
221
+ option_handler = OPTION_TO_HANDLER_MAP.get(option_name, None)
222
+ if option_handler is None:
223
+ raise KeyError(f"Option {option_name} isn't supported")
224
+ processor = option_handler(processor, option_kwargs)
225
+ return processor
226
+
227
+
152
228
  def process_op(op: Op) -> BaseProcessor[Any, Any, Any, Any]:
153
229
  """
154
230
  Processes an Op and returns an instance of BaseProcessor.
@@ -164,15 +240,17 @@ def process_op(op: Op) -> BaseProcessor[Any, Any, Any, Any]:
164
240
  """
165
241
  type_processor = get_processor(op.operation)
166
242
  kwargs: Dict[str, Any] = {}
243
+ kwargs_to_additional_processors: Dict[str, Any] = {}
167
244
  for k, v in op.kwargs.items():
168
245
  factory = KEYWORD_FACTORY_MAP.get(k, None)
169
246
  if factory:
170
247
  kwargs[k] = factory(**v) if isinstance(v, dict) else factory(v)
171
248
  else:
172
- kwargs[k] = v
173
- retry_args: Dict[str, Any] = kwargs.pop("retry_args", {})
249
+ kwargs_to_additional_processors[k] = v
174
250
  processor = type_processor(**kwargs)
175
- processor = prepare_retry_processor(processor, kwargs=retry_args)
251
+ processor = prepare_additional_options(
252
+ processor, kwargs_to_additional_processors
253
+ )
176
254
  return processor
177
255
 
178
256
 
@@ -21,6 +21,7 @@ Key Features:
21
21
  """
22
22
 
23
23
  from abc import ABCMeta
24
+ from functools import wraps
24
25
  from typing import Any, Callable, Generator, List, Optional, Type, Union
25
26
 
26
27
  from pipelet.exceptions.base import (
@@ -68,6 +69,7 @@ class ProcessorMeta(ABCMeta):
68
69
  Callable: A wrapped generator function with added exception handling.
69
70
  """
70
71
 
72
+ @wraps(func)
71
73
  def wrapper(
72
74
  obj: AbstractProcessor,
73
75
  *args,
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "pipelet"
3
- version = "0.0.2"
3
+ version = "0.0.3"
4
4
  description = ""
5
5
  authors = ["Daniel Naumowich <cskteam4@gmail.com>"]
6
6
  readme = "README.md"
@@ -1,3 +0,0 @@
1
- from pipelet.etl.transform.unzip.base import BaseUnzipProcessor
2
-
3
- __all__ = ("BaseUnzipProcessor",)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes