Skip to content

Commit a8c1ff4

Browse files
authored
Fix performance regression from version 4.0.0 (#386)
* Fix performance issue when collecting tests. * Add changelog entry
1 parent 6ca1df9 commit a8c1ff4

File tree

2 files changed

+42
-19
lines changed

2 files changed

+42
-19
lines changed

CHANGES.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Changelog
22
=========
33

4+
Unreleased
5+
----------
6+
- Fixed performance regression introduced in 4.0.0 where collection time of tests would take way longer than before. (youtux)
7+
8+
49
4.0.0
510
-----
611

pytest_bdd/utils.py

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,39 @@
11
"""Various utility functions."""
22

3-
import inspect
3+
from sys import _getframe
4+
from inspect import getframeinfo
45

56
import six
67

78
CONFIG_STACK = []
89

10+
if six.PY2:
11+
from inspect import getargspec as _getargspec
912

10-
def get_args(func):
11-
"""Get a list of argument names for a function.
13+
def get_args(func):
14+
"""Get a list of argument names for a function.
1215
13-
This is a wrapper around inspect.getargspec/inspect.signature because
14-
getargspec got deprecated in Python 3.5 and signature isn't available on
15-
Python 2.
16+
:param func: The function to inspect.
1617
17-
:param func: The function to inspect.
18+
:return: A list of argument names.
19+
:rtype: list
20+
"""
21+
return _getargspec(func).args
1822

19-
:return: A list of argument names.
20-
:rtype: list
21-
"""
22-
if six.PY2:
23-
return inspect.getargspec(func).args
2423

25-
params = inspect.signature(func).parameters.values()
26-
return [param.name for param in params if param.kind == param.POSITIONAL_OR_KEYWORD]
24+
else:
25+
from inspect import signature as _signature
26+
27+
def get_args(func):
28+
"""Get a list of argument names for a function.
29+
30+
:param func: The function to inspect.
31+
32+
:return: A list of argument names.
33+
:rtype: list
34+
"""
35+
params = _signature(func).parameters.values()
36+
return [param.name for param in params if param.kind == param.POSITIONAL_OR_KEYWORD]
2737

2838

2939
def get_parametrize_markers_args(node):
@@ -36,11 +46,19 @@ def get_parametrize_markers_args(node):
3646

3747

3848
def get_caller_module_locals(depth=2):
39-
frame_info = inspect.stack()[depth]
40-
frame = frame_info[0] # frame_info.frame
41-
return frame.f_locals
49+
"""Get the caller module locals dictionary.
50+
51+
We use sys._getframe instead of inspect.stack(0) because the latter is way slower, since it iterates over
52+
all the frames in the stack.
53+
"""
54+
return _getframe(depth).f_locals
4255

4356

4457
def get_caller_module_path(depth=2):
45-
frame_info = inspect.stack()[depth]
46-
return frame_info[1] # frame_info.filename
58+
"""Get the caller module path.
59+
60+
We use sys._getframe instead of inspect.stack(0) because the latter is way slower, since it iterates over
61+
all the frames in the stack.
62+
"""
63+
frame = _getframe(depth)
64+
return getframeinfo(frame, context=0).filename

0 commit comments

Comments
 (0)