Skip to content

Commit

Permalink
Merge branch 'main' into generic-signal
Browse files Browse the repository at this point in the history
  • Loading branch information
tlambert03 authored Nov 4, 2024
2 parents 66a86ce + d6281fc commit cdb2ec3
Show file tree
Hide file tree
Showing 14 changed files with 221 additions and 52 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
fetch-depth: 0
- uses: conda-incubator/setup-miniconda@v3
with:
installer-url: https://github.com/conda-forge/miniforge/releases/latest/download/Mambaforge-Linux-x86_64.sh
installer-url: https://github.com/conda-forge/miniforge/releases/download/24.1.2-0/Mambaforge-24.1.2-0-Linux-x86_64.sh
- name: install
run: |
pip install -U wheel asv
Expand Down
66 changes: 36 additions & 30 deletions .github/workflows/pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,66 @@ name: Publish to PyPI

on:
push:
branches:
- main
tags:
- "v*"
branches: [main]
tags: [v*]

jobs:
main:
if: startsWith(github.event.ref, 'refs/tags/v')
name: sdist + pure wheel
test:
uses: pyapp-kit/workflows/.github/workflows/test-pyrepo.yml@v2
with:
hatch-build-hooks-enable: true
coverage-upload: none

deploy-sdist:
needs: test
if: success() && startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up latest Python
uses: actions/setup-python@v5
- uses: actions/setup-python@v5
with:
python-version: "*"
python-version: "3.x"

- name: Install latest pip, build, twine
- name: 👷 Build
run: |
python -m pip install --upgrade --disable-pip-version-check pip
python -m pip install --upgrade build twine
- name: Build wheel and source distributions
run: python -m build
python -m pip install build
python -m build
- name: Upload to PyPI via Twine
env:
TWINE_PASSWORD: ${{ secrets.pypi_token }}
run: twine upload --verbose -u '__token__' dist/*
- name: 🚢 Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

- uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
files: "./dist/*"

mypyc:
deploy-wheel:
if: startsWith(github.event.ref, 'refs/tags/v')
needs: deploy-sdist
name: mypyc wheels (${{ matrix.name }})
runs-on: ${{ matrix.os }}
permissions:
id-token: write
contents: write
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
name: linux-x86_64
- os: windows-2019
- os: windows-latest
name: windows-amd64
- os: macos-11
- os: macos-13
name: macos-x86_64
macos_arch: "x86_64"
- os: macos-11
- os: macos-14
name: macos-arm64
macos_arch: "arm64"

Expand All @@ -65,17 +71,17 @@ jobs:
fetch-depth: 0

- name: Build wheels via cibuildwheel
uses: pypa/[email protected]
uses: pypa/[email protected]
with:
output-dir: dist
env:
CIBW_ARCHS_MACOS: "${{ matrix.macos_arch }}"

- name: Upload wheels as workflow artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.name }}-mypyc-wheels
path: ./wheelhouse/*.whl
path: ./dist/*.whl

- name: Upload wheels to PyPI via Twine
env:
TWINE_PASSWORD: ${{ secrets.pypi_token }}
run: pipx run twine upload --verbose -u '__token__' wheelhouse/*.whl
- name: 🚢 Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
31 changes: 21 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,18 @@ jobs:
test:
name: Test
uses: pyapp-kit/workflows/.github/workflows/test-pyrepo.yml@v1
uses: pyapp-kit/workflows/.github/workflows/test-pyrepo.yml@v2
with:
os: ${{ matrix.os }}
python-version: ${{ matrix.python-version }}
pip-post-installs: ${{ matrix.pydantic }}
fail-on-coverage-error: false
hatch-build-hooks-enable: ${{ matrix.compile }}
pip-install-pre-release: ${{ github.event_name == 'schedule' }}
report-failures: ${{ github.event_name == 'schedule' }}
secrets: inherit
coverage-upload: artifact
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
os: [ubuntu-latest, macos-latest, windows-latest]
compile: [true, false]
include:
Expand All @@ -60,29 +58,42 @@ jobs:
# still working on ci test errors
- os: windows-latest
python-version: "3.12"
- compile: true
python-version: "3.13"

test-qt:
name: Test Qt
uses: pyapp-kit/workflows/.github/workflows/test-pyrepo.yml@v1
uses: pyapp-kit/workflows/.github/workflows/test-pyrepo.yml@v2
with:
os: ${{ matrix.os }}
python-version: ${{ matrix.python-version }}
qt: ${{ matrix.qt }}
extras: "test,testqt"
hatch-build-hooks-enable: ${{ matrix.compile }}
pip-install-pre-release: ${{ github.event_name == 'schedule' }}
report-failures: ${{ github.event_name == 'schedule' }}
secrets: inherit
coverage-upload: artifact
strategy:
fail-fast: false
matrix:
python-version: ["3.10"]
os: [macos-latest, windows-latest]
qt: [PyQt5, PyQt6, PySide2, PySide6]
compile: [true, false]
exclude:
- os: macos-latest
qt: PySide2
include:
- os: macos-13
qt: PySide2

upload_coverage:
if: always()
needs: [test, test-qt]
uses: pyapp-kit/workflows/.github/workflows/upload-coverage.yml@v2
secrets: inherit

test-magicgui:
uses: pyapp-kit/workflows/.github/workflows/test-dependents.yml@v1
uses: pyapp-kit/workflows/.github/workflows/test-dependents.yml@v2
with:
dependency-repo: pyapp-kit/magicgui
dependency-extras: "test"
Expand Down Expand Up @@ -121,6 +132,6 @@ jobs:
HATCH_BUILD_HOOKS_ENABLE: "1"

- name: Run benchmarks
uses: CodSpeedHQ/action@v2
uses: CodSpeedHQ/action@v3
with:
run: pytest --codspeed -v --color=yes
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,24 @@ exclude: .asv

repos:
- repo: https://github.com/crate-ci/typos
rev: v1.19.0
rev: v1.24.5
hooks:
- id: typos

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

- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.16
rev: v0.19
hooks:
- id: validate-pyproject

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.8.0
rev: v1.11.2
hooks:
- id: mypy
exclude: tests|_throttler.pyi|.*_signal.pyi
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## [v0.11.1](https://github.com/pyapp-kit/psygnal/tree/v0.11.1) (2024-05-07)

[Full Changelog](https://github.com/pyapp-kit/psygnal/compare/v0.11.0...v0.11.1)

**Merged pull requests:**

- perf: let EventedSet use clear\(\) method of underlying set [\#307](https://github.com/pyapp-kit/psygnal/pull/307) ([DanGonite57](https://github.com/DanGonite57))

## [v0.11.0](https://github.com/pyapp-kit/psygnal/tree/v0.11.0) (2024-03-29)

[Full Changelog](https://github.com/pyapp-kit/psygnal/compare/v0.10.2...v0.11.0)
Expand Down
3 changes: 3 additions & 0 deletions benchmarks/benchmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@ def time_update_existing(self, n):
def time_update_overlap(self, n):
self.my_set.update(range(n // 2, n + n // 2))

def time_clear(self, _):
self.my_set.clear()


class EventedSetWithCallbackSuite(EventedSetSuite):
def setup(self, n):
Expand Down
9 changes: 6 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Typing :: Typed",
]
dynamic = ["version"]
Expand Down Expand Up @@ -63,7 +64,7 @@ test = [
"pytest>=6.0",
"pytest-cov",
"wrapt",
"msgspec",
"msgspec; python_version < '3.13'",
"toolz",
]
testqt = ["pytest-qt", "qtpy"]
Expand Down Expand Up @@ -167,8 +168,9 @@ testpaths = ["tests"]
filterwarnings = [
"error",
"ignore:The distutils package is deprecated:DeprecationWarning:",
"ignore:.*BackendFinder.find_spec()", # pyinstaller import
"ignore:.*BackendFinder.find_spec()", # pyinstaller import
"ignore:.*not using a cooperative constructor:pytest.PytestDeprecationWarning:",
"ignore:Failed to disconnect::pytestqt"
]

# https://mypy.readthedocs.io/en/stable/config_file.html
Expand Down Expand Up @@ -204,9 +206,10 @@ exclude_lines = [
"raise NotImplementedError()",
]
show_missing = true

[tool.coverage.run]
source = ["psygnal"]
omit = ["*/_pyinstaller_util/hook-psygnal.py"]
omit = ["*/_pyinstaller_util/*"]

# https://github.com/mgedmin/check-manifest#configuration
[tool.check-manifest]
Expand Down
1 change: 1 addition & 0 deletions src/psygnal/_group_descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

if TYPE_CHECKING:
from _weakref import ref as ref

from typing_extensions import TypeAlias

from psygnal._weak_callback import RefErrorChoice, WeakCallback
Expand Down
50 changes: 48 additions & 2 deletions src/psygnal/_signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,52 @@ def emit(

self._run_emit_loop(args)

def emit_fast(self, *args: Any) -> None:
"""Fast emit without any checks.
This method can be up to 10x faster than `emit()`, but it lacks most of the
features and safety checks of `emit()`. Use with caution. Specifically:
- It does not support `check_nargs` or `check_types`
- It does not use any thread safety locks.
- It is not possible to query the emitter with `Signal.current_emitter()`
- It is not possible to query the sender with `Signal.sender()`
- It does not support "queued" or "latest-only" reemission modes for nested
emits. It will always use "immediate" mode, wherein signals emitted by
callbacks are immediately processed in a deeper emission loop.
It DOES, however, support `paused()` and `blocked()`
Parameters
----------
*args : Any
These arguments will be passed when calling each slot (unless the slot
accepts fewer arguments, in which case extra args will be discarded.)
"""
if self._is_blocked:
return

if self._is_paused:
self._args_queue.append(args)
return

try:
for caller in self._slots:
caller.cb(args)
except RecursionError as e:
raise RecursionError(
f"RecursionError when "
f"emitting signal {self.name!r} with args {args}"
) from e
except EmitLoopError as e: # pragma: no cover
raise e
except Exception as cb_err:
loop_err = EmitLoopError(exc=cb_err, signal=self).with_traceback(
cb_err.__traceback__
)
# this comment will show up in the traceback
raise loop_err from cb_err # emit() call ABOVE || callback error BELOW

def __call__(
self, *args: Any, check_nargs: bool = False, check_types: bool = False
) -> None:
Expand All @@ -1222,9 +1268,9 @@ def _run_emit_loop(self, args: tuple[Any, ...]) -> None:
f"RecursionError when "
f"emitting signal {self.name!r} with args {args}"
) from e
except EmitLoopError as e:
raise e
except Exception as cb_err:
if isinstance(cb_err, EmitLoopError):
raise cb_err
loop_err = EmitLoopError(
exc=cb_err,
signal=self,
Expand Down
2 changes: 1 addition & 1 deletion src/psygnal/_weak_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ def dereference(self) -> MethodType | partial | None:
func = self._func_ref()
if obj is None or func is None:
return None
method = func.__get__(obj)
method = cast(MethodType, func.__get__(obj))
if self._args or self._kwargs:
return partial(method, *self._args, **self._kwargs)
return method
Expand Down
Loading

0 comments on commit cdb2ec3

Please sign in to comment.