aepp 0.4.0.post1__py3-none-any.whl → 0.4.0.post2__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.4.0-1"
1
+ __version__ = "0.4.0-2"
aepp/identity.py CHANGED
@@ -218,6 +218,36 @@ class Identity:
218
218
  self.endpoint + path, headers=self.header, data=creation_dict
219
219
  )
220
220
  return res
221
+
222
+ def getLinkedIdentities(self,xids:dict|list=None,projectionType:str="set",aam:bool=False,edgeMeta:bool=False,**kwargs)->dict:
223
+ """
224
+ Given set of identities, returns all linked identities in the graph corresponding to each identity.
225
+ Arguments:
226
+ xids : REQUIRED : A single or a list of xid composite such as:
227
+ {'nsid':'mynsid','id':'myid','ns':'mynamespace'}
228
+ projectionType : OPTIONAL : This define the format returned. Default is "set". Possible : "graph"
229
+ aam : OPTIONAL : Boolean that cannot be used with graph type. Default False.
230
+ edgeMeta : OPTIONAL : This is and optional field that is used to add edge meta data in the response, such as dataset_ids and batch_ids.
231
+ It will only apply if the requested projection_type is graph.
232
+ """
233
+ if xids is None:
234
+ raise Exception("Cannot process the request without Xid")
235
+ if type(xids) == str:
236
+ xids = list(xids)
237
+ if self.loggingEnabled:
238
+ self.logger.debug(f"Starting getLinkedIdentities")
239
+ path = "/identity/v2/graph"
240
+ data = {}
241
+ data["composite_xid"] = xids
242
+ data['projection_type'] = projectionType
243
+ data['aam_properties'] = {'return_data_sources':aam}
244
+ data['require_edge_meta_data'] = edgeMeta
245
+ if len(kwargs)>0:
246
+ for key, value in kwargs.items():
247
+ if key in ['graph_type','traverse','filter']:
248
+ data[key] = value
249
+ res = self.connector.postData(self.endpoint+path, data=data)
250
+ return res
221
251
 
222
252
  def updateIdentity(
223
253
  self,
@@ -290,117 +320,6 @@ class Identity:
290
320
  res = self.connector.getData(self.endpoint + path, headers=self.header)
291
321
  return res
292
322
 
293
- def getClustersMembers(
294
- self,
295
- xid: str = None,
296
- nsid: str = "411",
297
- namespace: str = "adcloud",
298
- id_value: str = None,
299
- graphType: str = "private",
300
- ) -> dict:
301
- """
302
- Given an XID return all XIDs, in the same or other namespaces, that are linked to it by the device graph type.
303
- The related XIDs are considered to be part of the same cluster.
304
- It is required to pass either xid or (namespace/nsid & id) pair to get cluster members.
305
- Arguments:
306
- xid : REQUIRED : Identity string returns by the getIdentity method.
307
- nsid : OPTIONAL : namespace id (default : 411)
308
- namespace : OPTIONAL : namespace code. (default : adcloud)
309
- id_value : OPTIONAL : ID of the customer in given namespace.
310
- graphType : OPTIONAL : Graph type (output type) you want to get the cluster from. (default private)
311
- """
312
- if self.loggingEnabled:
313
- self.logger.debug(f"Starting getClustersMembers")
314
- temp_header = deepcopy(self.header)
315
- temp_header["Accept"] = "application/json"
316
- temp_header["x-uis-cst-ctx"] = "stub"
317
- path = "/identity/cluster/members"
318
- params = {}
319
- if xid is not None:
320
- params["xid"] = xid
321
- params["graph-type"] = graphType
322
- res = self.connector.getData(
323
- self.endpoint + path, params=params, headers=temp_header
324
- )
325
- return res
326
- elif xid is None and id_value is not None:
327
- params["nsid"] = nsid
328
- params["namespace"] = namespace
329
- params["id"] = id_value
330
- params["graph-type"] = graphType
331
- res = self.connector.getData(
332
- self.endpoint + path, params=params, headers=temp_header
333
- )
334
- return res
335
-
336
- def postClustersMembers(
337
- self, xids: list = None, version: float = 1.0, graphType: str = "private"
338
- ) -> dict:
339
- """
340
- Given set of identities, returns all linked identities in cluster corresponding to each identity.
341
- Arguments:
342
- xids : REQUIRED : list of identity as returned by getIdentity method.
343
- version : OPTIONAL : Version of the clusterMembers (default 1.0)
344
- graphType : OPTIONAL : Graph type (output type) you want to get the cluster from. (default private)
345
- """
346
- if self.loggingEnabled:
347
- self.logger.debug(f"Starting postClustersMembers")
348
- temp_header = deepcopy(self.header)
349
- temp_header["Accept"] = "application/vnd.adobe.identity+json;version=1.2"
350
- temp_header["x-uis-cst-ctx"] = "stub"
351
- path = "/identity/cluster/members"
352
- if type(xids) != list:
353
- raise TypeError("xids must be of type list")
354
- list_body = [
355
- {"xid": [{"xid": xid}], "graph-type": graphType, "version": version}
356
- for xid in xids
357
- ]
358
- res = self.connector.postData(
359
- self.endpoint + path, data=list_body, headers=temp_header
360
- )
361
- return res
362
-
363
- def getClusterHistory(
364
- self,
365
- xid: str = None,
366
- nsid: int = 411,
367
- namespace: str = "adcloud",
368
- id_value: str = None,
369
- graphType: str = "private",
370
- ) -> dict:
371
- """
372
- Given an XID, return all cluster associations with that XID.
373
- It is required to pass either xid or (namespace/nsid & id) pair to get cluster history.
374
- Arguments:
375
- xid : REQUIRED : Identity string returns by the getIdentity method.
376
- nsid : OPTIONAL : namespace id (default : 411)
377
- namespace : OPTIONAL : namespace code. (default : adcloud)
378
- id_value : OPTIONAL : ID of the customer in given namespace.
379
- graphType : OPTIONAL : Graph type (output type) you want to get the cluster from. (default private)
380
- """
381
- if self.loggingEnabled:
382
- self.logger.debug(f"Starting getClusterHistory")
383
- temp_header = deepcopy(self.header)
384
- temp_header["Accept"] = "application/vnd.adobe.identity+json;version=1.2"
385
- temp_header["x-uis-cst-ctx"] = "stub"
386
- path = "/identity/cluster/history"
387
- params = {}
388
- if xid is not None:
389
- params["xid"] = xid
390
- params["graph-type"] = graphType
391
- res = aepp._getData(
392
- self.endpoint + path, params=params, headers=temp_header
393
- )
394
- return res
395
- elif xid is None and id_value is not None:
396
- params["nsid"] = nsid
397
- params["namespace"] = namespace
398
- params["id"] = id_value
399
- params["graph-type"] = graphType
400
- res = self.connector.getData(
401
- self.endpoint + path, params=params, headers=temp_header
402
- )
403
- return res
404
323
 
405
324
  def getIdentityMapping(
406
325
  self,
aepp/queryservice.py CHANGED
@@ -935,7 +935,7 @@ class InteractiveQuery:
935
935
  loggingEnabled = False
936
936
  logger = None
937
937
 
938
- def __init__(self, conn_object: dict = None, loggingObject: dict = None):
938
+ def __init__(self, conn_object: dict = None, loggingObject: dict = None,config:ConnectObject=None):
939
939
  """
940
940
  Importing the pg (PyGreSQL) library and instantiating the connection via the conn_object pass over the instantiation method.
941
941
  Arguments:
@@ -946,6 +946,7 @@ class InteractiveQuery:
946
946
  raise AttributeError(
947
947
  "You are missing the conn_object. Use the QueryService to retrieve the object."
948
948
  )
949
+ self.config = None
949
950
  self.dbname = conn_object["dbName"]
950
951
  self.host = conn_object["host"]
951
952
  self.port = conn_object["port"]
@@ -975,6 +976,17 @@ class InteractiveQuery:
975
976
  streamHandler = logging.StreamHandler()
976
977
  streamHandler.setFormatter(formatter)
977
978
  self.logger.addHandler(streamHandler)
979
+ if config is not None:
980
+ self.config = config
981
+ from aepp import catalog, segmentation
982
+ self.mycat = catalog.Catalog(config=self.config)
983
+ self.myseg = segmentation.Segmentation(config=self.config)
984
+
985
+ def addConfig(self,config:ConnectObject)->None:
986
+ self.config = config
987
+ from aepp import catalog,segmentation
988
+ self.mycat = catalog.Catalog(config=self.config)
989
+ self.myseg = segmentation.Segmentation(config=self.config)
978
990
 
979
991
  def query(
980
992
  self, sql: str = None, output: str = "dataframe"
@@ -1003,6 +1015,57 @@ class InteractiveQuery:
1003
1015
  return df
1004
1016
  else:
1005
1017
  raise KeyError("You didn't specify a correct value.")
1018
+
1019
+ def querySegmentPopulation(self,segmentId:str|list,extraFields:str|list=None,count:bool=False)->pd.DataFrame|object:
1020
+ """
1021
+ Retrieve the identities in the identityMap that are qualified to the segment ID passed.
1022
+ Arguments:
1023
+ segmentId : REQUIRED : Single or list of segment Ids
1024
+ extraFields : OPTIONAL : If you want to add more fields that are not in the IdentityMap
1025
+ count : OPTIONAL : If you just want to get the count of the profiles and no details
1026
+ """
1027
+ if self.config is None:
1028
+ raise Exception('Require to have a config available. Use addConfig method to add a configuration')
1029
+ if type(extraFields) == str:
1030
+ extraFields = [extraFields]
1031
+ if type(segmentId) == list:
1032
+ result = pd.DataFrame()
1033
+ for segId in segmentId:
1034
+ data = self.querySegmentPopulation(segId,count=count)
1035
+ if result.empty:
1036
+ result = data.copy()
1037
+ else:
1038
+ result = pd.concat([result,data],ignore_index=True)
1039
+ return result
1040
+ mysegment = self.myseg.getSegment(segmentId)
1041
+ mergePolicyId = mysegment.get('mergePolicyId')
1042
+ myProfileSnaphots = self.mycat.getProfileSnapshotDatasets()
1043
+ table = None
1044
+ for key, item in myProfileSnaphots.items():
1045
+ tmp_ds_mergePolicyId = item['tags']['unifiedProfile']
1046
+ if f"mergePolicyId:{mergePolicyId}" in tmp_ds_mergePolicyId:
1047
+ table = item['tags']['adobe/pqs/table'][0]
1048
+ if count == False:
1049
+ strIdentity = ""
1050
+ commaIdentity = ""
1051
+ strIdentityFinal = ""
1052
+ if extraFields is not None:
1053
+ commaFields = ","
1054
+ strFields = ','.join(extraFields)
1055
+ minifyFields = [el.split('.').pop() for el in extraFields]
1056
+ strFieldsFinal = ','.join(minifyFields)
1057
+ queryTemplate = f"""
1058
+ SELECT key, inline(value), '{segmentId}' segmentId {commaFields} {strFieldsFinal} FROM
1059
+ (SELECT explode(identityMap) {commaFields} {strFields}
1060
+ FROM {table}
1061
+ WHERE segmentMembership['ups']['{segmentId}'].status = 'realized') LIMIT 0
1062
+ """
1063
+ res = self.query(queryTemplate)
1064
+ return res
1065
+ else:
1066
+ dict_data = [{'count':mysegment.get('metrics',{}).get('data',{}).get('totalProfiles','No Data Yet'),'segmentId':segmentId}]
1067
+ df = pd.DataFrame(dict_data)
1068
+ return df
1006
1069
 
1007
1070
  def transformToDataFrame(self, query: object = None) -> pd.DataFrame:
1008
1071
  """
@@ -1091,7 +1154,7 @@ class InteractiveQuery2:
1091
1154
  loggingEnabled = False
1092
1155
  logger = None
1093
1156
 
1094
- def __init__(self, conn_object: dict = None, loggingObject: dict = None,sslmode:str="allow"):
1157
+ def __init__(self, conn_object: dict = None, loggingObject: dict = None,sslmode:str="allow",config:ConnectObject=None):
1095
1158
  """
1096
1159
  Importing the psycopg2 library and instantiating the connection via the conn_object pass over the instantiation method.
1097
1160
  Arguments:
@@ -1102,6 +1165,7 @@ class InteractiveQuery2:
1102
1165
  raise AttributeError(
1103
1166
  "You are missing the conn_object. Use the QueryService to retrieve the object."
1104
1167
  )
1168
+ self.config = None
1105
1169
  self.dbname = conn_object["dbName"]
1106
1170
  self.host = conn_object["host"]
1107
1171
  self.port = conn_object["port"]
@@ -1131,6 +1195,17 @@ class InteractiveQuery2:
1131
1195
  streamHandler = logging.StreamHandler()
1132
1196
  streamHandler.setFormatter(formatter)
1133
1197
  self.logger.addHandler(streamHandler)
1198
+ if config is not None:
1199
+ self.config = config
1200
+ from aepp import catalog, segmentation
1201
+ self.mycat = catalog.Catalog(config=self.config)
1202
+ self.myseg = segmentation.Segmentation(config=self.config)
1203
+
1204
+ def addConfig(self,config:ConnectObject)->None:
1205
+ self.config = config
1206
+ from aepp import catalog,segmentation
1207
+ self.mycat = catalog.Catalog(config=self.config)
1208
+ self.myseg = segmentation.Segmentation(config=self.config)
1134
1209
 
1135
1210
  def query(
1136
1211
  self, sql: str = None, output: str = "dataframe"
@@ -1160,6 +1235,58 @@ class InteractiveQuery2:
1160
1235
  else:
1161
1236
  raise KeyError("You didn't specify a correct value.")
1162
1237
 
1238
+ def querySegmentPopulation(self,segmentId:str|list,extraFields:str|list=None,count:bool=False)->pd.DataFrame|object:
1239
+ """
1240
+ Retrieve the identities in the identityMap that are qualified to the segment ID passed.
1241
+ Arguments:
1242
+ segmentId : REQUIRED : Single or list of segment Ids
1243
+ extraFields : OPTIONAL : If you want to add more identities that are not in the IdentityMap
1244
+ count : OPTIONAL : If you just want to get the population count of the segment IDs
1245
+ """
1246
+ if self.config is None:
1247
+ raise Exception('Require to have a config available. Use addConfig method to add a configuration')
1248
+ if type(extraFields) == str:
1249
+ extraFields = [extraFields]
1250
+ if type(segmentId) == list:
1251
+ result = pd.DataFrame()
1252
+ for segId in segmentId:
1253
+ data = self.querySegmentPopulation(segId,count=count)
1254
+ if result.empty:
1255
+ result = data.copy()
1256
+ else:
1257
+ result = pd.concat([result,data],ignore_index=True)
1258
+ return result
1259
+ mysegment = self.myseg.getSegment(segmentId)
1260
+ mergePolicyId = mysegment.get('mergePolicyId')
1261
+ myProfileSnaphots = self.mycat.getProfileSnapshotDatasets()
1262
+ table = None
1263
+ for key, item in myProfileSnaphots.items():
1264
+ tmp_ds_mergePolicyId = item['tags']['unifiedProfile']
1265
+ if f"mergePolicyId:{mergePolicyId}" in tmp_ds_mergePolicyId:
1266
+ table = item['tags']['adobe/pqs/table'][0]
1267
+ if count == False:
1268
+ strIdentity = ""
1269
+ commaIdentity = ""
1270
+ strIdentityFinal = ""
1271
+ if extraFields is not None:
1272
+ commaField = ","
1273
+ strFields = ','.join(extraFields)
1274
+ minifyFields = [el.split('.').pop() for el in extraFields]
1275
+ strFieldsFinal = ','.join(minifyFields)
1276
+ queryTemplate = f"""
1277
+ SELECT key, inline(value), '{segmentId}' segmentId {commaField} {strFieldsFinal} FROM
1278
+ (SELECT explode(identityMap) {commaField} {strFields}
1279
+ FROM {table}
1280
+ WHERE segmentMembership['ups']['{segmentId}'].status = 'realized') LIMIT 0
1281
+ """
1282
+ res = self.query(queryTemplate)
1283
+ return res
1284
+ else:
1285
+ dict_data = [{'count':mysegment.get('metrics',{}).get('data',{}).get('totalProfiles','No Data Yet'),'segmentId':segmentId}]
1286
+ df = pd.DataFrame(dict_data)
1287
+ return df
1288
+
1289
+
1163
1290
  def transformToDataFrame(self, query: object = None) -> pd.DataFrame:
1164
1291
  """
1165
1292
  Taking the raw output of the query method use with raw and returning a DataFrame
aepp/segmentation.py CHANGED
@@ -771,6 +771,7 @@ class Segmentation:
771
771
  limit:int=100,
772
772
  name:str=None,
773
773
  sort:str=None,
774
+ entityType:str="_xdm.context.profile",
774
775
  prop:str=None,
775
776
  description:str=None,
776
777
  **kwargs)->list:
@@ -780,13 +781,14 @@ class Segmentation:
780
781
  name : OPTIONAL : Filter audiences that contains that string in the name, case unsensitive.
781
782
  limit : OPTIONAL : The number of audiences to be returned by pages (default: 100)
782
783
  sort : OPTIONAL : If you want to sort by a specific attribute (ex: "updateTime:desc")
784
+ entityType : OPTIONAL : The type of entity available, default "_xdm.context.profile".
783
785
  prop : If you want to test a specific property of the result to filter the data.
784
786
  Ex: "audienceId==mytestAudienceId"
785
787
  description : OPTIONAL : Filter audiences that contains that string in the description, case unsensitive.
786
788
  """
787
789
  if self.loggingEnabled:
788
790
  self.logger.debug(f"Starting getAudiences")
789
- params = {"limit":limit,"withMetrics":True}
791
+ params = {"limit":limit}
790
792
  path = "/audiences"
791
793
  if name is not None:
792
794
  params['name'] = name
@@ -796,8 +798,6 @@ class Segmentation:
796
798
  params['property'] = prop
797
799
  if description is not None:
798
800
  params['description'] = description
799
- if kwargs.get('start',0) is not None:
800
- params['start'] = kwargs.get('start')
801
801
  res = self.connector.getData(self.endpoint+path, params=params)
802
802
  data = res.get('children',[])
803
803
  nextStart = res.get('_page',{}).get('next',0)
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aepp
3
- Version: 0.4.0.post1
3
+ Version: 0.4.0.post2
4
4
  Summary: Package to manage AEP API endpoint and some helper functions
5
5
  Home-page: https://github.com/adobe/aepp
6
6
  Author: Julien Piccini
7
7
  Author-email: piccini.julien@gmail.com
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Operating System :: OS Independent
10
- Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
10
+ Classifier: License :: OSI Approved :: Apache Software License
11
11
  Classifier: Topic :: Utilities
12
12
  Classifier: Topic :: Internet
13
13
  Classifier: Topic :: Software Development :: Libraries
@@ -1,5 +1,5 @@
1
1
  aepp/__init__.py,sha256=6Vx1MxvwnohShbXZgxQsB6Mg_dhx9AW7_fKGqoZhXHo,23409
2
- aepp/__version__.py,sha256=40YS1AO_IHn8Hsvg8yMW2rENEkTxRYiBd0zoWtQnnrg,23
2
+ aepp/__version__.py,sha256=tvf97IPct6tqCNAfd_EVu0K-LUWG2ExY2zhh5Qo9630,23
3
3
  aepp/accesscontrol.py,sha256=PB3FcrO4bvDjdNxjHx7p_20hp4ahBXewoOSxuTGMXC8,17423
4
4
  aepp/catalog.py,sha256=hK9m3SAP0fhgkYqu14Tcfq14qBhw54tLCOF0mH31b1M,68237
5
5
  aepp/classmanager.py,sha256=xHcbgb9HkaAko2LxA0itfxR9tCYfVHW49_wlZH2zPtw,58380
@@ -19,22 +19,22 @@ aepp/exportDatasetToDataLandingZone.py,sha256=C6jg3XttFC-0mswa3ypZb6qx3MCQ8_A_3k
19
19
  aepp/fieldgroupmanager.py,sha256=FnRgbbilz69NVo8H51aTQsuocIH_Qs69Nnynp3RsYuw,92146
20
20
  aepp/flowservice.py,sha256=gVayD3vIMu7-d9TGpVtkbQ1r9iwAjJHWNRVtxKURWKc,107610
21
21
  aepp/hygiene.py,sha256=VEspnyu9eUlcK3wLeJYclaFaOWl5G5I5MRwmVA-RnUg,15385
22
- aepp/identity.py,sha256=_moM_YE0FOpRK5wu7O1_10XaPiFltGsZnBk7POdCwbo,24123
22
+ aepp/identity.py,sha256=E9MCIgntScMssduqKZqehT6FqSfTjWHcq7E7wESj3Zc,20833
23
23
  aepp/ingestion.py,sha256=OamE7NDei2Ev5vXIDkMlzvdyBaN41nkIGmpAnUlQoZI,22372
24
24
  aepp/observability.py,sha256=bKe74nlXYB5E5syh7Lj4VqIgwUI3OjMxK383P05EdLU,9951
25
25
  aepp/policy.py,sha256=JbpvfCKJl2kE2McK2mn_ZI5HKd_6pTnrfMoUdyJesWQ,24924
26
26
  aepp/privacyservice.py,sha256=V6BkJeZG1LDBCyEQm9Gx0i68iRHG6uxSJiVnXzkHapI,8790
27
- aepp/queryservice.py,sha256=zt2o40iUCQz5jrOZnLeQNdaZkrLJz6CTFX27SFOSZrI,54821
27
+ aepp/queryservice.py,sha256=HT_UoiBcLNERr_SCDtcGsPqrxQtu97cdXtSQMHkyRpc,61210
28
28
  aepp/sandboxes.py,sha256=UwlSFkO2OOmH--6ISz8rxwDu2LcLH1MPqoH7yOEAZHc,29363
29
29
  aepp/schema.py,sha256=JK1lOBYVFPC4Y8GTJsNWc0eoVCjoKoCRIBka26OdXk0,122004
30
30
  aepp/schemamanager.py,sha256=xSQQQw7cX67vopR7HXsWBnlI4FIV7_JBxnIeeEao5Hg,51103
31
- aepp/segmentation.py,sha256=Oi4VnGt0HHAw59rV309XGaBArzxGObssuKM58H8xsnc,42606
31
+ aepp/segmentation.py,sha256=l-2MJuzV2eaO-RijWFdbELDLTAw1EHotFSzL343-up4,42636
32
32
  aepp/sensei.py,sha256=oYNy5BSWAEqsDkEexcQso6NfA6ntGGMnCOyHri0pJs8,7761
33
33
  aepp/som.py,sha256=JzNDQzGaHB9BRRv9zyY1B9Z1GZ-v1uioUZLxLtnf5vE,34206
34
34
  aepp/synchronizer.py,sha256=I32pSI0AVGIjtbbJiZq1qkeZKsIpMni-T72iqyAgo7c,58448
35
35
  aepp/tags.py,sha256=t2qBallTcWR4IOXcDBmrPpqjbSay1z3E2bcRijzVm1s,17641
36
36
  aepp/utils.py,sha256=tG-YVXylm38-bynqfp5N_Mzyo7mhlZj-dLo7wLoO4tM,1200
37
- aepp-0.4.0.post1.dist-info/licenses/LICENSE,sha256=HjYTlfne3BbS5gNHzNqJ5COCiTQLUdf87QkzRyFbE4Y,10337
37
+ aepp-0.4.0.post2.dist-info/licenses/LICENSE,sha256=HjYTlfne3BbS5gNHzNqJ5COCiTQLUdf87QkzRyFbE4Y,10337
38
38
  tests/__init__.py,sha256=d6zWJsJFZrQd5wAYM7sezSxwXbuMMWfNPkK_vpaUzFA,623
39
39
  tests/catalog_test.py,sha256=O4kkG0C_dXk3E77pSzWIt1ewfyKjfZqgbJmBwWwx0po,2246
40
40
  tests/dataaccess_test.py,sha256=bnHwOjPPauTM8s1c6O7iUYC--gqt6tPzT94aEZHDC-c,1238
@@ -44,7 +44,7 @@ tests/exportDatasetToDatalandingZone_test.py,sha256=193AgQR8yhnQmRWV9pgYz1X2Hz-Y
44
44
  tests/flowservice_test.py,sha256=Y1mpYWbKYL_x-ZlIY-EuOuNvlzVV1ERlKseDO7gN3Ss,4208
45
45
  tests/schema_test.py,sha256=6UsgdsizKmii1hzREpBEKWvZouXdJMvU68UKSxlt1uk,2774
46
46
  tests/som_test.py,sha256=a4ut0pEg1HJVMTESaPITmj7YkF54eWCMzKxTMIS-VvM,12101
47
- aepp-0.4.0.post1.dist-info/METADATA,sha256=pWbPbXNv4xNcKqrPXsvPXQVUZlueJT7NWrAu01MbDPI,5490
48
- aepp-0.4.0.post1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
49
- aepp-0.4.0.post1.dist-info/top_level.txt,sha256=Gn88pv1ywuEAgOvhmmXXhN4dosEfCrBNDskje3nqS34,11
50
- aepp-0.4.0.post1.dist-info/RECORD,,
47
+ aepp-0.4.0.post2.dist-info/METADATA,sha256=oPqgxU1JDeP4eT3fHoy8IdstSYmINapk2G5TNEEQxMM,5476
48
+ aepp-0.4.0.post2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
49
+ aepp-0.4.0.post2.dist-info/top_level.txt,sha256=Gn88pv1ywuEAgOvhmmXXhN4dosEfCrBNDskje3nqS34,11
50
+ aepp-0.4.0.post2.dist-info/RECORD,,