@@ -39,38 +39,12 @@ PREVIEW_PYTHON_VERSION = "3.15"
3939
4040CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute()
4141
42- if (CURRENT_DIRECTORY / "testing").exists():
43- LOWER_BOUND_CONSTRAINTS_FILE = (
44- CURRENT_DIRECTORY / "testing" / f"constraints-{ALL_PYTHON[0]}.txt"
45- )
46- else:
47- LOWER_BOUND_CONSTRAINTS_FILE = CURRENT_DIRECTORY / "constraints.txt"
42+ LOWER_BOUND_REQUIREMENTS_FILE = (
43+ CURRENT_DIRECTORY / "testing" / f"requirements-{ALL_PYTHON[0]}.txt"
44+ )
4845PACKAGE_NAME = "{{ api.naming.warehouse_package_name }}"
4946
50- UNIT_TEST_STANDARD_DEPENDENCIES = [
51- "mock",
52- "asyncmock",
53- "pytest",
54- "pytest-cov",
55- "pytest-asyncio",
56- ]
57- UNIT_TEST_EXTERNAL_DEPENDENCIES: List[str] = []
58- UNIT_TEST_LOCAL_DEPENDENCIES: List[str] = []
59- UNIT_TEST_DEPENDENCIES: List[str] = []
60- UNIT_TEST_EXTRAS: List[str] = []
61- UNIT_TEST_EXTRAS_BY_PYTHON: Dict[str, List[str]] = {}
62-
6347SYSTEM_TEST_PYTHON_VERSIONS: List[str] = ALL_PYTHON
64- SYSTEM_TEST_STANDARD_DEPENDENCIES = [
65- "mock",
66- "pytest",
67- "google-cloud-testutils",
68- ]
69- SYSTEM_TEST_EXTERNAL_DEPENDENCIES: List[str] = []
70- SYSTEM_TEST_LOCAL_DEPENDENCIES: List[str] = []
71- SYSTEM_TEST_DEPENDENCIES: List[str] = []
72- SYSTEM_TEST_EXTRAS: List[str] = []
73- SYSTEM_TEST_EXTRAS_BY_PYTHON: Dict[str, List[str]] = {}
7448
7549nox.options.sessions = [
7650 "unit",
@@ -112,33 +86,48 @@ def mypy(session):
11286
11387@nox.session
11488def update_lower_bounds(session):
115- " " " Update lower bounds in constraints .txt to match setup.py " " "
89+ " " " Update lower bounds in requirements .txt to match setup.py " " "
11690 session.install(" google-cloud-testutils " )
11791 session.install(" . " )
11892
93+ requirements_in = CURRENT_DIRECTORY / " testing " / f" requirements-{ALL_PYTHON[0]}.in "
94+
11995 session.run(
12096 " lower-bound-checker " ,
12197 " update " ,
12298 " --package-name " ,
12399 PACKAGE_NAME,
124100 " --constraints-file " ,
125- str(LOWER_BOUND_CONSTRAINTS_FILE),
101+ str(requirements_in),
102+ )
103+
104+ session.install(" pip-tools " )
105+ session.run(
106+ " pip-compile " ,
107+ " --allow-unsafe " ,
108+ " --generate-hashes " ,
109+ " --no-strip-extras " ,
110+ " --output-file " ,
111+ str(LOWER_BOUND_REQUIREMENTS_FILE),
112+ str(requirements_in),
126113 )
127114
128115
129116@nox.session
130117def check_lower_bounds(session):
131- " " " Check lower bounds in setup.py are reflected in constraints file " " "
118+ " " " Check lower bounds in setup.py are reflected in requirements file " " "
132119 session.install(" google-cloud-testutils " )
133120 session.install(" . " )
134121
122+ requirements_in = CURRENT_DIRECTORY / " testing " / f" requirements-{ALL_PYTHON[0]}.in "
123+
135124 session.run(
136125 " lower-bound-checker " ,
137126 " check " ,
138127 " --package-name " ,
139128 PACKAGE_NAME,
140129 " --constraints-file " ,
141- str(LOWER_BOUND_CONSTRAINTS_FILE ),
130+ str(requirements_in ),
142131 )
143132
144133
@@ -219,32 +208,17 @@ def lint_setup_py(session):
219208 session.run( " python" , " setup.py" , " check" , " --restructuredtext" , " --strict" )
220209
221210
222- def install_unittest_dependencies(session, *constraints):
223- standard_deps = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_DEPENDENCIES
224- session.install(*standard_deps, *constraints)
225-
226- if UNIT_TEST_EXTERNAL_DEPENDENCIES:
227- warnings.warn(
228- " 'unit_test_external_dependencies' is deprecated. Instead, please "
229- " use 'unit_test_dependencies' or 'unit_test_local_dependencies'." ,
230- DeprecationWarning,
211+ def install_unittest_dependencies(session, prerelease =False):
212+ if prerelease:
213+ requirements_path = str(
214+ CURRENT_DIRECTORY / " testing" / " requirements-prerelease.txt"
231215 )
232- session.install(*UNIT_TEST_EXTERNAL_DEPENDENCIES, *constraints)
233-
234- if UNIT_TEST_LOCAL_DEPENDENCIES:
235- session.install(*UNIT_TEST_LOCAL_DEPENDENCIES, *constraints)
236-
237- if UNIT_TEST_EXTRAS_BY_PYTHON:
238- extras = UNIT_TEST_EXTRAS_BY_PYTHON.get(session.python, [])
239- elif UNIT_TEST_EXTRAS:
240- extras = UNIT_TEST_EXTRAS
241- else:
242- extras = []
243-
244- if extras:
245- session.install( " -e" , f " .[{','.join(extras)}]" , *constraints)
246216 else:
247- session.install( " -e" , " ." , *constraints)
217+ requirements_path = str(
218+ CURRENT_DIRECTORY / " testing" / f " requirements-{session.python}.txt"
219+ )
220+ session.install( " -r" , requirements_path)
221+ session.install( " -e" , " ." , " --no-deps" )
248222
249223
250224@nox.session(python =ALL_PYTHON)
@@ -255,10 +229,7 @@ def install_unittest_dependencies(session, *constraints):
255229def unit(session, protobuf_implementation):
256230 # Install all test dependencies, then install this package in-place.
257231
258- constraints_path = str(
259- CURRENT_DIRECTORY / " testing" / f " constraints-{session.python}.txt"
260- )
261- install_unittest_dependencies(session, " -c" , constraints_path)
232+ install_unittest_dependencies(session)
262233
263234 # Run py.test against the unit tests.
264235 session.run(
@@ -284,42 +255,11 @@ def unit(session, protobuf_implementation):
284255{# TODO(https: //github.com /googleapis /gapic-generator-python /issues /2201) Add a `unit_rest_async` nox session to run tests with [async_rest] extra installed. #}
285256
286257
287- def install_systemtest_dependencies(session, *constraints):
288- {# Note that grpcio <=1.62.2 works on Python 3.11 but fails on 3.12+ because it requires pkg_resources for its source build. #}
289- if session.python >= "3.12":
290- session.install("--pre", "grpcio>=1.75.1")
291- else:
292- session.install("--pre", "grpcio<=1.62.2")
293-
294- session.install(*SYSTEM_TEST_STANDARD_DEPENDENCIES, *constraints)
295-
296- if SYSTEM_TEST_EXTERNAL_DEPENDENCIES:
297- session.install(*SYSTEM_TEST_EXTERNAL_DEPENDENCIES, *constraints)
298-
299- if SYSTEM_TEST_LOCAL_DEPENDENCIES:
300- session.install("-e", *SYSTEM_TEST_LOCAL_DEPENDENCIES, *constraints)
301-
302- if SYSTEM_TEST_DEPENDENCIES:
303- session.install("-e", *SYSTEM_TEST_DEPENDENCIES, *constraints)
304-
305- if SYSTEM_TEST_EXTRAS_BY_PYTHON:
306- extras = SYSTEM_TEST_EXTRAS_BY_PYTHON.get(session.python, [])
307- elif SYSTEM_TEST_EXTRAS:
308- extras = SYSTEM_TEST_EXTRAS
309- else:
310- extras = []
311-
312- if extras:
313- session.install("-e", f".[{','.join(extras)}]", *constraints)
314- else:
315- session.install("-e", ".", *constraints)
316-
317-
318258@nox.session(python =SYSTEM_TEST_PYTHON_VERSIONS)
319259def system(session):
320260 " " " Run the system test suite." " "
321- constraints_path = str(
322- CURRENT_DIRECTORY / "testing" / f"constraints -{session.python}.txt"
261+ requirements_path = str(
262+ CURRENT_DIRECTORY / " testing" / f " requirements -{session.python}.txt"
323263 )
324264 system_test_path = os.path.join( " tests" , " system.py" )
325265 system_test_folder_path = os.path.join( " tests" , " system" )
@@ -337,7 +277,7 @@ def system(session):
337277 if not system_test_exists and not system_test_folder_exists:
338278 session.skip( " System tests were not found" )
339279
340- install_systemtest_dependencies(session, "-c ", constraints_path )
280+ install_systemtest_dependencies(session, " -r " , requirements_path )
341281
342282 # Run py.test against the system tests.
343283 if system_test_exists:
@@ -463,32 +403,7 @@ def prerelease_deps(session, protobuf_implementation):
463403 `pip install --pre <package>`.
464404 " " "
465405
466- # Install all dependencies
467- session.install("-e", ".")
468-
469- # Install dependencies for the unit test environment
470- unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES
471- session.install(*unit_deps_all)
472-
473- # Because we test minimum dependency versions on the minimum Python
474- # version, the first version we test with in the unit tests sessions has a
475- # constraints file containing all dependencies and extras.
476- with open(
477- CURRENT_DIRECTORY / "testing" / f"constraints-{ALL_PYTHON[0]}.txt",
478- encoding="utf-8",
479- ) as constraints_file:
480- constraints_text = constraints_file.read()
481-
482- # Ignore leading whitespace and comment lines.
483- constraints_deps = [
484- match.group(1)
485- for match in re.finditer(
486- r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE
487- )
488- ]
489-
490- # Install dependencies specified in `testing/constraints-X.txt`.
491- session.install(*constraints_deps)
406+ install_unittest_dependencies(session, prerelease =True)
492407
493408 # Note: If a dependency is added to the `prerel_deps` list,
494409 # the `core_dependencies_from_source` list in the `core_deps_from_source`
@@ -515,22 +430,6 @@ def prerelease_deps(session, protobuf_implementation):
515430 for dep in prerel_deps
516431 }
517432
518- # Dynamically sort local packages vs PyPI dependencies
519- local_paths = []
520- pypi_deps = []
521-
522- for dep, pkg_name in parsed_deps.items():
523- if (deps_dir / pkg_name).exists():
524- local_paths.append(str(deps_dir / pkg_name))
525- else:
526- pypi_deps.append(dep)
527-
528- # Batch pip installations to avoid sequential overhead
529- if local_paths:
530- session.install(*local_paths, "--no-deps", "--ignore-installed")
531- if pypi_deps:
532- session.install(*pypi_deps, "--pre", "--no-deps", "--ignore-installed")
533-
534433 # TODO(https://github.com/grpc/grpc/issues/38965): Add `grpcio-status``
535434 # to the dictionary below once this bug is fixed.
536435 # TODO(https://github.com/googleapis/google-cloud-python/issues/13643): Add
@@ -565,6 +464,14 @@ def prerelease_deps(session, protobuf_implementation):
565464 )
566465
567466
467+ @nox.session(python=ALL_PYTHON[0])
468+ def security_check_minimum_version(session):
469+ # Do not pin `pip-audit` since we need the latest version to be aware of new vulnerabilities
470+ session.install("pip-audit")
471+ session.run("pip-audit", "--version")
472+ session.run("pip-audit", "-r", CURRENT_DIRECTORY / "testing" / f"requirements-{ALL_PYTHON[0]}.txt")
473+
474+
568475@nox.session(python=PREVIEW_PYTHON_VERSION)
569476@nox.parametrize(
570477 "protobuf_implementation",
@@ -575,32 +482,7 @@ def core_deps_from_source(session, protobuf_implementation):
575482 rather than pulling the dependencies from PyPI.
576483 """
577484
578- # Install all dependencies
579- session.install("-e", ".")
580-
581- # Install dependencies for the unit test environment
582- unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES
583- session.install(*unit_deps_all)
584-
585- # Because we test minimum dependency versions on the minimum Python
586- # version, the first version we test with in the unit tests sessions has a
587- # constraints file containing all dependencies and extras.
588- with open(
589- CURRENT_DIRECTORY / "testing" / f"constraints-{ALL_PYTHON[0]}.txt",
590- encoding="utf-8",
591- ) as constraints_file:
592- constraints_text = constraints_file.read()
593-
594- # Ignore leading whitespace and comment lines.
595- constraints_deps = [
596- match.group(1)
597- for match in re.finditer(
598- r"^\s*(\S+)(?===\S+)", constraints_text, flags=re.MULTILINE
599- )
600- ]
601-
602- # Install dependencies specified in `testing/constraints-X.txt`.
603- session.install(*constraints_deps)
485+ install_unittest_dependencies(session, prerelease=True)
604486
605487 # TODO(https://github.com/googleapis/gapic-generator-python/issues/2358): `grpcio` and
606488 # `grpcio-status` should be added to the list below so that they are installed from source,
0 commit comments