From 08135b06e77aa3668ea9571569b66ce3856193df Mon Sep 17 00:00:00 2001 From: Melissa DeLucchi <113376043+delucchi-cmu@users.noreply.github.com> Date: Mon, 26 Feb 2024 13:53:30 -0500 Subject: [PATCH] Install sphinx from docs/requirements. (#436) * Install sphinx from docs/requirements. * Apply suggestions from code review Co-authored-by: Konstantin Malanchev --------- Co-authored-by: Konstantin Malanchev --- docs/conf.py | 4 +- .../.initialize_new_project.sh | 1 + python-project-template/.setup_dev.sh | 1 + python-project-template/pyproject.toml.jinja | 34 +++-------- .../requirements.txt.jinja | 14 +++-- tests/test_package_creation.py | 60 ++++++++++++++----- 6 files changed, 66 insertions(+), 48 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 67d3ef8e..7b351b4c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -32,7 +32,7 @@ # -- sphinx-copybutton configuration ---------------------------------------- ## sets up the expected prompt text from console blocks, and excludes it from ## the text that goes into the clipboard. -copybutton_exclude = '.linenos, .gp' +copybutton_exclude = ".linenos, .gp" copybutton_prompt_text = ">> " ## lets us suppress the copy button on select code blocks. @@ -40,7 +40,7 @@ # -- Options for autosectionlabel ------------------------------------------------- -autosectionlabel_prefix_document=True +autosectionlabel_prefix_document = True # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output diff --git a/python-project-template/.initialize_new_project.sh b/python-project-template/.initialize_new_project.sh index fdb0f821..9aee0d39 100644 --- a/python-project-template/.initialize_new_project.sh +++ b/python-project-template/.initialize_new_project.sh @@ -44,6 +44,7 @@ python -m pip install -e . > /dev/null echo "Installing developer dependencies in local environment" python -m pip install -e .'[dev]' > /dev/null +if [ -f docs/requirements.txt ]; then python -m pip install -r docs/requirements.txt; fi echo "Installing pre-commit" pre-commit install > /dev/null diff --git a/python-project-template/.setup_dev.sh b/python-project-template/.setup_dev.sh index 47bc27ae..d8cd955c 100644 --- a/python-project-template/.setup_dev.sh +++ b/python-project-template/.setup_dev.sh @@ -32,6 +32,7 @@ python -m pip install -e . > /dev/null echo "Installing developer dependencies in local environment" python -m pip install -e .'[dev]' > /dev/null +if [ -f docs/requirements.txt ]; then python -m pip install -r docs/requirements.txt; fi echo "Installing pre-commit" pre-commit install > /dev/null diff --git a/python-project-template/pyproject.toml.jinja b/python-project-template/pyproject.toml.jinja index 6f5ae9c7..d3a4e7a1 100644 --- a/python-project-template/pyproject.toml.jinja +++ b/python-project-template/pyproject.toml.jinja @@ -20,9 +20,6 @@ classifiers = [ dynamic = ["version"] requires-python = ">={{ python_versions[0] }}" dependencies = [ -{%- if include_notebooks %} - "ipykernel", # Support for Jupyter notebooks -{%- endif %} ] [project.urls] @@ -31,36 +28,23 @@ dependencies = [ # On a mac, install optional dependencies with `pip install '.[dev]'` (include the single quotes) [project.optional-dependencies] dev = [ - "pytest", - "pytest-cov", # Used to report total code coverage - "pre-commit", # Used to run checks before finalizing a git commit -{%- if include_docs %} - "sphinx", # Used to automatically generate documentation - "sphinx-rtd-theme", # Used to render documentation - "sphinx-autoapi", # Used to automatically generate api documentation -{%- endif %} -{%- if 'pylint' in enforce_style %} - "pylint", # Used for static linting of files +{%- if include_benchmarks %} + "asv==0.6.1", # Used to compute performance benchmarks {%- endif %} {%- if 'black' in enforce_style %} "black", # Used for static linting of files {%- endif %} -{%- if 'ruff_lint' in enforce_style or 'ruff_format' in enforce_style %} - "ruff", # Used for static linting of files -{%- endif %} {%- if mypy_type_checking != 'none' %} "mypy", # Used for static type checking of files {%- endif %} -{%- if include_notebooks %} - # if you add dependencies here while experimenting in a notebook and you - # want that notebook to render in your documentation, please add the - # dependencies to ./docs/requirements.txt as well. - "nbconvert", # Needed for pre-commit check to clear output from Python notebooks - "nbsphinx", # Used to integrate Python notebooks into Sphinx documentation - "ipython", # Also used in building notebooks into Sphinx + "pre-commit", # Used to run checks before finalizing a git commit +{%- if 'pylint' in enforce_style %} + "pylint", # Used for static linting of files {%- endif %} -{%- if include_benchmarks %} - "asv==0.6.1", # Used to compute performance benchmarks + "pytest", + "pytest-cov", # Used to report total code coverage +{%- if 'ruff_lint' in enforce_style or 'ruff_format' in enforce_style %} + "ruff", # Used for static linting of files {%- endif %} ] diff --git a/python-project-template/{% if include_docs %}docs{% endif %}/requirements.txt.jinja b/python-project-template/{% if include_docs %}docs{% endif %}/requirements.txt.jinja index 7ae704e3..d0206a7e 100644 --- a/python-project-template/{% if include_docs %}docs{% endif %}/requirements.txt.jinja +++ b/python-project-template/{% if include_docs %}docs{% endif %}/requirements.txt.jinja @@ -1,10 +1,12 @@ -sphinx -sphinx-rtd-theme -sphinx-autoapi -sphinx-copybutton {%- if include_notebooks %} -nbsphinx +ipykernel ipython -jupytext jupyter +jupytext +nbconvert +nbsphinx {%- endif %} +sphinx +sphinx-autoapi +sphinx-copybutton +sphinx-rtd-theme \ No newline at end of file diff --git a/tests/test_package_creation.py b/tests/test_package_creation.py index fc7d8a1e..a83c9ca4 100644 --- a/tests/test_package_creation.py +++ b/tests/test_package_creation.py @@ -9,6 +9,26 @@ def successfully_created_project(result): return result.exit_code == 0 and result.exception is None and result.project_dir.is_dir() +def contains_required_files(result): + required_files = [ + ".copier-answers.yml", + ".git_archival.txt", + ".gitattributes", + ".gitignore", + ".pre-commit-config.yaml", + ".setup_dev.sh", + "LICENSE", + "pyproject.toml", + "README.md", + ] + all_found = True + for file in required_files: + if not (result.project_dir / file).is_file(): + all_found = False + print("Required file not generated:", file) + return all_found + + def directory_structure_is_correct(result, package_name="example_package"): """Test to ensure that the default directory structure ws created correctly""" return (result.project_dir / f"src/{package_name}").is_dir() and ( @@ -65,14 +85,24 @@ def docs_build_successfully(result): virtual environment for the project. """ - sphinx_results = subprocess.run( - ["make", "html"], - cwd=(result.project_dir / "docs"), - ) + required_files = [ + ".readthedocs.yml", + ] + all_found = True + for file in required_files: + if not (result.project_dir / file).is_file(): + all_found = False + print("Required file not generated:", file) + return all_found + + # sphinx_results = subprocess.run( + # ["make", "html"], + # cwd=(result.project_dir / "docs"), + # ) + + # return sphinx_results.returncode == 0 - return sphinx_results.returncode == 0 - def github_workflows_are_valid(result): """Test to ensure that the GitHub workflows are valid""" workflows_results = subprocess.run( @@ -95,14 +125,9 @@ def test_all_defaults(copie): result = copie.copy() assert successfully_created_project(result) - assert directory_structure_is_correct(result) - assert not pylint_runs_successfully(result) - - # make sure that some basic files were created - assert (result.project_dir / "README.md").is_file() - assert (result.project_dir / "pyproject.toml").is_file() + assert contains_required_files(result) # check to see if the README file was hydrated with copier answers. found_line = False @@ -130,10 +155,9 @@ def test_use_black_and_no_example_modules(copie): result = copie.copy(extra_answers=extra_answers) assert successfully_created_project(result) - assert directory_structure_is_correct(result) - assert pylint_runs_successfully(result) + assert contains_required_files(result) # make sure that the files that were not requested were not created assert not (result.project_dir / "src/example_package/example_module.py").is_file() @@ -174,6 +198,7 @@ def test_code_style_combinations(copie, enforce_style): result = copie.copy(extra_answers=extra_answers) assert successfully_created_project(result) assert directory_structure_is_correct(result) + assert contains_required_files(result) # black would still run successfully. assert black_runs_successfully(result) @@ -202,6 +227,7 @@ def test_smoke_test_notification(copie, notification): assert successfully_created_project(result) assert directory_structure_is_correct(result) assert black_runs_successfully(result) + assert contains_required_files(result) @pytest.mark.parametrize( @@ -226,6 +252,8 @@ def test_doc_combinations(copie, doc_answers): assert successfully_created_project(result) assert directory_structure_is_correct(result) assert black_runs_successfully(result) + assert contains_required_files(result) + assert docs_build_successfully(result) assert (result.project_dir / "docs").is_dir() @@ -251,9 +279,10 @@ def test_doc_combinations_no_docs(copie, doc_answers): assert successfully_created_project(result) assert directory_structure_is_correct(result) assert black_runs_successfully(result) + assert contains_required_files(result) assert not (result.project_dir / "docs").is_dir() - + def test_github_workflows_schema(copie): """Confirm the current GitHub workflows have valid schemas.""" extra_answers = { @@ -263,3 +292,4 @@ def test_github_workflows_schema(copie): result = copie.copy(extra_answers=extra_answers) initialize_git_project(result) assert github_workflows_are_valid(result) + assert contains_required_files(result)