-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdelete_entities.py
More file actions
192 lines (162 loc) · 6.33 KB
/
delete_entities.py
File metadata and controls
192 lines (162 loc) · 6.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
"""Delete the dynamic entities listed in a parsed entities file.
Reads an `entities_output.txt`-style file (produced by `parse_minimum_fields.py`
when you choose to save results) and, for every `Entity: <name>` line, deletes
that system dynamic entity on OBP — first removing all of its objects, then the
entity definition itself.
Usage:
python3 delete_entities.py [path/to/entities_output.txt] [--yes] [--token TOKEN]
Options:
file (positional) Path to the parsed entities file. Defaults to
`entities_output.txt`.
--yes Skip the interactive confirmation prompt.
--token DirectLogin token (overrides token from obp_client.py).
"""
import argparse
import logging
import sys
from obp_client import token as default_token
from get_and_delete_dynamic_entities import (
get_all_system_dynamic_entities,
get_all_objects_for_system_dynamic_entity,
delete_object_for_system_dynamic_entity,
delete_system_dynamic_entity,
)
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s | %(levelname)-8s | %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
)
logger = logging.getLogger(__name__)
DEFAULT_INPUT = "entities_output.txt"
ENTITY_PREFIX = "Entity:"
def print_separator(char="=", length=80):
logger.info(char * length)
def parse_entity_names(path):
"""Extract entity names from `Entity: <name>` lines in the parsed file."""
names = []
with open(path, encoding="utf-8") as f:
for line in f:
line = line.rstrip("\n")
if line.startswith(ENTITY_PREFIX):
name = line[len(ENTITY_PREFIX):].strip()
if name:
names.append(name)
return names
def main():
parser = argparse.ArgumentParser(
description="Delete dynamic entities listed in a parsed entities file."
)
parser.add_argument(
"file",
nargs="?",
default=DEFAULT_INPUT,
help=f"Path to the parsed entities file (default: {DEFAULT_INPUT}).",
)
parser.add_argument(
"--yes",
action="store_true",
help="Skip the interactive confirmation prompt.",
)
parser.add_argument(
"--token",
default=default_token,
help="DirectLogin token (overrides token from obp_client.py).",
)
args = parser.parse_args()
# -------------------------------------------------------------------------
# Read the list of entity names to delete
# -------------------------------------------------------------------------
try:
target_names = parse_entity_names(args.file)
except FileNotFoundError:
logger.error(f"File not found: {args.file}")
logger.error("Generate it first with: python3 parse_minimum_fields.py <xlsx> (and save to a file)")
sys.exit(1)
if not target_names:
logger.error(f"No 'Entity:' lines found in {args.file} - nothing to delete.")
sys.exit(1)
logger.info(f"Found {len(target_names)} entity name(s) in {args.file}:")
for name in target_names:
logger.info(f" - {name}")
print_separator()
# -------------------------------------------------------------------------
# Confirm before doing anything destructive
# -------------------------------------------------------------------------
if not args.yes:
answer = input(
f"This will DELETE these {len(target_names)} entities and ALL their records on OBP. Continue? (y/n): "
).lower().strip()
if answer not in ("y", "yes"):
logger.info("Aborted - nothing deleted.")
sys.exit(0)
# -------------------------------------------------------------------------
# STEP 1: Delete all objects for each target entity
# -------------------------------------------------------------------------
logger.info("STEP 1: Deleting entity objects")
print_separator("-")
total_objects_deleted = 0
total_objects_failed = 0
for name in target_names:
logger.info(f"Processing entity: {name}")
try:
response = get_all_objects_for_system_dynamic_entity(name, token=args.token)
if response is None:
logger.info(f" → Entity {name} does not exist yet - skipping")
continue
objects = response.get(f"{name.lower()}_list", [])
if not objects:
logger.info(f" → No objects found for {name}")
continue
logger.info(f" ✓ Found {len(objects)} object(s) for {name}")
except Exception as e:
logger.error(f" ✗ API error while fetching objects for {name}: {e}")
continue
object_ids = [x[f"{name.lower()}_id"] for x in objects]
for idx, obj_id in enumerate(object_ids, 1):
try:
delete_object_for_system_dynamic_entity(name, obj_id, token=args.token)
logger.info(f" ✓ [{idx}/{len(object_ids)}] Deleted object: {obj_id}")
total_objects_deleted += 1
except Exception as e:
logger.error(f" ✗ [{idx}/{len(object_ids)}] Failed to delete object {obj_id}: {e}")
total_objects_failed += 1
logger.info("")
print_separator("-")
logger.info(f"Object Deletion Summary: {total_objects_deleted} deleted, {total_objects_failed} failed")
print_separator()
# -------------------------------------------------------------------------
# STEP 2: Delete the entity definitions themselves
# -------------------------------------------------------------------------
logger.info("STEP 2: Deleting dynamic entity definitions")
print_separator("-")
try:
all_entities = get_all_system_dynamic_entities(token=args.token)["dynamic_entities"]
logger.info(f"Retrieved {len(all_entities)} total dynamic entities from system")
except Exception as e:
logger.error(f"Failed to retrieve dynamic entities: {e}")
sys.exit(1)
# Map entity name -> dynamic_entity_id for the entities we want to delete
name_to_id = {}
for entity in all_entities:
ename = entity.get("entity_name")
if ename in target_names:
name_to_id[ename] = entity.get("dynamic_entity_id")
missing = [n for n in target_names if n not in name_to_id]
if missing:
logger.info(f"Not present on OBP (skipped): {', '.join(missing)}")
total_entities_deleted = 0
total_entities_failed = 0
items = list(name_to_id.items())
for idx, (ename, entity_id) in enumerate(items, 1):
try:
delete_system_dynamic_entity(entity_id, token=args.token)
logger.info(f" ✓ [{idx}/{len(items)}] Deleted entity: {ename} ({entity_id})")
total_entities_deleted += 1
except Exception as e:
logger.error(f" ✗ [{idx}/{len(items)}] Failed to delete entity {ename} ({entity_id}): {e}")
total_entities_failed += 1
print_separator("-")
logger.info(f"Entity Deletion Summary: {total_entities_deleted} deleted, {total_entities_failed} failed")
print_separator("=")
if __name__ == "__main__":
main()