[pytest-dev] fixtures as context managers
holger krekel
holger at merlinux.eu
Mon May 27 09:36:04 CEST 2013
On Sun, May 26, 2013 at 15:37 +0000, Jason R. Coombs wrote:
> No. I haven't seen that syntax much if at all. I suggest it because it appeals to my aesthetic.
that's fine :)
> I'm not sure the distinction between class and decorator is so clear. After all, a decorator is just a callable with a particular signature. I haven't considered the implementation, but I imagine pytest.fixture could in fact be a class if you wanted it to be.
it could but decorators are typically functions.
> Even if fixture is only a factory function, it's conceivable that the alternate function could be appended as an attribute:
>
> def fixture(...):
> # primary behavior
>
> def _yielding_fixture(*args, **kwargs):
> # wrap or alter behavior of fixture(*args, **kwargs)
>
> fixture.yielding = _yielding_fixture
sure, that's possible.
> I agree the implementation is a little clumsy, but I would be inclined to accept a little bit of implementation cruft for a nicer exposed API.
I claim it would be a bit of an unexpected API. Maybe someone else than us
two can comment on it :)
> That said, I'm not trying to convince, but only to share. If you don't love the idea, I won't be offended if you don't incorporate it.
thanks for the relaxedness.
> Sent from Earth
:)
holger
>
> On May 26, 2013, at 7:52, "holger krekel" <holger at merlinux.eu> wrote:
>
> > Hi Jason,
> >
> > (your post contains a bit many blank lines, btw, deleting them :)
> >
> > On Sat, May 25, 2013 at 14:40 +0000, Jason R. Coombs wrote:
> >> May I suggest an alternate idea:
> >>
> >> @pytest.fixture.context(.)
> >>
> >> def func():
> >> .
> >>
> >> Or
> >>
> >> @pytest.fixture.yielding(.)
> >>
> >> def func():
> >> .
> >>
> >> Depending on which mode is not supported by fixture directly.
> >>
> >> Then, the decorator can take the same signature as the natural usage
> >> (@pytest.fixture), but alter the handling of a generator appropriately. It
> >> can be thought of as an alternate constructor for the same fixture factory.
> >> It provides a nice, namespaced name and doesn't threaten to pollute the
> >> pytest namespace with a proliferation of fixture variants.
> >
> > Not cramming the pytest.* is a goal i share but i am not sure about
> > this suggestion. The "idiomatic" way to introduce a decorator variant
> > in Python is adding a keyword argument or a new name.
> >
> > Your suggested syntax reminds of what one does for classes, i.e. providing
> > classmethods for alternate constructors. But i haven't seen it anywhere
> > for decorators, did you?
> >
> > best,
> > holger
> >
> >>
> >> From: Pytest-dev [mailto:pytest-dev-bounces+jaraco=jaraco.com at python.org] On
> >> Behalf Of Bruno Oliveira
> >> Sent: Friday, 24 May, 2013 17:13
> >> To: holger krekel; Harro van der Klauw; Andreas Pelme; pytest-dev at python.org
> >> Subject: Re: [pytest-dev] fixtures as context managers
> >>
> >>
> >>
> >> In light of the examples, IMHO, I agree that fixtures being explicit about
> >> using yield as context-managers is preferable.
> >>
> >>
> >>
> >> I like @pytest.contextfixture, it is easy to look-up and understand since it
> >> mimics what we already have in contextlib.
> >>
> >>
> >>
> >>
> >>
> >>
> >>
> >> On Fri, May 24, 2013 at 12:07 PM, holger krekel <holger at merlinux.eu
> >> <mailto:holger at merlinux.eu> > wrote:
> >>
> >> On Fri, May 24, 2013 at 16:50 +0200, Harro van der Klauw wrote:
> >>> As long as it throws an error hinting that you might need yielding=True it
> >>> should be obvious on how to fix
> >>> the backwards incompatibility issue as soon as you run your tests.
> >>
> >> We cannot easily throw an error with a hint. Consider this example:
> >>
> >> import pytest
> >>
> >>
> >> @pytest.fixture
> >> def fix():
> >> yield 1
> >> yield 2
> >>
> >> def test_fix(fix):
> >> for x in fix:
> >> assert x < 3
> >>
> >> This runs fine on pytest-2.3.5. On trunk it gives this error:
> >>
> >> ...
> >>
> >> fix = 1
> >>
> >> def test_fix(fix):
> >>> for x in fix:
> >> assert x < 3
> >> E TypeError: 'int' object is not iterable
> >>
> >> I've never written or seen somebody writing such a generator fixture,
> >> though.
> >> And what you would need to do is rewrite the fixture:
> >>
> >> @pytest.fixture
> >> def fix():
> >> def gen():
> >> yield 1
> >> yield 2
> >> return gen()
> >>
> >> Then again, when i first saw the contextlib.contextmanager decorator
> >> i found it not very intuitive. Did anyone? It looks like a hack.
> >>> From that angle i'd rather go for requiring "contextyield=True" or
> >> @pytest.contextfixture because that can be looked up in documentation
> >> and thus is easier to read for people not familiar with yields/contextlib.
> >>
> >> best,
> >> holger
> >>
> >>
> >>> I don't see a big problem with this, updating of a requirement is
> >> something
> >>> that you should never do automatically.
> >>>
> >>> Cheers,
> >>> Harro
> >>>
> >>>
> >>>
> >>> On 24 May 2013 16:36, Andreas Pelme <andreas at pelme.se
> >> <mailto:andreas at pelme.se> > wrote:
> >>>
> >>>> On Thursday 9 May 2013 at 15:56, holger krekel wrote:
> >>>>> This is probably used by very few people but to be on the safe side,
> >>>>> we probably should introduce a flag like this:
> >>>>>
> >>>>> @pytest.fixture(ctx=True) # signal this is a context manager style
> >>>> fixture
> >>>>> def fix():
> >>>>> yield 1
> >>>>>
> >>>>> What do you think? Any other suggestions for the flag name?
> >>>>>
> >>>>> I'd rather not introduce something like @pytest.contextfixture
> >>>>> because it would be a duplication of the API (scope, params).
> >>>>> But i am open to be convinced otherwise.
> >>>>
> >>>> I agree that another API like contextfixture should be avoided.
> >>>>
> >>>> We had a short discussion on IRC about this, Holger had the idea of
> >> doing
> >>>> the opposite if ctx=True - a new default argument "yielding=False" which
> >>>> would make it possible to restore the old behavior by putting
> >> yielding=True
> >>>> on fixtures that would be affected by this.
> >>>>
> >>>> A fixture that is a generator that currently looks like this
> >>>>
> >>>> @pytest.fixture
> >>>> def fix():
> >>>> yield 1
> >>>> yield 2
> >>>>
> >>>> Would then have to be changed to
> >>>>
> >>>> @pytest.fixture(yielding=True)
> >>>> def fix():
> >>>> yield 1
> >>>> yield 2
> >>>>
> >>>> This is backward incompatible, but given that it seems questionable if
> >>>> "generator fixtures" useful/is used, with a note in the release notes
> >> and
> >>>> documentation I think this could be a good compromise.
> >>>>
> >>>> I will be happy to give this a try if it is decided this could be a good
> >>>> approach!
> >>>>
> >>>> Cheers
> >>>> Andreas
> >>>>
> >>>>
> >>>> _______________________________________________
> >>>> Pytest-dev mailing list
> >>>> Pytest-dev at python.org <mailto:Pytest-dev at python.org>
> >>>> http://mail.python.org/mailman/listinfo/pytest-dev
> >>
> >>> _______________________________________________
> >>> Pytest-dev mailing list
> >>> Pytest-dev at python.org <mailto:Pytest-dev at python.org>
> >>> http://mail.python.org/mailman/listinfo/pytest-dev
> >>
> >> _______________________________________________
> >> Pytest-dev mailing list
> >> Pytest-dev at python.org <mailto:Pytest-dev at python.org>
> >> http://mail.python.org/mailman/listinfo/pytest-dev
> >
> >
> >
More information about the Pytest-dev
mailing list