unitysvc-services 0.2.6__py3-none-any.whl → 0.3.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/models/base.py +123 -0
- unitysvc_services/models/listing_v1.py +24 -2
- unitysvc_services/models/provider_v1.py +17 -2
- unitysvc_services/models/seller_v1.py +8 -2
- unitysvc_services/models/service_v1.py +8 -1
- unitysvc_services/publisher.py +510 -147
- unitysvc_services/query.py +3 -3
- unitysvc_services/validator.py +79 -23
- {unitysvc_services-0.2.6.dist-info → unitysvc_services-0.3.0.dist-info}/METADATA +1 -1
- unitysvc_services-0.3.0.dist-info/RECORD +24 -0
- unitysvc_services-0.2.6.dist-info/RECORD +0 -24
- {unitysvc_services-0.2.6.dist-info → unitysvc_services-0.3.0.dist-info}/WHEEL +0 -0
- {unitysvc_services-0.2.6.dist-info → unitysvc_services-0.3.0.dist-info}/entry_points.txt +0 -0
- {unitysvc_services-0.2.6.dist-info → unitysvc_services-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {unitysvc_services-0.2.6.dist-info → unitysvc_services-0.3.0.dist-info}/top_level.txt +0 -0
unitysvc_services/query.py
CHANGED
@@ -421,7 +421,7 @@ def query_offerings(
|
|
421
421
|
help="Output format: table, json",
|
422
422
|
),
|
423
423
|
fields: str = typer.Option(
|
424
|
-
"id,
|
424
|
+
"id,name,service_type,provider_name,status",
|
425
425
|
"--fields",
|
426
426
|
help=(
|
427
427
|
"Comma-separated list of fields to display. Available fields: "
|
@@ -447,7 +447,7 @@ def query_offerings(
|
|
447
447
|
unitysvc_services query offerings
|
448
448
|
|
449
449
|
# Show only specific fields
|
450
|
-
unitysvc_services query offerings --fields id,
|
450
|
+
unitysvc_services query offerings --fields id,name,status
|
451
451
|
|
452
452
|
# Retrieve more than 100 records
|
453
453
|
unitysvc_services query offerings --limit 500
|
@@ -469,7 +469,7 @@ def query_offerings(
|
|
469
469
|
"provider_id",
|
470
470
|
"status",
|
471
471
|
"price",
|
472
|
-
"
|
472
|
+
"name",
|
473
473
|
"service_type",
|
474
474
|
"provider_name",
|
475
475
|
}
|
unitysvc_services/validator.py
CHANGED
@@ -205,6 +205,54 @@ class DataValidator:
|
|
205
205
|
normalized = normalized.strip("-")
|
206
206
|
return normalized
|
207
207
|
|
208
|
+
def validate_with_pydantic_model(self, data: dict[str, Any], schema_name: str) -> list[str]:
|
209
|
+
"""
|
210
|
+
Validate data using Pydantic models for additional validation rules.
|
211
|
+
|
212
|
+
This complements JSON schema validation with Pydantic field validators
|
213
|
+
like name format validation.
|
214
|
+
|
215
|
+
Args:
|
216
|
+
data: The data to validate
|
217
|
+
schema_name: The schema name (e.g., 'provider_v1', 'seller_v1')
|
218
|
+
|
219
|
+
Returns:
|
220
|
+
List of validation error messages
|
221
|
+
"""
|
222
|
+
from pydantic import BaseModel
|
223
|
+
|
224
|
+
from unitysvc_services.models import ListingV1, ProviderV1, SellerV1, ServiceV1
|
225
|
+
|
226
|
+
errors: list[str] = []
|
227
|
+
|
228
|
+
# Map schema names to Pydantic model classes
|
229
|
+
model_map: dict[str, type[BaseModel]] = {
|
230
|
+
"provider_v1": ProviderV1,
|
231
|
+
"seller_v1": SellerV1,
|
232
|
+
"service_v1": ServiceV1,
|
233
|
+
"listing_v1": ListingV1,
|
234
|
+
}
|
235
|
+
|
236
|
+
if schema_name not in model_map:
|
237
|
+
return errors # No Pydantic model for this schema
|
238
|
+
|
239
|
+
model_class = model_map[schema_name]
|
240
|
+
|
241
|
+
try:
|
242
|
+
# Validate using the Pydantic model
|
243
|
+
model_class.model_validate(data)
|
244
|
+
|
245
|
+
except Exception as e:
|
246
|
+
# Extract meaningful error message from Pydantic ValidationError
|
247
|
+
error_msg = str(e)
|
248
|
+
# Pydantic errors can be verbose, try to extract just the relevant part
|
249
|
+
if "validation error" in error_msg.lower():
|
250
|
+
errors.append(f"Pydantic validation error: {error_msg}")
|
251
|
+
else:
|
252
|
+
errors.append(error_msg)
|
253
|
+
|
254
|
+
return errors
|
255
|
+
|
208
256
|
def load_data_file(self, file_path: Path) -> tuple[dict[str, Any] | None, list[str]]:
|
209
257
|
"""Load data from JSON or TOML file."""
|
210
258
|
errors: list[str] = []
|
@@ -259,6 +307,10 @@ class DataValidator:
|
|
259
307
|
except Exception as e:
|
260
308
|
errors.append(f"Validation error: {e}")
|
261
309
|
|
310
|
+
# Also validate using Pydantic models for additional validation rules
|
311
|
+
pydantic_errors = self.validate_with_pydantic_model(data, schema_name)
|
312
|
+
errors.extend(pydantic_errors)
|
313
|
+
|
262
314
|
# Find Union[str, HttpUrl] fields and validate file references
|
263
315
|
union_fields = self.find_union_fields(schema)
|
264
316
|
file_ref_errors = self.validate_file_references(data, file_path, union_fields)
|
@@ -308,6 +360,10 @@ class DataValidator:
|
|
308
360
|
|
309
361
|
# Find all data files with seller_v1 schema
|
310
362
|
for file_path in self.data_dir.rglob("*"):
|
363
|
+
# Skip hidden directories (those starting with .)
|
364
|
+
if any(part.startswith(".") for part in file_path.parts):
|
365
|
+
continue
|
366
|
+
|
311
367
|
if file_path.is_file() and file_path.suffix in [".json", ".toml"]:
|
312
368
|
try:
|
313
369
|
data, load_errors = self.load_data_file(file_path)
|
@@ -341,20 +397,17 @@ class DataValidator:
|
|
341
397
|
|
342
398
|
warnings: list[str] = []
|
343
399
|
|
344
|
-
# Find all provider files
|
345
|
-
provider_files =
|
400
|
+
# Find all provider files (skip hidden directories)
|
401
|
+
provider_files = [
|
402
|
+
f for f in self.data_dir.glob("*/provider.*") if not any(part.startswith(".") for part in f.parts)
|
403
|
+
]
|
346
404
|
|
347
405
|
for provider_file in provider_files:
|
348
406
|
try:
|
349
|
-
# Load provider data
|
350
|
-
data =
|
351
|
-
if
|
352
|
-
|
353
|
-
data = json.load(f)
|
354
|
-
elif provider_file.suffix == ".toml":
|
355
|
-
with open(provider_file, "rb") as f:
|
356
|
-
data = toml.load(f)
|
357
|
-
else:
|
407
|
+
# Load provider data using existing helper method
|
408
|
+
data, load_errors = self.load_data_file(provider_file)
|
409
|
+
if load_errors or data is None:
|
410
|
+
warnings.append(f"Failed to load provider file {provider_file}: {load_errors}")
|
358
411
|
continue
|
359
412
|
|
360
413
|
# Parse as ProviderV1
|
@@ -391,20 +444,15 @@ class DataValidator:
|
|
391
444
|
|
392
445
|
warnings: list[str] = []
|
393
446
|
|
394
|
-
# Find all seller files
|
395
|
-
seller_files =
|
447
|
+
# Find all seller files (skip hidden files)
|
448
|
+
seller_files = [f for f in self.data_dir.glob("seller.*") if not f.name.startswith(".")]
|
396
449
|
|
397
450
|
for seller_file in seller_files:
|
398
451
|
try:
|
399
|
-
# Load seller data
|
400
|
-
data =
|
401
|
-
if
|
402
|
-
|
403
|
-
data = json.load(f)
|
404
|
-
elif seller_file.suffix == ".toml":
|
405
|
-
with open(seller_file, "rb") as f:
|
406
|
-
data = toml.load(f)
|
407
|
-
else:
|
452
|
+
# Load seller data using existing helper method
|
453
|
+
data, load_errors = self.load_data_file(seller_file)
|
454
|
+
if load_errors or data is None:
|
455
|
+
warnings.append(f"Failed to load seller file {seller_file}: {load_errors}")
|
408
456
|
continue
|
409
457
|
|
410
458
|
# Parse as SellerV1
|
@@ -448,8 +496,12 @@ class DataValidator:
|
|
448
496
|
provider_warnings,
|
449
497
|
) # Warnings, not errors
|
450
498
|
|
451
|
-
# Find all data and MD files recursively
|
499
|
+
# Find all data and MD files recursively, skipping hidden directories
|
452
500
|
for file_path in self.data_dir.rglob("*"):
|
501
|
+
# Skip hidden directories (those starting with .)
|
502
|
+
if any(part.startswith(".") for part in file_path.parts):
|
503
|
+
continue
|
504
|
+
|
453
505
|
if file_path.is_file() and file_path.suffix in [".json", ".toml", ".md"]:
|
454
506
|
relative_path = file_path.relative_to(self.data_dir)
|
455
507
|
|
@@ -560,6 +612,10 @@ class DataValidator:
|
|
560
612
|
|
561
613
|
for pattern in ["*.json", "*.toml"]:
|
562
614
|
for file_path in data_dir.rglob(pattern):
|
615
|
+
# Skip hidden directories (those starting with .)
|
616
|
+
if any(part.startswith(".") for part in file_path.parts):
|
617
|
+
continue
|
618
|
+
|
563
619
|
try:
|
564
620
|
data, load_errors = self.load_data_file(file_path)
|
565
621
|
if load_errors or data is None:
|
@@ -0,0 +1,24 @@
|
|
1
|
+
unitysvc_services/__init__.py,sha256=J6F3RlZCJUVjhZoprfbrYCxe3l9ynQQbGO7pf7FyqlM,110
|
2
|
+
unitysvc_services/cli.py,sha256=OK0IZyAckxP15jRWU_W49hl3t7XcNRtd8BoDMyRKqNM,682
|
3
|
+
unitysvc_services/format_data.py,sha256=Jl9Vj3fRX852fHSUa5DzO-oiFQwuQHC3WMCDNIlo1Lc,5460
|
4
|
+
unitysvc_services/list.py,sha256=QDp9BByaoeFeJxXJN9RQ-jU99mH9Guq9ampfXCbpZmI,7033
|
5
|
+
unitysvc_services/populate.py,sha256=zkcjIy8BWuQSO7JwiRNHKgGoxQvc3ujluUQdYixdBvY,6626
|
6
|
+
unitysvc_services/publisher.py,sha256=sNqGbLQ3QulNCGzyRjBg6ks-I2nTVgip4vGFV4XCUto,52285
|
7
|
+
unitysvc_services/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
+
unitysvc_services/query.py,sha256=x2VUnfva21-mVd-JgtChajNBgXG1AQJ6c3umCw2FNWU,24089
|
9
|
+
unitysvc_services/scaffold.py,sha256=Y73IX8vskImxSvxDgR0mvEFuAMYnBKfttn3bjcz3jmQ,40331
|
10
|
+
unitysvc_services/update.py,sha256=K9swocTUnqqiSgARo6GmuzTzUySSpyqqPPW4xF7ZU-g,9659
|
11
|
+
unitysvc_services/utils.py,sha256=GN0gkVTU8fOx2G0EbqnWmx8w9eFsoPfRprPjwCyPYkE,11371
|
12
|
+
unitysvc_services/validator.py,sha256=VAII5mu_Jdyr96v4nwXzihsoAj7DJiXN6LjhL8lGGUo,29054
|
13
|
+
unitysvc_services/models/__init__.py,sha256=hJCc2KSZmIHlKWKE6GpLGdeVB6LIpyVUKiOKnwmKvCs,200
|
14
|
+
unitysvc_services/models/base.py,sha256=3FdlR-_tBOFC2JbVNFNQA4-D1Lhlo5UZQh1QDgKnS_I,18293
|
15
|
+
unitysvc_services/models/listing_v1.py,sha256=PPb9hIdWQp80AWKLxFXYBDcWXzNcDrO4v6rqt5_i2qo,3083
|
16
|
+
unitysvc_services/models/provider_v1.py,sha256=76EK1i0hVtdx_awb00-ZMtSj4Oc9Zp4xZ-DeXmG3iTY,2701
|
17
|
+
unitysvc_services/models/seller_v1.py,sha256=oll2ZZBPBDX8wslHrbsCKf_jIqHNte2VEj5RJ9bawR4,3520
|
18
|
+
unitysvc_services/models/service_v1.py,sha256=Xpk-K-95M1LRqYM8nNJcll8t-lsW9Xdi2_bVbYNs8-M,3019
|
19
|
+
unitysvc_services-0.3.0.dist-info/licenses/LICENSE,sha256=_p8V6A8OMPu2HIztn3O01v0-urZFwk0Dd3Yk_PTIlL8,1065
|
20
|
+
unitysvc_services-0.3.0.dist-info/METADATA,sha256=QPZzgXqlKCPdsJCuWnbxxcXe7sfk-SBTxCJbq2npEc8,6628
|
21
|
+
unitysvc_services-0.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
22
|
+
unitysvc_services-0.3.0.dist-info/entry_points.txt,sha256=-vodnbPmo7QQmFu8jdG6sCyGRVM727w9Nhwp4Vwau_k,64
|
23
|
+
unitysvc_services-0.3.0.dist-info/top_level.txt,sha256=GIotQj-Ro2ruR7eupM1r58PWqIHTAq647ORL7E2kneo,18
|
24
|
+
unitysvc_services-0.3.0.dist-info/RECORD,,
|
@@ -1,24 +0,0 @@
|
|
1
|
-
unitysvc_services/__init__.py,sha256=J6F3RlZCJUVjhZoprfbrYCxe3l9ynQQbGO7pf7FyqlM,110
|
2
|
-
unitysvc_services/cli.py,sha256=OK0IZyAckxP15jRWU_W49hl3t7XcNRtd8BoDMyRKqNM,682
|
3
|
-
unitysvc_services/format_data.py,sha256=Jl9Vj3fRX852fHSUa5DzO-oiFQwuQHC3WMCDNIlo1Lc,5460
|
4
|
-
unitysvc_services/list.py,sha256=QDp9BByaoeFeJxXJN9RQ-jU99mH9Guq9ampfXCbpZmI,7033
|
5
|
-
unitysvc_services/populate.py,sha256=zkcjIy8BWuQSO7JwiRNHKgGoxQvc3ujluUQdYixdBvY,6626
|
6
|
-
unitysvc_services/publisher.py,sha256=s3px0i1ov6FisnnYG-gkkMHwJhnGbf-Ug225vosfxxM,35733
|
7
|
-
unitysvc_services/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
unitysvc_services/query.py,sha256=Fz7ZXm_TOf2BVZsTUKGp61OArAjhChpdJsBUFDGaOrA,24113
|
9
|
-
unitysvc_services/scaffold.py,sha256=Y73IX8vskImxSvxDgR0mvEFuAMYnBKfttn3bjcz3jmQ,40331
|
10
|
-
unitysvc_services/update.py,sha256=K9swocTUnqqiSgARo6GmuzTzUySSpyqqPPW4xF7ZU-g,9659
|
11
|
-
unitysvc_services/utils.py,sha256=GN0gkVTU8fOx2G0EbqnWmx8w9eFsoPfRprPjwCyPYkE,11371
|
12
|
-
unitysvc_services/validator.py,sha256=zuFA44ezKlfUTtdJ8M2Xd7nk1Eot4HxbBksEUaIIpZs,26790
|
13
|
-
unitysvc_services/models/__init__.py,sha256=hJCc2KSZmIHlKWKE6GpLGdeVB6LIpyVUKiOKnwmKvCs,200
|
14
|
-
unitysvc_services/models/base.py,sha256=gm3xlcC35QNRST5ikJPhdk-dTTXoY9D_5Jxkyt8SBCU,13173
|
15
|
-
unitysvc_services/models/listing_v1.py,sha256=FJWRMdouz3NgiNI6E4uBxG1V_Cbb249NpKyKgvAwtRM,2450
|
16
|
-
unitysvc_services/models/provider_v1.py,sha256=cYK5kDDmzQEnLvUC2C8dKz-ZXci7hVn3fjNrJkaSr10,2050
|
17
|
-
unitysvc_services/models/seller_v1.py,sha256=SU4rqYAh9hE4EeUrEkqaVrLwusenV7MotPF77VcsRKo,3263
|
18
|
-
unitysvc_services/models/service_v1.py,sha256=u16zqM3khrJoTw_v0d45tMcKXjko5k_v3w8xwUtZ6nM,2720
|
19
|
-
unitysvc_services-0.2.6.dist-info/licenses/LICENSE,sha256=_p8V6A8OMPu2HIztn3O01v0-urZFwk0Dd3Yk_PTIlL8,1065
|
20
|
-
unitysvc_services-0.2.6.dist-info/METADATA,sha256=AjeLF0eSLtzkflQsrL3GP99DdZ853cfsZfWksap6AWw,6628
|
21
|
-
unitysvc_services-0.2.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
22
|
-
unitysvc_services-0.2.6.dist-info/entry_points.txt,sha256=-vodnbPmo7QQmFu8jdG6sCyGRVM727w9Nhwp4Vwau_k,64
|
23
|
-
unitysvc_services-0.2.6.dist-info/top_level.txt,sha256=GIotQj-Ro2ruR7eupM1r58PWqIHTAq647ORL7E2kneo,18
|
24
|
-
unitysvc_services-0.2.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|