Skip to content

Custom lock/rlock classes owning the protected data - #5102

Open
happz wants to merge 2 commits into
mainfrom
threading-locks-own-data
Open

Custom lock/rlock classes owning the protected data#5102
happz wants to merge 2 commits into
mainfrom
threading-locks-own-data

Conversation

@happz

@happz happz commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Compared to the well-known threading.Lock, the locks added here wrap the data they protect. It is still possible to modify the data, since Python does not have actual private attributes, but it's no longer possible to do so by accident or by omission:

# With the classical approach...
_SOME_SHARED_DATA_LOCK = threading.Lock()
SOME_SHARED_DATA = set()

# ... nothing stops me from changing the set without taking the lock:
SOME_SHARED_DATA.add('foo')

# On the other hand, with our custom locks, the set does not exist as
# a value I could modify directly...
SOME_SHARED_DATA: Lock[set[str]] = Lock(set())

# ... and it's "lent" to me only if the wrapper acquires the lock on my
# behalf:
with SOME_SHARED_DATA as the_wrapped_set:
    the_wrapped_set.add('foo')

Pull Request Checklist

  • implement the feature
  • write the documentation
  • extend the test coverage

@happz happz added this to planning Aug 3, 2026
@happz happz added the ci | full test Pull request is ready for the full test execution label Aug 3, 2026
@github-project-automation github-project-automation Bot moved this to backlog in planning Aug 3, 2026
@happz happz moved this from backlog to implement in planning Aug 3, 2026
Comment thread tmt/utils/_threading.py Outdated
@happz happz moved this from implement to review in planning Aug 3, 2026

@LecrisUT LecrisUT left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the intent to move all of the treading locks to these and deny the plain threading.Lock usage?

Also is this part of a chain? Could use the context and see some more in-action usage to confirm typing works and all that.

Comment thread tmt/utils/_threading.py
Comment thread tests/unit/test_threading.py
@happz

happz commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Is the intent to move all of the treading locks to these and deny the plain threading.Lock usage?

Eventually, yes.

Also is this part of a chain? Could use the context and see some more in-action usage to confirm typing works and all that.

Mostly drafts, nothing presentable. But the typing works.

diff --git a/tmt/utils/__init__.py b/tmt/utils/__init__.py
index 8663ea655..d8c78ab20 100644
--- a/tmt/utils/__init__.py
+++ b/tmt/utils/__init__.py
@@ -6220,7 +6220,8 @@ def is_url(url: str) -> bool:
 
 
 # Handle the thread synchronization for the `catch_warnings(...)` context manager
-_catch_warning_lock = RLock()
+import tmt.utils._threading
+_catch_warnings = tmt.utils._threading.RLock(warnings.catch_warnings)
 ActionType = Literal['default', 'error', 'ignore', 'always', 'module', 'once']
 
 
@@ -6246,6 +6247,7 @@ def catch_warnings_safe(
             ...
     """
 
-    with _catch_warning_lock, warnings.catch_warnings():
-        warnings.simplefilter(action=action, category=category)
-        yield
+    with _catch_warnings as catch_warnings:
+        with catch_warnings():
+            warnings.simplefilter(action=action, category=category)
+            yield

@happz
happz force-pushed the threading-locks-own-data branch 3 times, most recently from 7de5ff3 to 6ad7862 Compare August 22, 2026 12:56
@happz
happz force-pushed the threading-locks-own-data branch from 6ad7862 to b9311ee Compare August 26, 2026 14:40
@happz happz moved this from review to merge in planning Aug 27, 2026
@therazix therazix added this to the 1.79 milestone Aug 27, 2026
Compared to the well-known `threading.Lock`, the locks added here wrap
the data they protect. It is still possible to modify the data, since
Python does not have actual private attributes, but it's no longer
possible to do so by accident or by omission:

```python
# With the classical approach...
_SOME_SHARED_DATA_LOCK = threading.Lock()
SOME_SHARED_DATA = set()

# ... nothing stops me from changing the set without taking the lock:
SOME_SHARED_DATA.add('foo')

# On the other hand, with our custom locks, the set does not exist as
# a value I could modify directly...
SOME_SHARED_DATA: Lock[set[str]] = Lock(set())

# ... and it's "lent" to me only if the wrapper acquires the lock on my
# behalf:
with SOME_SHARED_DATA as the_wrapped_set:
    the_wrapped_set.add('foo')
```
@happz
happz force-pushed the threading-locks-own-data branch from b9311ee to ac8997d Compare September 2, 2026 07:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci | full test Pull request is ready for the full test execution

Projects

Status: merge

Development

Successfully merging this pull request may close these issues.

4 participants