Skip to content

Commit f5caea6

Browse files
authored
v1.0.2 bugfix release (#38)
- Don't show ugly traceback executing `pytest --help`. - Don't show debug output retrieving Python Blender location with `pytest-blender` CLI. - Avoid to display a warning retrieving Python Blender location in Blender >= 2.91. - Improve Blender executable path discovering in MacOS
1 parent 7fcf0ab commit f5caea6

File tree

14 files changed

+200
-57
lines changed

14 files changed

+200
-57
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 1.0.1
2+
current_version = 1.0.2
33

44
[bumpversion:file:pytest_blender/__init__.py]
55

.github/workflows/ci.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
- ubuntu-latest
2121
- macos-latest
2222
blender-version:
23-
- '2.93.4'
23+
- '2.93.5'
2424
- '2.92.0'
2525
- '2.91.2'
2626
- '2.90.1'
@@ -61,8 +61,12 @@ jobs:
6161
$PYTHON_BLENDER_EXECUTABLE -m ensurepip
6262
$PYTHON_BLENDER_EXECUTABLE -m pip install pytest
6363
echo "::set-output name=blender-executable::$BLENDER_EXECUTABLE_PATH"
64-
- name: Test with pytest
64+
- name: Test with Blender Python executable (no cache)
6565
run: pytest -svv -p no:cacheprovider --blender-executable "${{ steps.install-dependencies.outputs.blender-executable }}" tests
66+
- name: Test with Blender Python executable
67+
run: pytest -svv --blender-executable "${{ steps.install-dependencies.outputs.blender-executable }}" tests
68+
- name: Test with local Python executable
69+
run: BLENDER_EXECUTABLE="${{ steps.install-dependencies.outputs.blender-executable }}" pytest -svv -p no:pytest-blender tests
6670

6771
build-sdist:
6872
if: startsWith(github.ref, 'refs/tags/')

pytest_blender/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.0.1"
1+
__version__ = "1.0.2"

pytest_blender/__main__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ def parse_args(args):
4545

4646
def run(args):
4747
opts = parse_args(args)
48-
sys.stdout.write(f"{get_blender_binary_path_python(opts.blender_executable)}\n")
48+
blender_python = get_blender_binary_path_python(opts.blender_executable)
49+
sys.stdout.write(f"{blender_python}\n")
4950

5051
return 0
5152

pytest_blender/plugin.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ def _get_blender_executable(config):
2828

2929
@pytest.hookimpl(tryfirst=True)
3030
def pytest_configure(config):
31+
pytest_help_opt = False
32+
3133
# build propagated CLI args
3234
propagated_cli_args = []
3335
_inside_root_invocation_arg = False
@@ -38,8 +40,14 @@ def pytest_configure(config):
3840
elif arg == "--blender-executable":
3941
_inside_root_invocation_arg = True
4042
continue
43+
elif arg in ["-h", "--help"]:
44+
pytest_help_opt = True
45+
break
4146
propagated_cli_args.append(arg)
4247

48+
if pytest_help_opt:
49+
return
50+
4351
blender_executable = _get_blender_executable(config)
4452

4553
if not blender_executable:

pytest_blender/run_pytest.py

Lines changed: 60 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ def _join(value):
2424
return join(value)
2525

2626

27-
# this function can't be in 'utils'
28-
def get_blender_binary_path_python(blender_executable):
27+
def _parse_version(version_string):
28+
return tuple(int(i) for i in version_string.split(".") if i.isdigit())
29+
30+
31+
def get_blender_binary_path_python(blender_executable, blend_version=None):
2932
"""Get Blender's Python executable location.
3033
3134
This function can't be in utils because the module is not loaded from
@@ -42,13 +45,22 @@ def get_blender_binary_path_python(blender_executable):
4245
4346
str: Blender's Python executable path.
4447
"""
48+
if blend_version is None:
49+
blend_version = get_blender_version(blender_executable)
50+
python_expr = (
51+
"import sys;print(sys.executable);"
52+
if _parse_version(blend_version) >= (2, 91)
53+
else "import bpy;print(bpy.app.binary_path_python)"
54+
)
55+
4556
stdout = subprocess.check_output(
4657
[
4758
blender_executable,
4859
"-b",
4960
"--python-expr",
50-
"import bpy;print(bpy.app.binary_path_python)",
51-
]
61+
python_expr,
62+
],
63+
stderr=subprocess.STDOUT,
5264
)
5365

5466
blender_python_path = None
@@ -59,20 +71,35 @@ def get_blender_binary_path_python(blender_executable):
5971
return blender_python_path
6072

6173

74+
def get_blender_version(blender_executable):
75+
"""Get Blender's version goving its executable location.
76+
77+
blender_executable : str
78+
Blender's executable location.
79+
80+
Returns
81+
-------
82+
83+
str: Blender's version.
84+
"""
85+
version_stdout = subprocess.check_output([blender_executable, "--version"])
86+
return version_stdout.decode("utf-8").splitlines()[0].split(" ")[1]
87+
88+
6289
def main():
6390
raw_argv = shlex.split(_join(sys.argv).split(" -- ")[1:][0])
6491

6592
# disable self-propagation, if installed in Blender Python interpreter
6693
argv = ["-p", "no:pytest-blender"]
6794

6895
# parse Blender executable location, propagated from hook
69-
blender_executable, _inside_bexec_arg = (None, None)
96+
_blender_executable, _inside_bexec_arg = (None, None)
7097
for arg in raw_argv:
7198
if arg == "--pytest-blender-executable":
7299
_inside_bexec_arg = True
73100
continue
74101
elif _inside_bexec_arg:
75-
blender_executable = arg
102+
_blender_executable = arg
76103
_inside_bexec_arg = False
77104
continue
78105
argv.append(arg)
@@ -84,92 +111,91 @@ class PytestBlenderPlugin:
84111
"""
85112

86113
def _blender_python_executable(self, request):
87-
blender_python_executable = None
114+
response = None
88115

89116
# if pytest is executed without cache provider, the 'cache'
90117
# attribute will not be available (-p no:cacheprovider)
91118
if hasattr(request.config, "cache"):
92-
blender_python_executable = request.config.cache.get(
119+
response = request.config.cache.get(
93120
"pytest-blender/blender-python-executable",
94121
None,
95122
)
96123

97-
if blender_python_executable is None:
98-
blender_python_executable = get_blender_binary_path_python(
99-
blender_executable,
124+
if response is None:
125+
response = get_blender_binary_path_python(
126+
_blender_executable,
127+
blend_version=self._blender_version(request),
100128
)
101129
if hasattr(request.config, "cache"):
102130
request.config.cache.set(
103131
"pytest-blender/blender-python-executable",
104-
blender_python_executable,
132+
response,
105133
)
106-
return blender_python_executable
134+
return response
107135

108136
@pytest.fixture
109137
def blender_executable(self):
110138
"""Get the executable of the current Blender's session."""
111-
return blender_executable
139+
return _blender_executable
112140

113141
@pytest.fixture
114142
def blender_python_executable(self, request):
115143
"""Get the executable of the current Blender's Python session."""
116144
return self._blender_python_executable(request)
117145

118-
@pytest.fixture
119-
def blender_version(self, request):
120-
"""Get the Blender version of the current session."""
121-
blender_version = None
146+
def _blender_version(self, request):
147+
response = None
122148

123149
if hasattr(request.config, "cache"):
124-
blender_version = request.config.cache.get(
150+
response = request.config.cache.get(
125151
"pytest-blender/blender-version",
126152
None,
127153
)
128154

129-
if blender_version is None:
130-
version_stdout = subprocess.check_output(
131-
[blender_executable, "--version"]
132-
)
133-
blender_version = (
134-
version_stdout.decode("utf-8").splitlines()[0].split(" ")[1]
135-
)
155+
if response is None:
156+
response = get_blender_version(_blender_executable)
136157
if hasattr(request.config, "cache"):
137158
request.config.cache.set(
138159
"pytest-blender/blender-version",
139-
blender_version,
160+
response,
140161
)
141-
return blender_version
162+
return response
163+
164+
@pytest.fixture
165+
def blender_version(self, request):
166+
"""Get the Blender version of the current session."""
167+
return self._blender_version(request)
142168

143169
@pytest.fixture
144170
def blender_python_version(self, request):
145171
"""Get the version of the Blender's Python executable."""
146-
blender_python_version = None
172+
response = None
147173

148174
if hasattr(request.config, "cache"):
149-
blender_python_version = request.config.cache.get(
175+
response = request.config.cache.get(
150176
"pytest-blender/blender-python-version",
151177
None,
152178
)
153179

154-
if blender_python_version is None:
180+
if response is None:
155181
blender_python_executable = self._blender_python_executable(request)
156182
blender_python_version_stdout = subprocess.check_output(
157183
[
158184
blender_python_executable,
159185
"--version",
160186
]
161187
)
162-
blender_python_version = (
188+
response = (
163189
blender_python_version_stdout.decode("utf-8")
164190
.splitlines()[0]
165191
.split(" ")[1]
166192
)
167193
if hasattr(request.config, "cache"):
168194
request.config.cache.set(
169195
"pytest-blender/blender-python-version",
170-
blender_python_version,
196+
response,
171197
)
172-
return blender_python_version
198+
return response
173199

174200
@pytest.fixture(scope="session")
175201
def install_addons_from_dir(self, request):

pytest_blender/test.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import sys
2+
3+
4+
pytest_blender_unactive = "-p" in sys.argv and "no:pytest-blender" in sys.argv
5+
pytest_blender_active = not pytest_blender_unactive

pytest_blender/utils.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
def which_blender_by_os():
66
"""Get the expected Blender executable location by operative system."""
7-
if sys.platform == "darwin":
8-
return "Blender"
9-
return "blender.exe" if "win" in sys.platform else shutil.which("blender")
7+
return (
8+
shutil.which("Blender")
9+
if sys.platform == "darwin"
10+
else ("blender.exe" if "win" in sys.platform else shutil.which("blender"))
11+
)

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = pytest_blender
3-
version = 1.0.1
3+
version = 1.0.2
44
description = Blender Pytest plugin.
55
long_description = file: README.md
66
long_description_content_type = text/markdown

tests/conftest.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,26 @@
77
import pytest
88

99

10-
@pytest.fixture(scope="session", autouse=True)
11-
def _register_addons(request, install_addons_from_dir, disable_addons):
12-
addons_dir = os.path.join(
13-
os.path.abspath(os.path.dirname(__file__)),
14-
"addons",
15-
)
16-
addon_module_names = ["pytest_blender_basic"]
10+
try:
11+
from pytest_blender.test import pytest_blender_active
12+
except ImportError:
13+
# executing pytest from Python Blender executable, the plugin is active
14+
pytest_blender_active = True
1715

18-
f = io.StringIO()
19-
with redirect_stdout(f):
20-
install_addons_from_dir(addons_dir, addon_module_names)
16+
if pytest_blender_active:
2117

22-
yield
18+
@pytest.fixture(scope="session", autouse=True)
19+
def _register_addons(request, install_addons_from_dir, disable_addons):
20+
addons_dir = os.path.join(
21+
os.path.abspath(os.path.dirname(__file__)),
22+
"addons",
23+
)
24+
addon_module_names = ["pytest_blender_basic"]
2325

24-
disable_addons(addon_module_names)
26+
f = io.StringIO()
27+
with redirect_stdout(f):
28+
install_addons_from_dir(addons_dir, addon_module_names)
29+
30+
yield
31+
32+
disable_addons(addon_module_names)

tests/test_addons.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
"""Example addons testing."""
22

3-
import _bpy
4-
import addon_utils
3+
import pytest
54

65

6+
try:
7+
from pytest_blender.test import pytest_blender_unactive
8+
except ImportError:
9+
pytest_blender_unactive = False
10+
11+
12+
@pytest.mark.skipif(
13+
pytest_blender_unactive,
14+
reason="Requires testing loading the pytest-blender plugin.",
15+
)
716
def test_basic_addon():
17+
import _bpy
18+
import addon_utils
19+
820
_module_loaded = False
921
for addon_module in addon_utils.modules():
1022
if addon_module.__name__ == "pytest_blender_basic":

tests/test_bpy_import.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,15 @@
1+
import pytest
2+
3+
4+
try:
5+
from pytest_blender.test import pytest_blender_unactive
6+
except ImportError:
7+
pytest_blender_unactive = False
8+
9+
10+
@pytest.mark.skipif(
11+
pytest_blender_unactive,
12+
reason="Requires testing loading the pytest-blender plugin.",
13+
)
114
def test_bpy_import():
215
import bpy # noqa F401

0 commit comments

Comments
 (0)