
    c                        d Z ddlZddlZddlZddlmZ ddlmZ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mZ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m Z m!Z!m"Z"m#Z#m$Z$m%Z% ddl&m'Z' ddl(m)Z) ddl*m+Z+ ddl*m,Z,m-Z- ddl.m/Z/m0Z0 ddl.m1Z1m2Z2m3Z3 ddl4m5Z5m6Z6 ddl7Z7ddl/Z8ddl9m:Z: dZ;dZ<dZ=dZ> e?e8dd      s	 ddl@mAZB nddlmAZB 	 ddlDZDddlEmFZFmGZG dZHdZI ej                  d      ZJdeKd e!e	   fd!ZL ej                  d"      ZMd#eKd e!e	   fd$ZNd% ZOdId&ZP G d' d(eQ      ZRd) ZS G d* d+eQ      ZT G d, d-eT      ZUd. ZVd/ ZW e'd0      d1        ZX G d2 d3e/j                        ZZ G d4 d5e/j                        Z\ G d6 d7e/j                        Z^e,j                  j                  Za e:e,j                  d8      	 	 	 dJd9e d:e^d;e!e   d<e!e    d df
d=       Zb e:e,j                        d>        Zc G d? d@e/j                        Ze	 	 	 dKd9e d:e^dAefd;ed<e!e    d e^fdBZg	 	 	 dKd9e d:e^dAefd;ed<e!e    d e^fdCZhej                  dDk\  r	 	 	 dKd9e d:e^dAefd;ed<e!e    d e^fdEZgdF Zje^e/_]        e\e/_[        eee/_d        eZe/_Y        ej                  dGk\  re,j                  fe7j                  _l        ne,j                  fe/j                  _l        ege/j:                  _X        ehe/j:                  _n        eodHk(  r eX        yy# e
$ r5  eej                  j                  dd      j                  d            Z	Y w xY w# e
$ r  ej                  d       Y |w xY w# e
$ r dZHY {w xY w)Lac
  logilab-pytest is a tool that eases test running and debugging.

To be able to use logilab-pytest, you should either write tests using
the logilab.common.testlib's framework or the unittest module of the
Python's standard library.

You can customize logilab-pytest's behaviour by defining a ``pytestconf.py``
file somewhere in your test directory. In this file, you can add options or
change the way tests are run.

To add command line options, you must define a ``update_parser`` function in
your ``pytestconf.py`` file. The function must accept a single parameter
that will be the OptionParser's instance to customize.

If you wish to customize the tester, you'll have to define a class named
``CustomPyTester``. This class should extend the default `PyTester` class
defined in the logilab.common.pytest module. Take a look at the `PyTester` and
`DjangoTester` classes for more information about what can be done.

For instance, if you wish to add a custom -l option to specify a loglevel, you
could define the following ``pytestconf.py`` file ::

    import logging
    from logilab.common.pytest import PyTester

    def update_parser(parser):
        parser.add_option('-l', '--loglevel', dest='loglevel', action='store',
                          choices=('debug', 'info', 'warning', 'error', 'critical'),
                          default='critical', help="the default log level possible choices are "
                          "('debug', 'info', 'warning', 'error', 'critical')")
        return parser


    class CustomPyTester(PyTester):
        def __init__(self, cvg, options):
            super(CustomPyTester, self).__init__(cvg, options)
            loglevel = options.loglevel.upper()
            logger = logging.getLogger('erudi')
            logger.setLevel(logging.getLevelName(loglevel))


In your TestCase class you can then get the value of a specific option with
the ``optval`` method::

    class MyTestCase(TestCase):
        def test_foo(self):
            loglevel = self.optval('loglevel')
            # ...


You can also tag your tag your test for fine filtering

With those tag::

    from logilab.common.testlib import tag, TestCase

    class Exemple(TestCase):

        @tag('rouge', 'carre')
        def toto(self):
            pass

        @tag('carre', 'vert')
        def tata(self):
            pass

        @tag('rouge')
        def titi(test):
            pass

you can filter the function with a simple python expression

 * ``toto`` and ``titi`` match ``rouge``
 * ``toto``, ``tata`` and ``titi``, match ``rouge or carre``
 * ``tata`` and ``titi`` match``rouge ^ carre``
 * ``titi`` match ``rouge and not carre``
    N)process_timetime)Match )isgeneratorfunctionisclass	FrameInfo)shuffle)	dropwhile)_WritelnDecorator)	TestSuite)CallableAnyOptionalListTuple	GeneratorDict)callable_deprecated)abspath_listdir)	textutils)testlibSTD_BLACKLIST)unitteststart_interactive_mode)
nocoveragepause_tracereplace_trace)Debuggercolorize_source   )monkeypatchzrestructuredtext ena  %prog [OPTIONS] [testfile [testpattern]]

examples:

logilab-pytest path/to/mytests.py
logilab-pytest path/to/mytests.py TheseTests
logilab-pytest path/to/mytests.py TheseTests.test_thisone
logilab-pytest path/to/mytests.py -m '(not long and database) or regr'

logilab-pytest one (will run both test_thisone and test_thatone)
logilab-pytest path/to/mytests.py -s not (will skip test_notthisone)
Fz.pytest.restart__package__z7You have to install python-unittest2 to use this module)modpath_from_fileload_module_from_modpathTzpytestconf.pyz^((unit)?test.*|smoketest)\.py$filenamereturnc                 R    t         j                  t        j                  |             S )z2returns True if `filename` seems to be a test file)TESTFILE_REmatchospbasename)r&   s    7/usr/lib/python3/dist-packages/logilab/common/pytest.pythis_is_a_testfiler.      s    S\\(344    z^(unit)?tests?$dirpathc                 R    t         j                  t        j                  |             S )z7returns True if `filename` seems to be a test directory)
TESTDIR_REr*   r+   r,   )r0   s    r-   this_is_a_testdirr3      s    CLL122r/   c                     i }t        t        | d      j                         |       d|v r |d   |       |j                  dt              S )zRloads a ``pytestconf.py`` file and update default parser
    and / or tester.
    rbupdate_parserCustomPyTester)execopenreadgetPyTester)pathparser	namespaces      r-   load_pytest_confr@      sL     IdD				 ),)#"	/"6*==)844r/   c                    |t        j                         }t        j                  |      x}}t        }t        j
                  |t              }t        j                  |      rt        ||       }t        |      s)t        j                  t        j
                  |d            rt        j                  t        j
                  |t         j                              }||k(  r	 ||fS |}|}t        j
                  |t              }t        j                  |      rt        ||       }t        |      rt        j                  t        j
                  |d            r||fS )z1try to find project's root and add it to sys.path__init__.py)osgetcwdr+   abspathr<   join	CONF_FILEisfiler@   r3   normpathpardir)r>   projdirpreviousdircurdir	testerclsconf_file_pathnewdirs          r-   project_rootrQ      s   ))+;;w//K&IXXfi0N
zz.!$^V<	
F
#szz#((6=2Q'Rchhvryy9:V 	!! &)4::n%(@I F
#szz#((6=2Q'R 	!!r/   c                   .    e Zd ZdZd Zd Zd Zd Zd Zy)GlobalTestReportz'this class holds global test statisticsc                 t    d| _         d| _        d| _        d| _        d| _        d| _        d| _        g | _        y )Nr   )ranskippedfailureserrorsttimectimemodulescount
errmodulesselfs    r-   __init__zGlobalTestReport.__init__   s;    

r/   c           	      p   |j                   }| xj                  |z  c_        | xj                  t        t	        |dd            z  c_        | xj
                  t        |j
                        z  c_        | xj                  t        |j                        z  c_        | xj                  |z  c_        | xj                  |z  c_        | xj                  dz  c_	        |j                         sMt        |j
                        t        |j                        z   }| j                  j                  |dd ||f       yy)z8integrates new test information into internal statisticsrV    r!   N)testsRunrU   rV   lengetattrrW   rX   rY   rZ   r[   wasSuccessfulr\   append)r^   r&   
testresultrY   rZ   rU   problemss          r-   feedzGlobalTestReport.feed   s    !!CGJ	2>??Z0011s:,,--

e


e
Q''):../#j6G6G2HHHOO""HSbM8S#AB *r/   c                     | xj                   dz  c_         | xj                  dz  c_        | xj                  dz  c_        | j                  j	                  |dd ddf       y)z=called when the test module could not be imported by unittestr!   Nrb   )rX   r[   rU   r\   rg   r^   r&   s     r-   failed_to_test_modulez&GlobalTestReport.failed_to_test_module  sM    qQA"q!45r/   c                     | xj                   dz  c_         | xj                  dz  c_        | j                  j                  |d d ddf       y )Nr!   rb   r   )r[   rU   r\   rg   rl   s     r-   skip_modulezGlobalTestReport.skip_module
  s?    QA"q!45r/   c                    d| j                   | j                  | j                  fz  g}| j                  r|j	                  d| j                  z         | j
                  r|j	                  d| j
                  z         | j                  r|j	                  d| j                  z         | j                  t        | j                        z
  }| j                  s| j
                  rM|dt        | j                        d}dj                  | j                  D cg c]  }d|z  	 c}      }d	|z  }n|rd
|z  }d}nydj                  |      d||S c c}w )zthis is just presentation stuffz&Ran %s test cases in %.2fs (%.2fs CPU)z	%s errorsz%s failuresz
%s skippedz modules OK (z failed), z
%s [%s/%s]z
failures: %szAll %s modules OKr   
)rU   rY   rZ   rX   rg   rW   rV   r[   rd   r\   rF   )r^   line1	modulesokline2infodescrline3s          r-   __str__zGlobalTestReport.__str__  s   9TXXtzzSWS]S]<^^_;;LLt{{23==LL67<<LL45%%DOO(<<	;;$--3<c$//>RSEIItOt|d2OPE$u,E')3EE!YYu-ue<< Ps   EN)	__name__
__module____qualname____doc__r_   rj   rm   ro   ry   ra   r/   r-   rS   rS      s    1C66
=r/   rS   c                 
   t        t        j                  j                               D ]Y  \  }}|	t	        |d      s|j
                  }t        j                  |      r|j                  |       sIt        j                  |= [ y)ab  remove all modules from cache that come from `testdir`

    This is used to avoid strange side-effects when using the
    testall() mode of pytest.
    For instance, if we run pytest on this tree::

      A/test/test_utils.py
      B/test/test_utils.py

    we **have** to clean sys.modules to make sure the correct test_utils
    module is ran in B
    N__file__)	listsysmodulesitemshasattrr   r+   isabs
startswith)testdirmodnamemodmodfiles       r-   remove_local_modules_from_sysr   %  sn     S[[..01 
%;sJ',, yy!W%7%7%@G$
%r/   c                   R    e Zd ZdZd Zd Zd Zd Z eee      Z	d
dZ
d
dZd
dZy	)r<   zencapsulates testrun logicc                 Z    t               | _        || _        || _        d| _        d | _        y )NT)rS   reportcvgoptions
firstwrite_errcode)r^   r   r   s      r-   r_   zPyTester.__init__B  s(    &(r/   c                 D    t        d       t        | j                         y)z2prints the report and returns appropriate exitcodezO*******************************************************************************N)printr   r]   s    r-   show_reportzPyTester.show_reportI  s     	hdkkr/   c                     | j                   | j                   S | j                  j                  | j                  j                  z   S N)r   r   rW   rX   r]   s    r-   get_errcodezPyTester.get_errcodeO  s5    ==$== {{##dkk&8&888r/   c                     || _         y r   )r   )r^   errcodes     r-   set_errcodezPyTester.set_errcodeU  s	    r/   c                    t        j                         }t        j                  |      D ]m  \  }}}t        D ]  }||v s|j	                  |        t        j                  |      }t        |      sIt        d|       | j                  ||      s ng |dd o | j                  j                  dk(  rt        d|       | j                  |       yy)walks through current working directory, finds something
        which can be considered as a testdir and runs every test there
        
going intoNr   zno test dir found testing here:)rC   rD   walkr   remover+   r,   r3   r   
testonedirr   rU   )r^   	exitfirstheredirnamedirs_rV   r,   s           r-   testallzPyTester.testallZ  s     yy{ " 
	GT1( )d?KK() ||G,H *lG,w	:Q
	 ;;??a3T: OOD!  r/   c           	      "   t        |      }t        |       |D ]  }t        |      s| j                  j                  r7| j                  j
                  s!	 t        t        d      }|j                          | j#                  |d      }|r||j$                  j'                         s yd| _         t+        |       y# t        $ rH t        dt        j                  t        j                         t              t        j                           w xY w)finds each testfile in the `testdir` and runs it

        return true when all tests has been executed, false if exitfirst and
        some test has failed.
        w-Error while overwriting succeeded test file :fileT	batchmodeF)r   r
   r.   r   r   restartr9   FILE_RESTARTclose	Exceptionr   r+   rF   rC   rD   r   
__stderr__testfileresultrf   r   r   )r^   r   r   filesr&   restartfileprogs          r-   r   zPyTester.testonedirq  s      ( 	'H!(+<<))$,,2F2F	&*<&=#))+ }}X}>$,dkk6O6O6Q "&%	'( 	&g. % KHHRYY[,?!$
 s    B==ADc                    t        j                         }t        j                  |      }|rt        j                  |       | j
                  j                  rC| j
                  j                  s-| j                  r!	 t        t        d      }|j                          t        j"                  |      dd }t        dt        j"                  |      z  j%                  dd      t        j                          	 t'               t)               }}	 t+        ||| j,                  | j
                  t        j.                  	      }	t'               t)               }}||z
  ||z
  }}| j<                  jG                  ||	jH                  ||       |	|rt        j                  |       S S # t        $ rH t        dt        j                  t        j                         t              t        j                           w xY w# t0        $ r  t2        $ r}
|
j4                  | _         d}
~
wt8        j:                  $ rB t        d
|       | j<                  j?                  |       Y |rt        j                  |       yyt        $ rw | j<                  jA                  |       t        d|t        j.                         ddl!} |jD                  t        j.                         Y |rt        j                  |       yyw xY w# |rt        j                  |       w w xY w)mruns every test in `filename`

        :param filename: an absolute path pointing to a unittest file
        r   r   r   Nrb     %s  F   =)r   r   r   	outstreamzModule skipped:*unhandled exception occurred while testingr   )%rC   rD   r+   r   chdirr   r   r   r   r9   r   r   r   r   rF   r   r   r,   centerr   r   SkipAwareTestProgramr   stderrKeyboardInterrupt
SystemExitcoder   r   SkipTestr   ro   rm   	traceback	print_excrj   r   )r^   r&   r   r   r   r   r   tstartcstarttestprogexcr   tendcendrY   rZ   s                   r-   r   zPyTester.testfile  sU   
 yy{++h'HHW<<!!$,,*>*>4??	"<5!!# ,,x("-x#,,x0088SAW!	!V\^FF/' LL!jj0 $D 6MTF]5EKKXxuE S  CHHRYY[,7
 & %  "xx## '2''1    11(;BGRUR\R\] #	##4    sW   : F 4K, 	2G/ ;AK, AG,/K)H=K)K, *A$K)K, (K))K, ,LNF)rz   r{   r|   r}   r_   r   r   r   propertyr   r   r   r   ra   r/   r-   r<   r<   ?  s6    $9  {K0G".>8r/   r<   c                   6    e Zd Zd Zd Zd ZddZddZddZy)	DjangoTesterc                    t        j                  |      }t        j                  t        j                  |d            st        j                  t        j                  |d            rt        j                  t        j                  |t
        j                              }||k(  rt        d      |}t        j                  t        j                  |d            s*t        j                  t        j                  |d            rt        t        t        j                  |d                  }ddl
m}  ||       d|_        || _        |t        j                  vr!t        j                  j!                  d|       yy)	z)try to find project's setting and load itzsettings.pyrB   zcould not find settings.pyr   )setup_environFr!   N)r+   rE   rH   rF   rI   rC   rJ   AssertionErrorr%   r$   django.core.managementr   DEBUGsettingsr   r=   insert)r^   r   rM   rP   r   r   s         r-   load_django_settingsz!DjangoTester.load_django_settings  s   W%**SXXfm<=#**HHV]+C
 \\#((6299"=>F$%ABBF **SXXfm<=#**HHV]+C
 ,,=chhv}>],^_8h !HHOOAv& "r/   c                 r    ddl m} ddl m}  |         |d       | j                  j                  | _        y )Nr   )setup_test_environment)create_test_db	verbosity)django.test.utilsr   r   r   TEST_DATABASE_NAMEdbname)r^   r   r   s      r-   before_testfilezDjangoTester.before_testfile  s'    <4 #mm66r/   c                 ~    ddl m} ddl m}  |        t        d| j                          || j                  d       y )Nr   )teardown_test_environment)destroy_test_db
destroyingr   )r   r   r   r   r   )r^   r   r   s      r-   after_testfilezDjangoTester.after_testfile  s*    ?5!#lDKK(q1r/   c                 X   t        j                  t        j                               D ]  \  }}}dD ]  }||v s|j                  |        d|v r| j	                  ||      s yg |dd Bt        j                  |      }|dv s\t        d|       | j	                  ||      s yg |dd  y)r   )CVSz.svnz.hgtests.pyN)testtestsr   )rC   r   rD   r   r   r+   r,   r   )r^   r   r   r   r   rV   r,   s          r-   r   zDjangoTester.testall  s     %'GGBIIK$8 	! GT51 )d?KK() U"w	:Q<<000,0??7I> DG	!r/   c                 h   t        |      D cg c]  }t        |      s| }}t        |      dkD  r&	 |j                  t	        j
                  |d             |D ]6  }| j                  |d      }|s||j                  j                         r6 y t        |       yc c}w # t        $ r Y Ww xY w)r   r!   r   Tr   F)r   r.   rd   r   r+   rF   
ValueErrorr   r   rf   r   )r^   r   r   fpath	testfilesr&   r   s          r-   r   zDjangoTester.testonedir  s     )8(@^uDVW\D]U^	^y>A  ':!>? " 	H==T=:Ddl$++2K2K2M		 	&g. _  s   B B %B% %	B10B1c                 .   t        j                         }t        j                  |      }|rt        j                  |       | j                  |       t        j                  |      dd }t        dt        j                  |      z  j                  dd      t        j                         	 	 t               t               }}| j                          t        ||| j                        }t               t               }
}	|	|z
  |
|z
  }}| j                   j#                  ||j$                  ||       || j'                          |rt        j                  |       S S # t(        $ r  t*        $ r|}ddl} |j.                          | j                   j1                  |       t        d	|       t        d
|z         Y d}~| j'                          |rt        j                  |       yyd}~ww xY w# | j'                          |rt        j                  |       w w xY w)r   Nrb   r   r   r   r   )r   r   r   r   z	error: %s)rC   rD   r+   r   r   r   r,   r   r   r   r   r   r   r   r   r   r   rj   r   r   r   r   r   r   rm   )r^   r&   r   r   r   r   r   r   r   r   r   rY   rZ   r   r   s                  r-   r   zDjangoTester.testfile  s   
 yy{++h'HHW!!'*,,x("-x#,,x0088SA

S	!%$$&/9RVRZRZ[!V\^d $vu  8??E5I !     #	##%11(;BGLkC'(!  ! s,   -BE G'+A
G"5G* "G''G* **HNr   )	rz   r{   r|   r   r   r   r   r   r   ra   r/   r-   r   r     s     '*72!*."r/   r   c            	      x   ddl m}   | t              }g |_        d d }fd}|j	                  ddd	d
       |j	                  ddddd       |j	                  dddd       |j	                  dd|ddd       |j	                  dd|dddd        |j	                  d!d"|d#ddd$        |j	                  d%dd&       |j	                  d'd(d)d*d	d+,       |j	                  d-d.dd/       |j	                  d0d1d	d2d34       |j	                  d5d6d	d7d84       t
        r|j	                  d9d:d;ddd<       |S )=z!creates the OptionParser instancer   )OptionParser)usagec                 :    |j                   j                  |       y)z!carry the option to unittest_mainN)newargsrg   optionoptvaluer>   s       r-   rebuild_cmdlinez$make_parser.<locals>.rebuild_cmdlineL  s    c"r/   c                 |    |j                   j                  |       t        |j                  | j                  d       y)zXcarry the option to unittest_main and store
        the value on current parser
        TN)r   rg   setattrvaluesdestr   s       r-   rebuild_and_storez&make_parser.<locals>.rebuild_and_storeP  s*     	c"v{{D1r/   c                 P    t        j                  dt                | |||       y )Nignore)warningssimplefilterDeprecationWarning)r   r   r   r>   r   s       r-   capture_and_rebuildz(make_parser.<locals>.capture_and_rebuildW  s"    h(:;UF3r/   z-tr   Nz'directory where the tests will be found)r  defaulthelpz-ddbcF
store_truezenable design-by-contract)r  r
  actionr  -v	--verbosecallbackzVerbose output)r  r  r  -i--pdbpdbzEnable test failure inspection)r  r  r  r  -x--exitfirstr   zMExit on first failure (only make sense when logilab-pytest run one test file))r  r  r
  r  r  z-R	--restartr   ztRestart tests from where it failed (implies exitfirst) (only make sense if tests previously ran with exitfirst only)--colorzcolorize tracebacks-s--skipstorerV   zRtest names matching this name will be skipped to skip several patterns, use commas)r  r  r
  r  -q--quietzMinimal output-P	--profileprofilez2Profile execution and store data in the given file)r
  r  r  -m--matchtags_patternz5only execute test whose tag match the current patternz-Jz--djangodjangoz(use logilab-pytest for django test cases)optparser   
PYTEST_DOCr   
add_optionDJANGO_FOUND)r   r>   r  r	  r   s       @r-   make_parserr)  D  s   %
+FFN#24
 9d1Z   5%C^   kOJM]   "-   "_   "H  	 OJEZ    /   i/*K[   A   D   ; 	 	
 Mr/   c                    | j                         \  }}|D cg c]  }|j                  d      s| }}|r6t        |      dkD  r| j                  d       |d   }|j	                  |       nd}|j
                  t        _        | j                  }|j                  r|j                  d|j                  g       |j                  rd|_        ||z  }||fS c c}w )z}Parse the command line and return (options processed), (options to pass to
    unittest_main()), (explicitfile or None).
    z.pyr!   zonly one filename is acceptabler   Nr  T)
parse_argsendswithrd   errorr   r  r   
ENABLE_DBCr   rV   extendr   r   )r>   r   argsarg	filenamesexplicitfiler   s          r-   	parseargsr4    s    
 %%'MGT $<U(;<I<y>ALL:; |L! GnnG'//23  tOGL  ' =s
   CCzJ[logilab-common 1.3] logilab-pytest is deprecated, use another test runnerc                     t               } t        |       \  }}t        |       \  }}| j                  t        j
                  dd  d }dt        j                  vr t        j                  j                  dd       t        r|j                  rt        ||      }n	 |||      }|r|j                  |f}}nJ|j                  r%|j                  |j                  |j                  f}}n|j                  |j                  f}}	 	 |j                   rYdd l}	|	j%                  |j                         }
 |
j&                  |g|  |
j)                          t+        d|j                          n ||  |j5                          t	        j6                  |j8                         y # t,        $ r  t.        $ r dd l} |j2                          Y Yw xY w# |j5                          t	        j6                  |j8                         w xY w)Nr!   r   r   zprofile data saved in)r)  rQ   r4  r   r   argvr=   r   r(  r$  r   r   r   r   r   r   r   hotshotProfileruncallr   r   r   r   r   r   r   exitr   )r>   rootdirrN   r   r3  r   testercmdr0  r7  profr   s               r-   runr?    s   ]F%f-GY%f-G\>>CHHQRL
C	2c7+3(OOl_T	%%9J9J'KTNNW%6%6$8T!	"w7S(4(

-w?T
 	   	 	"I!	"
 	 s%   >A*F 'G?G GG 1G6c                   V     e Zd ZdZdddddej
                  f fd	Zd Zd Zd Z	 xZ
S )	r   az  Usage: %(progName)s [options] [test] [...]

Options:
  -h, --help       Show this message
  -v, --verbose    Verbose output
  -i, --pdb        Enable test failure inspection
  -x, --exitfirst  Exit on first failure
  -s, --skip       skip test matching this pattern (no regexp for now)
  -q, --quiet      Minimal output
  --color          colorize tracebacks

  -m, --match      Run only test whose tag match this pattern

  -P, --profile    FILE: Run the tests using cProfile and saving results
                   in FILE

Examples:
  %(progName)s                               - run default set of tests
  %(progName)s MyTestSuite                   - run suite 'MyTestSuite'
  %(progName)s MyTestCase.testSomething      - run MyTestCase.testSomething
  %(progName)s MyTestCase                    - run all 'test*' test methods
                                               in MyTestCase
__main__NFc                 z    || _         || _        || _        || _        t        t
        |   ||t                      y )N)moduledefaultTest
testLoader)r   r   r   r   superr   r_   NonStrictTestLoader)r^   rC  rD  r   r   r   r   	__class__s          r-   r_   zSkipAwareTestProgram.__init__  sA     #""D2{?R?T 	3 	
r/   c                    d| _         d| _        g | _        d | _        d | _        d| _        d | _        dd l}	 |j                  |dd  dg d      \  }}|D ]  \  }}|dv r| j                          |dv rd| _         |d	v rd| _        |d
v rd| _	        d| _        |dv rd| _
        |dv rd| _
        |dv r2|j                  d      D cg c]  }|j                          c}| _        |dk(  rd| _        |dv r|| j                  d<   |dv s|| _         | j                  | j                  _        t        |      dk(  r| j                   t#        | j$                  dd       }t'        |t(        j*                  t(        j,                  f      r | j$                  j/                         | _        y | j                  j3                  | j$                        | _        y t        |      dkD  r|d   | _        || _        n| j                   f| _        | j7                          y c c}w # |j8                  $ r}	| j                  |	       Y d }	~	y d }	~	ww xY w)NFr   r!   zhHvixrqcp:s:m:P:)
r  verbosequietr  r   r   zskip=colorzmatch=zprofile=)z-hz-Hz--help)r  r  T)r  r  )z-rr  )r  r  )r  r     )r  r  rq   r  )r!  r"  tag_pattern)r  r  suite)pdbmoder   skipped_patternstest_patternr#  colorizeprofile_namegetopt	usageExitr   r   splitstripr   rE  rd   rD  re   rC  
isinstancetypesFunctionType
MethodTyperO  r   loadTestsFromModule	testNamescreateTestsr-  )
r^   r6  rU  r   r0  r   r   pat	suitefuncmsgs
             r-   	parseArgszSkipAwareTestProgram.parseArgs   s7    "   7	 "MMQR"MGT  & .
U00NN$/)#'DL//%)DN--#'DL%)DN++%&DN--%&DN**DIKKPTDU,VSSYY[,VD))#$(DM++27DLL/--(-D%-.. 04/D/DDOO,4yA~$"2"2":#DKK$?	i%*<*<e>N>N)OP $ 1 1 3DI  !% C CDKK PDI4y1}$(G!!%"&"2"2!4+ -W, || 	 NN3	 s>   BH H+H BH %*H AH H I'H==Ic                     | j                   r3dd l}|j                  dt               t	               | j                          y | j                         S )Nr   zself._runTests())rT  cProfilerunctxglobalslocals	_runTests)r^   re  s     r-   runTestszSkipAwareTestProgram.runTestsc  s8    OO.	68TEVEVW>>##r/   c                    t        | j                  | j                  | j                  | j                  | j
                  | j                  | j                  | j                  | j                  | j                  
      | _        fdt        | j                  dd      rV	 t        t        d      }	 t        d |j!                         D              } | j"                  |       |j%                          	 | j                  j1                  | j"                        }| `t        |d	d       rt        | d
d       rt3        |       t        | dd       s$t5        j6                  |j9                                 || _        y # |j%                          w xY w# t&        $ r@}t'        dt)        j*                  t-        j.                         t              d|      d }~ww xY w)N)
r   streamr   rP  r   rR  rQ  rS  r   r   c                    t        | t        j                        r | j                  |       t        | t              r| dd D ]  }t        |t        j                        r
 ||       't        |t        j
                        sBdj                  |j                  j                  |j                  j                  |j                  f      }||v s| j                  |        yy)z_Recursive function that removes succTests from
            a TestSuite or TestCase
            N.)rY  r   r   _testsr   TestCaserF   rH  r{   rz   _testMethodNamer   )obj	succTestselrw   removeSucceededTestss       r-   ru  z<SkipAwareTestProgram._runTests.<locals>.removeSucceededTestsy  s     #x112$SZZ;#t$a& +B!"h&8&89,R;#B(9(9: #\\44bll6K6KRM_M_`! !I-JJrN+ %r/   r   Frc              3   >   K   | ]  }|j                  d         yw)z
N)rstrip).0elems     r-   	<genexpr>z1SkipAwareTestProgram._runTests.<locals>.<genexpr>  s     )b$$++f*=)bs   z)Error while reading succeeded tests into : 	debuggersrP  r   )SkipAwareTextTestRunnerr   r   r   rP  r   rR  rQ  rS  r   r   
testRunnerre   r9   r   r   	readlinesr   r   r   r+   rF   rC   rD   r?  r   r   r:  rf   r   )r^   r   succeededtestsexr   ru  s        @r-   ri  zSkipAwareTestProgram._runTestsk  sl   1nn>>nnLL**!22]]nnLL
	+$ 4<<E2"<5(%))b+J_J_Ja)b%bN(NC%%' $$TYY/ I6;-'$	42P"6*t[$/HH--//0  %%' xx		\:B@ s0   F .3E7 !F 7F		F 	G;GG)rz   r{   r|   USAGEr   r   r_   rc  rj  ri  __classcell__rH  s   @r-   r   r     s8    E6 **
"A F$7r/   r   c            
            e Zd Zej                  dddddddddf
 fd	ZdedefdZdd	e	d
edefdZ
d	e	defdZddZd Z xZS )r~  r!   FNra   c                     t         t        |   ||       || _        || _        || _        || _        || _        || _        |	| _	        |
| _
        y )N)rl  r   )rF  r~  r_   r   rP  r   rR  rQ  rS  r   r   )r^   rl  r   r   rP  r   rR  rQ  rS  r   r   rH  s              r-   r_   z SkipAwareTextTestRunner.__init__  sT     	%t5Vy5Y"( 0 "r/   
testednamer'   c                 V    t        | j                  D cg c]  }||v  c}      S c c}w r   anyrQ  r^   r  r`  s      r-   _this_is_skippedz(SkipAwareTextTestRunner._this_is_skipped  s&    43H3HICSJ&IJJI   &r   skipgeneratorc                    t        |t        j                        r|j                  }nt        |t        j                        r,|j                         }|j                  d|j                  }nvt        |t        j                        r|}|j                  }nMt        |t        j                        r2|j                  j                  }|j                  d|j                  }nyt        |      r|r| j                  |      S | j                  |      ry| j                  =	 | j                  j!                  d      \  }}|j!                  d      \  }	}
||	vs||
vry	 | j                  |      S # t"        $ r | j                  |vrY yY ,w xY w)Nrn  TF)rY  r   	InnerTestnamerp  _get_test_methodrz   rZ  r[  r\  __self__rH  r   does_match_tagsr  rR  rW  r   )r^   r   r  testnamemethfuncclsclasspatterntestpatternklassr  s              r-   _runconditionz%SkipAwareTextTestRunner._runcondition  sY   dG--.yyH$ 0 01,,.&*mmT]]CD%"4"45==D%"2"23mm--&)llDMMB"4(]++D11  *(!,0,=,=,C,CC,H)k&nnS1tu,40G  1H ##D))	  !$$H4  5!s   !:E. .F
	F
c                 f   | j                   t        | j                   dd       }|t        |dt        j                               }|j                  rPt        |t        j                        r6|t        |j                  j                  dt        j                               z  }|j                  |      S y)Nr#  tagsT)r   re   r   TagsinheritrY  rZ  r\  r  rH  r*   )r^   r   r#  r  s       r-   r  z'SkipAwareTextTestRunner.does_match_tags  s    <<#"4<<FL'tVW\\^<<<JtU5E5E$F'$--*A*A67<<>"ZZDzz,//r/   c           	          t        | j                  | j                  | j                  | j                  | j
                  | j                  | j                        S r   )SkipAwareTestResultrl  descriptionsr   r   rP  r   rS  r]   s    r-   _makeResultz#SkipAwareTextTestRunner._makeResult  sB    "KKNNNNLLHHMM
 	
r/   c                 N   | j                         }t               } ||| j                  | j                         t               }||z
  }|j	                          | j
                  s?| j                  j                  |j                         |j                  }| j                  j                  d||dk7  xr dxs d|fz         | j                  j                          |j                         sY| j                  r1| j                  j                  t        j                  dd             nt| j                  j                  d       nX| j                  r1| j                  j                  t        j                  d	d
             n| j                  j                  d	       t        t         |j"                  |j$                  |j&                  f      \  }}}	g }
d|j"                  fd|j$                  fd|j&                  ffD ]'  \  }}|s	|
j)                  d|t!        |      fz         ) |
r`| j                  j                  d       | j                  j                  dj+                  |
             | j                  j                  d       | j                  j                  d       |S )z&Run the given test case or test suite.runconditionr   zRan %d test%s in %.3fsr!   sr   FAILEDred)rL  OKgreenrW   rX   rV   z%s=%iz (rq   ))r  r   r  r   printErrorsr   rl  writeln
separator2rc   rf   rS  writer   colorize_ansimaprd   rW   rX   rV   rg   rF   )r^   r   r   	startTimestopTime	timeTakenr?  failederroredrV   det_resultsr  r   s                r-   r?  zSkipAwareTextTestRunner.run  s   !!#F	V$"4"4dllK6y(	~~KK 1 12//CKK 8CAQcAWUWYb;c cdKK!'')==KK%%i&=&=he&TUKK%%h/==KK%%i&=&=d'&RSKK%%d+'*3&--QWQ_Q_0`'a$FGWKV__-6==)FNN+  Ee
 &&w$E
1C'CDE !!$'!!$))K"89!!#&KK#r/   )T)r'   r  )rz   r{   r|   r   r   r_   strboolr  r   r  r  r  r?  r  r  s   @r-   r~  r~    sy     zz.K3 K4 K*( *4 *4 *>H  	
&r/   r~  c                        e Zd Z	 	 	 	 ddedededededee   ded	df fd
Zde	d	e
eee	f      fdZde	de	d	dfdZde
e   d	eeedf   fdZd Z fdZ fdZd Zd fdZddZd Z xZS )r  Nrl  r  r   r   rP  r   rS  r'   c                     t         t        |   |||       g | _        g | _        g | _        g | _        || _        || _        || _	        || _
        t        | _        |dkD  | _        y Nr!   )rF  r  r_   rV   r}  fail_descrserror_descrsr   rP  r   rS  r   pdbclassrJ  )	r^   rl  r  r   r   rP  r   rS  rH  s	           r-   r_   zSkipAwareTestResult.__init__  se     	!41&,	R.0!!#"$"   1}r/   flavourc                 <    t        | d|j                         z        S )Nz	%s_descrs)re   lower)r^   r  s     r-   
descrs_forzSkipAwareTestResult.descrs_for4  s    t[7==?:;;r/   
test_descrc                    | j                  |      j                  t        | j                        |f       | j                  r@| j                  j                  | j                  t        j                         d                y y )NrM  )r  rg   rd   r}  rP  r  r   exc_info)r^   r  r  s      r-   _create_pdbzSkipAwareTestResult._create_pdb7  sY     ''T^^)<j(IJ<<NN!!$--q0A"BC r/   framesc              #      K   fd}t        j                  t              t        j                  t        j                        t	        ||      D ]  }|  yw)z;only consider non-testlib frames when formatting  tracebackc                 <    t        j                  | d         fv S r  )r+   rE   )filgc_testlibstd_testlibs    r-   invalidz7SkipAwareTestResult._iter_valid_frames.<locals>.invalid?  s     ;;r!u%+{)CCCr/   N)r+   rE   r   r   r   )r^   r  r  	frameinfor  r  s       @@r-   _iter_valid_framesz&SkipAwareTestResult._iter_valid_frames<  sL     	D kk(+kk("3"34"7F3 	IO	s   AAc           	      z   |\  }}}dg}t        j                  |      }| j                  }t        | j	                  |            }|D ]  \  }	\  }
}}}}}t        j                  |      }|d}ndj                  |      }|r!t        j                  |d      }t        |      }|j                  d|d|d|       |j                  d|j                         z         | j                  s|j                  t        |
      d	|j                         |j                  d       |j                  d
dj!                  dd      z          t#        |
j$                  j'                               D ]c  \  }}|j                  d
|d|       |dk(  s#t#        t)        |      j'                               D ]  \  }}|j                  d|d|        e |j                  d       |j                  d        |j                  dj                  t+        j,                  ||                   dj                  |      S )zConverts a sys.exc_info()-style tuple of values into a string.

        This method is overridden here because we want to colorize
        lines if --color is passed, and display local variables if
        --verbose is passed
        z!Traceback (most recent call last)z<no source available>r   magentaz  File "z", line z, in z    %sz == z    z local variables B   -r|  r^   z      self.zF    ------------------------------------------------------------------rr   )inspectgetinnerframesrS  	enumerater  r+   rE   rF   r   r  r    rg   rX  rJ  dirr{   r   sortedf_localsr   varsr   format_exception_only)r^   errr   exctyper   tboutputr  rS  indexframer&   linenofuncnamectxctxindexsourcevarnamer   s                      r-   _exc_info_to_stringz'SkipAwareTestResult._exc_info_to_stringH  s    b56''+==4226:;IO 	"EEEE8VXsH{{8,H{0$228YG(0MM8VXVWMM(V\\^34||CJHIb!f':'A'A"c'JJK&,U^^-A-A-C&D RNGUMM'5"AB&(.4T%[5F5F5H.I RNGU"MM%*PQRR
 /0b!+	", 	bggi==gsKLMyy  r/   c                 *   |\  }}}t        |t        j                        r(|t        j                  k(  sJ | j                  ||       y| j                  rd| _        | j                  |      }t        t        | '  ||       | j                  |d       y)zerr ->  (exc_type, exc, tcbk)Tr-  N)rY  r   r   addSkipr   
shouldStopgetDescriptionrF  r  addErrorr  )r^   r   r  exc_typer   r   rw   rH  s          r-   r  zSkipAwareTestResult.addErrorm  s    #qc7++,w/////LLs#~~"&''-E%t5dC@UG,r/   c                     | j                   rd| _        | j                  |      }t        t        |   ||       | j                  |d       y )NTfail)r   r  r  rF  r  
addFailurer  )r^   r   r  rw   rH  s       r-   r  zSkipAwareTestResult.addFailurez  sC    >>"DO##D)!43D#>'r/   c                     | j                   j                  ||f       | j                  r| j                  j	                  d       y | j
                  r| j                  j                  d       y y )NSKIPPEDS)rV   rg   showAllrl  r  dotsr  )r^   r   reasons      r-   r  zSkipAwareTestResult.addSkip  sO    T6N+<<KK	*YYKKc" r/   c                 J    t         t        |           | j                          y r   )rF  r  r  printSkippedList)r^   rH  s    r-   r  zSkipAwareTestResult.printErrors  s    !446r/   c                    | j                   D ]y  \  }}| j                  |      }| j                  j                  | j                         | j                  j                  dd|       | j                  j                  d|z         { y )Nr  r|  z	%s)rV   r  rl  r  
separator1)r^   r   r  rw   s       r-   r  z$SkipAwareTestResult.printSkippedList  sl     	.ID#''-EKK0KKIu =>KK-		.r/   c                 X   t        | j                  |      |      D ]  \  \  }}\  }}| j                  j                  | j                         | j                  j                  |d|       | j                  j                  | j
                         | j                  j                  |       | j                  j                  dj                  t        | j
                                     | j                  j                  dj                  t        | j
                                      y )Nr|  z	no stdoutz	no stderr)zipr  rl  r  r  r  r   rd   )r^   r  rX   r   rw   r   r  s          r-   printErrorListz"SkipAwareTestResult.printErrorList  s    '*4??7+CV'L 	J#JQsKK0KKGU ;<KK0KK$KK 2 23t3G HIKK 2 23t3G HI	Jr/   )FFNFr'   N)rz   r{   r|   r   r  intr   r   r_   r  r   r   r  r  r	   r   r  r  r  r  r  r  r  r  r  r  s   @r-   r  r    s      !%!% % 	%
 % % c]% % 
%,<# <$uS#X*? <Dc DC DD D

i 
YyRUW[G[=\ 
#!J-(# .Jr/   r  __call__r^   r   r  r   c                 <   t        | |||       t        |d      r|j                  r	 t        t        d      }	 dj                  | j                  j                  | j                  j                  | j                  f      }|j                  |t        j                  z          |j                          y y y # |j                          w xY w# t        $ rH t        dt!        j
                  t        j"                         t              t$        j&                          w xY w)N)r   r  r   r   arn  z&Error while saving succeeded test intor   )	orig_callr   r   r9   r   rF   rH  r{   rz   rq  r  rC   linesepr   r   r   r+   rD   r   r   )r^   r   r  r   r   rw   s         r-   callr
    s     d6gN w$):):	|S1K$^^..0G0GI]I]^ !!%"**"45!!# *;$ !!# 	8l3^^
 	s$   C
 A(B5 "C
 5CC
 
ADc                     t               S )z.return a new instance of the defaultTestResult)r  r]   s    r-   defaultTestResultr    s       r/   c            	            e Zd ZdZddZddee   dedefdZ	dede
eeeee   f   f   fdZd Zd fd		Zd
edefdZdedee   f fdZ xZS )rG  a  
    Overrides default testloader to be able to omit classname when
    specifying tests to run on command line.

    For example, if the file test_foo.py contains ::

        class FooTC(TestCase):
            def test_foo1(self): # ...
            def test_foo2(self): # ...
            def test_bar1(self): # ...

        class BarTC(TestCase):
            def test_bar2(self): # ...

    'python test_foo.py' will run the 3 tests in FooTC
    'python test_foo.py FooTC' will run the 3 tests in FooTC
    'python test_foo.py test_foo' will run test_foo1 and test_foo2
    'python test_foo.py test_foo1' will run test_foo1
    'python test_foo.py test_bar' will run FooTC.test_bar1 and BarTC.test_bar2
    r'   c                     d| _         y )Nra   )rQ  r]   s    r-   r_   zNonStrictTestLoader.__init__  s
     "r/   namesrC  c                 x    g }|D ]#  }|j                  | j                  ||             % | j                  |      S r   )r/  loadTestsFromName
suiteClass)r^   r  rC  suitesr  s        r-   loadTestsFromNamesz&NonStrictTestLoader.loadTestsFromNames  s@     	@DMM$00v>?	@v&&r/   c                    i }t        |      j                         D ]  }t        |      st        |t        j
                        s*|j                  }|d   dk(  s| j                  |      rPg }t        |      D ]G  }|j                  | j                        st        ||      }t        |      s7|j                  |       I ||f||<    |S )Nr   r   )r  r  r   
issubclassr   rp  rz   r  r  r   testMethodPrefixre   callablerg   )r^   rC  r   rr  	classnamemethodnamesattrnameattrs           r-   _collect_testsz"NonStrictTestLoader._collect_tests  s    <&&( 	6Cs|
30A0A BLL	Q<3&$*?*?	*J  #C 9H**4+@+@A&sH5#D>'..x8	9 %(#5i 	6 r/   c                     	  t        ||             }t        |d      sJ |j                  d|d       |j                  S # t        $ r g cY S w xY w)Nro  rn  z is not a valid TestSuite)re   AttributeErrorr   rz   ro  )r^   rC  	suitenamerO  s       r-   loadTestsFromSuitez&NonStrictTestLoader.loadTestsFromSuite  sb    	.GFI.0E uh' 	
OO*
 	
' ||  	I	s   A AAc                    |j                  d      }|t        |      dkD  rt        t        |   |      gS | j                  |      }g }t        |      dk(  r|d   }t        t        ||d             r||vr| j                  ||      S ||v r&||   \  }}|D ]  }	|D 	cg c]
  }	 ||	       }}	 |S |j                         D ]G  \  }}| j                  D ]  }
|D 	cg c]  }	|
|	vr|	
 }}	 ||D 	cg c]  }	||	v s ||	       c}	z  }I |S t        |      dk(  r=|\  }}|j                  |d g f      \  }}|D ]  }	|D 	cg c]  }	||	v s ||	       }}	 |S c c}	w c c}	w c c}	w c c}	w )Nrn  rM  r!   r   )rW  rd   rF  rG  r  r  r  re   r!  r  rQ  r;   )r^   r  rC  partsr   	collectedpatternr  r  
methodnameskip_patternr  rH  s               r-   r  z%NonStrictTestLoader.loadTestsFromName  s   

3>SZ!^-tFtLMM##F+	u:?AhG67G5<P..vw??%%*7^"{"- RJEP Qzz!2 QI QR. ' +0,,. 
&E;(,(=(=  /:' *+:= '' ' <G".87V`K`j)" I
&  Z1_!&Iw!&9tRj!AE;) 
8C*4wR\G\E*%	  - !R'
"s$   EE!2	E&<
E&	E+
E+r  c                 V    t        | j                  D cg c]  }||v  c}      S c c}w r   r  r  s      r-   r  z$NonStrictTestLoader._this_is_skipped-  s(     43H3HICSJ&IJJIr  testCaseClassc                     | j                   }|j                  }|d   dk(  s ||      rg S t        t        |   |      }|D cg c]  } ||      r| c}S c c}w )zCReturn a sorted sequence of method names found within testCaseClassr   r   )r  rz   rF  rG  getTestCaseNames)r^   r)  
is_skippedr  	testnamesr  rH  s         r-   r+  z$NonStrictTestLoader.getTestCaseNames2  s^    **
!**	Q<3*Y"7I-tEmT	)2OX*X:NOOOs   AAr  r   )rz   r{   r|   r}   r_   r   r  typer   r  r   r   r  r!  r  r  r  r+  r  r  s   @r-   rG  rG    s    *#
'S	 '4 '9 'T d3dDIo8N3N.O $&PK3 K4 K
Pd PtCy P Pr/   rG  debugc                 t    | j                  |||       | j                  d |       | j                  |       |S )Nr  )_wrapped_run_tearDownPreviousClass_handleModuleTearDown)r^   r   r/  r  r   s        r-   _ts_runr4  B  s<     	f<If-v&Mr/   c                 (   | D ]  }|j                   r |S t        j                  |      rl| j                  ||       | j	                  ||       | j                  ||       |j                  |_        t        |j                  dd      st        |dd      rt        |d      r	 |j                  ||||       |s	  ||||       |j                           |S # t        $ r |j                  ||       Y w xY w# t        $ r  ||       Y w xY w)N_classSetupFailedF_moduleSetUpFailedr1  r  )r  unittest_suite_isnotsuiter2  _handleModuleFixture_handleClassSetUprH  _previousTestClassre   r   r1  	TypeErrorr/  )r^   r   r/  r  r   r   s         r-   _ts_wrapped_runr>  O  s"     > M= %%d+''f5%%dF3""40(,F%t~~':EBg,eG  4(1!!&%lT[!\ V\73 JJL?B M  1!!&%01
  Vs$   #C<
C<C98C9<DD)rM     c                     d}t        |dd      du r	dx|_        }| j                  ||||       |r*| j                  d |       | j	                  |       d|_        |S )NF_testRunEnteredT)re   rA  r1  r2  r3  )r^   r   r/  r  r   topLevels         r-   r4  r4  ~  sj     6,e4=044F"X&%w?''f5&&v.%*F"r/   c                      t         sy	 ddlm} ddlm} | D ]  }|j                  ||        y# t
        $ r" t        j                  j                  d       Y yw xY w)a  
    Without arguments, return True if contracts can be enabled and should be
    enabled (see option -d), return False otherwise.

    With arguments, return False if contracts can't or shouldn't be enabled,
    otherwise weave ContractAspect with items passed as arguments.
    Fr   )weaver)ContractAspectz>Warning: logilab.aspects is not available. Contracts disabled.T)
r.  logilab.aspects.weaverrD  logilab.aspects.lib.contractsrE  ImportErrorr   r   r  weave_module)r0  rD  rE  r1  s       r-   
enable_dbcrJ    s`     1@  1C01  

YZs   / (AA)rM     rA  r   )NNN)FNN)pr}   rC   rer   os.pathr=   r+   r   r   r   rH  r.  sre_compilecompiler*   r  rZ  r  r   r   r   r	   randomr
   	itertoolsr   unittest.runnerr   unittest.suiter   typingr   r   r   r   r   r   r   logilab.common.deprecationr   logilab.common.fileutilsr   logilab.commonr   r   r   logilab.common.testlibr   r   r   r   r   logilab.common.debuggerr   r    doctestunittest_legacy
decoratorsr"   __docformat__r&  r.  r   re   unittest2.suiterO  r8  r:  r$  logilab.common.modutilsr$   r%   r(  rG   r)   r  r.   r2   r3   r@   rQ   objectrS   r   r<   r   r)  r4  r?  TestProgramr   TextTestRunnerr~  _TextTestResultr  rp  r  r  r
  r  
TestLoaderrG  r  r4  r>  version_inforJ  DocTestCase	__bases__FunctionTestCaser1  rz   ra   r/   r-   <module>ri     s]  $L^ 
 	 
  #	:     ; ;   . $ H H H : 4 $ 1 D 
 >  " #%
 
 t4L0
 ,SL 	bjj;<5 5% 5
 RZZ)*
3s 3x 3
5"*:=v :=z%4Iv IXv8 vrgT!8 ab&! c&!Rn8// nbuh55 up~J(22 ~JB %%	 Wz* #''+!	
 8$ c]	
 
 +: W! !
tP(-- tP@ !!



 
 	

 c]
 
  !!(
(( ( 	(
 c]( (V v !%!%#  	
 # 
(, / 1 ) + v%,%5%5$7G!
 ,3+;+;*=H'    "1   zE ]*  : ''A.44R89E:~  LJKL  Ls5   K/ =L, M
 /6L)(L),MM
MM