From e9d53b0ff782bfeba6b212ee89f75eec020fb259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 24 Mar 2026 10:28:07 +0100 Subject: [PATCH 01/12] chore: update dates --- LICENSE.txt | 2 +- src/mss/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 0b055a04..95abf4ec 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,5 +1,5 @@ MIT License -Copyright (c) 2013-2025, Mickaël 'Tiger-222' Schoentgen +Copyright (c) 2013-2026, Mickaël 'Tiger-222' Schoentgen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/src/mss/__init__.py b/src/mss/__init__.py index ecac4b41..8ce267ed 100644 --- a/src/mss/__init__.py +++ b/src/mss/__init__.py @@ -12,7 +12,7 @@ __version__ = "10.2.0.dev0" __author__ = "Mickaël Schoentgen" -__date__ = "2013-2025" +__date__ = "2013-2026" __copyright__ = f""" Copyright (c) {__date__}, {__author__} From 9fb649b2db072f13338a92f173e00447dc7fb661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 24 Mar 2026 10:28:18 +0100 Subject: [PATCH 02/12] feat: update dependencies --- pyproject.toml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a45ffb59..b883ab0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,17 +78,17 @@ dev = [ "twine==6.2.0", ] docs = [ - "shibuya==2025.10.21", - "sphinx==8.2.3", + "shibuya==2026.1.9", + "sphinx==9.1.0", "sphinx-copybutton==0.5.2", - "sphinx-new-tab-link==0.8.0", + "sphinx-new-tab-link==0.8.1", ] tests = [ - "numpy==2.2.4 ; sys_platform == 'linux' and python_version == '3.13'", - "pillow==11.3.0 ; sys_platform == 'linux' and python_version == '3.13'", - "pytest==8.4.2", + "numpy==2.4.3 ; sys_platform == 'linux' and python_version == '3.13'", + "pillow==12.1.1 ; sys_platform == 'linux' and python_version == '3.13'", + "pytest==9.0.2", "pytest-cov==7.1.0", - "pytest-rerunfailures==16.0.1", + "pytest-rerunfailures==16.1", "pyvirtualdisplay==3.0 ; sys_platform == 'linux'", ] From 65a868e596d1e67df147eea702fe11aa3a895ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 24 Mar 2026 10:29:36 +0100 Subject: [PATCH 03/12] feat: automatic "pragma: nocover" setup --- pyproject.toml | 9 ++++++++- src/mss/__main__.py | 2 +- src/mss/base.py | 8 ++++---- src/mss/darwin.py | 2 +- src/mss/linux/xlib.py | 2 +- src/mss/screenshot.py | 2 +- src/mss/windows.py | 6 ++++-- src/tests/bench_general.py | 2 +- src/tests/test_implementation.py | 2 +- 9 files changed, 22 insertions(+), 13 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b883ab0c..b9f79d0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -112,6 +112,13 @@ packages = [ "src/mss", ] +[tool.coverage.report] +exclude_also = [ + "except ImportError:", + "if TYPE_CHECKING:", + 'if __name__ == "__main__":', +] + [tool.mypy] # Ensure we know what we do warn_redundant_casts = true @@ -193,4 +200,4 @@ ignore = [ ] [tool.ruff.per-file-target-version] -"src/xcbproto/*" = "py312" \ No newline at end of file +"src/xcbproto/*" = "py312" diff --git a/src/mss/__main__.py b/src/mss/__main__.py index 0445c5cb..1cb5b8c0 100644 --- a/src/mss/__main__.py +++ b/src/mss/__main__.py @@ -109,7 +109,7 @@ def main(*args: str) -> int: raise -if __name__ == "__main__": # pragma: nocover +if __name__ == "__main__": try: sys.exit(main()) except ScreenShotError as exc: diff --git a/src/mss/base.py b/src/mss/base.py index 64335ece..e0e0874b 100644 --- a/src/mss/base.py +++ b/src/mss/base.py @@ -12,7 +12,7 @@ from mss.screenshot import ScreenShot from mss.tools import to_png -if TYPE_CHECKING: # pragma: nocover +if TYPE_CHECKING: from collections.abc import Callable, Iterator from mss.models import Monitor, Monitors @@ -20,15 +20,15 @@ # Prior to 3.11, Python didn't have the Self type. typing_extensions does, but we don't want to depend on it. try: from typing import Self - except ImportError: # pragma: nocover + except ImportError: try: from typing_extensions import Self - except ImportError: # pragma: nocover + except ImportError: Self = Any # type: ignore[assignment] try: from datetime import UTC -except ImportError: # pragma: nocover +except ImportError: # Python < 3.11 from datetime import timezone diff --git a/src/mss/darwin.py b/src/mss/darwin.py index 8f95e6d5..a87666ab 100644 --- a/src/mss/darwin.py +++ b/src/mss/darwin.py @@ -28,7 +28,7 @@ from mss.exception import ScreenShotError from mss.screenshot import ScreenShot, Size -if TYPE_CHECKING: # pragma: nocover +if TYPE_CHECKING: from mss.models import CFunctions, Monitor __all__ = ("IMAGE_OPTIONS", "MSS") diff --git a/src/mss/linux/xlib.py b/src/mss/linux/xlib.py index 26708fef..d4b28be0 100644 --- a/src/mss/linux/xlib.py +++ b/src/mss/linux/xlib.py @@ -38,7 +38,7 @@ from mss.base import MSSBase from mss.exception import ScreenShotError -if TYPE_CHECKING: # pragma: nocover +if TYPE_CHECKING: from mss.models import CFunctions, Monitor from mss.screenshot import ScreenShot diff --git a/src/mss/screenshot.py b/src/mss/screenshot.py index 9443aba4..39dabace 100644 --- a/src/mss/screenshot.py +++ b/src/mss/screenshot.py @@ -8,7 +8,7 @@ from mss.exception import ScreenShotError from mss.models import Monitor, Pixel, Pixels, Pos, Size -if TYPE_CHECKING: # pragma: nocover +if TYPE_CHECKING: from collections.abc import Iterator diff --git a/src/mss/windows.py b/src/mss/windows.py index 89298f52..0a27e563 100644 --- a/src/mss/windows.py +++ b/src/mss/windows.py @@ -28,12 +28,14 @@ UINT, WORD, ) -from typing import TYPE_CHECKING, Any, Callable +from typing import TYPE_CHECKING from mss.base import MSSBase from mss.exception import ScreenShotError -if TYPE_CHECKING: # pragma: nocover +if TYPE_CHECKING: + from typing import Any, Callable + from mss.models import CFunctionsErrChecked, Monitor from mss.screenshot import ScreenShot diff --git a/src/tests/bench_general.py b/src/tests/bench_general.py index 100a4729..5de4f1c1 100644 --- a/src/tests/bench_general.py +++ b/src/tests/bench_general.py @@ -33,7 +33,7 @@ import mss import mss.tools -if TYPE_CHECKING: # pragma: nocover +if TYPE_CHECKING: from collections.abc import Callable from mss.base import MSSBase diff --git a/src/tests/test_implementation.py b/src/tests/test_implementation.py index ecd91eef..e64537ec 100644 --- a/src/tests/test_implementation.py +++ b/src/tests/test_implementation.py @@ -22,7 +22,7 @@ from mss.exception import ScreenShotError from mss.screenshot import ScreenShot -if TYPE_CHECKING: # pragma: nocover +if TYPE_CHECKING: from collections.abc import Callable from typing import Any From e398bd4504413b4bed41959be3b3f551cde40a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 24 Mar 2026 10:31:15 +0100 Subject: [PATCH 04/12] feat: minor refactorings proposed by Sourcery --- src/mss/base.py | 13 ++++++++----- src/mss/linux/base.py | 14 ++++++-------- src/mss/linux/xcb.py | 10 ++-------- src/mss/linux/xcbhelpers.py | 4 +--- src/mss/linux/xshmgetimage.py | 19 ++++++++----------- 5 files changed, 25 insertions(+), 35 deletions(-) diff --git a/src/mss/base.py b/src/mss/base.py index e0e0874b..f4639123 100644 --- a/src/mss/base.py +++ b/src/mss/base.py @@ -241,11 +241,14 @@ def primary_monitor(self) -> Monitor: msg = "No monitor found." raise ScreenShotError(msg) - for monitor in monitors[1:]: # Skip the "all monitors" entry at index 0 - if monitor.get("is_primary", False): - return monitor - # Fallback to the first monitor if no primary is found - return monitors[1] + return next( + ( + monitor + for monitor in monitors[1:] # Skip the "all monitors" entry at index 0 + if monitor.get("is_primary", False) + ), + monitors[1], # Fallback to the first monitor if no primary is found + ) def save( self, diff --git a/src/mss/linux/base.py b/src/mss/linux/base.py index 036eb984..fc70841a 100644 --- a/src/mss/linux/base.py +++ b/src/mss/linux/base.py @@ -286,9 +286,7 @@ def _choose_randr_output( if primary_output is None: # We don't want to use the `in` check if this could be None, according to MyPy. return outputs[0] - if primary_output in outputs: - return primary_output - return outputs[0] + return primary_output if primary_output in outputs else outputs[0] def _monitors_from_randr_monitors( self, primary_output: xcb.RandrOutput | None, edid_atom: xcb.Atom | None, / @@ -305,12 +303,12 @@ def _monitors_from_randr_monitors( "top": randr_monitor.y, "width": randr_monitor.width, "height": randr_monitor.height, + # Under XRandR, it's legal for no monitor to be primary. In this case, case MSSBase.primary_monitor + # will return the first monitor. That said, we note in the dict that we explicitly are told by XRandR + # that all of the monitors are not primary. (This is distinct from the XRandR 1.2 path, which doesn't + # have any information about primary monitors.) + "is_primary": bool(randr_monitor.primary), } - # Under XRandR, it's legal for no monitor to be primary. In this case, case MSSBase.primary_monitor will - # return the first monitor. That said, we note in the dict that we explicitly are told by XRandR that - # all of the monitors are not primary. (This is distinct from the XRandR 1.2 path, which doesn't have - # any information about primary monitors.) - monitor["is_primary"] = bool(randr_monitor.primary) if randr_monitor.nOutput > 0: outputs = xcb.randr_monitor_info_outputs(randr_monitor) diff --git a/src/mss/linux/xcb.py b/src/mss/linux/xcb.py index 64ea929a..862d04d8 100644 --- a/src/mss/linux/xcb.py +++ b/src/mss/linux/xcb.py @@ -359,10 +359,7 @@ def connect(display: str | bytes | None = None) -> tuple[Connection, int]: LIB.xcb.xcb_disconnect(conn_p) msg = "Cannot connect to display: " conn_errmsg = XCB_CONN_ERRMSG.get(conn_err) - if conn_errmsg: - msg += conn_errmsg - else: - msg += f"error code {conn_err}" + msg += conn_errmsg or f"error code {conn_err}" raise XError(msg) # Prefetch extension data for all extensions we support to populate XCB's internal cache. @@ -391,8 +388,5 @@ def disconnect(xcb_conn: Connection | _Pointer[Connection]) -> None: if conn_err != 0: msg = "Connection to X server closed: " conn_errmsg = XCB_CONN_ERRMSG.get(conn_err) - if conn_errmsg: - msg += conn_errmsg - else: - msg += f"error code {conn_err}" + msg += conn_errmsg or f"error code {conn_err}" raise XError(msg) diff --git a/src/mss/linux/xcbhelpers.py b/src/mss/linux/xcbhelpers.py index de5fafd0..32ab134d 100644 --- a/src/mss/linux/xcbhelpers.py +++ b/src/mss/linux/xcbhelpers.py @@ -102,9 +102,7 @@ class Connection(Structure): class XID(c_uint32): def __eq__(self, other: object) -> bool: - if isinstance(other, XID): - return self.value == other.value - return NotImplemented + return self.value == other.value if isinstance(other, XID) else NotImplemented def __hash__(self) -> int: return hash(self.value) diff --git a/src/mss/linux/xshmgetimage.py b/src/mss/linux/xshmgetimage.py index 6b5a4927..2c144280 100644 --- a/src/mss/linux/xshmgetimage.py +++ b/src/mss/linux/xshmgetimage.py @@ -101,18 +101,13 @@ def _setup_shm(self) -> ShmStatus: # noqa: PLR0911 try: self._memfd = os.memfd_create("mss-shm-buf", flags=os.MFD_CLOEXEC) # type: ignore[attr-defined] except OSError as e: - self._shm_report_issue("memfd_create failed", e) - self._shutdown_shm() - return ShmStatus.UNAVAILABLE + return self._shm_unavailable("memfd_create failed", e) os.ftruncate(self._memfd, self._bufsize) try: self._buf = mmap(self._memfd, self._bufsize, prot=PROT_READ) # type: ignore[call-arg] except OSError as e: - self._shm_report_issue("mmap failed", e) - self._shutdown_shm() - return ShmStatus.UNAVAILABLE - + return self._shm_unavailable("mmap failed", e) self._shmseg = xcb.ShmSeg(xcb.generate_id(self.conn).value) try: # This will normally be what raises an exception if you're on a remote connection. @@ -122,16 +117,18 @@ def _setup_shm(self) -> ShmStatus: # noqa: PLR0911 finally: self._memfd = None except xcb.XError as e: - self._shm_report_issue("Cannot attach MIT-SHM segment", e) - self._shutdown_shm() - return ShmStatus.UNAVAILABLE - + return self._shm_unavailable("Cannot attach MIT-SHM segment", e) except Exception: self._shutdown_shm() raise return ShmStatus.UNKNOWN + def _shm_unavailable(self, msg: str, exc: Exception) -> ShmStatus: + self._shm_report_issue(msg, exc) + self._shutdown_shm() + return ShmStatus.UNAVAILABLE + def _close_impl(self) -> None: self._shutdown_shm() super()._close_impl() From a9bce577e21a30c4dc2f215ca289e4c453ee22fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 24 Mar 2026 10:31:41 +0100 Subject: [PATCH 05/12] chore: conditional typing imports --- src/mss/models.py | 4 +++- src/mss/screenshot.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mss/models.py b/src/mss/models.py index da65594b..aa79c620 100644 --- a/src/mss/models.py +++ b/src/mss/models.py @@ -2,7 +2,7 @@ # Source: https://github.com/BoboTiG/python-mss. from __future__ import annotations -from typing import TYPE_CHECKING, Any, Callable, NamedTuple +from typing import TYPE_CHECKING, Any, NamedTuple # TODO @BoboTiG: https://github.com/BoboTiG/python-mss/issues/470 # Change this to a proper Monitor class in next major release. @@ -13,6 +13,8 @@ Pixels = list[tuple[Pixel, ...]] if TYPE_CHECKING: + from typing import Callable + CFunctions = dict[str, tuple[str, list[Any], Any]] CFunctionsErrChecked = dict[str, tuple[str, list[Any], Any, Callable | None]] diff --git a/src/mss/screenshot.py b/src/mss/screenshot.py index 39dabace..5edb08d7 100644 --- a/src/mss/screenshot.py +++ b/src/mss/screenshot.py @@ -3,13 +3,14 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from mss.exception import ScreenShotError from mss.models import Monitor, Pixel, Pixels, Pos, Size if TYPE_CHECKING: from collections.abc import Iterator + from typing import Any class ScreenShot: From b2d0e0db2f044b4e449dd699b5269b9d04328bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 24 Mar 2026 10:32:07 +0100 Subject: [PATCH 06/12] fix: absolute imports everywhere --- src/mss/linux/__init__.py | 6 +++--- src/mss/linux/base.py | 5 ++--- src/mss/linux/xcb.py | 6 +++--- src/mss/linux/xcbhelpers.py | 2 +- src/mss/linux/xgetimage.py | 3 +-- src/mss/linux/xshmgetimage.py | 3 +-- 6 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/mss/linux/__init__.py b/src/mss/linux/__init__.py index e98424b7..08defd6b 100644 --- a/src/mss/linux/__init__.py +++ b/src/mss/linux/__init__.py @@ -41,18 +41,18 @@ def mss(backend: str = "default", **kwargs: Any) -> MSSBase: """ backend = backend.lower() if backend == "xlib": - from . import xlib # noqa: PLC0415 + from mss.linux import xlib # noqa: PLC0415 return xlib.MSS(**kwargs) if backend == "xgetimage": - from . import xgetimage # noqa: PLC0415 + from mss.linux import xgetimage # noqa: PLC0415 # Note that the xshmgetimage backend will automatically fall back to XGetImage calls if XShmGetImage isn't # available. The only reason to use the xgetimage backend is if the user already knows that XShmGetImage # isn't going to be supported. return xgetimage.MSS(**kwargs) if backend in {"default", "xshmgetimage"}: - from . import xshmgetimage # noqa: PLC0415 + from mss.linux import xshmgetimage # noqa: PLC0415 return xshmgetimage.MSS(**kwargs) assert backend not in BACKENDS # noqa: S101 diff --git a/src/mss/linux/base.py b/src/mss/linux/base.py index fc70841a..76d5ba0c 100644 --- a/src/mss/linux/base.py +++ b/src/mss/linux/base.py @@ -5,11 +5,10 @@ from mss.base import MSSBase from mss.exception import ScreenShotError +from mss.linux import xcb +from mss.linux.xcb import LIB from mss.tools import parse_edid -from . import xcb -from .xcb import LIB - if TYPE_CHECKING: from ctypes import Array diff --git a/src/mss/linux/xcb.py b/src/mss/linux/xcb.py index 862d04d8..b2ae41d1 100644 --- a/src/mss/linux/xcb.py +++ b/src/mss/linux/xcb.py @@ -4,11 +4,11 @@ from ctypes import _Pointer, addressof, c_int from typing import Literal, overload -from . import xcbgen +from mss.linux import xcbgen # We import these just so they're re-exported to our users. # ruff: noqa: F401 -from .xcbgen import ( +from mss.linux.xcbgen import ( RANDR_MAJOR_VERSION, RANDR_MINOR_VERSION, RENDER_MAJOR_VERSION, @@ -129,7 +129,7 @@ ) # These are also here to re-export. -from .xcbhelpers import LIB, XID, Connection, InternAtomReply, QueryExtensionReply, XcbExtension, XError +from mss.linux.xcbhelpers import LIB, XID, Connection, InternAtomReply, QueryExtensionReply, XcbExtension, XError XCB_CONN_ERROR = 1 XCB_CONN_CLOSED_EXT_NOTSUPPORTED = 2 diff --git a/src/mss/linux/xcbhelpers.py b/src/mss/linux/xcbhelpers.py index 32ab134d..fada044c 100644 --- a/src/mss/linux/xcbhelpers.py +++ b/src/mss/linux/xcbhelpers.py @@ -429,7 +429,7 @@ def reset(self) -> None: def initialize(self, callbacks: Iterable[Callable[[], None]] = frozenset()) -> None: # noqa: PLR0915 # We'll need a couple of generated types, but we have to load them late, since xcbgen requires this library. - from .xcbgen import Setup # noqa: PLC0415 + from mss.linux.xcbgen import Setup # noqa: PLC0415 with self._lock: if self.initialized: diff --git a/src/mss/linux/xgetimage.py b/src/mss/linux/xgetimage.py index ba3cb44a..e256ac8f 100644 --- a/src/mss/linux/xgetimage.py +++ b/src/mss/linux/xgetimage.py @@ -9,11 +9,10 @@ .. versionadded:: 10.2.0 """ +from mss.linux.base import MSSXCBBase from mss.models import Monitor from mss.screenshot import ScreenShot -from .base import MSSXCBBase - class MSS(MSSXCBBase): """XCB backend using XGetImage requests on GNU/Linux. diff --git a/src/mss/linux/xshmgetimage.py b/src/mss/linux/xshmgetimage.py index 2c144280..454d72f7 100644 --- a/src/mss/linux/xshmgetimage.py +++ b/src/mss/linux/xshmgetimage.py @@ -20,10 +20,9 @@ from mss.exception import ScreenShotError from mss.linux import xcb +from mss.linux.base import ALL_PLANES, MSSXCBBase from mss.linux.xcbhelpers import LIB, XProtoError -from .base import ALL_PLANES, MSSXCBBase - if TYPE_CHECKING: from mss.models import Monitor from mss.screenshot import ScreenShot From af12c1fb2fb5f208c9ff5b7f78a1167b199fa157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 24 Mar 2026 10:32:36 +0100 Subject: [PATCH 07/12] chore: ignore MP4 files generated by demos --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 79426812..f3360ad8 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ .DS_Store *.orig *.jpg +*.mp4 /*.png *.png.old *.pickle From 4ef317c23d31aaf4d65ca105e358e75b57428428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 24 Mar 2026 10:34:39 +0100 Subject: [PATCH 08/12] chore: remove superfluous list() calls --- src/mss/__main__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mss/__main__.py b/src/mss/__main__.py index 1cb5b8c0..c170aefc 100644 --- a/src/mss/__main__.py +++ b/src/mss/__main__.py @@ -18,15 +18,15 @@ def _backend_cli_choices() -> list[str]: if os_name == "darwin": from mss import darwin # noqa: PLC0415 - return list(darwin.BACKENDS) + return darwin.BACKENDS if os_name == "linux": from mss import linux # noqa: PLC0415 - return list(linux.BACKENDS) + return linux.BACKENDS if os_name == "windows": from mss import windows # noqa: PLC0415 - return list(windows.BACKENDS) + return windows.BACKENDS return ["default"] From fd90762dcbc0982755a0333a175958a9b8aa6552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 24 Mar 2026 10:42:30 +0100 Subject: [PATCH 09/12] docs: tweak --- docs/source/conf.py | 1 + docs/source/examples.rst | 3 ++- docs/source/where.rst | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index de88ec8a..e0663580 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -60,6 +60,7 @@ "accent_color": "lime", "globaltoc_expand_depth": 1, "toctree_titles_only": False, + "show_ai_links": False, } html_favicon = "../icon.png" html_context = { diff --git a/docs/source/examples.rst b/docs/source/examples.rst index ce540141..09e3c2f2 100644 --- a/docs/source/examples.rst +++ b/docs/source/examples.rst @@ -214,7 +214,7 @@ Different possibilities to convert raw BGRA values to RGB:: Demos ===== -In addition to these simple examples, there are full demos of more complex use cases in the ``demos/`` directory of the +In addition to these simple examples, there are full demos of more complex use cases in the `demos `_ directory of the source code. The demos are not installed with the package, but you can run them directly from the source tree after cloning the repository. @@ -223,6 +223,7 @@ not only how to invoke MSS, but also some of the techniques for using the captur scenarios. These include: + - MP4 video capture with encoding using PyAV (FFmpeg bindings) - Live streaming to a TinyTV as MJPEG - Detect images of cats on the screen diff --git a/docs/source/where.rst b/docs/source/where.rst index 9a47882d..fccc6527 100644 --- a/docs/source/where.rst +++ b/docs/source/where.rst @@ -2,7 +2,7 @@ Who Uses it? ============ -This is a non exhaustive list where MSS is integrated or has inspired. +This is a non `exhaustive list `_ where MSS is integrated or has inspired. Do not hesitate to `say Hello! `_ if you are using MSS too. - Nvidia; From a3b4a8209536b704812e4c1862c888180b93631a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 24 Mar 2026 11:08:22 +0100 Subject: [PATCH 10/12] feat: include the changelog in the documentation --- .gitignore | 1 + CHANGELOG.md | 135 +++++++++++++++++++++++++------------- docs/source/changelog.rst | 2 + docs/source/conf.py | 6 +- docs/source/index.rst | 1 + pyproject.toml | 1 + 6 files changed, 100 insertions(+), 46 deletions(-) create mode 100644 docs/source/changelog.rst diff --git a/.gitignore b/.gitignore index f3360ad8..205fb8a3 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ build/ .cache/ dist/ +docs/__intersphinx_cache__/ docs_out/ *.egg-info/ .idea/ diff --git a/CHANGELOG.md b/CHANGELOG.md index c26a1bcc..f3ad7da3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ See Git commit messages for full history. -## 10.2.0.dev0 (2026-xx-xx) +## v10.2.0.dev0 +(2026-xx-xx) - Add `is_primary`, `name`, and `unique_id` keys to Monitor dicts for primary monitor detection, device names, and stable per-monitor identification (#153) - Add `primary_monitor` property to MSS base class for easy access to the primary monitor (#153) - Windows: add primary monitor detection using `GetMonitorInfoW` API (#153) @@ -20,19 +21,22 @@ See Git commit messages for full history. - Add full demos for different ways to use MSS (#444, #456, #465) - :heart: contributors: @jholveck, @halldorfannar -## 10.1.0 (2025-08-16) +## v10.1.0 +(2025-08-16) - Mac: up to 60% performances improvement by taking screenshots at nominal resolution (e.g. scaling is off by default). To enable back scaling, set `mss.darwin.IMAGE_OPTIONS = 0`. (#257) - docs: use the [shibuya](https://shibuya.lepture.com) theme - :heart: contributors: @brycedrennan -## 10.0.0 (2024-11-14) +## v10.0.0 +(2024-11-14) - removed support for Python 3.8 - added support for Python 3.14 - Linux: fixed a threading issue in `.close()` when calling `XCloseDisplay()` (#251) - Linux: minor optimization when checking for a X extension status (#251) - :heart: contributors: @kianmeng, @shravanasati, @mgorny -## 9.0.2 (2024-09-01) +## v9.0.2 +(2024-09-01) - added support for Python 3.13 - leveled up the packaging using `hatchling` - used `ruff` to lint the code base (#275) @@ -41,10 +45,12 @@ See Git commit messages for full history. - CI: automated release publishing on tag creation - :heart: contributors: @Andon-Li -## 9.0.1 (2023-04-20) +## v9.0.1 +(2023-04-20) - CLI: fixed entry point not taking into account arguments -## 9.0.0 (2023-04-18) +## v9.0.0 +(2023-04-18) - Linux: add failure handling to `XOpenDisplay()` call (fixes #246) - Mac: tiny improvement in monitors finding - Windows: refactored how internal handles are stored (fixes #198) @@ -55,7 +61,8 @@ See Git commit messages for full history. - tests: automatic rerun in case of failure (related to #251) - :heart: contributors: @mgorny, @CTPaHHuK-HEbA -## 8.0.3 (2023-04-15) +## v8.0.3 +(2023-04-15) - added support for Python 3.12 - MSS: added PEP 561 compatibility - MSS: include more files in the sdist package (#240) @@ -66,16 +73,19 @@ See Git commit messages for full history. - dev: review the structure of the repository to fix/improve packaging issues (#243) - :heart: contributors: @mgorny, @relent95 -## 8.0.2 (2023-04-09) +## v8.0.2 +(2023-04-09) - fixed `SetuptoolsDeprecationWarning`: Installing 'XXX' as data is deprecated, please list it in packages - CLI: fixed arguments handling -## 8.0.1 (2023-04-09) +## v8.0.1 +(2023-04-09) - MSS: ensure `--with-cursor`, and `with_cursor` argument & attribute, are simple NOOP on platforms not supporting the feature - CLI: do not raise a `ScreenShotError` when `-q`, or `--quiet`, is used but return ` - tests: fixed `test_entry_point()` with multiple monitors having the same resolution -## 8.0.0 (2023-04-09) +## v8.0.0 +(2023-04-09) - removed support for Python 3.6 - removed support for Python 3.7 - MSS: fixed PEP 484 prohibits implicit Optional @@ -88,10 +98,12 @@ See Git commit messages for full history. - tests: added PyPy 3.9, removed `tox`, and improved GNU/Linux coverage - :heart: contributors: @zorvios -## 7.0.1 (2022-10-27) +## v7.0.1 +(2022-10-27) - fixed the wheel package -## 7.0.0 (2022-10-27) +## v7.0.0 +(2022-10-27) - added support for Python 3.11 - added support for Python 3.10 - removed support for Python 3.5 @@ -100,7 +112,8 @@ See Git commit messages for full history. - MSS: fixed typos here, and there - docs: fixed an error when building the documentation -## 6.1.0 (2020-10-31) +## v6.1.0 +(2020-10-31) - MSS: reworked how C functions are initialized - Mac: reduce the number of function calls - Mac: support macOS Big Sur (fixes #178) @@ -108,7 +121,8 @@ See Git commit messages for full history. - tests: fixed macOS interpreter not found on Travis-CI - tests: fixed `test_entry_point()` when there are several monitors -## 6.0.0 (2020-06-30) +## v6.0.0 +(2020-06-30) - removed usage of deprecated `license_file` option for `license_files` - fixed flake8 usage in pre-commit - the module is now available on Conda (closes #170) @@ -116,7 +130,8 @@ See Git commit messages for full history. - Linux: better handling of the Xrandr extension (fixes #168) - tests: fixed a random bug on `test_grab_with_tuple_percents()` (fixes #142) -## 5.1.0 (2020-04-30) +## v5.1.0 +(2020-04-30) - produce wheels for Python 3 only - MSS: renamed again `MSSMixin` to `MSSBase`, now derived from `abc.ABCMeta` - tools: force write of file when saving a PNG file @@ -124,7 +139,8 @@ See Git commit messages for full history. - Windows: fixed multi-thread safety (fixes #150) - :heart: contributors: @narumishi -## 5.0.0 (2019-12-31) +## v5.0.0 +(2019-12-31) - removed support for Python 2.7 - MSS: improve type annotations and add CI check - MSS: use `__slots__` for better performances @@ -137,15 +153,18 @@ See Git commit messages for full history. - tests: move tests files into the package - :heart: contributors: @hugovk, @foone, @SergeyKalutsky -## 4.0.2 (2019-02-23) +## v4.0.2 +(2019-02-23) - Windows: ignore missing `SetProcessDPIAware()` on Window XP (fixes #109) - :heart: contributors: @foone -## 4.0.1 (2019-01-26) +## v4.0.1 +(2019-01-26) - Linux: fixed several Xlib functions signature (fixes #92) - Linux: improve monitors finding by a factor of 44 -## 4.0.0 (2019-01-11) +## v4.0.0 +(2019-01-11) - MSS: remove use of `setup.py` for `setup.cfg` - MSS: renamed `MSSBase` to `MSSMixin` in `base.py` - MSS: refactor ctypes `argtype`, `restype` and `errcheck` setup (fixes #84) @@ -158,29 +177,34 @@ See Git commit messages for full history. - MSS: fixed PyLint bad-super-call: Bad first argument 'Exception' given to `super()` - tests: use `tox`, enable PyPy and PyPy3, add macOS and Windows CI -## 3.3.2 (2018-11-20) +## v3.3.2 +(2018-11-20) - MSS: do monitor detection in MSS constructor (fixes #79) - MSS: specify compliant Python versions for pip install - tests: enable Python 3.7 - tests: fixed `test_entry_point()` with multiple monitors - :heart: contributors: @hugovk, @andreasbuhr -## 3.3.1 (2018-09-22) +## v3.3.1 +(2018-09-22) - Linux: fixed a memory leak introduced with 7e8ae5703f0669f40532c2be917df4328bc3985e (fixes #72) - docs: add the download statistics badge -## 3.3.0 (2018-09-04) +## v3.3.0 +(2018-09-04) - Linux: add an error handler for the XServer to prevent interpreter crash (fixes #61) - MSS: fixed a `ResourceWarning`: unclosed file in `setup.py` - tests: fixed a `ResourceWarning`: unclosed file - docs: fixed a typo in `Screenshot.pixel()` method (thanks to @mchlnix) - big code clean-up using `black` -## 3.2.1 (2018-05-21) +## v3.2.1 +(2018-05-21) - Windows: enable Hi-DPI awareness - :heart: contributors: @ryanfox -## 3.2.0 (2018-03-22) +## v3.2.0 +(2018-03-22) - removed support for Python 3.4 - MSS: add the `Screenshot.bgra` attribute - MSS: speed-up grabbing on the 3 platforms @@ -189,17 +213,20 @@ See Git commit messages for full history. - docs: add an example about capturing part of the monitor 2 - docs: add an example about computing BGRA values to RGB -## 3.1.2 (2018-01-05) +## v3.1.2 +(2018-01-05) - removed support for Python 3.3 - MSS: possibility to get the whole PNG raw bytes - Windows: capture all visible window - docs: improvements and fixes (fixes #37) - CI: build the documentation -## 3.1.1 (2017-11-27) +## v3.1.1 +(2017-11-27) - MSS: add the `mss` entry point -## 3.1.0 (2017-11-16) +## v3.1.0 +(2017-11-16) - MSS: add more way of customization to the output argument of `save()` - MSS: possibility to use custom class to handle screenshot data - Mac: properly support all display scaling and resolutions (fixes #14, #19, #21, #23) @@ -211,22 +238,26 @@ See Git commit messages for full history. - add the 'Say Thanks' button - :heart: contributors: @karanlyons -## 3.0.1 (2017-07-06) +## v3.0.1 +(2017-07-06) - fixed examples links -## 3.0.0 (2017-07-06) +## v3.0.0 +(2017-07-06) - big refactor, introducing the `ScreenShot` class - MSS: add Numpy array interface support to the `Screenshot` class - docs: add OpenCV/Numpy, PIL pixels, FPS -## 2.0.22 (2017-04-29) +## v2.0.22 +(2017-04-29) - MSS: better use of exception mechanism - Linux: use of `hasattr()` to prevent Exception on early exit - Mac: take into account extra black pixels added when screen with is not divisible by 16 (fixes #14) - docs: add an example to capture only a part of the screen - :heart: contributors: David Becker, @redodo -## 2.0.18 (2016-12-03) +## v2.0.18 +(2016-12-03) - change license to MIT - MSS: add type hints - MSS: remove unused code (reported by `Vulture`) @@ -239,7 +270,8 @@ See Git commit messages for full history. - tests: add tests and use Travis CI (fixes #9) - :heart: contributors: @cycomanic -## 2.0.0 (2016-06-04) +## v2.0.0 +(2016-06-04) - add issue and pull request templates - split the module into several files - MSS: a lot of code refactor and optimizations @@ -251,13 +283,16 @@ See Git commit messages for full history. - Linux: `get_pixels()` insanely fast, use of MSS library (C code) - Windows: screenshot not correct on Windows 8 (fixes #6) -## 1.0.2 (2016-04-22) +## v1.0.2 +(2016-04-22) - MSS: fixed non-existent alias -## 1.0.1 (2016-04-22) +## v1.0.1 +(2016-04-22) - MSS: `libpng` warning (ignoring bad filter type) (fixes #7) -## 1.0.0 (2015-04-16) +## v1.0.0 +(2015-04-16) - Python 2.6 to 3.5 ready - MSS: code clean-up and review, no more debug information - MSS: add a shortcut to take automatically use the proper `MSS` class (fixes #5) @@ -269,30 +304,35 @@ See Git commit messages for full history. - Windows: huge optimization of `get_pixels()` - CLI: delete `--debug` argument -## 0.1.1 (2015-04-10) +## v0.1.1 +(2015-04-10) - MSS: little code review - Linux: fixed monitor count - tests: remove `test-linux` binary - docs: add `doc/TESTING` - docs: remove Bonus section from README -## 0.1.0 (2015-04-10) +## v0.1.0 +(2015-04-10) - MSS: fixed code with `YAPF` tool - Linux: fully functional using Xrandr library - Linux: code clean-up (no more XML files to parse) - docs: better tests and examples -## 0.0.8 (2015-02-04) +## v0.0.8 +(2015-02-04) - MSS: filename's directory is not used when saving (fixes #3) - MSS: fixed flake8 error: E713 test for membership should be 'not in' - MSS: raise an exception for unimplemented methods - Windows: robustness to `MSSWindows.get_pixels` (fixes #4) - :heart: contributors: @sergey-vin, @thehesiod -## 0.0.7 (2014-03-20) +## v0.0.7 +(2014-03-20) - MSS: fixed path where screenshots are saved -## 0.0.6 (2014-03-19) +## v0.0.6 +(2014-03-19) - Python 3.4 ready - PEP8 compliant - MSS: review module structure to fit the "Code Like a Pythonista: Idiomatic Python" @@ -304,23 +344,28 @@ See Git commit messages for full history. - CLI: possibility to append `--debug` to the command line - :heart: contributors: @sametmax -## 0.0.5 (2013-11-01) +## v0.0.5 +(2013-11-01) - MSS: code simplified - Windows: few optimizations into `_arrange()` -## 0.0.4 (2013-10-31) +## v0.0.4 +(2013-10-31) - Linux: use of memoization → huge time/operations gains -## 0.0.3 (2013-10-30) +## v0.0.3 +(2013-10-30) - MSS: removed PNG filters - MSS: removed `ext` argument, using only PNG - MSS: do not overwrite existing image files - MSS: few optimizations into `png()` - Linux: few optimizations into `get_pixels()` -## 0.0.2 (2013-10-21) +## v0.0.2 +(2013-10-21) - added support for python 3 on Windows and GNU/Linux - :heart: contributors: Oros, Eownis -## 0.0.1 (2013-07-01) +## v0.0.1 +(2013-07-01) - first release diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst new file mode 100644 index 00000000..9f448a2b --- /dev/null +++ b/docs/source/changelog.rst @@ -0,0 +1,2 @@ +.. include:: ../../CHANGELOG.md + :parser: myst_parser.sphinx_ diff --git a/docs/source/conf.py b/docs/source/conf.py index e0663580..e95d58b6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -20,13 +20,17 @@ # -- General configuration ------------------------------------------------ extensions = [ + "myst_parser", "sphinx.ext.autodoc", "sphinx_copybutton", "sphinx.ext.intersphinx", "sphinx_new_tab_link", ] templates_path = ["_templates"] -source_suffix = {".rst": "restructuredtext"} +source_suffix = { + ".rst": "restructuredtext", + ".md": "markdown", +} master_doc = "index" new_tab_link_show_external_link_icon = True diff --git a/docs/source/index.rst b/docs/source/index.rst index e0e44719..78bf095d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -43,6 +43,7 @@ An ultra fast cross-platform multiple screenshots module in pure python using ct | support | | api | | developers | +| changelog | | where | +-------------------------+ diff --git a/pyproject.toml b/pyproject.toml index b9f79d0c..13b121b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,6 +78,7 @@ dev = [ "twine==6.2.0", ] docs = [ + "myst-parser==5.0.0", "shibuya==2026.1.9", "sphinx==9.1.0", "sphinx-copybutton==0.5.2", From ecf21cc04f1145f00021783bafab2cb9bbb7421c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 24 Mar 2026 11:11:49 +0100 Subject: [PATCH 11/12] fix: tests --- pyproject.toml | 3 ++- src/tests/test_setup.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 13b121b4..4bf2a43b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,7 +89,8 @@ tests = [ "pillow==12.1.1 ; sys_platform == 'linux' and python_version == '3.13'", "pytest==9.0.2", "pytest-cov==7.1.0", - "pytest-rerunfailures==16.1", + "pytest-rerunfailures==16.1 ; python_version > '3.9'", + "pytest-rerunfailures==16.0.1 ; python_version < '3.10'", "pyvirtualdisplay==3.0 ; sys_platform == 'linux'", ] diff --git a/src/tests/test_setup.py b/src/tests/test_setup.py index 29be9b62..0772d3f6 100644 --- a/src/tests/test_setup.py +++ b/src/tests/test_setup.py @@ -42,6 +42,7 @@ def test_sdist() -> None: f"mss-{__version__}/PKG-INFO", f"mss-{__version__}/README.md", f"mss-{__version__}/docs/source/api.rst", + f"mss-{__version__}/docs/source/changelog.rst", f"mss-{__version__}/docs/source/conf.py", f"mss-{__version__}/docs/source/developers.rst", f"mss-{__version__}/docs/source/examples.rst", From 040e55f7b2f5aa3e5cea6ab4b5ffeef2e256987a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Tue, 24 Mar 2026 11:17:10 +0100 Subject: [PATCH 12/12] fix: py39 --- pyproject.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4bf2a43b..7c41e2c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,10 +87,11 @@ docs = [ tests = [ "numpy==2.4.3 ; sys_platform == 'linux' and python_version == '3.13'", "pillow==12.1.1 ; sys_platform == 'linux' and python_version == '3.13'", - "pytest==9.0.2", + "pytest==9.0.2 ; python_version > '3.9'", + "pytest==8.4.2 ; python_version == '3.9'", "pytest-cov==7.1.0", "pytest-rerunfailures==16.1 ; python_version > '3.9'", - "pytest-rerunfailures==16.0.1 ; python_version < '3.10'", + "pytest-rerunfailures==16.0.1 ; python_version == '3.9'", "pyvirtualdisplay==3.0 ; sys_platform == 'linux'", ]