U
    ¿d=I                     @   sR  d Z ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddl	m
Z
 ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ dd Zdd Zdd Zdd Zdd Zdd Zdd Zd d! Z d"d# Z!d$d% Z"d&d' Z#d6d)d*Z$d+d, Z%d-d. Z&d/d0 Z'd1d2 Z(d3d4 Z)d5S )7z>
Appraise evaluation framework

See LICENSE for usage details
    )defaultdict)OrderedDict)md5)JSONDecodeError)load)User)CommandError)Campaign)CampaignTeam)LANGUAGE_CODES_AND_NAMES)validate_language_code)CAMPAIGN_TASK_TYPES)Market)Metadata)ObjectID)
TaskAgendac                 C   s   || }| dks||  dkr dS ||  }g }d}t | D ]F}g }t |D ]}	||	 | }
||
 |
}qH|d7 }|t| q8|S )zK
    Creates task maps, uniformly distributed across given annotators.
    r   N   )rangeappendtuple)
annotatorstasks	redudancyZ_total_tasksZ_tasks_per_annotator_resultsZ_current_task_idZ_unused_annotator_idZ_annotator_tasksZannotator_tasktask_id r   =/var/www/rival/public_html/translation-eval/Campaign/utils.py_create_uniform_task_map   s    
r   c                  C   s"   t jjdd} |  std| S )z
    Identify QuerySet of super users for the current Django instance.

    Raises CommandError if no super user can be found.
    T)is_superuserzFailure to identify superuser)r   objectsfilterexistsr   )Z
superusersr   r   r   _identify_super_users2   s    r"   c                 C   s0   t jj| d}| s(td| d |d S )z
    Gets campaign instance for given campaign name.

    Paramters:
    - campaign_name:str specifies name of Campaign instance.
    )campaignNamezCampaign {0!r} does not exist. zNo task agendas have been assigned. This message is expected if you are initializing a new campaign and have not created it in the admin panel. Create a new campaign or check for a misspelling and try again.r   )r	   r   r    r!   r   format)campaign_name	_campaignr   r   r   _get_campaign_instance?   s    r'   c                 C   s:   t jj| |dd|d}|d j| |d   |d S )zs
    Creates CampaignTeam instance, if it does not exist yet.

    Returns reference to CampaignTeam instance.
    d   2   )teamNameownerrequiredAnnotationsrequiredHours	createdByr   )r
   r   get_or_createmembersaddsave)namer+   r   r   Z_cteamr   r   r   _get_or_create_campaign_teamS   s    r4   c                 C   s   t jj| |||d\}}|S )zg
    Creates Market instance, if it does not exist yet.

    Returns reference to Market instance.
    )sourceLanguageCodetargetLanguageCode
domainNamer.   )r   r   r/   )source_codetarget_codedomain_namer+   _market_unused_created_signalr   r   r   _get_or_create_marketf   s    
r=   c                 C   s   t jj| ||||d\}}|S )zc
    Creates Meta instance, if it does not exist yet.

    Returns reference to Meta instance.
    )market
corpusNameversionInfosourcer.   )r   r   r/   )r>   corpus_nameversion_inforA   r+   _metar<   r   r   r   _get_or_create_metav   s    
rE   c           	      C   s   d}t || dttt|ddd d}tt}| dD ]L}d|	 
dd	| 
dd	}|| |d}|| | qF| D ]"}t|| }||d
 ||< q|S )a  
    Gets tasks by market, converting QuerySet to dictionary of lists of tasks.

    Assignment scheme:

    - T1 U1 U2
    - T2 U3 U4
    - T3 U1 U2
    - T4 U3 U4

    To assign this, we duplicate tasks, per market, based on REDUNDANCY

    Parameters:
    - tasks:QuerySet contains task instances to extract market keys for;
    - context:dict specifices CAMPAIGN_NO and REDUNDANCY.

    Raises:
    - CommandError in case of missing required key.

    Returns:
    - tasks_by_market:dict[list[str]] organises tasks by market.
    )CAMPAIGN_NO
REDUNDANCYz{{0}}{{1:0{0}x}}rF      Nidz{0}{1}- rG   )_validate_required_keysr$   maxlenhexgetr   listorder_bymarketSourceLanguageCodereplacemarketTargetLanguageCodelowerr   keys)	r   contextrequired_keys
format_strtasks_by_markettaskZmarket_codekeyZ_single_copyr   r   r   _get_tasks_by_market   s"    
r^   c                 C   sz   d}t || |d| |f}|dkr@d| |f}t|tdd |D |d dkrvd	| |f}t||S )
a  
    Gets tasks-to-annotators map for given language pair.

    Parameters:
    - source_code:str specifies source language ISO 639-2/3 code;
    - target_code:str specifies target language ISO 639-2/3 code;
    - context:dict specifices REDUNDANCY and TASKS_TO_ANNOTATORS.

    Raises:
    - CommandError in case of missing required key.

    Returns:
    - tasks_map:list[int] encodes number of annotators and assigned tasks.
    )rG   TASKS_TO_ANNOTATORSr_   Nz&No TASKS_TO_ANNOTATORS mapping for {0}c                 S   s   g | ]}t |qS r   rN   .0xr   r   r   
<listcomp>   s     z4_get_tasks_map_for_language_pair.<locals>.<listcomp>rG   r   z'Bad TASKS_TO_ANNOTATORS mapping for {0})rL   rP   r$   LookupErrorsum
ValueError)r8   r9   rX   rY   
_tasks_map_msgr   r   r    _get_tasks_map_for_language_pair   s    
 rj   c                 C   sd   t | ddN}zt|}W n* tk
rD } zt|W 5 d}~X Y nX |W  5 Q R  S W 5 Q R X dS )a/  Loads campaign manifest data from JSON file.

    Parameters:
    - json_path:str specifies path to JSON file containing manifest.

    Raises:
    - CommandError in case of errors parsing/loading from JSON file.

    Returns:
    - campaign_data:dict[str]->any campaign data parsed from JSON file.
    zutf-8)encodingN)openr   r   r   )	json_pathZ	json_fileZcampaign_dataexcr   r   r   _load_campaign_manifest   s    ro   c                 C   s   |   } d}d}tD ]:}|  dd}| |rt|t|kr|}t|}q| |d } d}tD ]2}|  dd}| |rdt|t|krd|}qd||fS )zM
    Given some market key, identifies source and target language codes.
    r   rK   rJ   N)rV   r   rT   
startswithrN   )r]   Z
target_posr8   codeZcmp_coder9   r   r   r   _identify_codes_for_key   s"    


rr   c                    s2  d}t || t| |}tt}|D ]  fdd|D }tjj|d}t \}}	zt||	|}
W n: t	t
fk
r } ztt| W Y q$W 5 d}~X Y nX |  }t|}tdd |
D }||krd||}t|t|d	|
D ]:\}}td
||	|| |D ]}|  || |f qqq$|S )a  
    Map tasks to users, by market, and considering TASKS_TO_ANNOTATORS.

    Parameters:
    - tasks:QuerySet contains task instances to map to users;
    - usernames:list specifies user names for campaign;
    - context:dict specifices CAMPAIGN_NO, REDUNDANCY and TASKS_TO_ANNOTATORS.

    Raises:
    - CommandError in case of missing required key or tasks/users issues.

    Returns:
    - tasks_to_users:dict[list[tuple(User,Task)]] maps tasks to users.
    )rF   rG   r_   c                 3   s   | ]}|  r|V  qd S )N)rp   ra   r]   r   r   	<genexpr>#  s     
 z0_map_tasks_to_users_by_market.<locals>.<genexpr>)Zusername__inNc                 S   s   g | ]}t |qS r   r`   ra   r   r   r   rd   5  s     z1_map_tasks_to_users_by_market.<locals>.<listcomp>z1Mismatch of available/required tasks ({0} != {1})rI   zMapping task(s) to user:)rL   r^   r   rQ   r   r   r    rr   rj   re   rg   printstrrN   rf   r$   r   ziprR   r   )r   	usernamesrX   rY   r[   tasks_to_users_mapZ
_usernamesusersr8   r9   rh   _excZ_tasks_for_current_keyZ_available_tasksZ_required_tasksri   userZtasks_for_userr   r   rs   r   _map_tasks_to_users_by_market	  sJ    


   r}   Tc                 C   sb  d}t || t|d}td|d td|d  t|d  }|jj|d}tdt| |r|jdd	}td
t| t	|| |}|D ]}td| || D ]\}	}
t|
d|	j
 tjj|
|d}| stjj|
|d}n|d }tjj|j|	j
d}||d r(q|	|
dk}|rL||d  q||d  qqdS )a  
    Processes TaskAgenda instances for campaign specified by CAMPAIGN_NAME.

    Parameters:
    - usernames:list specifies user names for campaign;
    - context:dict specifices CAMPAIGN_NO, REDUNDANCY, TASKS_TO_ANNOTATORS and
      TASK_TYPE;
    - only_activated:bool only include activated tasks for agenda creation.

    Raises:
    - CommandError in case of missing required key.
    )rF   rG   r_   	TASK_TYPECAMPAIGN_NAMEzIdentified Campaign {0!r}zTask type: {}r~   )campaignzIdentified {} task(s)T)	activatedzIdentified {} activated task(s)z[{0}]z-->)r|   r   r   )typeName	primaryIDN)rL   r'   rP   ru   r$   r   r   r    rN   r}   rI   r   r!   creater   r/   __name__contains_tasknext_item_for_usercomplete_taskactivate_task)rx   rX   Zonly_activatedrY   r&   Z
_task_typer   ry   r]   r\   r|   ZagendaZserialized_tZ_task_done_for_userr   r   r   _process_campaign_agendasJ  s<    
 r   c                 C   s`  d}t || | D ]F\}}zt|||}W n: ttfk
rf } ztt| W Y qW 5 d}~X Y nX tdd |D |d }t|}	t	|d|||	}
d
ttt|dd	d d	ttt|	d	d d	}t|	D ]r}|
| d
d| d
d|d|d }tjj|d}||
j krtd
|
j|j |
j| qqdS )a  
    Adds User objects to CampaignTeam instances for given language pairs.

    Parameters:
    - language_pairs:list[tuple(str, str), ...] list of language pairs;
    - owner:User sets the creator/owner of related campaign objects;
    - context:dict specifies additional context:
      CAMPAIGN_NAME, CAMPAIGN_NO, REDUNDANCY and TASKS_TO_ANNOTATORS.

    Raises:
    - CommandError in case of missing required key.
    )r   rF   rG   r_   Nc                 S   s   g | ]}t |qS r   r`   ra   r   r   r   rd     s     z+_process_campaign_teams.<locals>.<listcomp>rG   r    {{0}}{{1}}{{2:0{0}x}}{{3:0{1}x}}rF   rH   rJ   rK   r   usernamez{0} --> {1})rL   rj   re   rg   ru   rv   rf   rP   rN   r4   r$   rM   rO   r   rV   rT   r   r   r0   allr*   r   r1   )language_pairsr+   rX   rY   _src_tgtrh   r{   Z_tasks_annotatorsZcampaign_team_objectrZ   user_idr   Zuser_objectr   r   r   _process_campaign_teams  sH    
    r   c           	   	   K   sp   t f |}g }| D ]X\}}t|||dd|d}t||dd|dd|dd|d	}|||f q|S )
a(  
    Create Market and Metadata instances for given language pairs.

    Parameters:
    - language_pairs:list[tuple(str, str), ...] list of language pairs;
    - owner:User sets the creator/owner of Market and Metadata objects;
    - **kwargs allows to override defaults for other settings.
    r:   Z	UNDEFINED)r8   r9   r:   r+   rB   rC   z1.0rA   Zofficial)r>   rB   rC   rA   r+   )dictr=   rP   rE   r   )	r   r+   kwargs_contextZmarkets_and_metadatar   r   r;   rD   r   r   r   _process_market_and_metadata  s$    	




r   c              	   C   s*  d}t || t }| D ]
\}}t|||}t|}dttt|ddd dttt|dd d}t|D ]}	||	 
dd|	 
dd|d|	d }
t }||
d	 ||d
d	 | dd }tjj|
d stjj|
|d}|  |||
< q|q|S )a  
    Create User instances for given language pairs.

    Parameters:
    - language_pairs:list[tuple(str, str), ...] list of language pairs;
    - context:dict specifies additional context:
      CAMPAIGN_KEY, CAMPAIGN_NO, REDUNDANCY and TASKS_TO_ANNOTATORS.
    )CAMPAIGN_KEYrF   r   rF   rH   NrJ   rK   r   utf8r      r   )r   password)rL   r   rj   rN   r$   rM   rO   rP   r   rV   rT   r   updateencode	hexdigestr   r   r    r!   create_userr2   )r   rX   rY   Z_credentialsr   r   rh   r   rZ   r   r   hashersecretnew_userr   r   r   _process_users  s4    	
r   c                 C   s$   | D ]}t |std|qdS )z
    Checks that all language codes are valid.

    Parameters:
    - codes:tuple specifies language codes.

    Raises:
    - CommandError in case of invalid language code.
    z%{0!r} contains invalid language code!N)r   r   r$   )codesrq   r   r   r   _validate_language_codes  s    
r   c                 C   s(   |D ]}||   krtd|qdS )a  
    Checks that all required keys exist in given context dict.

    Parameters:
    - context:dict specifies context dictionary;
    - required_keys:tuple[str] specifies set of required keys.

    Raises:
    - CommandError in case of missing required key.
    z+context does not contain required key {0!r}N)rW   rg   r$   )rX   rY   required_keyr   r   r   rL   %  s
    rL   N)T)*__doc__collectionsr   r   hashlibr   jsonr   r   django.contrib.auth.modelsr   django.core.management.baser   Campaign.modelsr	   r
   Dashboard.modelsr   r   EvalData.modelsr   r   r   r   r   r   r"   r'   r4   r=   rE   r^   rj   ro   rr   r}   r   r   r   r   r   rL   r   r   r   r   <module>   sB   /"A
C<.