asa-api-cli 0.1.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.
- asa_api_cli/__init__.py +15 -0
- asa_api_cli/ad_groups.py +270 -0
- asa_api_cli/auth.py +186 -0
- asa_api_cli/brand.py +809 -0
- asa_api_cli/campaigns.py +371 -0
- asa_api_cli/keywords.py +514 -0
- asa_api_cli/main.py +76 -0
- asa_api_cli/optimize.py +961 -0
- asa_api_cli/reports.py +440 -0
- asa_api_cli/utils.py +503 -0
- asa_api_cli-0.1.0.dist-info/METADATA +196 -0
- asa_api_cli-0.1.0.dist-info/RECORD +15 -0
- asa_api_cli-0.1.0.dist-info/WHEEL +4 -0
- asa_api_cli-0.1.0.dist-info/entry_points.txt +2 -0
- asa_api_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
asa_api_cli/__init__.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Command-line interface for Apple Search Ads.
|
|
2
|
+
|
|
3
|
+
This module provides a CLI for interacting with the Apple Search Ads API.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
asa --help
|
|
7
|
+
asa campaigns list
|
|
8
|
+
asa reports campaigns --start 2024-01-01 --end 2024-01-31
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from asa_api_cli.main import app
|
|
12
|
+
|
|
13
|
+
__all__ = ["app"]
|
|
14
|
+
|
|
15
|
+
__version__ = "0.1.0"
|
asa_api_cli/ad_groups.py
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""Ad Group CLI commands."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated, Any
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from asa_api_client.exceptions import AppleSearchAdsError
|
|
7
|
+
from asa_api_client.models import AdGroupStatus, AdGroupUpdate, Money, Selector
|
|
8
|
+
|
|
9
|
+
from asa_api_cli.utils import (
|
|
10
|
+
OutputFormat,
|
|
11
|
+
confirm_action,
|
|
12
|
+
enum_value,
|
|
13
|
+
format_money,
|
|
14
|
+
get_client,
|
|
15
|
+
handle_api_error,
|
|
16
|
+
output_data,
|
|
17
|
+
print_json,
|
|
18
|
+
print_result_panel,
|
|
19
|
+
print_success,
|
|
20
|
+
print_warning,
|
|
21
|
+
spinner,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
app = typer.Typer(help="Manage ad groups")
|
|
25
|
+
|
|
26
|
+
AD_GROUP_COLUMNS = [
|
|
27
|
+
"id",
|
|
28
|
+
"name",
|
|
29
|
+
"status",
|
|
30
|
+
"serving_status",
|
|
31
|
+
"default_bid",
|
|
32
|
+
"search_match",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
AD_GROUP_COLUMN_LABELS = {
|
|
36
|
+
"id": "ID",
|
|
37
|
+
"serving_status": "Serving",
|
|
38
|
+
"default_bid": "Default Bid",
|
|
39
|
+
"search_match": "Search Match",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def ad_group_to_dict(ad_group: object) -> dict[str, Any]:
|
|
44
|
+
"""Convert ad group to display dictionary."""
|
|
45
|
+
return {
|
|
46
|
+
"id": ad_group.id, # type: ignore
|
|
47
|
+
"name": ad_group.name, # type: ignore
|
|
48
|
+
"status": enum_value(ad_group.status), # type: ignore
|
|
49
|
+
"serving_status": enum_value(ad_group.serving_status), # type: ignore
|
|
50
|
+
"default_bid": format_money(
|
|
51
|
+
ad_group.default_bid_amount.amount, # type: ignore
|
|
52
|
+
ad_group.default_bid_amount.currency, # type: ignore
|
|
53
|
+
),
|
|
54
|
+
"search_match": enum_value(ad_group.automated_keywords_opt_in), # type: ignore
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@app.command("list")
|
|
59
|
+
def list_ad_groups(
|
|
60
|
+
campaign_id: Annotated[int, typer.Argument(help="Campaign ID")],
|
|
61
|
+
status: Annotated[
|
|
62
|
+
AdGroupStatus | None,
|
|
63
|
+
typer.Option("--status", "-s", help="Filter by status"),
|
|
64
|
+
] = None,
|
|
65
|
+
limit: Annotated[
|
|
66
|
+
int,
|
|
67
|
+
typer.Option("--limit", "-l", help="Maximum number of results"),
|
|
68
|
+
] = 100,
|
|
69
|
+
format: Annotated[
|
|
70
|
+
OutputFormat,
|
|
71
|
+
typer.Option("--format", "-f", help="Output format"),
|
|
72
|
+
] = OutputFormat.TABLE,
|
|
73
|
+
) -> None:
|
|
74
|
+
"""List ad groups in a campaign.
|
|
75
|
+
|
|
76
|
+
Examples:
|
|
77
|
+
asa ad-groups list 123456789
|
|
78
|
+
asa ad-groups list 123456789 --status ENABLED
|
|
79
|
+
asa ad-groups list 123456789 --format json
|
|
80
|
+
"""
|
|
81
|
+
client = get_client()
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
with client:
|
|
85
|
+
with spinner("Fetching ad groups..."):
|
|
86
|
+
if status:
|
|
87
|
+
selector = Selector().where("status", "==", status.value).limit(limit)
|
|
88
|
+
ad_groups = client.campaigns(campaign_id).ad_groups.find(selector)
|
|
89
|
+
else:
|
|
90
|
+
ad_groups = client.campaigns(campaign_id).ad_groups.list(limit=limit)
|
|
91
|
+
|
|
92
|
+
if not ad_groups.data:
|
|
93
|
+
print_warning("No ad groups found")
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
data = [ad_group_to_dict(ag) for ag in ad_groups]
|
|
97
|
+
output_data(
|
|
98
|
+
data,
|
|
99
|
+
AD_GROUP_COLUMNS,
|
|
100
|
+
format,
|
|
101
|
+
title=f"Ad Groups ({ad_groups.total_results} total)",
|
|
102
|
+
column_labels=AD_GROUP_COLUMN_LABELS,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
except AppleSearchAdsError as e:
|
|
106
|
+
handle_api_error(e)
|
|
107
|
+
raise typer.Exit(1) from None
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@app.command("get")
|
|
111
|
+
def get_ad_group(
|
|
112
|
+
campaign_id: Annotated[int, typer.Argument(help="Campaign ID")],
|
|
113
|
+
ad_group_id: Annotated[int, typer.Argument(help="Ad Group ID")],
|
|
114
|
+
format: Annotated[
|
|
115
|
+
OutputFormat,
|
|
116
|
+
typer.Option("--format", "-f", help="Output format"),
|
|
117
|
+
] = OutputFormat.JSON,
|
|
118
|
+
) -> None:
|
|
119
|
+
"""Get details for a specific ad group.
|
|
120
|
+
|
|
121
|
+
Examples:
|
|
122
|
+
asa ad-groups get 123456789 987654321
|
|
123
|
+
asa ad-groups get 123456789 987654321 --format table
|
|
124
|
+
"""
|
|
125
|
+
client = get_client()
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
with client:
|
|
129
|
+
with spinner("Fetching ad group..."):
|
|
130
|
+
ad_group = client.campaigns(campaign_id).ad_groups.get(ad_group_id)
|
|
131
|
+
|
|
132
|
+
if format == OutputFormat.JSON:
|
|
133
|
+
print_json(ad_group, title=f"Ad Group {ad_group_id}")
|
|
134
|
+
else:
|
|
135
|
+
data = [ad_group_to_dict(ad_group)]
|
|
136
|
+
output_data(data, AD_GROUP_COLUMNS, format, column_labels=AD_GROUP_COLUMN_LABELS)
|
|
137
|
+
|
|
138
|
+
except AppleSearchAdsError as e:
|
|
139
|
+
handle_api_error(e)
|
|
140
|
+
raise typer.Exit(1) from None
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@app.command("pause")
|
|
144
|
+
def pause_ad_group(
|
|
145
|
+
campaign_id: Annotated[int, typer.Argument(help="Campaign ID")],
|
|
146
|
+
ad_group_id: Annotated[int, typer.Argument(help="Ad Group ID to pause")],
|
|
147
|
+
) -> None:
|
|
148
|
+
"""Pause an ad group.
|
|
149
|
+
|
|
150
|
+
Examples:
|
|
151
|
+
asa ad-groups pause 123456789 987654321
|
|
152
|
+
"""
|
|
153
|
+
client = get_client()
|
|
154
|
+
|
|
155
|
+
try:
|
|
156
|
+
with client:
|
|
157
|
+
with spinner("Pausing ad group..."):
|
|
158
|
+
ad_group = client.campaigns(campaign_id).ad_groups.update(
|
|
159
|
+
ad_group_id,
|
|
160
|
+
data=AdGroupUpdate(status=AdGroupStatus.PAUSED),
|
|
161
|
+
)
|
|
162
|
+
print_success(f"Ad group '{ad_group.name}' paused")
|
|
163
|
+
|
|
164
|
+
except AppleSearchAdsError as e:
|
|
165
|
+
handle_api_error(e)
|
|
166
|
+
raise typer.Exit(1) from None
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
@app.command("enable")
|
|
170
|
+
def enable_ad_group(
|
|
171
|
+
campaign_id: Annotated[int, typer.Argument(help="Campaign ID")],
|
|
172
|
+
ad_group_id: Annotated[int, typer.Argument(help="Ad Group ID to enable")],
|
|
173
|
+
) -> None:
|
|
174
|
+
"""Enable a paused ad group.
|
|
175
|
+
|
|
176
|
+
Examples:
|
|
177
|
+
asa ad-groups enable 123456789 987654321
|
|
178
|
+
"""
|
|
179
|
+
client = get_client()
|
|
180
|
+
|
|
181
|
+
try:
|
|
182
|
+
with client:
|
|
183
|
+
with spinner("Enabling ad group..."):
|
|
184
|
+
ad_group = client.campaigns(campaign_id).ad_groups.update(
|
|
185
|
+
ad_group_id,
|
|
186
|
+
data=AdGroupUpdate(status=AdGroupStatus.ENABLED),
|
|
187
|
+
)
|
|
188
|
+
print_success(f"Ad group '{ad_group.name}' enabled")
|
|
189
|
+
|
|
190
|
+
except AppleSearchAdsError as e:
|
|
191
|
+
handle_api_error(e)
|
|
192
|
+
raise typer.Exit(1) from None
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@app.command("set-bid")
|
|
196
|
+
def set_default_bid(
|
|
197
|
+
campaign_id: Annotated[int, typer.Argument(help="Campaign ID")],
|
|
198
|
+
ad_group_id: Annotated[int, typer.Argument(help="Ad Group ID")],
|
|
199
|
+
bid: Annotated[float, typer.Argument(help="New default bid amount")],
|
|
200
|
+
currency: Annotated[
|
|
201
|
+
str,
|
|
202
|
+
typer.Option("--currency", "-c", help="Currency code"),
|
|
203
|
+
] = "USD",
|
|
204
|
+
) -> None:
|
|
205
|
+
"""Set the default bid for an ad group.
|
|
206
|
+
|
|
207
|
+
Examples:
|
|
208
|
+
asa ad-groups set-bid 123456789 987654321 2.50
|
|
209
|
+
asa ad-groups set-bid 123456789 987654321 2.50 --currency EUR
|
|
210
|
+
"""
|
|
211
|
+
client = get_client()
|
|
212
|
+
|
|
213
|
+
try:
|
|
214
|
+
with client:
|
|
215
|
+
with spinner("Updating default bid..."):
|
|
216
|
+
ad_group = client.campaigns(campaign_id).ad_groups.update(
|
|
217
|
+
ad_group_id,
|
|
218
|
+
data=AdGroupUpdate(default_bid_amount=Money(amount=str(bid), currency=currency)),
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
print_result_panel(
|
|
222
|
+
"Default Bid Updated",
|
|
223
|
+
{
|
|
224
|
+
"Ad Group": ad_group.name,
|
|
225
|
+
"Default Bid": f"{ad_group.default_bid_amount.amount} {ad_group.default_bid_amount.currency}",
|
|
226
|
+
},
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
except AppleSearchAdsError as e:
|
|
230
|
+
handle_api_error(e)
|
|
231
|
+
raise typer.Exit(1) from None
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@app.command("delete")
|
|
235
|
+
def delete_ad_group(
|
|
236
|
+
campaign_id: Annotated[int, typer.Argument(help="Campaign ID")],
|
|
237
|
+
ad_group_id: Annotated[int, typer.Argument(help="Ad Group ID to delete")],
|
|
238
|
+
force: Annotated[
|
|
239
|
+
bool,
|
|
240
|
+
typer.Option("--force", "-f", help="Skip confirmation"),
|
|
241
|
+
] = False,
|
|
242
|
+
) -> None:
|
|
243
|
+
"""Delete an ad group.
|
|
244
|
+
|
|
245
|
+
WARNING: This action cannot be undone.
|
|
246
|
+
|
|
247
|
+
Examples:
|
|
248
|
+
asa ad-groups delete 123456789 987654321
|
|
249
|
+
asa ad-groups delete 123456789 987654321 --force
|
|
250
|
+
"""
|
|
251
|
+
client = get_client()
|
|
252
|
+
|
|
253
|
+
try:
|
|
254
|
+
with client:
|
|
255
|
+
with spinner("Fetching ad group..."):
|
|
256
|
+
ad_group = client.campaigns(campaign_id).ad_groups.get(ad_group_id)
|
|
257
|
+
|
|
258
|
+
if not force:
|
|
259
|
+
if not confirm_action(f"Are you sure you want to delete ad group '{ad_group.name}'?"):
|
|
260
|
+
print_warning("Cancelled")
|
|
261
|
+
raise typer.Exit(0)
|
|
262
|
+
|
|
263
|
+
with spinner("Deleting ad group..."):
|
|
264
|
+
client.campaigns(campaign_id).ad_groups.delete(ad_group_id)
|
|
265
|
+
|
|
266
|
+
print_success(f"Ad group '{ad_group.name}' deleted")
|
|
267
|
+
|
|
268
|
+
except AppleSearchAdsError as e:
|
|
269
|
+
handle_api_error(e)
|
|
270
|
+
raise typer.Exit(1) from None
|
asa_api_cli/auth.py
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""Authentication CLI commands."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
from asa_api_client import AppleSearchAdsClient, Settings
|
|
8
|
+
from asa_api_client.exceptions import AppleSearchAdsError, ConfigurationError
|
|
9
|
+
from pydantic import ValidationError
|
|
10
|
+
from rich.table import Table
|
|
11
|
+
|
|
12
|
+
from asa_api_cli.utils import (
|
|
13
|
+
console,
|
|
14
|
+
print_error,
|
|
15
|
+
print_info,
|
|
16
|
+
print_result_panel,
|
|
17
|
+
spinner,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
app = typer.Typer(help="Authentication commands")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@app.command("test")
|
|
24
|
+
def test_auth(
|
|
25
|
+
env_file: Annotated[
|
|
26
|
+
Path | None,
|
|
27
|
+
typer.Option("--env-file", "-e", help="Path to .env file"),
|
|
28
|
+
] = Path(".env"),
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Test authentication credentials.
|
|
31
|
+
|
|
32
|
+
Loads configuration from environment variables and .env file,
|
|
33
|
+
then attempts to authenticate with the Apple Search Ads API.
|
|
34
|
+
|
|
35
|
+
Examples:
|
|
36
|
+
asa auth test
|
|
37
|
+
asa auth test --env-file .env.production
|
|
38
|
+
"""
|
|
39
|
+
print_info("Testing Apple Search Ads API credentials...")
|
|
40
|
+
console.print()
|
|
41
|
+
|
|
42
|
+
# Try to load settings
|
|
43
|
+
try:
|
|
44
|
+
if env_file and env_file.exists():
|
|
45
|
+
settings = Settings(_env_file=env_file) # type: ignore[call-arg]
|
|
46
|
+
print_info(f"Loaded configuration from {env_file}")
|
|
47
|
+
else:
|
|
48
|
+
settings = Settings(_env_file=None) # type: ignore[call-arg]
|
|
49
|
+
if env_file:
|
|
50
|
+
print_info("No .env file found, using environment variables only")
|
|
51
|
+
except ValidationError as e:
|
|
52
|
+
# Show what's missing
|
|
53
|
+
table = Table(
|
|
54
|
+
title="Configuration Status",
|
|
55
|
+
show_header=True,
|
|
56
|
+
header_style="header",
|
|
57
|
+
border_style="muted",
|
|
58
|
+
)
|
|
59
|
+
table.add_column("Setting", style="label")
|
|
60
|
+
table.add_column("Status")
|
|
61
|
+
|
|
62
|
+
errors_by_field = {err["loc"][0]: err["msg"] for err in e.errors()}
|
|
63
|
+
|
|
64
|
+
for field in ["client_id", "team_id", "key_id", "org_id", "private_key", "private_key_path"]:
|
|
65
|
+
if field in errors_by_field:
|
|
66
|
+
table.add_row(f"ASA_{field.upper()}", f"[error]{errors_by_field[field]}[/error]")
|
|
67
|
+
else:
|
|
68
|
+
table.add_row(f"ASA_{field.upper()}", "[success]OK[/success]")
|
|
69
|
+
|
|
70
|
+
console.print(table)
|
|
71
|
+
console.print()
|
|
72
|
+
print_error("Configuration Error", "Missing or invalid settings")
|
|
73
|
+
raise typer.Exit(1) from None
|
|
74
|
+
|
|
75
|
+
# Display loaded configuration
|
|
76
|
+
table = Table(
|
|
77
|
+
title="Configuration",
|
|
78
|
+
show_header=True,
|
|
79
|
+
header_style="header",
|
|
80
|
+
border_style="muted",
|
|
81
|
+
)
|
|
82
|
+
table.add_column("Setting", style="label")
|
|
83
|
+
table.add_column("Value")
|
|
84
|
+
|
|
85
|
+
# Mask client_id
|
|
86
|
+
client_id_display = settings.client_id[:20] + "..." if len(settings.client_id) > 20 else settings.client_id
|
|
87
|
+
table.add_row("ASA_CLIENT_ID", f"[success]{client_id_display}[/success]")
|
|
88
|
+
table.add_row("ASA_TEAM_ID", f"[success]{settings.team_id}[/success]")
|
|
89
|
+
table.add_row("ASA_KEY_ID", f"[success]{settings.key_id}[/success]")
|
|
90
|
+
table.add_row("ASA_ORG_ID", f"[success]{settings.org_id}[/success]")
|
|
91
|
+
|
|
92
|
+
if settings.private_key_path:
|
|
93
|
+
table.add_row("ASA_PRIVATE_KEY_PATH", f"[success]{settings.private_key_path}[/success]")
|
|
94
|
+
if settings.private_key:
|
|
95
|
+
table.add_row("ASA_PRIVATE_KEY", "[success]<set>[/success]")
|
|
96
|
+
|
|
97
|
+
console.print(table)
|
|
98
|
+
console.print()
|
|
99
|
+
|
|
100
|
+
# Try to authenticate
|
|
101
|
+
print_info("Attempting to authenticate...")
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
client = AppleSearchAdsClient.from_env(env_file=env_file)
|
|
105
|
+
except ConfigurationError as e:
|
|
106
|
+
print_error("Configuration Error", e.message)
|
|
107
|
+
raise typer.Exit(1) from None
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
# Try to list campaigns to verify authentication works
|
|
111
|
+
with client:
|
|
112
|
+
with spinner("Authenticating with Apple Search Ads API..."):
|
|
113
|
+
campaigns = client.campaigns.list(limit=1)
|
|
114
|
+
|
|
115
|
+
print_result_panel(
|
|
116
|
+
"Authentication Successful",
|
|
117
|
+
{
|
|
118
|
+
"Organization ID": str(client.org_id),
|
|
119
|
+
"Total Campaigns": str(campaigns.total_results),
|
|
120
|
+
},
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
except AppleSearchAdsError as e:
|
|
124
|
+
print_error("API Error", e.message, f"Status code: {e.status_code}" if e.status_code else None)
|
|
125
|
+
raise typer.Exit(1) from None
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@app.command("show")
|
|
129
|
+
def show_config(
|
|
130
|
+
env_file: Annotated[
|
|
131
|
+
Path | None,
|
|
132
|
+
typer.Option("--env-file", "-e", help="Path to .env file"),
|
|
133
|
+
] = Path(".env"),
|
|
134
|
+
) -> None:
|
|
135
|
+
"""Show current authentication configuration.
|
|
136
|
+
|
|
137
|
+
Displays configuration loaded from environment variables and .env file.
|
|
138
|
+
|
|
139
|
+
Examples:
|
|
140
|
+
asa auth show
|
|
141
|
+
asa auth show --env-file .env.production
|
|
142
|
+
"""
|
|
143
|
+
# Try to load settings
|
|
144
|
+
try:
|
|
145
|
+
if env_file and env_file.exists():
|
|
146
|
+
settings = Settings(_env_file=env_file) # type: ignore[call-arg]
|
|
147
|
+
source = f"from {env_file}"
|
|
148
|
+
else:
|
|
149
|
+
settings = Settings(_env_file=None) # type: ignore[call-arg]
|
|
150
|
+
source = "from environment variables"
|
|
151
|
+
|
|
152
|
+
table = Table(
|
|
153
|
+
title=f"Current Configuration ({source})",
|
|
154
|
+
show_header=True,
|
|
155
|
+
header_style="header",
|
|
156
|
+
border_style="muted",
|
|
157
|
+
)
|
|
158
|
+
table.add_column("Setting", style="label")
|
|
159
|
+
table.add_column("Value")
|
|
160
|
+
|
|
161
|
+
# Mask client_id partially
|
|
162
|
+
client_id_display = settings.client_id[:20] + "..." if len(settings.client_id) > 20 else settings.client_id
|
|
163
|
+
table.add_row("ASA_CLIENT_ID", client_id_display)
|
|
164
|
+
table.add_row("ASA_TEAM_ID", settings.team_id)
|
|
165
|
+
table.add_row("ASA_KEY_ID", settings.key_id)
|
|
166
|
+
table.add_row("ASA_ORG_ID", str(settings.org_id))
|
|
167
|
+
|
|
168
|
+
if settings.private_key_path:
|
|
169
|
+
table.add_row("ASA_PRIVATE_KEY_PATH", str(settings.private_key_path))
|
|
170
|
+
else:
|
|
171
|
+
table.add_row("ASA_PRIVATE_KEY_PATH", "[muted]<not set>[/muted]")
|
|
172
|
+
|
|
173
|
+
if settings.private_key:
|
|
174
|
+
table.add_row("ASA_PRIVATE_KEY", "[success]<set>[/success]")
|
|
175
|
+
else:
|
|
176
|
+
table.add_row("ASA_PRIVATE_KEY", "[muted]<not set>[/muted]")
|
|
177
|
+
|
|
178
|
+
console.print(table)
|
|
179
|
+
|
|
180
|
+
except ValidationError as e:
|
|
181
|
+
print_error("Configuration Error", "Could not load settings")
|
|
182
|
+
for err in e.errors():
|
|
183
|
+
field = err["loc"][0]
|
|
184
|
+
msg = err["msg"]
|
|
185
|
+
console.print(f" [error]ASA_{str(field).upper()}:[/error] {msg}")
|
|
186
|
+
raise typer.Exit(1) from None
|