diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fd6512e..c7bf1bd 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -28,10 +28,10 @@ jobs: sparse-checkout-cone-mode: false - uses: actions/checkout@v4 with: - repository: PyDevices/graphics - path: graphics + repository: PyDevices/pygraphics + path: pygraphics sparse-checkout: | - lib/graphics + lib/pygraphics sparse-checkout-cone-mode: false - uses: actions/checkout@v4 with: @@ -49,5 +49,5 @@ jobs: run: ruff check lib tests scripts - name: Unit tests env: - PYTHONPATH: lib:tests/stubs:pydisplay/src/lib:graphics/lib:palettes/lib + PYTHONPATH: lib:tests/stubs:pydisplay/src/lib:pygraphics/lib:palettes/lib run: python -m unittest discover -s tests diff --git a/AGENTS.md b/AGENTS.md index 40ff7eb..8a83891 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,7 +5,7 @@ Cross-platform widget toolkit for pydisplay (`import pdwidgets`). ## Environment - Python venv at `.venv` — `.venv/bin/python`, `.venv/bin/ruff` -- Depends on pydisplay packages: `eventsys`, `graphics`, `multimer`, `palettes` +- Depends on pydisplay packages: `eventsys`, `pygraphics`, `multimer`, `palettes` - Source layout: `lib/pdwidgets/` (import name `pdwidgets`) ## Tests and lint @@ -39,13 +39,13 @@ Regenerate after editing widgets: The Cloud Agent update script creates the repo-root `.venv` (with `ruff`). `pdwidgets` is source-only and imports `palettes` plus pydisplay's -`eventsys`/`graphics`/`multimer` — none are pip-installed, so the bare +`eventsys`/`pygraphics`/`multimer` — none are pip-installed, so the bare `unittest discover` / bench commands above fail without `PYTHONPATH`. In this multi-repo workspace `palettes` comes from the sibling `palettes` repo (not pydisplay's `add_ons`, unlike CI's sparse-checkout): ```bash -PYTHONPATH="lib:tests/stubs:/agent/repos/palettes/lib:/agent/repos/graphics/lib:/agent/repos/pydisplay/src/lib" \ +PYTHONPATH="lib:tests/stubs:/agent/repos/palettes/lib:/agent/repos/pygraphics/lib:/agent/repos/pydisplay/src/lib" \ .venv/bin/python -m unittest discover -s tests ``` diff --git a/README.md b/README.md index 6c4240e..6c5efc1 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Cross-platform widget toolkit for [pydisplay](https://github.com/PyDevices/pydis pip install \ -i https://test.pypi.org/simple/ \ --extra-index-url https://pypi.org/simple/ \ - pdwidgets displaysys pydisplay-graphics eventsys multimer palettes + pdwidgets displaysys pygraphics eventsys multimer palettes ``` Requires a pydisplay `board_config` and display stack. @@ -69,7 +69,7 @@ Runtime icons are **importable Python modules** under [`lib/pdwidgets/icons/`](l # 1) Optional: regenerate mono .pbm / color .bmp from Material Design .venv/bin/python scripts/assets_generate_pdwidgets_icons.py .venv/bin/python scripts/assets_make_color_icons.py -# 2) Convert binaries → .py modules (BITMAP = bytearray; uses sibling or TestPyPI graphics) +# 2) Convert binaries → .py modules (BITMAP = bytearray; uses sibling or TestPyPI pygraphics) .venv/bin/python scripts/assets_icons_to_py.py --delete-binaries # Optional bulk dump into assets/icons/ .venv/bin/python scripts/assets_convert_md_png_to_pbm.py diff --git a/docs/index.md b/docs/index.md index d9ecbbd..b906e2b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,7 +2,7 @@ Documentation for the **pdwidgets** widget toolkit — a pydisplay add-on for building GUIs on microcontrollers and desktop Python. -pdwidgets depends on pydisplay core libraries (`eventsys`, `graphics`, `multimer`) and `palettes` for theming. +pdwidgets depends on pydisplay core libraries (`eventsys`, `pygraphics`, `multimer`) and `palettes` for theming. ## Links diff --git a/docs/installation.md b/docs/installation.md index 40bfe3c..9649297 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -13,7 +13,7 @@ import mip mip.install("pdwidgets", index="https://PyDevices.github.io/micropython-lib/mip/PyDevices") ``` -`pdwidgets` declares MIP dependencies on `eventsys`, `graphics`, `multimer`, and `palettes` — `mip` installs them from the same index when needed. +`pdwidgets` declares MIP dependencies on `eventsys`, `pygraphics`, `multimer`, and `palettes` — `mip` installs them from the same index when needed. ## CPython — TestPyPI @@ -23,7 +23,7 @@ Wheels are published to [TestPyPI](https://test.pypi.org/project/pdwidgets/) for pip install \ -i https://test.pypi.org/simple/ \ --extra-index-url https://pypi.org/simple/ \ - pdwidgets displaysys pydisplay-graphics eventsys multimer palettes + pdwidgets displaysys pygraphics eventsys multimer palettes ``` You also need a pydisplay `board_config` for your display backend. See [pydisplay desktop quick start](https://pydisplay.readthedocs.io/en/latest/guides/desktop-cpython/). diff --git a/lib/pdwidgets/__init__.py b/lib/pdwidgets/__init__.py index 287fd95..15f17a7 100644 --- a/lib/pdwidgets/__init__.py +++ b/lib/pdwidgets/__init__.py @@ -33,7 +33,7 @@ """ from eventsys import events -from graphics import Area +from pygraphics import Area from . import pct from ._constants import ( diff --git a/lib/pdwidgets/_icon_load.py b/lib/pdwidgets/_icon_load.py index c0142a0..3a36cc1 100644 --- a/lib/pdwidgets/_icon_load.py +++ b/lib/pdwidgets/_icon_load.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT """Load icon / image assets into ``FrameBuffer`` instances.""" -from graphics import FrameBuffer +from pygraphics import FrameBuffer def _from_module(mod): diff --git a/lib/pdwidgets/_write_font.py b/lib/pdwidgets/_write_font.py index d44c2b8..dca5882 100644 --- a/lib/pdwidgets/_write_font.py +++ b/lib/pdwidgets/_write_font.py @@ -30,7 +30,7 @@ add-on at import time. """ -from graphics import Area +from pygraphics import Area from micropython import const WHITE = const(0xFFFF) diff --git a/lib/pdwidgets/display.py b/lib/pdwidgets/display.py index 4f8f4e9..8904952 100644 --- a/lib/pdwidgets/display.py +++ b/lib/pdwidgets/display.py @@ -11,7 +11,7 @@ from multimer import ticks_ms from eventsys import events -from graphics import RGB565, Area, FrameBuffer +from pygraphics import RGB565, Area, FrameBuffer from ._constants import ALIGN from ._focus import FocusManager @@ -191,7 +191,7 @@ def clip_push(self, area: Area): if self._clip_stack: area = area.clip(self._clip_stack[-1]) self._clip_stack.append(area) - from graphics import ClippedCanvas + from pygraphics import ClippedCanvas self.framebuf = ClippedCanvas(self._framebuf_real, area) @@ -201,7 +201,7 @@ def clip_pop(self): return self._clip_stack.pop() if self._clip_stack: - from graphics import ClippedCanvas + from pygraphics import ClippedCanvas self.framebuf = ClippedCanvas(self._framebuf_real, self._clip_stack[-1]) else: diff --git a/lib/pdwidgets/pct.py b/lib/pdwidgets/pct.py index 6b66165..ad1ab89 100644 --- a/lib/pdwidgets/pct.py +++ b/lib/pdwidgets/pct.py @@ -27,7 +27,7 @@ class _Percent: """Base for :class:`Width` / :class:`Height`: a cached percentage of a widget dimension.""" # Value-like and dynamic, so it is intentionally unhashable (mirrors - # ``graphics.Area``); it is never used as a set/dict key. + # ``pygraphics.Area``); it is never used as a set/dict key. __hash__ = None def __init__(self, percent, widget): diff --git a/lib/pdwidgets/screen.py b/lib/pdwidgets/screen.py index 3009a8b..3077cc2 100644 --- a/lib/pdwidgets/screen.py +++ b/lib/pdwidgets/screen.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT """Full-screen widget container.""" -from graphics import Area +from pygraphics import Area from .display import Display from .widget import Widget diff --git a/lib/pdwidgets/widget.py b/lib/pdwidgets/widget.py index d55ba46..a5c0ede 100644 --- a/lib/pdwidgets/widget.py +++ b/lib/pdwidgets/widget.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT """Base widget class and geometry/event primitives.""" -from graphics import Area +from pygraphics import Area from ._constants import ALIGN, DEFAULT_PADDING, POSITION from ._themes import ColorTheme diff --git a/lib/pdwidgets/widgets/icon.py b/lib/pdwidgets/widgets/icon.py index b1aa40f..0ac2bcd 100644 --- a/lib/pdwidgets/widgets/icon.py +++ b/lib/pdwidgets/widgets/icon.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT """Icon display widget.""" -from graphics import RGB565, FrameBuffer +from pygraphics import RGB565, FrameBuffer from .._constants import DEFAULT_PADDING from .._icon_load import load_framebuffer diff --git a/lib/pdwidgets/widgets/image.py b/lib/pdwidgets/widgets/image.py index 6cfb4fa..8f8d856 100644 --- a/lib/pdwidgets/widgets/image.py +++ b/lib/pdwidgets/widgets/image.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT """Raster image widget.""" -from graphics import RGB565, FrameBuffer +from pygraphics import RGB565, FrameBuffer from .._constants import DEFAULT_PADDING from .._icon_load import load_framebuffer @@ -108,7 +108,7 @@ def draw(self, _=None): self.display.framebuf.blit(fbuf, px, py) return # Monochrome: recolor like Icon - from graphics import RGB565 as _RGB # local; palette buffer + from pygraphics import RGB565 as _RGB # local; palette buffer pal = FrameBuffer(memoryview(bytearray(4)), 2, 1, _RGB) key = -1 diff --git a/lib/pdwidgets/widgets/label.py b/lib/pdwidgets/widgets/label.py index f3efe16..b385b68 100644 --- a/lib/pdwidgets/widgets/label.py +++ b/lib/pdwidgets/widgets/label.py @@ -117,7 +117,7 @@ def text_width(self, text=None): ``font_data``). Defaults to measuring :attr:`value`. Newlines are not special-cased (same contract as - ``graphics.Font.text_width`` / ``write_width``). + ``pygraphics.Font.text_width`` / ``write_width``). Args: text (str | None): String to measure; ``None`` uses ``self.value``. @@ -132,7 +132,7 @@ def text_width(self, text=None): from .._write_font import write_width return int(write_width(self._font, s)) - from graphics import Font + from pygraphics import Font cached = getattr(self, "_measure_font", None) if ( diff --git a/scripts/assets_convert_md_png_to_pbm.py b/scripts/assets_convert_md_png_to_pbm.py index 79202fe..74a4774 100644 --- a/scripts/assets_convert_md_png_to_pbm.py +++ b/scripts/assets_convert_md_png_to_pbm.py @@ -10,7 +10,7 @@ For the curated runtime set under ``lib/pdwidgets/icons/``, use ``assets_generate_pdwidgets_icons.py`` instead. -Run from the pdwidgets repo root (needs sibling pydisplay for ``graphics`` / +Run from the pdwidgets repo root (needs sibling pydisplay for ``pygraphics`` / ``png``):: .venv/bin/python scripts/assets_convert_md_png_to_pbm.py @@ -37,11 +37,11 @@ def resolve_pydisplay_root() -> Path: ) ) for root in candidates: - if (root / "src" / "lib" / "graphics").is_dir(): + if (root / "src" / "lib" / "pygraphics").is_dir(): return root.resolve() tried = ", ".join(str(p) for p in candidates) raise SystemExit( - "pydisplay checkout not found (needed for graphics/png). " + "pydisplay checkout not found (needed for pygraphics/png). " f"Set PYDISPLAY_ROOT or clone sibling pydisplay. Tried: {tried}" ) @@ -49,7 +49,7 @@ def resolve_pydisplay_root() -> Path: _pydisplay = resolve_pydisplay_root() sys.path.insert(0, str(_pydisplay / "src")) import lib.path # noqa: E402, F401 -from graphics import MONO_HLSB, FrameBuffer # noqa: E402 +from pygraphics import MONO_HLSB, FrameBuffer # noqa: E402 from png import Reader # noqa: E402 # f"{source}/{category}/{short_name}/{family}/{size}/{scale}" diff --git a/scripts/assets_generate_pdwidgets_icons.py b/scripts/assets_generate_pdwidgets_icons.py index 476f26a..d1e1b96 100644 --- a/scripts/assets_generate_pdwidgets_icons.py +++ b/scripts/assets_generate_pdwidgets_icons.py @@ -13,7 +13,7 @@ For color BMP565 status icons, see ``assets_make_color_icons.py``. Run from the pdwidgets repo root (needs a sibling pydisplay checkout for -``graphics``):: +``pygraphics``):: .venv/bin/python scripts/assets_generate_pdwidgets_icons.py @@ -48,11 +48,11 @@ def resolve_pydisplay_root(explicit: str | None = None) -> Path: ) ) for root in candidates: - if (root / "src" / "lib" / "graphics").is_dir(): + if (root / "src" / "lib" / "pygraphics").is_dir(): return root.resolve() tried = ", ".join(str(p) for p in candidates) raise SystemExit( - "pydisplay checkout not found (needed for graphics). Clone " + "pydisplay checkout not found (needed for pygraphics). Clone " f"https://github.com/PyDevices/pydisplay or pass --pydisplay-root. Tried: {tried}" ) @@ -95,7 +95,7 @@ def find_source_png(md_root: Path, category: str, short_name: str, size: int) -> def png_to_pbm(src: Path, dest_file: Path, threshold: int = THRESHOLD) -> None: - from graphics import MONO_HLSB, FrameBuffer + from pygraphics import MONO_HLSB, FrameBuffer img = Image.open(src).convert("LA") width, height = img.size @@ -127,7 +127,7 @@ def main() -> int: parser.add_argument( "--pydisplay-root", default=None, - help="Local checkout of PyDevices/pydisplay (for graphics; default: PYDISPLAY_ROOT, ../pydisplay, …)", + help="Local checkout of PyDevices/pydisplay (for pygraphics; default: PYDISPLAY_ROOT, ../pydisplay, …)", ) parser.add_argument("--force", action="store_true", help="Regenerate files that already exist") args = parser.parse_args() diff --git a/scripts/assets_icons_to_py.py b/scripts/assets_icons_to_py.py index 341ad70..3af58ca 100644 --- a/scripts/assets_icons_to_py.py +++ b/scripts/assets_icons_to_py.py @@ -2,7 +2,7 @@ """ Convert ``lib/pdwidgets/icons/*.{pbm,bmp}`` into importable ``.py`` modules. -Installs ``pydisplay-graphics`` from TestPyPI (unless already importable), or +Installs ``pygraphics`` from TestPyPI (unless already importable), or uses sibling ``pydisplay/src/lib`` when present. Loads each binary via ``FrameBuffer.from_file``, then writes modules via ``FrameBuffer.export`` (``BITMAP = bytearray(...)`` for zero-copy MicroPython loads). @@ -36,11 +36,11 @@ def ensure_graphics(*, install: bool) -> None: if PYDISPLAY_LIB.is_dir() and str(PYDISPLAY_LIB) not in sys.path: sys.path.insert(0, str(PYDISPLAY_LIB)) try: - import graphics # noqa: F401 - from graphics import FrameBuffer + import pygraphics # noqa: F401 + from pygraphics import FrameBuffer if not hasattr(FrameBuffer, "export"): - raise ImportError("graphics.FrameBuffer.export missing (need newer pydisplay)") + raise ImportError("pygraphics.FrameBuffer.export missing (need newer pydisplay)") return except ImportError: if not install: @@ -57,15 +57,15 @@ def ensure_graphics(*, install: bool) -> None: "https://test.pypi.org/simple/", "--extra-index-url", "https://pypi.org/simple/", - "pydisplay-graphics", + "pygraphics", ] print("Running:", " ".join(cmd)) subprocess.check_call(cmd) - import graphics # noqa: F401 + import pygraphics # noqa: F401 def convert_one(path: Path) -> Path: - from graphics import FrameBuffer + from pygraphics import FrameBuffer fb = FrameBuffer.from_file(str(path)) out = path.with_suffix(".py") @@ -75,7 +75,7 @@ def convert_one(path: Path) -> Path: def convert_existing_py(py_path: Path) -> None: """Re-export an existing icon module into bytearray form.""" - from graphics import FrameBuffer + from pygraphics import FrameBuffer spec = importlib.util.spec_from_file_location(py_path.stem, py_path) if spec is None or spec.loader is None: @@ -87,7 +87,7 @@ def convert_existing_py(py_path: Path) -> None: def verify_one(src_bin: Path, py_path: Path) -> None: - from graphics import FrameBuffer + from pygraphics import FrameBuffer orig = FrameBuffer.from_file(str(src_bin)) spec = importlib.util.spec_from_file_location(py_path.stem, py_path) diff --git a/scripts/assets_make_color_icons.py b/scripts/assets_make_color_icons.py index 8f3571a..4647a42 100644 --- a/scripts/assets_make_color_icons.py +++ b/scripts/assets_make_color_icons.py @@ -9,7 +9,7 @@ a magenta chroma key so ``pdwidgets.Icon(chroma=CHROMA_565)`` can render them with a transparent background. No PNG is shipped or decoded at runtime. -Usage (from the pdwidgets repo root; needs sibling pydisplay for ``graphics``):: +Usage (from the pdwidgets repo root; needs sibling pydisplay for ``pygraphics``):: .venv/bin/python scripts/assets_make_color_icons.py @@ -56,11 +56,11 @@ def resolve_pydisplay_root(explicit: str | None = None) -> Path: ) ) for root in candidates: - if (root / "src" / "lib" / "graphics").is_dir(): + if (root / "src" / "lib" / "pygraphics").is_dir(): return root.resolve() tried = ", ".join(str(p) for p in candidates) raise SystemExit( - "pydisplay checkout not found (needed for graphics). Clone " + "pydisplay checkout not found (needed for pygraphics). Clone " f"https://github.com/PyDevices/pydisplay or pass --pydisplay-root. Tried: {tried}" ) @@ -93,7 +93,7 @@ def convert(png_bytes, accent, graphics): px = img.load() chroma = color565(*CHROMA_RGB) accent565 = color565(*accent) - fb = graphics.FrameBuffer(bytearray(w * h * 2), w, h, graphics.RGB565) + fb = pygraphics.FrameBuffer(bytearray(w * h * 2), w, h, pygraphics.RGB565) for y in range(h): for x in range(w): _, _, _, a = px[x, y] @@ -106,13 +106,13 @@ def main(): parser.add_argument( "--pydisplay-root", default=None, - help="Local checkout of PyDevices/pydisplay (for graphics; default: PYDISPLAY_ROOT, ../pydisplay, …)", + help="Local checkout of PyDevices/pydisplay (for pygraphics; default: PYDISPLAY_ROOT, ../pydisplay, …)", ) args = parser.parse_args() pydisplay_root = resolve_pydisplay_root(args.pydisplay_root) sys.path.insert(0, str(pydisplay_root / "src" / "lib")) - import graphics # noqa: E402 + import pygraphics # noqa: E402 icon_dir = REPO_ROOT / "src" / "pdwidgets" / "icons" @@ -123,7 +123,7 @@ def main(): fb, w, h = convert(png, accent, graphics) out = icon_dir / f"{base}_{dp}dp.bmp" out.parent.mkdir(parents=True, exist_ok=True) - graphics.save_image(fb, str(out)) + pygraphics.save_image(fb, str(out)) print(f"wrote {out} ({w}x{h})") diff --git a/scripts/publish_micropython_lib.sh b/scripts/publish_micropython_lib.sh index 7c3211e..0abc66e 100755 --- a/scripts/publish_micropython_lib.sh +++ b/scripts/publish_micropython_lib.sh @@ -158,7 +158,7 @@ metadata( pypi_publish="$BASENAME", ) require("eventsys") -require("graphics", pypi="pydisplay-graphics") +require("pygraphics", pypi="pygraphics") require("multimer") require("palettes") package("$BASENAME") diff --git a/tests/test_button_backdrop.py b/tests/test_button_backdrop.py index bb6f042..8b02ac6 100644 --- a/tests/test_button_backdrop.py +++ b/tests/test_button_backdrop.py @@ -6,7 +6,7 @@ from types import SimpleNamespace from unittest.mock import MagicMock, PropertyMock, patch -from graphics import Area +from pygraphics import Area from pdwidgets.widgets.button import Button