o
    i3"                     @   s   d Z ddlZddlZddlmZ ddlZddlmZ ddlZddl	Z
ddlmZ ddlmZ ddlmZ eeZejjZejZejZejZejZejZejZ dZ!d	d
 Z"G dd deZ#G dd dZ$dd Z%dS )ae  Provides functionality for supporting coverage collection when using multiprocessing

This module patches the multiprocessing module to install and start coverage collection when new processes are started.

The close, join, kill, and terminate methods are patched to ensure that coverage data is consumed when the
process finishes. Programs that do not call one of these methods will not collect coverage for the processes
started via multiprocessing.

Inspired by the coverage.py multiprocessing support at
https://github.com/nedbat/coveragepy/blob/401a63bf08bdfd780b662f64d2dfe3603f2584dd/coverage/multiproc.py
    N)
ConnectionPath)ModuleCodeCollector)
get_logger)CoverageLines_datadog_patchc                   C   s
   t ttS N)hasattrmultiprocessingDD_PATCH_ATTR r   r   f/home/ubuntu/.local/lib/python3.10/site-packages/ddtrace/internal/coverage/multiprocessing_coverage.py_is_patched'   s   
r   c                   @   sJ   e Zd ZdddZdddZdddZd	d
 Zdd Zdd Zdd Z	dS )CoverageCollectingMultiprocessreturnNc                 C   s   t  r	t jd u rd S | jd u rtjddd d S zG| j rY| j }|rQzt	|}W n tj
y;   td  w |di }|di }t || W d S td W d S td W d S  tyq   tjd	dd Y d S w )
Nz0Pipe was None when absorbing child coverage dataTexc_infoz8Could not unpickle coverage data, not injecting coveragelinescoveredz&Child process sent empty coverage dataz(Child process did not send coverage dataz$Failed to absorb child coverage data)r   coverage_enabled	_instance_parent_connlogdebugpollrecvpickleloadsUnpicklingErrorgetinject_coverage	Exception)selfrcvddatar   r   r   r   r   _absorb_child_coverage,   s.   



z5CoverageCollectingMultiprocess._absorb_child_coveragec                 O   s   | j rddlm} || jd t  t| g|R i |}| j rc| jdurctj}|du r/dS z| j	t
|j|jd W |S  t
jyR   tjddd Y |S  tyb   tjd	dd Y |S w |S )
a  Wraps around the execution of the process to collect coverage data

        Since this method executes in the child process, it is responsible for writing final coverage data back to the
        parent process. Context-based coverage is not used for processes started by this bootstrap because it is
        assumed that the parent process wants all coverage data from this child.
        r   installinclude_pathsN)r   r   z0Failed to pickle coverage data for child processTr   z.Failed to send coverage data to parent process)_dd_coverage_enabled#ddtrace.internal.coverage.installerr(   _dd_coverage_include_pathsr   start_coveragebase_process_bootstrap_child_connr   sendr   dumpsr   r   PicklingErrorr   warningr"   )r#   argskwargsr(   rvalinstancer   r   r   
_bootstrapI   s(   z)CoverageCollectingMultiprocess._bootstrapc                 O   sl   d| _ g | _d | _d | _t r)t \}}|| _|| _d| _ tjd ur)tjj	| _t
| g|R i | d S )NFT)r+   r-   r   r0   r   r   r   Piper   _include_pathsbase_process_init)r#   posargsr6   parent_conn
child_connr   r   r   __init__j   s   

z'CoverageCollectingMultiprocess.__init__c                 O   s"   t | g|R i |}|   |S r	   )base_process_joinr&   )r#   r5   r6   r7   r   r   r   join~   s   z#CoverageCollectingMultiprocess.joinc                 C      t | }|   |S r	   )base_process_closer&   r#   r7   r   r   r   close      z$CoverageCollectingMultiprocess.closec                 C   rC   r	   )base_process_terminater&   rE   r   r   r   	terminate   rG   z(CoverageCollectingMultiprocess.terminatec                 C   rC   r	   )base_process_killr&   rE   r   r   r   kill   rG   z#CoverageCollectingMultiprocess.kill)r   N)
__name__
__module____qualname__r&   r9   r@   rB   rF   rI   rK   r   r   r   r   r   +   s    


!r   c                   @   sd   e Zd ZdZddejee  deddfddZ	de
eejf fd	d
Zde
eef ddfddZdS )Stowawaya  Stowaway is unpickled as part of the child's get_preparation_data() method

    This which happens at the start of the process, which is when the ModuleCodeProcessor needs to be installed in order
    to instrument all the code being loaded in the child process.

    The _bootstrap method is called too late in the spawn or forkserver process start-up sequence and installing the
    ModuleCodeCollector in it leads to incomplete code coverage data.
    NTr*   dd_coverage_enabledr   c                 C   s,   || _ g | _|d urdd |D | _d S d S )Nc                 S      g | ]}t |qS r   )str).0include_pathr   r   r   
<listcomp>       z%Stowaway.__init__.<locals>.<listcomp>)rP   include_paths_strs)r#   r*   rP   r   r   r   r@      s
   zStowaway.__init__c                 C   s   t | j| jdS )N)rW   rP   )jsonr2   rW   rP   )r#   r   r   r   __getstate__   s   
zStowaway.__getstate__statec                 C   sD   dd t |d D }|d r ddlm} ||d t  d S d S )Nc                 S   rQ   r   r   )rS   include_path_strr   r   r   rU      rV   z)Stowaway.__setstate__.<locals>.<listcomp>rW   rP   r   r'   r)   )rX   r   r,   r(   _patch_multiprocessing)r#   rZ   r*   r(   r   r   r   __setstate__   s   

zStowaway.__setstate__)NT)rL   rM   rN   __doc__tOptionallistr   boolr@   dictrR   AnyrY   r]   r   r   r   r   rO      s
    "	rO   c               	      s   t  rd S tjtjj_tjtjj_tjtjj_tjtjj_tj	tjj_	tj
tjj_
tjtjj_zddlm}  | j W n ttfyE   Y nw dtdtttjf f fdd}|| _tttd d S )Nr   )spawnnamer   c                    s0    | }t jdu rg nt jj}t|d|d< |S )zdMake sure that the ModuleCodeCollector is installed as soon as possible, with the same include pathsNr)   stowaway)r   r   r;   rO   )rf   dr*   original_get_preparation_datar   r   "get_preparation_data_with_stowaway   s
   zB_patch_multiprocessing.<locals>.get_preparation_data_with_stowawayT)r   r   r9   r   processBaseProcessr@   rF   rB   rK   rI   r&   re   get_preparation_dataImportErrorAttributeErrorrR   rc   r_   rd   setattrr   )re   rk   r   ri   r   r\      s$   
 	r\   )&r^   rX   r   multiprocessing.connectionr   multiprocessing.processpathlibr   r   typingr_   ddtrace.internal.coverage.coder   ddtrace.internal.loggerr   /ddtrace.internal.test_visibility.coverage_linesr   rL   r   rl   rm   r9   r/   r@   r<   rF   rD   rB   rA   rI   rH   rK   rJ   r   r   r   rO   r\   r   r   r   r   <module>   s0    h 