unitysvc-services 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.
- unitysvc_services/__init__.py +4 -0
- unitysvc_services/cli.py +21 -0
- unitysvc_services/format_data.py +145 -0
- unitysvc_services/list.py +245 -0
- unitysvc_services/models/__init__.py +6 -0
- unitysvc_services/models/base.py +352 -0
- unitysvc_services/models/listing_v1.py +72 -0
- unitysvc_services/models/provider_v1.py +53 -0
- unitysvc_services/models/seller_v1.py +110 -0
- unitysvc_services/models/service_v1.py +80 -0
- unitysvc_services/populate.py +186 -0
- unitysvc_services/publisher.py +925 -0
- unitysvc_services/query.py +471 -0
- unitysvc_services/scaffold.py +1039 -0
- unitysvc_services/update.py +293 -0
- unitysvc_services/utils.py +240 -0
- unitysvc_services/validator.py +515 -0
- unitysvc_services-0.1.0.dist-info/METADATA +172 -0
- unitysvc_services-0.1.0.dist-info/RECORD +23 -0
- unitysvc_services-0.1.0.dist-info/WHEEL +5 -0
- unitysvc_services-0.1.0.dist-info/entry_points.txt +2 -0
- unitysvc_services-0.1.0.dist-info/licenses/LICENSE +21 -0
- unitysvc_services-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,471 @@
|
|
1
|
+
"""Query command group - query backend API for data."""
|
2
|
+
|
3
|
+
import json
|
4
|
+
import os
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
import httpx
|
8
|
+
import typer
|
9
|
+
from rich.console import Console
|
10
|
+
from rich.table import Table
|
11
|
+
|
12
|
+
app = typer.Typer(help="Query backend API for data")
|
13
|
+
console = Console()
|
14
|
+
|
15
|
+
|
16
|
+
class ServiceDataQuery:
|
17
|
+
"""Query service data from UnitySVC backend endpoints."""
|
18
|
+
|
19
|
+
def __init__(self, base_url: str, api_key: str):
|
20
|
+
"""Initialize query client with backend URL and API key.
|
21
|
+
|
22
|
+
Args:
|
23
|
+
base_url: UnitySVC backend URL
|
24
|
+
api_key: API key for authentication
|
25
|
+
|
26
|
+
Raises:
|
27
|
+
ValueError: If base_url or api_key is not provided
|
28
|
+
"""
|
29
|
+
if not base_url:
|
30
|
+
raise ValueError(
|
31
|
+
"Backend URL not provided. Use --backend-url or set UNITYSVC_BACKEND_URL env var."
|
32
|
+
)
|
33
|
+
if not api_key:
|
34
|
+
raise ValueError("API key not provided. Use --api-key or set UNITYSVC_API_KEY env var.")
|
35
|
+
|
36
|
+
self.base_url = base_url.rstrip("/")
|
37
|
+
self.api_key = api_key
|
38
|
+
self.client = httpx.Client(
|
39
|
+
headers={
|
40
|
+
"X-API-Key": api_key,
|
41
|
+
"Content-Type": "application/json",
|
42
|
+
},
|
43
|
+
timeout=30.0,
|
44
|
+
)
|
45
|
+
|
46
|
+
def list_service_offerings(self) -> list[dict[str, Any]]:
|
47
|
+
"""List all service offerings from the backend."""
|
48
|
+
response = self.client.get(f"{self.base_url}/publish/service_offering")
|
49
|
+
response.raise_for_status()
|
50
|
+
result = response.json()
|
51
|
+
return result.get("data", result) if isinstance(result, dict) else result
|
52
|
+
|
53
|
+
def list_service_listings(self) -> list[dict[str, Any]]:
|
54
|
+
"""List all service listings from the backend."""
|
55
|
+
response = self.client.get(f"{self.base_url}/services/")
|
56
|
+
response.raise_for_status()
|
57
|
+
result = response.json()
|
58
|
+
return result.get("data", result) if isinstance(result, dict) else result
|
59
|
+
|
60
|
+
def list_providers(self) -> list[dict[str, Any]]:
|
61
|
+
"""List all providers from the backend."""
|
62
|
+
response = self.client.get(f"{self.base_url}/providers/")
|
63
|
+
response.raise_for_status()
|
64
|
+
result = response.json()
|
65
|
+
return result.get("data", result) if isinstance(result, dict) else result
|
66
|
+
|
67
|
+
def list_sellers(self) -> list[dict[str, Any]]:
|
68
|
+
"""List all sellers from the backend."""
|
69
|
+
response = self.client.get(f"{self.base_url}/sellers/")
|
70
|
+
response.raise_for_status()
|
71
|
+
result = response.json()
|
72
|
+
return result.get("data", result) if isinstance(result, dict) else result
|
73
|
+
|
74
|
+
def list_access_interfaces(self) -> dict[str, Any]:
|
75
|
+
"""List all access interfaces from the backend (private endpoint)."""
|
76
|
+
response = self.client.get(f"{self.base_url}/private/access_interfaces")
|
77
|
+
response.raise_for_status()
|
78
|
+
return response.json()
|
79
|
+
|
80
|
+
def list_documents(self) -> dict[str, Any]:
|
81
|
+
"""List all documents from the backend (private endpoint)."""
|
82
|
+
response = self.client.get(f"{self.base_url}/private/documents")
|
83
|
+
response.raise_for_status()
|
84
|
+
return response.json()
|
85
|
+
|
86
|
+
def close(self):
|
87
|
+
"""Close the HTTP client."""
|
88
|
+
self.client.close()
|
89
|
+
|
90
|
+
def __enter__(self):
|
91
|
+
"""Context manager entry."""
|
92
|
+
return self
|
93
|
+
|
94
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
95
|
+
"""Context manager exit."""
|
96
|
+
self.close()
|
97
|
+
|
98
|
+
@staticmethod
|
99
|
+
def from_env(
|
100
|
+
backend_url: str | None = None, api_key: str | None = None
|
101
|
+
) -> "ServiceDataQuery":
|
102
|
+
"""Create ServiceDataQuery from environment variables or arguments.
|
103
|
+
|
104
|
+
Args:
|
105
|
+
backend_url: Optional backend URL (falls back to UNITYSVC_BACKEND_URL env var)
|
106
|
+
api_key: Optional API key (falls back to UNITYSVC_API_KEY env var)
|
107
|
+
|
108
|
+
Returns:
|
109
|
+
ServiceDataQuery instance
|
110
|
+
|
111
|
+
Raises:
|
112
|
+
ValueError: If required credentials are not provided
|
113
|
+
"""
|
114
|
+
resolved_backend_url = backend_url or os.getenv("UNITYSVC_BACKEND_URL") or ""
|
115
|
+
resolved_api_key = api_key or os.getenv("UNITYSVC_API_KEY") or ""
|
116
|
+
return ServiceDataQuery(base_url=resolved_backend_url, api_key=resolved_api_key)
|
117
|
+
|
118
|
+
|
119
|
+
@app.command("sellers")
|
120
|
+
def query_sellers(
|
121
|
+
backend_url: str | None = typer.Option(
|
122
|
+
None,
|
123
|
+
"--backend-url",
|
124
|
+
"-u",
|
125
|
+
help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
|
126
|
+
),
|
127
|
+
api_key: str | None = typer.Option(
|
128
|
+
None,
|
129
|
+
"--api-key",
|
130
|
+
"-k",
|
131
|
+
help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
|
132
|
+
),
|
133
|
+
format: str = typer.Option(
|
134
|
+
"table",
|
135
|
+
"--format",
|
136
|
+
"-f",
|
137
|
+
help="Output format: table, json",
|
138
|
+
),
|
139
|
+
):
|
140
|
+
"""Query all sellers from the backend."""
|
141
|
+
try:
|
142
|
+
with ServiceDataQuery.from_env(backend_url, api_key) as query:
|
143
|
+
sellers = query.list_sellers()
|
144
|
+
|
145
|
+
if format == "json":
|
146
|
+
console.print(json.dumps(sellers, indent=2))
|
147
|
+
else:
|
148
|
+
if not sellers:
|
149
|
+
console.print("[yellow]No sellers found.[/yellow]")
|
150
|
+
else:
|
151
|
+
table = Table(title="Sellers")
|
152
|
+
table.add_column("ID", style="cyan")
|
153
|
+
table.add_column("Name", style="green")
|
154
|
+
table.add_column("Display Name", style="blue")
|
155
|
+
table.add_column("Type", style="magenta")
|
156
|
+
table.add_column("Contact Email", style="yellow")
|
157
|
+
table.add_column("Active", style="white")
|
158
|
+
|
159
|
+
for seller in sellers:
|
160
|
+
table.add_row(
|
161
|
+
str(seller.get("id", "N/A")),
|
162
|
+
seller.get("name", "N/A"),
|
163
|
+
seller.get("display_name", "N/A"),
|
164
|
+
seller.get("seller_type", "N/A"),
|
165
|
+
seller.get("contact_email", "N/A"),
|
166
|
+
"✓" if seller.get("is_active") else "✗",
|
167
|
+
)
|
168
|
+
|
169
|
+
console.print(table)
|
170
|
+
except ValueError as e:
|
171
|
+
console.print(f"[red]✗[/red] {e}", style="bold red")
|
172
|
+
raise typer.Exit(code=1)
|
173
|
+
except Exception as e:
|
174
|
+
console.print(f"[red]✗[/red] Failed to query sellers: {e}", style="bold red")
|
175
|
+
raise typer.Exit(code=1)
|
176
|
+
|
177
|
+
|
178
|
+
@app.command("providers")
|
179
|
+
def query_providers(
|
180
|
+
backend_url: str | None = typer.Option(
|
181
|
+
None,
|
182
|
+
"--backend-url",
|
183
|
+
"-u",
|
184
|
+
help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
|
185
|
+
),
|
186
|
+
api_key: str | None = typer.Option(
|
187
|
+
None,
|
188
|
+
"--api-key",
|
189
|
+
"-k",
|
190
|
+
help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
|
191
|
+
),
|
192
|
+
format: str = typer.Option(
|
193
|
+
"table",
|
194
|
+
"--format",
|
195
|
+
"-f",
|
196
|
+
help="Output format: table, json",
|
197
|
+
),
|
198
|
+
):
|
199
|
+
"""Query all providers from the backend."""
|
200
|
+
try:
|
201
|
+
with ServiceDataQuery.from_env(backend_url, api_key) as query:
|
202
|
+
providers = query.list_providers()
|
203
|
+
|
204
|
+
if format == "json":
|
205
|
+
console.print(json.dumps(providers, indent=2))
|
206
|
+
else:
|
207
|
+
if not providers:
|
208
|
+
console.print("[yellow]No providers found.[/yellow]")
|
209
|
+
else:
|
210
|
+
table = Table(title="Providers")
|
211
|
+
table.add_column("ID", style="cyan")
|
212
|
+
table.add_column("Name", style="green")
|
213
|
+
table.add_column("Display Name", style="blue")
|
214
|
+
table.add_column("Time Created", style="magenta")
|
215
|
+
|
216
|
+
for provider in providers:
|
217
|
+
table.add_row(
|
218
|
+
str(provider.get("id", "N/A")),
|
219
|
+
provider.get("name", "N/A"),
|
220
|
+
provider.get("display_name", "N/A"),
|
221
|
+
str(provider.get("time_created", "N/A")),
|
222
|
+
)
|
223
|
+
|
224
|
+
console.print(table)
|
225
|
+
except ValueError as e:
|
226
|
+
console.print(f"[red]✗[/red] {e}", style="bold red")
|
227
|
+
raise typer.Exit(code=1)
|
228
|
+
except Exception as e:
|
229
|
+
console.print(f"[red]✗[/red] Failed to query providers: {e}", style="bold red")
|
230
|
+
raise typer.Exit(code=1)
|
231
|
+
|
232
|
+
|
233
|
+
@app.command("offerings")
|
234
|
+
def query_offerings(
|
235
|
+
backend_url: str | None = typer.Option(
|
236
|
+
None,
|
237
|
+
"--backend-url",
|
238
|
+
"-u",
|
239
|
+
help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
|
240
|
+
),
|
241
|
+
api_key: str | None = typer.Option(
|
242
|
+
None,
|
243
|
+
"--api-key",
|
244
|
+
"-k",
|
245
|
+
help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
|
246
|
+
),
|
247
|
+
format: str = typer.Option(
|
248
|
+
"table",
|
249
|
+
"--format",
|
250
|
+
"-f",
|
251
|
+
help="Output format: table, json",
|
252
|
+
),
|
253
|
+
):
|
254
|
+
"""Query all service offerings from UnitySVC backend."""
|
255
|
+
try:
|
256
|
+
with ServiceDataQuery.from_env(backend_url, api_key) as query:
|
257
|
+
offerings = query.list_service_offerings()
|
258
|
+
|
259
|
+
if format == "json":
|
260
|
+
console.print(json.dumps(offerings, indent=2))
|
261
|
+
else:
|
262
|
+
if not offerings:
|
263
|
+
console.print("[yellow]No service offerings found.[/yellow]")
|
264
|
+
else:
|
265
|
+
table = Table(title="Service Offerings", show_lines=True)
|
266
|
+
table.add_column("ID", style="cyan")
|
267
|
+
table.add_column("Name", style="green")
|
268
|
+
table.add_column("Display Name", style="blue")
|
269
|
+
table.add_column("Type", style="magenta")
|
270
|
+
table.add_column("Status", style="yellow")
|
271
|
+
table.add_column("Version")
|
272
|
+
|
273
|
+
for offering in offerings:
|
274
|
+
table.add_row(
|
275
|
+
str(offering.get("id", "N/A")),
|
276
|
+
offering.get("name", "N/A"),
|
277
|
+
offering.get("display_name", "N/A"),
|
278
|
+
offering.get("service_type", "N/A"),
|
279
|
+
offering.get("upstream_status", "N/A"),
|
280
|
+
offering.get("version", "N/A"),
|
281
|
+
)
|
282
|
+
|
283
|
+
console.print(table)
|
284
|
+
console.print(f"\n[green]Total:[/green] {len(offerings)} service offering(s)")
|
285
|
+
except ValueError as e:
|
286
|
+
console.print(f"[red]✗[/red] {e}", style="bold red")
|
287
|
+
raise typer.Exit(code=1)
|
288
|
+
except Exception as e:
|
289
|
+
console.print(f"[red]✗[/red] Failed to query service offerings: {e}", style="bold red")
|
290
|
+
raise typer.Exit(code=1)
|
291
|
+
|
292
|
+
|
293
|
+
@app.command("listings")
|
294
|
+
def query_listings(
|
295
|
+
backend_url: str | None = typer.Option(
|
296
|
+
None,
|
297
|
+
"--backend-url",
|
298
|
+
"-u",
|
299
|
+
help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
|
300
|
+
),
|
301
|
+
api_key: str | None = typer.Option(
|
302
|
+
None,
|
303
|
+
"--api-key",
|
304
|
+
"-k",
|
305
|
+
help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
|
306
|
+
),
|
307
|
+
format: str = typer.Option(
|
308
|
+
"table",
|
309
|
+
"--format",
|
310
|
+
"-f",
|
311
|
+
help="Output format: table, json",
|
312
|
+
),
|
313
|
+
):
|
314
|
+
"""Query all service listings from UnitySVC backend."""
|
315
|
+
try:
|
316
|
+
with ServiceDataQuery.from_env(backend_url, api_key) as query:
|
317
|
+
listings = query.list_service_listings()
|
318
|
+
|
319
|
+
if format == "json":
|
320
|
+
console.print(json.dumps(listings, indent=2))
|
321
|
+
else:
|
322
|
+
if not listings:
|
323
|
+
console.print("[yellow]No service listings found.[/yellow]")
|
324
|
+
else:
|
325
|
+
table = Table(title="Service Listings", show_lines=True)
|
326
|
+
table.add_column("ID", style="cyan")
|
327
|
+
table.add_column("Service ID", style="blue")
|
328
|
+
table.add_column("Seller", style="green")
|
329
|
+
table.add_column("Status", style="yellow")
|
330
|
+
table.add_column("Interfaces")
|
331
|
+
|
332
|
+
for listing in listings:
|
333
|
+
interfaces_count = len(listing.get("user_access_interfaces", []))
|
334
|
+
table.add_row(
|
335
|
+
str(listing.get("id", "N/A")),
|
336
|
+
str(listing.get("service_id", "N/A")),
|
337
|
+
listing.get("seller_name", "N/A"),
|
338
|
+
listing.get("listing_status", "N/A"),
|
339
|
+
str(interfaces_count),
|
340
|
+
)
|
341
|
+
|
342
|
+
console.print(table)
|
343
|
+
console.print(f"\n[green]Total:[/green] {len(listings)} service listing(s)")
|
344
|
+
except ValueError as e:
|
345
|
+
console.print(f"[red]✗[/red] {e}", style="bold red")
|
346
|
+
raise typer.Exit(code=1)
|
347
|
+
except Exception as e:
|
348
|
+
console.print(f"[red]✗[/red] Failed to query service listings: {e}", style="bold red")
|
349
|
+
raise typer.Exit(code=1)
|
350
|
+
|
351
|
+
|
352
|
+
@app.command("interfaces")
|
353
|
+
def query_interfaces(
|
354
|
+
backend_url: str | None = typer.Option(
|
355
|
+
None,
|
356
|
+
"--backend-url",
|
357
|
+
"-u",
|
358
|
+
help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
|
359
|
+
),
|
360
|
+
api_key: str | None = typer.Option(
|
361
|
+
None,
|
362
|
+
"--api-key",
|
363
|
+
"-k",
|
364
|
+
help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
|
365
|
+
),
|
366
|
+
format: str = typer.Option(
|
367
|
+
"table",
|
368
|
+
"--format",
|
369
|
+
"-f",
|
370
|
+
help="Output format: table, json",
|
371
|
+
),
|
372
|
+
):
|
373
|
+
"""Query all access interfaces from UnitySVC backend (private endpoint)."""
|
374
|
+
try:
|
375
|
+
with ServiceDataQuery.from_env(backend_url, api_key) as query:
|
376
|
+
data = query.list_access_interfaces()
|
377
|
+
|
378
|
+
if format == "json":
|
379
|
+
console.print(json.dumps(data, indent=2))
|
380
|
+
else:
|
381
|
+
interfaces = data.get("data", [])
|
382
|
+
if not interfaces:
|
383
|
+
console.print("[yellow]No access interfaces found.[/yellow]")
|
384
|
+
else:
|
385
|
+
table = Table(title="Access Interfaces", show_lines=True)
|
386
|
+
table.add_column("ID", style="cyan")
|
387
|
+
table.add_column("Name", style="green")
|
388
|
+
table.add_column("Context", style="blue")
|
389
|
+
table.add_column("Entity ID", style="yellow")
|
390
|
+
table.add_column("Method", style="magenta")
|
391
|
+
table.add_column("Active", style="green")
|
392
|
+
|
393
|
+
for interface in interfaces:
|
394
|
+
table.add_row(
|
395
|
+
str(interface.get("id", "N/A"))[:8] + "...",
|
396
|
+
interface.get("name", "N/A"),
|
397
|
+
interface.get("context_type", "N/A"),
|
398
|
+
str(interface.get("entity_id", "N/A"))[:8] + "...",
|
399
|
+
interface.get("access_method", "N/A"),
|
400
|
+
"✓" if interface.get("is_active") else "✗",
|
401
|
+
)
|
402
|
+
|
403
|
+
console.print(table)
|
404
|
+
console.print(f"\n[green]Total:[/green] {data.get('count', 0)} access interface(s)")
|
405
|
+
except ValueError as e:
|
406
|
+
console.print(f"[red]✗[/red] {e}", style="bold red")
|
407
|
+
raise typer.Exit(code=1)
|
408
|
+
except Exception as e:
|
409
|
+
console.print(f"[red]✗[/red] Failed to query access interfaces: {e}", style="bold red")
|
410
|
+
raise typer.Exit(code=1)
|
411
|
+
|
412
|
+
|
413
|
+
@app.command("documents")
|
414
|
+
def query_documents(
|
415
|
+
backend_url: str | None = typer.Option(
|
416
|
+
None,
|
417
|
+
"--backend-url",
|
418
|
+
"-u",
|
419
|
+
help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
|
420
|
+
),
|
421
|
+
api_key: str | None = typer.Option(
|
422
|
+
None,
|
423
|
+
"--api-key",
|
424
|
+
"-k",
|
425
|
+
help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
|
426
|
+
),
|
427
|
+
format: str = typer.Option(
|
428
|
+
"table",
|
429
|
+
"--format",
|
430
|
+
"-f",
|
431
|
+
help="Output format: table, json",
|
432
|
+
),
|
433
|
+
):
|
434
|
+
"""Query all documents from UnitySVC backend (private endpoint)."""
|
435
|
+
try:
|
436
|
+
with ServiceDataQuery.from_env(backend_url, api_key) as query:
|
437
|
+
data = query.list_documents()
|
438
|
+
|
439
|
+
if format == "json":
|
440
|
+
console.print(json.dumps(data, indent=2))
|
441
|
+
else:
|
442
|
+
documents = data.get("data", [])
|
443
|
+
if not documents:
|
444
|
+
console.print("[yellow]No documents found.[/yellow]")
|
445
|
+
else:
|
446
|
+
table = Table(title="Documents", show_lines=True)
|
447
|
+
table.add_column("ID", style="cyan")
|
448
|
+
table.add_column("Title", style="green")
|
449
|
+
table.add_column("Category", style="blue")
|
450
|
+
table.add_column("MIME Type", style="yellow")
|
451
|
+
table.add_column("Context", style="magenta")
|
452
|
+
table.add_column("Public", style="red")
|
453
|
+
|
454
|
+
for doc in documents:
|
455
|
+
table.add_row(
|
456
|
+
str(doc.get("id", "N/A"))[:8] + "...",
|
457
|
+
doc.get("title", "N/A")[:40],
|
458
|
+
doc.get("category", "N/A"),
|
459
|
+
doc.get("mime_type", "N/A"),
|
460
|
+
doc.get("context_type", "N/A"),
|
461
|
+
"✓" if doc.get("is_public") else "✗",
|
462
|
+
)
|
463
|
+
|
464
|
+
console.print(table)
|
465
|
+
console.print(f"\n[green]Total:[/green] {data.get('count', 0)} document(s)")
|
466
|
+
except ValueError as e:
|
467
|
+
console.print(f"[red]✗[/red] {e}", style="bold red")
|
468
|
+
raise typer.Exit(code=1)
|
469
|
+
except Exception as e:
|
470
|
+
console.print(f"[red]✗[/red] Failed to query documents: {e}", style="bold red")
|
471
|
+
raise typer.Exit(code=1)
|