Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ jobs:
- emoji: 🪟
runs-on: [windows-latest]
python:
- name: CPython 3.9
runs-on: "3.9"
- name: CPython 3.10
runs-on: "3.10"
- name: CPython 3.11
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ with MSS() as sct:

An ultra-fast cross-platform multiple screenshots module in pure python using ctypes.

- **Python 3.9+**, PEP8 compliant, no dependency, thread-safe;
- **Python 3.10+**, PEP8 compliant, no dependency, thread-safe;
- very basic, it will grab one screenshot by monitor or a screenshot of all monitors and save it to a PNG file;
- but you can use PIL and benefit from all its formats (or add yours directly);
- integrate well with Numpy and OpenCV;
Expand Down
2 changes: 1 addition & 1 deletion docs/source/examples/pil_pixels.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
img = Image.new("RGB", sct_img.size)

# Best solution: create a list(tuple(R, G, B), ...) for putdata()
pixels = zip(sct_img.raw[2::4], sct_img.raw[1::4], sct_img.raw[::4])
pixels = zip(sct_img.raw[2::4], sct_img.raw[1::4], sct_img.raw[::4], strict=False)
img.putdata(list(pixels))

# But you can set individual pixels too (slower)
Expand Down
2 changes: 1 addition & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Welcome to Python MSS's documentation!

An ultra fast cross-platform multiple screenshots module in pure python using ctypes.

- **Python 3.9+**, :pep:`8` compliant, no dependency, thread-safe;
- **Python 3.10+**, :pep:`8` compliant, no dependency, thread-safe;
- very basic, it will grab one screenshot by monitor or a screenshot of all monitors and save it to a PNG file;
- but you can use PIL and benefit from all its formats (or add yours directly);
- integrate well with Numpy and OpenCV;
Expand Down
9 changes: 9 additions & 0 deletions docs/source/release-history/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,12 @@ This is **version 11.0.0 of Python-MSS**, the ultra-fast cross-platform multiple

Release date: 2026-xx-x

---

## Highlights

### Python 3.9 EOL

Python 3.9 reached [end-of-life](https://devguide.python.org/developer-workflow/development-cycle/index.html#end-of-life-branches) on [October 31, 2025](https://devguide.python.org/versions/). It is no longer receiving any updates, even security updates.

The MSS project has chosen to end support for Python 3.9, in order to focus our resources on current versions of Python.
3 changes: 2 additions & 1 deletion docs/source/support.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Support
Feel free to try MSS on a system we had not tested, and let us know by creating an `issue <https://github.com/BoboTiG/python-mss/issues>`_.

- OS: GNU/Linux, macOS, and Windows
- Python: 3.9 and newer
- Python: 3.10 and newer


Future
Expand Down Expand Up @@ -35,3 +35,4 @@ Abandoned
- Python 3.6 (2022-10-27)
- Python 3.7 (2023-04-09)
- Python 3.8 (2024-11-14)
- Python 3.9 (2026-xx-xx)
11 changes: 4 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "hatchling.build"
name = "mss"
description = "An ultra fast cross-platform multiple screenshots module in pure python using ctypes."
readme = "README.md"
requires-python = ">= 3.9"
requires-python = ">= 3.10"
authors = [
{ name = "Mickaël Schoentgen", email="contact@tiger-222.fr" },
]
Expand All @@ -31,7 +31,6 @@ classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand Down Expand Up @@ -87,11 +86,9 @@ 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 ; python_version > '3.9'",
"pytest==8.4.2 ; python_version == '3.9'",
"pytest==9.0.2",
"pytest-cov==7.1.0",
"pytest-rerunfailures==16.1 ; python_version > '3.9'",
"pytest-rerunfailures==16.0.1 ; python_version == '3.9'",
"pytest-rerunfailures==16.1",
"pyvirtualdisplay==3.0 ; sys_platform == 'linux'",
]

Expand Down Expand Up @@ -163,7 +160,7 @@ exclude = [
]
line-length = 120
indent-width = 4
target-version = "py39"
target-version = "py310"

[tool.ruff.format]
quote-style = "double"
Expand Down
2 changes: 1 addition & 1 deletion src/mss/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
Pixels = list[tuple[Pixel, ...]]

if TYPE_CHECKING:
from typing import Callable
from collections.abc import Callable

CFunctions = dict[str, tuple[str, list[Any], Any]]
CFunctionsErrChecked = dict[str, tuple[str, list[Any], Any, Callable | None]]
Expand Down
4 changes: 2 additions & 2 deletions src/mss/screenshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ def pixels(self) -> Pixels:
Each pixel is a tuple of (R, G, B).
"""
if not self.__pixels:
rgb_tuples: Iterator[Pixel] = zip(self.raw[2::4], self.raw[1::4], self.raw[::4])
self.__pixels = list(zip(*[iter(rgb_tuples)] * self.width))
rgb_tuples: Iterator[Pixel] = zip(self.raw[2::4], self.raw[1::4], self.raw[::4], strict=False)
self.__pixels = list(zip(*[iter(rgb_tuples)] * self.width, strict=False))

return self.__pixels

Expand Down
3 changes: 2 additions & 1 deletion src/mss/windows/gdi.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
from mss.exception import ScreenShotError

if TYPE_CHECKING:
from typing import Any, Callable
from collections.abc import Callable
from typing import Any

from mss.models import CFunctionsErrChecked, Monitor, Monitors

Expand Down
7 changes: 5 additions & 2 deletions src/tests/test_implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def test_monitor_option_and_quiet(self, with_cursor: bool, capsys: pytest.Captur
filename.unlink()

assert filename is not None
for opts in zip(["-m 1", "--monitor=1"], ["-q", "--quiet"]):
for opts in zip(["-m 1", "--monitor=1"], ["-q", "--quiet"], strict=False):
self._run_main(with_cursor, *opts)
captured = capsys.readouterr()
assert not captured.out
Expand All @@ -144,7 +144,10 @@ def test_custom_output_pattern(self, with_cursor: bool, capsys: pytest.CaptureFi
self._run_main(with_cursor, opt, fmt)
captured = capsys.readouterr()
with mss.MSS() as sct:
for mon, (monitor, line) in enumerate(zip(sct.monitors[1:], captured.out.splitlines()), 1):
for mon, (monitor, line) in enumerate(
zip(sct.monitors[1:], captured.out.splitlines(), strict=False),
1,
):
filename = Path(fmt.format(mon=mon, **monitor))
assert line.endswith(filename.name)
assert filename.is_file()
Expand Down
4 changes: 2 additions & 2 deletions src/tests/test_xcb.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
sizeof,
)
from types import SimpleNamespace
from typing import TYPE_CHECKING, Any, Callable
from typing import TYPE_CHECKING, Any
from unittest.mock import Mock
from weakref import finalize

if TYPE_CHECKING:
from collections.abc import Generator
from collections.abc import Callable, Generator

import pytest

Expand Down
Loading