jsonstat-validator 0.1.1__tar.gz → 0.1.3__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.
- {jsonstat_validator-0.1.1/jsonstat_validator.egg-info → jsonstat_validator-0.1.3}/PKG-INFO +3 -1
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/README.md +2 -0
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/jsonstat_validator/validator.py +130 -5
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3/jsonstat_validator.egg-info}/PKG-INFO +3 -1
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/pyproject.toml +1 -1
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/LICENSE +0 -0
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/MANIFEST.in +0 -0
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/jsonstat_validator/__init__.py +0 -0
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/jsonstat_validator.egg-info/SOURCES.txt +0 -0
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/jsonstat_validator.egg-info/dependency_links.txt +0 -0
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/jsonstat_validator.egg-info/requires.txt +0 -0
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/jsonstat_validator.egg-info/top_level.txt +0 -0
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/requirements.txt +0 -0
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/setup.cfg +0 -0
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/setup.py +0 -0
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/tests/test_custom.py +0 -0
- {jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/tests/test_official_samples.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: jsonstat-validator
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.3
|
4
4
|
Summary: A Python validator for the JSON-stat 2.0 standard format, based on Pydantic.
|
5
5
|
Author-email: Ahmed Hassan <ahmedhassan.ahmed@fao.org>
|
6
6
|
License: # MIT License
|
@@ -76,6 +76,8 @@ Please note that this implementation is intentionally more strict than the offic
|
|
76
76
|
|
77
77
|
This dataset would be considered valid by the official JSON-stat validator tool, but will fail validation in this package because it violates the rule in the `dataset.size` section of the specification stating that: `size has the same number of elements and in the same order as in id`.
|
78
78
|
|
79
|
+
Additionally, we enforce the `role` field as required when class=`dataset`.
|
80
|
+
|
79
81
|
## Table of Contents
|
80
82
|
|
81
83
|
- [Installation](#installation)
|
@@ -23,6 +23,8 @@ Please note that this implementation is intentionally more strict than the offic
|
|
23
23
|
|
24
24
|
This dataset would be considered valid by the official JSON-stat validator tool, but will fail validation in this package because it violates the rule in the `dataset.size` section of the specification stating that: `size has the same number of elements and in the same order as in id`.
|
25
25
|
|
26
|
+
Additionally, we enforce the `role` field as required when class=`dataset`.
|
27
|
+
|
26
28
|
## Table of Contents
|
27
29
|
|
28
30
|
- [Installation](#installation)
|
@@ -177,6 +177,15 @@ class Category(JSONStatBaseModel):
|
|
177
177
|
if not self.index and not self.label:
|
178
178
|
raise ValueError("At least one of `index` or `label` is required.")
|
179
179
|
|
180
|
+
# Ensure index and label have the same keys if both are dictionaries
|
181
|
+
if self.index and self.label:
|
182
|
+
if isinstance(self.index, dict) and isinstance(self.label, dict):
|
183
|
+
if set(self.index.keys()) != set(self.label.keys()):
|
184
|
+
raise ValueError(
|
185
|
+
"If `index` and `label` are both dictionaries, "
|
186
|
+
"they must have the same keys."
|
187
|
+
)
|
188
|
+
|
180
189
|
# Ensure coordinates are a dictionary where keys are category IDs
|
181
190
|
# and values are an array of two numbers (longitude, latitude).
|
182
191
|
if self.coordinates:
|
@@ -300,7 +309,7 @@ class Dimension(JSONStatBaseModel):
|
|
300
309
|
default=None,
|
301
310
|
description=(
|
302
311
|
"It is used to provide a list of links related to a dataset or a dimension, "
|
303
|
-
"sorted by relation (see
|
312
|
+
"sorted by relation (see https://json-stat.org/full/#relationid)."
|
304
313
|
),
|
305
314
|
)
|
306
315
|
note: Optional[List[str]] = Field(
|
@@ -344,6 +353,113 @@ class Dimension(JSONStatBaseModel):
|
|
344
353
|
return v
|
345
354
|
|
346
355
|
|
356
|
+
class DatasetDimension(JSONStatBaseModel):
|
357
|
+
"""Dataset dimension.
|
358
|
+
|
359
|
+
A dimension model for when the dimension is a child of a Dataset
|
360
|
+
as it has different validation rules than a root Dimension.
|
361
|
+
"""
|
362
|
+
|
363
|
+
version: Optional[str] = Field(
|
364
|
+
default=None,
|
365
|
+
description=(
|
366
|
+
"It declares the JSON-stat version of the response. The goal "
|
367
|
+
"of this property is to help clients parsing that particular response."
|
368
|
+
),
|
369
|
+
)
|
370
|
+
class_: Optional[str] = Field(
|
371
|
+
default="dataset_dimension",
|
372
|
+
alias="class",
|
373
|
+
description=(
|
374
|
+
"JSON-stat supports several classes of responses. "
|
375
|
+
"Possible values of class are: dataset, dimension and collection. "
|
376
|
+
"This is an addition to the standard JSON-stat classes to allow for "
|
377
|
+
"different validation rules for dataset dimensions."
|
378
|
+
),
|
379
|
+
exclude=True,
|
380
|
+
init=False,
|
381
|
+
frozen=True,
|
382
|
+
)
|
383
|
+
label: Optional[str] = Field(
|
384
|
+
default=None,
|
385
|
+
description=(
|
386
|
+
"It is used to assign a very short (one line) descriptive text to IDs "
|
387
|
+
"at different levels of the response tree. It is language-dependent."
|
388
|
+
),
|
389
|
+
)
|
390
|
+
category: Optional[Category] = Field(
|
391
|
+
default=None,
|
392
|
+
description=(
|
393
|
+
"It is used to describe the possible values of a dimension. "
|
394
|
+
"It is language-dependent."
|
395
|
+
),
|
396
|
+
)
|
397
|
+
href: Optional[AnyUrl] = Field(
|
398
|
+
default=None,
|
399
|
+
description=(
|
400
|
+
"It specifies a URL. Providers can use this property to avoid "
|
401
|
+
"sending information that is shared between different requests "
|
402
|
+
"(for example, dimensions)."
|
403
|
+
),
|
404
|
+
)
|
405
|
+
link: Optional[Dict[str, List[Union[Link, JSONStatSchema]]]] = Field(
|
406
|
+
default=None,
|
407
|
+
description=(
|
408
|
+
"It is used to provide a list of links related to a dataset or a dimension, "
|
409
|
+
"sorted by relation (see https://json-stat.org/full/#relationid)."
|
410
|
+
),
|
411
|
+
)
|
412
|
+
note: Optional[List[str]] = Field(
|
413
|
+
default=None,
|
414
|
+
description=(
|
415
|
+
"Note allows to assign annotations to datasets (array), dimensions (array) "
|
416
|
+
"and categories (object)."
|
417
|
+
),
|
418
|
+
)
|
419
|
+
updated: Optional[str] = Field(
|
420
|
+
default=None,
|
421
|
+
description=(
|
422
|
+
"It contains the update time of the dataset. It is a string representing "
|
423
|
+
"a date in an ISO 8601 format recognized by the Javascript Date.parse "
|
424
|
+
"method (see ECMA-262 Date Time String Format: "
|
425
|
+
"https://262.ecma-international.org/6.0/#sec-date-time-string-format)."
|
426
|
+
),
|
427
|
+
)
|
428
|
+
source: Optional[str] = Field(
|
429
|
+
default=None,
|
430
|
+
description=(
|
431
|
+
"It contains a language-dependent short text describing the source "
|
432
|
+
"of the dataset."
|
433
|
+
),
|
434
|
+
)
|
435
|
+
extension: Optional[Dict[str, Any]] = Field(
|
436
|
+
default=None,
|
437
|
+
description=(
|
438
|
+
"Extension allows JSON-stat to be extended for particular needs. "
|
439
|
+
"Providers are free to define where they include this property and "
|
440
|
+
"what children are allowed in each case."
|
441
|
+
),
|
442
|
+
)
|
443
|
+
|
444
|
+
@field_validator("updated", mode="after")
|
445
|
+
@classmethod
|
446
|
+
def validate_updated_date(cls, v: Optional[str]):
|
447
|
+
"""Validates the updated date is in ISO 8601 format."""
|
448
|
+
if v and not is_valid_iso_date(v):
|
449
|
+
raise ValueError(f"Updated date: '{v}' is an invalid ISO 8601 format.")
|
450
|
+
return v
|
451
|
+
|
452
|
+
@model_validator(mode="after")
|
453
|
+
def validate_dataset_dimension(self):
|
454
|
+
"""Dataset dimension-wide validation checks."""
|
455
|
+
if not self.category and not self.href:
|
456
|
+
raise ValueError(
|
457
|
+
"A category is required if a reference (href) is not provided."
|
458
|
+
"For an example, see: https://json-stat.org/full/#href"
|
459
|
+
)
|
460
|
+
return self
|
461
|
+
|
462
|
+
|
347
463
|
class DatasetRole(JSONStatBaseModel):
|
348
464
|
"""Role of a dataset."""
|
349
465
|
|
@@ -372,6 +488,13 @@ class DatasetRole(JSONStatBaseModel):
|
|
372
488
|
),
|
373
489
|
)
|
374
490
|
|
491
|
+
@model_validator(mode="after")
|
492
|
+
def validate_dataset_role(self):
|
493
|
+
"""Dataset role-wide validation checks."""
|
494
|
+
if not self.time and not self.geo and not self.metric:
|
495
|
+
raise ValueError("At least one role must be provided.")
|
496
|
+
return self
|
497
|
+
|
375
498
|
|
376
499
|
class Dataset(JSONStatBaseModel):
|
377
500
|
"""JSON-stat dataset."""
|
@@ -430,12 +553,13 @@ class Dataset(JSONStatBaseModel):
|
|
430
553
|
"and in the same order as in id."
|
431
554
|
),
|
432
555
|
)
|
433
|
-
role:
|
556
|
+
role: DatasetRole = Field(
|
434
557
|
default=None,
|
435
558
|
description=(
|
436
559
|
"It can be used to assign special roles to dimensions. "
|
437
560
|
"At this moment, possible roles are: time, geo and metric. "
|
438
561
|
"A role can be shared by several dimensions."
|
562
|
+
"We differ from the specification in that the role is required, not optional"
|
439
563
|
),
|
440
564
|
)
|
441
565
|
value: Union[
|
@@ -457,10 +581,11 @@ class Dataset(JSONStatBaseModel):
|
|
457
581
|
),
|
458
582
|
)
|
459
583
|
|
460
|
-
dimension: Dict[str,
|
584
|
+
dimension: Dict[str, DatasetDimension] = Field(
|
461
585
|
description=(
|
462
586
|
"The dimension property contains information about the dimensions of "
|
463
|
-
"the dataset. dimension must have properties
|
587
|
+
"the dataset. dimension must have properties "
|
588
|
+
"(see https://json-stat.org/full/#dimensionid) with "
|
464
589
|
"the same names of each element in the id array."
|
465
590
|
),
|
466
591
|
)
|
@@ -483,7 +608,7 @@ class Dataset(JSONStatBaseModel):
|
|
483
608
|
default=None,
|
484
609
|
description=(
|
485
610
|
"It is used to provide a list of links related to a dataset or a dimension, "
|
486
|
-
"sorted by relation (see
|
611
|
+
"sorted by relation (see https://json-stat.org/full/#relationid)."
|
487
612
|
),
|
488
613
|
)
|
489
614
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: jsonstat-validator
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.3
|
4
4
|
Summary: A Python validator for the JSON-stat 2.0 standard format, based on Pydantic.
|
5
5
|
Author-email: Ahmed Hassan <ahmedhassan.ahmed@fao.org>
|
6
6
|
License: # MIT License
|
@@ -76,6 +76,8 @@ Please note that this implementation is intentionally more strict than the offic
|
|
76
76
|
|
77
77
|
This dataset would be considered valid by the official JSON-stat validator tool, but will fail validation in this package because it violates the rule in the `dataset.size` section of the specification stating that: `size has the same number of elements and in the same order as in id`.
|
78
78
|
|
79
|
+
Additionally, we enforce the `role` field as required when class=`dataset`.
|
80
|
+
|
79
81
|
## Table of Contents
|
80
82
|
|
81
83
|
- [Installation](#installation)
|
File without changes
|
File without changes
|
File without changes
|
{jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/jsonstat_validator.egg-info/SOURCES.txt
RENAMED
File without changes
|
File without changes
|
{jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/jsonstat_validator.egg-info/requires.txt
RENAMED
File without changes
|
{jsonstat_validator-0.1.1 → jsonstat_validator-0.1.3}/jsonstat_validator.egg-info/top_level.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|