Metadata-Version: 2.4
Name: cs-threads
Version: 20260912
Summary: threading and communication/synchronisation conveniences
Keywords: python2,python3
Author-email: Cameron Simpson <cs@cskk.id.au>
Description-Content-Type: text/markdown
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Requires-Dist: cs.context>=20250528
Requires-Dist: cs.deco>=20260912
Requires-Dist: cs.excutils>=20250306
Requires-Dist: cs.logutils>=20250323
Requires-Dist: cs.pfx>=20260912
Requires-Dist: cs.py.func>=20250914
Requires-Dist: cs.py.stack>=20250724
Requires-Dist: cs.seq>=20260912
Requires-Dist: icontract
Project-URL: MonoRepo Commits, https://bitbucket.org/cameron_simpson/css/commits/branch/main
Project-URL: Monorepo Git Mirror, https://github.com/cameron-simpson/css
Project-URL: Monorepo Hg/Mercurial Mirror, https://hg.sr.ht/~cameron-simpson/css
Project-URL: Source, https://github.com/cameron-simpson/css/blob/main/lib/python/cs/threads.py

Thread related convenience classes and functions.

*Latest release 20260912*:
pmap: dispatcher: issue a warning about exceptions and reraise so that they are visible.



Short summary:


* `AdjustableSemaphore`: A semaphore whose value may be tuned after instantiation.


* `bg`: Dispatch the callable `func` in its own `Thread`; return the `Thread`.


* `DeadlockError`: Raised by `NRLock` when a lock is attempted from the `Thread` currently holding the lock.


* `HasThreadState`: A mixin for classes with a `cs.threads.ThreadState` instance as `.state` providing a context manager which pushes `current=self` onto that state and a `default()` class method returning `cls.perthread_state.current` as the default instance of that class.


* `joinif`: Call `T.join()` if `T` is not the current `Thread`.


* `LockableMixin`: Trite mixin to control access to an object via its `._lock` attribute. Exposes the `._lock` as the property `.lock`. Presents a context manager interface for obtaining an object's lock.


* `locked`: A decorator for instance methods that must run within a lock.


* `locked_property`: A thread safe property whose value is cached. The lock is taken if the value needs to computed.


* `monitor`: Turn a class into a monitor, all of whose public methods are `@locked`.


* `NRLock`: A nonrecursive lock. Attempting to take this lock when it is already held by the current `Thread` will raise `DeadlockError`. Otherwise this behaves like `threading.Lock`.


* `pmap`: A generator yielding the result of `func(item)` for each `item` in the iterable `it`, evaluated in parallel, kin to `cs.nayasync.amap`.


* `PriorityLock`: A priority based mutex which is acquired by and released to waiters in priority order.


* `PriorityLockSubLock`: The record for the per-`acquire`r `Lock` held by `PriorityLock.acquire`.


* `State`: A `Thread` local object with attributes which can be used as a context manager to stack attribute values.


* `ThreadState`: A `Thread` local object with attributes which can be used as a context manager to stack attribute values.


* `via`: Return a callable that calls the supplied `func` inside a `with` statement using the context manager `cmanager`. This intended use case is aimed at deferred function calls.

# Functions

## bg(func, *, daemon=None, name=None, no_start=False, no_logexc=False, args=None, kwargs=None, thread_factory=None, pre_enter_objects=None, **thread_factory_kw)

Dispatch the callable `func` in its own `Thread`;
return the `Thread`.

Parameters:
* `func`: a callable for the `Thread` target.
* `args`, `kwargs`: passed to the `Thread` constructor
* `kwargs`, `kwargs`: passed to the `Thread` constructor
* `daemon`: optional argument specifying the `.daemon` attribute.
* `name`: optional argument specifying the `Thread` name,
  default: the name of `func`.
* `no_logexc`: if false (default `False`), wrap `func` in `@logexc`.
* `no_start`: optional argument, default `False`.
  If true, do not start the `Thread`.
* `pre_enter_objects`: an optional iterable of objects which
  should be entered using `with`

If `pre_enter_objects` is supplied, these context manager
objects will be entered using `with` via the `closeall()`
function before the `Thread` is started and exited when the
`Thread` target function ends.
If the `Thread` is _not_ started (`no_start=True`, very
unusual) then the objects will still be entered and it will
be the caller's responsibility to manage the entered objects.

## joinif(T: threading.Thread)

Call `T.join()` if `T` is not the current `Thread`.

Unlike `threading.Thread.join`, this function is a no-op if
`T` is the current `Thread.

The use case is situations such as the shutdown phase of the
`MultiOpenMixin.startup_shutdown` context manager. Because
the "initial open" startup phase is not necessarily run in
the same thread as the "final close" shutdown phase, it is
possible for example for a worker `Thread` to execute the
shutdown phase and try to join itself. Using this function
supports that scenario.

## locked(*da, **dkw)

A decorator for instance methods that must run within a lock.

Decorator keyword arguments:
* `initial_timeout`:
  the initial lock attempt timeout;
  if this is `>0` and exceeded a warning is issued
  and then an indefinite attempt is made.
  Default: `2.0`s
* `lockattr`:
  the name of the attribute of `self`
  which references the lock object.
  Default `'_lock'`

## locked_property(*da, **dkw)

A thread safe property whose value is cached.
The lock is taken if the value needs to computed.

The default lock attribute is `._lock`.
The default attribute for the cached value is `._`*funcname*
where *funcname* is `func.__name__`.
The default "unset" value for the cache is `None`.

## monitor(*da, **dkw)

Turn a class into a monitor, all of whose public methods are `@locked`.

This is a simple approach which requires class instances to have a
`._lock` which is an `RLock` or compatible
because methods may naively call each other.

Parameters:
* `attrs`: optional iterable of attribute names to wrap in `@locked`.
  If omitted, all names commencing with a letter are chosen.
* `initial_timeout`: optional initial lock timeout, default `10.0`s.
* `lockattr`: optional lock attribute name, default `'_lock'`.

Only attributes satifying `inspect.ismethod` are wrapped
because `@locked` requires access to the instance `._lock` attribute.

## pmap(func, it: Iterable, *, concurrent: Union[int, threading.Semaphore, NoneType] = None, unordered=False, indexed=False, with_exceptions=False) -> Generator

A generator yielding the result of `func(item)`
for each `item` in the iterable `it`,
evaluated in parallel, kin to `cs.nayasync.amap`.

See `cs.naysync.amap` for a version of this for asynchronous code.

Parameters:
* `func`: the callable to accept items from `it`
* `it`: an iterable of items to apply to `func`
* `concurrent`: a optional constraint on the number of parallel
  calls to `func`; if `None` then no constraint, if an `int` then
  a maximum of that many calls, if a `Semaphore` use that as
  the constraint
* `unordered`: optional flag, default `False`;
  if true then yield results as calls complete, otherwise
  yield results in the same order as `it` though still as
  soon as available
* `indexed`: if true, yield `(index,result)` instead of `result`
  where `index` is the ordinal from `enumerate(it)`
* `with_exceptions`: yield `(result,exc)` as the result value
  instead of `result`; in this mode exceptions from calls to
  `func` are not reraised, as they come back in the yield values

Note that `indexed=True` and `with_exceptions=True` produce
`(index,(result,exc))` tuples.

Example concurrent in call order:

    >>> import time
    >>> sleep_times = [0.1, 0.4, 0.2]
    >>>
    >>> start = time.time()
    >>> for index, result in pmap(
    ...   lambda delay: (time.sleep(delay),delay)[-1],
    ...   sleep_times,
    ...   unordered=False,
    ...   indexed=True):
    ...     print(index, result)
    ...
    0 0.1
    1 0.4
    2 0.2
    >>> # concurrent delays
    >>> assert 0.4 < time.time() - start < 0.5

Example concurrent in completion order:

    >>> import time
    >>> start = time.time()
    >>> for index, result in pmap(
    ...   lambda delay: (time.sleep(delay),delay)[-1],
    ...   sleep_times,
    ...   unordered=True,
    ...   indexed=True):
    ...     print(index, result)
    ...
    0 0.1
    2 0.2
    1 0.4
    >>> # concurrent delays
    >>> assert 0.4 < time.time() - start < 0.5

## via(cmanager, func, *a, **kw)

Return a callable that calls the supplied `func` inside a
`with` statement using the context manager `cmanager`.
This intended use case is aimed at deferred function calls.

# Classes

## class AdjustableSemaphore

A semaphore whose value may be tuned after instantiation.

### `AdjustableSemaphore.__dict__`

Read-only proxy of a mapping.

### `AdjustableSemaphore.__firstlineno__`

int([x]) -> integer
int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments
are given.  If x is a number, return x.__int__().  For floating-point
numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string,
bytes, or bytearray instance representing an integer literal in the
given base.  The literal can be preceded by '+' or '-' and be surrounded
by whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.
Base 0 means to interpret the base from the string as an integer literal.
>>> int('0b100', base=0)
4

### `AdjustableSemaphore.__static_attributes__`

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple.
If iterable is specified the tuple is initialized from iterable's items.

If the argument is a tuple, the return value is the same object.

### `AdjustableSemaphore.acquire(self, blocking=True)`

The acquire() method calls the base acquire() method if not blocking.
If blocking is true, the base acquire() is called inside a lock to
avoid competing with a reducing adjust().

### `AdjustableSemaphore.adjust(self, newvalue)`

Set capacity to `newvalue`
by calling release() or acquire() an appropriate number of times.

If `newvalue` lowers the semaphore capacity then adjust()
may block until the overcapacity is released.

### `AdjustableSemaphore.adjust_delta(self, delta)`

Adjust capacity by `delta` by calling release() or acquire()
an appropriate number of times.

If `delta` lowers the semaphore capacity then adjust() may block
until the overcapacity is released.

### `AdjustableSemaphore.release(self)`

Release the semaphore.

## class DeadlockError(builtins.RuntimeError)

Raised by `NRLock` when a lock is attempted from the `Thread` currently holding the lock.

### `DeadlockError.__firstlineno__`

int([x]) -> integer
int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments
are given.  If x is a number, return x.__int__().  For floating-point
numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string,
bytes, or bytearray instance representing an integer literal in the
given base.  The literal can be preceded by '+' or '-' and be surrounded
by whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.
Base 0 means to interpret the base from the string as an integer literal.
>>> int('0b100', base=0)
4

### `DeadlockError.__static_attributes__`

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple.
If iterable is specified the tuple is initialized from iterable's items.

If the argument is a tuple, the return value is the same object.

## class HasThreadState(cs.context.ContextManagerMixin)

A mixin for classes with a `cs.threads.ThreadState` instance as `.state`
providing a context manager which pushes `current=self` onto that state
and a `default()` class method returning `cls.perthread_state.current`
as the default instance of that class.

*NOTE*: the documentation here refers to `cls.perthread_state`, but in
fact we honour the `cls.THREAD_STATE_ATTR` attribute to name
the state attribute which allows perclass state attributes,
and also use with classes which already use `.perthread_state` for
another purpose.

*NOTE*: `HasThreadState.Thread` is a _class_ method whose default
is to push state for all active `HasThreadState` subclasses.
Contrast with `HasThreadState.bg` which is an _instance_ method
whose default is to push state for just that instance.
The top level `cs.threads.bg` function calls `HasThreadState.Thread`
to obtain its `Thread`.

### `HasThreadState.THREAD_STATE_ATTR`

str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or
errors is specified, then the object must expose a data buffer
that will be decoded using the given encoding and error handler.
Otherwise, returns the result of object.__str__() (if defined)
or repr(object).
encoding defaults to 'utf-8'.
errors defaults to 'strict'.

### `HasThreadState.Thread(*, name=None, target, enter_objects=None, **Thread_kw)`

Factory for a `Thread` to push the `.current` state for the
currently active classes.

The optional parameter `enter_objects` may be used to pass
an iterable of objects whose contexts should be entered
using `with obj:`.
If this is set to `True` that indicates that every "current"
`HasThreadStates` instance should be entered.
The default does not enter any object contexts.
The `HasThreadStates.bg` method defaults to passing
`enter_objects=(self,)` to enter the context for `self`.

### `HasThreadState.__enter_exit__(self)`

Push `self.perthread_state.current=self` as the `Thread` local current instance.

Include `self.__class__` in the set of currently active classes for the duration.

### `HasThreadState.__firstlineno__`

int([x]) -> integer
int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments
are given.  If x is a number, return x.__int__().  For floating-point
numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string,
bytes, or bytearray instance representing an integer literal in the
given base.  The literal can be preceded by '+' or '-' and be surrounded
by whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.
Base 0 means to interpret the base from the string as an integer literal.
>>> int('0b100', base=0)
4

### `HasThreadState.__static_attributes__`

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple.
If iterable is specified the tuple is initialized from iterable's items.

If the argument is a tuple, the return value is the same object.

### `HasThreadState.bg(self, func, *, enter_objects=None, **bg_kw)`

Get a `Thread` using `type(self).Thread` and start it.
Return the `Thread`.

The `HasThreadState.Thread` factory duplicates the current `Thread`'s
`HasThreadState` current objects as current in the new `Thread`.
Additionally, and optionally, it enters the contexts of
various objects using `with obj` according to the `enter_objects`
parameter.

The value of the optional parameter `enter_objects` governs
which objects have their context entered using `with obj`
in the child `Thread` while running `func` as follows:
- `None`: the default, meaning `(self,)`
- `False`: no object contexts are entered
- `True`: all current `HasThreadState` object contexts will be entered
- an iterable of objects whose contexts will be entered;
  pass `()` (or `False` as above) to enter no objects

### `HasThreadState.default(*, factory=None, raise_on_None=False)`

The default instance of this class from `cls.perthread_state.current`.

Parameters:
* `factory`: optional callable to create an instance of `cls`
  if `cls.perthread_state.current` is `None` or missing;
  if `factory` is `True` then `cls` is used as the factory
* `raise_on_None`: if `cls.perthread_state.current` is `None` or missing
  and `factory` is false and `raise_on_None` is true,
  raise a `RuntimeError`;
  this is primarily a debugging aid

### `HasThreadState.get_thread_states(all_classes=None)`

Return a mapping of `class`->*current_instance*`
for use with `HasThreadState.with_thread_states`
or `HasThreadState.Thread` or `HasThreadState.bg`.

The default behaviour returns just a mapping for this class,
expecting the default instance to be responsible for what
other resources it holds.

There is also a legacy mode for `all_classes=True`
where the mapping is for all active classes,
probably best used for `Thread`s spawned outside
a `HasThreadState` context.

Parameters:
* `all_classes`: optional flag, default `False`;
  if true, return a mapping of class to current instance
  for all `HasThreadState` subclasses with an open instance,
  otherwise just a mapping from this class to its current instance

## class LockableMixin

Trite mixin to control access to an object via its `._lock` attribute.
Exposes the `._lock` as the property `.lock`.
Presents a context manager interface for obtaining an object's lock.

### `LockableMixin.__dict__`

Read-only proxy of a mapping.

### `LockableMixin.__exit__(self, exc_type, exc_value, traceback)`

pylint: disable=unused-argument

### `LockableMixin.__firstlineno__`

int([x]) -> integer
int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments
are given.  If x is a number, return x.__int__().  For floating-point
numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string,
bytes, or bytearray instance representing an integer literal in the
given base.  The literal can be preceded by '+' or '-' and be surrounded
by whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.
Base 0 means to interpret the base from the string as an integer literal.
>>> int('0b100', base=0)
4

### `LockableMixin.__static_attributes__`

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple.
If iterable is specified the tuple is initialized from iterable's items.

If the argument is a tuple, the return value is the same object.

### `LockableMixin.lock`

The internal lock object.

## class NRLock

A nonrecursive lock.
Attempting to take this lock when it is already held by the current `Thread`
will raise `DeadlockError`.
Otherwise this behaves like `threading.Lock`.

### `NRLock.__firstlineno__`

int([x]) -> integer
int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments
are given.  If x is a number, return x.__int__().  For floating-point
numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string,
bytes, or bytearray instance representing an integer literal in the
given base.  The literal can be preceded by '+' or '-' and be surrounded
by whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.
Base 0 means to interpret the base from the string as an integer literal.
>>> int('0b100', base=0)
4

### `NRLock.__slots__`

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple.
If iterable is specified the tuple is initialized from iterable's items.

If the argument is a tuple, the return value is the same object.

### `NRLock.__static_attributes__`

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple.
If iterable is specified the tuple is initialized from iterable's items.

If the argument is a tuple, the return value is the same object.

### `NRLock.acquire(self, *a, caller_frame=None, **kw)`

Acquire the lock as for `threading.Lock`.
Raises `DeadlockError` is the lock is already held by the current `Thread`.

### `NRLock.locked(self)`

Return the lock status.

### `NRLock.release(self)`

Release the lock as for `threading.Lock`.

## class PriorityLock

A priority based mutex which is acquired by and released to waiters
in priority order.

The initialiser sets a default priority, itself defaulting to `0`.

The `acquire()` method accepts an optional `priority` value
which specifies the priority of the acquire request;
lower values have higher priorities.
`acquire` returns a new `PriorityLockSubLock`.

Note that internally this allocates a `threading.Lock` per acquirer.

When `acquire` is called, if the `PriorityLock` is taken
then the acquirer blocks on their personal `Lock`.

When `release()` is called the highest priority `Lock` is released.

Within a priority level `acquire`s are served in FIFO order.

Used as a context manager, the mutex is obtained at the default priority.
The `priority()` method offers a context manager
with a specified priority.
Both context managers return the `PriorityLockSubLock`
allocated by the `acquire`.

### `PriorityLock.__init__(self, default_priority=0, name=None)`

Initialise the `PriorityLock`.

Parameters:
* `default_priority`: the default `acquire` priority,
  default `0`.
* `name`: optional identifying name

### `PriorityLock.__dict__`

Read-only proxy of a mapping.

### `PriorityLock.__enter__(self)`

Enter the mutex as a context manager at the default priority.
Returns the new `Lock`.

### `PriorityLock.__exit__(self, *_)`

Exit the context manager.

### `PriorityLock.__firstlineno__`

int([x]) -> integer
int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments
are given.  If x is a number, return x.__int__().  For floating-point
numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string,
bytes, or bytearray instance representing an integer literal in the
given base.  The literal can be preceded by '+' or '-' and be surrounded
by whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.
Base 0 means to interpret the base from the string as an integer literal.
>>> int('0b100', base=0)
4

### `PriorityLock.__static_attributes__`

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple.
If iterable is specified the tuple is initialized from iterable's items.

If the argument is a tuple, the return value is the same object.

### `PriorityLock.acquire(self, priority=None)`

Acquire the mutex with `priority` (default from `default_priority`).
Return the new `PriorityLockSubLock`.

This blocks behind any higher priority `acquire`s
or any earlier `acquire`s of the same priority.

### `PriorityLock.priority(self, this_priority)`

A context manager with the specified `this_priority`.
Returns the new `Lock`.

### `PriorityLock.release(self)`

Release the mutex.

Internally, this releases the highest priority `Lock`,
allowing that `acquire`r to go forward.

## class PriorityLockSubLock(PriorityLockSubLock)

The record for the per-`acquire`r `Lock` held by `PriorityLock.acquire`.

### `PriorityLockSubLock.__dict__`

Read-only proxy of a mapping.

### `PriorityLockSubLock.__firstlineno__`

int([x]) -> integer
int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments
are given.  If x is a number, return x.__int__().  For floating-point
numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string,
bytes, or bytearray instance representing an integer literal in the
given base.  The literal can be preceded by '+' or '-' and be surrounded
by whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.
Base 0 means to interpret the base from the string as an integer literal.
>>> int('0b100', base=0)
4

### `PriorityLockSubLock.__static_attributes__`

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple.
If iterable is specified the tuple is initialized from iterable's items.

If the argument is a tuple, the return value is the same object.

## class State(_thread._local)

A `Thread` local object with attributes
which can be used as a context manager to stack attribute values.

Example:

    from cs.threads import ThreadState

    S = ThreadState(verbose=False)

    with S(verbose=True) as prev_attrs:
        if S.verbose:
            print("verbose! (formerly verbose=%s)" % prev_attrs['verbose'])

### `State.__init__(self, **kw)`

Initiate the `ThreadState`, providing the per-Thread initial values.

### `State.__call__(self, **kw)`

Calling a `ThreadState` returns a context manager which stacks some state.
The context manager yields the previous values
for the attributes which were stacked.

### `State.__dict__`

Read-only proxy of a mapping.

### `State.__firstlineno__`

int([x]) -> integer
int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments
are given.  If x is a number, return x.__int__().  For floating-point
numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string,
bytes, or bytearray instance representing an integer literal in the
given base.  The literal can be preceded by '+' or '-' and be surrounded
by whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.
Base 0 means to interpret the base from the string as an integer literal.
>>> int('0b100', base=0)
4

### `State.__static_attributes__`

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple.
If iterable is specified the tuple is initialized from iterable's items.

If the argument is a tuple, the return value is the same object.

## class ThreadState(_thread._local)

A `Thread` local object with attributes
which can be used as a context manager to stack attribute values.

Example:

    from cs.threads import ThreadState

    S = ThreadState(verbose=False)

    with S(verbose=True) as prev_attrs:
        if S.verbose:
            print("verbose! (formerly verbose=%s)" % prev_attrs['verbose'])

### `ThreadState.__init__(self, **kw)`

Initiate the `ThreadState`, providing the per-Thread initial values.

### `ThreadState.__call__(self, **kw)`

Calling a `ThreadState` returns a context manager which stacks some state.
The context manager yields the previous values
for the attributes which were stacked.

### `ThreadState.__dict__`

Read-only proxy of a mapping.

### `ThreadState.__firstlineno__`

int([x]) -> integer
int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments
are given.  If x is a number, return x.__int__().  For floating-point
numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string,
bytes, or bytearray instance representing an integer literal in the
given base.  The literal can be preceded by '+' or '-' and be surrounded
by whitespace.  The base defaults to 10.  Valid bases are 0 and 2-36.
Base 0 means to interpret the base from the string as an integer literal.
>>> int('0b100', base=0)
4

### `ThreadState.__static_attributes__`

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple.
If iterable is specified the tuple is initialized from iterable's items.

If the argument is a tuple, the return value is the same object.

# Release Log



*Release 20260912*:
pmap: dispatcher: issue a warning about exceptions and reraise so that they are visible.

*Release 20260610*:
Bugfix pmap, race condition could prevent termination detection resulting in a hang.

*Release 20260531*:
pmap docstring updates.

*Release 20260530*:
pmap: some bug fixes.

*Release 20260526*:
New pmap(func,items) function, a parallel version of map(), like cs.nayasync.amap().

*Release 20250528*:
Small doc update.

*Release 20250325*:
NRLock: include the lock name in DeadLock exceptions.

*Release 20250306*:
HasThreadState: various fixes.

*Release 20241005*:
Remove some debug noise.

*Release 20240630*:
* bg: use closeall instead of twostep/withall.
* HasThreadState.bg: drop pre_enter_objects (unused), gets plumbed by the **bg_kw.

*Release 20240422*:
HasThreadState.default: make factory and raise_on keyword only.

*Release 20240412*:
* New NRLock, an nonrecursive Lock and associated exception DeadlockError.
* bg: rename thread_class to thread_factory for clarity.
* HasThreadState: big refactor to separate the mapping of default instances from the previously automatic opening of a context for each.
* HasThreadState.bg: new optional pre_enter_objects to supply objects which should be opened before the Thread starts (before bg returns) and closed when the Thread exits.

*Release 20240316*:
Fixed release upload artifacts.

*Release 20240303*:
* HasThreadState: rename thread_states() to get_thread_states().
* HasThreadState.get_thread_states: some logic fixes.

*Release 20231129*:
* HasThreadState.thread_states: *policy change*: the default now makes a mapping only for this class, not for all HasThreadState subclasses, on the premise that this class can manage use of other classes if required.
* HasThreadState: new bg() class method like Thread() but also starting the Thread.

*Release 20230331*:
* HasThreadState: new thread_states() method to snapshot the current states.
* HasThreadState: new with_thread_states() context manager to apply a set of states.
* HasThreadState: rename the default state from .state to .perthread_state.
* HasThreadState.__enter_exit__: pass cls._HasThreadState_lock to stackset as the modification guard lock, prevents race in thread_states.
* Rename State to ThreadState, which how I always use it anyway, and leave a compatibility name behind.
* New joinif(Thread) method to join a Thread unless we are that Thread - this is because MultiOpenMixin.startup_shutdown stuff may run the shutdown in a differ Thread from that which ran the startup.
* @uses_runstate: use the prevailing RunState or create one.
* Drop Python 2 support.

*Release 20230212*:
* HasThreadState: maintain a set of the HasThreadState classes in use.
* New HasThreadState.Thread class factory method to create a new Thread with the current threads states at time of call instantiated in the new Thread.
* bg: new no_context=False parameter to suppress use of HasThreadState.Thread to create the new Thread.

*Release 20230125*:
New HasThreadState mixin for classes with a state=State() attribute to provide a cls.default() class method for the default instance and a context manager to push/pop self.state.current=self.

*Release 20221228*:
* Get error and warning from cs.gimmicks, breaks circular import with cs.logutils.
* Late import of cs.logutils.LogTime to avoid circular import.

*Release 20221207*:
Small bug fix.

*Release 20221118*:
REMOVE WorkerThreadPool, pulls in too many other things and was never used.

*Release 20211208*:
bg: do not pass the current Pfx prefix into the new Thread, seems to leak and grow.

*Release 20210306*:
bg: include the current Pfx prefix in the thread name and thread body Pfx, obsoletes cs.pfx.PfxThread.

*Release 20210123*:
New @monitor class decorator for simple RLock based reentrance protection.

*Release 20201025*:
* @locked: bump the default warning timeout to 10s, was firing too often.
* New State class for thread local state objects with default attribute values and a stacking __call__ context manager.

*Release 20200718*:
@locked: apply the interior __doc__ to the wrapper.

*Release 20200521*:
@locked_property: decorate with @cs.deco.decorator to support keyword arguments.

*Release 20191102*:
@locked: report slow-to-acquire locks, add initial_timeout and lockattr decorator keyword parameters.

*Release 20190923.2*:
Fix annoying docstring typo.

*Release 20190923.1*:
Docstring updates.

*Release 20190923*:
Remove dependence on cs.obj.

*Release 20190921*:
New PriorityLock class for a mutex which releases in (priority,fifo) order.

*Release 20190812*:
bg: compute default name before wrapping `func` in @logexc.

*Release 20190729*:
bg: provide default `name`, run callable inside Pfx, add optional no_logexc=False param preventing @logec wrapper if true.

*Release 20190422*:
bg(): new optional `no_start=False` keyword argument, preventing Thread.start if true

*Release 20190102*:
* Drop some unused classes.
* New LockableMixin, presenting a context manager and a .lock property.

*Release 20160828*:
Use "install_requires" instead of "requires" in DISTINFO.

*Release 20160827*:
* Replace bare "excepts" with "except BaseException".
* Doc updates. Other minor improvements.

*Release 20150115*:
First PyPI release.
