diff --git a/nox/manifest.py b/nox/manifest.py index dbc3304e..4f6912b9 100644 --- a/nox/manifest.py +++ b/nox/manifest.py @@ -55,15 +55,21 @@ class Manifest: session_functions (Mapping[str, function]): The registry of discovered session functions. global_config (.nox.main.GlobalConfig): The global configuration. + module_docstring (Optional[str]): The user noxfile.py docstring. + Defaults to `None`. """ def __init__( - self, session_functions: Mapping[str, "Func"], global_config: argparse.Namespace + self, + session_functions: Mapping[str, "Func"], + global_config: argparse.Namespace, + module_docstring: Optional[str] = None, ) -> None: self._all_sessions = [] # type: List[SessionRunner] self._queue = [] # type: List[SessionRunner] self._consumed = [] # type: List[SessionRunner] self._config = global_config # type: argparse.Namespace + self.module_docstring = module_docstring # type: Optional[str] # Create the sessions based on the provided session functions. for name, func in session_functions.items(): diff --git a/nox/tasks.py b/nox/tasks.py index 60b5f9a6..afb50a8d 100644 --- a/nox/tasks.py +++ b/nox/tasks.py @@ -104,8 +104,11 @@ def discover_manifest( # sorted by decorator call time. functions = registry.get() + # Get the docstring from the noxfile + module_docstring = module.__doc__ + # Return the final dictionary of session functions. - return Manifest(functions, global_config) + return Manifest(functions, global_config, module_docstring) def filter_manifest( @@ -166,7 +169,9 @@ def honor_list_request( return manifest # If the user just asked for a list of sessions, print that - # and be done. + # and any docstring specified in noxfile.py and be done. + if manifest.module_docstring: + print(manifest.module_docstring.strip(), end="\n\n") print("Sessions defined in {noxfile}:\n".format(noxfile=global_config.noxfile)) diff --git a/noxfile.py b/noxfile.py index 6aed0571..36150cd8 100644 --- a/noxfile.py +++ b/noxfile.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. + import functools import os import platform diff --git a/tests/test_tasks.py b/tests/test_tasks.py index 9827cfc8..4031724c 100644 --- a/tests/test_tasks.py +++ b/tests/test_tasks.py @@ -200,12 +200,21 @@ def test_honor_list_request_noop(): assert return_value is manifest -@pytest.mark.parametrize("description", [None, "bar"]) -def test_honor_list_request(description): +@pytest.mark.parametrize( + "description, module_docstring", + [ + (None, None), + (None, "hello docstring"), + ("Bar", None), + ("Bar", "hello docstring"), + ], +) +def test_honor_list_request(description, module_docstring): config = _options.options.namespace( list_sessions=True, noxfile="noxfile.py", color=False ) manifest = mock.create_autospec(Manifest) + manifest.module_docstring = module_docstring manifest.list_all_sessions.return_value = [ (argparse.Namespace(friendly_name="foo", description=description), True) ] @@ -218,6 +227,7 @@ def test_honor_list_request_skip_and_selected(capsys): list_sessions=True, noxfile="noxfile.py", color=False ) manifest = mock.create_autospec(Manifest) + manifest.module_docstring = None manifest.list_all_sessions.return_value = [ (argparse.Namespace(friendly_name="foo", description=None), True), (argparse.Namespace(friendly_name="bar", description=None), False), @@ -231,6 +241,44 @@ def test_honor_list_request_skip_and_selected(capsys): assert "- bar" in out +def test_honor_list_request_prints_docstring_if_present(capsys): + config = _options.options.namespace( + list_sessions=True, noxfile="noxfile.py", color=False + ) + manifest = mock.create_autospec(Manifest) + manifest.module_docstring = "Hello I'm a docstring" + manifest.list_all_sessions.return_value = [ + (argparse.Namespace(friendly_name="foo", description=None), True), + (argparse.Namespace(friendly_name="bar", description=None), False), + ] + + return_value = tasks.honor_list_request(manifest, global_config=config) + assert return_value == 0 + + out = capsys.readouterr().out + + assert "Hello I'm a docstring" in out + + +def test_honor_list_request_doesnt_print_docstring_if_not_present(capsys): + config = _options.options.namespace( + list_sessions=True, noxfile="noxfile.py", color=False + ) + manifest = mock.create_autospec(Manifest) + manifest.module_docstring = None + manifest.list_all_sessions.return_value = [ + (argparse.Namespace(friendly_name="foo", description=None), True), + (argparse.Namespace(friendly_name="bar", description=None), False), + ] + + return_value = tasks.honor_list_request(manifest, global_config=config) + assert return_value == 0 + + out = capsys.readouterr().out + + assert "Hello I'm a docstring" not in out + + def test_verify_manifest_empty(): config = _options.options.namespace(sessions=(), keywords=()) manifest = Manifest({}, config)