forked from nose-devs/nose2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathevents.py
1295 lines (839 loc) · 35.5 KB
/
events.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# Adapted from unittest2/events.py from the unittest2 plugins branch.
# This module contains some code copied from unittest2/events.py and other
# code developed in reference to that module and others within unittest2.
# unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All
# Rights Reserved. See: http://docs.python.org/license.html
import logging
import argparse
import six
from nose2 import config, util
log = logging.getLogger(__name__)
__unittest = True
# FIXME decide on a real rule for camelCase vs under_score and stick with it.
# XXX I'd rather move this stuff to Plugin.__init__ and
# have __init__ call self.configure() or something after the
# initial setup, but that would further break compatibilty
# with the unittest2 plugins branch Plugin class.
class PluginMeta(type):
def __call__(cls, *args, **kwargs):
session = kwargs.pop('session', None)
instance = object.__new__(cls, *args, **kwargs)
instance.session = session
instance.config = config.Config([])
config_section = getattr(instance, 'configSection', None)
switch = getattr(instance, 'commandLineSwitch', None)
if session is not None and config_section is not None:
instance.config = session.get(config_section)
always_on = instance.config.as_bool(
'always-on', default=instance.alwaysOn)
instance.__init__(*args, **kwargs)
if always_on:
instance.register()
else:
if switch is not None:
short_opt, long_opt, help = switch
instance.addOption(
instance._register_cb, short_opt, long_opt, help)
return instance
class Plugin(six.with_metaclass(PluginMeta)):
"""Base class for nose2 plugins
All nose2 plugins must subclass this class.
.. attribute :: session
The :class:`nose2.session.Session` under which the plugin
has been loaded.
.. attribute :: config
The :class:`nose2.config.Config` representing the plugin's
config section as loaded from the session's config files.
.. attribute :: commandLineSwitch
A tuple of (short opt, long opt, help text) that defines a command
line flag that activates this plugin. The short opt may be ``None``. If
defined, it must be a single upper-case character. Both short and
long opt must *not* start with dashes.
Example::
commandLineSwitch = ('B', 'buffer-output', 'Buffer output during
tests')
.. attribute :: configSection
The name config file section to load into this plugin's config.
.. attribute :: alwaysOn
If this plugin should automatically register itself, set alwaysOn to
``True``. Default is ``False``.
.. note ::
Plugins that use config values from config files and want to
use the nose2 sphinx extension to automatically generate
documentation *must* extract all config values from
``self.config`` in ``__init__``. Otherwise the extension will
not be able to detect the config keys that the plugin uses.
"""
alwaysOn = False
registered = False
def register(self):
"""Register with appropriate hooks.
This activates the plugin and enables it to receive events.
"""
if self.session is None:
log.warning("Unable to register %s, no session", self)
return
self.session.registerPlugin(self)
self.registered = True
def addMethods(self, *methods):
"""Add new plugin methods to hooks registry
Any plugins that are already registered and implement
a method added here will be registered for that
method as well.
"""
for method in methods:
self.session.hooks.addMethod(method)
for plugin in self.session.plugins:
for method in methods:
if plugin.registered and hasattr(plugin, method):
self.session.hooks.register(method, plugin)
def _register_cb(self, *_):
self.register()
def addFlag(self, callback, short_opt, long_opt, help_text=None):
"""Add command-line flag that takes no arguments
:param callback: Callback function to run when flag is seen.
The callback will receive one empty argument.
:param short_opt: Short option. Must be uppercase, no dashes.
:param long_opt: Long option. Must not start with dashes
:param help_text: Help text for users so they know what this
flag does.
"""
self.addOption(callback, short_opt, long_opt, help_text, nargs=0)
def addArgument(self, callback, short_opt, long_opt, help_text=None):
"""Add command-line option that takes one argument.
:param callback: Callback function to run when flag is seen.
The callback will receive one argument.
:param short_opt: Short option. Must be uppercase, no dashes.
:param long_opt: Long option. Must not start with dashes
:param help_text: Help text for users so they know what this
flag does.
"""
self.addOption(callback, short_opt, long_opt, help_text, nargs=1)
def addOption(self, callback, short_opt, long_opt, help_text=None, nargs=0):
"""Add command-line option.
:param callback: Callback function to run when flag is seen.
The callback will receive one argument.
The "callback" may also be a list, in which
case values submitted on the command line
will be appended to the list.
:param short_opt: Short option. Must be uppercase, no dashes.
:param long_opt: Long option. Must not start with dashes
:param help_text: Help text for users so they know what this
flag does.
:param nargs: Number of arguments to consume from command line.
"""
if self.session is None:
log.warning("Unable to add option %s/%s for %s, no session",
short_opt, long_opt, self)
return
class CB(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
if six.callable(callback):
callback(values)
elif isinstance(callback, list):
callback.extend(values)
else:
raise ValueError(
"Invalid callback %s for plugin option %s",
callback, option_string)
opts = []
if short_opt:
if short_opt.lower() == short_opt:
raise ValueError(
'Lowercase short options are reserved: %s' % short_opt)
opts.append('-' + short_opt)
if long_opt:
opts.append('--' + long_opt)
self.session.pluginargs.add_argument(
*opts, action=CB, help=help_text, const=True, nargs=nargs)
class Hook(object):
"""A plugin hook
Each plugin method in the :class:`nose2.events.PluginInterface` is
represented at runtime by a Hook instance that lists the plugins
that should be called by that hook.
.. attribute :: method
The name of the method that this Hook represents.
.. attribute :: plugins
The list of plugin instances bound to this hook.
"""
def __init__(self, method):
self.method = method
self.plugins = []
def __call__(self, event):
for plugin in self.plugins[:]:
result = getattr(plugin, self.method)(event)
if event.handled:
return result
def append(self, plugin):
if plugin not in self.plugins:
self.plugins.append(plugin)
class PluginInterface(object):
"""Definition of plugin interface.
Instances of this class contain the methods that may be called,
and a dictionary of :class:`nose2.events.Hook` instances bound
to each method.
In a plugin, PluginInterface instance is typically available as
self.session.hooks, and plugin hooks may be called on it
directly::
event = events.LoadFromModuleEvent(module=the_module)
self.session.hooks.loadTestsFromModule(event)
.. attribute :: preRegistrationMethods
Tuple of methods that are called before registration.
.. attribute :: methods
Tuple of available plugin hook methods.
.. attribute :: hookClass
Class to instantiate for each hook. Default: :class:`nose2.events.Hook`.
"""
preRegistrationMethods = ('pluginsLoaded', 'handleArgs')
methods = (
'loadTestsFromModule', 'loadTestsFromNames', 'handleFile',
'startLayerSetup', 'startLayerSetupTest', 'stopLayerSetupTest',
'stopLayerSetup', 'startTestRun', 'startTest', 'stopTest',
'startLayerTeardown', 'startLayerTeardownTest',
'stopLayerTeardownTest', 'stopLayerTeardown', 'loadTestsFromName',
'loadTestsFromTestCase', 'stopTestRun', 'matchPath', 'matchDirPath',
'getTestCaseNames', 'runnerCreated', 'resultCreated', 'testOutcome',
'wasSuccessful', 'resultStop', 'setTestOutcome', 'describeTest',
'reportStartTest', 'reportError', 'reportFailure', 'reportSkip',
'reportSuccess', 'reportExpectedFailure', 'reportUnexpectedSuccess',
'reportOtherOutcome', 'outcomeDetail', 'beforeErrorList',
'beforeSummaryReport', 'afterSummaryReport', 'beforeInteraction',
'afterInteraction', 'createTests', 'createdTestSuite', 'afterTestRun',
'moduleLoadedSuite', 'handleDir',
# ... etc?
)
hookClass = Hook
def __init__(self):
self.hooks = {}
def addMethod(self, method):
"""Add a method to the available method.
This allows plugins to register for this method.
:param method: A method name
"""
self.methods = self.methods + (method,)
def register(self, method, plugin):
"""Register a plugin for a method.
:param method: A method name
:param plugin: A plugin instance
"""
self.hooks.setdefault(method, self.hookClass(method)).append(plugin)
def __getattr__(self, attr):
return self.hooks.setdefault(attr, self.hookClass(attr))
class Event(object):
"""Base class for all events.
.. attribute :: metadata
Storage for arbitrary information attached to an event.
.. attribute :: handled
Set to ``True`` to indicate that a plugin has handled the event,
and no other plugins or core systems should process it further.
.. attribute :: version
Version of the event API. This will be incremented with each
release of nose2 that changes the API.
"""
_attrs = ('handled',)
version = '0.4'
def __init__(self, **metadata):
self.handled = False
self.metadata = {}
self.metadata.update(metadata)
def __str__(self):
return '%s(%s)' % (self.__class__.__name__, self._format())
def __repr__(self):
return str(self)
def _format(self):
return ', '.join(['%s=%r' % (k, getattr(self, k, None))
for k in self._attrs])
def __getstate__(self):
state = self.__dict__
# FIXME fails for loadTestsFailure
if 'test' in state:
state['test'] = util.test_name(state['test'])
if 'executeTests' in state:
state['executeTests'] = None
if 'exc_info' in state and state['exc_info'] is not None:
ec, ev, tb = state['exc_info']
state['exc_info'] = (
ec, ev, util.format_traceback(None, (ec, ev, tb)))
clear = ('loader', 'result', 'runner')
for attr in clear:
if attr in state:
state[attr] = None
return state
class PluginsLoadedEvent(Event):
"""Event fired after all plugin classes are loaded.
.. attribute :: pluginsLoaded
List of all loaded plugin classes
"""
_attrs = Event._attrs + ('pluginsLoaded',)
def __init__(self, pluginsLoaded, **kw):
self.pluginsLoaded = pluginsLoaded
super(PluginsLoadedEvent, self).__init__(**kw)
class RunnerCreatedEvent(Event):
"""Event fired when test runner is created.
.. attribute :: runner
Test runner instance. Plugins may replace the test runner by
setting this attribute to a new test runner instance.
"""
_attrs = Event._attrs + ('runner',)
def __init__(self, runner, **kw):
self.runner = runner
super(RunnerCreatedEvent, self).__init__(**kw)
class ResultCreatedEvent(Event):
"""Event fired when test result handler is created.
.. attribute :: result
Test result handler instance. Plugins may replace the test
result by setting this attribute to a new test result instance.
"""
_attrs = Event._attrs + ('result',)
def __init__(self, result, **kw):
self.result = result
super(ResultCreatedEvent, self).__init__(**kw)
class StartLayerSetupEvent(Event):
"""Event fired before running a layer setup.
.. attribute :: layer
The current layer instance, for which setup is about to run.
"""
_attrs = Event._attrs + ('layer',)
def __init__(self, layer, **kw):
self.layer = layer
super(StartLayerSetupEvent, self).__init__(**kw)
class StopLayerSetupEvent(Event):
"""Event fired after running a layer setup.
.. attribute :: layer
The current layer instance, for which setup just ran.
"""
_attrs = Event._attrs + ('layer',)
def __init__(self, layer, **kw):
self.layer = layer
super(StopLayerSetupEvent, self).__init__(**kw)
class StartLayerSetupTestEvent(Event):
"""Event fired before test cases setups in layers.
.. attribute :: layer
The current layer instance.
.. attribute :: test
The test instance for which the setup is about to run.
"""
_attrs = Event._attrs + ('layer', 'test')
def __init__(self, layer, test, **kw):
self.layer = layer
self.test = test
super(StartLayerSetupTestEvent, self).__init__(**kw)
class StopLayerSetupTestEvent(Event):
"""Event fired after test cases setups in layers.
.. attribute :: layer
The current layer instance.
.. attribute :: test
The test instance for which the setup just finished.
"""
_attrs = Event._attrs + ('layer', 'test')
def __init__(self, layer, test, **kw):
self.layer = layer
self.test = test
super(StopLayerSetupTestEvent, self).__init__(**kw)
class StartLayerTeardownEvent(Event):
"""Event fired before running a layer teardown.
.. attribute :: layer
The current layer instance, for which teardown is about to run.
"""
_attrs = Event._attrs + ('layer',)
def __init__(self, layer, **kw):
self.layer = layer
super(StartLayerTeardownEvent, self).__init__(**kw)
class StopLayerTeardownEvent(Event):
"""Event fired after running a layer teardown.
.. attribute :: layer
The current layer instance, for which teardown just ran.
"""
_attrs = Event._attrs + ('layer',)
def __init__(self, layer, **kw):
self.layer = layer
super(StopLayerTeardownEvent, self).__init__(**kw)
class StartLayerTeardownTestEvent(Event):
"""Event fired before test cases teardowns in layers.
.. attribute :: layer
The current layer instance.
.. attribute :: test
The test instance for which teardown is about to run.
"""
_attrs = Event._attrs + ('layer', 'test')
def __init__(self, layer, test, **kw):
self.layer = layer
self.test = test
super(StartLayerTeardownTestEvent, self).__init__(**kw)
class StopLayerTeardownTestEvent(Event):
"""Event fired after test cases teardowns in layers.
.. attribute :: layer
The current layer instance.
.. attribute :: test
The test instance for which teardown just ran.
"""
_attrs = Event._attrs + ('layer', 'test')
def __init__(self, layer, test, **kw):
self.layer = layer
self.test = test
super(StopLayerTeardownTestEvent, self).__init__(**kw)
class StartTestRunEvent(Event):
"""Event fired when test run is about to start.
Test collection is complete before this event fires, but
no tests have yet been executed.
.. attribute :: runner
Test runner
.. attribute :: suite
Top-level test suite to execute. Plugins can filter this suite,
or set event.suite to change which tests execute (or how they
execute).
.. attribute :: result
Test result
.. attribute :: startTime
Timestamp of test run start
.. attribute :: executeTests
Callable that will be used to execute tests. Plugins may set
this attribute to wrap or otherwise change test execution. The
callable must match the signature::
def execute(suite, result):
...
To prevent normal test execution, plugins may set ``handled`` on
this event to ``True``. When ``handled`` is true, the test executor
does not run at all.
"""
_attrs = Event._attrs + ('runner', 'suite', 'result', 'startTime',
'executeTests')
def __init__(self, runner, suite, result, startTime, executeTests, **kw):
self.suite = suite
self.runner = runner
self.result = result
self.startTime = startTime
self.executeTests = executeTests
super(StartTestRunEvent, self).__init__(**kw)
class StopTestRunEvent(Event):
"""Event fired when test run has stopped.
.. attribute :: runner
Test runner
.. attribute :: result
Test result
.. attribute :: stopTime
Timestamp of test run stop
.. attribute :: timeTaken
Number of seconds test run took to execute
"""
_attrs = Event._attrs + ('runner', 'result', 'stopTime', 'timeTaken')
def __init__(self, runner, result, stopTime, timeTaken, **kw):
self.runner = runner
self.result = result
self.stopTime = stopTime
self.timeTaken = timeTaken
super(StopTestRunEvent, self).__init__(**kw)
class StartTestEvent(Event):
"""Event fired before a test is executed.
.. attribute :: test
The test case
.. attribute :: result
Test result
.. attribute :: startTime
Timestamp of test start
"""
_attrs = Event._attrs + ('test', 'result', 'startTime')
def __init__(self, test, result, startTime, **kw):
self.test = test
self.result = result
self.startTime = startTime
super(StartTestEvent, self).__init__(**kw)
class StopTestEvent(Event):
"""Event fired after a test is executed.
.. attribute :: test
The test case
.. attribute :: result
Test result
.. attribute :: stopTime
Timestamp of test stop
"""
_attrs = Event._attrs + ('test', 'result', 'stopTime')
def __init__(self, test, result, stopTime, **kw):
self.test = test
self.result = result
self.stopTime = stopTime
super(StopTestEvent, self).__init__(**kw)
class TestOutcomeEvent(Event):
"""Event fired when a test completes.
.. attribute :: test
The test case
.. attribute :: result
Test result
.. attribute :: outcome
Description of test outcome. Typically will be one of 'error',
'failed', 'skipped', or 'passed'.
.. attribute :: exc_info
If the test resulted in an exception, the tuple of (exception
class, exception value, traceback) as returned by
``sys.exc_info()``. If the test did not result in an exception,
``None``.
.. attribute :: reason
For test outcomes that include a reason (``Skips``, for example),
the reason.
.. attribute :: expected
Boolean indicating whether the test outcome was expected. In
general, all tests are expected to pass, and any other outcome
will have expected as ``False``. The exceptions to that rule are
unexpected successes and expected failures.
.. attribute :: shortLabel
A short label describing the test outcome. (For example, 'E'
for errors).
.. attribute :: longLabel
A long label describing the test outcome (for example, 'ERROR'
for errors).
Plugins may influence how the rest of the system sees the test
outcome by setting ``outcome`` or ``exc_info`` or ``expected``. They
may influence how the test outcome is reported to the user by
setting ``shortLabel`` or ``longLabel``.
"""
_attrs = Event._attrs + ('test', 'result', 'outcome', 'exc_info', 'reason',
'expected', 'shortLabel', 'longLabel')
def __init__(self, test, result, outcome, exc_info=None, reason=None,
expected=False, shortLabel=None, longLabel=None, **kw):
self.test = test
self.result = result
self.outcome = outcome
self.exc_info = exc_info
self.reason = reason
self.expected = expected
self.shortLabel = shortLabel
self.longLabel = longLabel
super(TestOutcomeEvent, self).__init__(**kw)
class LoadFromModuleEvent(Event):
"""Event fired when a test module is loaded.
.. attribute :: loader
Test loader instance
.. attribute :: module
The module whose tests are to be loaded
.. attribute :: extraTests
A list of extra tests loaded from the module. To load tests
from a module without interfering with other plugins' loading
activities, append tests to extraTests.
Plugins may set ``handled`` on this event and return a test suite
to prevent other plugins from loading tests from the module. If
any plugin sets ``handled`` to ``True``, ``extraTests`` will be
ignored.
"""
_attrs = Event._attrs + ('loader', 'module', 'extraTests')
def __init__(self, loader, module, **kw):
self.loader = loader
self.module = module
self.extraTests = []
super(LoadFromModuleEvent, self).__init__(**kw)
class ModuleSuiteEvent(Event):
_attrs = Event._attrs + ('loader', 'module', 'suite')
def __init__(self, loader, module, suite, **kw):
self.loader = loader
self.module = module
self.suite = suite
super(ModuleSuiteEvent, self).__init__(**kw)
class LoadFromTestCaseEvent(Event):
"""Event fired when tests are loaded from a test case.
.. attribute :: loader
Test loader instance
.. attribute :: testCase
The :class:`unittest.TestCase` instance being loaded.
.. attribute :: extraTests
A list of extra tests loaded from the module. To load tests
from a test case without interfering with other plugins'
loading activities, append tests to extraTests.
Plugins may set ``handled`` on this event and return a test suite
to prevent other plugins from loading tests from the test case. If
any plugin sets ``handled`` to ``True``, ``extraTests`` will be
ignored.
"""
_attrs = Event._attrs + ('loader', 'testCase', 'extraTests')
def __init__(self, loader, testCase, **kw):
self.loader = loader
self.testCase = testCase
self.extraTests = []
super(LoadFromTestCaseEvent, self).__init__(**kw)
class LoadFromNamesEvent(Event):
"""Event fired to load tests from test names.
.. attribute :: loader
Test loader instance
.. attribute :: names
List of test names. May be empty or ``None``.
.. attribute :: module
Module to load from. May be ``None``. If not ``None``, names should be
considered relative to this module.
.. attribute :: extraTests
A list of extra tests loaded from the tests named. To load
tests from test names without interfering with other plugins'
loading activities, append tests to extraTests.
Plugins may set ``handled`` on this event and return a test suite
to prevent other plugins from loading tests from the test names. If
any plugin sets ``handled`` to ``True``, ``extraTests`` will be
ignored.
"""
_attrs = Event._attrs + ('loader', 'names', 'module', 'extraTests')
def __init__(self, loader, names, module, **kw):
self.loader = loader
self.names = names
self.module = module
self.extraTests = []
super(LoadFromNamesEvent, self).__init__(**kw)
def __str__(self):
return "LoadFromNames(names=%r, module=%r)" % (self.names, self.module)
class LoadFromNameEvent(Event):
"""Event fired to load tests from test names.
.. attribute :: loader
Test loader instance
.. attribute :: name
Test name to load
.. attribute :: module
Module to load from. May be ``None``. If not ``None``, names should be
considered relative to this module.
.. attribute :: extraTests
A list of extra tests loaded from the name. To load tests
from a test name without interfering with other plugins'
loading activities, append tests to extraTests.
Plugins may set ``handled`` on this event and return a test suite
to prevent other plugins from loading tests from the test name. If
any plugin sets ``handled`` to ``True``, ``extraTests`` will be
ignored.
"""
_attrs = Event._attrs + ('loader', 'name', 'module', 'extraTests')
def __init__(self, loader, name, module, **kw):
self.loader = loader
self.name = name
self.module = module
self.extraTests = []
super(LoadFromNameEvent, self).__init__(**kw)
class HandleFileEvent(Event):
"""Event fired when a non-test file is examined.
.. note ::
This event is fired for all processed python files and modules
including but not limited to the ones that
match the test file pattern.
.. attribute :: loader
Test loader instance
.. attribute :: name
File basename
.. attribute :: path
Full path to file
.. attribute :: pattern
Current test file match pattern
.. attribute :: topLevelDirectory
Top-level directory of the test run
.. attribute :: extraTests
A list of extra tests loaded from the file. To load tests
from a file without interfering with other plugins'
loading activities, append tests to extraTests.
Plugins may set ``handled`` on this event and return a test suite
to prevent other plugins from loading tests from the file. If
any plugin sets ``handled`` to ``True``, ``extraTests`` will be
ignored.
"""
_attrs = Event._attrs + ('loader', 'name', 'path', 'pattern',
'topLevelDirectory')
def __init__(self, loader, name, path, pattern, topLevelDirectory, **kw):
self.extraTests = []
self.path = path
self.loader = loader
self.name = name
# note: pattern may be None if not called during test discovery
self.pattern = pattern
self.topLevelDirectory = topLevelDirectory
super(HandleFileEvent, self).__init__(**kw)
class MatchPathEvent(Event):
"""Event fired during file matching.
Plugins may return ``False`` and set ``handled`` on this event to prevent
a file from being matched as a test file, regardless of other system
settings.
.. attribute :: path
Full path to the file
.. attribute :: name
File basename
.. attribute :: pattern
Current test file match pattern
"""
_attrs = Event._attrs + ('name', 'path', 'pattern')
def __init__(self, name, path, pattern, **kw):
self.path = path
self.name = name
self.pattern = pattern
super(MatchPathEvent, self).__init__(**kw)
class GetTestCaseNamesEvent(Event):
"""Event fired to find test case names in a test case.