~ibmcharmers/charms/xenial/ibm-cinder-storwize-svc/trunk

« back to all changes in this revision

Viewing changes to .tox/py35/lib/python3.5/site-packages/_pytest/fixtures.py

  • Committer: Ankammarao
  • Date: 2017-03-06 05:11:42 UTC
  • Revision ID: achittet@in.ibm.com-20170306051142-dpg27z4es1k56hfn
Marked tests folder executable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import sys
 
2
 
 
3
from py._code.code import FormattedExcinfo
 
4
 
 
5
import py
 
6
import pytest
 
7
import warnings
 
8
 
 
9
import inspect
 
10
import _pytest
 
11
from _pytest._code.code import TerminalRepr
 
12
from _pytest.compat import (
 
13
    NOTSET, exc_clear, _format_args,
 
14
    getfslineno, get_real_func,
 
15
    is_generator, isclass, getimfunc,
 
16
    getlocation, getfuncargnames,
 
17
)
 
18
 
 
19
def pytest_sessionstart(session):
 
20
    session._fixturemanager = FixtureManager(session)
 
21
 
 
22
 
 
23
scopename2class = {}
 
24
 
 
25
 
 
26
scope2props = dict(session=())
 
27
scope2props["module"] = ("fspath", "module")
 
28
scope2props["class"] = scope2props["module"] + ("cls",)
 
29
scope2props["instance"] = scope2props["class"] + ("instance", )
 
30
scope2props["function"] = scope2props["instance"] + ("function", "keywords")
 
31
 
 
32
def scopeproperty(name=None, doc=None):
 
33
    def decoratescope(func):
 
34
        scopename = name or func.__name__
 
35
 
 
36
        def provide(self):
 
37
            if func.__name__ in scope2props[self.scope]:
 
38
                return func(self)
 
39
            raise AttributeError("%s not available in %s-scoped context" % (
 
40
                scopename, self.scope))
 
41
 
 
42
        return property(provide, None, None, func.__doc__)
 
43
    return decoratescope
 
44
 
 
45
 
 
46
def pytest_namespace():
 
47
    scopename2class.update({
 
48
        'class': pytest.Class,
 
49
        'module': pytest.Module,
 
50
        'function': pytest.Item,
 
51
    })
 
52
    return {
 
53
        'fixture': fixture,
 
54
        'yield_fixture': yield_fixture,
 
55
        'collect': {'_fillfuncargs': fillfixtures}
 
56
    }
 
57
 
 
58
 
 
59
def get_scope_node(node, scope):
 
60
    cls = scopename2class.get(scope)
 
61
    if cls is None:
 
62
        if scope == "session":
 
63
            return node.session
 
64
        raise ValueError("unknown scope")
 
65
    return node.getparent(cls)
 
66
 
 
67
 
 
68
def add_funcarg_pseudo_fixture_def(collector, metafunc, fixturemanager):
 
69
    # this function will transform all collected calls to a functions
 
70
    # if they use direct funcargs (i.e. direct parametrization)
 
71
    # because we want later test execution to be able to rely on
 
72
    # an existing FixtureDef structure for all arguments.
 
73
    # XXX we can probably avoid this algorithm  if we modify CallSpec2
 
74
    # to directly care for creating the fixturedefs within its methods.
 
75
    if not metafunc._calls[0].funcargs:
 
76
        return # this function call does not have direct parametrization
 
77
    # collect funcargs of all callspecs into a list of values
 
78
    arg2params = {}
 
79
    arg2scope = {}
 
80
    for callspec in metafunc._calls:
 
81
        for argname, argvalue in callspec.funcargs.items():
 
82
            assert argname not in callspec.params
 
83
            callspec.params[argname] = argvalue
 
84
            arg2params_list = arg2params.setdefault(argname, [])
 
85
            callspec.indices[argname] = len(arg2params_list)
 
86
            arg2params_list.append(argvalue)
 
87
            if argname not in arg2scope:
 
88
                scopenum = callspec._arg2scopenum.get(argname,
 
89
                                                      scopenum_function)
 
90
                arg2scope[argname] = scopes[scopenum]
 
91
        callspec.funcargs.clear()
 
92
 
 
93
    # register artificial FixtureDef's so that later at test execution
 
94
    # time we can rely on a proper FixtureDef to exist for fixture setup.
 
95
    arg2fixturedefs = metafunc._arg2fixturedefs
 
96
    for argname, valuelist in arg2params.items():
 
97
        # if we have a scope that is higher than function we need
 
98
        # to make sure we only ever create an according fixturedef on
 
99
        # a per-scope basis. We thus store and cache the fixturedef on the
 
100
        # node related to the scope.
 
101
        scope = arg2scope[argname]
 
102
        node = None
 
103
        if scope != "function":
 
104
            node = get_scope_node(collector, scope)
 
105
            if node is None:
 
106
                assert scope == "class" and isinstance(collector, pytest.Module)
 
107
                # use module-level collector for class-scope (for now)
 
108
                node = collector
 
109
        if node and argname in node._name2pseudofixturedef:
 
110
            arg2fixturedefs[argname] = [node._name2pseudofixturedef[argname]]
 
111
        else:
 
112
            fixturedef =  FixtureDef(fixturemanager, '', argname,
 
113
                           get_direct_param_fixture_func,
 
114
                           arg2scope[argname],
 
115
                           valuelist, False, False)
 
116
            arg2fixturedefs[argname] = [fixturedef]
 
117
            if node is not None:
 
118
                node._name2pseudofixturedef[argname] = fixturedef
 
119
 
 
120
 
 
121
 
 
122
def getfixturemarker(obj):
 
123
    """ return fixturemarker or None if it doesn't exist or raised
 
124
    exceptions."""
 
125
    try:
 
126
        return getattr(obj, "_pytestfixturefunction", None)
 
127
    except KeyboardInterrupt:
 
128
        raise
 
129
    except Exception:
 
130
        # some objects raise errors like request (from flask import request)
 
131
        # we don't expect them to be fixture functions
 
132
        return None
 
133
 
 
134
 
 
135
 
 
136
def get_parametrized_fixture_keys(item, scopenum):
 
137
    """ return list of keys for all parametrized arguments which match
 
138
    the specified scope. """
 
139
    assert scopenum < scopenum_function  # function
 
140
    try:
 
141
        cs = item.callspec
 
142
    except AttributeError:
 
143
        pass
 
144
    else:
 
145
        # cs.indictes.items() is random order of argnames but
 
146
        # then again different functions (items) can change order of
 
147
        # arguments so it doesn't matter much probably
 
148
        for argname, param_index in cs.indices.items():
 
149
            if cs._arg2scopenum[argname] != scopenum:
 
150
                continue
 
151
            if scopenum == 0:    # session
 
152
                key = (argname, param_index)
 
153
            elif scopenum == 1:  # module
 
154
                key = (argname, param_index, item.fspath)
 
155
            elif scopenum == 2:  # class
 
156
                key = (argname, param_index, item.fspath, item.cls)
 
157
            yield key
 
158
 
 
159
 
 
160
# algorithm for sorting on a per-parametrized resource setup basis
 
161
# it is called for scopenum==0 (session) first and performs sorting
 
162
# down to the lower scopes such as to minimize number of "high scope"
 
163
# setups and teardowns
 
164
 
 
165
def reorder_items(items):
 
166
    argkeys_cache = {}
 
167
    for scopenum in range(0, scopenum_function):
 
168
        argkeys_cache[scopenum] = d = {}
 
169
        for item in items:
 
170
            keys = set(get_parametrized_fixture_keys(item, scopenum))
 
171
            if keys:
 
172
                d[item] = keys
 
173
    return reorder_items_atscope(items, set(), argkeys_cache, 0)
 
174
 
 
175
def reorder_items_atscope(items, ignore, argkeys_cache, scopenum):
 
176
    if scopenum >= scopenum_function or len(items) < 3:
 
177
        return items
 
178
    items_done = []
 
179
    while 1:
 
180
        items_before, items_same, items_other, newignore = \
 
181
                slice_items(items, ignore, argkeys_cache[scopenum])
 
182
        items_before = reorder_items_atscope(
 
183
                            items_before, ignore, argkeys_cache,scopenum+1)
 
184
        if items_same is None:
 
185
            # nothing to reorder in this scope
 
186
            assert items_other is None
 
187
            return items_done + items_before
 
188
        items_done.extend(items_before)
 
189
        items = items_same + items_other
 
190
        ignore = newignore
 
191
 
 
192
 
 
193
def slice_items(items, ignore, scoped_argkeys_cache):
 
194
    # we pick the first item which uses a fixture instance in the
 
195
    # requested scope and which we haven't seen yet.  We slice the input
 
196
    # items list into a list of items_nomatch, items_same and
 
197
    # items_other
 
198
    if scoped_argkeys_cache:  # do we need to do work at all?
 
199
        it = iter(items)
 
200
        # first find a slicing key
 
201
        for i, item in enumerate(it):
 
202
            argkeys = scoped_argkeys_cache.get(item)
 
203
            if argkeys is not None:
 
204
                argkeys = argkeys.difference(ignore)
 
205
                if argkeys:  # found a slicing key
 
206
                    slicing_argkey = argkeys.pop()
 
207
                    items_before = items[:i]
 
208
                    items_same = [item]
 
209
                    items_other = []
 
210
                    # now slice the remainder of the list
 
211
                    for item in it:
 
212
                        argkeys = scoped_argkeys_cache.get(item)
 
213
                        if argkeys and slicing_argkey in argkeys and \
 
214
                            slicing_argkey not in ignore:
 
215
                            items_same.append(item)
 
216
                        else:
 
217
                            items_other.append(item)
 
218
                    newignore = ignore.copy()
 
219
                    newignore.add(slicing_argkey)
 
220
                    return (items_before, items_same, items_other, newignore)
 
221
    return items, None, None, None
 
222
 
 
223
 
 
224
 
 
225
class FuncargnamesCompatAttr:
 
226
    """ helper class so that Metafunc, Function and FixtureRequest
 
227
    don't need to each define the "funcargnames" compatibility attribute.
 
228
    """
 
229
    @property
 
230
    def funcargnames(self):
 
231
        """ alias attribute for ``fixturenames`` for pre-2.3 compatibility"""
 
232
        return self.fixturenames
 
233
 
 
234
 
 
235
def fillfixtures(function):
 
236
    """ fill missing funcargs for a test function. """
 
237
    try:
 
238
        request = function._request
 
239
    except AttributeError:
 
240
        # XXX this special code path is only expected to execute
 
241
        # with the oejskit plugin.  It uses classes with funcargs
 
242
        # and we thus have to work a bit to allow this.
 
243
        fm = function.session._fixturemanager
 
244
        fi = fm.getfixtureinfo(function.parent, function.obj, None)
 
245
        function._fixtureinfo = fi
 
246
        request = function._request = FixtureRequest(function)
 
247
        request._fillfixtures()
 
248
        # prune out funcargs for jstests
 
249
        newfuncargs = {}
 
250
        for name in fi.argnames:
 
251
            newfuncargs[name] = function.funcargs[name]
 
252
        function.funcargs = newfuncargs
 
253
    else:
 
254
        request._fillfixtures()
 
255
 
 
256
 
 
257
 
 
258
def get_direct_param_fixture_func(request):
 
259
    return request.param
 
260
 
 
261
class FuncFixtureInfo:
 
262
    def __init__(self, argnames, names_closure, name2fixturedefs):
 
263
        self.argnames = argnames
 
264
        self.names_closure = names_closure
 
265
        self.name2fixturedefs = name2fixturedefs
 
266
 
 
267
 
 
268
class FixtureRequest(FuncargnamesCompatAttr):
 
269
    """ A request for a fixture from a test or fixture function.
 
270
 
 
271
    A request object gives access to the requesting test context
 
272
    and has an optional ``param`` attribute in case
 
273
    the fixture is parametrized indirectly.
 
274
    """
 
275
 
 
276
    def __init__(self, pyfuncitem):
 
277
        self._pyfuncitem = pyfuncitem
 
278
        #: fixture for which this request is being performed
 
279
        self.fixturename = None
 
280
        #: Scope string, one of "function", "class", "module", "session"
 
281
        self.scope = "function"
 
282
        self._fixture_values = {}  # argname -> fixture value
 
283
        self._fixture_defs = {}  # argname -> FixtureDef
 
284
        fixtureinfo = pyfuncitem._fixtureinfo
 
285
        self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy()
 
286
        self._arg2index = {}
 
287
        self._fixturemanager = pyfuncitem.session._fixturemanager
 
288
 
 
289
    @property
 
290
    def fixturenames(self):
 
291
        # backward incompatible note: now a readonly property
 
292
        return list(self._pyfuncitem._fixtureinfo.names_closure)
 
293
 
 
294
    @property
 
295
    def node(self):
 
296
        """ underlying collection node (depends on current request scope)"""
 
297
        return self._getscopeitem(self.scope)
 
298
 
 
299
 
 
300
    def _getnextfixturedef(self, argname):
 
301
        fixturedefs = self._arg2fixturedefs.get(argname, None)
 
302
        if fixturedefs is None:
 
303
            # we arrive here because of a  a dynamic call to
 
304
            # getfixturevalue(argname) usage which was naturally
 
305
            # not known at parsing/collection time
 
306
            parentid = self._pyfuncitem.parent.nodeid
 
307
            fixturedefs = self._fixturemanager.getfixturedefs(argname, parentid)
 
308
            self._arg2fixturedefs[argname] = fixturedefs
 
309
        # fixturedefs list is immutable so we maintain a decreasing index
 
310
        index = self._arg2index.get(argname, 0) - 1
 
311
        if fixturedefs is None or (-index > len(fixturedefs)):
 
312
            raise FixtureLookupError(argname, self)
 
313
        self._arg2index[argname] = index
 
314
        return fixturedefs[index]
 
315
 
 
316
    @property
 
317
    def config(self):
 
318
        """ the pytest config object associated with this request. """
 
319
        return self._pyfuncitem.config
 
320
 
 
321
 
 
322
    @scopeproperty()
 
323
    def function(self):
 
324
        """ test function object if the request has a per-function scope. """
 
325
        return self._pyfuncitem.obj
 
326
 
 
327
    @scopeproperty("class")
 
328
    def cls(self):
 
329
        """ class (can be None) where the test function was collected. """
 
330
        clscol = self._pyfuncitem.getparent(pytest.Class)
 
331
        if clscol:
 
332
            return clscol.obj
 
333
 
 
334
    @property
 
335
    def instance(self):
 
336
        """ instance (can be None) on which test function was collected. """
 
337
        # unittest support hack, see _pytest.unittest.TestCaseFunction
 
338
        try:
 
339
            return self._pyfuncitem._testcase
 
340
        except AttributeError:
 
341
            function = getattr(self, "function", None)
 
342
            if function is not None:
 
343
                return py.builtin._getimself(function)
 
344
 
 
345
    @scopeproperty()
 
346
    def module(self):
 
347
        """ python module object where the test function was collected. """
 
348
        return self._pyfuncitem.getparent(pytest.Module).obj
 
349
 
 
350
    @scopeproperty()
 
351
    def fspath(self):
 
352
        """ the file system path of the test module which collected this test. """
 
353
        return self._pyfuncitem.fspath
 
354
 
 
355
    @property
 
356
    def keywords(self):
 
357
        """ keywords/markers dictionary for the underlying node. """
 
358
        return self.node.keywords
 
359
 
 
360
    @property
 
361
    def session(self):
 
362
        """ pytest session object. """
 
363
        return self._pyfuncitem.session
 
364
 
 
365
    def addfinalizer(self, finalizer):
 
366
        """ add finalizer/teardown function to be called after the
 
367
        last test within the requesting test context finished
 
368
        execution. """
 
369
        # XXX usually this method is shadowed by fixturedef specific ones
 
370
        self._addfinalizer(finalizer, scope=self.scope)
 
371
 
 
372
    def _addfinalizer(self, finalizer, scope):
 
373
        colitem = self._getscopeitem(scope)
 
374
        self._pyfuncitem.session._setupstate.addfinalizer(
 
375
            finalizer=finalizer, colitem=colitem)
 
376
 
 
377
    def applymarker(self, marker):
 
378
        """ Apply a marker to a single test function invocation.
 
379
        This method is useful if you don't want to have a keyword/marker
 
380
        on all function invocations.
 
381
 
 
382
        :arg marker: a :py:class:`_pytest.mark.MarkDecorator` object
 
383
            created by a call to ``pytest.mark.NAME(...)``.
 
384
        """
 
385
        try:
 
386
            self.node.keywords[marker.markname] = marker
 
387
        except AttributeError:
 
388
            raise ValueError(marker)
 
389
 
 
390
    def raiseerror(self, msg):
 
391
        """ raise a FixtureLookupError with the given message. """
 
392
        raise self._fixturemanager.FixtureLookupError(None, self, msg)
 
393
 
 
394
    def _fillfixtures(self):
 
395
        item = self._pyfuncitem
 
396
        fixturenames = getattr(item, "fixturenames", self.fixturenames)
 
397
        for argname in fixturenames:
 
398
            if argname not in item.funcargs:
 
399
                item.funcargs[argname] = self.getfixturevalue(argname)
 
400
 
 
401
    def cached_setup(self, setup, teardown=None, scope="module", extrakey=None):
 
402
        """ (deprecated) Return a testing resource managed by ``setup`` &
 
403
        ``teardown`` calls.  ``scope`` and ``extrakey`` determine when the
 
404
        ``teardown`` function will be called so that subsequent calls to
 
405
        ``setup`` would recreate the resource.  With pytest-2.3 you often
 
406
        do not need ``cached_setup()`` as you can directly declare a scope
 
407
        on a fixture function and register a finalizer through
 
408
        ``request.addfinalizer()``.
 
409
 
 
410
        :arg teardown: function receiving a previously setup resource.
 
411
        :arg setup: a no-argument function creating a resource.
 
412
        :arg scope: a string value out of ``function``, ``class``, ``module``
 
413
            or ``session`` indicating the caching lifecycle of the resource.
 
414
        :arg extrakey: added to internal caching key of (funcargname, scope).
 
415
        """
 
416
        if not hasattr(self.config, '_setupcache'):
 
417
            self.config._setupcache = {} # XXX weakref?
 
418
        cachekey = (self.fixturename, self._getscopeitem(scope), extrakey)
 
419
        cache = self.config._setupcache
 
420
        try:
 
421
            val = cache[cachekey]
 
422
        except KeyError:
 
423
            self._check_scope(self.fixturename, self.scope, scope)
 
424
            val = setup()
 
425
            cache[cachekey] = val
 
426
            if teardown is not None:
 
427
                def finalizer():
 
428
                    del cache[cachekey]
 
429
                    teardown(val)
 
430
                self._addfinalizer(finalizer, scope=scope)
 
431
        return val
 
432
 
 
433
    def getfixturevalue(self, argname):
 
434
        """ Dynamically run a named fixture function.
 
435
 
 
436
        Declaring fixtures via function argument is recommended where possible.
 
437
        But if you can only decide whether to use another fixture at test
 
438
        setup time, you may use this function to retrieve it inside a fixture
 
439
        or test function body.
 
440
        """
 
441
        return self._get_active_fixturedef(argname).cached_result[0]
 
442
 
 
443
    def getfuncargvalue(self, argname):
 
444
        """ Deprecated, use getfixturevalue. """
 
445
        from _pytest import deprecated
 
446
        warnings.warn(
 
447
            deprecated.GETFUNCARGVALUE,
 
448
            DeprecationWarning)
 
449
        return self.getfixturevalue(argname)
 
450
 
 
451
    def _get_active_fixturedef(self, argname):
 
452
        try:
 
453
            return self._fixture_defs[argname]
 
454
        except KeyError:
 
455
            try:
 
456
                fixturedef = self._getnextfixturedef(argname)
 
457
            except FixtureLookupError:
 
458
                if argname == "request":
 
459
                    class PseudoFixtureDef:
 
460
                        cached_result = (self, [0], None)
 
461
                        scope = "function"
 
462
                    return PseudoFixtureDef
 
463
                raise
 
464
        # remove indent to prevent the python3 exception
 
465
        # from leaking into the call
 
466
        result = self._getfixturevalue(fixturedef)
 
467
        self._fixture_values[argname] = result
 
468
        self._fixture_defs[argname] = fixturedef
 
469
        return fixturedef
 
470
 
 
471
    def _get_fixturestack(self):
 
472
        current = self
 
473
        l = []
 
474
        while 1:
 
475
            fixturedef = getattr(current, "_fixturedef", None)
 
476
            if fixturedef is None:
 
477
                l.reverse()
 
478
                return l
 
479
            l.append(fixturedef)
 
480
            current = current._parent_request
 
481
 
 
482
    def _getfixturevalue(self, fixturedef):
 
483
        # prepare a subrequest object before calling fixture function
 
484
        # (latter managed by fixturedef)
 
485
        argname = fixturedef.argname
 
486
        funcitem = self._pyfuncitem
 
487
        scope = fixturedef.scope
 
488
        try:
 
489
            param = funcitem.callspec.getparam(argname)
 
490
        except (AttributeError, ValueError):
 
491
            param = NOTSET
 
492
            param_index = 0
 
493
            if fixturedef.params is not None:
 
494
                frame = inspect.stack()[3]
 
495
                frameinfo = inspect.getframeinfo(frame[0])
 
496
                source_path = frameinfo.filename
 
497
                source_lineno = frameinfo.lineno
 
498
                source_path = py.path.local(source_path)
 
499
                if source_path.relto(funcitem.config.rootdir):
 
500
                    source_path = source_path.relto(funcitem.config.rootdir)
 
501
                msg = (
 
502
                    "The requested fixture has no parameter defined for the "
 
503
                    "current test.\n\nRequested fixture '{0}' defined in:\n{1}"
 
504
                    "\n\nRequested here:\n{2}:{3}".format(
 
505
                        fixturedef.argname,
 
506
                        getlocation(fixturedef.func, funcitem.config.rootdir),
 
507
                        source_path,
 
508
                        source_lineno,
 
509
                    )
 
510
                )
 
511
                pytest.fail(msg)
 
512
        else:
 
513
            # indices might not be set if old-style metafunc.addcall() was used
 
514
            param_index = funcitem.callspec.indices.get(argname, 0)
 
515
            # if a parametrize invocation set a scope it will override
 
516
            # the static scope defined with the fixture function
 
517
            paramscopenum = funcitem.callspec._arg2scopenum.get(argname)
 
518
            if paramscopenum is not None:
 
519
                scope = scopes[paramscopenum]
 
520
 
 
521
        subrequest = SubRequest(self, scope, param, param_index, fixturedef)
 
522
 
 
523
        # check if a higher-level scoped fixture accesses a lower level one
 
524
        subrequest._check_scope(argname, self.scope, scope)
 
525
 
 
526
        # clear sys.exc_info before invoking the fixture (python bug?)
 
527
        # if its not explicitly cleared it will leak into the call
 
528
        exc_clear()
 
529
        try:
 
530
            # call the fixture function
 
531
            val = fixturedef.execute(request=subrequest)
 
532
        finally:
 
533
            # if fixture function failed it might have registered finalizers
 
534
            self.session._setupstate.addfinalizer(fixturedef.finish,
 
535
                                                  subrequest.node)
 
536
        return val
 
537
 
 
538
    def _check_scope(self, argname, invoking_scope, requested_scope):
 
539
        if argname == "request":
 
540
            return
 
541
        if scopemismatch(invoking_scope, requested_scope):
 
542
            # try to report something helpful
 
543
            lines = self._factorytraceback()
 
544
            pytest.fail("ScopeMismatch: You tried to access the %r scoped "
 
545
                "fixture %r with a %r scoped request object, "
 
546
                "involved factories\n%s" %(
 
547
                (requested_scope, argname, invoking_scope, "\n".join(lines))),
 
548
                pytrace=False)
 
549
 
 
550
    def _factorytraceback(self):
 
551
        lines = []
 
552
        for fixturedef in self._get_fixturestack():
 
553
            factory = fixturedef.func
 
554
            fs, lineno = getfslineno(factory)
 
555
            p = self._pyfuncitem.session.fspath.bestrelpath(fs)
 
556
            args = _format_args(factory)
 
557
            lines.append("%s:%d:  def %s%s" %(
 
558
                p, lineno, factory.__name__, args))
 
559
        return lines
 
560
 
 
561
    def _getscopeitem(self, scope):
 
562
        if scope == "function":
 
563
            # this might also be a non-function Item despite its attribute name
 
564
            return self._pyfuncitem
 
565
        node = get_scope_node(self._pyfuncitem, scope)
 
566
        if node is None and scope == "class":
 
567
            # fallback to function item itself
 
568
            node = self._pyfuncitem
 
569
        assert node
 
570
        return node
 
571
 
 
572
    def __repr__(self):
 
573
        return "<FixtureRequest for %r>" %(self.node)
 
574
 
 
575
 
 
576
class SubRequest(FixtureRequest):
 
577
    """ a sub request for handling getting a fixture from a
 
578
    test function/fixture. """
 
579
    def __init__(self, request, scope, param, param_index, fixturedef):
 
580
        self._parent_request = request
 
581
        self.fixturename = fixturedef.argname
 
582
        if param is not NOTSET:
 
583
            self.param = param
 
584
        self.param_index = param_index
 
585
        self.scope = scope
 
586
        self._fixturedef = fixturedef
 
587
        self.addfinalizer = fixturedef.addfinalizer
 
588
        self._pyfuncitem = request._pyfuncitem
 
589
        self._fixture_values  = request._fixture_values
 
590
        self._fixture_defs = request._fixture_defs
 
591
        self._arg2fixturedefs = request._arg2fixturedefs
 
592
        self._arg2index = request._arg2index
 
593
        self._fixturemanager = request._fixturemanager
 
594
 
 
595
    def __repr__(self):
 
596
        return "<SubRequest %r for %r>" % (self.fixturename, self._pyfuncitem)
 
597
 
 
598
 
 
599
class ScopeMismatchError(Exception):
 
600
    """ A fixture function tries to use a different fixture function which
 
601
    which has a lower scope (e.g. a Session one calls a function one)
 
602
    """
 
603
 
 
604
 
 
605
scopes = "session module class function".split()
 
606
scopenum_function = scopes.index("function")
 
607
 
 
608
 
 
609
def scopemismatch(currentscope, newscope):
 
610
    return scopes.index(newscope) > scopes.index(currentscope)
 
611
 
 
612
 
 
613
def scope2index(scope, descr, where=None):
 
614
    """Look up the index of ``scope`` and raise a descriptive value error
 
615
    if not defined.
 
616
    """
 
617
    try:
 
618
        return scopes.index(scope)
 
619
    except ValueError:
 
620
        raise ValueError(
 
621
            "{0} {1}has an unsupported scope value '{2}'".format(
 
622
                descr, 'from {0} '.format(where) if where else '',
 
623
                scope)
 
624
        )
 
625
 
 
626
 
 
627
class FixtureLookupError(LookupError):
 
628
    """ could not return a requested Fixture (missing or invalid). """
 
629
    def __init__(self, argname, request, msg=None):
 
630
        self.argname = argname
 
631
        self.request = request
 
632
        self.fixturestack = request._get_fixturestack()
 
633
        self.msg = msg
 
634
 
 
635
    def formatrepr(self):
 
636
        tblines = []
 
637
        addline = tblines.append
 
638
        stack = [self.request._pyfuncitem.obj]
 
639
        stack.extend(map(lambda x: x.func, self.fixturestack))
 
640
        msg = self.msg
 
641
        if msg is not None:
 
642
            # the last fixture raise an error, let's present
 
643
            # it at the requesting side
 
644
            stack = stack[:-1]
 
645
        for function in stack:
 
646
            fspath, lineno = getfslineno(function)
 
647
            try:
 
648
                lines, _ = inspect.getsourcelines(get_real_func(function))
 
649
            except (IOError, IndexError, TypeError):
 
650
                error_msg = "file %s, line %s: source code not available"
 
651
                addline(error_msg % (fspath, lineno+1))
 
652
            else:
 
653
                addline("file %s, line %s" % (fspath, lineno+1))
 
654
                for i, line in enumerate(lines):
 
655
                    line = line.rstrip()
 
656
                    addline("  " + line)
 
657
                    if line.lstrip().startswith('def'):
 
658
                        break
 
659
 
 
660
        if msg is None:
 
661
            fm = self.request._fixturemanager
 
662
            available = []
 
663
            parentid = self.request._pyfuncitem.parent.nodeid
 
664
            for name, fixturedefs in fm._arg2fixturedefs.items():
 
665
                faclist = list(fm._matchfactories(fixturedefs, parentid))
 
666
                if faclist and name not in available:
 
667
                    available.append(name)
 
668
            msg = "fixture %r not found" % (self.argname,)
 
669
            msg += "\n available fixtures: %s" %(", ".join(sorted(available)),)
 
670
            msg += "\n use 'pytest --fixtures [testpath]' for help on them."
 
671
 
 
672
        return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname)
 
673
 
 
674
 
 
675
class FixtureLookupErrorRepr(TerminalRepr):
 
676
    def __init__(self, filename, firstlineno, tblines, errorstring, argname):
 
677
        self.tblines = tblines
 
678
        self.errorstring = errorstring
 
679
        self.filename = filename
 
680
        self.firstlineno = firstlineno
 
681
        self.argname = argname
 
682
 
 
683
    def toterminal(self, tw):
 
684
        # tw.line("FixtureLookupError: %s" %(self.argname), red=True)
 
685
        for tbline in self.tblines:
 
686
            tw.line(tbline.rstrip())
 
687
        lines = self.errorstring.split("\n")
 
688
        if lines:
 
689
            tw.line('{0}       {1}'.format(FormattedExcinfo.fail_marker,
 
690
                                           lines[0].strip()), red=True)
 
691
            for line in lines[1:]:
 
692
                tw.line('{0}       {1}'.format(FormattedExcinfo.flow_marker,
 
693
                                               line.strip()), red=True)
 
694
        tw.line()
 
695
        tw.line("%s:%d" % (self.filename, self.firstlineno+1))
 
696
 
 
697
 
 
698
def fail_fixturefunc(fixturefunc, msg):
 
699
    fs, lineno = getfslineno(fixturefunc)
 
700
    location = "%s:%s" % (fs, lineno+1)
 
701
    source = _pytest._code.Source(fixturefunc)
 
702
    pytest.fail(msg + ":\n\n" + str(source.indent()) + "\n" + location,
 
703
                pytrace=False)
 
704
 
 
705
def call_fixture_func(fixturefunc, request, kwargs):
 
706
    yieldctx = is_generator(fixturefunc)
 
707
    if yieldctx:
 
708
        it = fixturefunc(**kwargs)
 
709
        res = next(it)
 
710
 
 
711
        def teardown():
 
712
            try:
 
713
                next(it)
 
714
            except StopIteration:
 
715
                pass
 
716
            else:
 
717
                fail_fixturefunc(fixturefunc,
 
718
                    "yield_fixture function has more than one 'yield'")
 
719
 
 
720
        request.addfinalizer(teardown)
 
721
    else:
 
722
        res = fixturefunc(**kwargs)
 
723
    return res
 
724
 
 
725
 
 
726
class FixtureDef:
 
727
    """ A container for a factory definition. """
 
728
    def __init__(self, fixturemanager, baseid, argname, func, scope, params,
 
729
                 unittest=False, ids=None):
 
730
        self._fixturemanager = fixturemanager
 
731
        self.baseid = baseid or ''
 
732
        self.has_location = baseid is not None
 
733
        self.func = func
 
734
        self.argname = argname
 
735
        self.scope = scope
 
736
        self.scopenum = scope2index(
 
737
            scope or "function",
 
738
            descr='fixture {0}'.format(func.__name__),
 
739
            where=baseid
 
740
        )
 
741
        self.params = params
 
742
        startindex = unittest and 1 or None
 
743
        self.argnames = getfuncargnames(func, startindex=startindex)
 
744
        self.unittest = unittest
 
745
        self.ids = ids
 
746
        self._finalizer = []
 
747
 
 
748
    def addfinalizer(self, finalizer):
 
749
        self._finalizer.append(finalizer)
 
750
 
 
751
    def finish(self):
 
752
        try:
 
753
            while self._finalizer:
 
754
                func = self._finalizer.pop()
 
755
                func()
 
756
        finally:
 
757
            ihook = self._fixturemanager.session.ihook
 
758
            ihook.pytest_fixture_post_finalizer(fixturedef=self)
 
759
            # even if finalization fails, we invalidate
 
760
            # the cached fixture value
 
761
            if hasattr(self, "cached_result"):
 
762
                del self.cached_result
 
763
 
 
764
    def execute(self, request):
 
765
        # get required arguments and register our own finish()
 
766
        # with their finalization
 
767
        for argname in self.argnames:
 
768
            fixturedef = request._get_active_fixturedef(argname)
 
769
            if argname != "request":
 
770
                fixturedef.addfinalizer(self.finish)
 
771
 
 
772
        my_cache_key = request.param_index
 
773
        cached_result = getattr(self, "cached_result", None)
 
774
        if cached_result is not None:
 
775
            result, cache_key, err = cached_result
 
776
            if my_cache_key == cache_key:
 
777
                if err is not None:
 
778
                    py.builtin._reraise(*err)
 
779
                else:
 
780
                    return result
 
781
            # we have a previous but differently parametrized fixture instance
 
782
            # so we need to tear it down before creating a new one
 
783
            self.finish()
 
784
            assert not hasattr(self, "cached_result")
 
785
 
 
786
        ihook = self._fixturemanager.session.ihook
 
787
        return ihook.pytest_fixture_setup(fixturedef=self, request=request)
 
788
 
 
789
    def __repr__(self):
 
790
        return ("<FixtureDef name=%r scope=%r baseid=%r >" %
 
791
                (self.argname, self.scope, self.baseid))
 
792
 
 
793
def pytest_fixture_setup(fixturedef, request):
 
794
    """ Execution of fixture setup. """
 
795
    kwargs = {}
 
796
    for argname in fixturedef.argnames:
 
797
        fixdef = request._get_active_fixturedef(argname)
 
798
        result, arg_cache_key, exc = fixdef.cached_result
 
799
        request._check_scope(argname, request.scope, fixdef.scope)
 
800
        kwargs[argname] = result
 
801
 
 
802
    fixturefunc = fixturedef.func
 
803
    if fixturedef.unittest:
 
804
        if request.instance is not None:
 
805
            # bind the unbound method to the TestCase instance
 
806
            fixturefunc = fixturedef.func.__get__(request.instance)
 
807
    else:
 
808
        # the fixture function needs to be bound to the actual
 
809
        # request.instance so that code working with "fixturedef" behaves
 
810
        # as expected.
 
811
        if request.instance is not None:
 
812
            fixturefunc = getimfunc(fixturedef.func)
 
813
            if fixturefunc != fixturedef.func:
 
814
                fixturefunc = fixturefunc.__get__(request.instance)
 
815
    my_cache_key = request.param_index
 
816
    try:
 
817
        result = call_fixture_func(fixturefunc, request, kwargs)
 
818
    except Exception:
 
819
        fixturedef.cached_result = (None, my_cache_key, sys.exc_info())
 
820
        raise
 
821
    fixturedef.cached_result = (result, my_cache_key, None)
 
822
    return result
 
823
 
 
824
 
 
825
class FixtureFunctionMarker:
 
826
    def __init__(self, scope, params, autouse=False, ids=None, name=None):
 
827
        self.scope = scope
 
828
        self.params = params
 
829
        self.autouse = autouse
 
830
        self.ids = ids
 
831
        self.name = name
 
832
 
 
833
    def __call__(self, function):
 
834
        if isclass(function):
 
835
            raise ValueError(
 
836
                    "class fixtures not supported (may be in the future)")
 
837
        function._pytestfixturefunction = self
 
838
        return function
 
839
 
 
840
 
 
841
 
 
842
def fixture(scope="function", params=None, autouse=False, ids=None, name=None):
 
843
    """ (return a) decorator to mark a fixture factory function.
 
844
 
 
845
    This decorator can be used (with or or without parameters) to define
 
846
    a fixture function.  The name of the fixture function can later be
 
847
    referenced to cause its invocation ahead of running tests: test
 
848
    modules or classes can use the pytest.mark.usefixtures(fixturename)
 
849
    marker.  Test functions can directly use fixture names as input
 
850
    arguments in which case the fixture instance returned from the fixture
 
851
    function will be injected.
 
852
 
 
853
    :arg scope: the scope for which this fixture is shared, one of
 
854
                "function" (default), "class", "module" or "session".
 
855
 
 
856
    :arg params: an optional list of parameters which will cause multiple
 
857
                invocations of the fixture function and all of the tests
 
858
                using it.
 
859
 
 
860
    :arg autouse: if True, the fixture func is activated for all tests that
 
861
                can see it.  If False (the default) then an explicit
 
862
                reference is needed to activate the fixture.
 
863
 
 
864
    :arg ids: list of string ids each corresponding to the params
 
865
       so that they are part of the test id. If no ids are provided
 
866
       they will be generated automatically from the params.
 
867
 
 
868
    :arg name: the name of the fixture. This defaults to the name of the
 
869
               decorated function. If a fixture is used in the same module in
 
870
               which it is defined, the function name of the fixture will be
 
871
               shadowed by the function arg that requests the fixture; one way
 
872
               to resolve this is to name the decorated function
 
873
               ``fixture_<fixturename>`` and then use
 
874
               ``@pytest.fixture(name='<fixturename>')``.
 
875
 
 
876
    Fixtures can optionally provide their values to test functions using a ``yield`` statement,
 
877
    instead of ``return``. In this case, the code block after the ``yield`` statement is executed
 
878
    as teardown code regardless of the test outcome. A fixture function must yield exactly once.
 
879
    """
 
880
    if callable(scope) and params is None and autouse == False:
 
881
        # direct decoration
 
882
        return FixtureFunctionMarker(
 
883
                "function", params, autouse, name=name)(scope)
 
884
    if params is not None and not isinstance(params, (list, tuple)):
 
885
        params = list(params)
 
886
    return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name)
 
887
 
 
888
 
 
889
def yield_fixture(scope="function", params=None, autouse=False, ids=None, name=None):
 
890
    """ (return a) decorator to mark a yield-fixture factory function.
 
891
 
 
892
    .. deprecated:: 3.0
 
893
        Use :py:func:`pytest.fixture` directly instead.
 
894
    """
 
895
    if callable(scope) and params is None and not autouse:
 
896
        # direct decoration
 
897
        return FixtureFunctionMarker(
 
898
                "function", params, autouse, ids=ids, name=name)(scope)
 
899
    else:
 
900
        return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name)
 
901
 
 
902
 
 
903
defaultfuncargprefixmarker = fixture()
 
904
 
 
905
 
 
906
@fixture(scope="session")
 
907
def pytestconfig(request):
 
908
    """ the pytest config object with access to command line opts."""
 
909
    return request.config
 
910
 
 
911
 
 
912
class FixtureManager:
 
913
    """
 
914
    pytest fixtures definitions and information is stored and managed
 
915
    from this class.
 
916
 
 
917
    During collection fm.parsefactories() is called multiple times to parse
 
918
    fixture function definitions into FixtureDef objects and internal
 
919
    data structures.
 
920
 
 
921
    During collection of test functions, metafunc-mechanics instantiate
 
922
    a FuncFixtureInfo object which is cached per node/func-name.
 
923
    This FuncFixtureInfo object is later retrieved by Function nodes
 
924
    which themselves offer a fixturenames attribute.
 
925
 
 
926
    The FuncFixtureInfo object holds information about fixtures and FixtureDefs
 
927
    relevant for a particular function.  An initial list of fixtures is
 
928
    assembled like this:
 
929
 
 
930
    - ini-defined usefixtures
 
931
    - autouse-marked fixtures along the collection chain up from the function
 
932
    - usefixtures markers at module/class/function level
 
933
    - test function funcargs
 
934
 
 
935
    Subsequently the funcfixtureinfo.fixturenames attribute is computed
 
936
    as the closure of the fixtures needed to setup the initial fixtures,
 
937
    i. e. fixtures needed by fixture functions themselves are appended
 
938
    to the fixturenames list.
 
939
 
 
940
    Upon the test-setup phases all fixturenames are instantiated, retrieved
 
941
    by a lookup of their FuncFixtureInfo.
 
942
    """
 
943
 
 
944
    _argprefix = "pytest_funcarg__"
 
945
    FixtureLookupError = FixtureLookupError
 
946
    FixtureLookupErrorRepr = FixtureLookupErrorRepr
 
947
 
 
948
    def __init__(self, session):
 
949
        self.session = session
 
950
        self.config = session.config
 
951
        self._arg2fixturedefs = {}
 
952
        self._holderobjseen = set()
 
953
        self._arg2finish = {}
 
954
        self._nodeid_and_autousenames = [("", self.config.getini("usefixtures"))]
 
955
        session.config.pluginmanager.register(self, "funcmanage")
 
956
 
 
957
 
 
958
    def getfixtureinfo(self, node, func, cls, funcargs=True):
 
959
        if funcargs and not hasattr(node, "nofuncargs"):
 
960
            if cls is not None:
 
961
                startindex = 1
 
962
            else:
 
963
                startindex = None
 
964
            argnames = getfuncargnames(func, startindex)
 
965
        else:
 
966
            argnames = ()
 
967
        usefixtures = getattr(func, "usefixtures", None)
 
968
        initialnames = argnames
 
969
        if usefixtures is not None:
 
970
            initialnames = usefixtures.args + initialnames
 
971
        fm = node.session._fixturemanager
 
972
        names_closure, arg2fixturedefs = fm.getfixtureclosure(initialnames,
 
973
                                                              node)
 
974
        return FuncFixtureInfo(argnames, names_closure, arg2fixturedefs)
 
975
 
 
976
    def pytest_plugin_registered(self, plugin):
 
977
        nodeid = None
 
978
        try:
 
979
            p = py.path.local(plugin.__file__)
 
980
        except AttributeError:
 
981
            pass
 
982
        else:
 
983
            # construct the base nodeid which is later used to check
 
984
            # what fixtures are visible for particular tests (as denoted
 
985
            # by their test id)
 
986
            if p.basename.startswith("conftest.py"):
 
987
                nodeid = p.dirpath().relto(self.config.rootdir)
 
988
                if p.sep != "/":
 
989
                    nodeid = nodeid.replace(p.sep, "/")
 
990
        self.parsefactories(plugin, nodeid)
 
991
 
 
992
    def _getautousenames(self, nodeid):
 
993
        """ return a tuple of fixture names to be used. """
 
994
        autousenames = []
 
995
        for baseid, basenames in self._nodeid_and_autousenames:
 
996
            if nodeid.startswith(baseid):
 
997
                if baseid:
 
998
                    i = len(baseid)
 
999
                    nextchar = nodeid[i:i+1]
 
1000
                    if nextchar and nextchar not in ":/":
 
1001
                        continue
 
1002
                autousenames.extend(basenames)
 
1003
        # make sure autousenames are sorted by scope, scopenum 0 is session
 
1004
        autousenames.sort(
 
1005
            key=lambda x: self._arg2fixturedefs[x][-1].scopenum)
 
1006
        return autousenames
 
1007
 
 
1008
    def getfixtureclosure(self, fixturenames, parentnode):
 
1009
        # collect the closure of all fixtures , starting with the given
 
1010
        # fixturenames as the initial set.  As we have to visit all
 
1011
        # factory definitions anyway, we also return a arg2fixturedefs
 
1012
        # mapping so that the caller can reuse it and does not have
 
1013
        # to re-discover fixturedefs again for each fixturename
 
1014
        # (discovering matching fixtures for a given name/node is expensive)
 
1015
 
 
1016
        parentid = parentnode.nodeid
 
1017
        fixturenames_closure = self._getautousenames(parentid)
 
1018
 
 
1019
        def merge(otherlist):
 
1020
            for arg in otherlist:
 
1021
                if arg not in fixturenames_closure:
 
1022
                    fixturenames_closure.append(arg)
 
1023
 
 
1024
        merge(fixturenames)
 
1025
        arg2fixturedefs = {}
 
1026
        lastlen = -1
 
1027
        while lastlen != len(fixturenames_closure):
 
1028
            lastlen = len(fixturenames_closure)
 
1029
            for argname in fixturenames_closure:
 
1030
                if argname in arg2fixturedefs:
 
1031
                    continue
 
1032
                fixturedefs = self.getfixturedefs(argname, parentid)
 
1033
                if fixturedefs:
 
1034
                    arg2fixturedefs[argname] = fixturedefs
 
1035
                    merge(fixturedefs[-1].argnames)
 
1036
        return fixturenames_closure, arg2fixturedefs
 
1037
 
 
1038
    def pytest_generate_tests(self, metafunc):
 
1039
        for argname in metafunc.fixturenames:
 
1040
            faclist = metafunc._arg2fixturedefs.get(argname)
 
1041
            if faclist:
 
1042
                fixturedef = faclist[-1]
 
1043
                if fixturedef.params is not None:
 
1044
                    func_params = getattr(getattr(metafunc.function, 'parametrize', None), 'args', [[None]])
 
1045
                    # skip directly parametrized arguments
 
1046
                    argnames = func_params[0]
 
1047
                    if not isinstance(argnames, (tuple, list)):
 
1048
                        argnames = [x.strip() for x in argnames.split(",") if x.strip()]
 
1049
                    if argname not in func_params and argname not in argnames:
 
1050
                        metafunc.parametrize(argname, fixturedef.params,
 
1051
                                             indirect=True, scope=fixturedef.scope,
 
1052
                                             ids=fixturedef.ids)
 
1053
            else:
 
1054
                continue  # will raise FixtureLookupError at setup time
 
1055
 
 
1056
    def pytest_collection_modifyitems(self, items):
 
1057
        # separate parametrized setups
 
1058
        items[:] = reorder_items(items)
 
1059
 
 
1060
    def parsefactories(self, node_or_obj, nodeid=NOTSET, unittest=False):
 
1061
        if nodeid is not NOTSET:
 
1062
            holderobj = node_or_obj
 
1063
        else:
 
1064
            holderobj = node_or_obj.obj
 
1065
            nodeid = node_or_obj.nodeid
 
1066
        if holderobj in self._holderobjseen:
 
1067
            return
 
1068
        self._holderobjseen.add(holderobj)
 
1069
        autousenames = []
 
1070
        for name in dir(holderobj):
 
1071
            obj = getattr(holderobj, name, None)
 
1072
            # fixture functions have a pytest_funcarg__ prefix (pre-2.3 style)
 
1073
            # or are "@pytest.fixture" marked
 
1074
            marker = getfixturemarker(obj)
 
1075
            if marker is None:
 
1076
                if not name.startswith(self._argprefix):
 
1077
                    continue
 
1078
                if not callable(obj):
 
1079
                    continue
 
1080
                marker = defaultfuncargprefixmarker
 
1081
                from _pytest import deprecated
 
1082
                self.config.warn('C1', deprecated.FUNCARG_PREFIX.format(name=name))
 
1083
                name = name[len(self._argprefix):]
 
1084
            elif not isinstance(marker, FixtureFunctionMarker):
 
1085
                # magic globals  with __getattr__ might have got us a wrong
 
1086
                # fixture attribute
 
1087
                continue
 
1088
            else:
 
1089
                if marker.name:
 
1090
                    name = marker.name
 
1091
                msg = 'fixtures cannot have "pytest_funcarg__" prefix ' \
 
1092
                      'and be decorated with @pytest.fixture:\n%s' % name
 
1093
                assert not name.startswith(self._argprefix), msg
 
1094
 
 
1095
            fixture_def = FixtureDef(self, nodeid, name, obj,
 
1096
                                     marker.scope, marker.params,
 
1097
                                     unittest=unittest, ids=marker.ids)
 
1098
 
 
1099
            faclist = self._arg2fixturedefs.setdefault(name, [])
 
1100
            if fixture_def.has_location:
 
1101
                faclist.append(fixture_def)
 
1102
            else:
 
1103
                # fixturedefs with no location are at the front
 
1104
                # so this inserts the current fixturedef after the
 
1105
                # existing fixturedefs from external plugins but
 
1106
                # before the fixturedefs provided in conftests.
 
1107
                i = len([f for f in faclist if not f.has_location])
 
1108
                faclist.insert(i, fixture_def)
 
1109
            if marker.autouse:
 
1110
                autousenames.append(name)
 
1111
 
 
1112
        if autousenames:
 
1113
            self._nodeid_and_autousenames.append((nodeid or '', autousenames))
 
1114
 
 
1115
    def getfixturedefs(self, argname, nodeid):
 
1116
        """
 
1117
        Gets a list of fixtures which are applicable to the given node id.
 
1118
 
 
1119
        :param str argname: name of the fixture to search for
 
1120
        :param str nodeid: full node id of the requesting test.
 
1121
        :return: list[FixtureDef]
 
1122
        """
 
1123
        try:
 
1124
            fixturedefs = self._arg2fixturedefs[argname]
 
1125
        except KeyError:
 
1126
            return None
 
1127
        else:
 
1128
            return tuple(self._matchfactories(fixturedefs, nodeid))
 
1129
 
 
1130
    def _matchfactories(self, fixturedefs, nodeid):
 
1131
        for fixturedef in fixturedefs:
 
1132
            if nodeid.startswith(fixturedef.baseid):
 
1133
                yield fixturedef
 
1134