launchpy 0.4.5.post6__tar.gz → 0.4.6__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 (31) hide show
  1. {launchpy-0.4.5.post6/launchpy.egg-info → launchpy-0.4.6}/PKG-INFO +1 -1
  2. {launchpy-0.4.5.post6 → launchpy-0.4.6}/docs/releases.md +3 -0
  3. {launchpy-0.4.5.post6 → launchpy-0.4.6}/docs/synchronizer.md +52 -3
  4. launchpy-0.4.6/launchpy/__version__.py +1 -0
  5. {launchpy-0.4.5.post6 → launchpy-0.4.6}/launchpy/connector.py +6 -6
  6. {launchpy-0.4.5.post6 → launchpy-0.4.6}/launchpy/launchpy.py +20 -4
  7. {launchpy-0.4.5.post6 → launchpy-0.4.6}/launchpy/synchronizer.py +23 -12
  8. {launchpy-0.4.5.post6 → launchpy-0.4.6/launchpy.egg-info}/PKG-INFO +1 -1
  9. launchpy-0.4.5.post6/launchpy/__version__.py +0 -1
  10. {launchpy-0.4.5.post6 → launchpy-0.4.6}/LICENSE +0 -0
  11. {launchpy-0.4.5.post6 → launchpy-0.4.6}/README.md +0 -0
  12. {launchpy-0.4.5.post6 → launchpy-0.4.6}/docs/admin.md +0 -0
  13. {launchpy-0.4.5.post6 → launchpy-0.4.6}/docs/getstarted.md +0 -0
  14. {launchpy-0.4.5.post6 → launchpy-0.4.6}/docs/library.md +0 -0
  15. {launchpy-0.4.5.post6 → launchpy-0.4.6}/docs/main.md +0 -0
  16. {launchpy-0.4.5.post6 → launchpy-0.4.6}/docs/property.md +0 -0
  17. {launchpy-0.4.5.post6 → launchpy-0.4.6}/docs/translator.md +0 -0
  18. {launchpy-0.4.5.post6 → launchpy-0.4.6}/launchpy/__init__.py +0 -0
  19. {launchpy-0.4.5.post6 → launchpy-0.4.6}/launchpy/admin.py +0 -0
  20. {launchpy-0.4.5.post6 → launchpy-0.4.6}/launchpy/config.py +0 -0
  21. {launchpy-0.4.5.post6 → launchpy-0.4.6}/launchpy/configs.py +0 -0
  22. {launchpy-0.4.5.post6 → launchpy-0.4.6}/launchpy/library.py +0 -0
  23. {launchpy-0.4.5.post6 → launchpy-0.4.6}/launchpy/property.py +0 -0
  24. {launchpy-0.4.5.post6 → launchpy-0.4.6}/launchpy.egg-info/SOURCES.txt +0 -0
  25. {launchpy-0.4.5.post6 → launchpy-0.4.6}/launchpy.egg-info/dependency_links.txt +0 -0
  26. {launchpy-0.4.5.post6 → launchpy-0.4.6}/launchpy.egg-info/requires.txt +0 -0
  27. {launchpy-0.4.5.post6 → launchpy-0.4.6}/launchpy.egg-info/top_level.txt +0 -0
  28. {launchpy-0.4.5.post6 → launchpy-0.4.6}/pyproject.toml +0 -0
  29. {launchpy-0.4.5.post6 → launchpy-0.4.6}/requirements.txt +0 -0
  30. {launchpy-0.4.5.post6 → launchpy-0.4.6}/setup.cfg +0 -0
  31. {launchpy-0.4.5.post6 → launchpy-0.4.6}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: launchpy
3
- Version: 0.4.5.post6
3
+ Version: 0.4.6
4
4
  Summary: Adobe Launch API wrapper
5
5
  Home-page: https://github.com/pitchmuc/launchpy
6
6
  Author: Julien Piccini
@@ -3,6 +3,9 @@
3
3
  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
+ ## 0.4.6
7
+ * Allow Synchronizer to be used in multi IMS organization setup.
8
+
6
9
  ## 0.4.5
7
10
  * adding `getExtension` in `Property` class
8
11
  * improve `upgradeExtension` in `Property` class
@@ -13,7 +13,6 @@ The Synchronizer will allow you to specify a template property and target proper
13
13
  This class is currently requiring the following elements on your side:
14
14
 
15
15
  * You have imported the config file (via `importConfigFile`) or configure your module via `configure` method.
16
- * Your template property and target properties are located in the same organization
17
16
  * You have unique name for your rule and data elements
18
17
  * You have the same extension installed in both the template and target properties.\
19
18
  The Synchronizer will not sync the extensions configuration.
@@ -24,8 +23,8 @@ If a rule and a data element have the same name, by passing that name in the `sy
24
23
 
25
24
  In order to instantiate the `Synchronizer` class, you will need to provide 2 elements:
26
25
 
27
- * The name of the base property (as string)
28
- * The names of the target properties (as a list of strings)
26
+ * The name of the base property, as `string` or `launchpy.Property` instance
27
+ * The names of the target properties (as a list of `strings`, or `launchpy.Property` instances)
29
28
 
30
29
  Example:
31
30
 
@@ -38,6 +37,56 @@ synchronizor = lp.Synchronizer(base='Prop1',targets=['Prop2'])
38
37
 
39
38
  ```
40
39
 
40
+ ### Multi Organization environments
41
+
42
+ For some clients, they may want to synchronize the rules and data elements across organization setup.\
43
+ That is possible, but the requirements are still needed regarding the following elements:
44
+ * You have unique name for your rule and data elements
45
+ * You have the same extension installed in both the template and target properties.
46
+
47
+ The synchronizer will use the environment credential lastly loaded in the system.\
48
+ We would recommend to load first the target organization that you want to sync to, and then the base organization.\
49
+ You will be able to use the Property instance of the target organization in order to sync the element afterwards.
50
+
51
+ Example of setup
52
+
53
+ ```py
54
+ import launchpy as lp
55
+
56
+
57
+ ### targeted org
58
+ lp.importConfigFile('config_target.json')
59
+ admin_target = lp.Admin()
60
+ targetId = admin_target.getCompanyId()
61
+ target_props = admin_target.getProperties(targetId)
62
+
63
+ target_prop = lp.Property(target_props[1]) ## selecting one of the property
64
+
65
+ ### Source org for base
66
+ lp.importConfigFile('config_source.json')
67
+ admin = lp.Admin()
68
+ sourceId = admin_target.getCompanyId()
69
+ source_props = admin.getProperties(sourceId)
70
+
71
+ base = lp.Property(source_props[0]) ### selecting the first one as base - it can be any
72
+
73
+ synchronizor = lp.Synchronizer(base=base,targets=['another Property Name to sync',target_prop])
74
+
75
+ ### rest is as usual
76
+ ```
77
+
78
+ If you have private extension that are not released between organization, you can pass a mapping to the synchronizer to tell that these extensions are to be treated as one.\
79
+ You would need to pass the target extension name and the base extension name so that it is mapped as a single one.
80
+
81
+ Example:
82
+ ```py
83
+
84
+ synchronizor = lp.Synchronizer(base=base,targets=['another Property Name to sync',target_prop],mapping_extensions={'extension_name_target':'extension_name_base'})
85
+
86
+ ```
87
+
88
+
89
+ ### Additional options
41
90
  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
91
 
43
92
  ## SyncComponent Method
@@ -0,0 +1 @@
1
+ __version__ = "0.4.6"
@@ -31,7 +31,7 @@ class AdobeRequest:
31
31
  raise Exception(
32
32
  'You have to upload the configuration file with importConfigFile method.')
33
33
  self.config = deepcopy(config_object)
34
- self.header = header
34
+ self.header = deepcopy(header)
35
35
  self.retry = retry
36
36
  if self.config['token'] == '' or time.time() > self.config['date_limit']:
37
37
  if 'scopes' in self.config.keys() and self.config.get('scopes',None) is not None:
@@ -42,9 +42,9 @@ class AdobeRequest:
42
42
  token_and_expiry = self.get_jwt_token_and_expiry_for_config(config=self.config, verbose=verbose)
43
43
  token = token_and_expiry['token']
44
44
  expiry = token_and_expiry['expiry']
45
- self.token = token
46
- self.config['token'] = token
47
- self.config['date_limit'] = time.time() + expiry - 500
45
+ self.token = deepcopy(token)
46
+ self.config['token'] = deepcopy(token)
47
+ self.config['date_limit'] = deepcopy(time.time() + expiry - 500)
48
48
  self.header.update({'Authorization': f'Bearer {token}'})
49
49
 
50
50
  def get_jwt_token_and_expiry_for_config(self,config: dict, verbose: bool = False, save: bool = False, *args, **kwargs) -> Dict[str, str]:
@@ -166,8 +166,8 @@ class AdobeRequest:
166
166
  elif self.connectionType == 'jwt':
167
167
  token_and_expiry = self.get_jwt_token_and_expiry_for_config(config=self.config)
168
168
  token = token_and_expiry['token']
169
- self.config['token'] = token
170
- self.config['date_limit'] = time.time() + token_and_expiry['expiry'] - 500
169
+ self.config['token'] = deepcopy(token)
170
+ self.config['date_limit'] = deepcopy(time.time() + token_and_expiry['expiry'] - 500)
171
171
  self.header.update({'Authorization': f'Bearer {token}'})
172
172
 
173
173
  def getData(self, endpoint: str, params: dict = None, data: dict = None, headers: dict = None, *args, **kwargs):
@@ -405,14 +405,23 @@ class Translator:
405
405
  --> You can use the translate method to translate Data Element settings
406
406
  3. setBaseRules
407
407
  4. extendRules
408
- --> You can use the translate method to translate Rule Components settings
408
+ --> You can use the translate method to translate Rule Components settings
409
+
410
+ Possible arguments:
411
+ mapping_extensions : dictionary of extension names that should be replaced.
412
+ Such as: {'old_name':'new_name'}
409
413
  """
410
414
 
411
- def __init__(self):
415
+ def __init__(self,**kwargs):
412
416
  self.rules = {}
413
417
  self.baseRuleIdName = {}
414
418
  self.extensions = {}
415
419
  self.baseExtensionIdName = {}
420
+ self.mapping_extension = {}
421
+ if kwargs.get('mapping_extensions') is not None:
422
+ if type(kwargs.get('mapping_extensions')) == dict:
423
+ for key, value in kwargs.get('mapping_extensions').items():
424
+ self.mapping_extension[key] = value
416
425
 
417
426
  def setBaseExtensions(self, base_property_extensions: list, property_name: str):
418
427
  """
@@ -422,8 +431,12 @@ class Translator:
422
431
  property_name : REQUIRED : name of your base property.
423
432
  """
424
433
  self.baseExtensionIdName = {ext['id'] : ext['attributes']['name'] for ext in base_property_extensions}
434
+ for extId, extName in self.baseExtensionIdName.items():
435
+ if extName in self.mapping_extension.keys():
436
+ self.baseExtensionIdName[extId] = self.mapping_extension[extName]
425
437
  self.extensions = {ext['attributes']['name']:{property_name:ext['id']} for ext in base_property_extensions}
426
438
 
439
+
427
440
  def extendExtensions(self, new_property_extensions: list, new_prop_name: str)-> None:
428
441
  """
429
442
  Add the extensions id from a target property.
@@ -432,8 +445,11 @@ class Translator:
432
445
  new_prop_name : REQUIRED : target property name.
433
446
  """
434
447
  for ext in new_property_extensions:
435
- if ext['attributes']['name'] in list(self.extensions.keys()):
436
- self.extensions[ext['attributes']['name']][new_prop_name] = ext['id']
448
+ extName = ext['attributes']['name']
449
+ if extName in self.mapping_extension.keys():
450
+ extName = self.mapping_extension[extName]
451
+ if extName in list(self.extensions.keys()):
452
+ self.extensions[extName][new_prop_name] = ext['id']
437
453
  return self.extensions
438
454
 
439
455
  def setBaseRules(self, base_property_rules: list, property_name: str):
@@ -21,37 +21,48 @@ class Synchronizer:
21
21
  It requires that you have imported a configuration file.
22
22
  """
23
23
 
24
- def __init__(self,base:str=None,targets:list=None,**kwargs)->None:
24
+ def __init__(self,base:str | Property = None,targets:list=None,**kwargs)->None:
25
25
  """
26
26
  Instantiating the Synchronizer taking 2 parameters, base property name, target property list.
27
27
  Arguments:
28
- base : REQUIRED : The name of your base/template property
28
+ base : REQUIRED : The name of your base/template property or the instance of Property class
29
29
  targets : REQUIRED : The list of property names that you want to sync with.
30
+ the list of target can be string of property name or Property instance for other organization.
30
31
  possible kwargs:
31
32
  dynamicRuleComponent: A data element name that contains rule for synchronization on the property.
33
+ mapping_extensions : A dictionary of target extension name and base extension name when in different IMS org and 2 private extensions are name differently for the same purpose.
32
34
  """
33
35
  tmp_admin = Admin()
34
36
  cid = tmp_admin.getCompanyId()
35
37
  properties = tmp_admin.getProperties(cid)
36
- base_property = [prop for prop in properties if prop['attributes']['name'] == base]
37
- if len(base_property) ==0:
38
- raise KeyError("The base property name has not been found in your account")
38
+ mapping_extensions = kwargs.get('mapping_extensions',None)
39
39
  self.base = {}
40
- self.base["name"] = base
41
- self.base["api"]:Property = Property(base_property[0])
40
+ if type(base) == str:
41
+ base_property = [prop for prop in properties if prop['attributes']['name'] == base]
42
+ if len(base_property) ==0:
43
+ raise KeyError("The base property name has not been found in your account")
44
+ self.base["name"] = base
45
+ self.base["api"]:Property = Property(base_property[0])
46
+ elif type(base) == Property:
47
+ self.base["name"] = base.name
48
+ self.base["api"]:Property = base
42
49
  self.base['rules'] = self.base['api'].getRules()
43
50
  self.base['dataElements'] = self.base['api'].getDataElements()
44
51
  self.base['extensions'] = self.base['api'].getExtensions()
45
- self.translator = Translator()
52
+ self.translator = Translator(mapping_extensions=mapping_extensions)
46
53
  self.translator.setBaseExtensions(self.base['extensions'],self.base['name'])
47
54
  self.translator.setBaseRules(self.base['rules'],self.base['name'])
48
55
  self.targets = {}
49
56
  self.target_configs = {}
50
57
  for target in targets:
51
- tmp_target = [prop for prop in properties if prop['attributes']['name'] == target]
52
- if len(tmp_target) == 0:
53
- raise KeyError(f"The target property : {target} cannot be found. Please, fix it")
54
- self.targets[target] = {'api' : Property(tmp_target[0]),'name':target}
58
+ if isinstance(target,str):
59
+ tmp_target = [prop for prop in properties if prop['attributes']['name'] == target]
60
+ if len(tmp_target) == 0:
61
+ raise KeyError(f"The target property : {target} cannot be found. Please, fix it")
62
+ self.targets[target] = {'api' : Property(tmp_target[0]),'name':target}
63
+ elif isinstance(target,Property):
64
+ self.targets[target.name] = {'api' : deepcopy(target),'name':target.name}
65
+ target = target.name
55
66
  self.targets[target]['rules'] = self.targets[target]['api'].getRules()
56
67
  self.targets[target]['extensions'] = self.targets[target]['api'].getExtensions()
57
68
  self.targets[target]['dataElements'] = self.targets[target]['api'].getDataElements()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: launchpy
3
- Version: 0.4.5.post6
3
+ Version: 0.4.6
4
4
  Summary: Adobe Launch API wrapper
5
5
  Home-page: https://github.com/pitchmuc/launchpy
6
6
  Author: Julien Piccini
@@ -1 +0,0 @@
1
- __version__ = "0.4.5-6"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes