launchpy 0.4.3.post1__tar.gz → 0.4.3.post3__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.
- {launchpy-0.4.3.post1/launchpy.egg-info → launchpy-0.4.3.post3}/PKG-INFO +1 -1
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/docs/getstarted.md +9 -1
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/docs/property.md +10 -1
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/docs/releases.md +3 -1
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/docs/synchronizer.md +51 -9
- launchpy-0.4.3.post3/launchpy/__version__.py +1 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/launchpy/connector.py +5 -1
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/launchpy/library.py +55 -1
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/launchpy/property.py +44 -1
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/launchpy/synchronizer.py +53 -25
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3/launchpy.egg-info}/PKG-INFO +1 -1
- launchpy-0.4.3.post1/launchpy/__version__.py +0 -1
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/LICENSE +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/README.md +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/docs/admin.md +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/docs/library.md +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/docs/main.md +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/docs/translator.md +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/launchpy/__init__.py +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/launchpy/admin.py +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/launchpy/config.py +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/launchpy/configs.py +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/launchpy/launchpy.py +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/launchpy.egg-info/SOURCES.txt +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/launchpy.egg-info/dependency_links.txt +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/launchpy.egg-info/requires.txt +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/launchpy.egg-info/top_level.txt +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/pyproject.toml +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/requirements.txt +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/setup.cfg +0 -0
- {launchpy-0.4.3.post1 → launchpy-0.4.3.post3}/setup.py +0 -0
|
@@ -26,7 +26,15 @@ lp.createConfigFile()
|
|
|
26
26
|
This will create a JSON and you will need to fill it with the information available in your adobe io account.
|
|
27
27
|
|
|
28
28
|
**NOTE**: scope in the config file has evolved over time so you can change it. Following this [link](https://www.adobe.io/authentication/auth-methods.html#!AdobeDocs/adobeio-auth/master/JWT/Scopes.md) to see the different scope possible.\
|
|
29
|
-
|
|
29
|
+
You can change the `scope` attribute for one of these values: `"https://ims-na1.adobelogin.com/s/ent_reactor_admin_sdk"` or `"https://ims-na1.adobelogin.com/s/ent_reactor_sdk"`
|
|
30
|
+
By default, I will test the dev scope if the scope provided fails. So normally nothing you need to do.
|
|
31
|
+
|
|
32
|
+
**NOTE 2**: There is a possibility till end of 2024 to use the JWT.\
|
|
33
|
+
launchpy supports both `jwt` and `oauthV2` authentication.\
|
|
34
|
+
By default the latest version will try to use the `oauthV2`.\
|
|
35
|
+
You can specify the keys generated in the config file by using the `auth_type` parameter.\
|
|
36
|
+
Possible values : `oauthV2` (default) or `jwt`
|
|
37
|
+
|
|
30
38
|
|
|
31
39
|
## 4. Import the configuration file
|
|
32
40
|
|
|
@@ -22,7 +22,7 @@ Here are shortlinks to the different methods explanation.
|
|
|
22
22
|
|
|
23
23
|
## Get methods
|
|
24
24
|
|
|
25
|
-
When you have your property instance created, the methods that you may want to call first are the get methods. They never take any argument, they don
|
|
25
|
+
When you have your property instance created, the methods that you may want to call first are the get methods. They never take any argument, they don't actually need any argument.
|
|
26
26
|
The only thing important to know is that you must run the getRules() method before the getRuleComponents() method.
|
|
27
27
|
|
|
28
28
|
The different get methods are the following :
|
|
@@ -82,6 +82,10 @@ The different get methods are the following :
|
|
|
82
82
|
- created_at : it will be greater that this date ('2022-12-12T10:19:20.867Z')
|
|
83
83
|
- updated_at : it will be greater that this date ('2022-12-12T10:19:20.867Z')
|
|
84
84
|
|
|
85
|
+
* **getLibrary** : Retrieve a specific library.
|
|
86
|
+
Argument:
|
|
87
|
+
* library : REQUIRED : Either the library name or the library ID
|
|
88
|
+
|
|
85
89
|
* **getNotes** : Retrieve the note associated with the object pass to the method. Returns list.
|
|
86
90
|
Arguments:
|
|
87
91
|
* data: OPTIONAL : object that is associated with a Note (rule, data element, etc...)
|
|
@@ -191,6 +195,11 @@ The different delete methods are:
|
|
|
191
195
|
Arguments:
|
|
192
196
|
* dataElement_id : REQUIRED : Data Element ID that needs to be deleted
|
|
193
197
|
|
|
198
|
+
* **deleteLibrary** : Delete a specific library. It only works for library in development state.
|
|
199
|
+
Arguments:
|
|
200
|
+
* library : REQUIRED : Either the library ID or the library Name
|
|
201
|
+
* components : OPTIONAL : Boolean, if set to `True`, it will try to delete the different components in that library afterwards. Only rules and data elements would be deleted, no extension.
|
|
202
|
+
|
|
194
203
|
## Update methods
|
|
195
204
|
|
|
196
205
|
As you can imagine the update methods enable you to update the different elements.\
|
|
@@ -4,7 +4,9 @@ This page gathered the changes made between version of the launchpy module.\
|
|
|
4
4
|
This has been started after the 0.3.0 release.\
|
|
5
5
|
|
|
6
6
|
## 0.4.3
|
|
7
|
-
* Refactor `Translator` class for removing `pandas` dependency
|
|
7
|
+
* Refactor `Translator` class for removing `pandas` dependency\
|
|
8
|
+
Patch:
|
|
9
|
+
* Fix an issue with dependency on `target_configs` attribute in synchronizor.
|
|
8
10
|
|
|
9
11
|
## 0.4.2
|
|
10
12
|
* Supporting the Oauth Token V2 authentication
|
|
@@ -38,6 +38,8 @@ synchronizor = lp.Synchronizer(base='Prop1',targets=['Prop2'])
|
|
|
38
38
|
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
There is a possibility to setup some rules so you can filter when migrating from one property to another. See [dynamic Filtering](#dynamic-component-filter)
|
|
42
|
+
|
|
41
43
|
## SyncComponent Method
|
|
42
44
|
|
|
43
45
|
The `syncComponent` method can take 3 arguments.
|
|
@@ -166,18 +168,58 @@ An example on how the data element looks like:
|
|
|
166
168
|
```
|
|
167
169
|
**NOTE** : The JSON representation should be flawless and the regular expression used as well, otherwise the script can break trying to decrypting it.
|
|
168
170
|
|
|
169
|
-
###
|
|
171
|
+
### Dynamic Component Filtering options
|
|
172
|
+
|
|
173
|
+
#### Data Elements
|
|
174
|
+
|
|
175
|
+
You can pass a Data Element name during the instanciation of the `Synchronizer`. This data element needs to resides in the base property and it will contain a valid JSON that will describe the different rules that will apply during the synchronization.\
|
|
176
|
+
The format of the JSON representation for the data element is [explained above](#dynamic-component-filter)\
|
|
177
|
+
The data element name needs to be passed in the `dynamicRuleComponent` parameter.
|
|
178
|
+
|
|
179
|
+
Hence the code would look like this for instantiation:
|
|
180
|
+
```python
|
|
181
|
+
|
|
182
|
+
import launchpy as lp
|
|
183
|
+
|
|
184
|
+
lp.importConfigFile('config.json')
|
|
185
|
+
synchronizor = lp.Synchronizer(base='Prop1',targets=['Prop2'],dynamicRuleComponent='dataElementName')
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### Code
|
|
190
|
+
|
|
191
|
+
You can also provide the JSON representation of the filter used for synchronization via a dictionary, directly in your notebook.\
|
|
192
|
+
A method called `dynamicFiltering` allows you to load a dynamic filter directly within the python application and do not require the creation of data element for it.
|
|
193
|
+
|
|
194
|
+
So after instantiation, you can now pass the rule such as:
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
import launchpy as lp
|
|
198
|
+
|
|
199
|
+
lp.importConfigFile('config.json')
|
|
200
|
+
synchronizor = lp.Synchronizer(base='Prop1',targets=['Prop2'])
|
|
201
|
+
myRules = [
|
|
202
|
+
{
|
|
203
|
+
'name':'myName',
|
|
204
|
+
'targetProperties':'.+ some condition .+ ',
|
|
205
|
+
'exclComponents':[
|
|
206
|
+
'DE - My Data Element',
|
|
207
|
+
'RL - My Rule'
|
|
208
|
+
],
|
|
209
|
+
'inclComponents':[
|
|
210
|
+
'somecomponent name'
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
]
|
|
170
214
|
|
|
171
|
-
|
|
215
|
+
synchronizor.dynamicFiltering(myRules)
|
|
172
216
|
|
|
173
|
-
```python
|
|
174
|
-
synchronizor = lp.Synchronizer(base='BaseProperty',targets=['Target Property 1',
|
|
175
|
-
'Target Property 2',
|
|
176
|
-
'Target Property 3'],
|
|
177
|
-
dynamicRuleComponent='syncFilter')
|
|
178
217
|
```
|
|
179
|
-
|
|
180
|
-
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
### Dynamic Component filter check
|
|
221
|
+
|
|
222
|
+
Once you have loaded your dynamic component rules in your Synchronizer class, you can access 2 attributes to verify the correct setup.
|
|
181
223
|
|
|
182
224
|
* `dict_config`
|
|
183
225
|
The `dict_config` attribute will be a copy of your data element setup, but a dictionary instead of an array where all of the target properties rule will be a key.\
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.4.3-3"
|
|
@@ -283,7 +283,7 @@ class AdobeRequest:
|
|
|
283
283
|
status_code = {'error': 'Request Error'}
|
|
284
284
|
return status_code
|
|
285
285
|
|
|
286
|
-
def deleteData(self, endpoint: str, params: dict = None, headers: dict = None, *args, **kwargs):
|
|
286
|
+
def deleteData(self, endpoint: str, params: dict = None, data=None, headers: dict = None, *args, **kwargs):
|
|
287
287
|
"""
|
|
288
288
|
Abstraction for deleting data
|
|
289
289
|
"""
|
|
@@ -294,6 +294,10 @@ class AdobeRequest:
|
|
|
294
294
|
res = requests.delete(endpoint, headers=headers)
|
|
295
295
|
elif params is not None:
|
|
296
296
|
res = requests.delete(endpoint, headers=headers, params=params)
|
|
297
|
+
elif params is None and data is not None:
|
|
298
|
+
res = requests.delete(endpoint, headers=headers, data=json.dumps(data))
|
|
299
|
+
elif params is not None and data is not None:
|
|
300
|
+
res = requests.delete(endpoint, headers=headers, params=params, data=json.dumps(data))
|
|
297
301
|
try:
|
|
298
302
|
status_code = res.status_code
|
|
299
303
|
except:
|
|
@@ -176,6 +176,24 @@ class Library:
|
|
|
176
176
|
res = self.connector.patchData(self.endpoint +url, data=obj)
|
|
177
177
|
return res
|
|
178
178
|
|
|
179
|
+
def removeDataElements(self,data_element_ids:list)->dict:
|
|
180
|
+
"""
|
|
181
|
+
Take a list of data elements and remove them from the library.
|
|
182
|
+
Arguments:
|
|
183
|
+
data_element_ids: REQUIRED : list of data elements id
|
|
184
|
+
"""
|
|
185
|
+
if self.state != 'development':
|
|
186
|
+
print('State is not development, cannot update relationships')
|
|
187
|
+
return None
|
|
188
|
+
obj = {'data': []}
|
|
189
|
+
if type(data_element_ids) == str:
|
|
190
|
+
data_element_ids = data_element_ids.split(' ')
|
|
191
|
+
for ids in data_element_ids:
|
|
192
|
+
obj['data'].append({"id": ids,"type": "data_elements"})
|
|
193
|
+
url = f'/libraries/{self.id}/relationships/data_elements'
|
|
194
|
+
print(obj)
|
|
195
|
+
res = self.connector.deleteData(self.endpoint +url, data=obj)
|
|
196
|
+
return res
|
|
179
197
|
|
|
180
198
|
def addRules(self, rules_ids: list)->dict:
|
|
181
199
|
"""
|
|
@@ -216,6 +234,25 @@ class Library:
|
|
|
216
234
|
res = self.connector.patchData(self.endpoint + url, data=obj)
|
|
217
235
|
return res
|
|
218
236
|
|
|
237
|
+
def removeRules(self,rules_ids:list)->dict:
|
|
238
|
+
"""
|
|
239
|
+
Remove the rules that are passed.
|
|
240
|
+
Arguments:
|
|
241
|
+
rules_ids: REQUIRED : list of rules id
|
|
242
|
+
"""
|
|
243
|
+
if self.state != 'development':
|
|
244
|
+
print('State is not development, cannot add relationships')
|
|
245
|
+
return None
|
|
246
|
+
obj = {'data': []}
|
|
247
|
+
if type(rules_ids) == str:
|
|
248
|
+
rules_ids = rules_ids.split(' ')
|
|
249
|
+
for ids in rules_ids:
|
|
250
|
+
obj['data'].append({"id": ids, "type": "rules"})
|
|
251
|
+
url = f'/libraries/{self.id}/relationships/rules'
|
|
252
|
+
res = self.connector.deleteData(self.endpoint + url, data=obj)
|
|
253
|
+
return res
|
|
254
|
+
|
|
255
|
+
|
|
219
256
|
def addExtensions(self, extensions_ids: list)->object:
|
|
220
257
|
"""
|
|
221
258
|
Take a list of extension id and attach them to the library.
|
|
@@ -291,9 +328,11 @@ class Library:
|
|
|
291
328
|
new_env = self.connector.getData(self.endpoint+path)
|
|
292
329
|
return new_env
|
|
293
330
|
|
|
294
|
-
def updateLibrary(self)->dict:
|
|
331
|
+
def updateLibrary(self,empty:bool=False)->dict:
|
|
295
332
|
"""
|
|
296
333
|
Update the library
|
|
334
|
+
Arguments:
|
|
335
|
+
empty : OPTIONAL : You want to empty the library.
|
|
297
336
|
"""
|
|
298
337
|
path = f'/libraries/{self.id}'
|
|
299
338
|
data = {
|
|
@@ -305,6 +344,21 @@ class Library:
|
|
|
305
344
|
}
|
|
306
345
|
}
|
|
307
346
|
}
|
|
347
|
+
if True:
|
|
348
|
+
data['relationships'] = {
|
|
349
|
+
"data_elements": {
|
|
350
|
+
"data": []
|
|
351
|
+
},
|
|
352
|
+
"rules": {
|
|
353
|
+
"data": []
|
|
354
|
+
},
|
|
355
|
+
"extensions": {
|
|
356
|
+
"data": []
|
|
357
|
+
},
|
|
358
|
+
"environment":{
|
|
359
|
+
"data":{},
|
|
360
|
+
}
|
|
361
|
+
}
|
|
308
362
|
res = self.connector.patchData(self.endpoint+path,data=data)
|
|
309
363
|
return res
|
|
310
364
|
|
|
@@ -48,7 +48,7 @@ class Property:
|
|
|
48
48
|
self._Rules = data['links']['rules']
|
|
49
49
|
self._RuleComponents = 'https://reactor.adobe.io/properties/' + \
|
|
50
50
|
self.id + '/rule_components'
|
|
51
|
-
self._Host = 'https://reactor.adobe.io
|
|
51
|
+
self._Host = 'https://reactor.adobe.io/properties/' + \
|
|
52
52
|
data['id']+'/hosts'
|
|
53
53
|
self._Note = 'https://reactor.adobe.io/notes/'
|
|
54
54
|
self._Environments = data['links']['environments']
|
|
@@ -507,6 +507,20 @@ class Property:
|
|
|
507
507
|
data = data + append_data
|
|
508
508
|
return data
|
|
509
509
|
|
|
510
|
+
def getLibrary(self,libraryId:str=None)->dict:
|
|
511
|
+
"""
|
|
512
|
+
get a library based on its ID.
|
|
513
|
+
Arguments:
|
|
514
|
+
libraryId : REQUIRED : Library ID to be retrieved
|
|
515
|
+
"""
|
|
516
|
+
if libraryId is None:
|
|
517
|
+
raise ValueError("Require a library ID")
|
|
518
|
+
path = f"/libraries/{libraryId}"
|
|
519
|
+
res = self.connector.getData(self.endpoint+path)
|
|
520
|
+
if 'data' in res.keys():
|
|
521
|
+
return res['data']
|
|
522
|
+
return res
|
|
523
|
+
|
|
510
524
|
def getNotes(self, data: object)->list:
|
|
511
525
|
"""
|
|
512
526
|
Retrieve the note associated with the object pass to the method. Returns list.
|
|
@@ -1145,6 +1159,35 @@ class Property:
|
|
|
1145
1159
|
'https://reactor.adobe.io/environments/'+env_id)
|
|
1146
1160
|
return data
|
|
1147
1161
|
|
|
1162
|
+
def deleteLibrary(self,library:str=None,components:bool=False)->str:
|
|
1163
|
+
"""
|
|
1164
|
+
Delete a Library based on its name or ID.
|
|
1165
|
+
Arguments:
|
|
1166
|
+
library : REQUIRED : Either the ID of the library or the name of the library.
|
|
1167
|
+
components : OPTIONAL : If set to True, it will try to delete all components inside that library.
|
|
1168
|
+
"""
|
|
1169
|
+
if library is None:
|
|
1170
|
+
raise ValueError("Require at least library ID")
|
|
1171
|
+
libraries = self.getLibraries()
|
|
1172
|
+
librariesIds = [lib['id'] for lib in libraries]
|
|
1173
|
+
librariesNameId = {lib['attributes']['name']:lib['id'] for lib in libraries}
|
|
1174
|
+
if library in librariesIds:
|
|
1175
|
+
libraryId = library
|
|
1176
|
+
else:
|
|
1177
|
+
libraryId = librariesNameId[library]
|
|
1178
|
+
path = f"/libraries/{libraryId}"
|
|
1179
|
+
if components==True:
|
|
1180
|
+
myLib = self.getLibrary(libraryId)
|
|
1181
|
+
libClass = Library(myLib)
|
|
1182
|
+
rules = libClass.getRules()
|
|
1183
|
+
dataelements = libClass.getDataElements()
|
|
1184
|
+
res = self.connector.deleteData('https://reactor.adobe.io/'+path)
|
|
1185
|
+
for rule in rules:
|
|
1186
|
+
self.deleteRule(rule['id'])
|
|
1187
|
+
for de in dataelements:
|
|
1188
|
+
self.deleteDataElement(de['id'])
|
|
1189
|
+
return res
|
|
1190
|
+
|
|
1148
1191
|
def extensionsInfo(data: list)->dict:
|
|
1149
1192
|
"""
|
|
1150
1193
|
Return a dictionary from the list provided from the extensions request.
|
|
@@ -44,21 +44,8 @@ class Synchronizer:
|
|
|
44
44
|
self.translator = Translator()
|
|
45
45
|
self.translator.setBaseExtensions(self.base['extensions'],self.base['name'])
|
|
46
46
|
self.translator.setBaseRules(self.base['rules'],self.base['name'])
|
|
47
|
-
self.dict_config = {}
|
|
48
|
-
if kwargs.get("dynamicRuleComponent",None) is not None:
|
|
49
|
-
configRules = [de for de in self.base['dataElements'] if de['attributes']['name'] == kwargs.get("dynamicRuleComponent",None)]
|
|
50
|
-
if len(configRules)==1:
|
|
51
|
-
configRules = configRules[0]
|
|
52
|
-
else:
|
|
53
|
-
raise ValueError("The dynamicRuleComponent is using a value that does not match any data element.")
|
|
54
|
-
codeConfig:list = json.loads(json.loads(configRules['attributes']['settings'])['source'])## list expected from the code
|
|
55
|
-
for rule in codeConfig:
|
|
56
|
-
self.dict_config[rule['targetProperties']] = {'inclComponents':[],'exclComponents':[]}
|
|
57
|
-
if 'inclComponents' in rule.keys():
|
|
58
|
-
self.dict_config[rule['targetProperties']]['inclComponents'] += rule['inclComponents']
|
|
59
|
-
if 'exclComponents' in rule.keys():
|
|
60
|
-
self.dict_config[rule['targetProperties']]['exclComponents'] += rule['exclComponents']
|
|
61
47
|
self.targets = {}
|
|
48
|
+
self.target_configs = {}
|
|
62
49
|
for target in targets:
|
|
63
50
|
tmp_target = [prop for prop in properties if prop['attributes']['name'] == target]
|
|
64
51
|
if len(tmp_target) == 0:
|
|
@@ -73,19 +60,60 @@ class Synchronizer:
|
|
|
73
60
|
self.translator.extendRules(self.targets[target]['rules'],self.targets[target]['name'])
|
|
74
61
|
else:
|
|
75
62
|
self.translator.rules[self.targets[target]['name']] = None
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
63
|
+
if kwargs.get("dynamicRuleComponent",None) is not None:
|
|
64
|
+
configRules = [de for de in self.base['dataElements'] if de['attributes']['name'] == kwargs.get("dynamicRuleComponent",None)]
|
|
65
|
+
if len(configRules)==1:
|
|
66
|
+
configRules = configRules[0]
|
|
67
|
+
else:
|
|
68
|
+
raise ValueError("The dynamicRuleComponent is using a value that does not match any data element.")
|
|
69
|
+
codeConfig:list = json.loads(json.loads(configRules['attributes']['settings'])['source'])## list expected from the code
|
|
70
|
+
self.dynamicFiltering(codeConfig)
|
|
71
|
+
|
|
72
|
+
def dynamicFiltering(self,dynamicFilterJSON:dict,override:bool=True)->None:
|
|
73
|
+
"""
|
|
74
|
+
Building the dynamic rule filtering for each of the target properties.
|
|
75
|
+
Base on this code format
|
|
76
|
+
[
|
|
77
|
+
{
|
|
78
|
+
'name':'myName',
|
|
79
|
+
'targetProperties':'.+ some condition .+ ',
|
|
80
|
+
'exclComponents':[
|
|
81
|
+
'DE - My Data Element',
|
|
82
|
+
'RL - My Rule'
|
|
83
|
+
],
|
|
84
|
+
'inclComponents':[
|
|
85
|
+
'somecomponent name'
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
Arguments:
|
|
90
|
+
dynamicFilterJSON : REQUIRED : The JSON representation of your rules.
|
|
91
|
+
override : OPTIONAL : Replace the existing dynamic filtering. Default True.
|
|
92
|
+
If set to False, apply the logic on top of the existing one loaded before.
|
|
93
|
+
"""
|
|
94
|
+
if override == True:
|
|
95
|
+
self.dict_config = {} ## global dynamic rule filtering
|
|
96
|
+
self.target_configs = {} ## dynamic rule filtering apply to target
|
|
97
|
+
for rule in dynamicFilterJSON:
|
|
98
|
+
self.dict_config[rule['targetProperties']] = {'inclComponents':[],'exclComponents':[]}
|
|
99
|
+
if 'inclComponents' in rule.keys():
|
|
100
|
+
self.dict_config[rule['targetProperties']]['inclComponents'] += rule['inclComponents']
|
|
101
|
+
if 'exclComponents' in rule.keys():
|
|
102
|
+
self.dict_config[rule['targetProperties']]['exclComponents'] += rule['exclComponents']
|
|
103
|
+
for rule in self.dict_config.keys():
|
|
104
|
+
for target in self.targets.keys():
|
|
105
|
+
if re.search(rule,target) is not None:
|
|
106
|
+
if target in self.target_configs.keys():
|
|
107
|
+
if self.dict_config[rule]['exclComponents'] not in self.target_configs[target]['exclComponents']:
|
|
82
108
|
self.target_configs[target]['exclComponents'] += deepcopy(self.dict_config[rule]['exclComponents'])
|
|
109
|
+
if self.dict_config[rule]['inclComponents'] not in self.target_configs[target]['inclComponents']:
|
|
83
110
|
self.target_configs[target]['inclComponents'] += deepcopy(self.dict_config[rule]['inclComponents'])
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
111
|
+
else:
|
|
112
|
+
self.target_configs[target] = {
|
|
113
|
+
'exclComponents': deepcopy(self.dict_config[rule]['exclComponents']),
|
|
114
|
+
'inclComponents': deepcopy(self.dict_config[rule]['inclComponents'])
|
|
115
|
+
}
|
|
116
|
+
|
|
89
117
|
|
|
90
118
|
def syncComponent(self,componentName:str=None,componentId:str=None,publishedVersion:bool=False,**kwargs)->None:
|
|
91
119
|
"""
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.4.3-1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|