pyobs-alpaca 2.0.0.dev4__tar.gz → 2.0.0.dev5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. pyobs_alpaca-2.0.0.dev5/.github/workflows/dependabot-automerge.yml +24 -0
  2. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/PKG-INFO +2 -2
  3. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/pyobs_alpaca/device.py +13 -0
  4. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/pyobs_alpaca/dome.py +14 -9
  5. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/pyobs_alpaca/focuser.py +9 -7
  6. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/pyobs_alpaca/telescope.py +8 -6
  7. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/pyproject.toml +2 -2
  8. pyobs_alpaca-2.0.0.dev5/tests/test_cooperative_init.py +64 -0
  9. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/uv.lock +26 -26
  10. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/.flake8 +0 -0
  11. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/.github/dependabot.yml +0 -0
  12. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/.github/workflows/pypi.yml +0 -0
  13. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/.github/workflows/pyrefly.yml +0 -0
  14. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/.github/workflows/pytest.yml +0 -0
  15. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/.github/workflows/ruff.yml +0 -0
  16. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/.pre-commit-config.yaml +0 -0
  17. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/.readthedocs.yml +0 -0
  18. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/CHANGELOG.rst +0 -0
  19. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/LICENSE +0 -0
  20. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/README.md +0 -0
  21. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/docs/Makefile +0 -0
  22. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/docs/make.bat +0 -0
  23. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/docs/requirements.txt +0 -0
  24. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/docs/source/_static/pyobs.gif +0 -0
  25. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/docs/source/conf.py +0 -0
  26. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/docs/source/index.rst +0 -0
  27. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/pyobs_alpaca/__init__.py +0 -0
  28. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/tests/test_device.py +0 -0
  29. {pyobs_alpaca-2.0.0.dev4 → pyobs_alpaca-2.0.0.dev5}/tests/test_import.py +0 -0
@@ -0,0 +1,24 @@
1
+ name: Dependabot auto-merge
2
+
3
+ on: pull_request
4
+
5
+ permissions:
6
+ contents: write
7
+ pull-requests: write
8
+
9
+ jobs:
10
+ dependabot:
11
+ runs-on: ubuntu-latest
12
+ if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}
13
+ steps:
14
+ - name: Fetch Dependabot metadata
15
+ id: metadata
16
+ uses: dependabot/fetch-metadata@v2
17
+ with:
18
+ compat-lookup: true
19
+ - name: Enable auto-merge for patch and minor updates
20
+ if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor' }}
21
+ run: gh pr merge --auto --merge "$PR_URL"
22
+ env:
23
+ PR_URL: ${{ github.event.pull_request.html_url }}
24
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pyobs-alpaca
3
- Version: 2.0.0.dev4
3
+ Version: 2.0.0.dev5
4
4
  Summary: pyobs module for ASCOM Alpaca
5
5
  Author-email: Tim-Oliver Husser <thusser@uni-goettingen.de>
6
6
  License-Expression: MIT
7
7
  License-File: LICENSE
8
8
  Requires-Python: >=3.11
9
9
  Requires-Dist: numpy<3,>=2.2.5
10
- Requires-Dist: pyobs-core<3,>=2.0.0.dev48
10
+ Requires-Dist: pyobs-core<3,>=2.0.0.dev82
@@ -23,6 +23,19 @@ class ServerGetResponse(NamedTuple):
23
23
  Value: Any
24
24
 
25
25
 
26
+ DEVICE_INIT_KWARGS = {"server", "port", "device_type", "device", "version", "alive_parameter"}
27
+ """Names of AlpacaDevice's own constructor params -- callers that also thread **kwargs through
28
+ their own cooperative super().__init__() chain must exclude these first, since nothing in that
29
+ chain (Module/mixins) recognizes them and they'd otherwise leak through to object.__init__()."""
30
+
31
+ OBJECT_SHARED_KWARGS = {"vfs", "comm", "timezone", "location", "observer"}
32
+ """Names of pyobs.object.Object's own constructor params. AlpacaDevice forwards anything beyond
33
+ its own params (see DEVICE_INIT_KWARGS) straight to Object cooperatively, so callers building an
34
+ AlpacaDevice from a module's **kwargs must restrict to DEVICE_INIT_KWARGS | OBJECT_SHARED_KWARGS --
35
+ any module/mixin-specific kwarg (e.g. fits_namespaces, motion_status_interfaces) would otherwise
36
+ leak through to object.__init__() the same way."""
37
+
38
+
26
39
  class AlpacaDevice(Object):
27
40
  def __init__(
28
41
  self,
@@ -13,12 +13,12 @@ from pyobs.utils.enums import MotionStatus
13
13
  from pyobs.utils.parallel import event_wait
14
14
  from pyobs.utils.threads import LockWithAbort
15
15
 
16
- from .device import AlpacaDevice
16
+ from .device import DEVICE_INIT_KWARGS, OBJECT_SHARED_KWARGS, AlpacaDevice
17
17
 
18
18
  log = logging.getLogger("pyobs")
19
19
 
20
20
 
21
- class AlpacaDome(FollowMixin, BaseDome):
21
+ class AlpacaDome(BaseDome, FollowMixin):
22
22
  __module__ = "pyobs_alpaca"
23
23
 
24
24
  def __init__(self, tolerance: float = 3, park_az: float = 180, follow: str | None = None, **kwargs: Any):
@@ -29,10 +29,20 @@ class AlpacaDome(FollowMixin, BaseDome):
29
29
  park_az: Azimuth for park position.
30
30
  follow: Name of other device (e.g. telescope) to follow.
31
31
  """
32
- BaseDome.__init__(self, **kwargs, motion_status_interfaces=["IDome"])
32
+ super().__init__(
33
+ motion_status_interfaces=["IDome"],
34
+ device=follow,
35
+ interval=10,
36
+ tolerance=tolerance,
37
+ mode=IPointingAltAz,
38
+ only_follow_when_ready=False,
39
+ **{k: v for k, v in kwargs.items() if k not in DEVICE_INIT_KWARGS},
40
+ )
33
41
 
34
42
  # device
35
- self._device = self.add_child_object(AlpacaDevice, **kwargs)
43
+ self._device = self.add_child_object(
44
+ AlpacaDevice, **{k: v for k, v in kwargs.items() if k in DEVICE_INIT_KWARGS | OBJECT_SHARED_KWARGS}
45
+ )
36
46
 
37
47
  # store
38
48
  self._tolerance = tolerance
@@ -53,11 +63,6 @@ class AlpacaDome(FollowMixin, BaseDome):
53
63
  # start thread
54
64
  self.add_background_task(self._update_status)
55
65
 
56
- # mixins
57
- FollowMixin.__init__(
58
- self, device=follow, interval=10, tolerance=tolerance, mode=IPointingAltAz, only_follow_when_ready=False
59
- )
60
-
61
66
  async def open(self) -> None:
62
67
  """Open module."""
63
68
  await BaseDome.open(self)
@@ -9,19 +9,24 @@ from pyobs.utils import exceptions as exc
9
9
  from pyobs.utils.enums import MotionStatus
10
10
  from pyobs.utils.threads import LockWithAbort
11
11
 
12
- from .device import AlpacaDevice
12
+ from .device import DEVICE_INIT_KWARGS, OBJECT_SHARED_KWARGS, AlpacaDevice
13
13
 
14
14
  log = logging.getLogger(__name__)
15
15
 
16
16
 
17
- class AlpacaFocuser(MotionStatusMixin, IFocuser, IFitsHeaderBefore, Module):
17
+ class AlpacaFocuser(Module, MotionStatusMixin, IFocuser, IFitsHeaderBefore):
18
18
  __module__ = "pyobs_alpaca"
19
19
 
20
20
  def __init__(self, **kwargs: Any):
21
- Module.__init__(self, **kwargs)
21
+ super().__init__(
22
+ motion_status_interfaces=["IFocuser"],
23
+ **{k: v for k, v in kwargs.items() if k not in DEVICE_INIT_KWARGS},
24
+ )
22
25
 
23
26
  # device
24
- self._device = self.add_child_object(AlpacaDevice, **kwargs)
27
+ self._device = self.add_child_object(
28
+ AlpacaDevice, **{k: v for k, v in kwargs.items() if k in DEVICE_INIT_KWARGS | OBJECT_SHARED_KWARGS}
29
+ )
25
30
 
26
31
  # variables
27
32
  self._focus_offset = 0.0
@@ -30,9 +35,6 @@ class AlpacaFocuser(MotionStatusMixin, IFocuser, IFitsHeaderBefore, Module):
30
35
  self._lock_motion = asyncio.Lock()
31
36
  self._abort_motion = asyncio.Event()
32
37
 
33
- # init mixins
34
- MotionStatusMixin.__init__(self, motion_status_interfaces=["IFocuser"])
35
-
36
38
  # register exception
37
39
  self._register_exception(exc.MotionError, 3, timespan=600, callback=self._default_remote_error_callback)
38
40
 
@@ -25,7 +25,7 @@ from pyobs.utils.enums import MotionStatus
25
25
  from pyobs.utils.parallel import acquire_lock, event_wait
26
26
  from pyobs.utils.threads import LockWithAbort
27
27
 
28
- from .device import AlpacaDevice
28
+ from .device import DEVICE_INIT_KWARGS, OBJECT_SHARED_KWARGS, AlpacaDevice
29
29
 
30
30
  log = logging.getLogger("pyobs")
31
31
 
@@ -40,10 +40,15 @@ class AlpacaTelescope(BaseTelescope, FitsNamespaceMixin, IFitsHeaderBefore, IOff
40
40
  settle_time: Time in seconds to wait after slew before finishing.
41
41
  park_position: Alt/Az park position.
42
42
  """
43
- BaseTelescope.__init__(self, **kwargs, motion_status_interfaces=["ITelescope"])
43
+ super().__init__(
44
+ motion_status_interfaces=["ITelescope"],
45
+ **{k: v for k, v in kwargs.items() if k not in DEVICE_INIT_KWARGS},
46
+ )
44
47
 
45
48
  # device
46
- self._device = self.add_child_object(AlpacaDevice, **kwargs)
49
+ self._device = self.add_child_object(
50
+ AlpacaDevice, **{k: v for k, v in kwargs.items() if k in DEVICE_INIT_KWARGS | OBJECT_SHARED_KWARGS}
51
+ )
47
52
 
48
53
  # variables
49
54
  self._settle_time = settle_time
@@ -57,9 +62,6 @@ class AlpacaTelescope(BaseTelescope, FitsNamespaceMixin, IFitsHeaderBefore, IOff
57
62
  self._cached_ra: float | None = None
58
63
  self._cached_dec: float | None = None
59
64
 
60
- # mixins
61
- FitsNamespaceMixin.__init__(self, **kwargs)
62
-
63
65
  # background position polling
64
66
  self.add_background_task(self._update_position)
65
67
 
@@ -1,13 +1,13 @@
1
1
  [project]
2
2
  name = "pyobs-alpaca"
3
- version = "2.0.0.dev4"
3
+ version = "2.0.0.dev5"
4
4
  description = "pyobs module for ASCOM Alpaca"
5
5
  authors = [{ name = "Tim-Oliver Husser", email = "thusser@uni-goettingen.de" }]
6
6
  requires-python = ">=3.11"
7
7
  license = "MIT"
8
8
  dependencies = [
9
9
  "numpy>=2.2.5,<3",
10
- "pyobs-core>=2.0.0.dev48,<3",
10
+ "pyobs-core>=2.0.0.dev82,<3",
11
11
  ]
12
12
 
13
13
  [dependency-groups]
@@ -0,0 +1,64 @@
1
+ """Regression tests for the cooperative-super()-chain conversion of AlpacaDome, AlpacaFocuser,
2
+ and AlpacaTelescope.
3
+
4
+ Each of these classes used to make separate, explicit calls to its Module/Base and mixin
5
+ __init__ methods with unfiltered kwargs, instead of a single cooperative super().__init__()
6
+ call. Against pyobs-core's cooperative __init__ chains, that pattern either drops kwargs a
7
+ sibling mixin declares (leaking them to object.__init__()) or re-threads already-consumed
8
+ kwargs through a second, redundant call -- both raise TypeError. If that happens here, these
9
+ constructor calls themselves raise instead of returning.
10
+ """
11
+
12
+ import inspect
13
+ from collections.abc import Callable
14
+ from typing import Any
15
+
16
+ from pyobs.mixins.follow import FollowMixin
17
+ from pyobs.object import Object
18
+ from pyobs.utils.enums import MotionStatus
19
+
20
+ from pyobs_alpaca import AlpacaDome, AlpacaFocuser, AlpacaTelescope
21
+ from pyobs_alpaca.device import DEVICE_INIT_KWARGS, OBJECT_SHARED_KWARGS, AlpacaDevice
22
+
23
+ _DEVICE_ARGS = dict(server="localhost", port=11111, device_type="dome", device=0)
24
+
25
+
26
+ def _param_names(func: Callable[..., Any]) -> set[str]:
27
+ return {name for name in inspect.signature(func).parameters if name not in ("self", "kwargs")}
28
+
29
+
30
+ def test_device_init_kwargs_matches_alpaca_device_signature() -> None:
31
+ """Keeps DEVICE_INIT_KWARGS honest: if AlpacaDevice's constructor ever gains/loses a param
32
+ without updating this set, callers threading a module's **kwargs through both AlpacaDevice
33
+ and the module's own super().__init__() chain would silently start leaking kwargs to
34
+ object.__init__() again -- exactly the bug this whole conversion fixes."""
35
+ assert DEVICE_INIT_KWARGS == _param_names(AlpacaDevice.__init__)
36
+
37
+
38
+ def test_object_shared_kwargs_matches_object_signature() -> None:
39
+ """Same invariant as above, for the Object-level kwargs AlpacaDevice forwards cooperatively
40
+ (and that the module chain also needs, e.g. comm/vfs)."""
41
+ assert OBJECT_SHARED_KWARGS == _param_names(Object.__init__)
42
+
43
+
44
+ def test_dome_constructor_threads_kwargs_cooperatively() -> None:
45
+ dome = AlpacaDome(tolerance=5, follow="telescope", **_DEVICE_ARGS)
46
+ assert dome.motion_status() == MotionStatus.UNKNOWN
47
+ assert isinstance(dome, FollowMixin)
48
+ assert dome.is_following is True
49
+ assert dome._tolerance == 5
50
+
51
+
52
+ def test_focuser_constructor_threads_kwargs_cooperatively() -> None:
53
+ focuser = AlpacaFocuser(**{**_DEVICE_ARGS, "device_type": "focuser"})
54
+ assert focuser.motion_status() == MotionStatus.UNKNOWN
55
+
56
+
57
+ def test_telescope_constructor_threads_kwargs_cooperatively() -> None:
58
+ telescope = AlpacaTelescope(
59
+ settle_time=1.5,
60
+ fits_namespaces={"instrument": None},
61
+ **{**_DEVICE_ARGS, "device_type": "telescope"},
62
+ )
63
+ assert telescope.motion_status() == MotionStatus.UNKNOWN
64
+ assert telescope._FitsNamespaceMixin__namespaces == {"instrument": None} # type: ignore[attr-defined]
@@ -1902,7 +1902,7 @@ wheels = [
1902
1902
 
1903
1903
  [[package]]
1904
1904
  name = "pyobs-alpaca"
1905
- version = "2.0.0.dev4"
1905
+ version = "2.0.0.dev5"
1906
1906
  source = { editable = "." }
1907
1907
  dependencies = [
1908
1908
  { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
@@ -1923,7 +1923,7 @@ dev = [
1923
1923
  [package.metadata]
1924
1924
  requires-dist = [
1925
1925
  { name = "numpy", specifier = ">=2.2.5,<3" },
1926
- { name = "pyobs-core", specifier = ">=2.0.0.dev48,<3" },
1926
+ { name = "pyobs-core", specifier = ">=2.0.0.dev82,<3" },
1927
1927
  ]
1928
1928
 
1929
1929
  [package.metadata.requires-dev]
@@ -1938,7 +1938,7 @@ dev = [
1938
1938
 
1939
1939
  [[package]]
1940
1940
  name = "pyobs-core"
1941
- version = "2.0.0.dev72"
1941
+ version = "2.0.0.dev82"
1942
1942
  source = { registry = "https://pypi.org/simple" }
1943
1943
  dependencies = [
1944
1944
  { name = "aiohttp" },
@@ -1970,9 +1970,9 @@ dependencies = [
1970
1970
  { name = "tenacity" },
1971
1971
  { name = "typing-extensions" },
1972
1972
  ]
1973
- sdist = { url = "https://files.pythonhosted.org/packages/d7/25/ac1a0571461eb87655374a38a4a21983db407f7239d60adce009e4ba8438/pyobs_core-2.0.0.dev72.tar.gz", hash = "sha256:b9ac8679bb9a72d1180ba60a97ad08b1878b1bc6b21158754d1f7fc7033231ee", size = 354347, upload-time = "2026-08-10T11:31:59.746Z" }
1973
+ sdist = { url = "https://files.pythonhosted.org/packages/13/b8/e0d2a5fa390e15eebd01c86a75360e47e72823036b9e8793f73961c4e24a/pyobs_core-2.0.0.dev82.tar.gz", hash = "sha256:eb5e6510e0ba113700876db409cdce4b5d57e6df399421fc8cf174ec9e5076a8", size = 362959, upload-time = "2026-08-19T04:27:17.94Z" }
1974
1974
  wheels = [
1975
- { url = "https://files.pythonhosted.org/packages/8e/6a/570856f6149a611d7e4858e980faa1e23c5ddedda22327808f8e3eb5b413/pyobs_core-2.0.0.dev72-py3-none-any.whl", hash = "sha256:321f6b80f2fb8703e3cbf2f62cea2333cb475b1a50f58d8900176644fe6ca6b2", size = 576647, upload-time = "2026-08-10T11:31:57.813Z" },
1975
+ { url = "https://files.pythonhosted.org/packages/81/17/83f22b85cfd9dea2c18396738d12fcd631232b2e8a111700133b037a7673/pyobs_core-2.0.0.dev82-py3-none-any.whl", hash = "sha256:b0cfe7d7a9dff89a8650ff4c01cdd3423f8ca9188aeef1d799d3e61085484bb2", size = 585768, upload-time = "2026-08-19T04:27:16.531Z" },
1976
1976
  ]
1977
1977
 
1978
1978
  [[package]]
@@ -2196,27 +2196,27 @@ wheels = [
2196
2196
 
2197
2197
  [[package]]
2198
2198
  name = "ruff"
2199
- version = "0.16.2"
2200
- source = { registry = "https://pypi.org/simple" }
2201
- sdist = { url = "https://files.pythonhosted.org/packages/73/e1/4508a569211b35599016e84ba65c1a992b7a4004b4b6c4bea02a851cba1b/ruff-0.16.2.tar.gz", hash = "sha256:c3d7828d12e8927a6fc65fe38e2c2541b9e762d360a1786d752cb1b8883b3c9c", size = 4885811, upload-time = "2026-08-07T13:31:01.432Z" }
2202
- wheels = [
2203
- { url = "https://files.pythonhosted.org/packages/14/57/db19951540f98859c956b50bdb4d31089b4d91e9f15e2968e7d5193806d5/ruff-0.16.2-py3-none-linux_armv6l.whl", hash = "sha256:3c8de4cf2181f01d57946d87d777aa52916976fc09942aed89938fab5e013318", size = 10847925, upload-time = "2026-08-07T13:30:14.468Z" },
2204
- { url = "https://files.pythonhosted.org/packages/13/5a/995fe85a8470d3e391ac0f7fa8054bb454eaf33ee138196d6172ed1079c0/ruff-0.16.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9a48cc05c6fbc811ca81b5d7ba95375affea6582d1b8024e455e41afbbf55344", size = 11072662, upload-time = "2026-08-07T13:30:18.143Z" },
2205
- { url = "https://files.pythonhosted.org/packages/32/53/370d767c61c71a971a4ace36703a7ecd8c393956349a7325d7fab2b56827/ruff-0.16.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a2c0d14fcbb26c91f0f867a6dc9bd71bbc30b1b6151829c884f23faeab2e5700", size = 10566771, upload-time = "2026-08-07T13:30:20.899Z" },
2206
- { url = "https://files.pythonhosted.org/packages/85/d6/9d96948caf5a632be62d62202d5ec914d6856f204fd79eb036e5915e79ea/ruff-0.16.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:335c621622c4650330be50842561c6586ac6971bb8ab5407fe34dcc9efb16bbe", size = 10975825, upload-time = "2026-08-07T13:30:23.517Z" },
2207
- { url = "https://files.pythonhosted.org/packages/3b/92/ea87129b3414acb0b5770563779c51804d37ac67675c7ba35447ddb14773/ruff-0.16.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20e66910f2c37cc753f9ef6580c914a621b80c4fa3549d3e3521e29d0f5bfc3f", size = 10649437, upload-time = "2026-08-07T13:30:26.097Z" },
2208
- { url = "https://files.pythonhosted.org/packages/ac/43/f8f291dcd4af5bb7872b74fdfa41a7cd7c856ca1d4069670971cf1b9f5cb/ruff-0.16.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7e36fbfba65510548156902bcf1350a979a958ce0347ce0f90d73894036b39f", size = 11446761, upload-time = "2026-08-07T13:30:28.752Z" },
2209
- { url = "https://files.pythonhosted.org/packages/71/4a/ef991fb2fcf516ab71f0808adcdd8da5e18c8cde447f4ceaf5f47a5132a5/ruff-0.16.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f0eab35f80df8f134aae5d1630e751901321d317cc8e50dc39e36fa3ed34cd12", size = 12336364, upload-time = "2026-08-07T13:30:31.468Z" },
2210
- { url = "https://files.pythonhosted.org/packages/f3/24/f615e74f307e6ca0e56a482872477b856c70d530aa356abfb6dfe5ca8a80/ruff-0.16.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40ea8c0594feb894e89c8c61ab9c103d38b0ea72dfde6c594107147ca31b1140", size = 11630720, upload-time = "2026-08-07T13:30:34.426Z" },
2211
- { url = "https://files.pythonhosted.org/packages/c5/d3/8ef50149e8412a77f7ab409efdef0e2b23803707a3863da4fc64cb23d459/ruff-0.16.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab3d62dde0b19facdd632008cc4827fc28ada7736c6bd35ab6f1050f0bfed53f", size = 11466130, upload-time = "2026-08-07T13:30:36.958Z" },
2212
- { url = "https://files.pythonhosted.org/packages/dd/a7/a19334985c4dea8c381981fa252cd854c7ee52dc4b1686dc16f4a911c702/ruff-0.16.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e43e1f5b8388da9eca1b9e88328d47a5cec794633ccf6f7484ac2dd15eee92c0", size = 11523634, upload-time = "2026-08-07T13:30:39.822Z" },
2213
- { url = "https://files.pythonhosted.org/packages/6e/6c/96d192b0e742412ceda08c0a50f9669b253dde9fd6a60ea1a10c9fa79a63/ruff-0.16.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c24788a980581e1d7ea3a0cbe4344c4fbeb0a6a9b1f4713aa46bb104f8294690", size = 10949807, upload-time = "2026-08-07T13:30:42.745Z" },
2214
- { url = "https://files.pythonhosted.org/packages/fa/51/e26599ceca11e79ee255c7df515995561edf87e9ca1893284e44d98f5a86/ruff-0.16.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:81806b08329130005dd4a8a8394a0c9da8c6f4cafb16ba438d2a2ee6a18bedf1", size = 10646891, upload-time = "2026-08-07T13:30:45.522Z" },
2215
- { url = "https://files.pythonhosted.org/packages/68/01/800c4b1f97bc8d7c6029e06b1f20473a3cf1e13c4933d8f3342add83fc55/ruff-0.16.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4ce4e02bad779bef557f541a1b31f20d6abeae1cc05ed1b1ac019d4ffd1044c8", size = 11162063, upload-time = "2026-08-07T13:30:48.131Z" },
2216
- { url = "https://files.pythonhosted.org/packages/e4/d0/1477ea50fc5a0d4b0b71d1d63d50770bdd794d90b43e37a7618e63ec9894/ruff-0.16.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e0422abdf70070255fc4073ce9dfc814cc03db577013761ddd09bc1e4a9a4fbd", size = 11556038, upload-time = "2026-08-07T13:30:50.686Z" },
2217
- { url = "https://files.pythonhosted.org/packages/b8/76/a7776f32048d991e16d4fa8ff91790b877342d3596cc3ed04acdbf1aaedc/ruff-0.16.2-py3-none-win32.whl", hash = "sha256:bf3a63d78fb39f4bf5ac8ae52051c5520505301abe19ba4e204c453b3f09bb0b", size = 10872850, upload-time = "2026-08-07T13:30:53.471Z" },
2218
- { url = "https://files.pythonhosted.org/packages/00/0d/929c800d920e61397d82a01b60bffc68da3052c17d31de59efaad2e4ed75/ruff-0.16.2-py3-none-win_amd64.whl", hash = "sha256:bcabe2f6d0fc7819f1431793005af4e4de7371927d037345bf941252b195b9fa", size = 12023338, upload-time = "2026-08-07T13:30:56.193Z" },
2219
- { url = "https://files.pythonhosted.org/packages/5b/6c/93e26c22c5f78ff87363e07da49c84955affbeb1098bd1936bf3b3f293bf/ruff-0.16.2-py3-none-win_arm64.whl", hash = "sha256:d614e95cedf38a2053fd351c55b103ba30d017d61688fdbfd40ee0412852a99f", size = 11374065, upload-time = "2026-08-07T13:30:58.775Z" },
2199
+ version = "0.16.3"
2200
+ source = { registry = "https://pypi.org/simple" }
2201
+ sdist = { url = "https://files.pythonhosted.org/packages/61/b3/3213589383f8f1b3938781bd1278713f6d18621a14992b3e81fefb8a5ef9/ruff-0.16.3.tar.gz", hash = "sha256:e76d33a347661a84b5be6d043d0347fdc745dfdcf825a8f4fed64b5e26eebdf2", size = 4891904, upload-time = "2026-08-13T15:17:13.381Z" }
2202
+ wheels = [
2203
+ { url = "https://files.pythonhosted.org/packages/bf/96/493770daebd68c0a67f1549fdf519f53be51fc435186c0585bcc272fd76c/ruff-0.16.3-py3-none-linux_armv6l.whl", hash = "sha256:0c5710e247a58a4521e66e124ba9a74655b414f61ba3a2e9e3811e11098f48f7", size = 10902799, upload-time = "2026-08-13T15:16:27.382Z" },
2204
+ { url = "https://files.pythonhosted.org/packages/5e/e6/2becf3942fddc29a29b8df47691d456fb1085391a694f74d84513251418c/ruff-0.16.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:fe155130631a2471fd2e14a7a664a4dfbd7194b8229c3d7b2a40b21178639081", size = 11135539, upload-time = "2026-08-13T15:16:30.87Z" },
2205
+ { url = "https://files.pythonhosted.org/packages/3e/1e/4b8b72f0d006dbf19326aa99f9ca0ee2ff374187c4d301cf529a51aa06fe/ruff-0.16.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e2ed719e14aa64d895c2ee922594a90a43c861a93f0575a95ff8c47cdbd13eb9", size = 10475095, upload-time = "2026-08-13T15:16:33.259Z" },
2206
+ { url = "https://files.pythonhosted.org/packages/92/32/2201fa49ba1f6c101ee321e83f051ac7a4b8d07b0ef6b4d3f2772b302275/ruff-0.16.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e0b1da805eb043654645d74d5de1e5ce2edc686e40790d2b86f56d71cc06a84", size = 10668771, upload-time = "2026-08-13T15:16:35.65Z" },
2207
+ { url = "https://files.pythonhosted.org/packages/c3/66/4afc5c8363bd04d45effce1b7c8713ca037d7a6740b7451a2403a6e3a972/ruff-0.16.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a37bdea0bbe21780f590bf437d6412c8c4e1b6cd010f91a65c2c40c5e5f5f870", size = 10699568, upload-time = "2026-08-13T15:16:38.195Z" },
2208
+ { url = "https://files.pythonhosted.org/packages/53/fd/c67d246bf36bf1698551c56de39e95cd07f70e64433e0098e6267d77061b/ruff-0.16.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09571e6d1288ed9be475207a3ac04ada404f1cd898104be0f6ab8d7df438575b", size = 11499365, upload-time = "2026-08-13T15:16:40.623Z" },
2209
+ { url = "https://files.pythonhosted.org/packages/67/0b/00ecbceb99a263af7b12f6f05ac3c92bc47b905e91adc3f207a836e3bc01/ruff-0.16.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c18c5a101eb540010638cc1ff3c84944d3adb3df62b8d98ca8f22ba484d3413", size = 12311728, upload-time = "2026-08-13T15:16:43.564Z" },
2210
+ { url = "https://files.pythonhosted.org/packages/54/b2/b7b3bb54f4d3f7db504e476ad4ab8de530dceebe2c061384b2757ee419e8/ruff-0.16.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8457c44f15033c85ddbb77b15d451df9e24e4bd03b628396dd3610cedc3b8f82", size = 11699896, upload-time = "2026-08-13T15:16:46.209Z" },
2211
+ { url = "https://files.pythonhosted.org/packages/c7/30/4c468429ac195addc5ee1b717b6ab1b66632786737ca3b2ed3443fb0c26a/ruff-0.16.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:294b95c4ae0cda9388525c2047778aa758d6b8d4bb876fd4e9eaa3ebc92343eb", size = 11058736, upload-time = "2026-08-13T15:16:48.823Z" },
2212
+ { url = "https://files.pythonhosted.org/packages/43/67/7a113cdaddf24b64d7f75b1242a99d04c82fcef4f6921fdbb832beaffb5f/ruff-0.16.3-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:3d0c7c40c87c2a820509c31ba007968da6e1306468c067b2d82fbfdbcd0e8474", size = 11586911, upload-time = "2026-08-13T15:16:51.913Z" },
2213
+ { url = "https://files.pythonhosted.org/packages/f1/c1/2e66f24c0f3ead25a5e660111778685e505e5da353c82802bf49f0cbe7b9/ruff-0.16.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:9f738c0fdfa8eed0b2ce7fb27ee7258208a92a68d7949e62aa15164bc7b389da", size = 10954265, upload-time = "2026-08-13T15:16:54.763Z" },
2214
+ { url = "https://files.pythonhosted.org/packages/c2/ba/4cee23bf52cba9a058d3726de623624daf50ef9638868edd86f4126157f6/ruff-0.16.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fb785f0be25abe69d320415cd4f833b59e17ba7613d9ba6a958023b6bceb0a50", size = 10709886, upload-time = "2026-08-13T15:16:57.339Z" },
2215
+ { url = "https://files.pythonhosted.org/packages/82/df/7da7194fa5d9dc0a285f7e6fa5a4722e7c63faac0b45b614ded9314363a1/ruff-0.16.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c5536e3acfbf9563085aa2be7b13c629c3077e902afc5b941ac44024dbb9f506", size = 11210392, upload-time = "2026-08-13T15:17:00.171Z" },
2216
+ { url = "https://files.pythonhosted.org/packages/35/85/7795f6e817af050e7517bf3e7aa9b061cce70ef33d280aad902c956c1ecf/ruff-0.16.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a2d85c02f9b8e165d85e6779184d38c4132de12603dab59c51c28e22584f9e4d", size = 11626910, upload-time = "2026-08-13T15:17:03.299Z" },
2217
+ { url = "https://files.pythonhosted.org/packages/78/9b/475b927cf27a5cbbda3c7bafb69ed6ff77e1d7923d5d85f17c2749d7ae32/ruff-0.16.3-py3-none-win32.whl", hash = "sha256:388cdf2166642bd9b13d52b5932d3170f34f8abed7e8d9a855f1d84b83645a0a", size = 10931415, upload-time = "2026-08-13T15:17:05.726Z" },
2218
+ { url = "https://files.pythonhosted.org/packages/b2/99/e2a2bfc4fbf0a1e8a916bc9ebe6fe6c58cc34c28e0ffc6ce281d572d1c2e/ruff-0.16.3-py3-none-win_amd64.whl", hash = "sha256:e80a7d69ca2a6d1c4d352ec91458cdca6e56c83cdbcabd93e4abe1e53591d948", size = 11445993, upload-time = "2026-08-13T15:17:08.353Z" },
2219
+ { url = "https://files.pythonhosted.org/packages/69/3e/4132e539aed78c148854d4997a2685b0ed4dc4e87110b59ce528564e184e/ruff-0.16.3-py3-none-win_arm64.whl", hash = "sha256:b8ca152da82c1acc1fa8d5874b15951935f0eef46f10e6954c83859011b6178a", size = 11399302, upload-time = "2026-08-13T15:17:10.908Z" },
2220
2220
  ]
2221
2221
 
2222
2222
  [[package]]