cof-cli 1.0.0__tar.gz → 1.0.1__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.
- {cof_cli-1.0.0 → cof_cli-1.0.1}/PKG-INFO +1 -1
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/__init__.py +1 -1
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/model.py +7 -1
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/validate.py +11 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli.egg-info/PKG-INFO +1 -1
- {cof_cli-1.0.0 → cof_cli-1.0.1}/pyproject.toml +1 -1
- {cof_cli-1.0.0 → cof_cli-1.0.1}/tests/test_roundtrip.py +40 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/README.md +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/cli.py +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/completeness.py +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/container.py +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/convert.py +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/migrate.py +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/ops.py +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/attitude.schema.json +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/body.schema.json +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/card.schema.json +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/consent.schema.json +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/garments-1.0.json +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/hair.schema.json +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/manifest.schema.json +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/pose.schema.json +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/psyche.schema.json +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/skeleton.schema.json +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/visemes.schema.json +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/voice-profile.schema.json +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/weights.schema.json +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/tokens.py +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli.egg-info/SOURCES.txt +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli.egg-info/dependency_links.txt +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli.egg-info/entry_points.txt +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli.egg-info/requires.txt +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli.egg-info/top_level.txt +0 -0
- {cof_cli-1.0.0 → cof_cli-1.0.1}/setup.cfg +0 -0
|
@@ -17,6 +17,12 @@ KINDS = {
|
|
|
17
17
|
}
|
|
18
18
|
# categories that are LIBRARIES in a preset: several variants of any kind, none mandatory at inference
|
|
19
19
|
LIBRARY_CATEGORIES = {"posture", "motion", "files"}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def is_library(cat: str) -> bool:
|
|
23
|
+
"""Library regime (SPEC § 2.3): posture, motion, files — and every category this version does not know
|
|
24
|
+
(`x-` categories, and categories added by a later 1.x minor), which are libraries unless an RFC says otherwise."""
|
|
25
|
+
return cat in LIBRARY_CATEGORIES or cat not in CATEGORIES
|
|
20
26
|
# kinds that may appear several times in one preset (subject to region rules)
|
|
21
27
|
MULTI_KINDS = {"clothing", "accessory", "pilosity", "feature", "environment"}
|
|
22
28
|
|
|
@@ -452,7 +458,7 @@ def region_conflicts(res: dict[str, list[dict]]) -> list[str]:
|
|
|
452
458
|
def single_kind_violations(res: dict[str, list[dict]]) -> list[str]:
|
|
453
459
|
out = []
|
|
454
460
|
for cat, lst in res.items():
|
|
455
|
-
if cat
|
|
461
|
+
if is_library(cat):
|
|
456
462
|
continue
|
|
457
463
|
seen = {}
|
|
458
464
|
for v in lst:
|
|
@@ -180,12 +180,23 @@ def validate_manifest(manifest: dict, rep: Report, newer: bool = False) -> None:
|
|
|
180
180
|
loc = "/".join(str(p) for p in e.path) or "(root)"
|
|
181
181
|
if newer and (e.validator == "enum" or (e.validator == "additionalProperties")):
|
|
182
182
|
rep.warnings.append(f"manifest.json [{loc}]: {_schema_msg(e)} (value or field from a later 1.x version — kept, not checked)")
|
|
183
|
+
elif newer and _later_category(e):
|
|
184
|
+
rep.warnings.append(f"manifest.json [{loc}]: category '{e.instance}' comes from a later 1.x version — kept as a library, its variants are not checked")
|
|
183
185
|
elif e.validator == "required" and "'presets'" in e.message:
|
|
184
186
|
rep.errors.append(f"manifest.json [{loc}]: {_schema_msg(e)} — a file declares at least one preset (`cof migrate` adds 'default')")
|
|
185
187
|
else:
|
|
186
188
|
rep.errors.append(f"manifest.json [{loc}]: {_schema_msg(e)}")
|
|
187
189
|
|
|
188
190
|
|
|
191
|
+
def _later_category(e) -> bool:
|
|
192
|
+
"""A key of `elements`, or of a preset's `slots` / `alternatives`, that the 1.0 schema's category pattern rejects:
|
|
193
|
+
in a later-minor file it is a category this validator does not know (SPEC § 12: warn, never refuse)."""
|
|
194
|
+
path = [str(p) for p in e.path]
|
|
195
|
+
if e.validator != "pattern" or not isinstance(e.instance, str):
|
|
196
|
+
return False
|
|
197
|
+
return path == ["elements"] or (len(path) == 3 and path[0] == "presets" and path[2] in ("slots", "alternatives"))
|
|
198
|
+
|
|
199
|
+
|
|
189
200
|
def validate_card(card: dict, rep: Report, lang: str, where: str) -> dict:
|
|
190
201
|
tokens = {}
|
|
191
202
|
if card.get("spec") not in ("chara_card_v3", "chara_card_v2"):
|
|
@@ -812,3 +812,43 @@ def test_age_tags_only_for_human_shapes():
|
|
|
812
812
|
assert "child" not in t and "has-minor-preset" not in t and "mechanical" in t
|
|
813
813
|
t2 = auto_tags(json.loads((ROOT / "spec/examples/02-ecoliere/manifest.json").read_text("utf-8")))
|
|
814
814
|
assert "child" in t2
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
def _with_later_category(m: dict, cat: str) -> dict:
|
|
818
|
+
"""Add a category this validator does not know, with two variants of one kind, listed by the default preset."""
|
|
819
|
+
m["elements"][cat] = {"variants": {"n1": {"kind": "note", "label": "One"}, "n2": {"kind": "note", "label": "Two"}}}
|
|
820
|
+
m["presets"]["default"].setdefault("slots", {})[cat] = ["n1", "n2"]
|
|
821
|
+
return m
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
def test_later_minor_category_is_a_warning_and_a_library(workdir):
|
|
825
|
+
"""SPEC § 12: a validator of an earlier minor treats what a later 1.x adds as a warning, never a reason to refuse;
|
|
826
|
+
SPEC § 2.3: categories it does not know are libraries (several variants of one kind are allowed)."""
|
|
827
|
+
mp = workdir / "manifest.json"
|
|
828
|
+
m = _with_later_category(json.loads(mp.read_text("utf-8")), "sketches")
|
|
829
|
+
m["cof"] = "1.9"
|
|
830
|
+
mp.write_text(json.dumps(m), "utf-8")
|
|
831
|
+
rep = Report()
|
|
832
|
+
validate_dir(workdir, rep, recompute=False)
|
|
833
|
+
assert rep.ok, rep.errors
|
|
834
|
+
assert any("sketches" in w and "later 1.x" in w for w in rep.warnings), rep.warnings
|
|
835
|
+
|
|
836
|
+
|
|
837
|
+
def test_x_category_is_a_library(workdir):
|
|
838
|
+
"""`x-` categories are accepted by the 1.0 schema and are libraries unless an RFC says otherwise (SPEC § 2.3)."""
|
|
839
|
+
mp = workdir / "manifest.json"
|
|
840
|
+
m = _with_later_category(json.loads(mp.read_text("utf-8")), "x-notes")
|
|
841
|
+
mp.write_text(json.dumps(m), "utf-8")
|
|
842
|
+
rep = Report()
|
|
843
|
+
validate_dir(workdir, rep, recompute=False)
|
|
844
|
+
assert rep.ok, rep.errors
|
|
845
|
+
|
|
846
|
+
|
|
847
|
+
def test_unknown_category_in_a_1_0_file_is_an_error(workdir):
|
|
848
|
+
"""A file that declares 1.0 cannot use a category the 1.0 schema does not define."""
|
|
849
|
+
mp = workdir / "manifest.json"
|
|
850
|
+
m = _with_later_category(json.loads(mp.read_text("utf-8")), "sketches")
|
|
851
|
+
mp.write_text(json.dumps(m), "utf-8")
|
|
852
|
+
rep = Report()
|
|
853
|
+
validate_dir(workdir, rep, recompute=False)
|
|
854
|
+
assert not rep.ok and any("sketches" in e for e in rep.errors)
|
|
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
|
|
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
|