direct-cli 0.0.0__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.
Files changed (39) hide show
  1. direct_cli/__init__.py +14 -0
  2. direct_cli/api.py +94 -0
  3. direct_cli/auth.py +58 -0
  4. direct_cli/cli.py +85 -0
  5. direct_cli/commands/__init__.py +61 -0
  6. direct_cli/commands/adextensions.py +96 -0
  7. direct_cli/commands/adgroups.py +189 -0
  8. direct_cli/commands/adimages.py +63 -0
  9. direct_cli/commands/ads.py +306 -0
  10. direct_cli/commands/agencyclients.py +64 -0
  11. direct_cli/commands/audiencetargets.py +187 -0
  12. direct_cli/commands/bidmodifiers.py +110 -0
  13. direct_cli/commands/bids.py +108 -0
  14. direct_cli/commands/businesses.py +61 -0
  15. direct_cli/commands/campaigns.py +311 -0
  16. direct_cli/commands/changes.py +97 -0
  17. direct_cli/commands/clients.py +98 -0
  18. direct_cli/commands/creatives.py +68 -0
  19. direct_cli/commands/dictionaries.py +64 -0
  20. direct_cli/commands/dynamicads.py +104 -0
  21. direct_cli/commands/feeds.py +99 -0
  22. direct_cli/commands/keywordbids.py +111 -0
  23. direct_cli/commands/keywords.py +309 -0
  24. direct_cli/commands/keywordsresearch.py +71 -0
  25. direct_cli/commands/leads.py +65 -0
  26. direct_cli/commands/negativekeywordsharedsets.py +97 -0
  27. direct_cli/commands/reports.py +128 -0
  28. direct_cli/commands/retargeting.py +104 -0
  29. direct_cli/commands/sitelinks.py +92 -0
  30. direct_cli/commands/smartadtargets.py +104 -0
  31. direct_cli/commands/turbopages.py +97 -0
  32. direct_cli/commands/vcards.py +93 -0
  33. direct_cli/output.py +143 -0
  34. direct_cli/utils.py +120 -0
  35. direct_cli-0.0.0.dist-info/METADATA +393 -0
  36. direct_cli-0.0.0.dist-info/RECORD +39 -0
  37. direct_cli-0.0.0.dist-info/WHEEL +5 -0
  38. direct_cli-0.0.0.dist-info/entry_points.txt +2 -0
  39. direct_cli-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,306 @@
1
+ """
2
+ Ads commands
3
+ """
4
+
5
+ import json
6
+ import click
7
+
8
+ from ..api import create_client
9
+ from ..output import format_output, print_error
10
+ from ..utils import parse_ids
11
+
12
+
13
+ @click.group()
14
+ def ads():
15
+ """Manage ads"""
16
+ pass
17
+
18
+
19
+ @ads.command()
20
+ @click.option("--ids", help="Comma-separated ad IDs")
21
+ @click.option("--campaign-ids", help="Comma-separated campaign IDs")
22
+ @click.option("--adgroup-ids", help="Comma-separated ad group IDs")
23
+ @click.option("--status", help="Filter by status")
24
+ @click.option("--limit", type=int, help="Limit number of results")
25
+ @click.option("--fetch-all", is_flag=True, help="Fetch all pages")
26
+ @click.option("--format", "output_format", default="json", help="Output format")
27
+ @click.option("--output", help="Output file")
28
+ @click.option("--fields", help="Comma-separated field names")
29
+ @click.pass_context
30
+ def get(
31
+ ctx,
32
+ ids,
33
+ campaign_ids,
34
+ adgroup_ids,
35
+ status,
36
+ limit,
37
+ fetch_all,
38
+ output_format,
39
+ output,
40
+ fields,
41
+ ):
42
+ """Get ads"""
43
+ try:
44
+ client = create_client(
45
+ token=ctx.obj.get("token"),
46
+ login=ctx.obj.get("login"),
47
+ sandbox=ctx.obj.get("sandbox"),
48
+ )
49
+
50
+ field_names = (
51
+ fields.split(",")
52
+ if fields
53
+ else ["Id", "CampaignId", "AdGroupId", "Status", "State", "Type"]
54
+ )
55
+
56
+ criteria = {}
57
+ if ids:
58
+ criteria["Ids"] = parse_ids(ids)
59
+ if campaign_ids:
60
+ criteria["CampaignIds"] = parse_ids(campaign_ids)
61
+ if adgroup_ids:
62
+ criteria["AdGroupIds"] = parse_ids(adgroup_ids)
63
+ if status:
64
+ criteria["Statuses"] = [status]
65
+
66
+ params = {"SelectionCriteria": criteria, "FieldNames": field_names}
67
+
68
+ if limit:
69
+ params["Page"] = {"Limit": limit}
70
+
71
+ body = {"method": "get", "params": params}
72
+
73
+ result = client.ads().post(data=body)
74
+
75
+ if fetch_all:
76
+ items = []
77
+ for item in result().iter_items():
78
+ items.append(item)
79
+ format_output(items, output_format, output)
80
+ else:
81
+ data = result().extract()
82
+ format_output(data, output_format, output)
83
+
84
+ except Exception as e:
85
+ print_error(str(e))
86
+ raise click.Abort()
87
+
88
+
89
+ @ads.command()
90
+ @click.option("--adgroup-id", required=True, type=int, help="Ad group ID")
91
+ @click.option("--type", "ad_type", default="TEXT_AD", help="Ad type")
92
+ @click.option("--title", help="Ad title")
93
+ @click.option("--text", help="Ad text")
94
+ @click.option("--href", help="Ad URL")
95
+ @click.option("--json", "extra_json", help="Additional JSON parameters")
96
+ @click.option("--dry-run", is_flag=True, help="Show request without sending")
97
+ @click.pass_context
98
+ def add(ctx, adgroup_id, ad_type, title, text, href, extra_json, dry_run):
99
+ """Add new ad"""
100
+ try:
101
+ ad_data = {"AdGroupId": adgroup_id, "Type": ad_type}
102
+
103
+ if ad_type == "TEXT_AD":
104
+ ad_data["TextAd"] = {}
105
+ if title:
106
+ ad_data["TextAd"]["Title"] = title
107
+ if text:
108
+ ad_data["TextAd"]["Text"] = text
109
+ if href:
110
+ ad_data["TextAd"]["Href"] = href
111
+
112
+ if extra_json:
113
+ extra = json.loads(extra_json)
114
+ ad_data.update(extra)
115
+
116
+ body = {"method": "add", "params": {"Ads": [ad_data]}}
117
+
118
+ if dry_run:
119
+ format_output(body, "json", None)
120
+ return
121
+
122
+ client = create_client(
123
+ token=ctx.obj.get("token"),
124
+ login=ctx.obj.get("login"),
125
+ sandbox=ctx.obj.get("sandbox"),
126
+ )
127
+
128
+ result = client.ads().post(data=body)
129
+ format_output(result().extract(), "json", None)
130
+
131
+ except Exception as e:
132
+ print_error(str(e))
133
+ raise click.Abort()
134
+
135
+
136
+ @ads.command()
137
+ @click.option("--id", "ad_id", required=True, type=int, help="Ad ID")
138
+ @click.option("--status", help="New status")
139
+ @click.option("--json", "extra_json", help="Additional JSON parameters")
140
+ @click.option("--dry-run", is_flag=True, help="Show request without sending")
141
+ @click.pass_context
142
+ def update(ctx, ad_id, status, extra_json, dry_run):
143
+ """Update ad"""
144
+ try:
145
+ ad_data = {"Id": ad_id}
146
+
147
+ if status:
148
+ ad_data["Status"] = status
149
+
150
+ if extra_json:
151
+ extra = json.loads(extra_json)
152
+ ad_data.update(extra)
153
+
154
+ body = {"method": "update", "params": {"Ads": [ad_data]}}
155
+
156
+ if dry_run:
157
+ format_output(body, "json", None)
158
+ return
159
+
160
+ client = create_client(
161
+ token=ctx.obj.get("token"),
162
+ login=ctx.obj.get("login"),
163
+ sandbox=ctx.obj.get("sandbox"),
164
+ )
165
+
166
+ result = client.ads().post(data=body)
167
+ format_output(result().extract(), "json", None)
168
+
169
+ except Exception as e:
170
+ print_error(str(e))
171
+ raise click.Abort()
172
+
173
+
174
+ @ads.command()
175
+ @click.option("--id", "ad_id", required=True, type=int, help="Ad ID")
176
+ @click.pass_context
177
+ def delete(ctx, ad_id):
178
+ """Delete ad"""
179
+ try:
180
+ client = create_client(
181
+ token=ctx.obj.get("token"),
182
+ login=ctx.obj.get("login"),
183
+ sandbox=ctx.obj.get("sandbox"),
184
+ )
185
+
186
+ body = {"method": "delete", "params": {"SelectionCriteria": {"Ids": [ad_id]}}}
187
+
188
+ result = client.ads().post(data=body)
189
+ format_output(result().extract(), "json", None)
190
+
191
+ except Exception as e:
192
+ print_error(str(e))
193
+ raise click.Abort()
194
+
195
+
196
+ @ads.command()
197
+ @click.option("--id", "ad_id", required=True, type=int, help="Ad ID")
198
+ @click.pass_context
199
+ def archive(ctx, ad_id):
200
+ """Archive ad"""
201
+ try:
202
+ client = create_client(
203
+ token=ctx.obj.get("token"),
204
+ login=ctx.obj.get("login"),
205
+ sandbox=ctx.obj.get("sandbox"),
206
+ )
207
+
208
+ body = {"method": "archive", "params": {"SelectionCriteria": {"Ids": [ad_id]}}}
209
+
210
+ result = client.ads().post(data=body)
211
+ format_output(result().extract(), "json", None)
212
+
213
+ except Exception as e:
214
+ print_error(str(e))
215
+ raise click.Abort()
216
+
217
+
218
+ @ads.command()
219
+ @click.option("--id", "ad_id", required=True, type=int, help="Ad ID")
220
+ @click.pass_context
221
+ def unarchive(ctx, ad_id):
222
+ """Unarchive ad"""
223
+ try:
224
+ client = create_client(
225
+ token=ctx.obj.get("token"),
226
+ login=ctx.obj.get("login"),
227
+ sandbox=ctx.obj.get("sandbox"),
228
+ )
229
+
230
+ body = {
231
+ "method": "unarchive",
232
+ "params": {"SelectionCriteria": {"Ids": [ad_id]}},
233
+ }
234
+
235
+ result = client.ads().post(data=body)
236
+ format_output(result().extract(), "json", None)
237
+
238
+ except Exception as e:
239
+ print_error(str(e))
240
+ raise click.Abort()
241
+
242
+
243
+ @ads.command()
244
+ @click.option("--id", "ad_id", required=True, type=int, help="Ad ID")
245
+ @click.pass_context
246
+ def suspend(ctx, ad_id):
247
+ """Suspend ad"""
248
+ try:
249
+ client = create_client(
250
+ token=ctx.obj.get("token"),
251
+ login=ctx.obj.get("login"),
252
+ sandbox=ctx.obj.get("sandbox"),
253
+ )
254
+
255
+ body = {"method": "suspend", "params": {"SelectionCriteria": {"Ids": [ad_id]}}}
256
+
257
+ result = client.ads().post(data=body)
258
+ format_output(result().extract(), "json", None)
259
+
260
+ except Exception as e:
261
+ print_error(str(e))
262
+ raise click.Abort()
263
+
264
+
265
+ @ads.command()
266
+ @click.option("--id", "ad_id", required=True, type=int, help="Ad ID")
267
+ @click.pass_context
268
+ def resume(ctx, ad_id):
269
+ """Resume ad"""
270
+ try:
271
+ client = create_client(
272
+ token=ctx.obj.get("token"),
273
+ login=ctx.obj.get("login"),
274
+ sandbox=ctx.obj.get("sandbox"),
275
+ )
276
+
277
+ body = {"method": "resume", "params": {"SelectionCriteria": {"Ids": [ad_id]}}}
278
+
279
+ result = client.ads().post(data=body)
280
+ format_output(result().extract(), "json", None)
281
+
282
+ except Exception as e:
283
+ print_error(str(e))
284
+ raise click.Abort()
285
+
286
+
287
+ @ads.command()
288
+ @click.option("--id", "ad_id", required=True, type=int, help="Ad ID")
289
+ @click.pass_context
290
+ def moderate(ctx, ad_id):
291
+ """Moderate ad"""
292
+ try:
293
+ client = create_client(
294
+ token=ctx.obj.get("token"),
295
+ login=ctx.obj.get("login"),
296
+ sandbox=ctx.obj.get("sandbox"),
297
+ )
298
+
299
+ body = {"method": "moderate", "params": {"SelectionCriteria": {"Ids": [ad_id]}}}
300
+
301
+ result = client.ads().post(data=body)
302
+ format_output(result().extract(), "json", None)
303
+
304
+ except Exception as e:
305
+ print_error(str(e))
306
+ raise click.Abort()
@@ -0,0 +1,64 @@
1
+ """
2
+ AgencyClients commands
3
+ """
4
+
5
+ import click
6
+
7
+ from ..api import create_client
8
+ from ..output import format_output, print_error
9
+ from ..utils import parse_ids, get_default_fields
10
+
11
+
12
+ @click.group()
13
+ def agencyclients():
14
+ """Manage agency clients"""
15
+ pass
16
+
17
+
18
+ @agencyclients.command()
19
+ @click.option("--ids", help="Comma-separated client IDs")
20
+ @click.option("--limit", type=int, help="Limit number of results")
21
+ @click.option("--fetch-all", is_flag=True, help="Fetch all pages")
22
+ @click.option("--format", "output_format", default="json", help="Output format")
23
+ @click.option("--output", help="Output file")
24
+ @click.option("--fields", help="Comma-separated field names")
25
+ @click.pass_context
26
+ def get(ctx, ids, limit, fetch_all, output_format, output, fields):
27
+ """Get agency clients"""
28
+ try:
29
+ client = create_client(
30
+ token=ctx.obj.get("token"),
31
+ login=ctx.obj.get("login"),
32
+ sandbox=ctx.obj.get("sandbox"),
33
+ )
34
+
35
+ field_names = fields.split(",") if fields else get_default_fields("clients")
36
+
37
+ criteria = {}
38
+ if ids:
39
+ criteria["ClientIds"] = parse_ids(ids)
40
+
41
+ params = {"FieldNames": field_names}
42
+
43
+ if criteria:
44
+ params["SelectionCriteria"] = criteria
45
+
46
+ if limit:
47
+ params["Page"] = {"Limit": limit}
48
+
49
+ body = {"method": "get", "params": params}
50
+
51
+ result = client.agencyclients().post(data=body)
52
+
53
+ if fetch_all:
54
+ items = []
55
+ for item in result().iter_items():
56
+ items.append(item)
57
+ format_output(items, output_format, output)
58
+ else:
59
+ data = result().extract()
60
+ format_output(data, output_format, output)
61
+
62
+ except Exception as e:
63
+ print_error(str(e))
64
+ raise click.Abort()
@@ -0,0 +1,187 @@
1
+ """
2
+ AudienceTargets commands
3
+ """
4
+
5
+ import json
6
+ import click
7
+
8
+ from ..api import create_client
9
+ from ..output import format_output, print_error
10
+ from ..utils import parse_ids
11
+
12
+
13
+ @click.group()
14
+ def audiencetargets():
15
+ """Manage audience targets"""
16
+ pass
17
+
18
+
19
+ @audiencetargets.command()
20
+ @click.option("--ids", help="Comma-separated target IDs")
21
+ @click.option("--adgroup-ids", help="Comma-separated ad group IDs")
22
+ @click.option("--campaign-ids", help="Comma-separated campaign IDs")
23
+ @click.option("--limit", type=int, help="Limit number of results")
24
+ @click.option("--fetch-all", is_flag=True, help="Fetch all pages")
25
+ @click.option("--format", "output_format", default="json", help="Output format")
26
+ @click.option("--output", help="Output file")
27
+ @click.pass_context
28
+ def get(ctx, ids, adgroup_ids, campaign_ids, limit, fetch_all, output_format, output):
29
+ """Get audience targets"""
30
+ try:
31
+ client = create_client(
32
+ token=ctx.obj.get("token"),
33
+ login=ctx.obj.get("login"),
34
+ sandbox=ctx.obj.get("sandbox"),
35
+ )
36
+
37
+ criteria = {}
38
+ if ids:
39
+ criteria["Ids"] = parse_ids(ids)
40
+ if adgroup_ids:
41
+ criteria["AdGroupIds"] = parse_ids(adgroup_ids)
42
+ if campaign_ids:
43
+ criteria["CampaignIds"] = parse_ids(campaign_ids)
44
+
45
+ params = {
46
+ "SelectionCriteria": criteria,
47
+ "FieldNames": ["Id", "AdGroupId", "RetargetingListId", "State", "Bid"],
48
+ }
49
+
50
+ if limit:
51
+ params["Page"] = {"Limit": limit}
52
+
53
+ body = {"method": "get", "params": params}
54
+
55
+ result = client.audiencetargets().post(data=body)
56
+
57
+ if fetch_all:
58
+ items = []
59
+ for item in result().iter_items():
60
+ items.append(item)
61
+ format_output(items, output_format, output)
62
+ else:
63
+ data = result().extract()
64
+ format_output(data, output_format, output)
65
+
66
+ except Exception as e:
67
+ print_error(str(e))
68
+ raise click.Abort()
69
+
70
+
71
+ @audiencetargets.command()
72
+ @click.option("--adgroup-id", required=True, type=int, help="Ad group ID")
73
+ @click.option(
74
+ "--retargeting-list-id", required=True, type=int, help="Retargeting list ID"
75
+ )
76
+ @click.option("--bid", type=float, help="Bid")
77
+ @click.option("--json", "extra_json", help="Additional JSON parameters")
78
+ @click.option("--dry-run", is_flag=True, help="Show request without sending")
79
+ @click.pass_context
80
+ def add(ctx, adgroup_id, retargeting_list_id, bid, extra_json, dry_run):
81
+ """Add audience target"""
82
+ try:
83
+ target_data = {
84
+ "AdGroupId": adgroup_id,
85
+ "RetargetingListId": retargeting_list_id,
86
+ }
87
+
88
+ if bid:
89
+ target_data["Bid"] = int(bid * 1000000)
90
+
91
+ if extra_json:
92
+ extra = json.loads(extra_json)
93
+ target_data.update(extra)
94
+
95
+ body = {"method": "add", "params": {"AudienceTargets": [target_data]}}
96
+
97
+ if dry_run:
98
+ format_output(body, "json", None)
99
+ return
100
+
101
+ client = create_client(
102
+ token=ctx.obj.get("token"),
103
+ login=ctx.obj.get("login"),
104
+ sandbox=ctx.obj.get("sandbox"),
105
+ )
106
+
107
+ result = client.audiencetargets().post(data=body)
108
+ format_output(result().extract(), "json", None)
109
+
110
+ except Exception as e:
111
+ print_error(str(e))
112
+ raise click.Abort()
113
+
114
+
115
+ @audiencetargets.command()
116
+ @click.option("--id", "target_id", required=True, type=int, help="Target ID")
117
+ @click.pass_context
118
+ def delete(ctx, target_id):
119
+ """Delete audience target"""
120
+ try:
121
+ client = create_client(
122
+ token=ctx.obj.get("token"),
123
+ login=ctx.obj.get("login"),
124
+ sandbox=ctx.obj.get("sandbox"),
125
+ )
126
+
127
+ body = {
128
+ "method": "delete",
129
+ "params": {"SelectionCriteria": {"Ids": [target_id]}},
130
+ }
131
+
132
+ result = client.audiencetargets().post(data=body)
133
+ format_output(result().extract(), "json", None)
134
+
135
+ except Exception as e:
136
+ print_error(str(e))
137
+ raise click.Abort()
138
+
139
+
140
+ @audiencetargets.command()
141
+ @click.option("--id", "target_id", required=True, type=int, help="Target ID")
142
+ @click.pass_context
143
+ def suspend(ctx, target_id):
144
+ """Suspend audience target"""
145
+ try:
146
+ client = create_client(
147
+ token=ctx.obj.get("token"),
148
+ login=ctx.obj.get("login"),
149
+ sandbox=ctx.obj.get("sandbox"),
150
+ )
151
+
152
+ body = {
153
+ "method": "suspend",
154
+ "params": {"SelectionCriteria": {"Ids": [target_id]}},
155
+ }
156
+
157
+ result = client.audiencetargets().post(data=body)
158
+ format_output(result().extract(), "json", None)
159
+
160
+ except Exception as e:
161
+ print_error(str(e))
162
+ raise click.Abort()
163
+
164
+
165
+ @audiencetargets.command()
166
+ @click.option("--id", "target_id", required=True, type=int, help="Target ID")
167
+ @click.pass_context
168
+ def resume(ctx, target_id):
169
+ """Resume audience target"""
170
+ try:
171
+ client = create_client(
172
+ token=ctx.obj.get("token"),
173
+ login=ctx.obj.get("login"),
174
+ sandbox=ctx.obj.get("sandbox"),
175
+ )
176
+
177
+ body = {
178
+ "method": "resume",
179
+ "params": {"SelectionCriteria": {"Ids": [target_id]}},
180
+ }
181
+
182
+ result = client.audiencetargets().post(data=body)
183
+ format_output(result().extract(), "json", None)
184
+
185
+ except Exception as e:
186
+ print_error(str(e))
187
+ raise click.Abort()
@@ -0,0 +1,110 @@
1
+ """
2
+ BidModifiers commands
3
+ """
4
+
5
+ import json
6
+ import click
7
+
8
+ from ..api import create_client
9
+ from ..output import format_output, print_error
10
+ from ..utils import parse_ids
11
+
12
+
13
+ @click.group()
14
+ def bidmodifiers():
15
+ """Manage bid modifiers"""
16
+ pass
17
+
18
+
19
+ @bidmodifiers.command()
20
+ @click.option("--campaign-ids", help="Comma-separated campaign IDs")
21
+ @click.option("--adgroup-ids", help="Comma-separated ad group IDs")
22
+ @click.option("--limit", type=int, help="Limit number of results")
23
+ @click.option("--fetch-all", is_flag=True, help="Fetch all pages")
24
+ @click.option("--format", "output_format", default="json", help="Output format")
25
+ @click.option("--output", help="Output file")
26
+ @click.pass_context
27
+ def get(ctx, campaign_ids, adgroup_ids, limit, fetch_all, output_format, output):
28
+ """Get bid modifiers"""
29
+ try:
30
+ client = create_client(
31
+ token=ctx.obj.get("token"),
32
+ login=ctx.obj.get("login"),
33
+ sandbox=ctx.obj.get("sandbox"),
34
+ )
35
+
36
+ criteria = {}
37
+ if campaign_ids:
38
+ criteria["CampaignIds"] = parse_ids(campaign_ids)
39
+ if adgroup_ids:
40
+ criteria["AdGroupIds"] = parse_ids(adgroup_ids)
41
+
42
+ params = {
43
+ "SelectionCriteria": criteria,
44
+ "FieldNames": ["Id", "CampaignId", "AdGroupId", "Type", "ModifierValue"],
45
+ }
46
+
47
+ if limit:
48
+ params["Page"] = {"Limit": limit}
49
+
50
+ body = {"method": "get", "params": params}
51
+
52
+ result = client.bidmodifiers().post(data=body)
53
+
54
+ if fetch_all:
55
+ items = []
56
+ for item in result().iter_items():
57
+ items.append(item)
58
+ format_output(items, output_format, output)
59
+ else:
60
+ data = result().extract()
61
+ format_output(data, output_format, output)
62
+
63
+ except Exception as e:
64
+ print_error(str(e))
65
+ raise click.Abort()
66
+
67
+
68
+ @bidmodifiers.command()
69
+ @click.option("--campaign-id", required=True, type=int, help="Campaign ID")
70
+ @click.option(
71
+ "--type",
72
+ "modifier_type",
73
+ required=True,
74
+ help="Modifier type (DEMOGRAPHICS, MOBILE, etc.)",
75
+ )
76
+ @click.option("--value", type=float, required=True, help="Modifier value")
77
+ @click.option("--json", "extra_json", help="Additional JSON parameters")
78
+ @click.option("--dry-run", is_flag=True, help="Show request without sending")
79
+ @click.pass_context
80
+ def set(ctx, campaign_id, modifier_type, value, extra_json, dry_run):
81
+ """Set bid modifier"""
82
+ try:
83
+ modifier_data = {
84
+ "CampaignId": campaign_id,
85
+ "Type": modifier_type,
86
+ "BidModifier": value,
87
+ }
88
+
89
+ if extra_json:
90
+ extra = json.loads(extra_json)
91
+ modifier_data.update(extra)
92
+
93
+ body = {"method": "set", "params": {"BidModifiers": [modifier_data]}}
94
+
95
+ if dry_run:
96
+ format_output(body, "json", None)
97
+ return
98
+
99
+ client = create_client(
100
+ token=ctx.obj.get("token"),
101
+ login=ctx.obj.get("login"),
102
+ sandbox=ctx.obj.get("sandbox"),
103
+ )
104
+
105
+ result = client.bidmodifiers().post(data=body)
106
+ format_output(result().extract(), "json", None)
107
+
108
+ except Exception as e:
109
+ print_error(str(e))
110
+ raise click.Abort()