Added Python 3.12 support.

Merge junit files.
Merge coverage files.
Extending UnitTesting to support code coverage in a matrix too.
This commit is contained in:
Patrick Lehmann
2023-10-08 17:33:34 +02:00
parent 582c5620b7
commit ec038f96e8
24 changed files with 944 additions and 339 deletions

View File

@@ -32,17 +32,17 @@ on:
python_version:
description: 'Python version.'
required: false
default: '3.11'
default: '3.12'
type: string
python_version_list:
description: 'Space separated list of Python versions to run tests with.'
required: false
default: '3.8 3.9 3.10 3.11'
default: '3.8 3.9 3.10 3.11 3.12'
type: string
system_list:
description: 'Space separated list of systems to run tests on.'
required: false
default: 'ubuntu windows mingw64 macos'
default: 'ubuntu windows macos mingw64 ucrt64'
type: string
include_list:
description: 'Space separated list of system:python items to be included into the list of test.'
@@ -102,9 +102,9 @@ jobs:
exclude_list = "${{ inputs.exclude_list }}".strip()
disable_list = "${{ inputs.disable_list }}".strip()
currentMSYS2Version = "3.10"
currentAlphaVersion = "3.12"
currentAlphaRelease = "3.12.0-alpha.1"
currentMSYS2Version = "3.11"
currentAlphaVersion = "3.13"
currentAlphaRelease = "3.13.0-alpha.1"
if systems == "":
print("::error title=Parameter::system_list is empty.")
@@ -131,8 +131,8 @@ jobs:
else:
disabled = [disable.strip() for disable in disable_list.split(" ")]
if "3.6" in versions:
print("::warning title=Deprecated::Support for Python 3.6 ended in 2021.12.23.")
if "3.7" in versions:
print("::warning title=Deprecated::Support for Python 3.7 ended in 2023.06.27.")
if "msys2" in systems:
print("::warning title=Deprecated::System 'msys2' will be replaced by 'mingw64'.")
if currentAlphaVersion in versions:
@@ -143,16 +143,17 @@ jobs:
data = {
# Python and PyPy versions supported by "setup-python" action
"python": {
"3.6": { "icon": "⚫", "until": "2021.12.23" },
"3.7": { "icon": "⚫", "until": "2023.06.27" },
"3.8": { "icon": "🔴", "until": "2024.10" },
"3.9": { "icon": "🟠", "until": "2025.10" },
"3.10": { "icon": "🟡", "until": "2026.10" },
"3.11": { "icon": "🟢", "until": "2027.10" },
"3.12": { "icon": "🟣", "until": "2028.10" },
"pypy-3.7": { "icon": "⟲🔴", "until": "????.??" },
"pypy-3.8": { "icon": "⟲🟠", "until": "????.??" },
"pypy-3.9": { "icon": "⟲🟡", "until": "????.??" },
"3.12": { "icon": "🟢", "until": "2028.10" },
# "3.13": { "icon": "🟣", "until": "2028.10" },
"pypy-3.7": { "icon": "⟲", "until": "????.??" },
"pypy-3.8": { "icon": "⟲🔴", "until": "????.??" },
"pypy-3.9": { "icon": "⟲🟠", "until": "????.??" },
"pypy-3.10": { "icon": "⟲🟡", "until": "????.??" },
},
# Runner systems (runner images) supported by GitHub Actions
"sys": {
@@ -211,6 +212,7 @@ jobs:
"sysicon": data["sys"][system]["icon"],
"system": system,
"runs-on": data["sys"][system]["runs-on"],
"runtime": "native",
"shell": data["sys"][system]["shell"],
"pyicon": data["python"][version]["icon"],
"python": currentAlphaRelease if version == currentAlphaVersion else version,
@@ -233,10 +235,13 @@ jobs:
artifact_names = {
"unittesting_xml": f"{name}-UnitTestReportSummary-XML",
"unittesting_html": f"{name}-UnitTestReportSummary-HTML",
"perftesting_xml": f"{name}-PerformanceTestReportSummary-XML",
"benchtesting_xml": f"{name}-BenchmarkTestReportSummary-XML",
"apptesting_xml": f"{name}-ApplicationTestReportSummary-XML",
"codecoverage_sqlite": f"{name}-CodeCoverage-SQLite",
"codecoverage_xml": f"{name}-CodeCoverage-XML",
"codecoverage_json": f"{name}-CodeCoverage-JSON",
"codecoverage_html": f"{name}-CodeCoverage-HTML",
"statictyping_html": f"{name}-StaticTyping-HTML",
"package_all": f"{name}-Packages",

View File

@@ -1,10 +0,0 @@
#name: Pipeline
name: Documentation
on:
push:
workflow_dispatch:
jobs:
BuildTheDocs:
uses: pyTooling/Actions/.github/workflows/BuildTheDocs.yml@dev

View File

@@ -19,15 +19,35 @@
# #
# SPDX-License-Identifier: Apache-2.0 #
# ==================================================================================================================== #
name: Publish Unit Test Results
name: Publish Code Coverage Results
on:
workflow_call:
inputs:
report_files:
description: 'Pattern of report files to upload. Can be a comma separated list.'
coverage_config:
description: 'Path to the .coveragerc file. Use pyproject.toml by default.'
required: false
default: 'artifacts/**/*.xml'
default: 'pyproject.toml'
type: string
coverage_sqlite_artifact:
description: 'Name of the SQLite coverage artifact.'
required: false
default: ''
type: string
coverage_xml_artifact:
description: 'Name of the XML coverage artifact.'
required: false
default: ''
type: string
coverage_json_artifact:
description: 'Name of the JSON coverage artifact.'
required: false
default: ''
type: string
coverage_html_artifact:
description: 'Name of the HTML coverage artifact.'
required: false
default: ''
type: string
secrets:
codacy_token:
@@ -35,8 +55,8 @@ on:
required: true
jobs:
PublishTestResults:
name: 📊 Publish Test Results
PublishCoverageResults:
name: 📊 Publish Code Coverage Results
runs-on: ubuntu-latest
if: always()
@@ -49,6 +69,134 @@ jobs:
with:
path: artifacts
- name: 🔧 Install coverage and tomli
run: |
python -m pip install --disable-pip-version-check -U coverage[toml] tomli
- name: 🔁 Extract configurations from pyproject.toml
id: getVariables
shell: python
run: |
from os import getenv
from pathlib import Path
from sys import version
from textwrap import dedent
print(f"Python: {version}")
from tomli import load as tomli_load
htmlDirectory = Path("htmlcov")
xmlFile = Path("./coverage.xml")
jsonFile = Path("./coverage.json")
coverageRC = "${{ inputs.coverage_config }}".strip()
# Read output paths from 'pyproject.toml' file
if coverageRC == "pyproject.toml":
pyProjectFile = Path("pyproject.toml")
if pyProjectFile.exists():
with pyProjectFile.open("rb") as file:
pyProjectSettings = tomli_load(file)
htmlDirectory = Path(pyProjectSettings["tool"]["coverage"]["html"]["directory"])
xmlFile = Path(pyProjectSettings["tool"]["coverage"]["xml"]["output"])
jsonFile = Path(pyProjectSettings["tool"]["coverage"]["json"]["output"])
else:
print(f"File '{pyProjectFile}' not found and no '.coveragerc' file specified.")
# Read output paths from '.coveragerc' file
elif len(coverageRC) > 0:
coverageRCFile = Path(coverageRC)
if coverageRCFile.exists():
with coverageRCFile.open("rb") as file:
coverageRCSettings = tomli_load(file)
htmlDirectory = Path(coverageRCSettings["html"]["directory"])
xmlFile = Path(coverageRCSettings["xml"]["output"])
jsonFile = Path(coverageRCSettings["json"]["output"])
else:
print(f"File '{coverageRCFile}' not found.")
# Write jobs to special file
github_output = Path(getenv("GITHUB_OUTPUT"))
print(f"GITHUB_OUTPUT: {github_output}")
with github_output.open("a+", encoding="utf-8") as f:
f.write(dedent(f"""\
coverage_report_html_directory={htmlDirectory.as_posix()}
coverage_report_xml={xmlFile}
coverage_report_json={jsonFile}
"""))
print(f"DEBUG:\n html={htmlDirectory}\n xml={xmlFile}\n json={jsonFile}")
- name: Rename .coverage files and collect them all to coverage/
run: |
mkdir -p coverage
find . -type f -path "*artifacts*SQLite*.coverage" -exec sh -c 'cp -v $0 "coverage/$(basename $0).$(basename $(dirname $0))"' {} ';'
tree -a coverage
- name: Combine SQLite files (using Coverage.py)
if: inputs.coverage_xml_artifact != ''
run: coverage combine coverage/
- name: Report code coverage
run: coverage report --rcfile=pyproject.toml --data-file=.coverage
- name: Convert to XML format (Cobertura)
if: inputs.coverage_xml_artifact != ''
run: coverage xml --data-file=.coverage
- name: Convert to JSON format
if: inputs.coverage_json_artifact != ''
run: coverage json --data-file=.coverage
- name: Convert to HTML format
if: inputs.coverage_html_artifact != ''
run: |
coverage html --data-file=.coverage -d report/coverage/html
rm report/coverage/html/.gitignore
tree -a report/coverage/html
- name: 📤 Upload 'Coverage SQLite Database' artifact
if: inputs.coverage_sqlite_artifact != ''
continue-on-error: true
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.coverage_sqlite_artifact }}
path: .coverage
if-no-files-found: error
retention-days: 1
- name: 📤 Upload 'Coverage XML Report' artifact
if: inputs.coverage_xml_artifact != ''
continue-on-error: true
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.coverage_xml_artifact }}
path: ${{ steps.getVariables.outputs.coverage_report_xml }}
if-no-files-found: error
retention-days: 1
- name: 📤 Upload 'Coverage JSON Report' artifact
if: inputs.coverage_json_artifact != ''
continue-on-error: true
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.coverage_json_artifact }}
path: ${{ steps.getVariables.outputs.coverage_report_json }}
if-no-files-found: error
retention-days: 1
- name: 📤 Upload 'Coverage HTML Report' artifact
if: inputs.coverage_html_artifact != ''
continue-on-error: true
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.coverage_html_artifact }}
path: ${{ steps.getVariables.outputs.coverage_report_html_directory }}
if-no-files-found: error
retention-days: 1
- name: 📊 Publish code coverage at CodeCov
if: inputs.CodeCov == true
continue-on-error: true

View File

@@ -24,12 +24,6 @@ name: Publish Unit Test Results
on:
workflow_call:
inputs:
report_files:
description: 'Pattern of report files to upload. Can be a comma separated list.'
required: false
default: 'artifacts/**/*.xml'
type: string
jobs:
PublishTestResults:
@@ -46,9 +40,35 @@ jobs:
with:
path: artifacts
- name: 🔧 Install junitparser
run: |
python -m pip install --disable-pip-version-check -U junitparser
- name: Move JUnit files and collect them all to junit/
run: |
mkdir -p junit
find . -type f -path "*artifacts*UnitTestReportSummary*.xml" -exec sh -c 'cp -v $0 "junit/$(basename $(dirname $0)).$(basename $0)"' {} ';'
tree -a junit
- name: 🔁 Merge JUnit Unit Test Summaries
shell: python
run: |
from pathlib import Path
from junitparser import JUnitXml
junitDirectory = Path("junit")
junitXml = None
for file in junitDirectory.iterdir():
if junitXml is None:
junitXml = JUnitXml.fromfile(file)
else:
junitXml += JUnitXml.fromfile(file)
junitXml.write(junitDirectory / "merged.xml")
- name: 📊 Publish Unit Test Results
uses: dorny/test-reporter@v1
with:
name: Unit Test Results
path: ${{ inputs.report_files }}
path: junit/merged.xml
reporter: java-junit

View File

@@ -20,7 +20,7 @@
# #
# SPDX-License-Identifier: Apache-2.0 #
# ==================================================================================================================== #
name: Unit Testing
name: Unit Testing (Matrix)
on:
workflow_call:
@@ -54,16 +54,45 @@ on:
required: false
default: 'unit'
type: string
artifact:
coverage_config:
description: 'Path to the .coveragerc file. Use pyproject.toml by default.'
required: false
default: 'pyproject.toml'
type: string
unittest_xml_artifact:
description: "Generate unit test report with junitxml and upload results as an artifact."
required: false
default: ''
type: string
unittest_html_artifact:
description: "Generate unit test report with junitxml and upload results as an artifact."
required: false
default: ''
type: string
coverage_sqlite_artifact:
description: 'Name of the SQLite coverage artifact.'
required: false
default: ''
type: string
coverage_xml_artifact:
description: 'Name of the XML coverage artifact.'
required: false
default: ''
type: string
coverage_json_artifact:
description: 'Name of the JSON coverage artifact.'
required: false
default: ''
type: string
coverage_html_artifact:
description: 'Name of the HTML coverage artifact.'
required: false
default: ''
type: string
jobs:
UnitTesting:
name: ${{ matrix.sysicon }} ${{ matrix.pyicon }} Unit Tests using Python ${{ matrix.python }}
name: ${{ matrix.sysicon }} ${{ matrix.pyicon }} Unit Tests - Python ${{ matrix.python }}
runs-on: ${{ matrix.runs-on }}
strategy:
@@ -79,6 +108,12 @@ jobs:
- name: ⏬ Checkout repository
uses: actions/checkout@v4
- name: 🔧 Install dependencies (system Python for Python shell)
if: matrix.system == 'msys2'
shell: pwsh
run: |
py -3.9 -m pip install --disable-pip-version-check -U tomli
- name: Compute pacman/pacboy packages
id: pacboy
if: matrix.system == 'msys2'
@@ -87,6 +122,9 @@ jobs:
from os import getenv
from pathlib import Path
from re import compile
from sys import version
print(f"Python: {version}")
def loadRequirementsFile(requirementsFile: Path):
requirements = []
@@ -111,13 +149,14 @@ jobs:
dependencies = [req.strip() for req in requirements.split(" ")]
packages = {
"pip": "python-pip:p",
"wheel": "python-wheel:p",
"coverage": "python-coverage:p",
"lxml": "python-lxml:p",
"ruamel.yaml": "python-ruamel-yaml:p python-ruamel.yaml.clib:p",
"numpy": "python-numpy:p",
"igraph": "igraph:p",
"lxml": "python-lxml:p",
"numpy": "python-numpy:p",
"pip": "python-pip:p",
"ruamel.yaml": "python-ruamel-yaml:p python-ruamel.yaml.clib:p",
"tomli": "python-tomli:p",
"wheel": "python-wheel:p",
}
subPackages = {
"pyTooling": {
@@ -127,7 +166,7 @@ jobs:
regExp = compile(r"(?P<PackageName>[\w_\-\.]+)(?:\[(?P<SubPackages>(?:\w+)(?:,\w+)*)\])?(?:\s*(?P<Comperator>[<>=]+)\s*)(?P<Version>\d+(?:\.\d+)*)(?:-(?P<VersionExtension>\w+))?")
pacboyPackages = set(("python-pip:p", "python-wheel:p"))
pacboyPackages = set(("python-pip:p", "python-wheel:p", "python-tomli:p"))
print(f"Processing dependencies ({len(dependencies)}):")
for dependency in dependencies:
print(f" {dependency}")
@@ -173,10 +212,10 @@ jobs:
with:
python-version: ${{ matrix.python }}
- name: 🔧 Install wheel and pip dependencies (native)
- name: 🔧 Install wheel,tomli and pip dependencies (native)
if: matrix.system != 'msys2'
run: |
python -m pip install --disable-pip-version-check -U wheel
python -m pip install --disable-pip-version-check -U wheel tomli
python -m pip install --disable-pip-version-check ${{ inputs.requirements }}
- name: 🔧 Install pip dependencies (MSYS2)
@@ -188,33 +227,164 @@ jobs:
python -m pip install --disable-pip-version-check ${{ inputs.requirements }}
fi
- name: ☑ Run unit tests (Windows)
if: matrix.system == 'windows'
- name: 🔁 Extract configurations from pyproject.toml
id: getVariables
shell: python
run: |
$env:ENVIRONMENT_NAME = "${{ matrix.envname }}"
$env:PYTHONPATH = (Get-Location).ToString()
cd "${{ inputs.tests_directory || '.' }}"
$PYTEST_ARGS = if ("${{ inputs.artifact }}") { "--junitxml=TestReportSummary.xml" } else { "" }
Write-Host "python -m pytest -rA $PYTEST_ARGS --color=yes ${{ inputs.unittest_directory }}"
python -m pytest -rA $PYTEST_ARGS --color=yes ${{ inputs.unittest_directory }}
from os import getenv
from pathlib import Path
from sys import version
from textwrap import dedent
print(f"Python: {version}")
from tomli import load as tomli_load
htmlDirectory = Path("htmlcov")
xmlFile = Path("./coverage.xml")
jsonFile = Path("./coverage.json")
coverageRC = "${{ inputs.coverage_config }}".strip()
# Read output paths from 'pyproject.toml' file
if coverageRC == "pyproject.toml":
pyProjectFile = Path("pyproject.toml")
if pyProjectFile.exists():
with pyProjectFile.open("rb") as file:
pyProjectSettings = tomli_load(file)
htmlDirectory = Path(pyProjectSettings["tool"]["coverage"]["html"]["directory"])
xmlFile = Path(pyProjectSettings["tool"]["coverage"]["xml"]["output"])
jsonFile = Path(pyProjectSettings["tool"]["coverage"]["json"]["output"])
else:
print(f"File '{pyProjectFile}' not found and no '.coveragerc' file specified.")
# Read output paths from '.coveragerc' file
elif len(coverageRC) > 0:
coverageRCFile = Path(coverageRC)
if coverageRCFile.exists():
with coverageRCFile.open("rb") as file:
coverageRCSettings = tomli_load(file)
htmlDirectory = Path(coverageRCSettings["html"]["directory"])
xmlFile = Path(coverageRCSettings["xml"]["output"])
jsonFile = Path(coverageRCSettings["json"]["output"])
else:
print(f"File '{coverageRCFile}' not found.")
# Write jobs to special file
github_output = Path(getenv("GITHUB_OUTPUT"))
print(f"GITHUB_OUTPUT: {github_output}")
with github_output.open("a+", encoding="utf-8") as f:
f.write(dedent(f"""\
unittest_report_html_directory={htmlDirectory}
coverage_report_html_directory={htmlDirectory.as_posix()}
coverage_report_xml={xmlFile}
coverage_report_json={jsonFile}
"""))
print(f"DEBUG:\n html={htmlDirectory}\n xml={xmlFile}\n json={jsonFile}")
- name: ☑ Run unit tests (Ubuntu/macOS)
if: matrix.system != 'windows'
run: |
export ENVIRONMENT_NAME="${{ matrix.envname }}"
export PYTHONPATH=$(pwd)
ABSDIR=$(pwd)
cd "${{ inputs.tests_directory || '.' }}"
[ -n '${{ inputs.coverage_config }}' ] && PYCOV_ARGS="--cov-config=${ABSDIR}/${{ inputs.coverage_config }}" || unset PYCOV_ARGS
[ -n '${{ inputs.artifact }}' ] && PYTEST_ARGS='--junitxml=TestReportSummary.xml' || unset PYTEST_ARGS
echo "python -m pytest -rA $PYTEST_ARGS --color=yes ${{ inputs.unittest_directory }}"
python -m pytest -rA $PYTEST_ARGS --color=yes ${{ inputs.unittest_directory }}
# cd "${{ inputs.tests_directory || '.' }}"
[ -n '${{ inputs.unittest_xml_artifact }}' ] && PYTEST_ARGS='--junitxml=report/unit/TestReportSummary.xml' || unset PYTEST_ARGS
if [ -n '${{ inputs.coverage_config }}' ]; then
echo "coverage run --data-file=.coverage --rcfile=pyproject.toml -m pytest -rA $PYTEST_ARGS --color=yes ${{ inputs.tests_directory || '.' }}/${{ inputs.unittest_directory }}"
coverage run --data-file=.coverage --rcfile=pyproject.toml -m pytest -rA $PYTEST_ARGS --color=yes ${{ inputs.tests_directory || '.' }}/${{ inputs.unittest_directory }}
else
echo "python -m pytest -rA $PYTEST_ARGS --color=yes ${{ inputs.tests_directory || '.' }}/${{ inputs.unittest_directory }}"
python -m pytest -rA $PYTEST_ARGS --color=yes ${{ inputs.tests_directory || '.' }}/${{ inputs.unittest_directory }}
fi
- name: ☑ Run unit tests (Windows)
if: matrix.system == 'windows'
run: |
$env:ENVIRONMENT_NAME = "${{ matrix.envname }}"
$env:PYTHONPATH = (Get-Location).ToString()
# cd "${{ inputs.tests_directory || '.' }}"
$PYTEST_ARGS = if ("${{ inputs.unittest_xml_artifact }}") { "--junitxml=report/unit/TestReportSummary.xml" } else { "" }
if ("${{ inputs.coverage_config }}") {
Write-Host "coverage run --data-file=.coverage --rcfile=pyproject.toml -m pytest -rA --color=yes ${{ inputs.tests_directory || '.' }}/${{ inputs.unittest_directory }}"
coverage run --data-file=.coverage --rcfile=pyproject.toml -m pytest -rA $PYTEST_ARGS --color=yes ${{ inputs.tests_directory || '.' }}/${{ inputs.unittest_directory }}
} else {
Write-Host "python -m pytest -rA $PYTEST_ARGS --color=yes ${{ inputs.tests_directory || '.' }}/${{ inputs.unittest_directory }}"
python -m pytest -rA $PYTEST_ARGS --color=yes ${{ inputs.tests_directory || '.' }}/${{ inputs.unittest_directory }}
}
- name: Convert to XML format (Cobertura)
if: inputs.coverage_xml_artifact != ''
run: coverage xml --data-file=.coverage
- name: Convert to JSON format
if: inputs.coverage_json_artifact != ''
run: coverage json --data-file=.coverage
- name: Convert to HTML format
if: inputs.coverage_html_artifact != ''
run: |
coverage html --data-file=.coverage -d ${{ steps.getVariables.outputs.coverage_report_html_directory }}
rm ${{ steps.getVariables.outputs.coverage_report_html_directory }}/.gitignore
- name: 📤 Upload 'TestReportSummary.xml' artifact
if: inputs.artifact != ''
if: inputs.unittest_xml_artifact != ''
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.artifact }}-${{ matrix.system }}-${{ matrix.python }}
path: ${{ inputs.tests_directory || '.' }}/TestReportSummary.xml
name: ${{ inputs.unittest_xml_artifact }}-${{ matrix.system }}-${{ matrix.runtime }}-${{ matrix.python }}
path: report/unit/TestReportSummary.xml
if-no-files-found: error
retention-days: 1
# - name: 📤 Upload 'Unit Tests HTML Report' artifact
# if: inputs.unittest_html_artifact != ''
# continue-on-error: true
# uses: actions/upload-artifact@v3
# with:
# name: ${{ inputs.unittest_html_artifact }}-${{ matrix.system }}-${{ matrix.runtime }}-${{ matrix.python }}
# path: ${{ steps.getVariables.outputs.unittest_report_html_directory }}
# if-no-files-found: error
# retention-days: 1
- name: 📤 Upload 'Coverage SQLite Database' artifact
if: inputs.coverage_sqlite_artifact != ''
continue-on-error: true
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.coverage_sqlite_artifact }}-${{ matrix.system }}-${{ matrix.runtime }}-${{ matrix.python }}
path: .coverage
if-no-files-found: error
retention-days: 1
- name: 📤 Upload 'Coverage XML Report' artifact
if: inputs.coverage_xml_artifact != ''
continue-on-error: true
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.coverage_xml_artifact }}-${{ matrix.system }}-${{ matrix.runtime }}-${{ matrix.python }}
path: ${{ steps.getVariables.outputs.coverage_report_xml }}
if-no-files-found: error
retention-days: 1
- name: 📤 Upload 'Coverage JSON Report' artifact
if: inputs.coverage_json_artifact != ''
continue-on-error: true
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.coverage_json_artifact }}-${{ matrix.system }}-${{ matrix.runtime }}-${{ matrix.python }}
path: ${{ steps.getVariables.outputs.coverage_report_json }}
if-no-files-found: error
retention-days: 1
- name: 📤 Upload 'Coverage HTML Report' artifact
if: inputs.coverage_html_artifact != ''
continue-on-error: true
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.coverage_html_artifact }}-${{ matrix.system }}-${{ matrix.runtime }}-${{ matrix.python }}
path: ${{ steps.getVariables.outputs.coverage_report_html_directory }}
if-no-files-found: error
retention-days: 1

View File

@@ -9,18 +9,15 @@ jobs:
uses: pyTooling/Actions/.github/workflows/Parameters.yml@cov
with:
name: pyDummy
python_version_list: "3.11"
# python_version_list: "3.7 3.8 pypy-3.8 3.9 pypy-3.9 3.10 3.11"
exclude_list: "windows:pypy-3.8 windows:pypy-3.9"
# disable_list: "windows:3.11"
python_version_list: "3.8 3.9 3.10 3.11 3.12 pypy-3.8 pypy-3.9 pypy-3.10"
disable_list: "windows:pypy-3.10"
PlatformTestingParams:
uses: pyTooling/Actions/.github/workflows/Parameters.yml@cov
with:
name: Platform
python_version_list: ""
system_list: "ubuntu"
# system_list: "ubuntu windows macos mingw32 mingw64 clang64 ucrt64"
system_list: "ubuntu windows macos mingw32 mingw64 clang64 ucrt64"
UnitTesting:
uses: pyTooling/Actions/.github/workflows/UnitTesting.yml@cov
@@ -28,7 +25,12 @@ jobs:
- UnitTestingParams
with:
jobs: ${{ needs.UnitTestingParams.outputs.python_jobs }}
artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).unittesting_xml }}
unittest_xml_artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).unittesting_xml }}
unittest_html_artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).unittesting_html }}
# coverage_sqlite_artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_sqlite }}
# coverage_xml_artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_xml }}
# coverage_json_artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_json }}
# coverage_html_artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_html }}
PlatformTesting:
uses: pyTooling/Actions/.github/workflows/UnitTesting.yml@cov
@@ -36,27 +38,24 @@ jobs:
- PlatformTestingParams
with:
jobs: ${{ needs.PlatformTestingParams.outputs.python_jobs }}
tests_directory: ""
unittest_directory: tests/unit/Platform
artifact: ${{ fromJson(needs.PlatformTestingParams.outputs.artifact_names).unittesting_xml }}
# tests_directory: ""
unittest_directory: platform
unittest_xml_artifact: ${{ fromJson(needs.PlatformTestingParams.outputs.artifact_names).unittesting_xml }}
unittest_html_artifact: ${{ fromJson(needs.PlatformTestingParams.outputs.artifact_names).unittesting_html }}
coverage_sqlite_artifact: ${{ fromJson(needs.PlatformTestingParams.outputs.artifact_names).codecoverage_sqlite }}
coverage_xml_artifact: ${{ fromJson(needs.PlatformTestingParams.outputs.artifact_names).codecoverage_xml }}
coverage_json_artifact: ${{ fromJson(needs.PlatformTestingParams.outputs.artifact_names).codecoverage_json }}
coverage_html_artifact: ${{ fromJson(needs.PlatformTestingParams.outputs.artifact_names).codecoverage_html }}
Coverage:
uses: pyTooling/Actions/.github/workflows/CoverageCollection.yml@cov
needs:
- UnitTestingParams
with:
python_version: ${{ needs.UnitTestingParams.outputs.python_version }}
artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_html }}
secrets:
codacy_token: ${{ secrets.CODACY_PROJECT_TOKEN }}
PublishCoverageResults:
uses: pyTooling/Actions/.github/workflows/PublishCoverageResults.yml@cov
needs:
- UnitTesting
- Coverage
secrets:
codacy_token: ${{ secrets.CODACY_PROJECT_TOKEN }}
# Coverage:
# uses: pyTooling/Actions/.github/workflows/CoverageCollection.yml@cov
# needs:
# - UnitTestingParams
# with:
# python_version: ${{ needs.UnitTestingParams.outputs.python_version }}
# artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_html }}
# secrets:
# codacy_token: ${{ secrets.CODACY_PROJECT_TOKEN }}
StaticTypeCheck:
uses: pyTooling/Actions/.github/workflows/StaticTypeCheck.yml@cov
@@ -69,44 +68,38 @@ jobs:
html_report: 'htmlmypy'
html_artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).statictyping_html }}
PublishCoverageResults:
uses: pyTooling/Actions/.github/workflows/PublishCoverageResults.yml@cov
needs:
- UnitTestingParams
- UnitTesting
- PlatformTesting
# - Coverage
with:
coverage_sqlite_artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_sqlite }}
coverage_xml_artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_xml }}
coverage_json_artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_json }}
coverage_html_artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_html }}
secrets:
codacy_token: ${{ secrets.CODACY_PROJECT_TOKEN }}
PublishTestResults:
uses: pyTooling/Actions/.github/workflows/PublishTestResults.yml@cov
needs:
- UnitTesting
- PlatformTesting
Package:
uses: pyTooling/Actions/.github/workflows/Package.yml@cov
needs:
- UnitTestingParams
- Coverage
- UnitTesting
# - Coverage
- PlatformTesting
with:
python_version: ${{ needs.UnitTestingParams.outputs.python_version }}
artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).package_all }}
Release:
uses: pyTooling/Actions/.github/workflows/Release.yml@cov
if: startsWith(github.ref, 'refs/tags')
needs:
- UnitTesting
- Coverage
- StaticTypeCheck
- Package
PublishOnPyPI:
uses: pyTooling/Actions/.github/workflows/PublishOnPyPI.yml@cov
if: startsWith(github.ref, 'refs/tags')
needs:
- UnitTestingParams
- Release
- Package
with:
python_version: ${{ needs.UnitTestingParams.outputs.python_version }}
requirements: -r dist/requirements.txt
artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).package_all }}
secrets:
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
# VerifyDocs:
# uses: pyTooling/Actions/.github/workflows/VerifyDocs.yml@cov
# needs:
@@ -114,33 +107,60 @@ jobs:
# with:
# python_version: ${{ needs.UnitTestingParams.outputs.python_version }}
# BuildTheDocs:
# uses: pyTooling/Actions/.github/workflows/BuildTheDocs.yml@cov
# needs:
# - UnitTestingParams
## - VerifyDocs
# with:
# artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).documentation_html }}
BuildTheDocs:
uses: pyTooling/Actions/.github/workflows/BuildTheDocs.yml@cov
needs:
- UnitTestingParams
# - VerifyDocs
with:
artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).documentation_html }}
PublishToGitHubPages:
uses: pyTooling/Actions/.github/workflows/PublishToGitHubPages.yml@cov
needs:
- UnitTestingParams
# - BuildTheDocs
- Coverage
- BuildTheDocs
# - Coverage
- PublishCoverageResults
- StaticTypeCheck
with:
doc: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).documentation_html }}
coverage: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_html }}
typing: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).statictyping_html }}
ReleasePage:
uses: pyTooling/Actions/.github/workflows/Release.yml@cov
if: startsWith(github.ref, 'refs/tags')
needs:
- UnitTesting
- PlatformTesting
# - Coverage
# - StaticTypeCheck
- Package
- PublishToGitHubPages
PublishOnPyPI:
uses: pyTooling/Actions/.github/workflows/PublishOnPyPI.yml@cov
if: startsWith(github.ref, 'refs/tags')
needs:
- UnitTestingParams
- ReleasePage
# - Package
with:
python_version: ${{ needs.UnitTestingParams.outputs.python_version }}
requirements: -r dist/requirements.txt
artifact: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).package_all }}
secrets:
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
ArtifactCleanUp:
uses: pyTooling/Actions/.github/workflows/ArtifactCleanUp.yml@cov
needs:
- UnitTestingParams
- PlatformTestingParams
- UnitTesting
- PlatformTesting
- Coverage
# - Coverage
- StaticTypeCheck
# - BuildTheDocs
- PublishToGitHubPages
@@ -150,6 +170,22 @@ jobs:
package: ${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).package_all }}
remaining: |
${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).unittesting_xml }}-*
${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).unittesting_html }}-*
${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_sqlite }}-*
${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_xml }}-*
${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_json }}-*
${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_html }}-*
${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).unittesting_xml }}
${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).unittesting_html }}
${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_sqlite }}
${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_xml }}
${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_json }}
${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).codecoverage_html }}
${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).statictyping_html }}
${{ fromJson(needs.UnitTestingParams.outputs.artifact_names).documentation_html }}
${{ fromJson(needs.PlatformTestingParams.outputs.artifact_names).unittesting_xml }}-*
${{ fromJson(needs.PlatformTestingParams.outputs.artifact_names).unittesting_html }}-*
${{ fromJson(needs.PlatformTestingParams.outputs.artifact_names).codecoverage_sqlite }}-*
${{ fromJson(needs.PlatformTestingParams.outputs.artifact_names).codecoverage_xml }}-*
${{ fromJson(needs.PlatformTestingParams.outputs.artifact_names).codecoverage_json }}-*
${{ fromJson(needs.PlatformTestingParams.outputs.artifact_names).codecoverage_html }}-*

4
.gitignore vendored
View File

@@ -24,8 +24,8 @@ coverage.xml
# Sphinx
doc/_build/
doc/pyTooling/**/*.*
!doc/pyTooling/index.rst
doc/pyDummy/**/*.*
!doc/pyDummy/index.rst
# BuildTheDocs
doc/_theme/**/*.*

View File

@@ -44,31 +44,31 @@ Complex Example
The following instantiation example creates 3 jobs from the same template, but with differing input parameters. The
first job `UnitTestingParams` might be used to create a job matrix of unit tests. It creates the cross of default
systems (Windows, Ubuntu, MacOS, MinGW64) and the given list of Python versions including some mypy versions. In
systems (Windows, Ubuntu, MacOS, MinGW64, UCRT64) and the given list of Python versions including some mypy versions. In
addition a list of excludes (marked as :deletion:`deletions`) and includes (marked as :addition:`additions`) is handed
over resulting in the following combinations:
+------------+-------------+-------------+-------------+--------------+-------------------------+------------+-------------+------------------------------+------------------------------+
| Version | 3.7 🔴 | 3.8 🟠 | 3.9 🟡 | 3.10 🟢 | 3.11 🟢 | 3.12.a1 🟣 | pypy-3.7 🔴 | pypy-3.8 🟠 | pypy-3.9 🟡 |
+============+=============+=============+=============+==============+=========================+============+=============+==============================+==============================+
| Windows 🧊 | windows:3.7 | windows:3.8 | windows:3.9 | windows:3.10 | | | | :deletion:`windows:pypy-3.8` | :deletion:`windows:pypy-3.9` |
+------------+-------------+-------------+-------------+--------------+-------------------------+------------+-------------+------------------------------+------------------------------+
| Ubuntu 🐧 | ubuntu:3.7 | ubuntu:3.8 | ubuntu:3.9 | ubuntu:3.10 | :addition:`ubuntu:3.11` | | | ubuntu:pypy-3.8 | ubuntu:pypy-3.9 |
+------------+-------------+-------------+-------------+--------------+-------------------------+------------+-------------+------------------------------+------------------------------+
| MacOS 🍎 | macos:3.7 | macos:3.8 | macos:3.9 | macos:3.10 | :addition:`macos:3.11` | | | macos:pypy-3.8 | macos:pypy-3.9 |
+------------+-------------+-------------+-------------+--------------+-------------------------+------------+-------------+------------------------------+------------------------------+
+------------+-------------+-------------+--------------+--------------+-------------------------+------------+-------------+------------------------------+-------------------------------+
| Version | 3.8 🔴 | 3.9 🟠 | 3.10 🟡 | 3.11 🟢 | 3.12 🟢 | 3.13.a1 🟣 | pypy-3.8 🔴 | pypy-3.9 🟠 | pypy-3.10 🟡 |
+============+=============+=============+==============+==============+=========================+============+=============+==============================+===============================+
| Windows 🧊 | windows:3.8 | windows:3.9 | windows:3.10 | windows:3.11 | | | | :deletion:`windows:pypy-3.9` | :deletion:`windows:pypy-3.10` |
+------------+-------------+-------------+--------------+--------------+-------------------------+------------+-------------+------------------------------+-------------------------------+
| Ubuntu 🐧 | ubuntu:3.8 | ubuntu:3.9 | ubuntu:3.10 | ubuntu:3.11 | :addition:`ubuntu:3.12` | | | ubuntu:pypy-3.9 | ubuntu:pypy-3.10 |
+------------+-------------+-------------+--------------+--------------+-------------------------+------------+-------------+------------------------------+-------------------------------+
| MacOS 🍎 | macos:3.8 | macos:3.9 | macos:3.10 | macos:3.11 | :addition:`macos:3.12` | | | macos:pypy-3.9 | macos:pypy-3.10 |
+------------+-------------+-------------+--------------+--------------+-------------------------+------------+-------------+------------------------------+-------------------------------+
| MSYS 🟪 | | | | | | | | | |
+------------+-------------+-------------+-------------+--------------+-------------------------+------------+-------------+------------------------------+------------------------------+
+------------+-------------+-------------+--------------+--------------+-------------------------+------------+-------------+------------------------------+-------------------------------+
| MinGW32 ⬛ | | | | | | | | | |
+------------+-------------+-------------+-------------+--------------+-------------------------+------------+-------------+------------------------------+------------------------------+
| MinGW64 🟦 | | | | mingw64:3.10 | | | | | |
+------------+-------------+-------------+-------------+--------------+-------------------------+------------+-------------+------------------------------+------------------------------+
+------------+-------------+-------------+--------------+--------------+-------------------------+------------+-------------+------------------------------+-------------------------------+
| MinGW64 🟦 | | | | mingw64:3.11 | | | | | |
+------------+-------------+-------------+--------------+--------------+-------------------------+------------+-------------+------------------------------+-------------------------------+
| Clang32 🟫 | | | | | | | | | |
+------------+-------------+-------------+-------------+--------------+-------------------------+------------+-------------+------------------------------+------------------------------+
+------------+-------------+-------------+--------------+--------------+-------------------------+------------+-------------+------------------------------+-------------------------------+
| Clang64 🟧 | | | | | | | | | |
+------------+-------------+-------------+-------------+--------------+-------------------------+------------+-------------+------------------------------+------------------------------+
+------------+-------------+-------------+--------------+--------------+-------------------------+------------+-------------+------------------------------+-------------------------------+
| UCRT64 🟨 | | | | | | | | | |
+------------+-------------+-------------+-------------+--------------+-------------------------+------------+-------------+------------------------------+------------------------------+
+------------+-------------+-------------+--------------+--------------+-------------------------+------------+-------------+------------------------------+-------------------------------+
.. code-block:: yaml
@@ -84,22 +84,22 @@ over resulting in the following combinations:
uses: pyTooling/Actions/.github/workflows/Parameters.yml@r0
with:
name: pyTooling
python_version_list: "3.7 3.8 3.9 3.10 pypy-3.8 pypy-3.9"
include_list: "ubuntu:3.11 macos:3.11"
exclude_list: "windows:pypy-3.8 windows:pypy-3.9"
python_version_list: "3.8 3.9 3.10 3.11 pypy-3.9 pypy-3.10"
include_list: "ubuntu:3.12 macos:3.12"
exclude_list: "windows:pypy-3.9 windows:pypy-3.10"
PerformanceTestingParams:
uses: pyTooling/Actions/.github/workflows/Parameters.yml@r0
with:
name: pyTooling
python_version_list: "3.10 3.11"
python_version_list: "3.11 3.12"
system_list: "ubuntu windows macos"
PlatformTestingParams:
uses: pyTooling/Actions/.github/workflows/Parameters.yml@dev
with:
name: pyTooling
python_version_list: "3.10"
python_version_list: "3.12"
system_list: "ubuntu windows macos mingw32 mingw64 clang64 ucrt64"
Parameters
@@ -125,7 +125,7 @@ python_version
+----------------+----------+----------+----------+
| Parameter Name | Required | Type | Default |
+================+==========+==========+==========+
| python_version | optional | string | ``3.11`` |
| python_version | optional | string | ``3.12`` |
+----------------+----------+----------+----------+
Python version to be used for all jobs requiring a single Python version.
@@ -134,52 +134,54 @@ Python version to be used for all jobs requiring a single Python version.
python_version_list
===================
+----------------------+----------+----------+---------------------------+
+----------------------+----------+----------+----------------------------+
| Parameter Name | Required | Type | Default |
+======================+==========+==========+===========================+
| python_version_list | optional | string | ``3.7 3.8 3.9 3.10 3.11`` |
+----------------------+----------+----------+---------------------------+
+======================+==========+==========+============================+
| python_version_list | optional | string | ``3.8 3.9 3.10 3.11 3.12`` |
+----------------------+----------+----------+-------------------------- -+
Space separated list of CPython versions and/or mypy version to run tests with.
**Possible values:**
* ``3.6``, ``3.7``, ``3.8``, ``3.9``, ``3.10`` , ``3.11``, ``3.12``
* ``pypy-3.7``, ``pypy-3.8``, ``pypy-3.9``
* ``3.7``, ``3.8``, ``3.9``, ``3.10`` , ``3.11``, ``3.12``, ``3.13``
* ``pypy-3.7``, ``pypy-3.8``, ``pypy-3.9``, ``pypy-3.10``
+------+-----------+------------------+-----------------------------------------+
| Icon | Version | Maintained until | Comments |
+======+===========+==================+=========================================+
| ⚫ | 3.6 | 2021.12.23 | :red:`outdated` |
| ⚫ | 3.7 | 2023.06.27 | :red:`outdated` |
+------+-----------+------------------+-----------------------------------------+
| 🔴 | 3.7 | 2023.06.27 | |
| 🔴 | 3.8 | 2024.10 | |
+------+-----------+------------------+-----------------------------------------+
| 🟠 | 3.8 | 2024.10 | |
| 🟠 | 3.9 | 2025.10 | |
+------+-----------+------------------+-----------------------------------------+
| 🟡 | 3.9 | 2025.10 | |
| 🟡 | 3.10 | 2026.10 | |
+------+-----------+------------------+-----------------------------------------+
| 🟢 | 3.10 | 2026.10 | |
| 🟢 | 3.11 | 2027.10 | |
+------+-----------+------------------+-----------------------------------------+
| 🟢 | 3.11 | 2027.10 | :green:`latest` |
| 🟢 | 3.12 | 2028.10 | :green:`latest` |
+------+-----------+------------------+-----------------------------------------+
| 🟣 | 3.12 | 2028.10 | Python 3.12 alpha (or RC) will be used. |
| 🟣 | 3.13 | 2029.10 | Python 3.13 alpha (or RC) will be used. |
+------+-----------+------------------+-----------------------------------------+
|🔴 | pypy-3.7 | ????.?? | |
| | pypy-3.7 | ????.?? | |
+------+-----------+------------------+-----------------------------------------+
|🟠 | pypy-3.8 | ????.?? | |
|🔴 | pypy-3.8 | ????.?? | |
+------+-----------+------------------+-----------------------------------------+
|🟡 | pypy-3.9 | ????.?? | |
|🟠 | pypy-3.9 | ????.?? | |
+------+-----------+------------------+-----------------------------------------+
| ⟲🟡 | pypy-3.10 | ????.?? | |
+------+-----------+------------------+-----------------------------------------+
system_list
===========
+----------------+----------+----------+----------------------------------+
+----------------+----------+----------+-----------------------------------------+
| Parameter Name | Required | Type | Default |
+================+==========+==========+==================================+
| system_list | optional | string | ``ubuntu windows mingw64 macos`` |
+----------------+----------+----------+----------------------------------+
+================+==========+==========+=========================================+
| system_list | optional | string | ``ubuntu windows macos mingw64 ucrt64`` |
+----------------+----------+----------+-----------------------------------------+
Space separated list of systems to run tests on.
@@ -193,9 +195,9 @@ Space separated list of systems to run tests on.
+======+===========+==============================+=================================================================+
| 🧊 | Windows | Windows Server 2022 (latest) | |
+------+-----------+------------------------------+-----------------------------------------------------------------+
| 🐧 | Ubuntu | Ubuntu 20.04 (LTS) (latest) | While this marked latest, Ubuntu 22.02 LTS is already provided. |
| 🐧 | Ubuntu | Ubuntu 22.04 (LTS) (latest) | |
+------+-----------+------------------------------+-----------------------------------------------------------------+
| 🍎 | MacOS | macOS Big Sur 11 (latest) | While this marked latest, macOS Monterey 12 is already provided.|
| 🍎 | MacOS | macOS Monterey 12 (latest) | While this marked latest, macOS Ventura 13 is already provided. |
+------+-----------+------------------------------+-----------------------------------------------------------------+
| 🟪 | MSYS | | |
+------+-----------+------------------------------+-----------------------------------------------------------------+
@@ -210,6 +212,7 @@ Space separated list of systems to run tests on.
| 🟨 | UCRT64 | | |
+------+-----------+------------------------------+-----------------------------------------------------------------+
Source: `Images provided by GitHub <https://github.com/actions/runner-images>`__
include_list
============
@@ -370,6 +373,9 @@ A dictionary of artifact names sharing a common prefix.
The supported artifacts are:
* ``unittesting_xml`` - UnitTesting XML summary report
* ``unittesting_html`` - UnitTesting HTML summary report
* ``codecoverage_sqlite`` - Code Coverage internal database (SQLite)
* ``codecoverage_json`` - Code Coverage JSON report
* ``codecoverage_xml`` - Code Coverage XML report
* ``codecoverage_html`` - Code Coverage HTML report
* ``statictyping_html`` - Static Type Checking HTML report

160
doc/_templates/autoapi/module.rst vendored Normal file
View File

@@ -0,0 +1,160 @@
.. # Template modified by Patrick Lehmann
* removed automodule on top, because private members are activated for autodoc (no doubled documentation).
* Made sections like 'submodules' bold text, but no headlines to reduce number of ToC levels.
{{ '=' * node.name|length }}
{{ node.name }}
{{ '=' * node.name|length }}
.. automodule:: {{ node.name }}
{##}
{%- block modules -%}
{%- if subnodes %}
**Submodules**
.. toctree::
:maxdepth: 1
{% for item in subnodes %}
{{ item.name }}
{%- endfor %}
{##}
{%- endif -%}
{%- endblock -%}
{##}
.. currentmodule:: {{ node.name }}
{##}
{%- if node.variables %}
**Variables**
{% for item, obj in node.variables.items() -%}
- :py:data:`{{ item }}`
{#{ obj|summary }#}
{% endfor -%}
{%- endif -%}
{%- if node.functions %}
**Functions**
{% for item, obj in node.functions.items() -%}
- :py:func:`{{ item }}`:
{{ obj|summary }}
{% endfor -%}
{%- endif -%}
{%- if node.exceptions %}
**Exceptions**
{% for item, obj in node.exceptions.items() -%}
- :py:exc:`{{ item }}`:
{{ obj|summary }}
{% endfor -%}
{%- endif -%}
{%- if node.classes %}
**Classes**
{% for item, obj in node.classes.items() -%}
- :py:class:`{{ item }}`:
{{ obj|summary }}
{% endfor -%}
{%- endif -%}
{%- block variables -%}
{%- if node.variables %}
---------------------
**Variables**
{#% for item, obj in node.variables.items() -%}
- :py:data:`{{ item }}`
{% endfor -%#}
{% for item, obj in node.variables.items() %}
.. autodata:: {{ item }}
:annotation:
.. code-block:: text
{{ obj|pprint|indent(6) }}
{##}
{%- endfor -%}
{%- endif -%}
{%- endblock -%}
{%- block functions -%}
{%- if node.functions %}
---------------------
**Functions**
{% for item in node.functions %}
.. autofunction:: {{ item }}
{##}
{%- endfor -%}
{%- endif -%}
{%- endblock -%}
{%- block exceptions -%}
{%- if node.exceptions %}
---------------------
**Exceptions**
{#% for item, obj in node.exceptions.items() -%}
- :py:exc:`{{ item }}`:
{{ obj|summary }}
{% endfor -%#}
{% for item in node.exceptions %}
.. autoexception:: {{ item }}
.. rubric:: Inheritance
.. inheritance-diagram:: {{ item }}
:parts: 1
{##}
{%- endfor -%}
{%- endif -%}
{%- endblock -%}
{%- block classes -%}
{%- if node.classes %}
---------------------
**Classes**
{#% for item, obj in node.classes.items() -%}
- :py:class:`{{ item }}`:
{{ obj|summary }}
{% endfor -%#}
{% for item in node.classes %}
.. autoclass:: {{ item }}
:members:
:private-members:
:special-members:
:inherited-members:
:exclude-members: __weakref__
.. rubric:: Inheritance
.. inheritance-diagram:: {{ item }}
:parts: 1
{##}
{%- endfor -%}
{%- endif -%}
{%- endblock -%}

14
doc/_templates/autoapi/package.rst vendored Normal file
View File

@@ -0,0 +1,14 @@
.. # Template created by Patrick Lehmann
Python Class Reference
######################
Reference of all packages and modules:
.. automodule:: {{ node.name }}
.. toctree::
:maxdepth: 1
{% for item in subnodes %}
{{ item.name }}
{%- endfor %}

View File

@@ -13,7 +13,7 @@ ROOT = Path(__file__).resolve().parent
sys_path.insert(0, abspath("."))
sys_path.insert(0, abspath(".."))
#sys_path.insert(0, abspath("../pyTooling"))
sys_path.insert(0, abspath("../pyDummy"))
sys_path.insert(0, abspath("_extensions"))
@@ -25,7 +25,7 @@ sys_path.insert(0, abspath("_extensions"))
# built documents.
project = "Actions"
packageInformationFile = Path(f"../{project}/__init__.py")
packageInformationFile = Path(f"../pyDummy/__init__.py")
versionInformation = extractVersionInformation(packageInformationFile)
author = versionInformation.Author
@@ -173,9 +173,11 @@ latex_documents = [
# ==============================================================================
extensions = [
# Standard Sphinx extensions
"sphinx.ext.autodoc",
"sphinx.ext.coverage",
"sphinx.ext.extlinks",
"sphinx.ext.intersphinx",
"sphinx.ext.inheritance_diagram",
"sphinx.ext.todo",
"sphinx.ext.graphviz",
"sphinx.ext.mathjax",
@@ -185,6 +187,9 @@ extensions = [
"sphinxcontrib.mermaid",
# Other extensions
"sphinx_fontawesome",
"sphinx_autodoc_typehints",
"sphinx_inline_tabs",
"autoapi.sphinx",
]
@@ -216,9 +221,9 @@ autodoc_typehints = "both"
# Sphinx.Ext.ExtLinks
# ==============================================================================
extlinks = {
"gh": ("https://GitHub.com/%s", "gh:"),
"ghissue": ("https://GitHub.com/pyTooling/Actions/issues/%s", "issue #"),
"ghpull": ("https://GitHub.com/pyTooling/Actions/pull/%s", "pull request #"),
"gh": ("https://GitHub.com/%s", "gh:%s"),
"ghissue": ("https://GitHub.com/pyTooling/Actions/issues/%s", "issue #%s"),
"ghpull": ("https://GitHub.com/pyTooling/Actions/pull/%s", "pull request #%s"),
"ghsrc": ("https://GitHub.com/pyTooling/Actions/blob/main/%s", None),
"wiki": ("https://en.wikipedia.org/wiki/%s", None),
}
@@ -239,6 +244,18 @@ mermaid_params = [
mermaid_verbose = True
# ==============================================================================
# Sphinx.Ext.Inheritance_Diagram
# ==============================================================================
inheritance_node_attrs = {
# "shape": "ellipse",
# "fontsize": 14,
# "height": 0.75,
"color": "dodgerblue1",
"style": "filled"
}
# ==============================================================================
# Sphinx.Ext.ToDo
# ==============================================================================
@@ -251,3 +268,15 @@ todo_link_only = True
# Sphinx.Ext.Coverage
# ==============================================================================
coverage_show_missing_items = True
# ==============================================================================
# AutoAPI.Sphinx
# ==============================================================================
autoapi_modules = {
"pyDummy": {
"template": "module",
"output": "pyDummy",
"override": True
}
}

4
doc/coverage/index.rst Normal file
View File

@@ -0,0 +1,4 @@
Coverage Report
###############
*Placeholder for the Coverage report generated with* ``pytest`` *and* ``coverage``.

View File

@@ -171,6 +171,19 @@ License
JobTemplate/Release
JobTemplate/ArtifactCleanUp
.. raw:: latex
\part{pyDummy Example}
.. toctree::
:caption: pyDummy Example
:hidden:
pyDummy/pyDummy
Unittest Report ➚ <unittests/index>
Coverage Report ➚ <coverage/index>
Static Type Check Report ➚ <typing/index>
.. raw:: latex
\part{Appendix}

0
doc/pyDummy/.gitempty Normal file
View File

View File

@@ -3,7 +3,8 @@
pyTooling >= 5.0.0, < 6.0
# Enforce latest version on ReadTheDocs
sphinx >=5.3, < 6.0
sphinx >= 7.1, < 8.0
docutils >= 0.18.0, < 0.19.0
# Sphinx Extenstions
#sphinx.ext.coverage
@@ -12,12 +13,8 @@ sphinxcontrib-mermaid>=0.9.2
#sphinxcontrib-seqdiag>=0.8.5
#sphinxcontrib-textstyle>=0.2.1
#sphinxcontrib-spelling>=2.2.0
autoapi
sphinx_fontawesome>=0.0.6
sphinx_autodoc_typehints>=1.19.5
autoapi >= 2.0.1
sphinx_fontawesome >= 0.0.6
sphinx-inline-tabs >= 2023.4.21
sphinx_autodoc_typehints >= 1.24.0
# changelog>=0.3.5
# BuildTheDocs Extensions (mostly patched Sphinx extensions)
# For pyTooling.Configuration.YAML documentation
ruamel.yaml>=0.17

8
doc/typing/index.rst Normal file
View File

@@ -0,0 +1,8 @@
Static Type Checking Report
###########################
*Placeholder for the Static Type Checking report generated with* ``mypy``.
.. #raw:: html
<iframe src="../../../../report/typing/index.html" width="100%" height="500px" style="border:none;"/>

4
doc/unittests/index.rst Normal file
View File

@@ -0,0 +1,4 @@
UnitTest Report
###############
*Placeholder for the unittest report generated with* ``pytest``.

View File

@@ -28,24 +28,74 @@
# SPDX-License-Identifier: Apache-2.0 #
# ==================================================================================================================== #
#
"""
A module for a set of dummy classes.
"""
__author__ = "Patrick Lehmann"
__email__ = "Paebbels@gmail.com"
__copyright__ = "2017-2023, Patrick Lehmann"
__license__ = "Apache License, Version 2.0"
__version__ = "0.1.0"
__keywords__ = ["dummy"]
__version__ = "0.4.4"
__keywords__ = ["GitHub Actions"]
__issue_tracker__ = "https://GitHub.com/pyTooling/Actions/issues"
from pyTooling.Decorators import export
from pyTooling.Platform import Platform
@export
class Application:
_value: int
class Base:
"""
A base-class for dummy applications.
"""
_value: int #: An internal value.
def __init__(self) -> None:
self._value = 1
"""
Initializes the base-class.
"""
self._value = 0
@property
def Value(self) -> int:
"""
Read-only property to return the internal value.
:return: Internal value.
"""
return self._value
@export
class Application(Base):
"""
A dummy application for demonstration purposes.
"""
def __init__(self) -> None:
"""
Initializes the dummy application.
"""
super().__init__()
platform = Platform()
if platform.IsNativeLinux:
self._value += 1
elif platform.IsNativeMacOS:
self._value += 2
elif platform.IsNativeWindows:
self._value += 3
elif platform.IsMSYSOnWindows:
self._value += 11
elif platform.IsMinGW32OnWindows:
self._value += 12
elif platform.IsMinGW64OnWindows:
self._value += 13
elif platform.IsUCRT64OnWindows:
self._value += 14
elif platform.IsClang32OnWindows:
self._value += 15
elif platform.IsClang64OnWindows:
self._value += 16

View File

@@ -32,10 +32,14 @@ filterwarnings = [
[tool.coverage.run]
branch = true
relative_files = true
omit = [
"*site-packages*",
"setup.py",
"tests/*"
"tests/benchmark/*",
"tests/performance/*",
"tests/platform/*",
"tests/unit/*"
]
[tool.coverage.report]

View File

@@ -38,7 +38,8 @@ packageName = "pyDummy"
packageDirectory = packageName
packageInformationFile = Path(f"{packageDirectory}/__init__.py")
setup(**DescribePythonPackageHostedOnGitHub(
# setup(**
DescribePythonPackageHostedOnGitHub(
packageName=packageName,
description="pyDummy is a test package to verify GitHub actions for Python projects.",
gitHubNamespace=gitHubNamespace,
@@ -47,4 +48,5 @@ setup(**DescribePythonPackageHostedOnGitHub(
dataFiles={
packageName: ["py.typed"]
}
))
)
# )

View File

@@ -28,10 +28,71 @@
# SPDX-License-Identifier: Apache-2.0 #
# ==================================================================================================================== #
#
"""Placeholder"""
__author__ = "Patrick Lehmann"
__email__ = "Paebbels@gmail.com"
__copyright__ = "2017-2022, Patrick Lehmann"
__license__ = "Apache License, Version 2.0"
__version__ = "0.4.4"
__keywords__ = []
from unittest import TestCase
from pytest import mark
from pyTooling.Common import CurrentPlatform
from pyDummy import Application
if __name__ == "__main__": # pragma: no cover
print("ERROR: you called a testcase declaration file as an executable module.")
print("Use: 'python -m unitest <testcase module>'")
exit(1)
class PlatformTesting(TestCase):
@mark.skipif(not CurrentPlatform.IsNativeLinux, reason="Skipped, if current platform isn't native Linux.")
def test_ApplicationOnNativeLinux(self):
app = Application()
self.assertEqual(1, app.Value)
@mark.skipif(not CurrentPlatform.IsNativeMacOS, reason="Skipped, if current platform isn't native macOS.")
def test_ApplicationOnNativeMacOS(self):
app = Application()
self.assertEqual(2, app.Value)
@mark.skipif(not CurrentPlatform.IsNativeWindows, reason="Skipped, if current platform isn't native Windows.")
def test_ApplicationOnNativeWindows(self):
app = Application()
self.assertEqual(3, app.Value)
@mark.skipif(not CurrentPlatform.IsMSYSOnWindows, reason="Skipped, if current platform isn't MSYS on Windows.")
def test_ApplicationOnMSYS2OnWindows(self):
app = Application()
self.assertEqual(11, app.Value)
@mark.skipif(not CurrentPlatform.IsMinGW32OnWindows, reason="Skipped, if current platform isn't MinGW32 on Windows.")
def test_ApplicationOnMinGW32OnWindows(self):
app = Application()
self.assertEqual(12, app.Value)
@mark.skipif(not CurrentPlatform.IsMinGW64OnWindows, reason="Skipped, if current platform isn't MinGW64 on Windows.")
def test_ApplicationOnMinGW64OnWindows(self):
app = Application()
self.assertEqual(13, app.Value)
@mark.skipif(not CurrentPlatform.IsUCRT64OnWindows, reason="Skipped, if current platform isn't UCRT64 on Windows.")
def test_ApplicationOnURTC64OnWindows(self):
app = Application()
self.assertEqual(14, app.Value)
@mark.skipif(not CurrentPlatform.IsClang32OnWindows, reason="Skipped, if current platform isn't Clang32 on Windows.")
def test_ApplicationOnClang32OnWindows(self):
app = Application()
self.assertEqual(15, app.Value)
@mark.skipif(not CurrentPlatform.IsClang64OnWindows, reason="Skipped, if current platform isn't Clang64 on Windows.")
def test_ApplicationOnClang64OnWindows(self):
app = Application()
self.assertEqual(16, app.Value)

View File

@@ -37,4 +37,4 @@ class Instantiation(TestCase):
def test_Application(self):
app = Application()
self.assertEqual(1, app.Value)
self.assertGreater(app.Value, 0)

View File

@@ -1,116 +0,0 @@
# ==================================================================================================================== #
# _____ _ _ _ _ _ #
# _ __ _ |_ _|__ ___ | (_)_ __ __ _ / \ ___| |_(_) ___ _ __ ___ #
# | '_ \| | | || |/ _ \ / _ \| | | '_ \ / _` | / _ \ / __| __| |/ _ \| '_ \/ __| #
# | |_) | |_| || | (_) | (_) | | | | | | (_| |_ / ___ \ (__| |_| | (_) | | | \__ \ #
# | .__/ \__, ||_|\___/ \___/|_|_|_| |_|\__, (_)_/ \_\___|\__|_|\___/|_| |_|___/ #
# |_| |___/ |___/ #
# ==================================================================================================================== #
# Authors: #
# Patrick Lehmann #
# #
# License: #
# ==================================================================================================================== #
# Copyright 2017-2023 Patrick Lehmann - Bötzingen, Germany #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); #
# you may not use this file except in compliance with the License. #
# You may obtain a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
# #
# SPDX-License-Identifier: Apache-2.0 #
# ==================================================================================================================== #
#
"""Unit tests for TBD."""
from os import getenv as os_getenv
from pytest import mark
from unittest import TestCase
from pyTooling.Platform import Platform
if __name__ == "__main__": # pragma: no cover
print("ERROR: you called a testcase declaration file as an executable module.")
print("Use: 'python -m unitest <testcase module>'")
exit(1)
class AnyPlatform(TestCase):
expected = os_getenv("ENVIRONMENT_NAME", default="Windows (x86-64)")
@mark.skipif(os_getenv("ENVIRONMENT_NAME", "skip") == "skip", reason="Skipped when environment variable 'ENVIRONMENT_NAME' isn't set.")
def test_PlatformString(self) -> None:
platform = Platform()
print()
print(platform)
@mark.skipif("Linux (x86-64)" != os_getenv("ENVIRONMENT_NAME", "skip"), reason=f"Skipped 'test_NativeLinux' when environment variable 'ENVIRONMENT_NAME' doesn't match. {os_getenv('ENVIRONMENT_NAME', 'skip')}")
def test_NativeLinux(self) -> None:
platform = Platform()
print()
print(platform)
@mark.skipif("MacOS (x86-64)" != os_getenv("ENVIRONMENT_NAME", "skip"), reason=f"Skipped 'test_NativeMacOS' when environment variable 'ENVIRONMENT_NAME' doesn't match. {os_getenv('ENVIRONMENT_NAME', 'skip')}")
def test_NativeMacOS(self) -> None:
platform = Platform()
print()
print(platform)
@mark.skipif("Windows (x86-64)" != os_getenv("ENVIRONMENT_NAME", "skip"), reason=f"Skipped 'test_NativeWindows' when environment variable 'ENVIRONMENT_NAME' doesn't match. {os_getenv('ENVIRONMENT_NAME', 'skip')}")
def test_NativeWindows(self) -> None:
platform = Platform()
print()
print(platform)
@mark.skipif("Windows+MSYS2 (x86-64) - MSYS" != os_getenv("ENVIRONMENT_NAME", "skip"), reason=f"Skipped 'test_MSYS' when environment variable 'ENVIRONMENT_NAME' doesn't match. {os_getenv('ENVIRONMENT_NAME', 'skip')}")
def test_MSYS(self) -> None:
platform = Platform()
print()
print(platform)
@mark.skipif("Windows+MSYS2 (x86-64) - MinGW32" != os_getenv("ENVIRONMENT_NAME", "skip"), reason=f"Skipped 'test_MinGW32' when environment variable 'ENVIRONMENT_NAME' doesn't match. {os_getenv('ENVIRONMENT_NAME', 'skip')}")
def test_MinGW32(self) -> None:
platform = Platform()
print()
print(platform)
@mark.skipif("Windows+MSYS2 (x86-64) - MinGW64" != os_getenv("ENVIRONMENT_NAME", "skip"), reason=f"Skipped 'test_MinGW64' when environment variable 'ENVIRONMENT_NAME' doesn't match. {os_getenv('ENVIRONMENT_NAME', 'skip')}")
def test_MinGW64(self) -> None:
platform = Platform()
print()
print(platform)
@mark.skipif("Windows+MSYS2 (x86-64) - UCRT64" != os_getenv("ENVIRONMENT_NAME", "skip"), reason=f"Skipped 'test_UCRT64' when environment variable 'ENVIRONMENT_NAME' doesn't match. {os_getenv('ENVIRONMENT_NAME', 'skip')}")
def test_UCRT64(self) -> None:
platform = Platform()
print()
print(platform)
@mark.skipif("Windows+MSYS2 (x86-64) - Clang32" != os_getenv("ENVIRONMENT_NAME", "skip"), reason=f"Skipped 'test_Clang32' when environment variable 'ENVIRONMENT_NAME' doesn't match. {os_getenv('ENVIRONMENT_NAME', 'skip')}")
def test_Clang32(self) -> None:
platform = Platform()
print()
print(platform)
@mark.skipif("Windows+MSYS2 (x86-64) - Clang64" != os_getenv("ENVIRONMENT_NAME", "skip"), reason=f"Skipped 'test_Clang64' when environment variable 'ENVIRONMENT_NAME' doesn't match. {os_getenv('ENVIRONMENT_NAME', 'skip')}")
def test_Clang64(self) -> None:
platform = Platform()
print()
print(platform)

View File

@@ -28,4 +28,4 @@
# SPDX-License-Identifier: Apache-2.0 #
# ==================================================================================================================== #
#
"""Test code for pyTooling."""
"""Test code for pyDummy."""