-
Notifications
You must be signed in to change notification settings - Fork 77
/
setuptools_behave.py
136 lines (121 loc) · 5.04 KB
/
setuptools_behave.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
130
131
132
133
134
135
136
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Setuptools command for behave.
.. code-block:: console
python setup.py behave_test
.. seealso::
* https://pypi.org/project/behave
* https://github.com/behave/behave
"""
from setuptools import Command
from distutils import dir_util
from fnmatch import fnmatch
import os.path
import sys
import shlex
import subprocess
# =============================================================================
# SPECIAL SECTION: behave.example
# =============================================================================
# USE_PROJECT_SITECUSTOMIZE = True
# HERE = os.path.dirname(__file__)
# PROJECT_SITECUSTOMIZE = os.path.join(HERE, "bin", "project_sizecustomize.py")
# if USE_PROJECT_SITECUSTOMIZE and os.path.exists(PROJECT_SITECUSTOMIZE):
# sys.path.insert(0, os.path.dirname(PROJECT_SITECUSTOMIZE))
# import project_sitecustomize
# =============================================================================
# CLASS: behave_test
# =============================================================================
class behave_test(Command):
"""
Simple test runner that runs 'behave' via a "setup.py" file.
This ensures that all requirements are provided before the tests are run.
"""
command_name = "behave_test"
description = "Run feature tests with behave"
default_format = "progress"
default_args = "features"
local_egg_dir = "eggs"
command_consumes_arguments = False
user_options = [
("format=", "f", "Use formatter (default: %s)" % default_format),
("tags=", "t", "Use tags to select/exclude features/scenarios"),
("dry-run", "d", "Use dry-run mode"),
("args=", None,
"Features to run (default: %s)" % default_args),
]
boolean_options = [ "dry-run" ]
def initialize_options(self):
self.format = self.default_format
self.tags = None
self.dry_run = None
self.args = self.default_args
def finalize_options(self):
self.ensure_string("format", self.default_format)
self.ensure_string_list_with_comma_words("tags")
self.ensure_string_list("args")
def ensure_string_list_with_comma_words(self, option):
"""Ensures that a string with whitespace separated words
is converted into list of strings.
Note that commas are allowed in words
(compared :meth:`ensure_string_list()`).
"""
value = getattr(self, option, None)
if not value:
return
parts = shlex.split(value)
setattr(self, option, parts)
def _ensure_required_packages_are_installed(self, install_dir="."):
# -- NOTE: Packages are downloaded and provided as local eggs.
self.announce("ensure_required_packages_are_installed")
initial_dir = os.getcwd()
try:
dir_util.mkpath(install_dir)
os.chdir(self.local_egg_dir)
if self.distribution.install_requires:
self.distribution.fetch_build_eggs(self.distribution.install_requires)
if self.distribution.tests_require:
self.distribution.fetch_build_eggs(self.distribution.tests_require)
finally:
os.chdir(initial_dir)
def _select_paths(self, path=".", pattern="*"):
selected = [ os.path.join(path, f)
for f in os.listdir(path) if fnmatch(f, pattern)]
return selected
def _setup_env_with_local_python_path(self, egg_install_dir):
PYTHONPATH = os.environ.get("PYTHONPATH", "")
pathsep = os.pathsep
PPATH=[x for x in PYTHONPATH.split(pathsep) if x]
PPATH.insert(0, os.getcwd())
local_eggs = self._select_paths(egg_install_dir, "*.egg")
if local_eggs:
PPATH[1:1] = [ os.path.abspath(p) for p in local_eggs]
os.environ["PYTHONPATH"] = pathsep.join(PPATH)
self.announce("Use PYTHONPATH=%s" % os.environ["PYTHONPATH"], level=3)
return PYTHONPATH
def run(self):
# -- UPDATE SEARCHPATH: Ensure that local dir and local eggs are used.
egg_install_dir = self.local_egg_dir
self._ensure_required_packages_are_installed(egg_install_dir)
OLD_PYTHONPATH = self._setup_env_with_local_python_path(egg_install_dir)
for path in self.args:
returncode = self.behave(path)
if returncode:
self.announce("FAILED", level=4)
raise SystemExit(returncode)
# -- FINALLY: Restore
os.environ["PYTHONPATH"] = OLD_PYTHONPATH
return returncode
def behave(self, path):
behave = os.path.join("bin", "behave")
if not os.path.exists(behave):
behave = "behave"
cmd_options = ""
if self.tags:
cmd_options = "--tags=" + " --tags=".join(self.tags)
if self.dry_run:
cmd_options += " --dry-run"
cmd_options += " --format=%s %s" % (self.format, path)
self.announce("CMDLINE: %s %s" % (behave, cmd_options), level=3)
return subprocess.call([sys.executable, behave] + shlex.split(cmd_options))