magmascript 3.2.3__tar.gz → 3.2.4__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 (101) hide show
  1. {magmascript-3.2.3 → magmascript-3.2.4}/PKG-INFO +2 -1
  2. {magmascript-3.2.3 → magmascript-3.2.4}/README.md +1 -0
  3. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/__init__.py +10 -1
  4. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/cli.py +17 -2
  5. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/archive/client.py +1 -1
  6. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/mcp/client.py +11 -3
  7. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript.egg-info/PKG-INFO +2 -1
  8. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript.egg-info/SOURCES.txt +1 -0
  9. {magmascript-3.2.3 → magmascript-3.2.4}/pyproject.toml +1 -1
  10. {magmascript-3.2.3 → magmascript-3.2.4}/tests/test_cli.py +17 -0
  11. magmascript-3.2.4/tests/test_cli_regressions.py +99 -0
  12. {magmascript-3.2.3 → magmascript-3.2.4}/LICENSE +0 -0
  13. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/codegen/__init__.py +0 -0
  14. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/codegen/c.py +0 -0
  15. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/core/__init__.py +0 -0
  16. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/core/cache.py +0 -0
  17. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/core/command_registry.py +0 -0
  18. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/core/commands.py +0 -0
  19. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/core/config.py +0 -0
  20. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/core/exceptions.py +0 -0
  21. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/core/github.py +0 -0
  22. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/core/output.py +0 -0
  23. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/core/registry.py +0 -0
  24. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/core/rpc.py +0 -0
  25. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/core/runner.py +0 -0
  26. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/__init__.py +0 -0
  27. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/archive/__init__.py +0 -0
  28. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/gh/__init__.py +0 -0
  29. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/gh/client.py +0 -0
  30. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/gh/tools.py +0 -0
  31. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/lastfm/__init__.py +0 -0
  32. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/lastfm/client.py +0 -0
  33. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/mac/__init__.py +0 -0
  34. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/mac/client.py +0 -0
  35. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/mac/tools.py +0 -0
  36. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/mb/__init__.py +0 -0
  37. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/mb/client.py +0 -0
  38. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/mc1/__init__.py +0 -0
  39. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/mc1/client.py +0 -0
  40. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/mc1/tools.py +0 -0
  41. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/mcp/__init__.py +0 -0
  42. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/mcp/tools.py +0 -0
  43. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/media/__init__.py +0 -0
  44. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/media/client.py +0 -0
  45. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/media/providers/__init__.py +0 -0
  46. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/media/providers/archive.py +0 -0
  47. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/media/providers/met_museum.py +0 -0
  48. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/media/providers/openverse.py +0 -0
  49. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/media/providers/pexels.py +0 -0
  50. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/media/providers/pixabay.py +0 -0
  51. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/media/providers/smithsonian.py +0 -0
  52. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/media/tools.py +0 -0
  53. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/pi/__init__.py +0 -0
  54. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/pi/client.py +0 -0
  55. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/pi/tools.py +0 -0
  56. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/rights/__init__.py +0 -0
  57. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/rights/client.py +0 -0
  58. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/rights/tools.py +0 -0
  59. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/scores/__init__.py +0 -0
  60. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/scores/client.py +0 -0
  61. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/scores/tools.py +0 -0
  62. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/search/__init__.py +0 -0
  63. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/domains/search/client.py +0 -0
  64. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/__init__.py +0 -0
  65. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/ast_nodes.py +0 -0
  66. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/astheno/__init__.py +0 -0
  67. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/astheno/arena.py +0 -0
  68. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/astheno/dump.py +0 -0
  69. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/astheno/floorplan.py +0 -0
  70. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/astheno/numeric.py +0 -0
  71. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/builtins.py +0 -0
  72. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/domain_bridge.py +0 -0
  73. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/environment.py +0 -0
  74. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/hypnagogia.py +0 -0
  75. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/interpreter.py +0 -0
  76. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/lexer.py +0 -0
  77. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/parser.py +0 -0
  78. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/pretty.py +0 -0
  79. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/pygments_mgs.py +0 -0
  80. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/tokens.py +0 -0
  81. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/util.py +0 -0
  82. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/lang/visitor.py +0 -0
  83. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/repl.py +0 -0
  84. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript/scaffold/__init__.py +0 -0
  85. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript.egg-info/dependency_links.txt +0 -0
  86. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript.egg-info/entry_points.txt +0 -0
  87. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript.egg-info/requires.txt +0 -0
  88. {magmascript-3.2.3 → magmascript-3.2.4}/magmascript.egg-info/top_level.txt +0 -0
  89. {magmascript-3.2.3 → magmascript-3.2.4}/setup.cfg +0 -0
  90. {magmascript-3.2.3 → magmascript-3.2.4}/tests/test_astheno.py +0 -0
  91. {magmascript-3.2.3 → magmascript-3.2.4}/tests/test_cache.py +0 -0
  92. {magmascript-3.2.3 → magmascript-3.2.4}/tests/test_classes.py +0 -0
  93. {magmascript-3.2.3 → magmascript-3.2.4}/tests/test_commands.py +0 -0
  94. {magmascript-3.2.3 → magmascript-3.2.4}/tests/test_domain_bridge.py +0 -0
  95. {magmascript-3.2.3 → magmascript-3.2.4}/tests/test_import.py +0 -0
  96. {magmascript-3.2.3 → magmascript-3.2.4}/tests/test_lang.py +0 -0
  97. {magmascript-3.2.3 → magmascript-3.2.4}/tests/test_mac.py +0 -0
  98. {magmascript-3.2.3 → magmascript-3.2.4}/tests/test_mc1.py +0 -0
  99. {magmascript-3.2.3 → magmascript-3.2.4}/tests/test_mcp_client.py +0 -0
  100. {magmascript-3.2.3 → magmascript-3.2.4}/tests/test_rpc.py +0 -0
  101. {magmascript-3.2.3 → magmascript-3.2.4}/tests/test_try_catch.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: magmascript
3
- Version: 3.2.3
3
+ Version: 3.2.4
4
4
  Summary: Scripting toolkit with domain-first subcommands
5
5
  Author: Jake McCoy
6
6
  License-Expression: MIT
@@ -702,6 +702,7 @@ Full documentation on the [Wiki](https://github.com/magmacrunch-media/magmascrip
702
702
  If you find magmascript useful, consider supporting its development:
703
703
 
704
704
  [![Sponsor](https://img.shields.io/badge/%E2%9D%A4_Sponsor-pink)](https://github.com/sponsors/magmacrunch-media)
705
+ [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue)](https://www.paypal.biz/magmacrunchmedia)
705
706
 
706
707
  ## License
707
708
 
@@ -664,6 +664,7 @@ Full documentation on the [Wiki](https://github.com/magmacrunch-media/magmascrip
664
664
  If you find magmascript useful, consider supporting its development:
665
665
 
666
666
  [![Sponsor](https://img.shields.io/badge/%E2%9D%A4_Sponsor-pink)](https://github.com/sponsors/magmacrunch-media)
667
+ [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue)](https://www.paypal.biz/magmacrunchmedia)
667
668
 
668
669
  ## License
669
670
 
@@ -1,6 +1,15 @@
1
1
  """magmascript — a scripting toolkit with domain-first subcommands."""
2
2
 
3
- __version__ = "3.2.2"
3
+ # The version lives in pyproject.toml alone. It was also a literal here, and the
4
+ # two drifted: 3.2.3 shipped reporting itself as 3.2.2, in the REPL banner and
5
+ # in the MCP client's User-Agent.
6
+ from importlib.metadata import PackageNotFoundError as _PackageNotFoundError
7
+ from importlib.metadata import version as _version
8
+
9
+ try:
10
+ __version__ = _version("magmascript")
11
+ except _PackageNotFoundError: # running from a source tree that was never installed
12
+ __version__ = "0+unknown"
4
13
 
5
14
  from magmascript.core.config import Config, GHConfig, MediaConfig, MC1Config, PIConfig, get_config, load_config, set_config
6
15
  from magmascript.core.registry import get_domain, list_domains, register_domain
@@ -11,6 +11,7 @@ from __future__ import annotations
11
11
 
12
12
  import json
13
13
  import sys
14
+ from datetime import datetime
14
15
  from functools import wraps
15
16
  from typing import Callable
16
17
 
@@ -66,7 +67,12 @@ def _generate_channels_js(channels: list[dict]) -> str:
66
67
 
67
68
  # -- register domain commands --------------------------------------------
68
69
 
70
+ _DOMAINS_REGISTERED = False
71
+
72
+
69
73
  def _register_domains():
74
+ global _DOMAINS_REGISTERED
75
+
70
76
  from magmascript.domains.mcp import MCPClient
71
77
  from magmascript.domains.pi import PIClient
72
78
  from magmascript.domains.mac import MacClient
@@ -138,6 +144,8 @@ def _register_domains():
138
144
 
139
145
  register("search", "Site search index builder")(_search_handler)
140
146
 
147
+ _DOMAINS_REGISTERED = True
148
+
141
149
 
142
150
  # -- register built-in meta commands ------------------------------------
143
151
 
@@ -437,8 +445,15 @@ def main():
437
445
  no_cache = True
438
446
  rest.remove("--no-cache")
439
447
 
440
- # Register domain commands (lazy, on first use)
441
- if not COMMANDS:
448
+ # Register domain commands (lazy, on first use).
449
+ #
450
+ # This was `if not COMMANDS:`, which assumed the table starts empty. It did
451
+ # until 3.2.2 registered the built-in commands (run, repl, cache, ...) with
452
+ # @register at import. From then on COMMANDS was never empty, this never
453
+ # ran, and every domain command -- archive, mb, lastfm, scores, search and
454
+ # the rest -- failed as "Unknown domain" in 3.2.2 and 3.2.3. A flag says
455
+ # what is actually meant: have the domains been registered yet.
456
+ if not _DOMAINS_REGISTERED:
442
457
  _register_domains()
443
458
 
444
459
  try:
@@ -98,7 +98,7 @@ class ArchiveClient:
98
98
  "events": "c-events",
99
99
  "games": "c-games",
100
100
  "links": "c-links",
101
- "music videos": "c-music-videos",
101
+ "videos": "c-videos",
102
102
  "network": "c-network",
103
103
  "documentary": "c-documentary",
104
104
  "personnel": "c-personnel",
@@ -43,6 +43,14 @@ from magmascript.domains.mcp.tools import (
43
43
  )
44
44
 
45
45
 
46
+ def _user_agent() -> str:
47
+ # Imported here, not at module level: magmascript/__init__.py imports this
48
+ # module. It was a literal "magmascript/3.2.2", still sent by 3.2.3.
49
+ from magmascript import __version__
50
+
51
+ return f"magmascript/{__version__} (https://github.com/magmacrunch-media/magmascript)"
52
+
53
+
46
54
  def _wrap_mcp_error(e: Exception, context: str = "") -> Exception:
47
55
  """Wrap RPC and HTTP exceptions into typed magmascript errors."""
48
56
  if isinstance(e, RPCError):
@@ -262,7 +270,7 @@ class MCPClient:
262
270
  """Search MusicBrainz for releases by query string."""
263
271
  url = "https://musicbrainz.org/ws/2/release/"
264
272
  params = {"query": query, "fmt": "json", "limit": limit}
265
- headers = {"User-Agent": "magmascript/3.2.2 (https://github.com/magmacrunch-media/magmascript)"}
273
+ headers = {"User-Agent": _user_agent()}
266
274
  try:
267
275
  resp = httpx.get(url, params=params, headers=headers, timeout=10.0)
268
276
  resp.raise_for_status()
@@ -275,7 +283,7 @@ class MCPClient:
275
283
  """Get full release details including track list with recordings."""
276
284
  url = f"https://musicbrainz.org/ws/2/release/{mbid}"
277
285
  params = {"fmt": "json", "inc": "artist-credits+recordings"}
278
- headers = {"User-Agent": "magmascript/3.2.2 (https://github.com/magmacrunch-media/magmascript)"}
286
+ headers = {"User-Agent": _user_agent()}
279
287
  try:
280
288
  resp = httpx.get(url, params=params, headers=headers, timeout=10.0)
281
289
  resp.raise_for_status()
@@ -288,7 +296,7 @@ class MCPClient:
288
296
  """Get recording details including ISRCs and work relationships."""
289
297
  url = f"https://musicbrainz.org/ws/2/recording/{mbid}"
290
298
  params = {"fmt": "json", "inc": "artist-credits+isrcs+work-rels"}
291
- headers = {"User-Agent": "magmascript/3.2.2 (https://github.com/magmacrunch-media/magmascript)"}
299
+ headers = {"User-Agent": _user_agent()}
292
300
  try:
293
301
  resp = httpx.get(url, params=params, headers=headers, timeout=10.0)
294
302
  resp.raise_for_status()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: magmascript
3
- Version: 3.2.3
3
+ Version: 3.2.4
4
4
  Summary: Scripting toolkit with domain-first subcommands
5
5
  Author: Jake McCoy
6
6
  License-Expression: MIT
@@ -702,6 +702,7 @@ Full documentation on the [Wiki](https://github.com/magmacrunch-media/magmascrip
702
702
  If you find magmascript useful, consider supporting its development:
703
703
 
704
704
  [![Sponsor](https://img.shields.io/badge/%E2%9D%A4_Sponsor-pink)](https://github.com/sponsors/magmacrunch-media)
705
+ [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue)](https://www.paypal.biz/magmacrunchmedia)
705
706
 
706
707
  ## License
707
708
 
@@ -87,6 +87,7 @@ tests/test_astheno.py
87
87
  tests/test_cache.py
88
88
  tests/test_classes.py
89
89
  tests/test_cli.py
90
+ tests/test_cli_regressions.py
90
91
  tests/test_commands.py
91
92
  tests/test_domain_bridge.py
92
93
  tests/test_import.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "magmascript"
7
- version = "3.2.3"
7
+ version = "3.2.4"
8
8
  description = "Scripting toolkit with domain-first subcommands"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -5,9 +5,26 @@ from unittest.mock import MagicMock, patch
5
5
 
6
6
  import pytest
7
7
 
8
+ from magmascript import cli
8
9
  from magmascript.cli import main
9
10
 
10
11
 
12
+ @pytest.fixture(autouse=True)
13
+ def fresh_domain_registration():
14
+ """Register the domains again inside each test.
15
+
16
+ Registration binds each domain's client class once, at first use, so the
17
+ first test to reach it would fix its own patched MCPClient in place for
18
+ every later test -- test_scoreboards_action then asserts against a mock the
19
+ handler never calls. This order dependence was hidden while registration
20
+ never ran at all (3.2.2 and 3.2.3, where these tests failed as "Unknown
21
+ domain" instead).
22
+ """
23
+ cli._DOMAINS_REGISTERED = False
24
+ yield
25
+ cli._DOMAINS_REGISTERED = False
26
+
27
+
11
28
  class TestCLI:
12
29
  def test_help_exits(self):
13
30
  with pytest.raises(SystemExit) as exc_info:
@@ -0,0 +1,99 @@
1
+ """Regression tests for the three faults fixed in 3.2.4.
2
+
3
+ Each of these shipped. The first two broke the website's bots and CI. The third
4
+ left `archive check-format` blind to the site's "videos" buttons: a label
5
+ missing from its map is not checked at all, so a wrong class there passed.
6
+ """
7
+
8
+ from unittest.mock import MagicMock, patch
9
+
10
+ import pytest
11
+
12
+ from magmascript import cli
13
+ from magmascript.cli import COMMANDS, main
14
+ from magmascript.domains.archive import ArchiveClient
15
+ from magmascript.domains.scores.tools import PlayerStats, ScoresReport
16
+
17
+
18
+ class TestDomainRegistration:
19
+ """3.2.2 and 3.2.3: every domain command was "Unknown domain".
20
+
21
+ Registration ran only `if not COMMANDS`, and the built-in commands had
22
+ started registering themselves at import, so the table was never empty.
23
+ """
24
+
25
+ def test_builtins_are_registered_at_import(self):
26
+ # The precondition that exposed the bug. If this stops holding, the
27
+ # test below no longer exercises it.
28
+ assert "run" in COMMANDS
29
+
30
+ @pytest.mark.parametrize("domain", ["archive", "mb", "lastfm", "scores", "search"])
31
+ def test_domain_commands_are_reachable(self, domain, capsys):
32
+ with patch("sys.argv", ["magmascript", domain, "--help"]):
33
+ try:
34
+ main()
35
+ except SystemExit:
36
+ pass
37
+ assert "Unknown domain" not in capsys.readouterr().err
38
+ assert domain in COMMANDS
39
+ assert cli._DOMAINS_REGISTERED
40
+
41
+
42
+ class TestScoresReportPostDiscussion:
43
+ """Every release: `scores report --post-discussion` raised NameError.
44
+
45
+ cli.py called datetime.now() without importing datetime, so the report
46
+ printed and the Discussion was never posted.
47
+ """
48
+
49
+ def test_posts_with_a_dated_title(self, capsys):
50
+ client = MagicMock()
51
+ client.report.return_value = ScoresReport(
52
+ generated_at="September 16, 2026",
53
+ total_games=0,
54
+ total_scores=0,
55
+ scoreboards=[],
56
+ player_stats=[PlayerStats(name="JAM", total_entries=1, games_played=1)],
57
+ )
58
+ gh = MagicMock()
59
+ gh.create_discussion.return_value = "https://example.invalid/discussions/1"
60
+
61
+ with patch("magmascript.core.config.get_config"), \
62
+ patch("magmascript.domains.gh.GHClient", return_value=gh):
63
+ cli._dispatch_scores("report", ["--post-discussion"], client, "table")
64
+
65
+ title, body, category = gh.create_discussion.call_args.args
66
+ assert title.startswith("Weekly High Scores — 20")
67
+ assert "# Weekly High Scores" in body
68
+ assert category == "high-scores"
69
+ gh.close.assert_called_once()
70
+
71
+
72
+ class TestArchiveVideosLabel:
73
+ """The site renamed the artist "music videos" pages to "videos" (website
74
+ 53dc9606). With the old map, "videos" was not a known label, so the checker
75
+ skipped those buttons -- 34 of them on the site at the time -- and the
76
+ mismatch below went unreported."""
77
+
78
+ CSS = ".nav-card.c-videos { color: red; }\n.nav-card.c-music-videos { color: red; }\n"
79
+
80
+ def _page(self, tmp_path, cls):
81
+ artist = tmp_path / "archive" / "by-artist" / "someone"
82
+ artist.mkdir(parents=True)
83
+ (artist / "someone-shared.css").write_text(self.CSS, encoding="utf-8")
84
+ (artist / "about.html").write_text(
85
+ '<div class="sub-nav">\n'
86
+ ' <a href="./" class="nav-card c-back">← back</a>\n'
87
+ f' <a href="videos.html" class="nav-card {cls}">videos</a>\n'
88
+ '</div>\n',
89
+ encoding="utf-8",
90
+ )
91
+ return ArchiveClient(project_root=tmp_path)
92
+
93
+ def test_videos_link_with_videos_class_is_clean(self, tmp_path):
94
+ assert self._page(tmp_path, "c-videos").check_format() == []
95
+
96
+ def test_videos_link_with_old_class_warns(self, tmp_path):
97
+ warnings = self._page(tmp_path, "c-music-videos").check_format()
98
+ assert len(warnings) == 1
99
+ assert "expected c-videos" in warnings[0].msg
File without changes
File without changes