Skip to content

Commit

Permalink
feat: add support for async lambda_fixtures
Browse files Browse the repository at this point in the history
  • Loading branch information
theY4Kman committed May 17, 2022
1 parent 1c8f738 commit e65902a
Show file tree
Hide file tree
Showing 11 changed files with 214 additions and 179 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.


## [Unreleased]
### Added
- Add support for async/awaitable fixtures


## [1.2.6] — 2022-05-15
## Changed
### Changed
- Add support for pytest versions 7.0 and 7.1
- Relax pytest version pin to allow all versions under 8.x

Expand Down
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def test_the_namerator(full_name):
# Cheatsheet

```python
import asyncio
import pytest
from pytest_lambda import (
disabled_fixture,
Expand All @@ -42,6 +43,9 @@ from pytest_lambda import (
# Basic usage
fixture_name = lambda_fixture(lambda other_fixture: 'expression', scope='session', autouse=True)

# Async fixtures (awaitables automatically awaited) — requires an async plugin, like pytest-asyncio
fixture_name = lambda_fixture(lambda: asyncio.sleep(0, 'expression'), async_=True)

# Request fixtures by name
fixture_name = lambda_fixture('other_fixture')
fixture_name = lambda_fixture('other_fixture', 'another_fixture', 'cant_believe_its_not_fixture')
Expand Down Expand Up @@ -224,6 +228,32 @@ class ContextOcean:
```


### Async fixtures

By passing `async_=True` to `lambda_fixture`, the fixture will be defined as an async function, and if the returned value is awaitable, it will be automatically awaited before exposing it to pytest. This allows the usage of async things while only being slightly salty that Python, TO THIS DAY, still does not support `await` expressions within lambdas! Yes, only slightly salty!

NOTE: an asyncio pytest plugin is required to use async fixtures, such as [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio)

```python
# test_a_sink.py

import asyncio
import pytest
from pytest_lambda import lambda_fixture

async def hows_the_sink():
await asyncio.sleep(1)
return 'leaky'

a_sink = lambda_fixture(lambda: hows_the_sink(), async_=True)

class DescribeASink:
@pytest.mark.asyncio
async def it_is_leaky(self, a_sink):
assert a_sink is 'leaky'
```


# Development

How can I build and test the thing locally?
Expand Down
3 changes: 3 additions & 0 deletions _tox_install_command.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
poetry install -v \
&& poetry run pip install --no-warn-conflicts "$@"
110 changes: 55 additions & 55 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,17 @@ classifiers=[

[tool.poetry.dependencies]
# Typing annotations are used
# XXX: for whatever reason, poetry doesn't like `>=3.6` — the additional pin allows locking to work
python = '^3.6.1, >= 3.6.1'
# XXX: for whatever reason, poetry doesn't like `>=3.7` — the additional pin allows locking to work
python = '^3.7.0, >= 3.7.0'

pytest = '>=3.6, <8'
wrapt = '^1.11.0'


[tool.poetry.dev-dependencies]
tox = "^3.12"
pytest-markdown = "^1.0.2"
pytest-markdown = "*"
pytest-asyncio = "*"


[tool.poetry.plugins."pytest11"]
Expand Down
3 changes: 2 additions & 1 deletion pytest.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[pytest]
addopts = -v --tb=short --doctest-modules
testpaths = "tests"

asyncio_mode = auto

python_classes = Test* Describe* Context*
python_functions = test_* it_* its_* test
Expand Down
5 changes: 5 additions & 0 deletions pytest_lambda/compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
try:
from _pytest.compat import _PytestWrapper
except ImportError: # pytest<4
# Old pytest versions set the wrapped value directly to __pytest_wrapped__
_PytestWrapper = lambda obj: obj
12 changes: 9 additions & 3 deletions pytest_lambda/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

def lambda_fixture(fixture_name_or_lambda: Union[str, Callable]=None,
*other_fixture_names: Iterable[str],
bind=False,
bind: bool = False, async_: bool = False,
scope="function", params=None, autouse=False, ids=None, name=None):
"""Use a fixture name or lambda function to compactly declare a fixture
Expand All @@ -29,14 +29,20 @@ class DescribeMyTests:
first parameter in your fixture. This cannot be true if using a fixture
name.
:param async_: If True, the lambda will be wrapped in an async function; if the
lambda evaluates to an awaitable value, it will be awaited.
"""
if other_fixture_names:
fixture_names_or_lambda = (fixture_name_or_lambda,) + other_fixture_names
else:
fixture_names_or_lambda = fixture_name_or_lambda

return LambdaFixture(fixture_names_or_lambda, bind=bind, scope=scope,
params=params, autouse=autouse, ids=ids, name=name)
return LambdaFixture(
fixture_names_or_lambda,
bind=bind, async_=async_,
scope=scope, params=params, autouse=autouse, ids=ids, name=name,
)


def static_fixture(value: Any, **fixture_kwargs):
Expand Down
Loading

0 comments on commit e65902a

Please sign in to comment.