diff --git a/.github/workflows/code-projects-type-check.yml b/.github/workflows/code-projects-type-check.yml index 832f4b4bf..dd3a6a452 100644 --- a/.github/workflows/code-projects-type-check.yml +++ b/.github/workflows/code-projects-type-check.yml @@ -3,12 +3,12 @@ name: code_projects Type Check on: push: paths: - - 'frontend/py_modules/code_projects/**' + - 'frontend/python/rst_code_example_pipeline/**' pull_request: branches: - main paths: - - 'frontend/py_modules/code_projects/**' + - 'frontend/python/rst_code_example_pipeline/**' jobs: pyright: @@ -27,6 +27,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install pyright run: pip install pyright - - name: Run pyright on code_projects - working-directory: frontend/py_modules/code_projects + - name: Install rst_code_example_pipeline + run: pip install -e frontend/python/rst_code_example_pipeline + - name: Run pyright on rst_code_example_pipeline + working-directory: frontend/python/rst_code_example_pipeline run: pyright . diff --git a/.github/workflows/install_toolchain.sh b/.github/workflows/install_toolchain.sh index 599639378..9f60a8595 100755 --- a/.github/workflows/install_toolchain.sh +++ b/.github/workflows/install_toolchain.sh @@ -2,7 +2,7 @@ GNAT_FSF_BUILDS=https://github.com/alire-project/GNAT-FSF-builds/releases/download -TOOLCHAIN_CONFIG=${GITHUB_WORKSPACE}/frontend/py_modules/code_projects/toolchain.ini +TOOLCHAIN_CONFIG=${GITHUB_WORKSPACE}/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/data/toolchain.ini INSTALL_GNATPROVE=NO INSTALL_GNAT=NO diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8afd9fec8..ec6e35c45 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -532,7 +532,7 @@ By default, the standard version of the GNAT toolchain specified in the frontend is used in the testing phase. The list of versions for each specific tool from the GNAT toolchain can be found in this file: -frontend/py_modules/code_projects/toolchain.ini +frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/data/toolchain.ini An alternative version of a tool can be selected for a specific code block using the `gnat=`, `gnatprove=` or `gprbuild=` parameters. For example: diff --git a/README.md b/README.md index 2b2a3c122..774bc42c6 100644 --- a/README.md +++ b/README.md @@ -111,15 +111,11 @@ website being served from the local Python-based HTTP server. The ReST files found in the [content directory](content) have `.. code:: ada` blocks that contain source-code examples. To test the expected behavior of those examples, a test script called `compile_blocks.py` is available, as well -as the `code_projects` module. +as the `rst_code_example_pipeline` package. To make use of this test infrastructure, the best approach is to start the -Vagrant publishing server (`epub`) and install the environment: - -```sh -cd /vagrant/frontend -export PYTHONPATH="$PYTHONPATH:sphinx:py_modules" -``` +Vagrant publishing server (`epub`). The Python environment is configured +automatically during provisioning. ### Using the `compile_blocks.py` script @@ -203,28 +199,28 @@ python3 tests/compile_blocks.py \ ``` -### Using the code_projects module +### Using the rst_code_example_pipeline package -The [code_projects module](frontend/py_modules/code_projects) contains the +The [rst_code_example_pipeline package](frontend/python/rst_code_example_pipeline) contains the actual Python modules that are called by the `compile_blocks.py` script. It's -possible to use them directly: +possible to use them directly via the installed entry points: -- `extract_projects.py` extracts all code blocks and stores into the specified +- `extract-code` extracts all code blocks and stores into the specified directory; -- `check_projects.py` checks each code blocks from the specified directory. +- `check-code` checks each code block from the specified directory. For example, to build the source-code examples from the [Introduction to Ada course](content/courses/intro-to-ada), run: ```sh -python3 py_modules/code_projects/extract_projects.py \ +extract-code \ --build-dir test_output \ $(find ../content/courses/intro-to-ada/ -name '*.rst') -python3 py_modules/code_projects/check_projects.py \ +check-code \ --build-dir test_output ``` For more examples and alternative configurations, please refer to the -[README of the code_projects module](frontend/py_modules/code_projects/README.md) +[README of the rst_code_example_pipeline package](frontend/python/rst_code_example_pipeline/README.md) diff --git a/Vagrantfile b/Vagrantfile index ea4a2d64b..5ad06e6a0 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -71,6 +71,7 @@ $frontend = <<-SHELL python3 -m venv /vagrant/venv source /vagrant/venv/bin/activate pip3 install -r /vagrant/frontend/requirements_frozen.txt + pip3 install -e /vagrant/frontend/python/rst_code_example_pipeline # File system: increase number of user watches # Needed for npm @@ -205,6 +206,7 @@ $epub = <<-SHELL python3 -m venv /vagrant/venv source /vagrant/venv/bin/activate pip3 install -r /vagrant/frontend/requirements_frozen.txt + pip3 install -e /vagrant/frontend/python/rst_code_example_pipeline # File system: increase number of user watches # Needed for npm @@ -232,7 +234,7 @@ Vagrant.configure("2") do |config| web.vm.synced_folder './frontend', '/vagrant/frontend' web.vm.synced_folder './content', '/vagrant/content' - web.vm.provision "file", source: "./frontend/py_modules/code_projects/toolchain.ini", destination: "/home/vagrant/toolchain.ini" + web.vm.provision "file", source: "./frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/data/toolchain.ini", destination: "/home/vagrant/toolchain.ini" web.vm.provision "file", source: "./frontend/vm_apt_web.txt", destination: "/home/vagrant/vm_apt.txt" web.vm.provision :shell, inline: $frontend end @@ -244,7 +246,7 @@ Vagrant.configure("2") do |config| epub.vm.synced_folder './frontend', '/vagrant/frontend' epub.vm.synced_folder './content', '/vagrant/content' - epub.vm.provision "file", source: "./frontend/py_modules/code_projects/toolchain.ini", destination: "/home/vagrant/toolchain.ini" + epub.vm.provision "file", source: "./frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/data/toolchain.ini", destination: "/home/vagrant/toolchain.ini" epub.vm.provision "file", source: "./frontend/vm_apt_epub.txt", destination: "/home/vagrant/vm_apt.txt" epub.vm.provision :shell, inline: $epub end diff --git a/frontend/Makefile b/frontend/Makefile index af422ebc3..f01803c42 100644 --- a/frontend/Makefile +++ b/frontend/Makefile @@ -6,9 +6,9 @@ SPHINXCONF = sphinx BUILDDIR = dist SRC_TEST_DIR = $(BUILDDIR)/test_output TEST_LAMBDA ?= 0 -TEST_LOCAL_DRIVER = PYTHONPATH="$PYTHONPATH:sphinx:py_modules" python3 tests/compile_blocks.py --keep_files -B $(SRC_TEST_DIR) +TEST_LOCAL_DRIVER = PYTHONPATH="$PYTHONPATH:sphinx" python3 tests/compile_blocks.py --keep_files -B $(SRC_TEST_DIR) TEST_OPTIONS ?= -TEST_LAMBDA_DRIVER = PYTHONPATH="$PYTHONPATH:sphinx:py_modules" python3 tests/execute_rst_code_blocks.py --halt-on-failure +TEST_LAMBDA_DRIVER = PYTHONPATH="$PYTHONPATH:sphinx" python3 tests/execute_rst_code_blocks.py --halt-on-failure ifeq ($(strip $(TEST_LAMBDA)),1) TEST_DRIVER := $(TEST_LAMBDA_DRIVER) diff --git a/frontend/py_modules/code_projects/README.md b/frontend/py_modules/code_projects/README.md deleted file mode 100644 index 00ef9d74e..000000000 --- a/frontend/py_modules/code_projects/README.md +++ /dev/null @@ -1,169 +0,0 @@ -# Code_projects module - -## Introduction - -The [code_projects module](frontend/py_modules/code_projects) contains scripts -to extract, build and run the code blocks from the ReST files. These are the -main scripts: - -- `extract_projects.py` extracts all code blocks and stores into the specified - build directory; - -- `check_projects.py` checks each code blocks from the specified build - directory; - -- `check_code_block.py` checks a single (previously extracted) code block. - - -## Simple usage - -To build and run the source-code examples from a course, just run the -`extract_projects.py` script followed by `check_projects.py` script. For -example, to test the source-code examples from the -[Introduction to Ada course](content/courses/intro-to-ada), run: - -```sh -python3 py_modules/code_projects/extract_projects.py \ - --build-dir test_output \ - $(find ../content/courses/intro-to-ada/ -name '*.rst') - -python3 py_modules/code_projects/check_projects.py \ - --build-dir test_output -``` - -When the `extract_projects.py` runs, it creates a JSON file called -`block_info.json` for each code block (source-code example) that is extracted -from the ReST files. The `check_projects.py` looks for all `block_info.json` -files in the build directory and checks the source code example described in -each of those JSON files. - - -## Verbose mode - -All the test script have a `--verbose` switch. For example: - -```sh -python3 py_modules/code_projects/extract_projects.py \ - --verbose \ - --build-dir test_output \ - $(find ../content/courses/intro-to-ada/ -name '*.rst') - -python3 py_modules/code_projects/check_projects.py \ - --verbose \ - --build-dir test_output -``` - - -## JSON file: list of extracted projects - -It's possible to store the list of extracted projects into a JSON file and -use that file for checking the projects. For example, to build the source-code -examples from the -[Introduction to Ada course](content/courses/intro-to-ada), run: - -```sh -python3 py_modules/code_projects/extract_projects.py \ - --extracted_projects test_output/extracted_projects.json \ - $(find ../content/courses/intro-to-ada/ -name '*.rst') - -python3 py_modules/code_projects/check_projects.py \ - --extracted_projects test_output/extracted_projects.json -``` - -To build the source-code examples extracted from a single ReST file: - -```sh -python3 py_modules/code_projects/extract_projects.py \ - --extracted_projects test_output/extracted_projects.json \ - ../content/courses/intro-to-ada/chapters/imperative_language.rst - -python3 py_modules/code_projects/check_projects.py \ - --extracted_projects test_output/extracted_projects.json -``` - - -### JSON file and build directory - -If only `--extracted_projects` is specified without `--build-dir`, then the -build directory corresponds to the path to the JSON file. For example, if -`--extracted_projects test_output/extracted_projects.json` is specified, then -the build directory is `test_output`. - -To store the JSON file completely separate from the build directory, use -both `--extracted_projects` and `--build-dir` switches and specify different -paths. For example: - -```sh -python3 py_modules/code_projects/extract_projects.py \ - --build-dir test_output \ - --extracted_projects extracted_projects.json \ - $(find ../content/courses/intro-to-ada/ -name '*.rst') - -python3 py_modules/code_projects/check_projects.py \ - --build-dir test_output \ - --extracted_projects extracted_projects.json -``` - - -## Checking single code blocks - -When extracting the source-code examples from the ReST files, a JSON file -called `block_info.json` is created for each code block. It's possible to check a -single code block by using the `check_code_block.py` and indicating this -JSON file. For example: - -```sh -python3 py_modules/code_projects/check_code_block.py \ - test_output/projects/Courses/Intro_To_Ada/Imperative_Language/Greet/cba89a34b87c9dfa71533d982d05e6ab/block_info.json -``` - - -### Forced check - -To force checking of a specific code block, use the `--force` switch: - -```sh -python3 py_modules/code_projects/check_code_block.py \ - --force \ - test_output/projects/Courses/Intro_To_Ada/Imperative_Language/Greet/cba89a34b87c9dfa71533d982d05e6ab/block_info.json -``` - - - -## Testing single code block - -To test just a single code block from an ReST file, use the `--code-block-at` -switch: - - -```sh -python3 py_modules/code_projects/extract_projects.py \ - --code-block-at=28 \ - --extracted_projects test_output/extracted_projects.json \ - ../content/courses/intro-to-ada/chapters/imperative_language.rst - -python3 py_modules/code_projects/check_projects.py \ - --extracted_projects test_output/extracted_projects.json -``` - - -## Style check: maximum number of columns - -To ensure that a maximum limit of 80 columns per line is respected in the code -examples, use the `--max_columns` switch. - -For example, using the `check_projects.py` script: - -```sh -python3 py_modules/code_projects/check_projects.py \ - --max-columns 80 \ - --extracted_projects test_output/extracted_projects.json -``` - -For example, using the `check_code_block.py` script: - -```sh -python3 py_modules/code_projects/check_code_block.py \ - --max-columns 80 \ - test_output/projects/Courses/Intro_To_Ada/Imperative_Language/Greet/cba89a34b87c9dfa71533d982d05e6ab/block_info.json -``` diff --git a/frontend/py_modules/code_projects/__init__.py b/frontend/py_modules/code_projects/__init__.py deleted file mode 100644 index 43f722c4a..000000000 --- a/frontend/py_modules/code_projects/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -__title__ = 'code_projects' -__version__ = '0.2.0' diff --git a/frontend/py_modules/code_projects/pyrightconfig.json b/frontend/py_modules/code_projects/pyrightconfig.json deleted file mode 100644 index 78155394b..000000000 --- a/frontend/py_modules/code_projects/pyrightconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "pythonVersion": "3.10", - "extraPaths": [ - "../../sphinx" - ] -} diff --git a/frontend/python/README.md b/frontend/python/README.md new file mode 100644 index 000000000..b924d45f4 --- /dev/null +++ b/frontend/python/README.md @@ -0,0 +1,7 @@ +# Python packages + +This directory contains Python packages used by the learn infrastructure. + +| Package | Description | +|---------|-------------| +| [rst_code_example_pipeline](rst_code_example_pipeline/) | Extract, build, and check RST code blocks | diff --git a/frontend/python/rst_code_example_pipeline/README.md b/frontend/python/rst_code_example_pipeline/README.md new file mode 100644 index 000000000..5009f5e01 --- /dev/null +++ b/frontend/python/rst_code_example_pipeline/README.md @@ -0,0 +1,170 @@ +# rst_code_example_pipeline + +## Introduction + +The [rst_code_example_pipeline](frontend/python/rst_code_example_pipeline) package contains +scripts to extract, build and run the code blocks from the ReST files. These are the main +entry points: + +- `extract-code` extracts all code blocks and stores into the specified + build directory; + +- `check-code` checks each code block from the specified build directory; + +- `check-block` checks a single (previously extracted) code block. + +The package is installed in editable mode as part of the VM provisioning: +```sh +pip install -e frontend/python/rst_code_example_pipeline +``` + + +## Simple usage + +To build and run the source-code examples from a course, just run +`extract-code` followed by `check-code`. For example, to test +the source-code examples from the +[Introduction to Ada course](content/courses/intro-to-ada), run: + +```sh +extract-code \ + --build-dir test_output \ + $(find ../content/courses/intro-to-ada/ -name '*.rst') + +check-code \ + --build-dir test_output +``` + +When `extract-code` runs, it creates a JSON file called `block_info.json` +for each code block (source-code example) that is extracted from the ReST files. +`check-code` looks for all `block_info.json` files in the build directory +and checks the source-code example described in each of those JSON files. + + +## Verbose mode + +All the scripts have a `--verbose` / `-v` switch. For example: + +```sh +extract-code \ + --verbose \ + --build-dir test_output \ + $(find ../content/courses/intro-to-ada/ -name '*.rst') + +check-code \ + --verbose \ + --build-dir test_output +``` + + +## JSON file: list of extracted projects + +It's possible to store the list of extracted projects into a JSON file and +use that file for checking the projects. For example, to build the source-code +examples from the +[Introduction to Ada course](content/courses/intro-to-ada), run: + +```sh +extract-code \ + --extracted_projects test_output/extracted_projects.json \ + $(find ../content/courses/intro-to-ada/ -name '*.rst') + +check-code \ + --extracted_projects test_output/extracted_projects.json +``` + +To build the source-code examples extracted from a single ReST file: + +```sh +extract-code \ + --extracted_projects test_output/extracted_projects.json \ + ../content/courses/intro-to-ada/chapters/imperative_language.rst + +check-code \ + --extracted_projects test_output/extracted_projects.json +``` + + +### JSON file and build directory + +If only `--extracted_projects` is specified without `--build-dir`, then the +build directory corresponds to the path to the JSON file. For example, if +`--extracted_projects test_output/extracted_projects.json` is specified, then +the build directory is `test_output`. + +To store the JSON file completely separate from the build directory, use +both `--extracted_projects` and `--build-dir` switches and specify different +paths. For example: + +```sh +extract-code \ + --build-dir test_output \ + --extracted_projects extracted_projects.json \ + $(find ../content/courses/intro-to-ada/ -name '*.rst') + +check-code \ + --build-dir test_output \ + --extracted_projects extracted_projects.json +``` + + +## Checking single code blocks + +When extracting the source-code examples from the ReST files, a JSON file +called `block_info.json` is created for each code block. It's possible to check +a single code block by using `check-block` and indicating this JSON file. +For example: + +```sh +check-block \ + test_output/projects/Courses/Intro_To_Ada/Imperative_Language/Greet/cba89a34b87c9dfa71533d982d05e6ab/block_info.json +``` + + +### Forced check + +To force checking of a specific code block, use the `--force` switch: + +```sh +check-block \ + --force \ + test_output/projects/Courses/Intro_To_Ada/Imperative_Language/Greet/cba89a34b87c9dfa71533d982d05e6ab/block_info.json +``` + + +## Testing single code block + +To test just a single code block from an ReST file, use the `--code-block-at` +switch: + +```sh +extract-code \ + --code-block-at=28 \ + --extracted_projects test_output/extracted_projects.json \ + ../content/courses/intro-to-ada/chapters/imperative_language.rst + +check-code \ + --extracted_projects test_output/extracted_projects.json +``` + + +## Style check: maximum number of columns + +To ensure that a maximum limit of 80 columns per line is respected in the code +examples, use the `--max-columns` switch. + +For example, using `check-code`: + +```sh +check-code \ + --max-columns 80 \ + --extracted_projects test_output/extracted_projects.json +``` + +For example, using `check-block`: + +```sh +check-block \ + --max-columns 80 \ + test_output/projects/Courses/Intro_To_Ada/Imperative_Language/Greet/cba89a34b87c9dfa71533d982d05e6ab/block_info.json +``` diff --git a/frontend/python/rst_code_example_pipeline/pyproject.toml b/frontend/python/rst_code_example_pipeline/pyproject.toml new file mode 100644 index 000000000..69ba8bf23 --- /dev/null +++ b/frontend/python/rst_code_example_pipeline/pyproject.toml @@ -0,0 +1,22 @@ +[build-system] +requires = ["setuptools>=42"] +build-backend = "setuptools.build_meta" + +[project] +name = "rst-code-example-pipeline" +version = "0.2.0" +requires-python = ">=3.10" + +[project.scripts] +extract-code = "rst_code_example_pipeline.cli.extract:main" +check-code = "rst_code_example_pipeline.cli.check:main" +check-block = "rst_code_example_pipeline.cli.check_block:main" + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.setuptools.package-data] +rst_code_example_pipeline = ["data/*.ini"] + +[tool.pyright] +pythonVersion = "3.10" diff --git a/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/__init__.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/__init__.py new file mode 100644 index 000000000..24131d7f4 --- /dev/null +++ b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/__init__.py @@ -0,0 +1,2 @@ +__title__ = 'rst_code_example_pipeline' +__version__ = '0.2.0' diff --git a/frontend/py_modules/code_projects/blocks.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/blocks.py similarity index 99% rename from frontend/py_modules/code_projects/blocks.py rename to frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/blocks.py index 724b65113..b618cef12 100644 --- a/frontend/py_modules/code_projects/blocks.py +++ b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/blocks.py @@ -6,8 +6,8 @@ import json from typing import Any -import colors as C -import toolchain_info +from . import colors as C +from . import toolchain_info class Block(object): @staticmethod diff --git a/frontend/py_modules/code_projects/check_code_block.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/check_code_block.py similarity index 99% rename from frontend/py_modules/code_projects/check_code_block.py rename to frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/check_code_block.py index 94c5bcf84..36a53277b 100755 --- a/frontend/py_modules/code_projects/check_code_block.py +++ b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/check_code_block.py @@ -18,10 +18,10 @@ import glob import re -import blocks -import checks -import fmt_utils -import toolchain_setup +from . import blocks +from . import checks +from . import fmt_utils +from . import toolchain_setup LOOK_FOR_PREVIOUS_CHECKS = True diff --git a/frontend/py_modules/code_projects/check_projects.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/check_projects.py similarity index 97% rename from frontend/py_modules/code_projects/check_projects.py rename to frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/check_projects.py index ed638716b..6672b031f 100755 --- a/frontend/py_modules/code_projects/check_projects.py +++ b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/check_projects.py @@ -8,10 +8,10 @@ import os import glob -import blocks -import check_code_block -import extract_projects -import fmt_utils +from . import blocks +from . import check_code_block +from . import extract_projects +from . import fmt_utils verbose: bool = False all_diagnostics: bool = False diff --git a/frontend/py_modules/code_projects/checks.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/checks.py similarity index 100% rename from frontend/py_modules/code_projects/checks.py rename to frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/checks.py diff --git a/frontend/sphinx/widget/chop.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/chop.py similarity index 100% rename from frontend/sphinx/widget/chop.py rename to frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/chop.py diff --git a/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/cli/__init__.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/cli/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/cli/check.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/cli/check.py new file mode 100644 index 000000000..0776e0647 --- /dev/null +++ b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/cli/check.py @@ -0,0 +1,6 @@ +import runpy + + +def main() -> None: + runpy.run_module('rst_code_example_pipeline.check_projects', + run_name='__main__', alter_sys=True) diff --git a/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/cli/check_block.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/cli/check_block.py new file mode 100644 index 000000000..8840ca1f1 --- /dev/null +++ b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/cli/check_block.py @@ -0,0 +1,6 @@ +import runpy + + +def main() -> None: + runpy.run_module('rst_code_example_pipeline.check_code_block', + run_name='__main__', alter_sys=True) diff --git a/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/cli/extract.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/cli/extract.py new file mode 100644 index 000000000..a2f25bd3d --- /dev/null +++ b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/cli/extract.py @@ -0,0 +1,6 @@ +import runpy + + +def main() -> None: + runpy.run_module('rst_code_example_pipeline.extract_projects', + run_name='__main__', alter_sys=True) diff --git a/frontend/py_modules/code_projects/colors.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/colors.py similarity index 97% rename from frontend/py_modules/code_projects/colors.py rename to frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/colors.py index cad3789e8..e88cdd207 100644 --- a/frontend/py_modules/code_projects/colors.py +++ b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/colors.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, division, print_function - from collections.abc import Iterator from contextlib import contextmanager import sys diff --git a/frontend/py_modules/code_projects/toolchain.ini b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/data/toolchain.ini similarity index 100% rename from frontend/py_modules/code_projects/toolchain.ini rename to frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/data/toolchain.ini diff --git a/frontend/py_modules/code_projects/extract_projects.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/extract_projects.py similarity index 99% rename from frontend/py_modules/code_projects/extract_projects.py rename to frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/extract_projects.py index 01c1ed922..78b2b0885 100755 --- a/frontend/py_modules/code_projects/extract_projects.py +++ b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/extract_projects.py @@ -13,11 +13,11 @@ import re import json -from widget.chop import manual_chop, real_gnatchop +from .chop import manual_chop, real_gnatchop -import blocks -import fmt_utils -import toolchain_setup +from . import blocks +from . import fmt_utils +from . import toolchain_setup current_config = blocks.ConfigBlock( diff --git a/frontend/py_modules/code_projects/fmt_utils.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/fmt_utils.py similarity index 93% rename from frontend/py_modules/code_projects/fmt_utils.py rename to frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/fmt_utils.py index 24be44bb8..f5caa5f93 100644 --- a/frontend/py_modules/code_projects/fmt_utils.py +++ b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/fmt_utils.py @@ -1,6 +1,6 @@ #! /usr/bin/env python3 -import colors as C +from . import colors as C def header(strn: str) -> str: return C.col("{}\n{}\n".format(strn, '*' * len(strn)), C.Colors.BLUE) diff --git a/frontend/sphinx/widget/resource.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/resource.py similarity index 100% rename from frontend/sphinx/widget/resource.py rename to frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/resource.py diff --git a/frontend/py_modules/code_projects/toolchain_info.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/toolchain_info.py similarity index 88% rename from frontend/py_modules/code_projects/toolchain_info.py rename to frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/toolchain_info.py index bdae8c293..cbcb57a3d 100644 --- a/frontend/py_modules/code_projects/toolchain_info.py +++ b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/toolchain_info.py @@ -1,10 +1,8 @@ #! /usr/bin/env python3 -import os import re import configparser - -TOOLCHAIN_CONFIG = os.path.dirname(os.path.realpath(__file__)) + "/" + "toolchain.ini" +from importlib.resources import files TOOLCHAIN_PATH: dict[str, str] = {} TOOLCHAINS: dict[str, list[str]] = {} @@ -12,8 +10,9 @@ def init_toolchain_info() -> None: config = configparser.ConfigParser() - - config.read(TOOLCHAIN_CONFIG) + config.read_string( + files('rst_code_example_pipeline').joinpath('data/toolchain.ini').read_text() + ) DEFAULT_VERSION['gnat'] = config['default_version']['gnat'] DEFAULT_VERSION['gnatprove'] = config['default_version']['gnatprove'] diff --git a/frontend/py_modules/code_projects/toolchain_setup.py b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/toolchain_setup.py similarity index 96% rename from frontend/py_modules/code_projects/toolchain_setup.py rename to frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/toolchain_setup.py index b707a235d..8e8eaf43b 100644 --- a/frontend/py_modules/code_projects/toolchain_setup.py +++ b/frontend/python/rst_code_example_pipeline/src/rst_code_example_pipeline/toolchain_setup.py @@ -3,8 +3,8 @@ import os import re -import blocks -import toolchain_info as info +from . import blocks +from . import toolchain_info as info def set_toolchain(block: blocks.CodeBlock) -> None: diff --git a/frontend/python/rst_code_example_pipeline/tests/__init__.py b/frontend/python/rst_code_example_pipeline/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/python/rst_code_example_pipeline/tests/test_smoke.py b/frontend/python/rst_code_example_pipeline/tests/test_smoke.py new file mode 100644 index 000000000..c0d727c3b --- /dev/null +++ b/frontend/python/rst_code_example_pipeline/tests/test_smoke.py @@ -0,0 +1,78 @@ +""" +Smoke tests for rst_code_example_pipeline. + +Run with: + python -m unittest discover -s tests/ +or (from the project root): + python -m unittest rst_code_example_pipeline.tests.test_smoke +""" +import unittest +from unittest.mock import patch + +import rst_code_example_pipeline + + +class TestPackageMetadata(unittest.TestCase): + def test_title(self) -> None: + self.assertEqual(rst_code_example_pipeline.__title__, + 'rst_code_example_pipeline') + + def test_version(self) -> None: + self.assertRegex(rst_code_example_pipeline.__version__, + r'^\d+\.\d+\.\d+$') + + +class TestModuleImports(unittest.TestCase): + """Each module must be importable without side-effects.""" + + def test_import_colors(self) -> None: + from rst_code_example_pipeline import colors # noqa: F401 + + def test_import_fmt_utils(self) -> None: + from rst_code_example_pipeline import fmt_utils # noqa: F401 + + def test_import_checks(self) -> None: + from rst_code_example_pipeline import checks # noqa: F401 + + def test_import_blocks(self) -> None: + from rst_code_example_pipeline import blocks # noqa: F401 + + def test_import_toolchain_info(self) -> None: + from rst_code_example_pipeline import toolchain_info # noqa: F401 + + def test_import_toolchain_setup(self) -> None: + from rst_code_example_pipeline import toolchain_setup # noqa: F401 + + def test_import_check_code_block(self) -> None: + from rst_code_example_pipeline import check_code_block # noqa: F401 + + def test_import_extract_projects(self) -> None: + from rst_code_example_pipeline import extract_projects # noqa: F401 + + def test_import_check_projects(self) -> None: + from rst_code_example_pipeline import check_projects # noqa: F401 + + +class TestEntryPoints(unittest.TestCase): + """Entry-point main() functions must accept --help (exit 0).""" + + def _assert_help_exits_zero(self, entry: str) -> None: + from importlib import import_module + mod = import_module(f'rst_code_example_pipeline.cli.{entry}') + with patch('sys.argv', [entry, '--help']): + with self.assertRaises(SystemExit) as ctx: + mod.main() + self.assertEqual(ctx.exception.code, 0) + + def test_check_block_help(self) -> None: + self._assert_help_exits_zero('check_block') + + def test_extract_help(self) -> None: + self._assert_help_exits_zero('extract') + + def test_check_help(self) -> None: + self._assert_help_exits_zero('check') + + +if __name__ == '__main__': + unittest.main() diff --git a/frontend/sphinx/tests/test_chop.py b/frontend/sphinx/tests/test_chop.py index aeab04dd3..136e77579 100644 --- a/frontend/sphinx/tests/test_chop.py +++ b/frontend/sphinx/tests/test_chop.py @@ -1,7 +1,7 @@ import unittest -from widget.chop import manual_chop, cheapo_gnatchop, real_gnatchop -from widget.resource import Resource +from rst_code_example_pipeline.chop import manual_chop, cheapo_gnatchop, real_gnatchop +from rst_code_example_pipeline.resource import Resource class TestManual_Chop(unittest.TestCase): diff --git a/frontend/sphinx/tests/test_resource.py b/frontend/sphinx/tests/test_resource.py index c20f95d41..2f00216a9 100644 --- a/frontend/sphinx/tests/test_resource.py +++ b/frontend/sphinx/tests/test_resource.py @@ -1,6 +1,6 @@ import unittest -from widget.resource import Resource +from rst_code_example_pipeline.resource import Resource class TestResource(unittest.TestCase): diff --git a/frontend/sphinx/widget/widget.py b/frontend/sphinx/widget/widget.py index 8544de797..58e60e2d7 100644 --- a/frontend/sphinx/widget/widget.py +++ b/frontend/sphinx/widget/widget.py @@ -3,8 +3,8 @@ from typing import List, Match, Dict, Optional from .button import Button -from .chop import manual_chop, cheapo_gnatchop, real_gnatchop, ChopStrategy -from .resource import Resource +from rst_code_example_pipeline.chop import manual_chop, cheapo_gnatchop, real_gnatchop, ChopStrategy +from rst_code_example_pipeline.resource import Resource class ButtonException(Exception): pass diff --git a/frontend/tests/compile_blocks.py b/frontend/tests/compile_blocks.py index fcf32623f..4b63ac00d 100755 --- a/frontend/tests/compile_blocks.py +++ b/frontend/tests/compile_blocks.py @@ -28,11 +28,10 @@ import argparse import os -import colors as C import shutil from datetime import datetime -import code_projects.fmt_utils as fmt_utils +import rst_code_example_pipeline.fmt_utils as fmt_utils EXTRACTED_PROJECTS_JSON = "extracted_projects_TIMESTAMP.json" USE_TIMESTAMP = True @@ -80,13 +79,8 @@ print("Storing list of project in " + extracted_projects_json) if CALL_SCRIPTS: - PATH_CODE_PROJECTS = \ - os.path.dirname(os.path.realpath(__file__)) + \ - "/../py_modules/code_projects" - if RUN_PROJECT_EXTRACTION: - cmd_extract_projects = PATH_CODE_PROJECTS + \ - "/extract_projects.py" + cmd_extract_projects = "extract-code" cmd_extract_projects += " --build-dir " + \ os.path.abspath(args.build_dir) @@ -111,8 +105,7 @@ test_error = ret_value != 0 if RUN_PROJECT_CHECK: - cmd_check_projects = PATH_CODE_PROJECTS + \ - "/check_projects.py" + cmd_check_projects = "check-code" cmd_check_projects += " --extracted_projects " + \ extracted_projects_json diff --git a/frontend/tests/execute_rst_code_blocks.py b/frontend/tests/execute_rst_code_blocks.py index b93f4daf4..46476059f 100755 --- a/frontend/tests/execute_rst_code_blocks.py +++ b/frontend/tests/execute_rst_code_blocks.py @@ -16,7 +16,7 @@ SPHINX_PATH = (Path(__file__).parent.parent / 'sphinx').resolve() sys.path.append(str(SPHINX_PATH)) -from widget.chop import manual_chop, real_gnatchop +from rst_code_example_pipeline.chop import manual_chop, real_gnatchop from code_block import CodeBlock, get_blocks