amazon-sp-cli 0.1.3__tar.gz → 0.1.4__tar.gz
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.
- {amazon_sp_cli-0.1.3/amazon_sp_cli.egg-info → amazon_sp_cli-0.1.4}/PKG-INFO +1 -1
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/amazon_sp_cli/main.py +120 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4/amazon_sp_cli.egg-info}/PKG-INFO +1 -1
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/setup.py +1 -1
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/LICENSE +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/MANIFEST.in +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/README.md +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/amazon_sp_cli/__init__.py +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/amazon_sp_cli/__main__.py +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/amazon_sp_cli/auth.py +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/amazon_sp_cli/client.py +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/amazon_sp_cli.egg-info/SOURCES.txt +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/amazon_sp_cli.egg-info/dependency_links.txt +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/amazon_sp_cli.egg-info/entry_points.txt +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/amazon_sp_cli.egg-info/requires.txt +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/amazon_sp_cli.egg-info/top_level.txt +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/pyproject.toml +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/setup.cfg +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/tests/__init__.py +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/tests/test_auth.py +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/tests/test_client.py +0 -0
- {amazon_sp_cli-0.1.3 → amazon_sp_cli-0.1.4}/tests/test_sale_price.py +0 -0
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
"""Main CLI entry point for Amazon SP-API CLI."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
import os
|
|
4
5
|
from datetime import datetime, timezone
|
|
5
6
|
|
|
6
7
|
import click
|
|
8
|
+
import yaml
|
|
7
9
|
|
|
8
10
|
from .auth import SPAPIAuth
|
|
9
11
|
from .client import SPAPIClient
|
|
10
12
|
|
|
13
|
+
DEFAULT_CREDENTIALS_PATH = os.path.expanduser("~/.config/amazon-sp-cli/credentials.yml")
|
|
14
|
+
|
|
11
15
|
|
|
12
16
|
def _check_path():
|
|
13
17
|
"""Check if the CLI is accessible in PATH and warn once per day."""
|
|
@@ -62,6 +66,122 @@ def cli(ctx, credentials):
|
|
|
62
66
|
ctx.obj["client"] = SPAPIClient(ctx.obj["auth"])
|
|
63
67
|
|
|
64
68
|
|
|
69
|
+
@cli.group()
|
|
70
|
+
def auth():
|
|
71
|
+
"""Authentication commands."""
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@auth.command("setup")
|
|
76
|
+
@click.option("--path", default=DEFAULT_CREDENTIALS_PATH, help="Path to save credentials")
|
|
77
|
+
@click.option("--profile", default="default", help="Credential profile name")
|
|
78
|
+
@click.option("--refresh-token", help="Refresh token")
|
|
79
|
+
@click.option("--client-id", help="Client ID")
|
|
80
|
+
@click.option("--client-secret", help="Client secret")
|
|
81
|
+
@click.option("--aws-access-key-id", help="AWS Access Key ID")
|
|
82
|
+
@click.option("--aws-secret-access-key", help="AWS Secret Access Key")
|
|
83
|
+
@click.option("--seller-id", default="A2GKV2AN9F8YG3", help="Seller ID")
|
|
84
|
+
@click.option("--marketplace-id", default="ATVPDKIKX0DER", help="Marketplace ID")
|
|
85
|
+
@click.pass_context
|
|
86
|
+
def auth_setup(
|
|
87
|
+
ctx,
|
|
88
|
+
path,
|
|
89
|
+
profile,
|
|
90
|
+
refresh_token,
|
|
91
|
+
client_id,
|
|
92
|
+
client_secret,
|
|
93
|
+
aws_access_key_id,
|
|
94
|
+
aws_secret_access_key,
|
|
95
|
+
seller_id,
|
|
96
|
+
marketplace_id,
|
|
97
|
+
):
|
|
98
|
+
"""Set up Amazon SP-API credentials.
|
|
99
|
+
|
|
100
|
+
When flags are omitted, falls back to interactive prompts.
|
|
101
|
+
"""
|
|
102
|
+
click.echo("🔐 Amazon SP-API Credential Setup")
|
|
103
|
+
click.echo("=" * 50)
|
|
104
|
+
click.echo()
|
|
105
|
+
|
|
106
|
+
interactive = not all([refresh_token, client_id, client_secret, aws_access_key_id, aws_secret_access_key])
|
|
107
|
+
if interactive:
|
|
108
|
+
click.echo("You'll need the following from your Amazon Developer account:")
|
|
109
|
+
click.echo(" 1. Refresh Token (from LWA authorization)")
|
|
110
|
+
click.echo(" 2. Client ID (from your app registration)")
|
|
111
|
+
click.echo(" 3. Client Secret (from your app registration)")
|
|
112
|
+
click.echo(" 4. AWS Access Key ID")
|
|
113
|
+
click.echo(" 5. AWS Secret Access Key")
|
|
114
|
+
click.echo()
|
|
115
|
+
|
|
116
|
+
profile = profile or click.prompt("Profile name", default="default")
|
|
117
|
+
refresh_token = refresh_token or click.prompt("Refresh token", hide_input=True)
|
|
118
|
+
client_id = client_id or click.prompt("Client ID")
|
|
119
|
+
client_secret = client_secret or click.prompt("Client secret", hide_input=True)
|
|
120
|
+
aws_access_key_id = aws_access_key_id or click.prompt("AWS Access Key ID")
|
|
121
|
+
aws_secret_access_key = aws_secret_access_key or click.prompt("AWS Secret Access Key", hide_input=True)
|
|
122
|
+
|
|
123
|
+
credentials = {
|
|
124
|
+
"version": "1.0",
|
|
125
|
+
profile: {
|
|
126
|
+
"refresh_token": refresh_token,
|
|
127
|
+
"client_id": client_id,
|
|
128
|
+
"client_secret": client_secret,
|
|
129
|
+
"aws_access_key_id": aws_access_key_id,
|
|
130
|
+
"aws_secret_access_key": aws_secret_access_key,
|
|
131
|
+
"seller_id": seller_id,
|
|
132
|
+
"marketplace_id": marketplace_id,
|
|
133
|
+
},
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# Merge with existing if present
|
|
137
|
+
if os.path.exists(path):
|
|
138
|
+
try:
|
|
139
|
+
with open(path, "r") as f:
|
|
140
|
+
existing = yaml.safe_load(f) or {}
|
|
141
|
+
existing[profile] = credentials[profile]
|
|
142
|
+
credentials = existing
|
|
143
|
+
click.echo(f"\n📝 Merged with existing credentials at {path}")
|
|
144
|
+
except Exception as e:
|
|
145
|
+
click.echo(f"⚠️ Could not read existing file: {e}")
|
|
146
|
+
|
|
147
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
148
|
+
with open(path, "w") as f:
|
|
149
|
+
yaml.dump(credentials, f, default_flow_style=False, sort_keys=False)
|
|
150
|
+
|
|
151
|
+
click.echo(f"✅ Credentials saved to {path}")
|
|
152
|
+
click.echo(f" Profile: {profile}")
|
|
153
|
+
click.echo(f" Seller ID: {seller_id}")
|
|
154
|
+
click.echo(f" Marketplace ID: {marketplace_id}")
|
|
155
|
+
click.echo()
|
|
156
|
+
click.echo("You can now use: python -m amazon_sp_cli.main --profile {profile} get-price <sku>")
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@auth.command("show")
|
|
160
|
+
@click.option("--path", default=DEFAULT_CREDENTIALS_PATH, help="Path to credentials file")
|
|
161
|
+
@click.pass_context
|
|
162
|
+
def auth_show(ctx, path):
|
|
163
|
+
"""Show configured profiles (without secrets)."""
|
|
164
|
+
if not os.path.exists(path):
|
|
165
|
+
click.echo(f"❌ No credentials file found at {path}")
|
|
166
|
+
click.echo("Run: python -m amazon_sp_cli.main auth setup")
|
|
167
|
+
return
|
|
168
|
+
|
|
169
|
+
with open(path, "r") as f:
|
|
170
|
+
creds = yaml.safe_load(f) or {}
|
|
171
|
+
|
|
172
|
+
click.echo(f"\n📄 Credentials file: {path}")
|
|
173
|
+
click.echo("-" * 40)
|
|
174
|
+
|
|
175
|
+
for profile, data in creds.items():
|
|
176
|
+
if profile == "version":
|
|
177
|
+
continue
|
|
178
|
+
click.echo(f"Profile: {profile}")
|
|
179
|
+
click.echo(f" Client ID: {data.get('client_id', 'N/A')[:20]}...")
|
|
180
|
+
click.echo(f" Seller ID: {data.get('seller_id', 'N/A')}")
|
|
181
|
+
click.echo(f" Marketplace ID: {data.get('marketplace_id', 'N/A')}")
|
|
182
|
+
click.echo()
|
|
183
|
+
|
|
184
|
+
|
|
65
185
|
@cli.command()
|
|
66
186
|
@click.argument("sku")
|
|
67
187
|
@click.pass_context
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|