a
    4ñ»jÌF  ã                   @   s,  d Z ddlmZ ddlmZ ddlZddlZddlZddlZddl	m
Z
 ddlmZ ddlmZ ddlmZ G d	d
„ d
eƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZd(dd„Zd)dd„Zd*dd„Zdd„ Zd+d d!„Zd,d"d#„Z d-d$d%„Z!d&d'„ Z"dS ).z5
Contains utility functions and classes for Runners.
é    )Úabsolute_import©ÚbisectN)Ústring_types)Úparser)ÚFileLocation)Úensure_stream_with_encoderc                   @   s   e Zd ZdS )ÚFileNotFoundErrorN©Ú__name__Ú
__module__Ú__qualname__© r   r   ú8E:\soccer\ml_env\Lib\site-packages\behave/runner_util.pyr	      s   r	   c                   @   s   e Zd ZdS )ÚInvalidFileLocationErrorNr
   r   r   r   r   r      s   r   c                   @   s   e Zd ZdS )ÚInvalidFilenameErrorNr
   r   r   r   r   r      s   r   c                   @   s&   e Zd Ze dej¡Zedd„ ƒZdS )ÚFileLocationParserz&^\s*(?P<filename>.*):(?P<line>\d+)\s*$c                 C   sF   | j  |¡}|r6| d¡ ¡ }t| d¡ƒ}t||ƒS | ¡ }t|ƒS )NÚfilenameÚline)ÚpatternÚmatchÚgroupÚstripÚintr   )ÚclsÚtextr   r   r   r   r   r   Úparse(   s    
zFileLocationParser.parseN)	r   r   r   ÚreÚcompileÚUNICODEr   Úclassmethodr   r   r   r   r   r   %   s   r   c                   @   sH   e Zd ZdZddd„Zdd„ Zdd„ Zed	d
„ ƒZddd„Z	dd„ Z
dS )Ú FeatureScenarioLocationCollectoraÓ  
    Collects FileLocation objects for a feature.
    This is used to select a subset of scenarios in a feature that should run.

    USE CASE:
        behave feature/foo.feature:10
        behave @selected_features.txt
        behave @rerun_failed_scenarios.txt

    With features configuration files, like:

        # -- file:rerun_failed_scenarios.txt
        feature/foo.feature:10
        feature/foo.feature:25
        feature/bar.feature
        # -- EOF

    Nc                 C   sJ   |s|r|j }|| _|| _ d| _tƒ | _tƒ | _tƒ | _|rF|  |¡ d S ©NF)r   ÚfeatureÚuse_all_scenariosÚsetÚscenario_linesÚall_scenariosÚselected_scenariosÚadd_location)Úselfr#   Úlocationr   r   r   r   Ú__init__P   s    z)FeatureScenarioLocationCollector.__init__c                 C   s.   d | _ d | _d| _tƒ | _tƒ | _tƒ | _d S r"   )r#   r   r$   r%   r&   r'   r(   ©r*   r   r   r   Úclear\   s    z&FeatureScenarioLocationCollector.clearc                 C   sN   | j s|j | _ | j |j ks.J d| j |j f ƒ‚|jrD| j |j¡ nd| _d S )Nz	%s <=> %sT)r   r   r&   Úaddr$   )r*   r+   r   r   r   r)   d   s    ÿz-FeatureScenarioLocationCollector.add_locationc                 C   s*   |sdS t || ƒd }|dk r"d}|| S )a5  
        Select scenario line for any given line.

        ALGORITHM: scenario.line <= line < next_scenario.line

        :param line:  A line number in the file (as number).
        :param scenario_lines: Sorted list of scenario lines.
        :return: Scenario.line (first line) for the given line.
        r   é   r   )r   r&   Úposr   r   r   Úselect_scenario_line_fors   s    z9FeatureScenarioLocationCollector.select_scenario_line_forFc           
      C   sÐ   | j s
J ‚| js| j  ¡ | _dd„ | jD ƒ}t| jƒ}|D ]L}|  ||¡}||kr:| j |¡ | j |¡ |r:d|| j|f }t	|ƒ‚q:t
| jƒ}t
ƒ }| jD ]$}	|	j|v rž| |	¡ | |	j¡ qž|rÌJ ‚|S )a½  
        Discovers selected scenarios based on the provided file locations.
        In addition:
          * discover all scenarios
          * auto-correct BAD LINE-NUMBERS

        :param strict:  If true, raises exception if file location is invalid.
        :return: List of selected scenarios of this feature (as set).
        :raises InvalidFileLocationError:
            If file location is no exactly correct and strict is true.
        c                 S   s   g | ]
}|j ‘qS r   )r   )Ú.0Úscenarior   r   r   Ú
<listcomp>–   ó    zPFeatureScenarioLocationCollector.discover_selected_scenarios.<locals>.<listcomp>z-Scenario location '...:%d' should be: '%s:%d')r#   r'   Úwalk_scenariosÚlistr&   r2   Úremover/   r   r   r%   r   )
r*   ÚstrictZexisting_linesZselected_linesr   Únew_lineÚmsgr&   r(   r4   r   r   r   Údiscover_selected_scenarios…   s.    


ÿ




z<FeatureScenarioLocationCollector.discover_selected_scenariosc                 C   sr   | j  p| j}| jr|r| jS | j ¡ | _|  ¡ | _t| jƒ| j }|D ]"}d|jv sHd|jv rbqH| 	¡  qH| jS )al  
        Determines which scenarios in the feature are selected and marks the
        remaining scenarios as skipped. Scenarios with the following tags
        are excluded from skipped-marking:

          * @setup
          * @teardown

        If no file locations are stored, the unmodified feature is returned.

        :return: Feature object to use.
        ÚsetupZteardown)
r&   r$   r#   r7   r'   r=   r(   r%   ÚtagsZmark_skipped)r*   r$   Zunselected_scenariosr4   r   r   r   Úbuild_feature®   s    


z.FeatureScenarioLocationCollector.build_feature)NNN)F)r   r   r   Ú__doc__r,   r.   r)   Ústaticmethodr2   r=   r@   r   r   r   r   r!   =   s   


)r!   c                   @   s*   e Zd ZdZeddd„ƒZedd„ ƒZdS )ÚFeatureListParsera’  
    Read textual file, ala '@features.txt'. This file contains:

      * a feature filename or FileLocation on each line
      * empty lines (skipped)
      * comment lines (skipped)
      * wildcards are expanded to select 0..N filenames or directories

    Relative path names are evaluated relative to the listfile directory.
    A leading '@' (AT) character is removed from the listfile name.
    Nc                 C   s    g }|   ¡ D ]Ž}| ¡ }|s qn| d¡r,q|rJtj |¡sJtj ||¡}tj |¡}t 	|¡r†t 
|¡D ]}t |¡}| |¡ qjqt |¡}| |¡ q|S )zê
        Parse contents of a features list file as text.

        :param text: Contents of a features list(file).
        :param here: Current working directory to use (optional).
        :return: List of FileLocation objects
        ú#)Ú
splitlinesr   Ú
startswithÚosÚpathÚisabsÚjoinÚnormpathÚglobÚ	has_magicÚiglobr   r   Úappend)r   ÚhereÚ	locationsr   r   Ú	filename2r+   r   r   r   r   Ø   s"    	



zFeatureListParser.parsec                 C   sR   |  d¡r|dd… }tj |¡s*t|ƒ‚tj |¡p8d}t|ƒ ¡ }|  ||¡S )z 
        Read textual file, ala '@features.txt'.

        :param filename:  Name of feature list file.
        :return: List of feature file locations.
        ú@r0   NÚ.)	rF   rG   rH   Úisfiler	   ÚdirnameÚopenÚreadr   )r   r   rP   Úcontentsr   r   r   Ú
parse_fileö   s    
zFeatureListParser.parse_file)N)r   r   r   rA   rB   r   r    rZ   r   r   r   r   rC   Ë   s
   rC   c                   @   s2   e Zd ZdZddd„Zdd„ Zdd„ Zd	d
„ ZdS )ÚPathManagerzVContext manager to add paths to sys.path (python search path)
    within a scope.
    Nc                 C   s   |pg | _ d | _d S ©N)Úinitial_pathsÚpaths)r*   r^   r   r   r   r,     s    
zPathManager.__init__c                 C   s   t | jƒ| _| jtj t_d S r\   )r8   r]   r^   ÚsysrH   r-   r   r   r   Ú	__enter__  s    zPathManager.__enter__c                 G   s"   | j D ]}tj |¡ qd | _ d S r\   )r^   r_   rH   r9   )r*   ZcraprH   r   r   r   Ú__exit__  s    
zPathManager.__exit__c                 C   s6   | j d u r| j |¡ ntj d|¡ | j  |¡ d S )Nr   )r^   r]   rO   r_   rH   Úinsert)r*   rH   r   r   r   r/     s    
zPathManager.add)N)r   r   r   rA   r,   r`   ra   r/   r   r   r   r   r[   	  s
   
r[   c                 C   sÐ   t ƒ }g }| D ]¤}t|tƒs:t|tƒs*J ‚ttj |¡ƒ}|j|jkrT| |¡ qn |j	rt| 
¡ }| |¡ | ¡  t|tƒs‚J ‚tj |j¡}tj||d�}|r||_	| |¡ q|j	rÌ| 
¡ }| |¡ |S )aV  
    Parse feature files and return list of Feature model objects.
    Handles:

      * feature file names, ala "alice.feature"
      * feature file locations, ala: "alice.feature:10"

    :param feature_files: List of feature file names to parse.
    :param language:      Default language to use.
    :return: List of feature objects.
    ©Úlanguage)r!   Ú
isinstancer   r   rG   rH   rK   r   r)   r#   r@   rO   r.   Úabspathr   rZ   )Zfeature_filesrd   Zscenario_collectorÚfeaturesr+   Zcurrent_featurer   r#   r   r   r   Úparse_features'  s.    



rh   Tc           	      C   sØ   g }| D ]Ê}t j |¡rlt  |¡D ]F\}}}| ¡  t|ƒD ]*}| d¡r<tt j ||¡ƒ}| 	|¡ q<q"q| 
d¡r�| t |dd… ¡¡ qt |¡}|j d¡s²t|jƒ‚q| ¡ rÆ| 	|¡ q|rt|ƒ‚q|S )a¸  
    Collect feature file names by processing list of paths (from command line).
    A path can be a:

      * filename (ending with ".feature")
      * location, ala "{filename}:{line_number}"
      * features configuration filename, ala "@features.txt"
      * directory, to discover and collect all "*.feature" files below.

    :param paths:  Paths to process.
    :return: Feature file locations to use (as list of FileLocations).
    z.featurerS   r0   N)rG   rH   ÚisdirÚwalkÚsortÚsortedÚendswithr   rJ   rO   rF   ÚextendrC   rZ   r   r   r   r   Úexistsr	   )	r^   r:   rQ   rH   ÚdirpathÚdirnamesÚ	filenamesr   r+   r   r   r   Úcollect_feature_locationsS  s&    



rs   c                 C   s€   |d u ri }|d u r|}| |d< t | dƒ�B}tj | t ¡ ¡}t| ¡ |ddd�}t|||ƒ W d   ƒ n1 sr0    Y  d S )NÚ__file__ÚrbÚexecT)Údont_inherit)rW   rG   rH   ÚrelpathÚgetcwdr   rX   rv   )r   Úglobals_Zlocals_ÚfrR   Úcoder   r   r   Ú	exec_filex  s    r}   c                 C   sª   ddl m} ddlm} |j|jdœ}||ƒ t| ƒ�` |j}| D ]D}tt	 
|¡ƒD ]0}| d¡rT| ¡ }tt	j ||¡|ƒ ||_qTqBW d  ƒ n1 sœ0    Y  dS )zDLoad step modules with step definitions from step_paths directories.r   ©Úmatchers)Úsetup_step_decorators)Úuse_step_matcherÚstep_matcherz.pyN)Úbehaver   Zbehave.step_registryr€   r�   r‚   r[   Úcurrent_matcherrl   rG   Úlistdirrm   Úcopyr}   rH   rJ   )Z
step_pathsr   r€   Zstep_globalsZdefault_matcherrH   ÚnameZstep_module_globalsr   r   r   Úload_step_modules…  s    þ

rˆ   c                 C   s†   t | tƒr4| }tj||d�}|d } | s4J d| ƒ‚d}d}|| jv rV| j |d¡| _d}|d7 }|| j|| j|| j ¡ | jf }|S )	züHelper function to create an undefined-step snippet for a step.

    :param step: Step to use (as Step object or string).
    :param language: i18n language, optionally needed for step text parsing.
    :return: Undefined-step snippet (as string).
    rc   r   zParseError: %sÚuú'z\'z$@%s(%s'%s')
def step_impl(context):
z0    raise NotImplementedError(%s'STEP: %s %s')

)re   r   r   Zparse_stepsr‡   ÚreplaceZ	step_typeÚtitle)Ústeprd   Z	step_textZstepsÚprefixZsingle_quoteZschemaZsnippetr   r   r   Úmake_undefined_step_snippet   s    

ÿr�   c                 C   sJ   |du rt }g }tƒ }| D ]*}||v r(q| |¡ ||ƒ}| |¡ q|S )a@  Creates a list of undefined step snippets.
    Note that duplicated steps are removed internally.

    :param undefined_steps: List of undefined steps (as Step object or string).
    :param make_snippet:    Function that generates snippet (optional)
    :return: List of undefined step snippets (as list of strings)
    N)r�   r%   r/   rO   )Úundefined_stepsZmake_snippetZstep_snippetsZcollected_stepsZundefined_stepZstep_snippetr   r   r   Úmake_undefined_step_snippets¹  s    
r‘   c                 C   sr   | sdS |st j}d}|d7 }|d t| ƒ¡7 }|rTddlm} |d | |d  }t|ƒ}| |¡ | ¡  dS )	a   
    Print snippets for the undefined steps that were discovered.

    :param undefined_steps:  List of undefined steps (as list<string>).
    :param stream:      Output stream to use (default: sys.stderr).
    :param colored:     Indicates if coloring should be used (default: True)
    Nz=
You can implement step definitions for undefined steps with zthese snippets:

Ú
r   )ÚescapesZ	undefinedÚreset)	r_   ÚstderrrJ   r‘   Zbehave.formatter.ansi_escapesr“   r   ÚwriteÚflush)r�   ÚstreamZcoloredr<   r“   r   r   r   Úprint_undefined_step_snippetsÐ  s    
r™   c                  C   sD   ddl m}  ddl m} |  ¡ | _|  d| j¡ i |j_|j|_dS )zVReset runtime environment.
    Best effort to reset module data to initial state.
    r   )Ústep_registryr~   N)	rƒ   rš   r   ZStepRegistryÚregistryr€   ZParseMatcherZcustom_typesr„   )rš   r   r   r   r   Úreset_runtimeê  s    
rœ   )N)T)NN)N)N)NT)#rA   Ú
__future__r   r   rL   Úos.pathrG   r   r_   Úsixr   rƒ   r   Zbehave.model_corer   Zbehave.textutilr   ÚLookupErrorr	   r   Ú
ValueErrorr   Úobjectr   r!   rC   r[   rh   rs   r}   rˆ   r�   r‘   r™   rœ   r   r   r   r   Ú<module>   s4    >
,
%



