Skip to content

Commit 3b5b206

Browse files
Make running individual Python tests less painful
Before this change, running Python tests individually required building a tox environment via the run_tests script and then specifying long environment variables to filter out just the test we wanted to run (and then we wouldn't be able to get the output on interrupt, nor would we have an easy way of determining the PID of the process for debugger attachment). Now invoking the build_python.sh script creates a workable python virtual environment that includes all necessary libraries and tests (s.t. running a single test is now possible by just knowing the module name). This does not change existing supported means of running tests (e.g. through run_tests.py). An additional way of running individual tests has been introduced. Following invocation of `./tools/run_tests/build_python.sh` (or run_tests.py), one may invoke ./$VENV/bin/python -m $TEST_MODULE_NAME and acquire a single running process that *is* the test process (rather than a parent of the process). $VENV is the virtual environment name specified to `build_python.sh` (defaults to `py27`) and $TEST_MODULE_NAME is what it says on the tin.
1 parent 1ff429d commit 3b5b206

File tree

6 files changed

+114
-51
lines changed

6 files changed

+114
-51
lines changed

PYTHON-MANIFEST.in

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
recursive-include src/python/grpcio/grpc *.c *.h *.py *.pyx *.pxd *.pxi *.python *.pem
22
recursive-exclude src/python/grpcio/grpc/_cython *.so *.pyd
3-
graft src/python/grpcio/tests
43
graft src/python/grpcio/grpcio.egg-info
54
graft src/core
65
graft src/boringssl

tools/run_tests/build_python.sh

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,70 @@ set -ex
3333
# change to grpc repo root
3434
cd $(dirname $0)/../..
3535

36-
TOX_PYTHON_ENV="$1"
37-
PY_VERSION="${TOX_PYTHON_ENV: -2}"
36+
PYTHON=${1:-python2.7}
37+
VENV=${2:-py27}
38+
VENV_RELATIVE_PYTHON=${3:-bin/python}
39+
TOOLCHAIN=${4:-unix}
3840

3941
ROOT=`pwd`
4042
export CFLAGS="-I$ROOT/include -std=gnu99 -fno-wrapv"
4143
export GRPC_PYTHON_BUILD_WITH_CYTHON=1
4244

43-
if [ "$CONFIG" = "gcov" ]
44-
then
45+
# If ccache is available, use it... unless we're on Mac, then all hell breaks
46+
# loose because Python does hacky things to support other hacky things done to
47+
# hacky things on Mac OS X
48+
PLATFORM=`uname -s`
49+
if [ "${PLATFORM/Darwin}" = "$PLATFORM" ]; then
50+
# We're not on Darwin (Mac OS X)
51+
if [ -x "$(command -v ccache)" ]; then
52+
if [ -x "$(command -v gcc)" ]; then
53+
export CC='ccache gcc'
54+
elif [ -x "$(command -v clang)" ]; then
55+
export CC='ccache clang'
56+
fi
57+
fi
58+
fi
59+
60+
# Find `realpath`
61+
if [ -x "$(command -v realpath)" ]; then
62+
export REALPATH=realpath
63+
elif [ -x "$(command -v grealpath)" ]; then
64+
export REALPATH=grealpath
65+
else
66+
echo 'Couldn'"'"'t find `realpath` or `grealpath`'
67+
exit 1
68+
fi
69+
70+
if [ "$CONFIG" = "gcov" ]; then
4571
export GRPC_PYTHON_ENABLE_CYTHON_TRACING=1
4672
fi
4773

48-
tox -e ${TOX_PYTHON_ENV} --notest
74+
($PYTHON -m virtualenv $VENV || true)
75+
VENV_PYTHON=`$REALPATH -s "$VENV/$VENV_RELATIVE_PYTHON"`
76+
77+
# pip-installs the directory specified. Used because on MSYS the vanilla Windows
78+
# Python gets confused when parsing paths.
79+
pip_install_dir() {
80+
PWD=`pwd`
81+
cd $1
82+
($VENV_PYTHON setup.py build_ext -c $TOOLCHAIN || true)
83+
# install the dependencies
84+
$VENV_PYTHON -m pip install --upgrade .
85+
# ensure that we've reinstalled the test packages
86+
$VENV_PYTHON -m pip install --upgrade --force-reinstall --no-deps .
87+
cd $PWD
88+
}
4989

50-
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/pip install cython
51-
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/pip install $ROOT
52-
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/python $ROOT/tools/distrib/python/make_grpcio_tools.py
53-
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/pip install $ROOT/tools/distrib/python/grpcio_tools
54-
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/python $ROOT/src/python/grpcio_health_checking/setup.py preprocess
55-
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/pip install $ROOT/src/python/grpcio_health_checking
56-
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/python $ROOT/src/python/grpcio_tests/setup.py preprocess
57-
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/python $ROOT/src/python/grpcio_tests/setup.py build_proto_modules
90+
$VENV_PYTHON -m pip install --upgrade pip setuptools
91+
$VENV_PYTHON -m pip install cython
92+
pip_install_dir $ROOT
93+
$VENV_PYTHON $ROOT/tools/distrib/python/make_grpcio_tools.py
94+
pip_install_dir $ROOT/tools/distrib/python/grpcio_tools
95+
# TODO(atash) figure out namespace packages and grpcio-tools and auditwheel
96+
# etc...
97+
pip_install_dir $ROOT
98+
$VENV_PYTHON $ROOT/src/python/grpcio_health_checking/setup.py preprocess
99+
pip_install_dir $ROOT/src/python/grpcio_health_checking
100+
$VENV_PYTHON $ROOT/src/python/grpcio_tests/setup.py preprocess
101+
$VENV_PYTHON $ROOT/src/python/grpcio_tests/setup.py build_proto_modules
102+
pip_install_dir $ROOT/src/python/grpcio_tests

tools/run_tests/performance/run_worker_python.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,4 @@ set -ex
3232

3333
cd $(dirname $0)/../../..
3434

35-
PYTHONPATH=src/python/grpcio_tests:src/python/grpcio:src/python/gens .tox/py27/bin/python src/python/grpcio_tests/tests/qps/qps_worker.py $@
35+
PYTHONPATH=src/python/grpcio_tests:src/python/grpcio:src/python/gens py27/bin/python src/python/grpcio_tests/tests/qps/qps_worker.py $@

tools/run_tests/run_interop_tests.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -304,17 +304,23 @@ def __init__(self):
304304

305305
def client_cmd(self, args):
306306
return [
307-
'tox -einterop_client --',
308-
' '.join(args)
307+
'py27/bin/python',
308+
'src/python/grpcio_tests/setup.py',
309+
'run_interop',
310+
'--client',
311+
'--args="{}"'.format(' '.join(args))
309312
]
310313

311314
def cloud_to_prod_env(self):
312315
return {}
313316

314317
def server_cmd(self, args):
315318
return [
316-
'tox -einterop_server --',
317-
' '.join(args) + ' --use_tls=true'
319+
'py27/bin/python',
320+
'src/python/grpcio_tests/setup.py',
321+
'run_interop',
322+
'--server',
323+
'--args="{}"'.format(' '.join(args) + ' --use_tls=true')
318324
]
319325

320326
def global_env(self):

tools/run_tests/run_python.sh

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,11 @@ set -ex
3333
# change to grpc repo root
3434
cd $(dirname $0)/../..
3535

36-
TOX_PYTHON_ENV="$1"
36+
PYTHON=`realpath -s "${1:-py27/bin/python}"`
3737

3838
ROOT=`pwd`
39-
export LD_LIBRARY_PATH=$ROOT/libs/$CONFIG
40-
export DYLD_LIBRARY_PATH=$ROOT/libs/$CONFIG
41-
export PATH=$ROOT/bins/$CONFIG:$ROOT/bins/$CONFIG/protobuf:$PATH
42-
export CFLAGS="-I$ROOT/include -std=c89"
43-
export LDFLAGS="-L$ROOT/libs/$CONFIG"
44-
export GRPC_PYTHON_BUILD_WITH_CYTHON=1
45-
export GRPC_PYTHON_USE_PRECOMPILED_BINARIES=0
4639

47-
if [ "$CONFIG" = "gcov" ]
48-
then
49-
export GRPC_PYTHON_ENABLE_CYTHON_TRACING=1
50-
tox -e ${TOX_PYTHON_ENV}
51-
else
52-
$ROOT/.tox/${TOX_PYTHON_ENV}/bin/python $ROOT/src/python/grpcio_tests/setup.py test_lite
53-
fi
40+
$PYTHON $ROOT/src/python/grpcio_tests/setup.py test_lite
5441

5542
mkdir -p $ROOT/reports
5643
rm -rf $ROOT/reports/python-coverage

tools/run_tests/run_tests.py

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@
3232

3333
import argparse
3434
import ast
35+
import collections
3536
import glob
3637
import itertools
3738
import json
3839
import multiprocessing
3940
import os
41+
import os.path
4042
import platform
4143
import random
4244
import re
@@ -372,12 +374,20 @@ def __str__(self):
372374
return 'php'
373375

374376

377+
class PythonConfig(collections.namedtuple('PythonConfig', [
378+
'python', 'venv', 'venv_relative_python', 'toolchain',])):
379+
380+
@property
381+
def venv_python(self):
382+
return os.path.abspath('{}/{}'.format(self.venv, self.venv_relative_python))
383+
384+
375385
class PythonLanguage(object):
376386

377387
def configure(self, config, args):
378388
self.config = config
379389
self.args = args
380-
self._tox_envs = self._get_tox_envs(self.args.compiler)
390+
self.pythons = self._get_pythons(self.args.compiler)
381391

382392
def test_specs(self):
383393
# load list of known test suites
@@ -386,33 +396,42 @@ def test_specs(self):
386396
environment = dict(_FORCE_ENVIRON_FOR_WRAPPERS)
387397
if self.config.build_config != 'gcov':
388398
return [self.config.job_spec(
389-
['tools/run_tests/run_python.sh', tox_env],
399+
['tools/run_tests/run_python.sh', config.venv_python],
400+
None,
390401
environ=dict(environment.items() +
391402
[('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
392-
shortname='%s.test.%s' % (tox_env, suite_name),
403+
shortname='%s.test.%s' % (config.venv, suite_name),
393404
timeout_seconds=5*60)
394405
for suite_name in tests_json
395-
for tox_env in self._tox_envs]
406+
for config in self.pythons]
396407
else:
397-
return [self.config.job_spec(['tools/run_tests/run_python.sh', tox_env],
398-
environ=environment,
399-
shortname='%s.test.coverage' % tox_env,
400-
timeout_seconds=15*60)
401-
for tox_env in self._tox_envs]
408+
return [self.config.job_spec(
409+
['tools/run_tests/run_python.sh', config.venv_python],
410+
None,
411+
environ=environment,
412+
shortname='%s.test.coverage' % config.venv,
413+
timeout_seconds=15*60)
414+
for config in self.pythons]
402415

403416

404417
def pre_build_steps(self):
405418
return []
406419

407420
def make_targets(self):
408-
return ['static_c', 'grpc_python_plugin', 'shared_c']
421+
return []
409422

410423
def make_options(self):
411424
return []
412425

413426
def build_steps(self):
414-
return [['tools/run_tests/build_python.sh', tox_env]
415-
for tox_env in self._tox_envs]
427+
return [
428+
[
429+
'tools/run_tests/build_python.sh',
430+
config.python, config.venv,
431+
config.venv_relative_python, config.toolchain
432+
]
433+
for config in self.pythons
434+
]
416435

417436
def post_tests_steps(self):
418437
return []
@@ -423,14 +442,21 @@ def makefile_name(self):
423442
def dockerfile_dir(self):
424443
return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
425444

426-
def _get_tox_envs(self, compiler):
427-
"""Returns name of tox environment based on selected compiler."""
445+
def _get_pythons(self, compiler):
446+
if os.name == 'nt':
447+
venv_relative_python = 'Scripts/python.exe'
448+
toolchain = 'mingw32'
449+
else:
450+
venv_relative_python = 'bin/python'
451+
toolchain = 'unix'
452+
python27_config = PythonConfig('python2.7', 'py27', venv_relative_python, toolchain)
453+
python34_config = PythonConfig('python3.4', 'py34', venv_relative_python, toolchain)
428454
if compiler == 'default':
429-
return ('py27', 'py34')
455+
return (python27_config, python34_config,)
430456
elif compiler == 'python2.7':
431-
return ('py27',)
457+
return (python27_config,)
432458
elif compiler == 'python3.4':
433-
return ('py34',)
459+
return (python34_config,)
434460
else:
435461
raise Exception('Compiler %s not supported.' % compiler)
436462

0 commit comments

Comments
 (0)