
    	]j+                        d Z ddlZddlZddlmZmZmZ ddlmZmZ ej                  rddl
mZ ddlmZ  ej                  e      Z G d d      Z e       Zd	efd
Zd	efdZ G d d      Z e       Zd	efdZd	eddfdZd	eded   fdZdeded   fdZ G d d      Z e       Z	 	 	 	 dd	edededededefdZ y)z
FSM Model Registry for Model State Management.

This module provides a registry system for state models and state choices,
allowing the FSM to be decoupled from concrete implementations.
    N)DictOptionalType)ModelTextChoices)	BaseState)BaseTransitionc                   `    e Zd ZdZd Zdedee   fdZdede	ee      fdZ
dee   fdZd	 Zy
)StateChoicesRegistryz
    Registry for managing state choices for different entity types.

    Provides a centralized way to register, discover, and manage state choices
    for different entity types in the FSM system.
    c                     i | _         y N)_choicesselfs    C/root/env/lib/python3.12/site-packages/label_studio/fsm/registry.py__init__zStateChoicesRegistry.__init__   s	    68    entity_namechoices_classc                 >    || j                   |j                         <   y)z
        Register state choices for an entity type.

        Args:
            entity_name: Name of the entity (e.g., 'task', 'annotation')
            choices_class: Django TextChoices class defining valid states
        N)r   lower)r   r   r   s      r   registerzStateChoicesRegistry.register    s     .;k'')*r   returnc                 T    | j                   j                  |j                               S )z
        Get state choices for an entity type.

        Args:
            entity_name: Name of the entity

        Returns:
            Django TextChoices class or None if not found
        )r   getr   r   r   s     r   get_choicesz StateChoicesRegistry.get_choices*   s"     }}  !2!2!455r   c                 H    t        | j                  j                               S z*Get a list of all registered entity types.)listr   keysr   s    r   list_entitiesz"StateChoicesRegistry.list_entities6   s    DMM&&())r   c                 8    | j                   j                          y)zp
        Clear all registered choices.

        Useful for testing to ensure clean state between tests.
        N)r   clearr   s    r   r$   zStateChoicesRegistry.clear:   s     	r   N)__name__
__module____qualname____doc__r   strr   r   r   r   r   r    r"   r$    r   r   r   r      sV    9;C ;[8I ;
6s 
6x[8I/J 
6*tCy *r   r   r   c                 ,    t         j                  |       S )z
    Get state choices for an entity type.

    Args:
        entity_name: Name of the entity

    Returns:
        Django TextChoices class or None if not found
    )state_choices_registryr   r   s    r   get_state_choicesr.   G   s     "--k::r   c                 H     dt         t           dt         t           f fd}|S )a  
    Decorator to register state choices for an entity type.

    Args:
        entity_name: Name of the entity type

    Example:
        @register_state_choices('task')
        class TaskStateChoices(models.TextChoices):
            CREATED = 'CREATED', _('Created')
            IN_PROGRESS = 'IN_PROGRESS', _('In Progress')
            COMPLETED = 'COMPLETED', _('Completed')
    r   r   c                 4    t         j                  |        | S r   )r,   r   )r   r   s    r   	decoratorz)register_state_choices.<locals>.decoratorc   s    '']Cr   )r   r   r   r1   s   ` r   register_state_choicesr3   T   s(    k!2 tK7H  r   c                   h    e Zd ZdZd ZdeddfdZdeded   fdZdede	fd	Z
d
 Zdeedf   fdZy)StateModelRegistryz
    Registry for state models and their configurations.

    This allows projects to register their state models dynamically
    without hardcoding them in the FSM framework.
    c                     i | _         y r   )_modelsr   s    r   r   zStateModelRegistry.__init__r   s	    /1r   r   state_modelr   c                 "   |j                         }|| j                  v r=t        j                  dd|| j                  |   j                  |j                  d       || j                  |<   t        j                  dd||j                  d       y)	z
        Register a state model for an entity type.

        Args:
            entity_name: Name of the entity (e.g., 'task', 'annotation')
            state_model: The state model class for this entity
        z Overwriting existing state modelzfsm.registry_overwrite)evententity_typeprevious_model	new_modelextrazRegistered state modelzfsm.model_registered)r:   r;   
model_nameN)r   r7   loggerdebugr%   )r   r   r8   
entity_keys       r   register_modelz!StateModelRegistry.register_modelu   s     !&&(
%LL25#-&*ll:&>&G&G!,!5!5	   $/Z $/))22 	 	
r   r   c                 T    | j                   j                  |j                               S )z
        Get the state model for an entity type.

        Args:
            entity_name: Name of the entity

        Returns:
            State model class or None if not registered
        )r7   r   r   r   s     r   	get_modelzStateModelRegistry.get_model   s"     || 1 1 344r   c                 :    |j                         | j                  v S )z2Check if a model is registered for an entity type.)r   r7   r   s     r   is_registeredz StateModelRegistry.is_registered   s      "dll22r   c                 j    | j                   j                          t        j                  dddi       y)z1Clear all registered models (useful for testing).zState model registry clearedr:   zfsm.registry_clearedr>   N)r7   r$   rA   rB   r   s    r   r$   zStateModelRegistry.clear   s/    *23 	 	
r   c                 6    | j                   j                         S )zGet all registered models.)r7   copyr   s    r   get_all_modelsz!StateModelRegistry.get_all_models   s    ||  ""r   N)r%   r&   r'   r(   r   r)   rD   r   rF   boolrH   r$   r   rL   r*   r   r   r5   r5   j   se    2
# 
K 
>
5S 
5Xk-B 
53 3 3
#S+%5 6 #r   r5   c                      d fd}|S )a  
    Decorator to register a state model.

    Args:
        entity_name: Name of the entity (e.g., 'task', 'annotation')

    Example:
        @register_state_model('task')
        class TaskState(BaseState):
            @classmethod
            def get_denormalized_fields(cls, entity):
                return {
                    'project_id': entity.project_id,
                    'priority': entity.priority
                }
    c                 4    t         j                  |        | S r   state_model_registryrD   )r8   r   s    r   r1   z'register_state_model.<locals>.decorator   s    ++KEr   )r8   r   r   r   r*   r2   s   ` r   register_state_modelrR      s    $ r   r8   r   c                 0    t         j                  | |       y)z
    Convenience function to register a state model programmatically.

    Args:
        entity_name: Name of the entity (e.g., 'task', 'annotation')
        state_model: The state model class for this entity
    NrP   )r   r8   s     r   register_state_model_classrT      s     ''[Ar   r   c                 ,    t         j                  |       S )z
    Convenience function to get a state model.

    Args:
        entity_name: Name of the entity

    Returns:
        State model class or None if not registered
    )rQ   rF   r-   s    r   get_state_modelrV      s      ))+66r   entityc                 `    | j                   j                  j                         }t        |      S )z"Get the state model for an entity.)_metar@   r   rV   )rW   r   s     r   get_state_model_for_entityrZ      s%    ,,))//1K;''r   c                   v    e Zd ZdZd ZdededdfdZdededed   fd	Zdede	edf   fd
Z
dee   fdZd Zy)TransitionRegistryz
    Registry for managing declarative transitions.

    Provides a centralized way to register, discover, and execute transitions
    for different entity types and state models.
    c                     i | _         y r   _transitionsr   s    r   r   zTransitionRegistry.__init__   s
    DFr   r   transition_nametransition_classr	   c                 b    || j                   vri | j                   |<   || j                   |   |<   y)a6  
        Register a transition class for an entity.

        Args:
            entity_name: Name of the entity type (e.g., 'task', 'annotation')
            transition_name: Name of the transition (e.g., 'start_task', 'submit_annotation')
            transition_class: The transition class to register
        Nr^   )r   r   r`   ra   s       r   r   zTransitionRegistry.register   s7     d///-/Dk*:J+&7r   r   c                 X    | j                   j                  |i       j                  |      S )z
        Get a registered transition class.

        Args:
            entity_name: Name of the entity type
            transition_name: Name of the transition

        Returns:
            The transition class if found, None otherwise
        )r_   r   )r   r   r`   s      r   get_transitionz!TransitionRegistry.get_transition  s(       $$["599/JJr   c                 V    | j                   j                  |i       j                         S )z
        Get all registered transitions for an entity type.

        Args:
            entity_name: Name of the entity type

        Returns:
            Dictionary mapping transition names to transition classes
        )r_   r   rK   r   s     r   get_transitions_for_entityz-TransitionRegistry.get_transitions_for_entity  s&       $$["5::<<r   c                 H    t        | j                  j                               S r   )r    r_   r!   r   s    r   r"   z TransitionRegistry.list_entities  s    D%%**,--r   c                 8    | j                   j                          y)zt
        Clear all registered transitions.

        Useful for testing to ensure clean state between tests.
        N)r_   r$   r   s    r   r$   zTransitionRegistry.clear"  s     	!r   N)r%   r&   r'   r(   r   r)   r   r   rd   r   rf   r    r"   r$   r*   r   r   r\   r\      s    GKC K# KQa KK# K KQaHb K
=c 
=d3HXCX>Y 
=.tCy ."r   r\   r`   triggers_on_createtriggers_on_updatetriggers_onforce_state_recordc                 (     d fd}|S )a  
    Decorator to register a state transition class with trigger metadata.

    This decorator not only registers the transition but also configures when
    it should be triggered based on model changes.

    Args:
        entity_name: Name of the entity type (e.g., 'task', 'project')
        transition_name: Name of the transition (e.g., 'task_created')
        triggers_on_create: If True, triggers when entity is created
        triggers_on_update: If True, can trigger on updates (default: True)
        triggers_on: List of field names that trigger this transition
        force_state_record: If True, creates state record even if state doesn't change (for audit trails)

    Example:
        # Trigger only on creation
        @register_state_transition('task', 'task_created', triggers_on_create=True)
        class TaskCreatedTransition(ModelChangeTransition):
            pass

        # Trigger when specific fields change
        @register_state_transition('project', 'project_published', triggers_on=['is_published'])
        class ProjectPublishedTransition(ModelChangeTransition):
            pass

        # Trigger when any of several fields change
        @register_state_transition('project', 'settings_changed',
                                   triggers_on=['maximum_annotations', 'overlap_cohort_percentage'])
        class ProjectSettingsChangedTransition(ModelChangeTransition):
            pass
    c                     | _         | _        xs g | _        | _        | _        t
        j                  |        | S r   )_triggers_on_create_triggers_on_update_trigger_fields_transition_name_force_state_recordtransition_registryr   )ra   r   rl   r`   rk   ri   rj   s    r   r1   z,register_state_transition.<locals>.decoratorW  sN    /A,/A,+6+<"(,;)/A,$$[/CSTr   )ra   r	   r   r	   r*   )r   r`   ri   rj   rk   rl   r1   s   `````` r   register_state_transitionru   /  s    P	  	  r   )FTNF)!r(   loggingtypingr   r   r   django.db.modelsr   r   TYPE_CHECKINGfsm.state_modelsr   fsm.transitionsr	   	getLoggerr%   rA   r   r,   r)   r.   r3   r5   rQ   rR   rT   rV   rZ   r\   rt   rM   r    ru   r*   r   r   <module>r}      s5     ' ' /	*.			8	$+ +^ ./ 
;3 
; ,D# D#P *+ c 2BC Bk B
7 
7+)> 
7(u (+1F (<" <"@ )*   %#$333 3 	3
 3 3r   