Skip to content

Commit 3696e95

Browse files
authored
Merge pull request #49 from pepkit/dev
Release 0.9.2
2 parents ce0b9bd + 69f1c49 commit 3696e95

4 files changed

Lines changed: 25 additions & 26 deletions

File tree

changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format.
44

5+
## [0.9.2] -- 2026-04-02
6+
7+
### Fixed
8+
- Signal handler registration no longer logs false errors in non-main threads (e.g. uvicorn workers); uses `threading.current_thread()` guard instead of try/except
9+
510
## [0.9.1] -- 2026-02-27
611

712
- Added param to untar function

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "ubiquerg"
7-
version = "0.9.1"
7+
version = "0.9.2"
88
description = "Various utility functions"
99
readme = "README.md"
1010
license = "BSD-2-Clause"

ubiquerg/file_locking.py

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import glob
33
import logging
44
import os
5+
import threading
56
from contextlib import contextmanager
67
from signal import SIGINT, SIGTERM, getsignal, signal
78

@@ -218,29 +219,24 @@ def read_lock(obj: object) -> object:
218219
raise AttributeError(f"Cannot lock: {obj}.")
219220

220221
# handle a premature Ctrl+C exit from this context manager
221-
old_sigterm = None
222-
old_sigint = None
223-
try:
224-
old_sigterm = getsignal(SIGTERM)
225-
old_sigint = getsignal(SIGINT)
222+
prev_sigterm = None
223+
prev_sigint = None
224+
if threading.current_thread() is threading.main_thread():
225+
prev_sigterm = getsignal(SIGTERM)
226+
prev_sigint = getsignal(SIGINT)
226227
signal(SIGTERM, locker._interrupt_handler)
227228
signal(SIGINT, locker._interrupt_handler)
228-
# If this is run in a thread, the signal module is not available and raises an exception.
229-
# ValueError: signal only works in main thread of the main interpreter
230-
# That's fine; in this case, we don't need to handle signals anyway.
231-
except ValueError as e:
232-
_LOGGER.error(f"Failed to set interrupt handler: {e}")
233229

234230
locker.read_lock()
235231

236232
try:
237233
yield obj
238234
finally:
239235
locker.read_unlock()
240-
if old_sigterm is not None:
236+
if prev_sigterm is not None:
241237
try:
242-
signal(SIGTERM, old_sigterm)
243-
signal(SIGINT, old_sigint)
238+
signal(SIGTERM, prev_sigterm)
239+
signal(SIGINT, prev_sigint)
244240
except ValueError:
245241
pass
246242

@@ -276,30 +272,28 @@ def write_lock(obj: object) -> object:
276272
raise AttributeError(f"Cannot lock: {obj}.")
277273

278274
# handle a premature Ctrl+C exit from this context manager
279-
old_sigterm = None
280-
old_sigint = None
281-
try:
282-
old_sigterm = getsignal(SIGTERM)
283-
old_sigint = getsignal(SIGINT)
275+
prev_sigterm = None
276+
prev_sigint = None
277+
if threading.current_thread() is threading.main_thread():
278+
prev_sigterm = getsignal(SIGTERM)
279+
prev_sigint = getsignal(SIGINT)
284280
signal(SIGTERM, locker._interrupt_handler)
285281
signal(SIGINT, locker._interrupt_handler)
286-
except ValueError as e:
287-
_LOGGER.error(f"Failed to set interrupt handler: {e}")
288282

289283
locker.write_lock()
290284
try:
291285
yield obj
292286
finally:
293287
locker.write_unlock()
294-
if old_sigterm is not None:
288+
if prev_sigterm is not None:
295289
try:
296-
signal(SIGTERM, old_sigterm)
297-
signal(SIGINT, old_sigint)
290+
signal(SIGTERM, prev_sigterm)
291+
signal(SIGINT, prev_sigint)
298292
except ValueError:
299293
pass
300294

301295

302-
def locked_read_file(filepath, create_file: bool = False) -> str:
296+
def locked_read_file(filepath: str, create_file: bool = False) -> str:
303297
"""Read a file contents into memory after locking the file.
304298
305299
This will prevent other ThreeLocker-protected processes from writing to the

ubiquerg/files.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def untar(src: str, dst: str, **kwargs) -> None:
131131
Args:
132132
src: path to unpack
133133
dst: path to output folder
134-
**kwargs: passed to tarfile.extractall (e.g. filter="fully_trusted")
134+
**kwargs (Any): passed to tarfile.extractall (e.g. filter="fully_trusted")
135135
"""
136136
with topen(src) as tf:
137137
tf.extractall(path=dst, **kwargs)

0 commit comments

Comments
 (0)