
    6bi                     X    S r SSKrSSKrSSKJr  SSKJr  \" S/ S9 " S S5      5       rg)	zThread utilities.    N)logging)keras_exportzkeras.utils.TimedThread)v1c                   f    \ rS rSrSrS rS rS rS rS r	S r
S	 r\R                  S
 5       rSrg)TimedThread   a	  Time-based interval Threads.

Runs a timed thread every x seconds. It can be used to run a threaded
function alongside model training or any other snippet of code.

Args:
    interval: The interval, in seconds, to wait between calls to the
        `on_interval` function.
    **kwargs: additional args that are passed to `threading.Thread`. By
        default, `Thread` is started as a `daemon` thread unless
        overridden by the user in `kwargs`.

Examples:

```python
class TimedLogIterations(keras.utils.TimedThread):
    def __init__(self, model, interval):
        self.model = model
        super().__init__(interval)

    def on_interval(self):
        # Logs Optimizer iterations every x seconds
        try:
            opt_iterations = self.model.optimizer.iterations.numpy()
            print(f"Epoch: {epoch}, Optimizer Iterations: {opt_iterations}")
        except Exception as e:
            print(str(e))  # To prevent thread from getting killed

# `start` and `stop` the `TimerThread` manually. If the `on_interval` call
# requires access to `model` or other objects, override `__init__` method.
# Wrap it in a `try-except` to handle exceptions and `stop` the thread run.
timed_logs = TimedLogIterations(model=model, interval=5)
timed_logs.start()
try:
    model.fit(...)
finally:
    timed_logs.stop()

# Alternatively, run the `TimedThread` in a context manager
with TimedLogIterations(model=model, interval=5):
    model.fit(...)

# If the timed thread instance needs access to callback events,
# subclass both `TimedThread` and `Callback`.  Note that when calling
# `super`, they will have to called for each parent class if both of them
# have the method that needs to be run. Also, note that `Callback` has
# access to `model` as an attribute and need not be explictly provided.
class LogThreadCallback(
    keras.utils.TimedThread, keras.callbacks.Callback
):
    def __init__(self, interval):
        self._epoch = 0
        keras.utils.TimedThread.__init__(self, interval)
        keras.callbacks.Callback.__init__(self)

    def on_interval(self):
        if self.epoch:
            opt_iter = self.model.optimizer.iterations.numpy()
            logging.info(f"Epoch: {self._epoch}, Opt Iteration: {opt_iter}")

    def on_epoch_begin(self, epoch, logs=None):
        self._epoch = epoch

with LogThreadCallback(interval=5) as thread_callback:
    # It's required to pass `thread_callback` to also `callbacks` arg of
    # `model.fit` to be triggered on callback events.
    model.fit(..., callbacks=[thread_callback])
```
c                 f    Xl         UR                  SS5      U l        X l        S U l        S U l        g )NdaemonT)intervalpopr
   thread_kwargsthreadthread_stop_event)selfr   kwargss      Z/home/james-whalen/.local/lib/python3.13/site-packages/tf_keras/src/utils/timed_threads.py__init__TimedThread.__init__`   s.     jj40#!%    c                     U R                   R                  5       (       dW  U R                  5         U R                   R                  U R                  5        U R                   R                  5       (       d  MV  g g N)r   is_seton_intervalwaitr   r   s    r   _call_on_intervalTimedThread._call_on_intervalg   sR    ((//11""''6 ((//11r   c                 r   U R                   (       a6  U R                   R                  5       (       a  [        R                  " S5        g[        R
                  " SU R                  U R                  S.U R                  D6U l         [        R                  " 5       U l
        U R                   R                  5         g)z"Creates and starts the thread run.zThread is already running.N)targetr
    )r   is_aliver   warning	threadingThreadr   r
   r   Eventr   startr   s    r   r&   TimedThread.startm   s    ;;4;;//11OO89&& 
));;
   

 "+!2r   c                 \    U R                   (       a  U R                   R                  5         gg)zStops the thread run.N)r   setr   s    r   stopTimedThread.stopz   s"    !!""&&( "r   c                 Z    U R                   (       a  U R                   R                  5       $ g)z;Returns True if thread is running. Otherwise returns False.F)r   r!   r   s    r   r!   TimedThread.is_alive   s    ;;;;''))r   c                 &    U R                  5         U $ r   )r&   r   s    r   	__enter__TimedThread.__enter__   s    

r   c                 $    U R                  5         g r   )r*   )r   argsr   s      r   __exit__TimedThread.__exit__   s    		r   c                     [        S5      e)z3User-defined behavior that is called in the thread.zURuns every x interval seconds. Needs to be implemented in subclasses of `TimedThread`)NotImplementedErrorr   s    r   r   TimedThread.on_interval   s     "9
 	
r   )r
   r   r   r   r   N)__name__
__module____qualname____firstlineno____doc__r   r   r&   r*   r!   r/   r3   abcabstractmethodr   __static_attributes__r    r   r   r   r      sF    DL&7)

 	
 
r   r   )r<   r=   r#   abslr    tensorflow.python.util.tf_exportr   r   r    r   r   <module>rB      s:     
   9 'B/{
 {
 0{
r   