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
4 changes: 2 additions & 2 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
name: Benchmark
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-python@v6
Expand All @@ -40,7 +40,7 @@ jobs:

- name: Restore previous results
if: github.event_name != 'pull_request'
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: .asv
key: asv-${{ runner.os }}
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
name: 🐍 sdist and universal wheel
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: hynek/build-and-inspect-python-package@v2
Expand All @@ -24,14 +24,14 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest, macos-13, macos-latest]
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: astral-sh/setup-uv@v7
- name: Build wheels via cibuildwheel
uses: pypa/cibuildwheel@v3.2
uses: pypa/cibuildwheel@v3.3
- name: Upload wheels artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: cibw-wheels-${{ runner.os }}-${{ runner.arch }}
path: ./wheelhouse/*.whl
Expand All @@ -47,12 +47,12 @@ jobs:
steps:

- name: Get sdist
uses: actions/download-artifact@v5
uses: actions/download-artifact@v7
with:
name: Packages
path: dist
- name: Get wheels
uses: actions/download-artifact@v5
uses: actions/download-artifact@v7
with:
pattern: cibw-wheels-*
path: dist
Expand All @@ -61,7 +61,7 @@ jobs:
- name: 🚢 Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
fetch-depth: 0

Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
check-manifest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- run: pipx run check-manifest

test:
Expand Down Expand Up @@ -55,7 +55,7 @@ jobs:
compile: "1"

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v7
with:
enable-cache: true
Expand All @@ -82,7 +82,7 @@ jobs:
run: uv run coverage run -p -m pytest -v

- name: Upload coverage
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: covreport-${{ matrix.os }}-py${{ matrix.python-version }}-mypyc${{ matrix.compile }}-${{ matrix.qt }}
path: ./.coverage*
Expand All @@ -105,7 +105,7 @@ jobs:
typing:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v7
with:
enable-cache: true
Expand All @@ -116,7 +116,7 @@ jobs:
benchmarks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.13"
Expand Down
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,29 @@ repos:
- id: validate-pyproject

- repo: https://github.com/rhysd/actionlint
rev: v1.7.8
rev: v1.7.9
hooks:
- id: actionlint
files: "^\\.github/workflows/.*\\.ya?ml$"

- repo: https://github.com/adhtruong/mirrors-typos
rev: v1.38.1
rev: v1.40.0
hooks:
- id: typos
args: [--force-exclude] # omitting --write-changes

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.0
rev: v0.14.7
hooks:
- id: ruff-check
args: [--fix, --unsafe-fixes]
- id: ruff-format

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.18.2
rev: v1.19.0
hooks:
- id: mypy
exclude: tests|_throttler.pyi
exclude: tests|_throttler.pyi|_group.pyi
additional_dependencies:
- types-attrs
- pydantic
Expand Down
10 changes: 0 additions & 10 deletions src/psygnal/_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,16 +539,6 @@ def __getitem__(self, item: str) -> SignalInstance:
"""Get a signal instance by name."""
return self._psygnal_instances[item]

# this is just here for type checking, particularly on cases
# where the SignalGroup comes from the SignalGroupDescriptor
# (such as in evented dataclasses). In those cases, it's hard to indicate
# to mypy that all remaining attributes are SignalInstances.
def __getattr__(self, __name: str) -> SignalInstance:
"""Get a signal instance by name."""
raise AttributeError( # pragma: no cover
f"{type(self).__name__!r} object has no attribute {__name!r}"
)

def __iter__(self) -> Iterator[str]:
"""Yield the names of all signals in the group."""
return iter(self._psygnal_instances)
Expand Down
39 changes: 39 additions & 0 deletions src/psygnal/_group.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# This stub provides __getattr__ for type checking, which cannot be in the
# main file because mypyc doesn't support __getattr__ in classes with
# allow_interpreted_subclasses=True.
from collections.abc import Iterator, Mapping
from typing import Any, ClassVar

from psygnal._signal import Signal, SignalInstance

class SignalRelay(SignalInstance):
instance: Any
def __init__(
self, signals: Mapping[str, SignalInstance], instance: Any = None
) -> None: ...

class SignalGroup:
_psygnal_signals: ClassVar[Mapping[str, Signal]]
_psygnal_uniform: ClassVar[bool]
_psygnal_name_conflicts: ClassVar[set[str]]
_psygnal_aliases: ClassVar[dict[str, str | None]]
_psygnal_instances: dict[str, SignalInstance]

def __init__(self, instance: Any = None) -> None: ...
def __init_subclass__(
cls,
strict: bool = False,
signal_aliases: Mapping[str, str | None] = ...,
) -> None: ...
@property
def instance(self) -> Any: ...
@property
def all(self) -> SignalRelay: ...
@property
def signals(self) -> Mapping[str, SignalInstance]: ...
def __len__(self) -> int: ...
def __getitem__(self, item: str) -> SignalInstance: ...
def __getattr__(self, name: str) -> SignalInstance: ...
def __iter__(self) -> Iterator[str]: ...
def __contains__(self, item: str) -> bool: ...
def __repr__(self) -> str: ...
Loading