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.
Files changed (34) hide show
  1. {cof_cli-1.0.0 → cof_cli-1.0.1}/PKG-INFO +1 -1
  2. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/__init__.py +1 -1
  3. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/model.py +7 -1
  4. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/validate.py +11 -0
  5. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli.egg-info/PKG-INFO +1 -1
  6. {cof_cli-1.0.0 → cof_cli-1.0.1}/pyproject.toml +1 -1
  7. {cof_cli-1.0.0 → cof_cli-1.0.1}/tests/test_roundtrip.py +40 -0
  8. {cof_cli-1.0.0 → cof_cli-1.0.1}/README.md +0 -0
  9. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/cli.py +0 -0
  10. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/completeness.py +0 -0
  11. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/container.py +0 -0
  12. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/convert.py +0 -0
  13. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/migrate.py +0 -0
  14. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/ops.py +0 -0
  15. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/attitude.schema.json +0 -0
  16. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/body.schema.json +0 -0
  17. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/card.schema.json +0 -0
  18. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/consent.schema.json +0 -0
  19. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/garments-1.0.json +0 -0
  20. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/hair.schema.json +0 -0
  21. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/manifest.schema.json +0 -0
  22. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/pose.schema.json +0 -0
  23. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/psyche.schema.json +0 -0
  24. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/skeleton.schema.json +0 -0
  25. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/visemes.schema.json +0 -0
  26. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/voice-profile.schema.json +0 -0
  27. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/schemas/weights.schema.json +0 -0
  28. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli/tokens.py +0 -0
  29. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli.egg-info/SOURCES.txt +0 -0
  30. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli.egg-info/dependency_links.txt +0 -0
  31. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli.egg-info/entry_points.txt +0 -0
  32. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli.egg-info/requires.txt +0 -0
  33. {cof_cli-1.0.0 → cof_cli-1.0.1}/cof_cli.egg-info/top_level.txt +0 -0
  34. {cof_cli-1.0.0 → cof_cli-1.0.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cof-cli
3
- Version: 1.0.0
3
+ Version: 1.0.1
4
4
  Summary: COF — Character Open File: validate, pack, unpack and convert .cof character containers
5
5
  Author: Yann Souetre
6
6
  License-Expression: MIT
@@ -1,5 +1,5 @@
1
1
  """cof-cli — reference tooling for COF (Character Open File)."""
2
2
 
3
- __version__ = "1.0.0"
3
+ __version__ = "1.0.1"
4
4
  MIMETYPE = "application/vnd.cof.character+zip"
5
5
  SPEC_VERSION = "1.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 in LIBRARY_CATEGORIES:
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"):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cof-cli
3
- Version: 1.0.0
3
+ Version: 1.0.1
4
4
  Summary: COF — Character Open File: validate, pack, unpack and convert .cof character containers
5
5
  Author: Yann Souetre
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cof-cli"
7
- version = "1.0.0"
7
+ version = "1.0.1"
8
8
  description = "COF — Character Open File: validate, pack, unpack and convert .cof character containers"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -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