1818
1919from __future__ import absolute_import
2020
21+ from functools import wraps
2122import os
2223import pathlib
2324import re
2425import shutil
26+ import time
2527from typing import Dict , List
2628import warnings
2729
110112
111113CURRENT_DIRECTORY = pathlib .Path (__file__ ).parent .absolute ()
112114
115+
116+ def _calculate_duration (func ):
117+ """This decorator prints the execution time for the decorated function."""
118+
119+ @wraps (func )
120+ def wrapper (* args , ** kwargs ):
121+ start = time .monotonic ()
122+ result = func (* args , ** kwargs )
123+ end = time .monotonic ()
124+ total_seconds = round (end - start )
125+ hours = total_seconds // 3600 # Integer division to get hours
126+ remaining_seconds = total_seconds % 3600 # Modulo to find remaining seconds
127+ minutes = remaining_seconds // 60
128+ seconds = remaining_seconds % 60
129+ human_time = f"{ hours :} :{ minutes :0>2} :{ seconds :0>2} "
130+ print (f"Session ran in { total_seconds } seconds ({ human_time } )" )
131+ return result
132+
133+ return wrapper
134+
135+
113136nox .options .sessions = [
114137 "unit" ,
115138 "system" ,
128151
129152
130153@nox .session (python = DEFAULT_PYTHON_VERSION )
154+ @_calculate_duration
131155def lint (session ):
132156 """Run linters.
133157
134158 Returns a failure if the linters find linting errors or sufficiently
135159 serious code quality issues.
136160 """
137161 session .install (FLAKE8_VERSION , BLACK_VERSION )
162+ session .run ("python" , "-m" , "pip" , "freeze" )
138163 session .run (
139164 "black" ,
140165 "--check" ,
@@ -144,16 +169,19 @@ def lint(session):
144169
145170
146171@nox .session (python = DEFAULT_PYTHON_VERSION )
172+ @_calculate_duration
147173def blacken (session ):
148174 """Run black. Format code to uniform standard."""
149175 session .install (BLACK_VERSION )
176+ session .run ("python" , "-m" , "pip" , "freeze" )
150177 session .run (
151178 "black" ,
152179 * LINT_PATHS ,
153180 )
154181
155182
156183@nox .session (python = DEFAULT_PYTHON_VERSION )
184+ @_calculate_duration
157185def format (session ):
158186 """
159187 Run isort to sort imports. Then run black
@@ -162,6 +190,7 @@ def format(session):
162190 session .install (BLACK_VERSION , ISORT_VERSION )
163191 # Use the --fss option to sort imports using strict alphabetical order.
164192 # See https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections
193+ session .run ("python" , "-m" , "pip" , "freeze" )
165194 session .run (
166195 "isort" ,
167196 "--fss" ,
@@ -174,9 +203,11 @@ def format(session):
174203
175204
176205@nox .session (python = DEFAULT_PYTHON_VERSION )
206+ @_calculate_duration
177207def lint_setup_py (session ):
178208 """Verify that setup.py is valid (including RST check)."""
179209 session .install ("docutils" , "pygments" )
210+ session .run ("python" , "-m" , "pip" , "freeze" )
180211 session .run ("python" , "setup.py" , "check" , "--restructuredtext" , "--strict" )
181212
182213
@@ -213,6 +244,7 @@ def install_unittest_dependencies(session, *constraints):
213244 "protobuf_implementation" ,
214245 ["python" , "upb" , "cpp" ],
215246)
247+ @_calculate_duration
216248def unit (session , protobuf_implementation , install_extras = True ):
217249 # Install all test dependencies, then install this package in-place.
218250
@@ -239,6 +271,7 @@ def unit(session, protobuf_implementation, install_extras=True):
239271 session .install ("protobuf<4" )
240272
241273 # Run py.test against the unit tests.
274+ session .run ("python" , "-m" , "pip" , "freeze" )
242275 session .run (
243276 "py.test" ,
244277 "--quiet" ,
@@ -288,6 +321,7 @@ def install_systemtest_dependencies(session, *constraints):
288321
289322
290323@nox .session (python = SYSTEM_TEST_PYTHON_VERSIONS )
324+ @_calculate_duration
291325def system (session ):
292326 """Run the system test suite."""
293327 constraints_path = str (
@@ -310,6 +344,7 @@ def system(session):
310344 session .skip ("System tests were not found" )
311345
312346 install_systemtest_dependencies (session , "-c" , constraints_path )
347+ session .run ("python" , "-m" , "pip" , "freeze" )
313348
314349 # Run py.test against the system tests.
315350 if system_test_exists :
@@ -331,6 +366,7 @@ def system(session):
331366
332367
333368@nox .session (python = SYSTEM_TEST_PYTHON_VERSIONS )
369+ @_calculate_duration
334370def system_noextras (session ):
335371 """Run the system test suite."""
336372 constraints_path = str (
@@ -355,6 +391,7 @@ def system_noextras(session):
355391 global SYSTEM_TEST_EXTRAS_BY_PYTHON
356392 SYSTEM_TEST_EXTRAS_BY_PYTHON = False
357393 install_systemtest_dependencies (session , "-c" , constraints_path )
394+ session .run ("python" , "-m" , "pip" , "freeze" )
358395
359396 # Run py.test against the system tests.
360397 if system_test_exists :
@@ -376,6 +413,7 @@ def system_noextras(session):
376413
377414
378415@nox .session (python = SYSTEM_TEST_PYTHON_VERSIONS [- 1 ])
416+ @_calculate_duration
379417def compliance (session ):
380418 """Run the SQLAlchemy dialect-compliance system tests"""
381419 constraints_path = str (
@@ -430,19 +468,22 @@ def compliance(session):
430468
431469
432470@nox .session (python = DEFAULT_PYTHON_VERSION )
471+ @_calculate_duration
433472def cover (session ):
434473 """Run the final coverage report.
435474
436475 This outputs the coverage report aggregating coverage from the unit
437476 test runs (not system test runs), and then erases coverage data.
438477 """
439478 session .install ("coverage" , "pytest-cov" )
479+ session .run ("python" , "-m" , "pip" , "freeze" )
440480 session .run ("coverage" , "report" , "--show-missing" , "--fail-under=100" )
441481
442482 session .run ("coverage" , "erase" )
443483
444484
445485@nox .session (python = "3.10" )
486+ @_calculate_duration
446487def docs (session ):
447488 """Build the docs for this library."""
448489
@@ -465,6 +506,7 @@ def docs(session):
465506 )
466507
467508 shutil .rmtree (os .path .join ("docs" , "_build" ), ignore_errors = True )
509+ session .run ("python" , "-m" , "pip" , "freeze" )
468510 session .run (
469511 "sphinx-build" ,
470512 "-W" , # warnings as errors
@@ -480,6 +522,7 @@ def docs(session):
480522
481523
482524@nox .session (python = "3.10" )
525+ @_calculate_duration
483526def docfx (session ):
484527 """Build the docfx yaml files for this library."""
485528
@@ -502,6 +545,7 @@ def docfx(session):
502545 )
503546
504547 shutil .rmtree (os .path .join ("docs" , "_build" ), ignore_errors = True )
548+ session .run ("python" , "-m" , "pip" , "freeze" )
505549 session .run (
506550 "sphinx-build" ,
507551 "-T" , # show full traceback on exception
@@ -532,6 +576,7 @@ def docfx(session):
532576 "protobuf_implementation" ,
533577 ["python" , "upb" , "cpp" ],
534578)
579+ @_calculate_duration
535580def prerelease_deps (session , protobuf_implementation ):
536581 """Run all tests with prerelease versions of dependencies installed."""
537582
@@ -593,6 +638,7 @@ def prerelease_deps(session, protobuf_implementation):
593638 "requests" ,
594639 ]
595640 session .install (* other_deps )
641+ session .run ("python" , "-m" , "pip" , "freeze" )
596642
597643 # Print out prerelease package versions
598644 session .run (
0 commit comments