-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path__init__.py
129 lines (103 loc) · 4 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
from argparse import Namespace
import contextlib
import imp
import inspect
import re
import sys
import types
from behave.parser import Parser
from behave.step_registry import StepRegistry
from behave.step_registry import names as step_names
class SubContext(Namespace):
@contextlib.contextmanager
def user_mode(self):
"""To keep Match.run happy."""
yield
class SubSteps:
def __init__(self, language=None, variant=None):
self.parser = Parser(language=language, variant=variant)
self.registry = StepRegistry()
# Create decorators for the local registry
for step_type in step_names.split():
setattr(self, step_type, self.registry.make_decorator(step_type))
@staticmethod
def run_match(match, context):
args = []
kwargs = {}
for arg in match.arguments:
if arg.name is not None:
kwargs[arg.name] = arg.value
else:
args.append(arg.value)
return match.func(context, *args, **kwargs)
def run(self, text, context):
"""
Parse the given text and yield step functions.
"""
steps = self.parser.parse_steps(text)
for step in steps:
match = self.registry.find_match(step)
if match is None:
raise ValueError("substep not found '%s'" % step)
else:
subcontext = SubContext(
table=step.table,
text=step.text,
step_context=context)
yield self.run_match(match, context)
def define_steps(package_regex, step_module, translations, substeps=False):
class BehaveStepCollectionLoader:
def __init__(self, language, translation):
self.language = language
self.translation = translation
def load_module(self, fullname):
try:
return sys.modules[fullname]
except KeyError:
pass
module = imp.new_module(fullname)
module.__file__ = step_module.__file__
module.__doc__ = step_module.__doc__
module.__path__ = []
module.__loader__ = self
module.LANG = self.language
if substeps:
module.substeps = SubSteps(language=self.language)
step_decorator = module.substeps.step
else:
from behave import step as step_decorator
members = inspect.getmembers(step_module, inspect.isfunction)
for name, value in members:
if name.startswith('_'): # Private function
continue
# Copy the function adding custom globals
new_globals = value.__globals__.copy()
new_globals['__language__'] = self.language
function_copy = types.FunctionType(
value.__code__,
new_globals,
value.__name__,
value.__defaults__,
value.__closure__)
for text in reversed(self.translation[name]):
value = step_decorator(text)(function_copy)
setattr(module, name, value)
sys.modules.setdefault(fullname, module)
return module
class BehaveStepCollectionFinder:
module_pattern = re.compile(package_regex)
def find_module(self, fullname, path=None):
match = self.module_pattern.match(fullname)
if match:
request_lang = match.group("lang")
try:
translation = translations[request_lang]
except KeyError:
return None
else:
return BehaveStepCollectionLoader(request_lang,
translation)
else:
return None
# Append the step finder to sys.meta_path
sys.meta_path.append(BehaveStepCollectionFinder())