From 993985f0fc4b37152e588f0549bcbdaf34666023 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Fri, 1 Apr 2022 11:40:13 -0400 Subject: [PATCH] chore(python): refactor unit / system test dependency install (#1294) * chore(python): refactor unit / system test dependency install Closes #1185. * chore: use editable installs for local deps * chore: don't install deps using '-e' * chore: deprecate 'unit_test_external_dependencies' * fix: install standard + main unit test deps together FBO pip resolver. Co-authored-by: Anthonios Partheniou --- .../templates/python_library/noxfile.py.j2 | 153 ++++++++++++------ tests/test_python_library.py | 80 ++++++--- 2 files changed, 169 insertions(+), 64 deletions(-) diff --git a/synthtool/gcp/templates/python_library/noxfile.py.j2 b/synthtool/gcp/templates/python_library/noxfile.py.j2 index 2e5f31513..51cf9b61d 100644 --- a/synthtool/gcp/templates/python_library/noxfile.py.j2 +++ b/synthtool/gcp/templates/python_library/noxfile.py.j2 @@ -20,16 +20,62 @@ from __future__ import absolute_import import os import pathlib import shutil +import warnings import nox - BLACK_VERSION = "black==22.3.0" BLACK_PATHS = ["docs", "google", "tests", "noxfile.py", "setup.py"] DEFAULT_PYTHON_VERSION="{{ default_python_version }}" -SYSTEM_TEST_PYTHON_VERSIONS=[{% for v in system_test_python_versions %}"{{v}}"{% if not loop.last %},{% endif %}{% endfor %}] -UNIT_TEST_PYTHON_VERSIONS=[{% for v in unit_test_python_versions %}"{{v}}"{% if not loop.last %},{% endif %}{% endfor %}] + +UNIT_TEST_PYTHON_VERSIONS=[{% for v in unit_test_python_versions %}"{{v}}"{% if not loop.last %}, {% endif %}{% endfor %}] +UNIT_TEST_STANDARD_DEPENDENCIES = [ + "mock", + "asyncmock", + "pytest", + "pytest-cov", + "pytest-asyncio", +] +UNIT_TEST_EXTERNAL_DEPENDENCIES = [{% for v in unit_test_external_dependencies %} + "{{v}}",{% endfor %} +] +UNIT_TEST_LOCAL_DEPENDENCIES = [{% for v in unit_test_local_dependencies %} + "{{v}}",{% endfor %} +] +UNIT_TEST_DEPENDENCIES = [{% for v in unit_test_dependencies %} + "{{v}}",{% endfor %} +] +UNIT_TEST_EXTRAS = [{% for v in unit_test_extras %} + "{{v}}",{% endfor %} +] +UNIT_TEST_EXTRAS_BY_PYTHON = {{ '{' }}{% if unit_test_extras_by_python %}{% for python_version, extras in unit_test_extras_by_python.items() %} + "{{python_version}}": [{% for v in extras %} + "{{v}}",{% endfor %} + ],{% endfor %}{% endif %} +} + +SYSTEM_TEST_PYTHON_VERSIONS=[{% for v in system_test_python_versions %}"{{v}}"{% if not loop.last %}, {% endif %}{% endfor %}] +SYSTEM_TEST_STANDARD_DEPENDENCIES = [ + "mock", "pytest", "google-cloud-testutils", +] +SYSTEM_TEST_EXTERNAL_DEPENDENCIES = [{% for v in system_test_external_dependencies %} + "{{v}}",{% endfor %} +] +SYSTEM_TEST_LOCAL_DEPENDENCIES = [{% for v in system_test_local_dependencies %} + "{{v}}",{% endfor %} +] +SYSTEM_TEST_DEPENDENCIES = [{% for v in system_test_dependencies %} + "{{v}}",{% endfor %} +] +SYSTEM_TEST_EXTRAS = [{% for v in system_test_extras %} + "{{v}}",{% endfor %} +] +SYSTEM_TEST_EXTRAS_BY_PYTHON = {{ '{' }}{% if system_test_extras_by_python %}{% for python_version, extras in system_test_extras_by_python.items() %} + "{{python_version}}": [{% for v in extras %} + "{{v}}",{% endfor %} + ],{% endfor %}{% endif %} +} CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute() @@ -81,31 +127,41 @@ def lint_setup_py(session): session.run("python", "setup.py", "check", "--restructuredtext", "--strict") +def install_unittest_dependencies(session, *constraints): + standard_deps = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_DEPENDENCIES + session.install(*standard_deps, *constraints) + + if UNIT_TEST_EXTERNAL_DEPENDENCIES: + warnings.warn( + "'unit_test_external_dependencies' is deprecated. Instead, please " + "use 'unit_test_dependencies' or 'unit_test_local_dependencies'.", + DeprecationWarning, + ) + session.install(*UNIT_TEST_EXTERNAL_DEPENDENCIES, *constraints) + + if UNIT_TEST_LOCAL_DEPENDENCIES: + session.install(*UNIT_TEST_LOCAL_DEPENDENCIES, *constraints) + + if UNIT_TEST_EXTRAS_BY_PYTHON: + extras = UNIT_TEST_EXTRAS_BY_PYTHON.get(session.python, []) + elif UNIT_TEST_EXTRAS: + extras = UNIT_TEST_EXTRAS + else: + extras = [] + + if extras: + session.install("-e", f".[{','.join(extras)}]", *constraints) + else: + session.install("-e", ".", *constraints) + + def default(session): # Install all test dependencies, then install this package in-place. constraints_path = str( CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" ) - session.install("mock", "asyncmock", "pytest", "pytest-cov", "pytest-asyncio", "-c", constraints_path) - {% for d in unit_test_external_dependencies -%} - session.install("{{d}}", "-c", constraints_path) - {% endfor %} - {% for dependency in unit_test_local_dependencies %}session.install("-e", "{{dependency}}", "-c", constraints_path) - {% endfor %} - {% for dependency in unit_test_dependencies %}session.install("-e", "{{dependency}}", "-c", constraints_path){% endfor %} - {%- if unit_test_extras_by_python %} - {% for extras_python in unit_test_extras_by_python %} - {%- if not loop.first %}el{% endif %}if session.python == "{{extras_python}}": - extras = "[{{",".join(unit_test_extras_by_python[extras_python])}}]" - {% endfor %}else: - extras = "{%- if unit_test_extras %}[{{",".join(unit_test_extras)}}]{% endif %}" - session.install("-e", f".{extras}", "-c", constraints_path) - {% elif unit_test_extras %} - session.install("-e", ".[{{",".join(unit_test_extras)}}]", "-c", constraints_path) - {% else %} - session.install("-e", ".", "-c", constraints_path) - {% endif %} + install_unittest_dependencies(session, "-c", constraints_path) # Run py.test against the unit tests. session.run( @@ -128,6 +184,35 @@ def unit(session): default(session) +def install_systemtest_dependencies(session, *constraints): + + # Use pre-release gRPC for system tests. + session.install("--pre", "grpcio") + + session.install(*SYSTEM_TEST_STANDARD_DEPENDENCIES, *constraints) + + if SYSTEM_TEST_EXTERNAL_DEPENDENCIES: + session.install(*SYSTEM_TEST_EXTERNAL_DEPENDENCIES, *constraints) + + if SYSTEM_TEST_LOCAL_DEPENDENCIES: + session.install("-e", *SYSTEM_TEST_LOCAL_DEPENDENCIES, *constraints) + + if SYSTEM_TEST_DEPENDENCIES: + session.install("-e", *SYSTEM_TEST_DEPENDENCIES, *constraints) + + if SYSTEM_TEST_EXTRAS_BY_PYTHON: + extras = SYSTEM_TEST_EXTRAS_BY_PYTHON.get(session.python, []) + elif SYSTEM_TEST_EXTRAS: + extras = SYSTEM_TEST_EXTRAS + else: + extras = [] + + if extras: + session.install("-e", f".[{','.join(extras)}]", *constraints) + else: + session.install("-e", ".", *constraints) + + @nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) def system(session): """Run the system test suite.""" @@ -150,29 +235,7 @@ def system(session): if not system_test_exists and not system_test_folder_exists: session.skip("System tests were not found") - # Use pre-release gRPC for system tests. - session.install("--pre", "grpcio") - - # Install all test dependencies, then install this package into the - # virtualenv's dist-packages. - session.install("mock", "pytest", "google-cloud-testutils"{% for d in system_test_external_dependencies %}, "{{d}}"{% endfor %}, "-c", constraints_path) - - {%- if system_test_local_dependencies %} - {% for dependency in system_test_local_dependencies %}session.install("-e", "{{dependency}}", "-c", constraints_path) - {% endfor %} - {%- endif %} - {%- if system_test_extras_by_python %} - {% for extras_python in system_test_extras_by_python %} - {%- if not loop.first %}el{% endif %}if session.python == "{{extras_python}}": - extras = "[{{",".join(system_test_extras_by_python[extras_python])}}]" - {% endfor %}else: - extras = "{%- if system_test_extras %}[{{",".join(system_test_extras)}}]{% endif %}" - session.install("-e", f".{extras}", "-c", constraints_path) - {% elif system_test_extras %} - session.install("-e", ".[{{",".join(system_test_extras)}}]", "-c", constraints_path) - {% else %} - session.install("-e", ".", "-c", constraints_path) - {% endif %} + install_systemtest_dependencies(session, "-c", constraints_path) # Run py.test against the system tests. if system_test_exists: diff --git a/tests/test_python_library.py b/tests/test_python_library.py index a0a3ab160..e91a5ceaf 100644 --- a/tests/test_python_library.py +++ b/tests/test_python_library.py @@ -30,43 +30,67 @@ @pytest.mark.parametrize( ["template_kwargs", "expected_text"], [ - ({}, ["import nox", 'session.install("-e", ".", "-c", constraints_path)']), + ({}, ["import nox", 'session.install("-e", ".", *constraints)']), ( {"unit_test_local_dependencies": ["../testutils", "../unitutils"]}, [ - 'session.install("-e", "../testutils", "-c", constraints_path)', - 'session.install("-e", "../unitutils", "-c", constraints_path)', + """\ +UNIT_TEST_LOCAL_DEPENDENCIES = [ + "../testutils", + "../unitutils", +]""", ], ), ( {"system_test_local_dependencies": ["../testutils", "../sysutils"]}, [ - 'session.install("-e", "../testutils", "-c", constraints_path)', - 'session.install("-e", "../sysutils", "-c", constraints_path)', + """\ +SYSTEM_TEST_LOCAL_DEPENDENCIES = [ + "../testutils", + "../sysutils", +]""", ], ), ( {"unit_test_extras": ["abc", "def"]}, - ['session.install("-e", ".[abc,def]", "-c", constraints_path)'], + [ + """\ +UNIT_TEST_EXTRAS = [ + "abc", + "def", +]""", + ], ), ( {"system_test_extras": ["abc", "def"]}, - ['session.install("-e", ".[abc,def]", "-c", constraints_path)'], + """\ +SYSTEM_TEST_EXTRAS = [ + "abc", + "def", +]""", ), ( {"unit_test_extras_by_python": {"3.8": ["abc", "def"]}}, [ - 'if session.python == "3.8":\n extras = "[abc,def]"', - 'else:\n extras = ""', - 'session.install("-e", f".{extras}", "-c", constraints_path)', + """\ +UNIT_TEST_EXTRAS_BY_PYTHON = { + "3.8": [ + "abc", + "def", + ], +}""", ], ), ( {"system_test_extras_by_python": {"3.8": ["abc", "def"]}}, [ - 'if session.python == "3.8":\n extras = "[abc,def]"', - 'else:\n extras = ""', - 'session.install("-e", f".{extras}", "-c", constraints_path)', + """\ +SYSTEM_TEST_EXTRAS_BY_PYTHON = { + "3.8": [ + "abc", + "def", + ], +}""", ], ), ( @@ -75,9 +99,18 @@ "unit_test_extras_by_python": {"3.8": ["abc", "def"]}, }, [ - 'if session.python == "3.8":\n extras = "[abc,def]"', - 'else:\n extras = "[tuv,wxyz]"', - 'session.install("-e", f".{extras}", "-c", constraints_path)', + """\ +UNIT_TEST_EXTRAS = [ + "tuv", + "wxyz", +]""", + """\ +UNIT_TEST_EXTRAS_BY_PYTHON = { + "3.8": [ + "abc", + "def", + ], +}""", ], ), ( @@ -86,9 +119,18 @@ "system_test_extras_by_python": {"3.8": ["abc", "def"]}, }, [ - 'if session.python == "3.8":\n extras = "[abc,def]"', - 'else:\n extras = "[tuv,wxyz]"', - 'session.install("-e", f".{extras}", "-c", constraints_path)', + """\ +SYSTEM_TEST_EXTRAS = [ + "tuv", + "wxyz", +]""", + """\ +SYSTEM_TEST_EXTRAS_BY_PYTHON = { + "3.8": [ + "abc", + "def", + ], +}""", ], ), ],