aepp 0.5.1.post1__py3-none-any.whl → 0.5.2.post1__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.
aepp/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.5.1-1"
1
+ __version__ = "0.5.2-1"
aepp/classmanager.py CHANGED
@@ -23,7 +23,7 @@ class ClassManager:
23
23
  schemaAPI:'Schema'=None,
24
24
  config: Union[dict,ConnectObject] = aepp.config.config_object,
25
25
  description: str = 'power by aepp',
26
- localFolder:str=None,
26
+ localFolder:str | list | None = None,
27
27
  sandbox:str=None,
28
28
  **kwargs
29
29
  )->None:
@@ -48,13 +48,16 @@ class ClassManager:
48
48
  elif config is not None and localFolder is None:
49
49
  self.schemaAPI = Schema(config=config)
50
50
  elif localFolder is not None:
51
- self.localfolder = Path(localFolder)
52
- if self.localfolder.exists() is False:
51
+ if isinstance(localFolder, str):
52
+ self.localfolder = [Path(localFolder)]
53
+ elif isinstance(localFolder, list):
54
+ self.localfolder = [Path(lf) for lf in localFolder]
55
+ if any([folder.exists() is False for folder in self.localfolder]):
53
56
  raise Exception(f"The local folder {self.localfolder} does not exist. Please create it and extract your sandbox before using it.")
54
57
  self.schemaAPI = None
55
- self.classFolder = self.localfolder / 'class'
56
- self.behavFolder = self.localfolder / 'behaviour'
57
- if self.classFolder.exists() is False:
58
+ self.classFolder = [folder / 'class' for folder in self.localfolder]
59
+ self.behavFolder = [folder / 'behaviour' for folder in self.localfolder]
60
+ if any([folder.exists() is False for folder in self.classFolder]):
58
61
  raise Exception(f"The local folder {self.classFolder} does not exist. Please create it and extract your sandbox before using it.")
59
62
  else:
60
63
  raise Exception("You need to provide a schemaAPI instance or a config object to connect to the API or a local folder to use the local storage")
@@ -71,9 +74,11 @@ class ClassManager:
71
74
  elif type(aepclass) == dict:
72
75
  self.tenantId = aepclass.get('meta:tenantNamespace'," ")
73
76
  elif self.localfolder is not None:
74
- config_json = json.load(FileIO(self.localfolder / 'config.json'))
75
- if config_json.get('tenantId',None) is not None:
76
- self.tenantId = config_json.get('tenantId')
77
+ for folder in self.localfolder:
78
+ config_json = json.load(FileIO(folder / 'config.json'))
79
+ if config_json.get('tenantId',None) is not None:
80
+ self.tenantId = config_json.get('tenantId')
81
+ break
77
82
  else:
78
83
  self.tenantId = " "
79
84
  if type(aepclass) == dict:
@@ -82,10 +87,15 @@ class ClassManager:
82
87
  self.aepclass = self.schemaAPI.getClass(aepclass['$id'],full=False,xtype='xed')
83
88
  self.EDITABLE = True
84
89
  elif self.localfolder is not None:
85
- for json_file in self.classFolder.glob('*.json'):
86
- tmp_def = json.load(FileIO(json_file))
87
- if tmp_def.get('$id') == aepclass['$id']:
88
- self.aepclass = tmp_def
90
+ found = False
91
+ for folder in self.classFolder:
92
+ for json_file in folder.glob('*.json'):
93
+ tmp_def = json.load(FileIO(json_file))
94
+ if tmp_def.get('$id') == aepclass['$id']:
95
+ self.aepclass = tmp_def
96
+ found = True
97
+ break
98
+ if found:
89
99
  break
90
100
  self.EDITABLE = False
91
101
  elif self.tenantId[1:] not in aepclass['$id']:
@@ -93,10 +103,15 @@ class ClassManager:
93
103
  self.aepclass = self.schemaAPI.getClass(aepclass['$id'],full=True,xtype='xed')
94
104
  self.EDITABLE = False
95
105
  elif self.localfolder is not None:
96
- for json_file in self.classFolder.glob('*.json'):
97
- tmp_def = json.load(FileIO(json_file))
98
- if tmp_def.get('$id') == aepclass['$id']:
99
- self.aepclass = tmp_def
106
+ found = False
107
+ for folder in self.classFolder:
108
+ for json_file in folder.glob('*.json'):
109
+ tmp_def = json.load(FileIO(json_file))
110
+ if tmp_def.get('$id') == aepclass['$id']:
111
+ self.aepclass = tmp_def
112
+ found = True
113
+ break
114
+ if found:
100
115
  break
101
116
  self.EDITABLE = False
102
117
  self.__setAttributes__(self.aepclass)
@@ -106,20 +121,30 @@ class ClassManager:
106
121
  self.aepclass = self.schemaAPI.getClass(aepclass,full=False,xtype='xed')
107
122
  self.EDITABLE = True
108
123
  elif self.localfolder is not None:
109
- for json_file in self.classFolder.glob('*.json'):
110
- tmp_def = json.load(FileIO(json_file))
111
- if tmp_def.get('$id') == aepclass or tmp_def.get('meta:altId') == aepclass:
112
- self.aepclass = tmp_def
124
+ found = False
125
+ for folder in self.classFolder:
126
+ for json_file in folder.glob('*.json'):
127
+ tmp_def = json.load(FileIO(json_file))
128
+ if tmp_def.get('$id') == aepclass or tmp_def.get('meta:altId') == aepclass:
129
+ self.aepclass = tmp_def
130
+ found = True
131
+ break
132
+ if found:
113
133
  break
114
134
  self.EDITABLE = False
115
135
  else:
116
136
  if self.schemaAPI is not None:
117
137
  self.aepclass = self.schemaAPI.getClass(aepclass,full=True,xtype='xed')
118
138
  elif self.localfolder is not None:
119
- for json_file in self.classFolder.glob('*.json'):
120
- tmp_def = json.load(FileIO(json_file))
121
- if tmp_def.get('$id') == aepclass or tmp_def.get('meta:altId') == aepclass:
122
- self.aepclass = tmp_def
139
+ found = False
140
+ for folder in self.classFolder:
141
+ for json_file in folder.glob('*.json'):
142
+ tmp_def = json.load(FileIO(json_file))
143
+ if tmp_def.get('$id') == aepclass or tmp_def.get('meta:altId') == aepclass:
144
+ self.aepclass = tmp_def
145
+ found = True
146
+ break
147
+ if found:
123
148
  break
124
149
  self.EDITABLE = False
125
150
  self.__setAttributes__(self.aepclass)
@@ -168,10 +193,15 @@ class ClassManager:
168
193
  if self.schemaAPI is not None:
169
194
  self.behaviorDefinition = self.schemaAPI.getBehavior(behavId,full=True,xtype='xed')
170
195
  elif self.localfolder is not None:
171
- for json_file in self.behavFolder.glob('*.json'):
172
- tmp_def = json.load(FileIO(json_file))
173
- if tmp_def.get('$id') == behavId:
174
- self.behaviorDefinition = tmp_def
196
+ found = False
197
+ for folder in self.behavFolder:
198
+ for json_file in folder.glob('*.json'):
199
+ tmp_def = json.load(FileIO(json_file))
200
+ if tmp_def.get('$id') == behavId:
201
+ self.behaviorDefinition = tmp_def
202
+ found = True
203
+ break
204
+ if found:
175
205
  break
176
206
  self.requiredFields = set()
177
207
 
aepp/cli/__main__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from ast import arg
2
2
  from matplotlib.pyplot import table
3
3
  import aepp
4
- from aepp import synchronizer, schema, schemamanager, fieldgroupmanager, datatypemanager, identity, queryservice,catalog,flowservice
4
+ from aepp import synchronizer, schema, schemamanager, fieldgroupmanager, datatypemanager, identity, queryservice,catalog,flowservice,sandboxes, segmentation
5
5
  import argparse, cmd, shlex, json
6
6
  from functools import wraps
7
7
  from rich.console import Console
@@ -47,26 +47,25 @@ class ServiceShell(cmd.Cmd):
47
47
  self.sandbox = str(dict_config.get("sandbox-name","prod"))
48
48
  else:
49
49
  self.sandbox = str(kwargs.get("sandbox","prod"))
50
- self.secret = str(dict_config.get("secret",kwargs.get("secret")))
51
- self.org_id = str(dict_config.get("org_id",kwargs.get("org_id")))
52
- self.client_id = str(dict_config.get("client_id",kwargs.get("client_id")))
53
- self.scopes = str(dict_config.get("scopes",kwargs.get("scopes")))
50
+ self.secret = dict_config.get("secret",kwargs.get("secret"))
51
+ self.org_id = dict_config.get("org_id",kwargs.get("org_id"))
52
+ self.client_id = dict_config.get("client_id",kwargs.get("client_id"))
53
+ self.scopes = dict_config.get("scopes",kwargs.get("scopes"))
54
54
  else:
55
- self.sandbox = str(kwargs.get("sandbox","prod"))
56
- self.secret = str(kwargs.get("secret"))
57
- self.org_id = str(kwargs.get("org_id"))
58
- self.client_id = str(kwargs.get("client_id"))
59
- self.scopes = str(kwargs.get("scopes"))
60
- self.connectInstance = True
55
+ self.sandbox:str|None = kwargs.get("sandbox","prod")
56
+ self.secret:str|None = kwargs.get("secret")
57
+ self.org_id:str|None = kwargs.get("org_id")
58
+ self.client_id:str|None = kwargs.get("client_id")
59
+ self.scopes:str|None = kwargs.get("scopes")
61
60
  if self.sandbox is not None and self.secret is not None and self.org_id is not None and self.client_id is not None and self.scopes is not None:
62
61
  print("Configuring connection...")
63
62
  self.config = aepp.configure(
64
- connectInstance=self.connectInstance,
65
63
  sandbox=self.sandbox,
66
64
  secret=self.secret,
67
65
  org_id=self.org_id,
68
66
  client_id=self.client_id,
69
- scopes=self.scopes
67
+ scopes=self.scopes,
68
+ connectInstance=self.connectInstance
70
69
  )
71
70
  self.prompt = f"{self.config.sandbox}> "
72
71
  console.print(Panel(f"Connected to [bold green]{self.sandbox}[/bold green]", style="blue"))
@@ -82,7 +81,6 @@ class ServiceShell(cmd.Cmd):
82
81
  console.print(f"Configuration file created at {Path.cwd() / Path(filename_json)}", style="green")
83
82
  return
84
83
 
85
-
86
84
  # # --- Commands ---
87
85
  def do_config(self, arg:Any) -> None:
88
86
  """connect to an AEP instance"""
@@ -94,14 +92,14 @@ class ServiceShell(cmd.Cmd):
94
92
  parser.add_argument("-cid", "--client_id", help="Auto-login client ID")
95
93
  parser.add_argument("-cf", "--config_file", help="Path to config file", default=None)
96
94
  args = parser.parse_args(shlex.split(arg))
97
- if args.config_file:
95
+ if args.config_file is not None:
98
96
  mypath = Path.cwd()
99
97
  dict_config = json.load(FileIO(mypath / Path(args.config_file)))
100
- self.sandbox = str(args.sandbox) if args.sandbox else str(dict_config.get("sandbox-name",args.sandbox))
101
- self.secret = str(dict_config.get("secret",args.secret))
102
- self.org_id = str(dict_config.get("org_id",args.org_id))
103
- self.client_id = str(dict_config.get("client_id",args.client_id))
104
- self.scopes = str(dict_config.get("scopes",args.scopes))
98
+ self.sandbox:str|None = args.sandbox if args.sandbox else dict_config.get("sandbox-name",args.sandbox)
99
+ self.secret:str|None = dict_config.get("secret",args.secret)
100
+ self.org_id:str|None = dict_config.get("org_id",args.org_id)
101
+ self.client_id:str|None = dict_config.get("client_id",args.client_id)
102
+ self.scopes:str|None = dict_config.get("scopes",args.scopes)
105
103
  self.connectInstance = True
106
104
  else:
107
105
  if args.sandbox: self.sandbox = str(args.sandbox)
@@ -136,6 +134,42 @@ class ServiceShell(cmd.Cmd):
136
134
  else:
137
135
  console.print(Panel("(!) You must configure the connection first using the 'config' command.", style="red"))
138
136
 
137
+ @login_required
138
+ def do_get_sandboxes(self, args:Any) -> None:
139
+ """List all sandboxes for the current organization"""
140
+ parser = argparse.ArgumentParser(prog='get_sandboxes', add_help=True)
141
+ parser.add_argument("-sv", "--save",help="Save sandboxes to CSV file")
142
+ try:
143
+ args = parser.parse_args(shlex.split(args))
144
+ aepp_sandboxes = sandboxes.Sandboxes(config=self.config)
145
+ sandboxes_list = aepp_sandboxes.getSandboxes()
146
+ if sandboxes_list:
147
+ table = Table(title=f"Sandboxes in Org: {self.config.org_id}")
148
+ table.add_column("Name", style="cyan")
149
+ table.add_column("Title", style="magenta")
150
+ table.add_column("Type", style="green")
151
+ table.add_column("Region", style="yellow")
152
+ table.add_column("Created", style="medium_violet_red")
153
+ for sb in sandboxes_list:
154
+ table.add_row(
155
+ sb.get("name","N/A"),
156
+ sb.get("title","N/A"),
157
+ sb.get("type","N/A"),
158
+ sb.get("region","N/A"),
159
+ sb.get("createdDate","N/A"),
160
+ )
161
+ console.print(table)
162
+ if args.save:
163
+ df_sandboxes = pd.DataFrame(sandboxes_list)
164
+ df_sandboxes.to_csv(f"sandboxes_{self.config.org_id}.csv", index=False)
165
+ console.print(f"Sandboxes exported to sandboxes_{self.config.org_id}.csv", style="green")
166
+ else:
167
+ console.print("(!) No sandboxes found.", style="red")
168
+ except Exception as e:
169
+ console.print(f"(!) Error: {str(e)}", style="red")
170
+ except SystemExit:
171
+ return
172
+
139
173
 
140
174
  @login_required
141
175
  def do_get_schemas(self, args:Any) -> None:
@@ -740,7 +774,7 @@ class ServiceShell(cmd.Cmd):
740
774
  ds.get("name","N/A"),
741
775
  datetime.fromtimestamp(ds.get("created",1000)/1000).isoformat().split('T')[0],
742
776
  str(ds.get("dataIngested",False)),
743
- ds.get("classification",{}).get("dataBehavior","unknown")
777
+ ds.get('classification').get('dataBehavior','N/A'),
744
778
  )
745
779
  console.print(table)
746
780
  except Exception as e:
@@ -748,6 +782,74 @@ class ServiceShell(cmd.Cmd):
748
782
  except SystemExit:
749
783
  return
750
784
 
785
+ @login_required
786
+ def do_get_datasets_tableName(self, args:Any) -> None:
787
+ parser = argparse.ArgumentParser(prog='get_datasets', add_help=True)
788
+ try:
789
+ args = parser.parse_args(shlex.split(args))
790
+ aepp_cat = catalog.Catalog(config=self.config)
791
+ datasets = aepp_cat.getDataSets(output='list')
792
+ table = Table(title=f"Datasets in Sandbox: {self.config.sandbox}")
793
+ table.add_column("Name", style="white")
794
+ table.add_column("Table Name", style="cyan",no_wrap=True)
795
+ table.add_column("Data Type", style="red")
796
+ for ds in datasets:
797
+ table.add_row(
798
+ ds.get("name","N/A"),
799
+ ds.get('tags',{}).get('adobe/pqs/table',["N/A"])[0],
800
+ ds.get('classification').get('dataBehavior','N/A'),
801
+ )
802
+ console.print(table)
803
+ except Exception as e:
804
+ console.print(f"(!) Error: {str(e)}", style="red")
805
+ except SystemExit:
806
+ return
807
+
808
+ @login_required
809
+ def do_get_observable_schema_json(self,args:Any) -> None:
810
+ """Get the observable schema for a dataset by name or ID"""
811
+ parser = argparse.ArgumentParser(prog='get_observable_schema', add_help=True)
812
+ parser.add_argument("dataset", help="Dataset ID or Dataset Name to retrieve observable schema for",type=str)
813
+ try:
814
+ args = parser.parse_args(shlex.split(args))
815
+ aepp_cat = catalog.Catalog(config=self.config)
816
+ datasets = aepp_cat.getDataSets(output='list')
817
+ for ds in datasets:
818
+ if ds.get("name","") == args.dataset or ds.get("id","") == args.dataset:
819
+ datasetId = ds.get("id")
820
+ schema_json = aepp_cat.getDataSetObservableSchema(datasetId=datasetId,appendDatasetInfo=True)
821
+ myObs = catalog.ObservableSchemaManager(schema_json,config=self.config)
822
+ data = myObs.to_dict()
823
+ with open(f"{args.dataset}_observable_schema.json", 'w') as f:
824
+ json.dump(data, f, indent=4)
825
+ console.print(f"Saved Observable schema to {args.dataset}_observable_schema.json.", style="green")
826
+ except Exception as e:
827
+ console.print(f"(!) Error: {str(e)}", style="red")
828
+ except SystemExit:
829
+ return
830
+
831
+ @login_required
832
+ def do_get_observable_schema_csv(self,args:Any) -> None:
833
+ """Get the observable schema for a dataset by name or ID"""
834
+ parser = argparse.ArgumentParser(prog='get_observable_schema', add_help=True)
835
+ parser.add_argument("dataset", help="Dataset ID or Dataset Name to retrieve observable schema for",type=str)
836
+ try:
837
+ args = parser.parse_args(shlex.split(args))
838
+ aepp_cat = catalog.Catalog(config=self.config)
839
+ datasets = aepp_cat.getDataSets(output='list')
840
+ for ds in datasets:
841
+ if ds.get("name","") == args.dataset or ds.get("id","") == args.dataset:
842
+ datasetId = ds.get("id")
843
+ schema_json = aepp_cat.getDataSetObservableSchema(datasetId=datasetId,appendDatasetInfo=True)
844
+ myObs = catalog.ObservableSchemaManager(schema_json,config=self.config)
845
+ data = myObs.to_dataframe()
846
+ data.to_csv(f"{args.dataset}_observable_schema.csv", index=False)
847
+ console.print(f"Saved Observable schema to {args.dataset}_observable_schema.csv.", style="green")
848
+ except Exception as e:
849
+ console.print(f"(!) Error: {str(e)}", style="red")
850
+ except SystemExit:
851
+ return
852
+
751
853
  @login_required
752
854
  def do_get_datasets_infos(self, args:Any) -> None:
753
855
  """List all datasets in the current sandbox"""
@@ -756,23 +858,58 @@ class ServiceShell(cmd.Cmd):
756
858
  args = parser.parse_args(shlex.split(args))
757
859
  aepp_cat = catalog.Catalog(config=self.config)
758
860
  datasets = aepp_cat.getDataSets()
861
+ aepp_cat.data.infos = aepp_cat.data.infos.sort_values(by=['ups_storageSize','datalake_storageSize'], ascending=False)
759
862
  aepp_cat.data.infos.to_csv(f"{aepp_cat.sandbox}_datasets_infos.csv",index=False)
760
863
  console.print(f"Datasets infos exported to {aepp_cat.sandbox}_datasets_infos.csv", style="green")
761
864
  table = Table(title=f"Datasets in Sandbox: {self.config.sandbox}")
762
865
  table.add_column("ID", style="white")
763
866
  table.add_column("Name", style="white",no_wrap=True)
764
- table.add_column("Datalake_rows", style="blue")
765
- table.add_column("Datalake_storage", style="blue")
766
- table.add_column("UPS_rows", style="magenta")
767
- table.add_column("UPS_storage", style="magenta")
867
+ table.add_column("UPS Rows", style="cyan")
868
+ table.add_column("UPS Storage Size", style="green")
869
+ table.add_column("Datalake Rows", style="magenta")
870
+ table.add_column("Datalake Storage Size", style="yellow")
768
871
  for _, ds in aepp_cat.data.infos.iterrows():
769
872
  table.add_row(
770
873
  ds.get("id","N/A"),
771
874
  ds.get("name","N/A"),
875
+ str(ds.get("ups_rows","N/A")),
876
+ str(ds.get("ups_storageSize","N/A")),
772
877
  str(ds.get("datalake_rows","N/A")),
773
878
  str(ds.get("datalake_storageSize","N/A")),
774
- str(ds.get("ups_rows","N/A")),
775
- str(ds.get("ups_storageSize","N/A"))
879
+ )
880
+ console.print(table)
881
+ except Exception as e:
882
+ console.print(f"(!) Error: {str(e)}", style="red")
883
+ except SystemExit:
884
+ return
885
+
886
+ @login_required
887
+ def do_get_snapshot_datasets(self,args:Any) -> None:
888
+ """List all snapshot datasets in the current sandbox"""
889
+ parser = argparse.ArgumentParser(prog='get_snapshot_datasets', add_help=True)
890
+ try:
891
+ args = parser.parse_args(shlex.split(args))
892
+ aepp_cat = catalog.Catalog(config=self.config)
893
+ datasets = aepp_cat.getProfileSnapshotDatasets(explicitMergePolicy=True)
894
+ list_ds = []
895
+ for key, ds in datasets.items():
896
+ obj = ds
897
+ obj['id'] = key
898
+ list_ds.append(obj)
899
+ df_datasets = pd.DataFrame(list_ds)
900
+ df_datasets.to_csv(f"{self.config.sandbox}_snapshot_datasets.csv",index=False)
901
+ console.print(f"Snapshot Datasets exported to {self.config.sandbox}_snapshot_datasets.csv", style="green")
902
+ table = Table(title=f"Snapshot Datasets in Sandbox: {self.config.sandbox}")
903
+ table.add_column("ID", style="white")
904
+ table.add_column("Table Name", style="white")
905
+ table.add_column("Merge Policy Name", style="yellow")
906
+ table.add_column("Merge Policy ID", style="green")
907
+ for ds in list_ds:
908
+ table.add_row(
909
+ ds.get("id","N/A"),
910
+ ds.get("tags",{}).get('adobe/pqs/table',["N/A"])[0],
911
+ ds.get('mergePolicyName','N/A'),
912
+ [el.split(':')[1] for el in ds.get('tags',{}).get('unifiedProfile',[]) if el.startswith('mergePolicyId')][0]
776
913
  )
777
914
  console.print(table)
778
915
  except Exception as e:
@@ -846,6 +983,37 @@ class ServiceShell(cmd.Cmd):
846
983
  except SystemExit:
847
984
  return
848
985
 
986
+ @login_required
987
+ def do_get_audiences(self, args:Any) -> None:
988
+ """List all audiences in the current sandbox"""
989
+ parser = argparse.ArgumentParser(prog='get_audiences', add_help=True)
990
+ try:
991
+ args = parser.parse_args(shlex.split(args))
992
+ aepp_audience = segmentation.Segmentation(config=self.config)
993
+ audiences = aepp_audience.getAudiences()
994
+ df_audiences = pd.DataFrame(audiences)
995
+ df_audiences.to_csv(f"{self.config.sandbox}_audiences.csv",index=False)
996
+ console.print(f"Audiences exported to {self.config.sandbox}_audiences.csv", style="green")
997
+ table = Table(title=f"Audiences in Sandbox: {self.config.sandbox}")
998
+ table.add_column("ID", style="cyan")
999
+ table.add_column("Name", style="magenta")
1000
+ table.add_column("Evaluation", style="yellow")
1001
+ table.add_column("Total Profiles", style="green")
1002
+ table.add_column("Evaluation Date", style="white")
1003
+ for aud in audiences:
1004
+ table.add_row(
1005
+ aud.get("id","N/A"),
1006
+ aud.get("name","N/A"),
1007
+ '[red3]Batch[/red3]' if aud.get("evaluationInfo",{}).get("batch",{}).get('enabled') else '[chartreuse1]Streaming[/chartreuse1]' if aud.get("evaluationInfo",{}).get("continuous",{}).get('enabled') else '[blue_violet]Edge[/blue_violet]' if aud.get("evaluationInfo",{}).get("synchronous",{}).get('enabled') else 'N/A',
1008
+ str(aud.get('metrics',{}).get('data',{}).get('totalProfiles','N/A')),
1009
+ datetime.fromtimestamp(aud.get('metrics',{}).get('updateEpoch',0)).isoformat(),
1010
+ )
1011
+ console.print(table)
1012
+ except Exception as e:
1013
+ console.print(f"(!) Error: {str(e)}", style="red")
1014
+ except SystemExit:
1015
+ return
1016
+
849
1017
  @login_required
850
1018
  def do_get_flows(self, args:Any) -> None:
851
1019
  """List flows in the current sandbox based on parameters provided. By default, list all sources and destinations."""
@@ -1203,18 +1371,14 @@ class ServiceShell(cmd.Cmd):
1203
1371
  console.print("Syncing artifact...", style="blue")
1204
1372
  parser = argparse.ArgumentParser(prog='extractArtifact', description='Extract artifacts from AEP')
1205
1373
  parser.add_argument('artifact', help='artifact to extract (name or id): "schema","fieldgroup","datatype","descriptor","dataset","identity","mergepolicy","audience"')
1206
- parser.add_argument('-at','--artifactType', help='artifact type ')
1207
- parser.add_argument('-t','--targets', help='target sandboxes')
1208
- parser.add_argument('-lf','--localfolder', help='Local folder to extract artifacts to',default='extractions')
1374
+ parser.add_argument('-at','--artifactType', help='artifact type ',type=str)
1375
+ parser.add_argument('-t','--targets', help='target sandboxes',nargs='+',type=str)
1376
+ parser.add_argument('-lf','--localfolder', help='Local folder to extract artifacts to',default='extractions',nargs='+',type=str)
1209
1377
  parser.add_argument('-b','--baseSandbox', help='Base sandbox for synchronization')
1210
1378
  parser.add_argument('-rg','--region', help='Region to extract artifacts from: "ndl2" (default), "va7", "aus5", "can2", "ind2"',default='ndl2')
1211
1379
  parser.add_argument('-v','--verbose', help='Enable verbose output',default=True)
1212
1380
  try:
1213
1381
  args = parser.parse_args(shlex.split(args))
1214
- if ',' in args.targets:
1215
- args.targets = args.targets.split(',')
1216
- else:
1217
- args.targets = [args.targets]
1218
1382
  console.print("Initializing Synchronizor...", style="blue")
1219
1383
  if args.baseSandbox:
1220
1384
  synchronizor = synchronizer.Synchronizer(
aepp/datatypemanager.py CHANGED
@@ -36,7 +36,7 @@ class DataTypeManager:
36
36
  schemaAPI:'Schema'=None,
37
37
  config: Union[dict,ConnectObject] = aepp.config.config_object,
38
38
  description:str="",
39
- localFolder:str=None,
39
+ localFolder:str|list|None=None,
40
40
  sandbox:str=None,
41
41
  **kwargs
42
42
  )->None:
@@ -65,10 +65,13 @@ class DataTypeManager:
65
65
  elif config is not None and localFolder is None:
66
66
  self.schemaAPI = Schema(config=config)
67
67
  elif localFolder is not None:
68
- self.localfolder = Path(localFolder)
69
- self.datatypeFolder = self.localfolder / 'datatype'
70
- self.datatypeGlobalFolder = self.datatypeFolder / 'global'
71
- if self.localfolder.exists() is False:
68
+ if isinstance(localFolder, str):
69
+ self.localfolder = [Path(localFolder)]
70
+ elif isinstance(localFolder, list):
71
+ self.localfolder = [Path(folder) for folder in localFolder]
72
+ self.datatypeFolder = [folder / 'datatype' for folder in self.localfolder]
73
+ self.datatypeGlobalFolder = [folder / 'global' for folder in self.datatypeFolder]
74
+ if any([folder.exists() is False for folder in self.localfolder]):
72
75
  raise Exception(f"The local folder {self.localfolder} does not exist. Please create it and extract your sandbox before using it.")
73
76
  self.schemaAPI = None
74
77
  if self.schemaAPI is not None:
@@ -99,20 +102,32 @@ class DataTypeManager:
99
102
  self.dataType = self.schemaAPI.getDataType(dataType['$id'],full=False)
100
103
  self.EDITABLE = True
101
104
  elif self.localfolder is not None:
102
- for dataTypeFile in self.datatypeFolder.glob(f"*.json"):
103
- tmp_def = json.load(FileIO(dataTypeFile))
104
- if tmp_def.get('$id') == dataType.get('$id') or tmp_def.get('meta:altId') == dataType.get('meta:altId'):
105
- self.dataType = tmp_def
105
+ found = False
106
+ for folder in self.datatypeFolder:
107
+ for dataTypeFile in folder.glob(f"*.json"):
108
+ tmp_def = json.load(FileIO(dataTypeFile))
109
+ if tmp_def.get('$id') == dataType.get('$id') or tmp_def.get('meta:altId') == dataType.get('meta:altId'):
110
+ self.dataType = tmp_def
111
+ found = True
112
+ break
113
+ if found:
114
+ break
106
115
  self.EDITABLE = False
107
116
  else:
108
117
  if self.schemaAPI is not None:
109
118
  self.dataType = self.schemaAPI.getDataType(dataType['$id'],full=True)
110
119
  self.EDITABLE = True
111
120
  elif self.localfolder is not None:
112
- for dataTypeFile in self.datatypeGlobalFolder.glob("*.json"):
113
- tmp_def = json.load(FileIO(dataTypeFile))
114
- if tmp_def.get('$id') == dataType.get('$id') or tmp_def.get('meta:altId') == dataType.get('meta:altId') or tmp_def.get('title') == dataType.get('title'):
115
- self.dataType = tmp_def
121
+ found = False
122
+ for folder in self.datatypeGlobalFolder:
123
+ for dataTypeFile in folder.glob("*.json"):
124
+ tmp_def = json.load(FileIO(dataTypeFile))
125
+ if tmp_def.get('$id') == dataType.get('$id') or tmp_def.get('meta:altId') == dataType.get('meta:altId') or tmp_def.get('title') == dataType.get('title'):
126
+ self.dataType = tmp_def
127
+ found = True
128
+ break
129
+ if found:
130
+ break
116
131
  self.EDITABLE = False
117
132
  elif type(dataType) == str:
118
133
  if self.tenantId[1:] in dataType:
@@ -122,10 +137,16 @@ class DataTypeManager:
122
137
  raise ValueError(f"Cannot find the data type with id {dataType} in the schema API.")
123
138
  self.EDITABLE = True
124
139
  elif self.localfolder is not None:
125
- for dataTypeFile in self.datatypeFolder.glob("*.json"):
126
- tmp_def = json.load(FileIO(dataTypeFile))
127
- if tmp_def.get('$id') == dataType or tmp_def.get('meta:altId') == dataType or tmp_def.get('title') == dataType:
128
- self.dataType = tmp_def
140
+ found = False
141
+ for folder in self.datatypeFolder:
142
+ for dataTypeFile in folder.glob("*.json"):
143
+ tmp_def = json.load(FileIO(dataTypeFile))
144
+ if tmp_def.get('$id') == dataType or tmp_def.get('meta:altId') == dataType or tmp_def.get('title') == dataType:
145
+ self.dataType = tmp_def
146
+ found = True
147
+ break
148
+ if found:
149
+ break
129
150
  self.EDITABLE = False
130
151
  else:
131
152
  raise Exception("You try to retrieve the datatype definition from the id, but no API or localFolder has been passed as a parameter.")
@@ -136,10 +157,16 @@ class DataTypeManager:
136
157
  raise ValueError(f"Cannot find the data type with id {dataType} in the schema API.")
137
158
  self.EDITABLE = True
138
159
  elif self.localfolder is not None:
139
- for dataTypeFile in self.datatypeGlobalFolder.glob("*.json"):
140
- tmp_def = json.load(FileIO(dataTypeFile))
141
- if tmp_def.get('$id') == dataType or tmp_def.get('meta:altId') == dataType or tmp_def.get('title') == dataType:
142
- self.dataType = tmp_def
160
+ found = False
161
+ for folder in self.datatypeGlobalFolder:
162
+ for dataTypeFile in folder.glob("*.json"):
163
+ tmp_def = json.load(FileIO(dataTypeFile))
164
+ if tmp_def.get('$id') == dataType or tmp_def.get('meta:altId') == dataType or tmp_def.get('title') == dataType:
165
+ self.dataType = tmp_def
166
+ found = True
167
+ break
168
+ if found:
169
+ break
143
170
  self.EDITABLE = False
144
171
  else:
145
172
  raise Exception("You try to retrieve the datatype definition from the id, but no API or localFolder has been passed as a parameter.")
@@ -181,12 +208,18 @@ class DataTypeManager:
181
208
  self.dataTypeManagers[dt_manager.title] = dt_manager
182
209
  elif self.localfolder is not None:
183
210
  for dt in dataTypes: ## today only searching custom data types in local folder
184
- for dataTypeFile in self.datatypeFolder.glob("*.json"):
185
- tmp_def = json.load(FileIO(dataTypeFile))
186
- if tmp_def.get('$id') == dt or tmp_def.get('meta:altId') == dt or tmp_def.get('title') == dt:
187
- dt_manager = DataTypeManager(dataType=tmp_def,localFolder=self.localfolder,tenantId=self.tenantId,sandbox=self.sandbox)
188
- self.dataTypes[dt_manager.id] = dt_manager.title
189
- self.dataTypeManagers[dt_manager.title] = dt_manager
211
+ found = False
212
+ for folder in self.datatypeFolder:
213
+ for dataTypeFile in folder.glob("*.json"):
214
+ tmp_def = json.load(FileIO(dataTypeFile))
215
+ if tmp_def.get('$id') == dt or tmp_def.get('meta:altId') == dt or tmp_def.get('title') == dt:
216
+ dt_manager = DataTypeManager(dataType=tmp_def,localFolder=self.localfolder,tenantId=self.tenantId,sandbox=self.sandbox)
217
+ self.dataTypes[dt_manager.id] = dt_manager.title
218
+ self.dataTypeManagers[dt_manager.title] = dt_manager
219
+ found = True
220
+ break
221
+ if found:
222
+ break
190
223
  if title is not None:
191
224
  self.dataType['title'] = title
192
225
  self.title = title