unitysvc-services 0.2.2__py3-none-any.whl → 0.2.4__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/publisher.py +7 -2
- unitysvc_services/query.py +482 -187
- {unitysvc_services-0.2.2.dist-info → unitysvc_services-0.2.4.dist-info}/METADATA +5 -2
- {unitysvc_services-0.2.2.dist-info → unitysvc_services-0.2.4.dist-info}/RECORD +8 -8
- {unitysvc_services-0.2.2.dist-info → unitysvc_services-0.2.4.dist-info}/WHEEL +0 -0
- {unitysvc_services-0.2.2.dist-info → unitysvc_services-0.2.4.dist-info}/entry_points.txt +0 -0
- {unitysvc_services-0.2.2.dist-info → unitysvc_services-0.2.4.dist-info}/licenses/LICENSE +0 -0
- {unitysvc_services-0.2.2.dist-info → unitysvc_services-0.2.4.dist-info}/top_level.txt +0 -0
unitysvc_services/publisher.py
CHANGED
@@ -106,6 +106,11 @@ class ServiceDataPublisher:
|
|
106
106
|
|
107
107
|
# Resolve file references and include content
|
108
108
|
base_path = data_file.parent
|
109
|
+
data = convert_convenience_fields_to_documents(
|
110
|
+
data, base_path, logo_field="logo", terms_field="terms_of_service"
|
111
|
+
)
|
112
|
+
|
113
|
+
# Resolve file references and include content
|
109
114
|
data_with_content = self.resolve_file_references(data, base_path)
|
110
115
|
|
111
116
|
# Extract provider_name from directory structure
|
@@ -139,7 +144,7 @@ class ServiceDataPublisher:
|
|
139
144
|
|
140
145
|
# Post to the endpoint
|
141
146
|
response = self.client.post(
|
142
|
-
f"{self.base_url}/publish/
|
147
|
+
f"{self.base_url}/publish/offering",
|
143
148
|
json=data_with_content,
|
144
149
|
)
|
145
150
|
response.raise_for_status()
|
@@ -250,7 +255,7 @@ class ServiceDataPublisher:
|
|
250
255
|
|
251
256
|
# Post to the endpoint
|
252
257
|
response = self.client.post(
|
253
|
-
f"{self.base_url}/publish/
|
258
|
+
f"{self.base_url}/publish/listing",
|
254
259
|
json=data_with_content,
|
255
260
|
)
|
256
261
|
response.raise_for_status()
|
unitysvc_services/query.py
CHANGED
@@ -39,45 +39,65 @@ class ServiceDataQuery:
|
|
39
39
|
timeout=30.0,
|
40
40
|
)
|
41
41
|
|
42
|
-
def list_service_offerings(self) -> list[dict[str, Any]]:
|
43
|
-
"""List all service offerings from the backend.
|
44
|
-
response = self.client.get(f"{self.base_url}/publish/service_offerings")
|
45
|
-
response.raise_for_status()
|
46
|
-
result = response.json()
|
47
|
-
return result.get("data", result) if isinstance(result, dict) else result
|
42
|
+
def list_service_offerings(self, skip: int = 0, limit: int = 100) -> list[dict[str, Any]]:
|
43
|
+
"""List all service offerings from the backend.
|
48
44
|
|
49
|
-
|
50
|
-
|
51
|
-
|
45
|
+
Args:
|
46
|
+
skip: Number of records to skip (for pagination)
|
47
|
+
limit: Maximum number of records to return
|
48
|
+
"""
|
49
|
+
response = self.client.get(
|
50
|
+
f"{self.base_url}/publish/offerings",
|
51
|
+
params={"skip": skip, "limit": limit}
|
52
|
+
)
|
52
53
|
response.raise_for_status()
|
53
54
|
result = response.json()
|
54
55
|
return result.get("data", result) if isinstance(result, dict) else result
|
55
56
|
|
56
|
-
def
|
57
|
-
"""List all
|
58
|
-
|
57
|
+
def list_service_listings(self, skip: int = 0, limit: int = 100) -> list[dict[str, Any]]:
|
58
|
+
"""List all service listings from the backend.
|
59
|
+
|
60
|
+
Args:
|
61
|
+
skip: Number of records to skip (for pagination)
|
62
|
+
limit: Maximum number of records to return
|
63
|
+
"""
|
64
|
+
response = self.client.get(
|
65
|
+
f"{self.base_url}/publish/listings",
|
66
|
+
params={"skip": skip, "limit": limit}
|
67
|
+
)
|
59
68
|
response.raise_for_status()
|
60
69
|
result = response.json()
|
61
70
|
return result.get("data", result) if isinstance(result, dict) else result
|
62
71
|
|
63
|
-
def
|
64
|
-
"""List all
|
65
|
-
|
72
|
+
def list_providers(self, skip: int = 0, limit: int = 100) -> list[dict[str, Any]]:
|
73
|
+
"""List all providers from the backend.
|
74
|
+
|
75
|
+
Args:
|
76
|
+
skip: Number of records to skip (for pagination)
|
77
|
+
limit: Maximum number of records to return
|
78
|
+
"""
|
79
|
+
response = self.client.get(
|
80
|
+
f"{self.base_url}/publish/providers",
|
81
|
+
params={"skip": skip, "limit": limit}
|
82
|
+
)
|
66
83
|
response.raise_for_status()
|
67
84
|
result = response.json()
|
68
85
|
return result.get("data", result) if isinstance(result, dict) else result
|
69
86
|
|
70
|
-
def
|
71
|
-
"""List all
|
72
|
-
response = self.client.get(f"{self.base_url}/private/access_interfaces")
|
73
|
-
response.raise_for_status()
|
74
|
-
return response.json()
|
87
|
+
def list_sellers(self, skip: int = 0, limit: int = 100) -> list[dict[str, Any]]:
|
88
|
+
"""List all sellers from the backend.
|
75
89
|
|
76
|
-
|
77
|
-
|
78
|
-
|
90
|
+
Args:
|
91
|
+
skip: Number of records to skip (for pagination)
|
92
|
+
limit: Maximum number of records to return
|
93
|
+
"""
|
94
|
+
response = self.client.get(
|
95
|
+
f"{self.base_url}/publish/sellers",
|
96
|
+
params={"skip": skip, "limit": limit}
|
97
|
+
)
|
79
98
|
response.raise_for_status()
|
80
|
-
|
99
|
+
result = response.json()
|
100
|
+
return result.get("data", result) if isinstance(result, dict) else result
|
81
101
|
|
82
102
|
def close(self):
|
83
103
|
"""Close the HTTP client."""
|
@@ -100,37 +120,152 @@ def query_sellers(
|
|
100
120
|
"-f",
|
101
121
|
help="Output format: table, json",
|
102
122
|
),
|
123
|
+
fields: str = typer.Option(
|
124
|
+
"id,name,display_name,seller_type",
|
125
|
+
"--fields",
|
126
|
+
help=(
|
127
|
+
"Comma-separated list of fields to display. Available fields: "
|
128
|
+
"id, name, display_name, seller_type, contact_email, "
|
129
|
+
"secondary_contact_email, homepage, description, "
|
130
|
+
"business_registration, tax_id, account_manager_id, "
|
131
|
+
"created_at, updated_at, status"
|
132
|
+
),
|
133
|
+
),
|
134
|
+
skip: int = typer.Option(
|
135
|
+
0,
|
136
|
+
"--skip",
|
137
|
+
help="Number of records to skip (for pagination)",
|
138
|
+
),
|
139
|
+
limit: int = typer.Option(
|
140
|
+
100,
|
141
|
+
"--limit",
|
142
|
+
help="Maximum number of records to return (default: 100)",
|
143
|
+
),
|
103
144
|
):
|
104
|
-
"""Query all sellers from the backend.
|
145
|
+
"""Query all sellers from the backend.
|
146
|
+
|
147
|
+
Examples:
|
148
|
+
# Use default fields
|
149
|
+
unitysvc_services query sellers
|
150
|
+
|
151
|
+
# Show only specific fields
|
152
|
+
unitysvc_services query sellers --fields id,name,contact_email
|
153
|
+
|
154
|
+
# Retrieve more than 100 records
|
155
|
+
unitysvc_services query sellers --limit 500
|
156
|
+
|
157
|
+
# Pagination: skip first 100, get next 100
|
158
|
+
unitysvc_services query sellers --skip 100 --limit 100
|
159
|
+
|
160
|
+
# Show all available fields
|
161
|
+
unitysvc_services query sellers --fields \\
|
162
|
+
id,name,display_name,seller_type,contact_email,homepage,created_at,updated_at
|
163
|
+
"""
|
164
|
+
# Parse fields list
|
165
|
+
field_list = [f.strip() for f in fields.split(",")]
|
166
|
+
|
167
|
+
# Define allowed fields from SellerPublic model
|
168
|
+
allowed_fields = {
|
169
|
+
"id",
|
170
|
+
"name",
|
171
|
+
"display_name",
|
172
|
+
"seller_type",
|
173
|
+
"contact_email",
|
174
|
+
"secondary_contact_email",
|
175
|
+
"homepage",
|
176
|
+
"description",
|
177
|
+
"business_registration",
|
178
|
+
"tax_id",
|
179
|
+
"account_manager_id",
|
180
|
+
"created_at",
|
181
|
+
"updated_at",
|
182
|
+
"status",
|
183
|
+
}
|
184
|
+
|
185
|
+
# Validate fields
|
186
|
+
invalid_fields = [f for f in field_list if f not in allowed_fields]
|
187
|
+
if invalid_fields:
|
188
|
+
console.print(
|
189
|
+
f"[red]✗[/red] Invalid field(s): {', '.join(invalid_fields)}",
|
190
|
+
style="bold red",
|
191
|
+
)
|
192
|
+
console.print(f"[yellow]Allowed fields:[/yellow] {', '.join(sorted(allowed_fields))}")
|
193
|
+
raise typer.Exit(code=1)
|
194
|
+
|
105
195
|
try:
|
106
196
|
with ServiceDataQuery() as query:
|
107
|
-
sellers = query.list_sellers()
|
197
|
+
sellers = query.list_sellers(skip=skip, limit=limit)
|
108
198
|
|
109
199
|
if format == "json":
|
110
|
-
|
200
|
+
# For JSON, filter fields if not all are requested
|
201
|
+
if set(field_list) != allowed_fields:
|
202
|
+
filtered_sellers = [{k: v for k, v in seller.items() if k in field_list} for seller in sellers]
|
203
|
+
console.print(json.dumps(filtered_sellers, indent=2))
|
204
|
+
else:
|
205
|
+
console.print(json.dumps(sellers, indent=2))
|
111
206
|
else:
|
112
207
|
if not sellers:
|
113
208
|
console.print("[yellow]No sellers found.[/yellow]")
|
114
209
|
else:
|
115
210
|
table = Table(title="Sellers")
|
116
|
-
table.add_column("ID", style="cyan")
|
117
|
-
table.add_column("Name", style="green")
|
118
|
-
table.add_column("Display Name", style="blue")
|
119
|
-
table.add_column("Type", style="magenta")
|
120
|
-
table.add_column("Contact Email", style="yellow")
|
121
|
-
table.add_column("Active", style="white")
|
122
211
|
|
212
|
+
# Define column styles
|
213
|
+
field_styles = {
|
214
|
+
"id": "cyan",
|
215
|
+
"name": "green",
|
216
|
+
"display_name": "blue",
|
217
|
+
"seller_type": "magenta",
|
218
|
+
"contact_email": "yellow",
|
219
|
+
"secondary_contact_email": "yellow",
|
220
|
+
"homepage": "blue",
|
221
|
+
"description": "white",
|
222
|
+
"business_registration": "white",
|
223
|
+
"tax_id": "white",
|
224
|
+
"account_manager_id": "cyan",
|
225
|
+
"created_at": "white",
|
226
|
+
"updated_at": "white",
|
227
|
+
"status": "green",
|
228
|
+
}
|
229
|
+
|
230
|
+
# Define column headers
|
231
|
+
field_headers = {
|
232
|
+
"id": "ID",
|
233
|
+
"name": "Name",
|
234
|
+
"display_name": "Display Name",
|
235
|
+
"seller_type": "Type",
|
236
|
+
"contact_email": "Contact Email",
|
237
|
+
"secondary_contact_email": "Secondary Email",
|
238
|
+
"homepage": "Homepage",
|
239
|
+
"description": "Description",
|
240
|
+
"business_registration": "Business Reg",
|
241
|
+
"tax_id": "Tax ID",
|
242
|
+
"account_manager_id": "Account Manager ID",
|
243
|
+
"created_at": "Created At",
|
244
|
+
"updated_at": "Updated At",
|
245
|
+
"status": "Status",
|
246
|
+
}
|
247
|
+
|
248
|
+
# Add columns based on requested fields
|
249
|
+
for field in field_list:
|
250
|
+
header = field_headers.get(field, field.title())
|
251
|
+
style = field_styles.get(field, "white")
|
252
|
+
table.add_column(header, style=style)
|
253
|
+
|
254
|
+
# Add rows
|
123
255
|
for seller in sellers:
|
124
|
-
|
125
|
-
|
126
|
-
seller.get(
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
256
|
+
row = []
|
257
|
+
for field in field_list:
|
258
|
+
value = seller.get(field)
|
259
|
+
if value is None:
|
260
|
+
row.append("N/A")
|
261
|
+
elif isinstance(value, dict | list):
|
262
|
+
row.append(str(value)[:50]) # Truncate complex types
|
263
|
+
else:
|
264
|
+
row.append(str(value))
|
265
|
+
table.add_row(*row)
|
132
266
|
|
133
267
|
console.print(table)
|
268
|
+
console.print(f"\n[green]Total:[/green] {len(sellers)} seller(s)")
|
134
269
|
except ValueError as e:
|
135
270
|
console.print(f"[red]✗[/red] {e}", style="bold red")
|
136
271
|
raise typer.Exit(code=1)
|
@@ -147,33 +282,140 @@ def query_providers(
|
|
147
282
|
"-f",
|
148
283
|
help="Output format: table, json",
|
149
284
|
),
|
285
|
+
fields: str = typer.Option(
|
286
|
+
"id,name,display_name,status",
|
287
|
+
"--fields",
|
288
|
+
help=(
|
289
|
+
"Comma-separated list of fields to display. Available fields: "
|
290
|
+
"id, name, display_name, contact_email, secondary_contact_email, "
|
291
|
+
"homepage, description, status, created_at, updated_at"
|
292
|
+
),
|
293
|
+
),
|
294
|
+
skip: int = typer.Option(
|
295
|
+
0,
|
296
|
+
"--skip",
|
297
|
+
help="Number of records to skip (for pagination)",
|
298
|
+
),
|
299
|
+
limit: int = typer.Option(
|
300
|
+
100,
|
301
|
+
"--limit",
|
302
|
+
help="Maximum number of records to return (default: 100)",
|
303
|
+
),
|
150
304
|
):
|
151
|
-
"""Query all providers from the backend.
|
305
|
+
"""Query all providers from the backend.
|
306
|
+
|
307
|
+
Examples:
|
308
|
+
# Use default fields
|
309
|
+
unitysvc_services query providers
|
310
|
+
|
311
|
+
# Retrieve more than 100 records
|
312
|
+
unitysvc_services query providers --limit 500
|
313
|
+
|
314
|
+
# Pagination: skip first 100, get next 100
|
315
|
+
unitysvc_services query providers --skip 100 --limit 100
|
316
|
+
|
317
|
+
# Show only specific fields
|
318
|
+
unitysvc_services query providers --fields id,name,contact_email
|
319
|
+
|
320
|
+
# Show all available fields
|
321
|
+
unitysvc_services query providers --fields \\
|
322
|
+
id,name,display_name,contact_email,homepage,status,created_at,updated_at
|
323
|
+
"""
|
324
|
+
# Parse fields list
|
325
|
+
field_list = [f.strip() for f in fields.split(",")]
|
326
|
+
|
327
|
+
# Define allowed fields from ProviderPublic model
|
328
|
+
allowed_fields = {
|
329
|
+
"id",
|
330
|
+
"name",
|
331
|
+
"display_name",
|
332
|
+
"contact_email",
|
333
|
+
"secondary_contact_email",
|
334
|
+
"homepage",
|
335
|
+
"description",
|
336
|
+
"status",
|
337
|
+
"created_at",
|
338
|
+
"updated_at",
|
339
|
+
}
|
340
|
+
|
341
|
+
# Validate fields
|
342
|
+
invalid_fields = [f for f in field_list if f not in allowed_fields]
|
343
|
+
if invalid_fields:
|
344
|
+
console.print(
|
345
|
+
f"[red]✗[/red] Invalid field(s): {', '.join(invalid_fields)}",
|
346
|
+
style="bold red",
|
347
|
+
)
|
348
|
+
console.print(f"[yellow]Allowed fields:[/yellow] {', '.join(sorted(allowed_fields))}")
|
349
|
+
raise typer.Exit(code=1)
|
350
|
+
|
152
351
|
try:
|
153
352
|
with ServiceDataQuery() as query:
|
154
|
-
providers = query.list_providers()
|
353
|
+
providers = query.list_providers(skip=skip, limit=limit)
|
155
354
|
|
156
355
|
if format == "json":
|
157
|
-
|
356
|
+
# For JSON, filter fields if not all are requested
|
357
|
+
if set(field_list) != allowed_fields:
|
358
|
+
filtered_providers = [
|
359
|
+
{k: v for k, v in provider.items() if k in field_list} for provider in providers
|
360
|
+
]
|
361
|
+
console.print(json.dumps(filtered_providers, indent=2))
|
362
|
+
else:
|
363
|
+
console.print(json.dumps(providers, indent=2))
|
158
364
|
else:
|
159
365
|
if not providers:
|
160
366
|
console.print("[yellow]No providers found.[/yellow]")
|
161
367
|
else:
|
162
368
|
table = Table(title="Providers")
|
163
|
-
table.add_column("ID", style="cyan")
|
164
|
-
table.add_column("Name", style="green")
|
165
|
-
table.add_column("Display Name", style="blue")
|
166
|
-
table.add_column("Time Created", style="magenta")
|
167
369
|
|
370
|
+
# Define column styles
|
371
|
+
field_styles = {
|
372
|
+
"id": "cyan",
|
373
|
+
"name": "green",
|
374
|
+
"display_name": "blue",
|
375
|
+
"contact_email": "yellow",
|
376
|
+
"secondary_contact_email": "yellow",
|
377
|
+
"homepage": "blue",
|
378
|
+
"description": "white",
|
379
|
+
"status": "green",
|
380
|
+
"created_at": "magenta",
|
381
|
+
"updated_at": "magenta",
|
382
|
+
}
|
383
|
+
|
384
|
+
# Define column headers
|
385
|
+
field_headers = {
|
386
|
+
"id": "ID",
|
387
|
+
"name": "Name",
|
388
|
+
"display_name": "Display Name",
|
389
|
+
"contact_email": "Contact Email",
|
390
|
+
"secondary_contact_email": "Secondary Email",
|
391
|
+
"homepage": "Homepage",
|
392
|
+
"description": "Description",
|
393
|
+
"status": "Status",
|
394
|
+
"created_at": "Created At",
|
395
|
+
"updated_at": "Updated At",
|
396
|
+
}
|
397
|
+
|
398
|
+
# Add columns based on requested fields
|
399
|
+
for field in field_list:
|
400
|
+
header = field_headers.get(field, field.title())
|
401
|
+
style = field_styles.get(field, "white")
|
402
|
+
table.add_column(header, style=style)
|
403
|
+
|
404
|
+
# Add rows
|
168
405
|
for provider in providers:
|
169
|
-
|
170
|
-
|
171
|
-
provider.get(
|
172
|
-
|
173
|
-
|
174
|
-
|
406
|
+
row = []
|
407
|
+
for field in field_list:
|
408
|
+
value = provider.get(field)
|
409
|
+
if value is None:
|
410
|
+
row.append("N/A")
|
411
|
+
elif isinstance(value, dict | list):
|
412
|
+
row.append(str(value)[:50]) # Truncate complex types
|
413
|
+
else:
|
414
|
+
row.append(str(value))
|
415
|
+
table.add_row(*row)
|
175
416
|
|
176
417
|
console.print(table)
|
418
|
+
console.print(f"\n[green]Total:[/green] {len(providers)} provider(s)")
|
177
419
|
except ValueError as e:
|
178
420
|
console.print(f"[red]✗[/red] {e}", style="bold red")
|
179
421
|
raise typer.Exit(code=1)
|
@@ -190,35 +432,107 @@ def query_offerings(
|
|
190
432
|
"-f",
|
191
433
|
help="Output format: table, json",
|
192
434
|
),
|
435
|
+
fields: str = typer.Option(
|
436
|
+
"id,service_name,service_type,provider_name,status",
|
437
|
+
"--fields",
|
438
|
+
help=(
|
439
|
+
"Comma-separated list of fields to display. Available fields: "
|
440
|
+
"id, definition_id, provider_id, status, price, service_name, "
|
441
|
+
"service_type, provider_name"
|
442
|
+
),
|
443
|
+
),
|
444
|
+
skip: int = typer.Option(
|
445
|
+
0,
|
446
|
+
"--skip",
|
447
|
+
help="Number of records to skip (for pagination)",
|
448
|
+
),
|
449
|
+
limit: int = typer.Option(
|
450
|
+
100,
|
451
|
+
"--limit",
|
452
|
+
help="Maximum number of records to return (default: 100)",
|
453
|
+
),
|
193
454
|
):
|
194
|
-
"""Query all service offerings from UnitySVC backend.
|
455
|
+
"""Query all service offerings from UnitySVC backend.
|
456
|
+
|
457
|
+
Examples:
|
458
|
+
# Use default fields
|
459
|
+
unitysvc_services query offerings
|
460
|
+
|
461
|
+
# Show only specific fields
|
462
|
+
unitysvc_services query offerings --fields id,service_name,status
|
463
|
+
|
464
|
+
# Retrieve more than 100 records
|
465
|
+
unitysvc_services query offerings --limit 500
|
466
|
+
|
467
|
+
# Pagination: skip first 100, get next 100
|
468
|
+
unitysvc_services query offerings --skip 100 --limit 100
|
469
|
+
|
470
|
+
# Show all available fields
|
471
|
+
unitysvc_services query offerings --fields \\
|
472
|
+
id,service_name,service_type,provider_name,status,price,definition_id,provider_id
|
473
|
+
"""
|
474
|
+
# Parse fields list
|
475
|
+
field_list = [f.strip() for f in fields.split(",")]
|
476
|
+
|
477
|
+
# Define allowed fields from ServiceOfferingPublic model
|
478
|
+
allowed_fields = {
|
479
|
+
"id",
|
480
|
+
"definition_id",
|
481
|
+
"provider_id",
|
482
|
+
"status",
|
483
|
+
"price",
|
484
|
+
"service_name",
|
485
|
+
"service_type",
|
486
|
+
"provider_name",
|
487
|
+
}
|
488
|
+
|
489
|
+
# Validate fields
|
490
|
+
invalid_fields = [f for f in field_list if f not in allowed_fields]
|
491
|
+
if invalid_fields:
|
492
|
+
console.print(
|
493
|
+
f"[red]Error:[/red] Invalid field(s): {', '.join(invalid_fields)}",
|
494
|
+
style="bold red",
|
495
|
+
)
|
496
|
+
console.print(f"[yellow]Available fields:[/yellow] {', '.join(sorted(allowed_fields))}")
|
497
|
+
raise typer.Exit(code=1)
|
498
|
+
|
195
499
|
try:
|
196
500
|
with ServiceDataQuery() as query:
|
197
|
-
offerings = query.list_service_offerings()
|
501
|
+
offerings = query.list_service_offerings(skip=skip, limit=limit)
|
198
502
|
|
199
503
|
if format == "json":
|
200
|
-
|
504
|
+
# For JSON, filter fields if not all are requested
|
505
|
+
if set(field_list) != allowed_fields:
|
506
|
+
filtered_offerings = [
|
507
|
+
{k: v for k, v in offering.items() if k in field_list} for offering in offerings
|
508
|
+
]
|
509
|
+
console.print(json.dumps(filtered_offerings, indent=2))
|
510
|
+
else:
|
511
|
+
console.print(json.dumps(offerings, indent=2))
|
201
512
|
else:
|
202
513
|
if not offerings:
|
203
514
|
console.print("[yellow]No service offerings found.[/yellow]")
|
204
515
|
else:
|
205
|
-
table = Table(title="Service Offerings"
|
206
|
-
table.add_column("ID", style="cyan")
|
207
|
-
table.add_column("Name", style="green")
|
208
|
-
table.add_column("Display Name", style="blue")
|
209
|
-
table.add_column("Type", style="magenta")
|
210
|
-
table.add_column("Status", style="yellow")
|
211
|
-
table.add_column("Version")
|
516
|
+
table = Table(title="Service Offerings")
|
212
517
|
|
518
|
+
# Add columns dynamically based on selected fields
|
519
|
+
for field in field_list:
|
520
|
+
# Capitalize and format field names for display
|
521
|
+
column_name = field.replace("_", " ").title()
|
522
|
+
table.add_column(column_name)
|
523
|
+
|
524
|
+
# Add rows
|
213
525
|
for offering in offerings:
|
214
|
-
|
215
|
-
|
216
|
-
offering.get(
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
526
|
+
row = []
|
527
|
+
for field in field_list:
|
528
|
+
value = offering.get(field)
|
529
|
+
if value is None:
|
530
|
+
row.append("N/A")
|
531
|
+
elif isinstance(value, dict | list):
|
532
|
+
row.append(str(value)[:50]) # Truncate complex types
|
533
|
+
else:
|
534
|
+
row.append(str(value))
|
535
|
+
table.add_row(*row)
|
222
536
|
|
223
537
|
console.print(table)
|
224
538
|
console.print(f"\n[green]Total:[/green] {len(offerings)} service offering(s)")
|
@@ -238,34 +552,113 @@ def query_listings(
|
|
238
552
|
"-f",
|
239
553
|
help="Output format: table, json",
|
240
554
|
),
|
555
|
+
fields: str = typer.Option(
|
556
|
+
"id,service_name,service_type,seller_name,listing_type,status",
|
557
|
+
"--fields",
|
558
|
+
help=(
|
559
|
+
"Comma-separated list of fields to display. Available fields: "
|
560
|
+
"id, offering_id, offering_status, seller_id, status, created_at, updated_at, "
|
561
|
+
"parameters_schema, parameters_ui_schema, tags, service_name, "
|
562
|
+
"service_type, provider_name, seller_name, listing_type"
|
563
|
+
),
|
564
|
+
),
|
565
|
+
skip: int = typer.Option(
|
566
|
+
0,
|
567
|
+
"--skip",
|
568
|
+
help="Number of records to skip (for pagination)",
|
569
|
+
),
|
570
|
+
limit: int = typer.Option(
|
571
|
+
100,
|
572
|
+
"--limit",
|
573
|
+
help="Maximum number of records to return (default: 100)",
|
574
|
+
),
|
241
575
|
):
|
242
|
-
"""Query all service listings from UnitySVC backend.
|
576
|
+
"""Query all service listings from UnitySVC backend.
|
577
|
+
|
578
|
+
Examples:
|
579
|
+
# Use default fields
|
580
|
+
unitysvc_services query listings
|
581
|
+
|
582
|
+
# Show only specific fields
|
583
|
+
unitysvc_services query listings --fields id,service_name,status
|
584
|
+
|
585
|
+
# Retrieve more than 100 records
|
586
|
+
unitysvc_services query listings --limit 500
|
587
|
+
|
588
|
+
# Pagination: skip first 100, get next 100
|
589
|
+
unitysvc_services query listings --skip 100 --limit 100
|
590
|
+
|
591
|
+
# Show all available fields
|
592
|
+
unitysvc_services query listings --fields \\
|
593
|
+
id,service_name,service_type,seller_name,listing_type,status,provider_name
|
594
|
+
"""
|
595
|
+
# Parse fields list
|
596
|
+
field_list = [f.strip() for f in fields.split(",")]
|
597
|
+
|
598
|
+
# Define allowed fields from ServiceListingPublic model
|
599
|
+
allowed_fields = {
|
600
|
+
"id",
|
601
|
+
"offering_id",
|
602
|
+
"offering_status",
|
603
|
+
"seller_id",
|
604
|
+
"status",
|
605
|
+
"created_at",
|
606
|
+
"updated_at",
|
607
|
+
"parameters_schema",
|
608
|
+
"parameters_ui_schema",
|
609
|
+
"tags",
|
610
|
+
"service_name",
|
611
|
+
"service_type",
|
612
|
+
"provider_name",
|
613
|
+
"seller_name",
|
614
|
+
"listing_type",
|
615
|
+
}
|
616
|
+
|
617
|
+
# Validate fields
|
618
|
+
invalid_fields = [f for f in field_list if f not in allowed_fields]
|
619
|
+
if invalid_fields:
|
620
|
+
console.print(
|
621
|
+
f"[red]Error:[/red] Invalid field(s): {', '.join(invalid_fields)}",
|
622
|
+
style="bold red",
|
623
|
+
)
|
624
|
+
console.print(f"[yellow]Available fields:[/yellow] {', '.join(sorted(allowed_fields))}")
|
625
|
+
raise typer.Exit(code=1)
|
626
|
+
|
243
627
|
try:
|
244
628
|
with ServiceDataQuery() as query:
|
245
|
-
listings = query.list_service_listings()
|
629
|
+
listings = query.list_service_listings(skip=skip, limit=limit)
|
246
630
|
|
247
631
|
if format == "json":
|
248
|
-
|
632
|
+
# For JSON, filter fields if not all are requested
|
633
|
+
if set(field_list) != allowed_fields:
|
634
|
+
filtered_listings = [{k: v for k, v in listing.items() if k in field_list} for listing in listings]
|
635
|
+
console.print(json.dumps(filtered_listings, indent=2))
|
636
|
+
else:
|
637
|
+
console.print(json.dumps(listings, indent=2))
|
249
638
|
else:
|
250
639
|
if not listings:
|
251
640
|
console.print("[yellow]No service listings found.[/yellow]")
|
252
641
|
else:
|
253
|
-
table = Table(title="Service Listings"
|
254
|
-
table.add_column("ID", style="cyan")
|
255
|
-
table.add_column("Service ID", style="blue")
|
256
|
-
table.add_column("Seller", style="green")
|
257
|
-
table.add_column("Status", style="yellow")
|
258
|
-
table.add_column("Interfaces")
|
642
|
+
table = Table(title="Service Listings")
|
259
643
|
|
644
|
+
# Add columns dynamically based on selected fields
|
645
|
+
for field in field_list:
|
646
|
+
# Capitalize and format field names for display
|
647
|
+
column_name = field.replace("_", " ").title()
|
648
|
+
table.add_column(column_name)
|
649
|
+
|
650
|
+
# Add rows
|
260
651
|
for listing in listings:
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
652
|
+
row = []
|
653
|
+
for field in field_list:
|
654
|
+
value = listing.get(field)
|
655
|
+
if value is None:
|
656
|
+
row.append("N/A")
|
657
|
+
elif isinstance(value, dict | list):
|
658
|
+
row.append(str(value)[:50]) # Truncate complex types
|
659
|
+
else:
|
660
|
+
row.append(str(value))
|
661
|
+
table.add_row(*row)
|
269
662
|
|
270
663
|
console.print(table)
|
271
664
|
console.print(f"\n[green]Total:[/green] {len(listings)} service listing(s)")
|
@@ -275,101 +668,3 @@ def query_listings(
|
|
275
668
|
except Exception as e:
|
276
669
|
console.print(f"[red]✗[/red] Failed to query service listings: {e}", style="bold red")
|
277
670
|
raise typer.Exit(code=1)
|
278
|
-
|
279
|
-
|
280
|
-
@app.command("interfaces")
|
281
|
-
def query_interfaces(
|
282
|
-
format: str = typer.Option(
|
283
|
-
"table",
|
284
|
-
"--format",
|
285
|
-
"-f",
|
286
|
-
help="Output format: table, json",
|
287
|
-
),
|
288
|
-
):
|
289
|
-
"""Query all access interfaces from UnitySVC backend (private endpoint)."""
|
290
|
-
try:
|
291
|
-
with ServiceDataQuery() as query:
|
292
|
-
data = query.list_access_interfaces()
|
293
|
-
|
294
|
-
if format == "json":
|
295
|
-
console.print(json.dumps(data, indent=2))
|
296
|
-
else:
|
297
|
-
interfaces = data.get("data", [])
|
298
|
-
if not interfaces:
|
299
|
-
console.print("[yellow]No access interfaces found.[/yellow]")
|
300
|
-
else:
|
301
|
-
table = Table(title="Access Interfaces", show_lines=True)
|
302
|
-
table.add_column("ID", style="cyan")
|
303
|
-
table.add_column("Name", style="green")
|
304
|
-
table.add_column("Context", style="blue")
|
305
|
-
table.add_column("Entity ID", style="yellow")
|
306
|
-
table.add_column("Method", style="magenta")
|
307
|
-
table.add_column("Active", style="green")
|
308
|
-
|
309
|
-
for interface in interfaces:
|
310
|
-
table.add_row(
|
311
|
-
str(interface.get("id", "N/A"))[:8] + "...",
|
312
|
-
interface.get("name", "N/A"),
|
313
|
-
interface.get("context_type", "N/A"),
|
314
|
-
str(interface.get("entity_id", "N/A"))[:8] + "...",
|
315
|
-
interface.get("access_method", "N/A"),
|
316
|
-
"✓" if interface.get("is_active") else "✗",
|
317
|
-
)
|
318
|
-
|
319
|
-
console.print(table)
|
320
|
-
console.print(f"\n[green]Total:[/green] {data.get('count', 0)} access interface(s)")
|
321
|
-
except ValueError as e:
|
322
|
-
console.print(f"[red]✗[/red] {e}", style="bold red")
|
323
|
-
raise typer.Exit(code=1)
|
324
|
-
except Exception as e:
|
325
|
-
console.print(f"[red]✗[/red] Failed to query access interfaces: {e}", style="bold red")
|
326
|
-
raise typer.Exit(code=1)
|
327
|
-
|
328
|
-
|
329
|
-
@app.command("documents")
|
330
|
-
def query_documents(
|
331
|
-
format: str = typer.Option(
|
332
|
-
"table",
|
333
|
-
"--format",
|
334
|
-
"-f",
|
335
|
-
help="Output format: table, json",
|
336
|
-
),
|
337
|
-
):
|
338
|
-
"""Query all documents from UnitySVC backend (private endpoint)."""
|
339
|
-
try:
|
340
|
-
with ServiceDataQuery() as query:
|
341
|
-
data = query.list_documents()
|
342
|
-
|
343
|
-
if format == "json":
|
344
|
-
console.print(json.dumps(data, indent=2))
|
345
|
-
else:
|
346
|
-
documents = data.get("data", [])
|
347
|
-
if not documents:
|
348
|
-
console.print("[yellow]No documents found.[/yellow]")
|
349
|
-
else:
|
350
|
-
table = Table(title="Documents", show_lines=True)
|
351
|
-
table.add_column("ID", style="cyan")
|
352
|
-
table.add_column("Title", style="green")
|
353
|
-
table.add_column("Category", style="blue")
|
354
|
-
table.add_column("MIME Type", style="yellow")
|
355
|
-
table.add_column("Context", style="magenta")
|
356
|
-
table.add_column("Public", style="red")
|
357
|
-
|
358
|
-
for doc in documents:
|
359
|
-
table.add_row(
|
360
|
-
str(doc.get("id", "N/A"))[:8] + "...",
|
361
|
-
doc.get("title", "N/A")[:40],
|
362
|
-
doc.get("category", "N/A"),
|
363
|
-
doc.get("mime_type", "N/A"),
|
364
|
-
doc.get("context_type", "N/A"),
|
365
|
-
"✓" if doc.get("is_public") else "✗",
|
366
|
-
)
|
367
|
-
|
368
|
-
console.print(table)
|
369
|
-
console.print(f"\n[green]Total:[/green] {data.get('count', 0)} document(s)")
|
370
|
-
except ValueError as e:
|
371
|
-
console.print(f"[red]✗[/red] {e}", style="bold red")
|
372
|
-
raise typer.Exit(code=1)
|
373
|
-
except Exception as e:
|
374
|
-
console.print(f"[red]✗[/red] Failed to query documents: {e}", style="bold red")
|
375
|
-
raise typer.Exit(code=1)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: unitysvc-services
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.4
|
4
4
|
Summary: SDK for digital service providers on UnitySVC
|
5
5
|
Author-email: Bo Peng <bo.peng@unitysvc.com>
|
6
6
|
Maintainer-email: Bo Peng <bo.peng@unitysvc.com>
|
@@ -87,8 +87,11 @@ unitysvc_services publish
|
|
87
87
|
# Or publish specific types only
|
88
88
|
unitysvc_services publish providers
|
89
89
|
|
90
|
-
# Verify
|
90
|
+
# Verify with default fields
|
91
91
|
unitysvc_services query offerings
|
92
|
+
|
93
|
+
# Query with custom fields
|
94
|
+
unitysvc_services query providers --fields id,name,contact_email
|
92
95
|
```
|
93
96
|
|
94
97
|
## Key Features
|
@@ -3,9 +3,9 @@ unitysvc_services/cli.py,sha256=OK0IZyAckxP15jRWU_W49hl3t7XcNRtd8BoDMyRKqNM,682
|
|
3
3
|
unitysvc_services/format_data.py,sha256=Jl9Vj3fRX852fHSUa5DzO-oiFQwuQHC3WMCDNIlo1Lc,5460
|
4
4
|
unitysvc_services/list.py,sha256=QDp9BByaoeFeJxXJN9RQ-jU99mH9Guq9ampfXCbpZmI,7033
|
5
5
|
unitysvc_services/populate.py,sha256=zkcjIy8BWuQSO7JwiRNHKgGoxQvc3ujluUQdYixdBvY,6626
|
6
|
-
unitysvc_services/publisher.py,sha256=
|
6
|
+
unitysvc_services/publisher.py,sha256=hRqbN9rXeFLgfsjK9ViFQjPNbYR3trcqanPUecjcSjM,35567
|
7
7
|
unitysvc_services/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
unitysvc_services/query.py,sha256=
|
8
|
+
unitysvc_services/query.py,sha256=yfCIMTjQwantf9LxktpRcE05qrBIKQMkanpb9JYYsi0,24228
|
9
9
|
unitysvc_services/scaffold.py,sha256=Y73IX8vskImxSvxDgR0mvEFuAMYnBKfttn3bjcz3jmQ,40331
|
10
10
|
unitysvc_services/update.py,sha256=K9swocTUnqqiSgARo6GmuzTzUySSpyqqPPW4xF7ZU-g,9659
|
11
11
|
unitysvc_services/utils.py,sha256=GN0gkVTU8fOx2G0EbqnWmx8w9eFsoPfRprPjwCyPYkE,11371
|
@@ -16,9 +16,9 @@ unitysvc_services/models/listing_v1.py,sha256=CC_GXoN3NHJFzEQ3cBHDQpdUaBNpvLdHAR
|
|
16
16
|
unitysvc_services/models/provider_v1.py,sha256=cYK5kDDmzQEnLvUC2C8dKz-ZXci7hVn3fjNrJkaSr10,2050
|
17
17
|
unitysvc_services/models/seller_v1.py,sha256=SU4rqYAh9hE4EeUrEkqaVrLwusenV7MotPF77VcsRKo,3263
|
18
18
|
unitysvc_services/models/service_v1.py,sha256=u16zqM3khrJoTw_v0d45tMcKXjko5k_v3w8xwUtZ6nM,2720
|
19
|
-
unitysvc_services-0.2.
|
20
|
-
unitysvc_services-0.2.
|
21
|
-
unitysvc_services-0.2.
|
22
|
-
unitysvc_services-0.2.
|
23
|
-
unitysvc_services-0.2.
|
24
|
-
unitysvc_services-0.2.
|
19
|
+
unitysvc_services-0.2.4.dist-info/licenses/LICENSE,sha256=_p8V6A8OMPu2HIztn3O01v0-urZFwk0Dd3Yk_PTIlL8,1065
|
20
|
+
unitysvc_services-0.2.4.dist-info/METADATA,sha256=FmrqIeMrb31pjtn7u0RyBz-tn-acfTo0omSIqLLwdNg,6628
|
21
|
+
unitysvc_services-0.2.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
22
|
+
unitysvc_services-0.2.4.dist-info/entry_points.txt,sha256=-vodnbPmo7QQmFu8jdG6sCyGRVM727w9Nhwp4Vwau_k,64
|
23
|
+
unitysvc_services-0.2.4.dist-info/top_level.txt,sha256=GIotQj-Ro2ruR7eupM1r58PWqIHTAq647ORL7E2kneo,18
|
24
|
+
unitysvc_services-0.2.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|