deltafi 2.0rc1719271450675__tar.gz → 2.0rc1720817063181__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.

Potentially problematic release.


This version of deltafi might be problematic. Click here for more details.

Files changed (26) hide show
  1. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/PKG-INFO +1 -1
  2. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/action.py +5 -5
  3. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/domain.py +10 -10
  4. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/test_kit/framework.py +45 -19
  5. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/pyproject.toml +1 -1
  6. deltafi-2.0rc1719271450675/deltafi/test_kit/domain.py +0 -59
  7. deltafi-2.0rc1719271450675/deltafi/test_kit/enrich.py +0 -70
  8. deltafi-2.0rc1719271450675/deltafi/test_kit/validate.py +0 -54
  9. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/README.md +0 -0
  10. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/__init__.py +0 -0
  11. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/actioneventqueue.py +0 -0
  12. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/actiontype.py +0 -0
  13. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/exception.py +0 -0
  14. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/genericmodel.py +0 -0
  15. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/input.py +0 -0
  16. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/logger.py +0 -0
  17. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/metric.py +0 -0
  18. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/plugin.py +0 -0
  19. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/result.py +0 -0
  20. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/storage.py +0 -0
  21. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/test_kit/__init__.py +0 -0
  22. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/test_kit/assertions.py +0 -0
  23. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/test_kit/compare_helpers.py +0 -0
  24. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/test_kit/constants.py +0 -0
  25. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/test_kit/egress.py +0 -0
  26. {deltafi-2.0rc1719271450675 → deltafi-2.0rc1720817063181}/deltafi/test_kit/transform.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: deltafi
3
- Version: 2.0rc1719271450675
3
+ Version: 2.0rc1720817063181
4
4
  Summary: SDK for DeltaFi plugins and actions
5
5
  License: Apache License, Version 2.0
6
6
  Keywords: deltafi
@@ -38,8 +38,8 @@ class Action(ABC):
38
38
  def build_input(self, context: Context, delta_file_message: DeltaFileMessage):
39
39
  pass
40
40
 
41
- def collect(self, action_inputs: List[Any]):
42
- raise RuntimeError(f"Collect is not supported for {self.__class__.__name__}")
41
+ def join(self, action_inputs: List[Any]):
42
+ raise RuntimeError(f"Join is not supported for {self.__class__.__name__}")
43
43
 
44
44
  @abstractmethod
45
45
  def execute(self, context: Context, action_input: Any, params: BaseModel):
@@ -48,10 +48,10 @@ class Action(ABC):
48
48
  def execute_action(self, event):
49
49
  if event.delta_file_messages is None or not len(event.delta_file_messages):
50
50
  raise RuntimeError(f"Received event with no delta file messages for did {event.context.did}")
51
- if event.context.collect is not None:
51
+ if event.context.join is not None:
52
52
  result = self.execute(
53
53
  event.context,
54
- self.collect([self.build_input(event.context, delta_file_message)
54
+ self.join([self.build_input(event.context, delta_file_message)
55
55
  for delta_file_message in event.delta_file_messages]),
56
56
  self.param_class().model_validate(event.params))
57
57
  else:
@@ -119,7 +119,7 @@ class TransformAction(Action, ABC):
119
119
  def build_input(self, context: Context, delta_file_message: DeltaFileMessage):
120
120
  return TransformInput(content=delta_file_message.content_list, metadata=delta_file_message.metadata)
121
121
 
122
- def collect(self, transform_inputs: List[TransformInput]):
122
+ def join(self, transform_inputs: List[TransformInput]):
123
123
  all_content = []
124
124
  all_metadata = {}
125
125
  for transform_input in transform_inputs:
@@ -50,8 +50,8 @@ class Context(NamedTuple):
50
50
  hostname: str
51
51
  system_name: str
52
52
  content_service: ContentService
53
- collect: dict = None
54
- collected_dids: List[str] = None
53
+ join: dict = None
54
+ joined_dids: List[str] = None
55
55
  memo: str = None
56
56
  logger: Logger = None
57
57
 
@@ -94,14 +94,14 @@ class Context(NamedTuple):
94
94
  system_name = context['systemName']
95
95
  else:
96
96
  system_name = None
97
- if 'collect' in context:
98
- collect = context['collect']
97
+ if 'join' in context:
98
+ join = context['join']
99
99
  else:
100
- collect = None
101
- if 'collectedDids' in context:
102
- collected_dids = context['collectedDids']
100
+ join = None
101
+ if 'joinedDids' in context:
102
+ joined_dids = context['joinedDids']
103
103
  else:
104
- collected_dids = None
104
+ joined_dids = None
105
105
  if 'memo' in context:
106
106
  memo = context['memo']
107
107
  else:
@@ -117,8 +117,8 @@ class Context(NamedTuple):
117
117
  action_version=action_version,
118
118
  hostname=hostname,
119
119
  system_name=system_name,
120
- collect=collect,
121
- collected_dids=collected_dids,
120
+ join=join,
121
+ joined_dids=joined_dids,
122
122
  memo=memo,
123
123
  content_service=content_service,
124
124
  logger=logger)
@@ -37,15 +37,20 @@ class IOContent:
37
37
  The IOContent class holds the details for loading input or output
38
38
  content into the test framework.
39
39
  Attributes:
40
- file_name (str): The name of file in test/data.
41
- content_name (str): The name of the content.
42
- content_type (str): The media type of the content
43
- offset (int): Offset to use in Segment
44
- content_bytes (str): Bypass file read, and uses these bytes for content
40
+ file_name (str) : The name of file in test/data.
41
+ content_name (str) : The name of the content.
42
+ content_type (str) : The media type of the content
43
+ offset (int) : Offset to use in Segment
44
+ content_bytes (str): Optional. If set to a String of length greater than zero, indicates to consumers of this
45
+ IOContent that they should bypass file read and use these bytes for content.
46
+ no_content (bool) : Optional. If 'True', then consumers should not attempt to interpret content but should
47
+ apply other aspects of this IOContent. When 'True', 'content_bytes' should be ignored and
48
+ loaded content, if any, should be interpreted as empty String or otherwise as documented by
49
+ the consumer.
45
50
  """
46
51
 
47
52
  def __init__(self, file_name: str, content_name: str = None, content_type: str = None, offset: int = 0,
48
- content_bytes: str = ""):
53
+ content_bytes: str = "", no_content: bool = False):
49
54
  self.file_name = file_name
50
55
  if content_name is None:
51
56
  self.content_name = file_name
@@ -56,7 +61,11 @@ class IOContent:
56
61
  else:
57
62
  self.content_type = content_type
58
63
  self.offset = offset
59
- self.content_bytes = content_bytes
64
+ self.no_content = no_content
65
+ if no_content:
66
+ self.content_bytes = None
67
+ else:
68
+ self.content_bytes = content_bytes
60
69
  self.segment_uuid = uuid.uuid4()
61
70
 
62
71
  @classmethod
@@ -79,7 +88,10 @@ class LoadedContent:
79
88
  if data is not None:
80
89
  self.data = data
81
90
  else:
82
- self.data = ioc.content_bytes
91
+ if ioc.no_content:
92
+ self.data = ""
93
+ else:
94
+ self.data = ioc.content_bytes
83
95
  self.segment = Segment.from_dict(
84
96
  {"uuid": str(ioc.segment_uuid), "offset": self.offset, "size": len(self.data), "did": did})
85
97
 
@@ -127,6 +139,8 @@ class TestCaseBase(ABC):
127
139
  - inputs: (optional) List[IOContent]: input content to action
128
140
  - parameters: (optional) Dict: map of action input parameters
129
141
  - in_meta: (optional) Dict: map of metadata as input to action
142
+ - join_meta: (optional): List[Dict]: When a List is provided, this enables the JOIN portion of an action.
143
+ When using JOIN, join_meta must match the size of inputs, though the Dict can be empty
130
144
  - did: (optional): str: overrides random DID
131
145
  """
132
146
  if "action" in data:
@@ -153,6 +167,7 @@ class TestCaseBase(ABC):
153
167
  self.err_or_filt_cause = None
154
168
  self.err_or_filt_context = None
155
169
  self.err_or_filt_annotations = None
170
+ self.join_meta = data["join_meta"] if "join_meta" in data else None
156
171
  self.expected_metrics = []
157
172
 
158
173
  def add_metric(self, metric: Metric):
@@ -163,7 +178,7 @@ class TestCaseBase(ABC):
163
178
  A Sets the expected output of the action to an Error Result
164
179
  :param cause: the expected error cause
165
180
  :param context: the expected error context
166
- :param annotations (Optional): Dict: the expected annotations
181
+ :param annotations: Dict: (Optional) the expected annotations
167
182
  """
168
183
  self.expected_result_type = ErrorResult
169
184
  self.err_or_filt_cause = cause
@@ -174,8 +189,8 @@ class TestCaseBase(ABC):
174
189
  """
175
190
  A Sets the expected output of the action to a Filter Result
176
191
  :param cause: the expected filter cause (message)
177
- :param context (Optional): the expected filter context
178
- :param annotations (Optional): Dict: the expected annotations
192
+ :param context: (Optional) the expected filter context
193
+ :param annotations: Dict: (Optional) the expected annotations
179
194
  """
180
195
  self.expected_result_type = FilterResult
181
196
  self.err_or_filt_cause = cause
@@ -217,12 +232,12 @@ class ActionTest(ABC):
217
232
 
218
233
  # Load inputs
219
234
  for input_ioc in test_case.inputs:
220
- if len(input_ioc.content_bytes) == 0:
235
+ if not input_ioc.no_content and len(input_ioc.content_bytes) == 0:
221
236
  self.loaded_inputs.append(LoadedContent(self.did, input_ioc, self.load_file(input_ioc)))
222
237
  else:
223
238
  self.loaded_inputs.append(LoadedContent(self.did, input_ioc, None))
224
239
 
225
- def make_content_list(self, test_case: TestCaseBase):
240
+ def make_content_list(self):
226
241
  content_list = []
227
242
  for loaded_input in self.loaded_inputs:
228
243
  c = Content(name=loaded_input.name, segments=[loaded_input.segment], media_type=loaded_input.content_type,
@@ -232,15 +247,25 @@ class ActionTest(ABC):
232
247
 
233
248
  return content_list
234
249
 
235
- def make_df_msg(self, test_case: TestCaseBase):
236
- content_list = self.make_content_list(test_case)
250
+ def make_df_msgs(self, test_case: TestCaseBase):
251
+ content_list = self.make_content_list()
237
252
  self.content_service.load(self.loaded_inputs)
238
253
 
239
- return DeltaFileMessage(metadata=test_case.in_meta,
240
- content_list=content_list)
254
+ delta_file_messages = []
255
+
256
+ if test_case.join_meta is None:
257
+ delta_file_messages.append(DeltaFileMessage(metadata=test_case.in_meta, content_list=content_list))
258
+ else:
259
+ for index, content in enumerate(content_list):
260
+ delta_file_messages.append(DeltaFileMessage(
261
+ metadata=test_case.join_meta[index],
262
+ content_list=[content]))
263
+
264
+ return delta_file_messages
241
265
 
242
266
  def make_context(self, test_case: TestCaseBase):
243
267
  action_name = INGRESS_FLOW + "." + test_case.action.__class__.__name__
268
+ join = {} if test_case.join_meta else None
244
269
  return Context(
245
270
  did=self.did,
246
271
  delta_file_name=test_case.file_name,
@@ -253,10 +278,11 @@ class ActionTest(ABC):
253
278
  hostname=HOSTNAME,
254
279
  system_name=SYSTEM,
255
280
  content_service=self.content_service,
281
+ join=join,
256
282
  logger=get_logger())
257
283
 
258
284
  def make_event(self, test_case: TestCaseBase):
259
- return Event(delta_file_messages=[self.make_df_msg(test_case)], context=self.make_context(test_case),
285
+ return Event(delta_file_messages=self.make_df_msgs(test_case), context=self.make_context(test_case),
260
286
  params=test_case.parameters, queue_name="", return_address="")
261
287
 
262
288
  def call_action(self, test_case: TestCaseBase):
@@ -311,7 +337,7 @@ class ActionTest(ABC):
311
337
  def compare_content_list(self, comparator: CompareHelper, expected_outputs: List[IOContent], content: List):
312
338
  assert_equal_len(expected_outputs, content)
313
339
  for index, expected_ioc in enumerate(expected_outputs):
314
- if len(expected_ioc.content_bytes) == 0:
340
+ if not expected_ioc.no_content and len(expected_ioc.content_bytes) == 0:
315
341
  expected = LoadedContent(self.did, expected_ioc, self.load_file(expected_ioc))
316
342
  else:
317
343
  expected = LoadedContent(self.did, expected_ioc, None)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "deltafi"
3
- version = "2.0rc1719271450675"
3
+ version = "2.0rc1720817063181"
4
4
  description = "SDK for DeltaFi plugins and actions"
5
5
  authors = ["DeltaFi <deltafi@systolic.com>"]
6
6
  license = "Apache License, Version 2.0"
@@ -1,59 +0,0 @@
1
- #
2
- # DeltaFi - Data transformation and enrichment platform
3
- #
4
- # Copyright 2021-2023 DeltaFi Contributors <deltafi@deltafi.org>
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
-
19
- from deltafi.result import DomainResult
20
-
21
- from .assertions import *
22
- from .framework import TestCaseBase, ActionTest
23
-
24
-
25
- class DomainTestCase(TestCaseBase):
26
- def __init__(self, fields: Dict):
27
- super().__init__(fields)
28
- self.annotations = {}
29
-
30
- def expect_domain_result(self, annotations: Dict):
31
- self.expected_result_type = DomainResult
32
- self.annotations = annotations
33
-
34
-
35
- class DomainActionTest(ActionTest):
36
- def __init__(self, package_name: str):
37
- """
38
- Provides structure for testing DeltaFi Domain action
39
- Args:
40
- package_name: name of the actions package for finding resources
41
- """
42
- super().__init__(package_name)
43
-
44
- def domain(self, test_case: DomainTestCase):
45
- if test_case.expected_result_type == DomainResult:
46
- self.expect_domain_result(test_case)
47
- else:
48
- super().execute(test_case)
49
-
50
- def expect_domain_result(self, test_case: DomainTestCase):
51
- result = super().run_and_check_result_type(test_case, DomainResult)
52
- self.assert_domain_result(test_case, result)
53
-
54
- def assert_domain_result(self, test_case: DomainTestCase, result: DomainResult):
55
- # Check metrics
56
- self.compare_metrics(test_case.expected_metrics, result.metrics)
57
-
58
- # Check annotations
59
- assert_keys_and_values(test_case.annotations, result.annotations)
@@ -1,70 +0,0 @@
1
- #
2
- # DeltaFi - Data transformation and enrichment platform
3
- #
4
- # Copyright 2021-2023 DeltaFi Contributors <deltafi@deltafi.org>
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
-
19
- from deltafi.result import EnrichResult
20
-
21
- from .assertions import *
22
- from .framework import TestCaseBase, ActionTest
23
-
24
-
25
- class EnrichTestCase(TestCaseBase):
26
- def __init__(self, fields: Dict):
27
- super().__init__(fields)
28
- self.enrichments = []
29
- self.annotations = {}
30
-
31
- def expect_enrich_result(self, annotations: Dict):
32
- self.expected_result_type = EnrichResult
33
- self.annotations = annotations
34
-
35
- def add_enrichment(self, name: str, value: str, media_type: str):
36
- self.enrichments.append({'name': name, 'value': value, 'mediaType': media_type})
37
-
38
-
39
- class EnrichActionTest(ActionTest):
40
- def __init__(self, package_name: str):
41
- """
42
- Provides structure for testing DeltaFi Enrich action
43
- Args:
44
- package_name: name of the actions package for finding resources
45
- """
46
- super().__init__(package_name)
47
-
48
- def enrich(self, test_case: EnrichTestCase):
49
- if test_case.expected_result_type == EnrichResult:
50
- self.expect_enrich_result(test_case)
51
- else:
52
- super().execute(test_case)
53
-
54
- def expect_enrich_result(self, test_case: EnrichTestCase):
55
- result = super().run_and_check_result_type(test_case, EnrichResult)
56
- self.assert_enrich_result(test_case, result)
57
-
58
- def assert_enrich_result(self, test_case: EnrichTestCase, result: EnrichResult):
59
- # Check metrics
60
- self.compare_metrics(test_case.expected_metrics, result.metrics)
61
-
62
- # Check annotations
63
- assert_keys_and_values(test_case.annotations, result.annotations)
64
-
65
- # Check enrichments
66
- assert_equal_len(test_case.enrichments, result.enrichments)
67
- if len(test_case.enrichments) > 0:
68
- for index, expected in enumerate(test_case.enrichments):
69
- actual = result.enrichments[index]
70
- assert_equal(expected, actual)
@@ -1,54 +0,0 @@
1
- #
2
- # DeltaFi - Data transformation and enrichment platform
3
- #
4
- # Copyright 2021-2023 DeltaFi Contributors <deltafi@deltafi.org>
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
-
19
- from deltafi.result import ValidateResult
20
-
21
- from .assertions import *
22
- from .framework import TestCaseBase, ActionTest
23
-
24
-
25
- class ValidateTestCase(TestCaseBase):
26
- def __init__(self, fields: Dict):
27
- super().__init__(fields)
28
-
29
- def expect_validate_result(self):
30
- self.expected_result_type = ValidateResult
31
-
32
-
33
- class ValidateActionTest(ActionTest):
34
- def __init__(self, package_name: str):
35
- """
36
- Provides structure for testing DeltaFi Validate action
37
- Args:
38
- package_name: name of the actions package for finding resources
39
- """
40
- super().__init__(package_name)
41
-
42
- def validate(self, test_case: ValidateTestCase):
43
- if test_case.expected_result_type == ValidateResult:
44
- self.expect_validate_result(test_case)
45
- else:
46
- super().execute(test_case)
47
-
48
- def expect_validate_result(self, test_case: ValidateTestCase):
49
- result = super().run_and_check_result_type(test_case, ValidateResult)
50
- self.assert_validate_result(test_case, result)
51
-
52
- def assert_validate_result(self, test_case: ValidateTestCase, result: ValidateResult):
53
- # Check metrics
54
- self.compare_metrics(test_case.expected_metrics, result.metrics)