deltafi 1.0.6__py3-none-any.whl → 1.0.7__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.

Potentially problematic release.


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

deltafi/domain.py CHANGED
@@ -25,6 +25,7 @@ from deltafi.storage import ContentService, Segment
25
25
 
26
26
  class Context(NamedTuple):
27
27
  did: str
28
+ action_flow: str
28
29
  action_name: str
29
30
  source_filename: str
30
31
  ingress_flow: str
@@ -37,7 +38,9 @@ class Context(NamedTuple):
37
38
  @classmethod
38
39
  def create(cls, context: dict, hostname: str, content_service: ContentService, logger: Logger):
39
40
  did = context['did']
40
- action_name = context['name']
41
+ action_name_parts = context['name'].split(".")
42
+ action_flow = action_name_parts[0]
43
+ action_name = action_name_parts[1]
41
44
  if 'sourceFilename' in context:
42
45
  source_filename = context['sourceFilename']
43
46
  else:
@@ -49,6 +52,7 @@ class Context(NamedTuple):
49
52
  egress_flow = None
50
53
  system = context['systemName']
51
54
  return Context(did=did,
55
+ action_flow=action_flow,
52
56
  action_name=action_name,
53
57
  source_filename=source_filename,
54
58
  ingress_flow=ingress_flow,
deltafi/plugin.py CHANGED
@@ -270,7 +270,7 @@ class Plugin(object):
270
270
 
271
271
  response = {
272
272
  'did': event.context.did,
273
- 'action': event.context.action_name,
273
+ 'action': event.context.action_flow + "." + event.context.action_name,
274
274
  'start': start_time,
275
275
  'stop': time.time(),
276
276
  'type': result.result_type,
deltafi/result.py CHANGED
@@ -17,8 +17,8 @@
17
17
  #
18
18
 
19
19
  import abc
20
- from typing import Dict, List
21
20
  import uuid
21
+ from typing import Dict, List
22
22
 
23
23
  from deltafi.domain import Content, Context
24
24
  from deltafi.metric import Metric
@@ -123,40 +123,66 @@ class FormatResult(Result):
123
123
  def __init__(self, context: Context):
124
124
  super().__init__('format', 'FORMAT', context)
125
125
  self.content = None
126
+ self.delete_metadata_keys = []
126
127
  self.metadata = {}
127
128
 
128
129
  def add_metadata(self, key: str, value: str):
129
130
  self.metadata[key] = value
130
131
  return self
131
132
 
133
+ def delete_metadata_key(self, key: str):
134
+ self.delete_metadata_keys.append(key)
135
+ return self
136
+
132
137
  def set_content(self, content: Content):
133
138
  self.content = content
134
139
  return self
135
140
 
136
141
  def save_string_content(self, string_data: str, name: str, media_type: str):
137
142
  segment = self.context.content_service.put_str(self.context.did, string_data)
138
- self.content = Content(name=name, segments=[segment], media_type=media_type, content_service=self.context.content_service)
143
+ self.content = Content(name=name, segments=[segment], media_type=media_type,
144
+ content_service=self.context.content_service)
139
145
  return self
140
146
 
141
147
  def save_byte_content(self, byte_data: bytes, name: str, media_type: str):
142
148
  segment = self.context.content_service.put_bytes(self.context.did, byte_data)
143
- self.content = Content(name=name, segments=[segment], media_type=media_type, content_service=self.context.content_service)
149
+ self.content = Content(name=name, segments=[segment], media_type=media_type,
150
+ content_service=self.context.content_service)
144
151
  return self
145
152
 
146
153
  def response(self):
147
154
  return {
148
155
  'content': self.content.json(),
149
- 'metadata': self.metadata
156
+ 'metadata': self.metadata,
157
+ 'deleteMetadataKeys': self.delete_metadata_keys
150
158
  }
151
159
 
152
160
 
161
+ class ChildFormatResult:
162
+ def __init__(self, format_result: FormatResult = None):
163
+ self._did = str(uuid.uuid4())
164
+ self.format_result = format_result
165
+
166
+ @property
167
+ def did(self):
168
+ return self._did
169
+
170
+ def response(self):
171
+ res = self.format_result.response()
172
+ res["did"] = self._did
173
+ return res
174
+
175
+
153
176
  class FormatManyResult(Result):
154
177
  def __init__(self, context: Context):
155
178
  super().__init__('formatMany', 'FORMAT_MANY', context)
156
179
  self.format_results = []
157
180
 
158
- def add_format_result(self, format_result: FormatResult):
159
- self.format_results.append(format_result)
181
+ def add_format_result(self, format_result):
182
+ if isinstance(format_result, ChildFormatResult):
183
+ self.format_results.append(format_result)
184
+ else:
185
+ self.format_results.append(ChildFormatResult(format_result))
160
186
  return self
161
187
 
162
188
  def response(self):
@@ -184,12 +210,14 @@ class LoadResult(Result):
184
210
 
185
211
  def save_string_content(self, string_data: str, name: str, media_type: str):
186
212
  segment = self.context.content_service.put_str(self.context.did, string_data)
187
- self.content.append(Content(name=name, segments=[segment], media_type=media_type, content_service=self.context.content_service))
213
+ self.content.append(
214
+ Content(name=name, segments=[segment], media_type=media_type, content_service=self.context.content_service))
188
215
  return self
189
216
 
190
217
  def save_byte_content(self, byte_data: bytes, name: str, media_type: str):
191
218
  segment = self.context.content_service.put_bytes(self.context.did, byte_data)
192
- self.content.append(Content(name=name, segments=[segment], media_type=media_type, content_service=self.context.content_service))
219
+ self.content.append(
220
+ Content(name=name, segments=[segment], media_type=media_type, content_service=self.context.content_service))
193
221
  return self
194
222
 
195
223
  def add_metadata(self, key: str, value: str):
@@ -300,12 +328,14 @@ class TransformResult(Result):
300
328
 
301
329
  def save_string_content(self, string_data: str, name: str, media_type: str):
302
330
  segment = self.context.content_service.put_str(self.context.did, string_data)
303
- self.content.append(Content(name=name, segments=[segment], media_type=media_type, content_service=self.context.content_service))
331
+ self.content.append(
332
+ Content(name=name, segments=[segment], media_type=media_type, content_service=self.context.content_service))
304
333
  return self
305
334
 
306
335
  def save_byte_content(self, byte_data: bytes, name: str, media_type: str):
307
336
  segment = self.context.content_service.put_bytes(self.context.did, byte_data)
308
- self.content.append(Content(name=name, segments=[segment], media_type=media_type, content_service=self.context.content_service))
337
+ self.content.append(
338
+ Content(name=name, segments=[segment], media_type=media_type, content_service=self.context.content_service))
309
339
  return self
310
340
 
311
341
  def add_metadata(self, key: str, value: str):
@@ -0,0 +1,99 @@
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
+ from typing import List
19
+
20
+ from deltafi.result import FormatResult, FormatManyResult
21
+
22
+ from .assertions import *
23
+ from .framework import TestCaseBase, ActionTest
24
+
25
+
26
+ class FormatTestCase(TestCaseBase):
27
+ def __init__(self, fields: Dict):
28
+ super().__init__(fields)
29
+ self.metadata = {}
30
+ self.delete_metadata_keys = []
31
+ self.expected_format_many_result = []
32
+
33
+ def expect_format_result(self, metadata: Dict, delete_metadata_keys: List[str]):
34
+ self.expected_result_type = FormatResult
35
+ self.metadata = metadata
36
+ self.delete_metadata_keys = delete_metadata_keys
37
+
38
+ def add_format_many_result(self, metadata: Dict, delete_metadata_keys: List):
39
+ self.expected_result_type = FormatManyResult
40
+ self.expected_format_many_result.append(
41
+ {
42
+ "metadata": metadata,
43
+ "delete_metadata_keys": delete_metadata_keys
44
+ }
45
+ )
46
+
47
+
48
+ class FormatActionTest(ActionTest):
49
+ def __init__(self, package_name: str):
50
+ """
51
+ Provides structure for testing DeltaFi Format action
52
+ Args:
53
+ package_name: name of the actions package for finding resources
54
+ """
55
+ super().__init__(package_name)
56
+
57
+ def format(self, test_case: FormatTestCase):
58
+ if test_case.expected_result_type == FormatManyResult:
59
+ self.expect_format_many_result(test_case)
60
+ elif test_case.expected_result_type == FormatResult:
61
+ self.expect_format_result(test_case)
62
+ else:
63
+ super().execute(test_case)
64
+
65
+ def expect_format_result(self, test_case: FormatTestCase):
66
+ result = super().run_and_check_result_type(test_case, FormatResult)
67
+ self.assert_format_result(test_case, result)
68
+
69
+ def expect_format_many_result(self, test_case: FormatTestCase):
70
+ result = super().run_and_check_result_type(test_case, FormatManyResult)
71
+ self.assert_format_many_result(test_case, result)
72
+
73
+ def assert_format_result(self, test_case: FormatTestCase, result: FormatResult):
74
+ # Check output
75
+ if result.content is None:
76
+ self.compare_all_output(test_case.compare_tool, [])
77
+ else:
78
+ self.compare_all_output(test_case.compare_tool, [result.content])
79
+
80
+ # Check metadata
81
+ assert_keys_and_values(test_case.metadata, result.metadata)
82
+
83
+ # Check deleted metadata
84
+ for key in test_case.delete_metadata_keys:
85
+ assert_key_in(key, result.delete_metadata_keys)
86
+
87
+ def assert_format_many_result(self, test_case: FormatTestCase, actual: FormatManyResult):
88
+ assert_equal_len(test_case.expected_format_many_result, actual.format_results)
89
+ for index, expected_child_result in enumerate(test_case.expected_format_many_result):
90
+ actual_child = actual.format_results[index]
91
+ self.compare_one_content(test_case.compare_tool,
92
+ self.expected_outputs[index],
93
+ actual_child.format_result.content,
94
+ index)
95
+
96
+ assert_keys_and_values(expected_child_result['metadata'],
97
+ actual_child.format_result.metadata)
98
+ for key in expected_child_result['delete_metadata_keys']:
99
+ assert_key_in(key, actual_child.format_result.delete_metadata_keys)
@@ -118,8 +118,7 @@ class TestCaseBase(ABC):
118
118
  A test case for DeltaFi python actions
119
119
  :param data: Dict of test case fields
120
120
  - action: instance of the action being tested
121
- - pkg_name: str: name of the actions package for finding resources
122
- - test_name: str: name of the test for finding test files, e.g. test/data/{test_name)
121
+ - data_dir: str: subdirectory name (e.g., test name) for locating test data files, i.e., test/data/{data_dir)
123
122
  - compare_tool: (optional) CompareHelper instanced for comparing output content
124
123
  - inputs: (optional) List[IOContent]: input content to action
125
124
  - parameters: (optional) Dict: map of action input parameters
@@ -132,15 +131,10 @@ class TestCaseBase(ABC):
132
131
  else:
133
132
  raise ValueError("action is required")
134
133
 
135
- if "pkg_name" in data:
136
- self.pkg_name = data["pkg_name"]
134
+ if "data_dir" in data:
135
+ self.data_dir = data["data_dir"]
137
136
  else:
138
- raise ValueError("pkg_name is required")
139
-
140
- if "test_name" in data:
141
- self.test_name = data["test_name"]
142
- else:
143
- raise ValueError("test_name is required")
137
+ raise ValueError("data_dir is required")
144
138
 
145
139
  if "compare_tool" in data:
146
140
  self.compare_tool = data["compare_tool"]
@@ -178,11 +172,17 @@ class TestCaseBase(ABC):
178
172
 
179
173
 
180
174
  class ActionTest(ABC):
181
- def __init__(self):
175
+ def __init__(self, package_name: str):
176
+ """
177
+ Provides structure for testing DeltaFi actions
178
+ Args:
179
+ package_name: name of the actions package for finding resources
180
+ """
182
181
  self.content_service = InternalContentService()
183
182
  self.did = ""
184
183
  self.expected_outputs = []
185
184
  self.loaded_inputs = []
185
+ self.package_name = package_name
186
186
  self.res_path = ""
187
187
 
188
188
  def __reset__(self):
@@ -199,8 +199,8 @@ class ActionTest(ABC):
199
199
  return contents
200
200
 
201
201
  def get_contents(self, test_case: TestCaseBase):
202
- pkg_path = files(test_case.pkg_name)
203
- self.res_path = pkg_path.joinpath(f"test/data/{test_case.test_name}/")
202
+ pkg_path = files(self.package_name)
203
+ self.res_path = pkg_path.joinpath(f"test/data/{test_case.data_dir}/")
204
204
 
205
205
  # Load inputs
206
206
  for input_ioc in test_case.inputs:
@@ -240,6 +240,7 @@ class ActionTest(ABC):
240
240
  def make_context(self, test_case: TestCaseBase):
241
241
  action_name = INGRESS_FLOW + "." + test_case.action.__class__.__name__
242
242
  return Context(did=self.did,
243
+ action_flow=INGRESS_FLOW,
243
244
  action_name=action_name,
244
245
  source_filename=test_case.file_name,
245
246
  ingress_flow=INGRESS_FLOW,
@@ -293,16 +294,19 @@ class ActionTest(ABC):
293
294
  assert_equal(expected.content_type, actual.media_type)
294
295
  assert_equal(expected.name, actual.name)
295
296
 
297
+ def compare_one_content(self, comparitor: CompareHelper, expected: LoadedContent, actual, index):
298
+ self.compare_content_details(expected, actual)
299
+ seg_id = actual.segments[0].uuid
300
+ comparitor.compare(
301
+ expected.data,
302
+ self.content_service.get_output(seg_id),
303
+ f"Content[{index}]"
304
+ )
305
+
296
306
  def compare_all_output(self, comparitor: CompareHelper, content: List):
297
307
  assert_equal_len(self.expected_outputs, content)
298
308
  for index, expected in enumerate(self.expected_outputs):
299
- self.compare_content_details(expected, content[index])
300
- seg_id = content[index].segments[0].uuid
301
- comparitor.compare(
302
- expected.data,
303
- self.content_service.get_output(seg_id),
304
- f"Content[{index}]"
305
- )
309
+ self.compare_one_content(comparitor, expected, content[index], index)
306
310
 
307
311
  def compare_domains(self, comparitor: CompareHelper, expected_items: List[Dict], results: List[Dict]):
308
312
  assert_equal_len(expected_items, results)
deltafi/test_kit/load.py CHANGED
@@ -44,14 +44,26 @@ class LoadTestCase(TestCaseBase):
44
44
  self.annotations = annotations
45
45
  self.domains = domains
46
46
 
47
- def expect_reinject_result(self, children: List):
47
+ def add_reinject_child(self, filename: str, flow: str, content: IOContent, metadata: Dict):
48
48
  self.expected_result_type = ReinjectResult
49
- self.children = children
49
+ self.children.append(
50
+ {
51
+ "filename": filename,
52
+ "flow": flow,
53
+ "content": content,
54
+ "metadata": metadata
55
+ }
56
+ )
50
57
 
51
58
 
52
59
  class LoadActionTest(ActionTest):
53
- def __init__(self):
54
- super().__init__()
60
+ def __init__(self, package_name: str):
61
+ """
62
+ Provides structure for testing DeltaFi Load action
63
+ Args:
64
+ package_name: name of the actions package for finding resources
65
+ """
66
+ super().__init__(package_name)
55
67
 
56
68
  def load(self, test_case: LoadTestCase):
57
69
  if test_case.expected_result_type == ReinjectResult:
@@ -38,8 +38,13 @@ class TransformTestCase(TestCaseBase):
38
38
 
39
39
 
40
40
  class TransformActionTest(ActionTest):
41
- def __init__(self):
42
- super().__init__()
41
+ def __init__(self, package_name: str):
42
+ """
43
+ Provides structure for testing DeltaFi Transform action
44
+ Args:
45
+ package_name: name of the actions package for finding resources
46
+ """
47
+ super().__init__(package_name)
43
48
 
44
49
  def transform(self, test_case: TransformTestCase):
45
50
  if test_case.expected_result_type == TransformResult:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: deltafi
3
- Version: 1.0.6
3
+ Version: 1.0.7
4
4
  Summary: SDK for DeltaFi plugins and actions
5
5
  License: Apache License, Version 2.0
6
6
  Keywords: deltafi
@@ -2,21 +2,22 @@ deltafi/__init__.py,sha256=PNMUt1SbY5DhoTxle11dPv21Pr_bo8paVc7TVu4Cs7E,706
2
2
  deltafi/action.py,sha256=ssbSGP-Nn15mD2UdHXmbBuNnVw5vPZY88RZRCV9xqMw,7330
3
3
  deltafi/actioneventqueue.py,sha256=HR1n-Co5Nq8IarYKR7Uzydi8mkCdOZbC-yJWHuA6KwA,1981
4
4
  deltafi/actiontype.py,sha256=gt8j4PgYuxoRbif5-FJi1fu4eLSy2J4oVbQ2qceRgqM,985
5
- deltafi/domain.py,sha256=x0tS5DKv9tXYJK7eda1SVkkbOhRk_4scpXMfU-FZSJM,11025
5
+ deltafi/domain.py,sha256=-0ad8dGq-JcLyTnrIXHSMr7ZgBnailUJSZn1yPwEHI8,11197
6
6
  deltafi/exception.py,sha256=qQ2TY2QPtMU9t5RH8jmFo_cX98AJ-zOFWP_Wfm5U6qQ,1149
7
7
  deltafi/input.py,sha256=DuY280ZglZxEUkhjTtyr0g9Ohu2drn16UVhASH244nA,6290
8
8
  deltafi/logger.py,sha256=q76R_Gn8BfcASH3Zy0V82m5ot34bjTnSELyKbjhvx3E,2136
9
9
  deltafi/metric.py,sha256=eIDjZQVO53KuAFoEtjLNFwqMrp_7BC0Td9GLD1tb6sE,967
10
- deltafi/plugin.py,sha256=7eHU-P8GIqmK8fz9Re7sOWafZ9wxOayifWmmnyKXRrw,11666
11
- deltafi/result.py,sha256=aIFyytP5fOQBXmV-8IQleR5cQQrKVW36DEuOJSAGCgA,10706
10
+ deltafi/plugin.py,sha256=dIBbhwRLbBlF2NyuRz09-Jj8BSIkvJa74JkAzsfiYBc,11700
11
+ deltafi/result.py,sha256=fRo83BZNcTfIDYDePGBJuB84FOnpgBiR23zbedJ2mD8,11512
12
12
  deltafi/storage.py,sha256=toq58EPZgzj2TfDF-YpFUmRnsWSjACA0KQAZzkM04xU,2740
13
13
  deltafi/test_kit/__init__.py,sha256=PNMUt1SbY5DhoTxle11dPv21Pr_bo8paVc7TVu4Cs7E,706
14
14
  deltafi/test_kit/assertions.py,sha256=2yJKCLTenJW44CprFLGorqfjVC6_6z-oAfPY1Q7J__0,1377
15
15
  deltafi/test_kit/compare_helpers.py,sha256=xeP6ToXvlCxVK3LX4glf9VsDfAmOoexYjkQpltfZ2T8,1580
16
16
  deltafi/test_kit/constants.py,sha256=epz0OS-qILcc8t7iIs5B3m2-wvZx8FpYpyb19ZsImbI,833
17
- deltafi/test_kit/framework.py,sha256=T3F3owpsis7vZXmJ2bs6WvHZ8KyEuA7t3m1nHXmGJ2k,12637
18
- deltafi/test_kit/load.py,sha256=CNy1mIbQ24rTSQ5VedmTQu8SpkPEauxoLfEOfMea4j0,4432
19
- deltafi/test_kit/transform.py,sha256=jQ_gH9hFYonGgIqFvNDc0hhID_02mL4jdfoEXEdOpUc,2398
20
- deltafi-1.0.6.dist-info/METADATA,sha256=c1xxvw6K0zgxhBB6KFLoyZFoCN1H5qvy4alddt4SU5A,1749
21
- deltafi-1.0.6.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
22
- deltafi-1.0.6.dist-info/RECORD,,
17
+ deltafi/test_kit/format.py,sha256=NTG7UnwvXQlzn6WqKjMG9EZg0tKTu1g3CcNDD_6AQwk,4070
18
+ deltafi/test_kit/framework.py,sha256=fEdllkV8luBwdZYkwMZo7-BzgRO_GIcg5e6lMyTD8fI,12855
19
+ deltafi/test_kit/load.py,sha256=0K5vCQXbXl5pos9Yg_4qcZ9bJYfdQUGUosTxncv0xmw,4854
20
+ deltafi/test_kit/transform.py,sha256=Eeqxev_dxoiFw72eAlYJ-3MDQH-kJtuHRGSIMbaatrg,2607
21
+ deltafi-1.0.7.dist-info/METADATA,sha256=x24guqKi-7KbkMFCqJd-XGqgbeNGf7zhldbX34xfouQ,1749
22
+ deltafi-1.0.7.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
23
+ deltafi-1.0.7.dist-info/RECORD,,