1818
1919from __future__ import absolute_import
2020
21+ from functools import wraps
2122import os
2223import pathlib
2324import re
2425import shutil
2526import subprocess
27+ import time
2628import warnings
2729
2830import nox
7678
7779CURRENT_DIRECTORY = pathlib .Path (__file__ ).parent .absolute ()
7880
81+
82+ def _calculate_duration (func ):
83+ """This decorator prints the execution time for the decorated function."""
84+
85+ @wraps (func )
86+ def wrapper (* args , ** kwargs ):
87+ start = time .monotonic ()
88+ result = func (* args , ** kwargs )
89+ end = time .monotonic ()
90+ total_seconds = round (end - start )
91+ hours = total_seconds // 3600 # Integer division to get hours
92+ remaining_seconds = total_seconds % 3600 # Modulo to find remaining seconds
93+ minutes = remaining_seconds // 60
94+ seconds = remaining_seconds % 60
95+ human_time = f"{ hours :} :{ minutes :0>2} :{ seconds :0>2} "
96+ print (f"Session ran in { total_seconds } seconds ({ human_time } )" )
97+ return result
98+
99+ return wrapper
100+
101+
79102# 'docfx' is excluded since it only needs to run in 'docs-presubmit'
80103nox .options .sessions = [
81104 "unit" ,
92115
93116
94117@nox .session (python = DEFAULT_PYTHON_VERSION )
118+ @_calculate_duration
95119def lint (session ):
96120 """Run linters.
97121
@@ -108,6 +132,7 @@ def lint(session):
108132
109133
110134@nox .session (python = DEFAULT_PYTHON_VERSION )
135+ @_calculate_duration
111136def blacken (session ):
112137 """Run black. Format code to uniform standard."""
113138 session .install (BLACK_VERSION )
@@ -118,6 +143,7 @@ def blacken(session):
118143
119144
120145@nox .session (python = DEFAULT_PYTHON_VERSION )
146+ @_calculate_duration
121147def format (session ):
122148 """
123149 Run isort to sort imports. Then run black
@@ -138,6 +164,7 @@ def format(session):
138164
139165
140166@nox .session (python = DEFAULT_PYTHON_VERSION )
167+ @_calculate_duration
141168def lint_setup_py (session ):
142169 """Verify that setup.py is valid (including RST check)."""
143170 session .install ("docutils" , "pygments" )
@@ -199,6 +226,7 @@ def default(session):
199226
200227
201228@nox .session (python = UNIT_TEST_PYTHON_VERSIONS )
229+ @_calculate_duration
202230def unit (session ):
203231 """Run the unit test suite."""
204232 default (session )
@@ -235,6 +263,7 @@ def install_systemtest_dependencies(session, *constraints):
235263
236264
237265@nox .session (python = SYSTEM_TEST_PYTHON_VERSIONS )
266+ @_calculate_duration
238267def system (session ):
239268 """Run the system test suite."""
240269 constraints_path = str (
@@ -281,6 +310,7 @@ def system(session):
281310
282311
283312@nox .session (python = DEFAULT_PYTHON_VERSION )
313+ @_calculate_duration
284314def prerelease (session ):
285315 session .install (
286316 "--extra-index-url" ,
@@ -334,7 +364,7 @@ def prerelease(session):
334364 constraints_text = constraints_file .read ()
335365
336366 # Ignore leading whitespace and comment lines.
337- deps = [
367+ constraints_deps = [
338368 match .group (1 )
339369 for match in re .finditer (
340370 r"^\s*(\S+)(?===\S+)" , constraints_text , flags = re .MULTILINE
@@ -343,7 +373,7 @@ def prerelease(session):
343373
344374 # We use --no-deps to ensure that pre-release versions aren't overwritten
345375 # by the version ranges in setup.py.
346- session .install (* deps )
376+ session .install (* constraints_deps )
347377 session .install ("--no-deps" , "-e" , ".[all]" )
348378
349379 # Print out prerelease package versions.
@@ -368,6 +398,7 @@ def prerelease(session):
368398
369399
370400@nox .session (python = DEFAULT_PYTHON_VERSION )
401+ @_calculate_duration
371402def cover (session ):
372403 """Run the final coverage report.
373404
@@ -390,6 +421,7 @@ def cover(session):
390421
391422
392423@nox .session (python = "3.9" )
424+ @_calculate_duration
393425def docs (session ):
394426 """Build the docs for this library."""
395427
@@ -425,6 +457,7 @@ def docs(session):
425457
426458
427459@nox .session (python = "3.10" )
460+ @_calculate_duration
428461def docfx (session ):
429462 """Build the docfx yaml files for this library."""
430463
@@ -470,92 +503,6 @@ def docfx(session):
470503 )
471504
472505
473- @nox .session (python = SYSTEM_TEST_PYTHON_VERSIONS )
474- def prerelease_deps (session ):
475- """Run all tests with prerelease versions of dependencies installed."""
476-
477- # Install all dependencies
478- session .install ("-e" , ".[all, tests, tracing]" )
479- unit_deps_all = UNIT_TEST_STANDARD_DEPENDENCIES + UNIT_TEST_EXTERNAL_DEPENDENCIES
480- session .install (* unit_deps_all )
481- system_deps_all = (
482- SYSTEM_TEST_STANDARD_DEPENDENCIES + SYSTEM_TEST_EXTERNAL_DEPENDENCIES
483- )
484- session .install (* system_deps_all )
485-
486- # Because we test minimum dependency versions on the minimum Python
487- # version, the first version we test with in the unit tests sessions has a
488- # constraints file containing all dependencies and extras.
489- with open (
490- CURRENT_DIRECTORY
491- / "testing"
492- / f"constraints-{ UNIT_TEST_PYTHON_VERSIONS [0 ]} .txt" ,
493- encoding = "utf-8" ,
494- ) as constraints_file :
495- constraints_text = constraints_file .read ()
496-
497- # Ignore leading whitespace and comment lines.
498- constraints_deps = [
499- match .group (1 )
500- for match in re .finditer (
501- r"^\s*(\S+)(?===\S+)" , constraints_text , flags = re .MULTILINE
502- )
503- ]
504-
505- session .install (* constraints_deps )
506-
507- prerel_deps = [
508- # "protobuf",
509- # dependency of grpc
510- "six" ,
511- "googleapis-common-protos" ,
512- # Exclude version 1.52.0rc1 which has a known issue. See https://github.com/grpc/grpc/issues/32163
513- "grpcio!=1.52.0rc1" ,
514- "grpcio-status" ,
515- "google-api-core" ,
516- "google-auth" ,
517- "proto-plus" ,
518- "google-cloud-testutils" ,
519- # dependencies of google-cloud-testutils"
520- "click" ,
521- ]
522-
523- for dep in prerel_deps :
524- session .install ("--pre" , "--no-deps" , "--upgrade" , dep )
525-
526- # Remaining dependencies
527- other_deps = [
528- "requests" ,
529- ]
530- session .install (* other_deps )
531-
532- # Print out package versions.
533- session .run ("python" , "-m" , "pip" , "freeze" )
534-
535- session .run ("py.test" , "tests/unit" )
536-
537- system_test_path = os .path .join ("tests" , "system.py" )
538- system_test_folder_path = os .path .join ("tests" , "system" )
539-
540- # Only run system tests if found.
541- if os .path .exists (system_test_path ):
542- session .run (
543- "py.test" ,
544- "--verbose" ,
545- f"--junitxml=system_{ session .python } _sponge_log.xml" ,
546- system_test_path ,
547- * session .posargs ,
548- )
549- if os .path .exists (system_test_folder_path ):
550- session .run (
551- "py.test" ,
552- "--verbose" ,
553- f"--junitxml=system_{ session .python } _sponge_log.xml" ,
554- system_test_folder_path ,
555- * session .posargs ,
556- )
557-
558-
559506def install_conda_unittest_dependencies (session , standard_deps , conda_forge_packages ):
560507 """Installs packages from conda forge, pypi, and locally."""
561508
@@ -573,6 +520,7 @@ def install_conda_unittest_dependencies(session, standard_deps, conda_forge_pack
573520
574521
575522@nox .session (python = CONDA_TEST_PYTHON_VERSIONS , venv_backend = "mamba" )
523+ @_calculate_duration
576524def conda_test (session ):
577525 """Run test suite in a conda virtual environment.
578526
0 commit comments