diff --git a/.gitignore b/.gitignore index 79426812..205fb8a3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ .DS_Store *.orig *.jpg +*.mp4 /*.png *.png.old *.pickle @@ -13,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/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/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 de88ec8a..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 @@ -60,6 +64,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/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/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; diff --git a/pyproject.toml b/pyproject.toml index a45ffb59..7c41e2c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,17 +78,20 @@ dev = [ "twine==6.2.0", ] docs = [ - "shibuya==2025.10.21", - "sphinx==8.2.3", + "myst-parser==5.0.0", + "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 ; python_version > '3.9'", + "pytest==8.4.2 ; python_version == '3.9'", "pytest-cov==7.1.0", - "pytest-rerunfailures==16.0.1", + "pytest-rerunfailures==16.1 ; python_version > '3.9'", + "pytest-rerunfailures==16.0.1 ; python_version == '3.9'", "pyvirtualdisplay==3.0 ; sys_platform == 'linux'", ] @@ -112,6 +115,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 +203,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/__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__} diff --git a/src/mss/__main__.py b/src/mss/__main__.py index 0445c5cb..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"] @@ -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..f4639123 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 @@ -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/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/__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 036eb984..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 @@ -286,9 +285,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 +302,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..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 @@ -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..fada044c 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) @@ -431,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/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/linux/xshmgetimage.py b/src/mss/linux/xshmgetimage.py index 6b5a4927..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 @@ -101,18 +100,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 +116,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() 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 9443aba4..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: # pragma: nocover +if TYPE_CHECKING: from collections.abc import Iterator + from typing import Any class ScreenShot: 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 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",