catocli 3.0.18__py3-none-any.whl → 3.0.24__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 catocli might be problematic. Click here for more details.

Files changed (43) hide show
  1. catocli/Utils/clidriver.py +16 -8
  2. catocli/Utils/formatter_account_metrics.py +544 -0
  3. catocli/Utils/formatter_app_stats.py +184 -0
  4. catocli/Utils/formatter_app_stats_timeseries.py +377 -0
  5. catocli/Utils/formatter_events_timeseries.py +459 -0
  6. catocli/Utils/formatter_socket_port_metrics.py +189 -0
  7. catocli/Utils/formatter_socket_port_metrics_timeseries.py +339 -0
  8. catocli/Utils/formatter_utils.py +251 -0
  9. catocli/__init__.py +1 -1
  10. catocli/clisettings.json +37 -5
  11. catocli/parsers/customParserApiClient.py +211 -66
  12. catocli/parsers/mutation_policy/__init__.py +405 -405
  13. catocli/parsers/mutation_site/__init__.py +15 -15
  14. catocli/parsers/mutation_sites/__init__.py +15 -15
  15. catocli/parsers/query_accountMetrics/README.md +90 -0
  16. catocli/parsers/query_accountMetrics/__init__.py +6 -0
  17. catocli/parsers/query_appStats/README.md +2 -2
  18. catocli/parsers/query_appStats/__init__.py +4 -2
  19. catocli/parsers/query_appStatsTimeSeries/__init__.py +4 -2
  20. catocli/parsers/query_eventsTimeSeries/README.md +280 -0
  21. catocli/parsers/query_eventsTimeSeries/__init__.py +6 -0
  22. catocli/parsers/query_policy/__init__.py +42 -42
  23. catocli/parsers/query_socketPortMetrics/README.md +44 -0
  24. catocli/parsers/query_socketPortMetrics/__init__.py +6 -0
  25. catocli/parsers/query_socketPortMetricsTimeSeries/README.md +83 -0
  26. catocli/parsers/query_socketPortMetricsTimeSeries/__init__.py +4 -2
  27. catocli/parsers/utils/export_utils.py +6 -2
  28. catocli-3.0.24.dist-info/METADATA +184 -0
  29. {catocli-3.0.18.dist-info → catocli-3.0.24.dist-info}/RECORD +37 -35
  30. {catocli-3.0.18.dist-info → catocli-3.0.24.dist-info}/top_level.txt +0 -1
  31. models/mutation.xdr.analystFeedback.json +822 -87
  32. models/query.xdr.stories.json +822 -87
  33. models/query.xdr.story.json +822 -87
  34. schema/catolib.py +89 -64
  35. catocli/Utils/csv_formatter.py +0 -663
  36. catocli-3.0.18.dist-info/METADATA +0 -124
  37. scripts/catolib.py +0 -62
  38. scripts/export_if_rules_to_json.py +0 -188
  39. scripts/export_wf_rules_to_json.py +0 -111
  40. scripts/import_wf_rules_to_tfstate.py +0 -331
  41. {catocli-3.0.18.dist-info → catocli-3.0.24.dist-info}/WHEEL +0 -0
  42. {catocli-3.0.18.dist-info → catocli-3.0.24.dist-info}/entry_points.txt +0 -0
  43. {catocli-3.0.18.dist-info → catocli-3.0.24.dist-info}/licenses/LICENSE +0 -0
schema/catolib.py CHANGED
@@ -256,8 +256,8 @@ def processOperation(operationType, operationName):
256
256
 
257
257
  childOperations = operation_data.get("childOperations", {}).keys() if "childOperations" in operation_data else []
258
258
 
259
- # Process with recursion depth tracking
260
- parsedOperation = parseOperationWithDepthTracking(operation_data, childOperations, max_depth=50)
259
+ # Process with recursion depth tracking and pass operation name for filtering
260
+ parsedOperation = parseOperationWithDepthTracking(operation_data, childOperations, max_depth=50, operation_path=operationName)
261
261
  parsedOperation = getOperationArgs(parsedOperation["type"]["definition"], parsedOperation)
262
262
  parsedOperation["path"] = operationName
263
263
 
@@ -313,7 +313,7 @@ def processOperation(operationType, operationName):
313
313
  print(f"Error in processOperation {operationName}: {e}")
314
314
  raise
315
315
 
316
- def parseOperationWithDepthTracking(curOperation, childOperations, max_depth=50):
316
+ def parseOperationWithDepthTracking(curOperation, childOperations, max_depth=50, operation_path=None):
317
317
  """Parse operation with recursion depth tracking to prevent stack overflow"""
318
318
  if not hasattr(thread_local, 'depth'):
319
319
  thread_local.depth = 0
@@ -325,7 +325,7 @@ def parseOperationWithDepthTracking(curOperation, childOperations, max_depth=50)
325
325
  print(f"WARNING: Max recursion depth {max_depth} reached, truncating...")
326
326
  return curOperation
327
327
 
328
- return parseOperation(curOperation, childOperations)
328
+ return parseOperation(curOperation, childOperations, operation_path)
329
329
  finally:
330
330
  thread_local.depth -= 1
331
331
 
@@ -405,7 +405,7 @@ def getNestedArgDefinitions(argsAry, parentParamPath, childOperations, parentFie
405
405
  newArgsList[arg["id_str"]] = arg
406
406
  return newArgsList
407
407
 
408
- def getNestedInterfaceDefinitions(possibleTypesAry, parentParamPath, childOperations, parentFields):
408
+ def getNestedInterfaceDefinitions(possibleTypesAry, parentParamPath, childOperations, parentFields, operation_path=None):
409
409
  """Thread-safe version of interface definitions processing"""
410
410
  curInterfaces = {}
411
411
  for possibleType in possibleTypesAry:
@@ -416,13 +416,13 @@ def getNestedInterfaceDefinitions(possibleTypesAry, parentParamPath, childOperat
416
416
  curInterface = curInterfaces[interfaceName]
417
417
  curParamPath = "" if (parentParamPath == None) else parentParamPath + curInterface["name"] + "___"
418
418
  if "fields" in curInterface and curInterface["fields"] != None and curInterface["name"] != "CatoEndpointUser":
419
- curInterface["fields"] = getNestedFieldDefinitions(copy.deepcopy(curInterface["fields"]), curParamPath, childOperations, parentFields, curInterface["name"])
419
+ curInterface["fields"] = getNestedFieldDefinitions(copy.deepcopy(curInterface["fields"]), curParamPath, childOperations, parentFields, curInterface["name"], operation_path)
420
420
  if "inputFields" in curInterface and curInterface["inputFields"] != None:
421
- curInterface["inputFields"] = getNestedFieldDefinitions(copy.deepcopy(curInterface["inputFields"]), curParamPath, childOperations, parentFields, curInterface["name"])
421
+ curInterface["inputFields"] = getNestedFieldDefinitions(copy.deepcopy(curInterface["inputFields"]), curParamPath, childOperations, parentFields, curInterface["name"], operation_path)
422
422
  if "interfaces" in curInterface and curInterface["interfaces"] != None:
423
- curInterface["interfaces"] = getNestedInterfaceDefinitions(copy.deepcopy(curInterface["interfaces"]), parentParamPath, childOperations, parentFields)
423
+ curInterface["interfaces"] = getNestedInterfaceDefinitions(copy.deepcopy(curInterface["interfaces"]), parentParamPath, childOperations, parentFields, operation_path)
424
424
  if "possibleTypes" in curInterface and curInterface["possibleTypes"] != None:
425
- curInterface["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(curInterface["possibleTypes"]), parentParamPath, childOperations, parentFields)
425
+ curInterface["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(curInterface["possibleTypes"]), parentParamPath, childOperations, parentFields, operation_path)
426
426
 
427
427
  return curInterfaces
428
428
 
@@ -728,8 +728,16 @@ def main(args=None):
728
728
  # Print CSV output directly without JSON formatting
729
729
  print(response[0]["__csv_output__"], end='')
730
730
  else:
731
- # Standard JSON output
732
- print(json.dumps(response[0], sort_keys=True, indent=4))
731
+ # Handle different response formats more robustly
732
+ if isinstance(response, list) and len(response) > 0:
733
+ # Standard format: [data, status, headers]
734
+ print(json.dumps(response[0], sort_keys=True, indent=4))
735
+ elif isinstance(response, dict):
736
+ # Direct dict response
737
+ print(json.dumps(response, sort_keys=True, indent=4))
738
+ else:
739
+ # Fallback: print as-is
740
+ print(json.dumps(response, sort_keys=True, indent=4))
733
741
  except KeyboardInterrupt:
734
742
  print('Operation cancelled by user (Ctrl+C).')
735
743
  exit(130) # Standard exit code for SIGINT
@@ -752,9 +760,10 @@ def writeOperationParsers(catoApiSchema):
752
760
  """Write operation parsers - thread-safe implementation"""
753
761
  parserMapping = {"query":{},"mutation":{}}
754
762
 
755
- # Load settings to get CSV-supported operations
763
+ # Load settings to get format-supported operations
756
764
  settings = loadJSON("../catocli/clisettings.json")
757
765
  csv_supported_operations = settings.get("queryOperationCsvOutput", {})
766
+ format_overrides = settings.get("queryOperationDefaultFormatOverrides", {})
758
767
 
759
768
  ## Write the raw query parser ##
760
769
  cliDriverStr =f"""
@@ -825,9 +834,11 @@ def {parserName}_parse({operationType}_subparsers):
825
834
  usage=get_help("{operationType}_{operationName}"), formatter_class=CustomSubparserHelpFormatter)
826
835
  """
827
836
  if "path" in parser:
828
- # Check if this operation supports CSV output
837
+ # Check if this operation supports format overrides (CSV, etc.)
829
838
  operation_path = parserName.replace("_", ".")
830
- supports_csv = operation_path in csv_supported_operations
839
+ supports_csv = (operation_path in csv_supported_operations or
840
+ (operation_path in format_overrides and
841
+ format_overrides[operation_path].get("enabled", False)))
831
842
 
832
843
  cliDriverStr += f"""
833
844
  {parserName}_parser.add_argument('json', nargs='?', default='{{}}', help='Variables in JSON format (defaults to empty object if not provided).')
@@ -840,11 +851,17 @@ def {parserName}_parse({operationType}_subparsers):
840
851
  {parserName}_parser.add_argument('-H', '--header', action='append', dest='headers', help='Add custom headers in "Key: Value" format. Can be used multiple times.')
841
852
  {parserName}_parser.add_argument('--headers-file', dest='headers_file', help='Load headers from a file. Each line should contain a header in "Key: Value" format.')
842
853
  """
843
- # Add -f flag for CSV-supported operations
854
+ # Add format flags for operations with format overrides
844
855
  if supports_csv:
856
+ # Generate appropriate default CSV filename from operation name
857
+ # Use the full operation name instead of stripping parts to ensure clarity
858
+ default_csv_name = f"{operationName.lower()}.csv"
859
+
845
860
  cliDriverStr += f"""
846
- {parserName}_parser.add_argument('-f', '--format', choices=['json', 'csv'], default='json', help='Output format (default: json)')
847
- {parserName}_parser.add_argument('--csv-filename', dest='csv_filename', help='Override CSV file name (default: accountmetrics.csv)')
861
+
862
+ {parserName}_parser.add_argument('-f', '--format', choices=['json', 'csv'], help='Output format (default: formatted json, use -raw for original json)')
863
+ {parserName}_parser.add_argument('-raw', '--raw', dest='raw_output', action='store_true', help='Return raw/original JSON format (bypasses default formatting)')
864
+ {parserName}_parser.add_argument('--csv-filename', dest='csv_filename', help='Override CSV file name (default: {default_csv_name})')
848
865
  {parserName}_parser.add_argument('--append-timestamp', dest='append_timestamp', action='store_true', help='Append timestamp to the CSV file name')
849
866
  """
850
867
 
@@ -1180,7 +1197,7 @@ catocli {operationCmd} '{example_json_pretty}'
1180
1197
 
1181
1198
  print(" - README files written successfully")
1182
1199
 
1183
- def getOfType(curType, ofType, parentParamPath, childOperations, parentFields, parentTypeName=None):
1200
+ def getOfType(curType, ofType, parentParamPath, childOperations, parentFields, parentTypeName=None, operation_path=None):
1184
1201
  """Thread-safe version with recursion depth management"""
1185
1202
  if not hasattr(thread_local, 'depth'):
1186
1203
  thread_local.depth = 0
@@ -1196,7 +1213,7 @@ def getOfType(curType, ofType, parentParamPath, childOperations, parentFields, p
1196
1213
  curParamPath = "" if (parentParamPath == None) else parentParamPath + "___"
1197
1214
 
1198
1215
  if curType["ofType"] != None:
1199
- ofType = getOfType(copy.deepcopy(curType["ofType"]), ofType, parentParamPath, childOperations, parentFields)
1216
+ ofType = getOfType(copy.deepcopy(curType["ofType"]), ofType, parentParamPath, childOperations, parentFields, parentTypeName, operation_path)
1200
1217
  else:
1201
1218
  ofType["name"] = curType["name"]
1202
1219
 
@@ -1210,28 +1227,28 @@ def getOfType(curType, ofType, parentParamPath, childOperations, parentFields, p
1210
1227
  ofType["indexType"] = "input_object"
1211
1228
  ofType["definition"] = copy.deepcopy(catoApiIntrospection["input_objects"][ofType["name"]])
1212
1229
  if ofType["definition"]["inputFields"] != None:
1213
- ofType["definition"]["inputFields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["inputFields"]), curParamPath, childOperations, parentFields, ofType["name"])
1230
+ ofType["definition"]["inputFields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["inputFields"]), curParamPath, childOperations, parentFields, ofType["name"], operation_path)
1214
1231
  elif "UNION" in ofType["kind"]:
1215
1232
  ofType["indexType"] = "interface"
1216
1233
  ofType["definition"] = copy.deepcopy(catoApiIntrospection["unions"][ofType["name"]])
1217
1234
  if ofType["definition"]["possibleTypes"] != None:
1218
- ofType["definition"]["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["possibleTypes"]), curParamPath, childOperations, parentFields)
1235
+ ofType["definition"]["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["possibleTypes"]), curParamPath, childOperations, parentFields, operation_path)
1219
1236
  elif "OBJECT" in ofType["kind"]:
1220
1237
  ofType["indexType"] = "object"
1221
1238
  ofType["definition"] = copy.deepcopy(catoApiIntrospection["objects"][ofType["name"]])
1222
1239
  if ofType["definition"]["fields"] != None and childOperations!=None:
1223
1240
  ofType["definition"]["fields"] = checkForChildOperation(copy.deepcopy(ofType["definition"]["fields"]), childOperations)
1224
- ofType["definition"]["fields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["fields"]), curParamPath, childOperations, parentFields, ofType["name"])
1241
+ ofType["definition"]["fields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["fields"]), curParamPath, childOperations, parentFields, ofType["name"], operation_path)
1225
1242
  if ofType["definition"]["interfaces"] != None:
1226
- ofType["definition"]["interfaces"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["interfaces"]), curParamPath, childOperations, parentFields)
1243
+ ofType["definition"]["interfaces"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["interfaces"]), curParamPath, childOperations, parentFields, operation_path)
1227
1244
  elif "INTERFACE" in ofType["kind"]:
1228
1245
  ofType["indexType"] = "interface"
1229
1246
  ofType["definition"] = copy.deepcopy(catoApiIntrospection["interfaces"][ofType["name"]])
1230
1247
  if ofType["definition"]["fields"] != None:
1231
- ofType["definition"]["fields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["fields"]), curParamPath, childOperations, parentFields, ofType["name"])
1248
+ ofType["definition"]["fields"] = getNestedFieldDefinitions(copy.deepcopy(ofType["definition"]["fields"]), curParamPath, childOperations, parentFields, ofType["name"], operation_path)
1232
1249
  # CRITICAL FIX: Also handle possibleTypes for interfaces (like MergedIncident)
1233
1250
  if ofType["definition"]["possibleTypes"] != None:
1234
- ofType["definition"]["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["possibleTypes"]), curParamPath, childOperations, parentFields)
1251
+ ofType["definition"]["possibleTypes"] = getNestedInterfaceDefinitions(copy.deepcopy(ofType["definition"]["possibleTypes"]), curParamPath, childOperations, parentFields, operation_path)
1235
1252
  elif "ENUM" in ofType["kind"]:
1236
1253
  ofType["indexType"] = "enum"
1237
1254
  ofType["definition"] = copy.deepcopy(catoApiIntrospection["enums"][ofType["name"]])
@@ -1240,17 +1257,54 @@ def getOfType(curType, ofType, parentParamPath, childOperations, parentFields, p
1240
1257
  finally:
1241
1258
  thread_local.depth -= 1
1242
1259
 
1243
- def getNestedFieldDefinitions(fieldsAry, parentParamPath, childOperations, parentFields, parentTypeName=None):
1244
- """Thread-safe version with FIXED records exclusion removal"""
1260
+ def should_exclude_field(field_name, field_type, operation_path, parent_path):
1261
+ """
1262
+ Determine if a field should be excluded from model generation for query.policy and mutation.policy operations.
1263
+
1264
+ Excludes:
1265
+ - subPolicyId field (type: ID) from rules.rule.section and sections.section
1266
+ - access field from sections with EntityAccess type containing action field (enum: RBACAction)
1267
+ """
1268
+ # Only apply filtering to query.policy and mutation.policy operations
1269
+ if not operation_path or not (operation_path.startswith("query.policy") or operation_path.startswith("mutation.policy")):
1270
+ return False
1271
+
1272
+ # Exclude subPolicyId field from specific sections (handles nested paths like firewall.rule.section)
1273
+ if (field_name == "subPolicyId" and
1274
+ field_type.get("name") == "ID" and
1275
+ parent_path and (
1276
+ parent_path.endswith(".section.subPolicyId") and
1277
+ ("rules.rule" in parent_path or "sections.section" in parent_path or
1278
+ "rule.rule.section" in parent_path or # For mutations like addRule.rule.rule.section
1279
+ "section.section" in parent_path or # For mutations like addSection.section.section
1280
+ "firewall.rule.section" in parent_path) # For socketLan mutations like addRule.rule.rule.firewall.rule.section
1281
+ )):
1282
+ return True
1283
+
1284
+ # Exclude access field from sections with EntityAccess type
1285
+ if (field_name == "access" and
1286
+ field_type.get("name") == "EntityAccess" and
1287
+ parent_path and ("sections.access" in parent_path or
1288
+ parent_path.endswith(".access") and "section" in parent_path)):
1289
+ return True
1290
+
1291
+ return False
1292
+
1293
+ def getNestedFieldDefinitions(fieldsAry, parentParamPath, childOperations, parentFields, parentTypeName=None, operation_path=None):
1294
+ """Thread-safe version with field exclusion logic for policy operations"""
1245
1295
  newFieldsList = {}
1246
1296
  for field in fieldsAry:
1247
1297
  if isinstance(field, str):
1248
1298
  field = fieldsAry[field]
1249
1299
  curParamPath = field["name"] if (parentParamPath == None) else (parentParamPath.replace("___",".") + field["name"])
1250
- field["type"] = getOfType(field["type"], { "non_null": False, "kind": [], "name": None }, curParamPath, childOperations, parentFields, parentTypeName)
1300
+ field["type"] = getOfType(field["type"], { "non_null": False, "kind": [], "name": None }, curParamPath, childOperations, parentFields, parentTypeName, operation_path)
1251
1301
  field["path"] = curParamPath
1252
1302
  field["id_str"] = curParamPath.replace(".","___")
1253
1303
 
1304
+ # Check if this field should be excluded from policy operations
1305
+ if should_exclude_field(field["name"], field["type"], operation_path, curParamPath):
1306
+ continue # Skip this field
1307
+
1254
1308
  if isinstance(field["type"]["kind"], list):
1255
1309
  field["required"] = True if field["type"]["kind"][0] == "NON_NULL" else False
1256
1310
  else:
@@ -1316,21 +1370,21 @@ def send(api_key, query, variables={}, operationName=None):
1316
1370
  # writeCliDriver, writeOperationParsers, writeReadmes, etc.)
1317
1371
  # For space reasons, I'm not including them all here, but they should be copied over
1318
1372
 
1319
- def parseOperation(curOperation, childOperations):
1373
+ def parseOperation(curOperation, childOperations, operation_path=None):
1320
1374
  if "operationArgs" not in curOperation:
1321
1375
  curOperation["operationArgs"] = {}
1322
1376
  curOperation["fieldTypes"] = {}
1323
- curOfType = getOfType(curOperation["type"], { "non_null": False, "kind": [], "name": None }, None, childOperations, None)
1377
+ curOfType = getOfType(curOperation["type"], { "non_null": False, "kind": [], "name": None }, None, childOperations, None, None, operation_path)
1324
1378
  curOperation["type"] = copy.deepcopy(curOfType)
1325
1379
  if curOfType["name"] in catoApiIntrospection["objects"]:
1326
1380
  curOperation["args"] = getNestedArgDefinitions(curOperation["args"], None, childOperations, None)
1327
1381
  curOperation["type"]["definition"] = copy.deepcopy(catoApiIntrospection["objects"][curOperation["type"]["name"]])
1328
1382
  if "fields" in curOperation["type"]["definition"] and curOperation["type"]["definition"]["fields"] != None:
1329
1383
  curOperation["type"]["definition"]["fields"] = checkForChildOperation(copy.deepcopy(curOperation["type"]["definition"]["fields"]), childOperations)
1330
- curOperation["type"]["definition"]["fields"] = copy.deepcopy(getNestedFieldDefinitions(curOperation["type"]["definition"]["fields"], None, childOperations, [], curOperation["type"]["name"]))
1384
+ curOperation["type"]["definition"]["fields"] = copy.deepcopy(getNestedFieldDefinitions(curOperation["type"]["definition"]["fields"], None, childOperations, [], curOperation["type"]["name"], operation_path))
1331
1385
  if "inputFields" in curOperation["type"]["definition"] and curOperation["type"]["definition"]["inputFields"] != None:
1332
1386
  parentFields = curOperation["type"]["definition"]["inputFields"].keys()
1333
- curOperation["type"]["definition"]["inputFields"] = copy.deepcopy(getNestedFieldDefinitions(curOperation["type"]["definition"]["inputFields"], None, childOperations, parentFields, curOperation["type"]["name"]))
1387
+ curOperation["type"]["definition"]["inputFields"] = copy.deepcopy(getNestedFieldDefinitions(curOperation["type"]["definition"]["inputFields"], None, childOperations, parentFields, curOperation["type"]["name"], operation_path))
1334
1388
  return curOperation
1335
1389
 
1336
1390
  def checkForChildOperation(fieldsAry, childOperations):
@@ -1455,7 +1509,7 @@ def renderInputFieldVal(arg):
1455
1509
 
1456
1510
  return value
1457
1511
 
1458
- def getNestedInterfaceDefinitions(possibleTypesAry, parentParamPath, childOperations, parentFields):
1512
+ def getNestedInterfaceDefinitions(possibleTypesAry, parentParamPath, childOperations, parentFields, operation_path=None):
1459
1513
  """Get nested interface definitions - returns expanded possibleTypes array with complete field definitions"""
1460
1514
  expandedTypes = []
1461
1515
  for possibleType in possibleTypesAry:
@@ -1472,7 +1526,8 @@ def getNestedInterfaceDefinitions(possibleTypesAry, parentParamPath, childOperat
1472
1526
  parentParamPath,
1473
1527
  childOperations,
1474
1528
  parentFields,
1475
- possibleType["name"]
1529
+ possibleType["name"],
1530
+ operation_path
1476
1531
  )
1477
1532
  expandedTypes.append(expandedType)
1478
1533
  else:
@@ -1700,33 +1755,3 @@ catocli {subOperationCmd} '{example_json_pretty}'
1700
1755
  # Only recurse if subOperation is a dict and doesn't have a "path" key
1701
1756
  if isinstance(subOperation, dict) and "path" not in subOperation:
1702
1757
  renderSubReadme(subOperation, operationType, subOperationPath)
1703
-
1704
- def main():
1705
- # Main execution function with threading support
1706
- options = initParser()
1707
-
1708
- # Load the introspection schema
1709
- print("Loading schema...")
1710
- schema = loadJSON("./introspection.json")
1711
-
1712
- print("Starting multi-threaded schema parsing...")
1713
- start_time = time.time()
1714
-
1715
- # Parse the schema using multi-threading
1716
- parseSchema(schema)
1717
-
1718
- end_time = time.time()
1719
- print(f"\n• Schema processing completed in {end_time - start_time:.2f} seconds")
1720
-
1721
- print("\n• Generating CLI components...")
1722
- writeCliDriver(catoApiSchema)
1723
- writeOperationParsers(catoApiSchema)
1724
- writeReadmes(catoApiSchema)
1725
-
1726
- total_operations = len(catoApiSchema["query"]) + len(catoApiSchema["mutation"])
1727
- print(f"\n• Successfully generated {total_operations} operation models")
1728
- print(f" - Query operations: {len(catoApiSchema['query'])}")
1729
- print(f" - Mutation operations: {len(catoApiSchema['mutation'])}")
1730
-
1731
- if __name__ == "__main__":
1732
- main()