mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-04 06:15:09 +00:00
chore(deprecation): remove the 35 APIs deprecated for 3.8.0 (#708)
* chore(deprecation): remove the 35 APIs deprecated for 3.8.0 The usage scan (docs/DEPRECATIONS_3.8.md, regenerated 2026-10-01 and committed here) finds no call or override of any of them in the 46 monorepo plugins or the 8 third-party plugins plugins.json lists; the only core callers were other deprecated methods removed alongside. - CacheManager: 13 methods, plus the private helpers only has_data_changed used (_has_*_changed, _is_market_open). - DisplayManager: 7 methods, plus WEATHER_COLORS and the private _draw_sun/_cloud/_rain/_snow/_storm helpers only the icon methods used. - FontManager: 14 methods, plus size_tokens, _save_overrides and _clear_plugin_font_cache. font_overrides and _load_overrides stay: resolve_font() still applies config/font_overrides.json. performance_stats stays: get_font() keeps it and tests read it. - PluginManager.get_enabled_plugins. test_deprecation.py pins only the two 3.9.0 markers now; the scanner tests run against a stand-in core instead of the real markers. The memory-tier tests read stats through log_memory_cache_stats() and the component, and the test of the removed _clear_plugin_font_cache goes. Docs drop the removed methods' reference entries; the Deprecated APIs table becomes "Removed in 3.8.0". CHANGELOG gains a Removed section. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(deprecation): drop the test harness's copies of the removed icon methods VisualTestDisplayManager still drew weather icons that DisplayManager no longer has, so a plugin's visual tests could pass on calls that raise AttributeError on the real display. Its draw_sun/draw_cloud/draw_rain/ draw_snow/draw_weather_icon/draw_text_with_icons, WEATHER_COLORS and the private helpers go, with the tests that exercised them. The CHANGELOG's Deprecations entries no longer say nothing is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -196,42 +196,3 @@ class TestVisualDisplayManager:
|
||||
assert '11th' in result
|
||||
|
||||
|
||||
class TestWeatherDrawing:
|
||||
"""Test weather icon rendering."""
|
||||
|
||||
def test_draw_sun(self):
|
||||
vdm = VisualTestDisplayManager(width=128, height=32)
|
||||
vdm.draw_sun(0, 0, 16)
|
||||
pixels = list(vdm.image.getdata())
|
||||
non_black = [p for p in pixels if p != (0, 0, 0)]
|
||||
assert len(non_black) > 0
|
||||
|
||||
def test_draw_cloud(self):
|
||||
vdm = VisualTestDisplayManager(width=128, height=32)
|
||||
vdm.draw_cloud(0, 0, 16)
|
||||
pixels = list(vdm.image.getdata())
|
||||
non_black = [p for p in pixels if p != (0, 0, 0)]
|
||||
assert len(non_black) > 0
|
||||
|
||||
def test_draw_rain(self):
|
||||
vdm = VisualTestDisplayManager(width=128, height=32)
|
||||
vdm.draw_rain(0, 0, 16)
|
||||
pixels = list(vdm.image.getdata())
|
||||
non_black = [p for p in pixels if p != (0, 0, 0)]
|
||||
assert len(non_black) > 0
|
||||
|
||||
def test_draw_snow(self):
|
||||
vdm = VisualTestDisplayManager(width=128, height=32)
|
||||
vdm.draw_snow(0, 0, 16)
|
||||
pixels = list(vdm.image.getdata())
|
||||
non_black = [p for p in pixels if p != (0, 0, 0)]
|
||||
assert len(non_black) > 0
|
||||
|
||||
def test_draw_weather_icon_dispatches(self):
|
||||
vdm = VisualTestDisplayManager(width=128, height=32)
|
||||
for condition in ['clear', 'cloudy', 'rain', 'snow', 'storm', 'unknown']:
|
||||
vdm.clear()
|
||||
vdm.draw_weather_icon(condition, 0, 0, 16)
|
||||
pixels = list(vdm.image.getdata())
|
||||
non_black = [p for p in pixels if p != (0, 0, 0)]
|
||||
assert len(non_black) > 0, f"draw_weather_icon('{condition}') should render pixels"
|
||||
|
||||
@@ -40,11 +40,9 @@ def test_cleanup_and_stats_follow_a_replaced_component(cm):
|
||||
assert cm._memory_cache_component.get("stale") is None
|
||||
assert cm._memory_cache_component.get("fresh") == {"v": 1}
|
||||
|
||||
stats = cm.get_memory_cache_stats()
|
||||
assert stats["size"] == 1
|
||||
assert stats["max_size"] == 7
|
||||
assert stats["cleanup_interval"] == 11.0
|
||||
assert stats["usage_percent"] == pytest.approx(100 / 7)
|
||||
with patch.object(cm.logger, "info") as info:
|
||||
cm.log_memory_cache_stats()
|
||||
assert "Size: 1/7 (14.3%)" in info.call_args[0][0]
|
||||
|
||||
|
||||
def test_periodic_cleanup_is_throttled_and_records_its_run(cm):
|
||||
@@ -60,16 +58,16 @@ def test_periodic_cleanup_is_throttled_and_records_its_run(cm):
|
||||
before = time.time()
|
||||
cm.get_cached_data("missing") # triggers the periodic sweep
|
||||
assert mem.size() == 0
|
||||
assert cm.get_memory_cache_stats()["last_cleanup"] >= before
|
||||
assert mem.get_stats()["last_cleanup"] >= before
|
||||
|
||||
|
||||
def test_stats_have_the_documented_shape(cm):
|
||||
def test_memory_stats_log_reads_the_live_tier(cm):
|
||||
cm.set("k", {"v": 1})
|
||||
stats = cm.get_memory_cache_stats()
|
||||
assert set(stats) == {"size", "max_size", "usage_percent",
|
||||
"last_cleanup", "cleanup_interval"}
|
||||
assert stats["size"] == 1
|
||||
assert stats["max_size"] == cm._memory_cache_component.max_size()
|
||||
with patch.object(cm.logger, "info") as info:
|
||||
cm.log_memory_cache_stats()
|
||||
message = info.call_args[0][0]
|
||||
assert f"Size: 1/{cm._memory_cache_component.max_size()}" in message
|
||||
assert "Last cleanup:" in message
|
||||
|
||||
|
||||
def test_listing_the_cache_dir_does_not_hold_the_memory_lock(cm, tmp_path):
|
||||
|
||||
+62
-40
@@ -20,31 +20,10 @@ from src.deprecation import deprecated
|
||||
|
||||
REPO = Path(__file__).resolve().parents[1]
|
||||
|
||||
#: Everything deprecated for removal in 3.8.0 (first announced for 3.7.0,
|
||||
#: which shipped with all of them still in place). docs/DEPRECATIONS_3.8.md
|
||||
#: says which are unused. Removing one of these, or deprecating another,
|
||||
#: should be a deliberate edit here too.
|
||||
DEPRECATED = {
|
||||
"src.cache_manager.CacheManager": [
|
||||
"has_data_changed", "update_cache", "setup_persistent_cache",
|
||||
"get_sport_live_interval", "get_sport_key_from_cache_key",
|
||||
"get_background_cached_data", "is_background_data_available",
|
||||
"record_cache_hit", "record_cache_miss", "record_fetch_time",
|
||||
"get_cache_metrics", "log_cache_metrics", "get_memory_cache_stats",
|
||||
],
|
||||
"src.display_manager.DisplayManager": [
|
||||
"draw_sun", "draw_cloud", "draw_rain", "draw_snow", "draw_weather_icon",
|
||||
"draw_text_with_icons", "get_scrolling_stats",
|
||||
],
|
||||
"src.font_manager.FontManager": [
|
||||
"get_manager_fonts", "get_detected_fonts", "unregister_plugin_fonts",
|
||||
"get_plugin_fonts", "set_override", "remove_override", "get_overrides",
|
||||
"get_available_fonts", "get_size_tokens", "get_performance_stats",
|
||||
"get_font_catalog", "add_font", "remove_font", "validate_font",
|
||||
],
|
||||
"src.plugin_system.plugin_manager.PluginManager": ["get_enabled_plugins"],
|
||||
}
|
||||
|
||||
#: Everything still deprecated. (The 35 methods deprecated for 3.8.0 were
|
||||
#: removed in it: docs/DEPRECATIONS_3.8.md found them unused.) Removing one
|
||||
#: of these, or deprecating another, should be a deliberate edit here too.
|
||||
#:
|
||||
#: Deprecated with Vegas participation, for removal in 3.9.0: core never read
|
||||
#: them (src.plugin_system.base_plugin.VEGAS_LEGACY_REMOVAL).
|
||||
DEPRECATED_3_9 = {
|
||||
@@ -55,7 +34,7 @@ DEPRECATED_3_9 = {
|
||||
|
||||
#: Every pinned marker: (class path, method) -> the release that removes it.
|
||||
PINNED = {(path, name): removal
|
||||
for removal, table in (("3.8.0", DEPRECATED), ("3.9.0", DEPRECATED_3_9))
|
||||
for removal, table in (("3.9.0", DEPRECATED_3_9),)
|
||||
for path, names in table.items() for name in names}
|
||||
|
||||
|
||||
@@ -132,7 +111,57 @@ def test_usage_script_lists_exactly_the_pinned_markers(usage_script):
|
||||
assert found == {(path, name, removal) for (path, name), removal in PINNED.items()}
|
||||
|
||||
|
||||
def test_usage_script_tells_uses_from_name_collisions(usage_script, tmp_path):
|
||||
#: A stand-in core for the scanner tests below, so they keep working whichever
|
||||
#: real markers exist (the 3.8.0 ones they were written against are gone).
|
||||
FAKE_CORE = {
|
||||
"src/cache_manager.py": """\
|
||||
class CacheManager:
|
||||
@deprecated("9.9.0", "use set()")
|
||||
def update_cache(self, key, data):
|
||||
pass
|
||||
""",
|
||||
"src/display_manager.py": """\
|
||||
class DisplayManager:
|
||||
@deprecated("9.9.0")
|
||||
def draw_sun(self, x, y):
|
||||
pass
|
||||
|
||||
@deprecated("9.9.0")
|
||||
def draw_cloud(self, x, y):
|
||||
pass
|
||||
|
||||
@deprecated("9.9.0")
|
||||
def draw_rain(self, x, y):
|
||||
self.draw_cloud(x, y)
|
||||
|
||||
@deprecated("9.9.0")
|
||||
def draw_snow(self, x, y):
|
||||
pass
|
||||
|
||||
@deprecated("9.9.0")
|
||||
def get_scrolling_stats(self):
|
||||
return {}
|
||||
""",
|
||||
"src/font_manager.py": """\
|
||||
class FontManager:
|
||||
@deprecated("9.9.0")
|
||||
def add_font(self, path, name):
|
||||
return True
|
||||
""",
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fake_core(tmp_path):
|
||||
root = tmp_path / "core"
|
||||
for rel, source in FAKE_CORE.items():
|
||||
path = root / rel
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(textwrap.dedent(source), encoding="utf-8")
|
||||
return root
|
||||
|
||||
|
||||
def test_usage_script_tells_uses_from_name_collisions(usage_script, fake_core, tmp_path):
|
||||
"""Calls on the owning object and overrides count; same-named methods of
|
||||
unrelated classes and hits in test files do not."""
|
||||
plugin = tmp_path / "demo"
|
||||
@@ -163,7 +192,7 @@ def test_usage_script_tells_uses_from_name_collisions(usage_script, tmp_path):
|
||||
display_manager.draw_snow.assert_not_called()
|
||||
"""), encoding="utf-8")
|
||||
|
||||
markers = usage_script.find_markers(REPO)
|
||||
markers = usage_script.find_markers(fake_core)
|
||||
source = usage_script.Source("demo", "monorepo", plugin)
|
||||
usage_script.scan_tree(source, [plugin], plugin, markers, core=False)
|
||||
kinds = {key: sorted(("test " if h.test else "") + h.kind for h in hits)
|
||||
@@ -186,11 +215,12 @@ def test_usage_script_tells_uses_from_name_collisions(usage_script, tmp_path):
|
||||
assert status["DisplayManager.draw_snow"][0] == "unused" # a test mock only
|
||||
|
||||
|
||||
def test_usage_script_follows_calls_between_deprecated_core_methods(usage_script):
|
||||
def test_usage_script_follows_calls_between_deprecated_core_methods(usage_script, fake_core):
|
||||
"""draw_rain calls draw_cloud; with no outside callers both are unused."""
|
||||
markers = usage_script.find_markers(REPO)
|
||||
core = usage_script.Source("core", "core", REPO)
|
||||
usage_script.scan_tree(core, [REPO / "src" / "display_manager.py"], REPO, markers, core=True)
|
||||
markers = usage_script.find_markers(fake_core)
|
||||
core = usage_script.Source("core", "core", fake_core)
|
||||
usage_script.scan_tree(core, [fake_core / "src" / "display_manager.py"], fake_core,
|
||||
markers, core=True)
|
||||
kinds = {h.kind for h in core.hits["DisplayManager.draw_cloud"]}
|
||||
assert kinds == {"internal"}
|
||||
assert usage_script.verdicts(markers, [core])["DisplayManager.draw_cloud"][0] == "unused"
|
||||
@@ -219,11 +249,3 @@ def test_first_call_warns_and_logs_then_stays_quiet(fresh, caplog):
|
||||
assert caught[0].filename == __file__ # points at the caller
|
||||
assert sum("will be removed in LEDMatrix 9.9.9" in r.message for r in caplog.records) == 1
|
||||
assert old.__name__ == "old" and old.__doc__ == "Doc."
|
||||
|
||||
|
||||
def test_decorated_methods_still_work(fresh):
|
||||
from src.font_manager import FontManager
|
||||
fm = FontManager({})
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
assert fm.get_font_catalog() == fm.font_catalog
|
||||
|
||||
@@ -150,16 +150,6 @@ class TestCacheLifecycle:
|
||||
fm.clear_cache()
|
||||
assert fm.cache_generation == gen_before + 1
|
||||
|
||||
def test_clearing_a_plugins_cached_fonts_bumps_generation(self, fm):
|
||||
fm.font_cache["demo::tiny_8"] = object()
|
||||
gen_before = fm.cache_generation
|
||||
fm._clear_plugin_font_cache("demo")
|
||||
assert "demo::tiny_8" not in fm.font_cache
|
||||
assert fm.cache_generation == gen_before + 1
|
||||
# Nothing to drop, nothing to rebuild.
|
||||
fm._clear_plugin_font_cache("demo")
|
||||
assert fm.cache_generation == gen_before + 1
|
||||
|
||||
|
||||
class TestPluginFonts:
|
||||
"""plugin:// sources resolve against the plugin's own directory, which
|
||||
|
||||
Reference in New Issue
Block a user