From d2d029c2d21c3800e761c704a795ccc5e21a82fa Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Thu, 30 May 2024 12:37:36 +0000 Subject: [PATCH] update to copier template --- .copier-answers.yml | 16 ++ .devcontainer/devcontainer.json | 86 ++++----- .github/CONTRIBUTING.md | 27 +++ .../actions/install_requirements/action.yml | 65 +++---- .github/dependabot.yml | 24 +++ .github/pages/index.html | 8 +- .github/pages/make_switcher.py | 95 ++++++++++ .github/workflows/_check.yml | 27 +++ .github/workflows/_dist.yml | 36 ++++ .github/workflows/_pypi.yml | 17 ++ .github/workflows/_release.yml | 32 ++++ .github/workflows/_test.yml | 62 ++++++ .github/workflows/_tox.yml | 22 +++ .github/workflows/ci.yml | 54 ++++++ .github/workflows/code.yml | 152 --------------- .github/workflows/docs.yml | 65 ------- .gitignore | 15 +- .pre-commit-config.yaml | 16 +- .vscode/extensions.json | 4 +- .vscode/launch.json | 58 +----- .vscode/settings.json | 14 +- .vscode/tasks.json | 4 +- CHANGELOG.rst | 17 -- CONTRIBUTING.rst | 159 ---------------- Dockerfile | 13 ++ README.md | 32 ++++ README.rst | 40 ---- catalog-info.yaml | 10 + docs/_static/theme_overrides.css | 34 ---- docs/conf.py | 126 ------------- docs/explanations.rst | 11 -- docs/explanations/todo.rst | 4 - docs/how-to.rst | 11 -- docs/how-to/todo.rst | 4 - docs/images/builder2ibek-favicon.ico | Bin 14318 -> 0 bytes docs/images/builder2ibek-logo.svg | 177 ------------------ docs/index.rst | 48 ----- docs/reference.rst | 18 -- docs/reference/api.rst | 17 -- docs/reference/contributing.rst | 1 - docs/tutorials.rst | 11 -- docs/tutorials/installation.rst | 47 ----- pyproject.toml | 69 +++---- src/builder2ibek/__init__.py | 13 +- src/builder2ibek/__main__.py | 7 +- src/builder2ibek/builder.py | 3 +- src/builder2ibek/convert.py | 6 +- src/builder2ibek/moduleinfos.py | 9 +- src/builder2ibek/types.py | 9 +- tests/conftest.py | 28 ++- tests/test_cli.py | 31 --- 51 files changed, 610 insertions(+), 1244 deletions(-) create mode 100644 .copier-answers.yml create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/dependabot.yml create mode 100755 .github/pages/make_switcher.py create mode 100644 .github/workflows/_check.yml create mode 100644 .github/workflows/_dist.yml create mode 100644 .github/workflows/_pypi.yml create mode 100644 .github/workflows/_release.yml create mode 100644 .github/workflows/_test.yml create mode 100644 .github/workflows/_tox.yml create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/code.yml delete mode 100644 .github/workflows/docs.yml delete mode 100644 CHANGELOG.rst delete mode 100644 CONTRIBUTING.rst create mode 100644 Dockerfile create mode 100644 README.md delete mode 100644 README.rst create mode 100644 catalog-info.yaml delete mode 100644 docs/_static/theme_overrides.css delete mode 100644 docs/conf.py delete mode 100644 docs/explanations.rst delete mode 100644 docs/explanations/todo.rst delete mode 100644 docs/how-to.rst delete mode 100644 docs/how-to/todo.rst delete mode 100644 docs/images/builder2ibek-favicon.ico delete mode 100644 docs/images/builder2ibek-logo.svg delete mode 100644 docs/index.rst delete mode 100644 docs/reference.rst delete mode 100644 docs/reference/api.rst delete mode 100644 docs/reference/contributing.rst delete mode 100644 docs/tutorials.rst delete mode 100644 docs/tutorials/installation.rst diff --git a/.copier-answers.yml b/.copier-answers.yml new file mode 100644 index 0000000..4875a14 --- /dev/null +++ b/.copier-answers.yml @@ -0,0 +1,16 @@ +# Changes here will be overwritten by Copier +_commit: 2.1.0 +_src_path: gh:diamondlightsource/python-copier-template +author_email: giles.knap@diamond.ac.uk +author_name: Giles Knap +component_owner: group:default/sscc +description: Conversion tool for DLS XML builder IOC instances to ibek ioc.yaml +distribution_name: builder2ibek +docker: false +docs_type: README +git_platform: github.com +github_org: epics-containers +package_name: builder2ibek +pypi: true +repo_name: builder2ibek +type_checker: mypy diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index af6666d..79b85ff 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,68 +1,46 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: -// https://github.com/microsoft/vscode-dev-containers/tree/v0.231.6/containers/python-3 +// For format details, see https://containers.dev/implementors/json_reference/ { - "name": "Python 3", + "name": "Python 3 Developer Container", "build": { - "dockerfile": "Dockerfile", - "target": "developer", - "context": "..", - "args": {} + "dockerfile": "../Dockerfile", + "target": "developer" }, "remoteEnv": { + // Allow X11 apps to run inside the container "DISPLAY": "${localEnv:DISPLAY}" }, - // Set *default* container specific settings.json values on container create. - "settings": { - "python.defaultInterpreterPath": "/usr/local/bin/python", - "python.linting.enabled": true, - "python.linting.pylintEnabled": true, - "python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8", - "python.formatting.blackPath": "/usr/local/py-utils/bin/black", - "python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf", - "python.linting.banditPath": "/usr/local/py-utils/bin/bandit", - "python.linting.flake8Path": "/usr/local/py-utils/bin/flake8", - "python.linting.mypyPath": "/usr/local/py-utils/bin/mypy", - "python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle", - "python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle", - "python.linting.pylintPath": "/usr/local/py-utils/bin/pylint" + "customizations": { + "vscode": { + // Set *default* container specific settings.json values on container create. + "settings": { + "python.defaultInterpreterPath": "/venv/bin/python" + }, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-python.python", + "github.vscode-github-actions", + "tamasfe.even-better-toml", + "redhat.vscode-yaml", + "ryanluker.vscode-coverage-gutters", + "charliermarsh.ruff", + "ms-azuretools.vscode-docker" + ] + } }, - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "ms-python.python", - "ms-python.vscode-pylance", - "streetsidesoftware.code-spell-checker", - "ryanluker.vscode-coverage-gutters", - "mhutchie.git-graph", - "eamodio.gitlens", - "gruntfuggly.todo-tree", - "redhat.vscode-yaml", - "nsd.vscode-epics", - "alefragnani.bookmarks" - ], "features": { - //"docker-from-docker": "20.10", - "git": "os-provided" + // Some default things like git config + "ghcr.io/devcontainers/features/common-utils:2": { + "upgradePackages": false + } }, - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. - // "remoteUser": "vscode", - // Make sure the files we are mapping into the container exist on the host - "initializeCommand": "bash -c 'for i in $HOME/.inputrc $HOME/.bashrc_dev; do [ -f $i ] || touch $i; done'", "runArgs": [ - "--privileged", + // Allow the container to access the host X11 display and EPICS CA "--net=host", - "-v=${localEnv:HOME}/.ssh:/root/.ssh", - "-v=${localEnv:HOME}/.bashrc_dev:/root/.bashrc", - "-v=${localEnv:HOME}/.inputrc:/root/.inputrc" - ], - "mounts": [ - // map in home directory - not strictly necessary but may be useful - "source=${localEnv:HOME},target=${localEnv:HOME},type=bind,consistency=cached" + // Make sure SELinux does not disable with access to host filesystems like tmp + "--security-opt=label=disable" ], - "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind", - "workspaceFolder": "/workspace", + // Mount the parent as /workspaces so we can pip install peers as editable + "workspaceMount": "source=${localWorkspaceFolder}/..,target=/workspaces,type=bind", // After the container is created, install the python project in editable form - // This installs into the system python of the container - "postCreateCommand": "pip install $([ -f requirements_dev.txt ] && echo -r requirements_dev.txt ) -e .[dev]" + "postCreateCommand": "pip install $([ -f dev-requirements.txt ] && echo '-c dev-requirements.txt') -e '.[dev]' && pre-commit install" } \ No newline at end of file diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..e3a795d --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,27 @@ +# Contribute to the project + +Contributions and issues are most welcome! All issues and pull requests are +handled through [GitHub](https://github.com/epics-containers/builder2ibek/issues). Also, please check for any existing issues before +filing a new one. If you have a great idea but it involves big changes, please +file a ticket before making a pull request! We want to make sure you don't spend +your time coding something that might not fit the scope of the project. + +## Issue or Discussion? + +Github also offers [discussions](https://github.com/epics-containers/builder2ibek/discussions) as a place to ask questions and share ideas. If +your issue is open ended and it is not obvious when it can be "closed", please +raise it as a discussion instead. + +## Code Coverage + +While 100% code coverage does not make a library bug-free, it significantly +reduces the number of easily caught bugs! Please make sure coverage remains the +same or is improved by a pull request! + +## Developer Information + +It is recommended that developers use a [vscode devcontainer](https://code.visualstudio.com/docs/devcontainers/containers). This repository contains configuration to set up a containerized development environment that suits its own needs. + +This project was created using the [Diamond Light Source Copier Template](https://github.com/DiamondLightSource/python-copier-template) for Python projects. + +For more information on common tasks like setting up a developer environment, running the tests, and setting a pre-commit hook, see the template's [How-to guides](https://diamondlightsource.github.io/python-copier-template/2.1.0/how-to.html). diff --git a/.github/actions/install_requirements/action.yml b/.github/actions/install_requirements/action.yml index 6cc2e54..d33e080 100644 --- a/.github/actions/install_requirements/action.yml +++ b/.github/actions/install_requirements/action.yml @@ -1,57 +1,34 @@ name: Install requirements -description: Run pip install with requirements and upload resulting requirements +description: Install a version of python then call pip install and report what was installed inputs: - requirements_file: - description: Name of requirements file to use and upload - required: true - install_options: + python-version: + description: Python version to install, default is from Dockerfile + default: "dev" + pip-install: description: Parameters to pass to pip install - required: true - python_version: - description: Python version to install - default: "3.10" + default: "$([ -f dev-requirements.txt ] && echo '-c dev-requirements.txt') -e .[dev]" runs: using: composite - steps: - - name: Setup python - uses: actions/setup-python@v4 - with: - python-version: ${{ inputs.python_version }} - - - name: Pip install - run: | - touch ${{ inputs.requirements_file }} - # -c uses requirements.txt as constraints, see 'Validate requirements file' - pip install -c ${{ inputs.requirements_file }} ${{ inputs.install_options }} - shell: bash - - - name: Create lockfile + - name: Get version of python run: | - mkdir -p lockfiles - pip freeze --exclude-editable > lockfiles/${{ inputs.requirements_file }} - # delete the self referencing line and make sure it isn't blank - sed -i'' -e '/file:/d' lockfiles/${{ inputs.requirements_file }} + PYTHON_VERSION="${{ inputs.python-version }}" + if [ $PYTHON_VERSION == "dev" ]; then + PYTHON_VERSION=$(sed -n "s/ARG PYTHON_VERSION=//p" Dockerfile) + fi + echo "PYTHON_VERSION=$PYTHON_VERSION" >> "$GITHUB_ENV" shell: bash - - name: Upload lockfiles - uses: actions/upload-artifact@v3 + - name: Setup python + uses: actions/setup-python@v5 with: - name: lockfiles - path: lockfiles + python-version: ${{ env.PYTHON_VERSION }} - # This eliminates the class of problems where the requirements being given no - # longer match what the packages themselves dictate. E.g. In the rare instance - # where I install some-package which used to depend on vulnerable-dependency - # but now uses good-dependency (despite being nominally the same version) - # pip will install both if given a requirements file with -r - - name: If requirements file exists, check it matches pip installed packages - run: | - if [ -s ${{ inputs.requirements_file }} ]; then - if ! diff -u ${{ inputs.requirements_file }} lockfiles/${{ inputs.requirements_file }}; then - echo "Error: ${{ inputs.requirements_file }} need the above changes to be exhaustive" - exit 1 - fi - fi + - name: Install packages + run: pip install ${{ inputs.pip-install }} + shell: bash + + - name: Report what was installed + run: pip freeze shell: bash diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..184ba36 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,24 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + groups: + actions: + patterns: + - "*" + + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + groups: + dev-dependencies: + patterns: + - "*" diff --git a/.github/pages/index.html b/.github/pages/index.html index bd85627..80f0a00 100644 --- a/.github/pages/index.html +++ b/.github/pages/index.html @@ -2,10 +2,10 @@ - Redirecting to main branch - - - + Redirecting to main branch + + + \ No newline at end of file diff --git a/.github/pages/make_switcher.py b/.github/pages/make_switcher.py new file mode 100755 index 0000000..dbf8acc --- /dev/null +++ b/.github/pages/make_switcher.py @@ -0,0 +1,95 @@ +import json +import logging +from argparse import ArgumentParser +from pathlib import Path +from subprocess import CalledProcessError, check_output +from typing import Optional + + +def report_output(stdout: bytes, label: str) -> list[str]: + ret = stdout.decode().strip().split("\n") + print(f"{label}: {ret}") + return ret + + +def get_branch_contents(ref: str) -> list[str]: + """Get the list of directories in a branch.""" + stdout = check_output(["git", "ls-tree", "-d", "--name-only", ref]) + return report_output(stdout, "Branch contents") + + +def get_sorted_tags_list() -> list[str]: + """Get a list of sorted tags in descending order from the repository.""" + stdout = check_output(["git", "tag", "-l", "--sort=-v:refname"]) + return report_output(stdout, "Tags list") + + +def get_versions(ref: str, add: Optional[str]) -> list[str]: + """Generate the file containing the list of all GitHub Pages builds.""" + # Get the directories (i.e. builds) from the GitHub Pages branch + try: + builds = set(get_branch_contents(ref)) + except CalledProcessError: + builds = set() + logging.warning(f"Cannot get {ref} contents") + + # Add and remove from the list of builds + if add: + builds.add(add) + + # Get a sorted list of tags + tags = get_sorted_tags_list() + + # Make the sorted versions list from main branches and tags + versions: list[str] = [] + for version in ["master", "main"] + tags: + if version in builds: + versions.append(version) + builds.remove(version) + + # Add in anything that is left to the bottom + versions += sorted(builds) + print(f"Sorted versions: {versions}") + return versions + + +def write_json(path: Path, repository: str, versions: str): + org, repo_name = repository.split("/") + pages_url = f"https://{org}.github.io" + if repo_name != f"{org}.github.io": + # Only add the repo name if it isn't the source for the org pages site + pages_url += f"/{repo_name}" + struct = [ + {"version": version, "url": f"{pages_url}/{version}/"} for version in versions + ] + text = json.dumps(struct, indent=2) + print(f"JSON switcher:\n{text}") + path.write_text(text, encoding="utf-8") + + +def main(args=None): + parser = ArgumentParser( + description="Make a versions.json file from gh-pages directories" + ) + parser.add_argument( + "--add", + help="Add this directory to the list of existing directories", + ) + parser.add_argument( + "repository", + help="The GitHub org and repository name: ORG/REPO", + ) + parser.add_argument( + "output", + type=Path, + help="Path of write switcher.json to", + ) + args = parser.parse_args(args) + + # Write the versions file + versions = get_versions("origin/gh-pages", args.add) + write_json(args.output, args.repository, versions) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/_check.yml b/.github/workflows/_check.yml new file mode 100644 index 0000000..a6139c1 --- /dev/null +++ b/.github/workflows/_check.yml @@ -0,0 +1,27 @@ +on: + workflow_call: + outputs: + branch-pr: + description: The PR number if the branch is in one + value: ${{ jobs.pr.outputs.branch-pr }} + +jobs: + pr: + runs-on: "ubuntu-latest" + outputs: + branch-pr: ${{ steps.script.outputs.result }} + steps: + - uses: actions/github-script@v7 + id: script + if: github.event_name == 'push' + with: + script: | + const prs = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + head: context.repo.owner + ':${{ github.ref_name }}' + }) + if (prs.data.length) { + console.log(`::notice ::Skipping CI on branch push as it is already run in PR #${prs.data[0]["number"]}`) + return prs.data[0]["number"] + } diff --git a/.github/workflows/_dist.yml b/.github/workflows/_dist.yml new file mode 100644 index 0000000..b1c4c93 --- /dev/null +++ b/.github/workflows/_dist.yml @@ -0,0 +1,36 @@ +on: + workflow_call: + +jobs: + build: + runs-on: "ubuntu-latest" + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # Need this to get version number from last tag + fetch-depth: 0 + + - name: Build sdist and wheel + run: > + export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) && + pipx run build + + - name: Upload sdist and wheel as artifacts + uses: actions/upload-artifact@v4 + with: + name: dist + path: dist + + - name: Check for packaging errors + run: pipx run twine check --strict dist/* + + - name: Install produced wheel + uses: ./.github/actions/install_requirements + with: + pip-install: dist/*.whl + + - name: Test module --version works using the installed wheel + # If more than one module in src/ replace with module name to test + run: python -m $(ls --hide='*.egg-info' src | head -1) --version diff --git a/.github/workflows/_pypi.yml b/.github/workflows/_pypi.yml new file mode 100644 index 0000000..0c5258d --- /dev/null +++ b/.github/workflows/_pypi.yml @@ -0,0 +1,17 @@ +on: + workflow_call: + +jobs: + upload: + runs-on: ubuntu-latest + environment: release + + steps: + - name: Download dist artifact + uses: actions/download-artifact@v4 + with: + name: dist + path: dist + + - name: Publish to PyPI using trusted publishing + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/_release.yml b/.github/workflows/_release.yml new file mode 100644 index 0000000..e55efdb --- /dev/null +++ b/.github/workflows/_release.yml @@ -0,0 +1,32 @@ +on: + workflow_call: + +jobs: + artifacts: + runs-on: ubuntu-latest + + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + merge-multiple: true + + - name: Zip up docs + run: | + set -vxeuo pipefail + if [ -d html ]; then + mv html $GITHUB_REF_NAME + zip -r docs.zip $GITHUB_REF_NAME + rm -rf $GITHUB_REF_NAME + fi + + - name: Create GitHub Release + # We pin to the SHA, not the tag, for security reasons. + # https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions + uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564 # v2.0.4 + with: + prerelease: ${{ contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc') }} + files: "*" + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml new file mode 100644 index 0000000..f652d41 --- /dev/null +++ b/.github/workflows/_test.yml @@ -0,0 +1,62 @@ +on: + workflow_call: + inputs: + python-version: + type: string + description: The version of python to install + required: true + runs-on: + type: string + description: The runner to run this job on + required: true + secrets: + CODECOV_TOKEN: + required: true + +env: + # https://github.com/pytest-dev/pytest/issues/2042 + PY_IGNORE_IMPORTMISMATCH: "1" + +jobs: + run: + runs-on: ${{ inputs.runs-on }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # Need this to get version number from last tag + fetch-depth: 0 + + - if: inputs.python-version == 'dev' + name: Install dev versions of python packages + uses: ./.github/actions/install_requirements + + - if: inputs.python-version == 'dev' + name: Write the requirements as an artifact + run: pip freeze --exclude-editable > /tmp/dev-requirements.txt + + - if: inputs.python-version == 'dev' + name: Upload dev-requirements.txt + uses: actions/upload-artifact@v4 + with: + name: dev-requirements + path: /tmp/dev-requirements.txt + + - if: inputs.python-version != 'dev' + name: Install latest versions of python packages + uses: ./.github/actions/install_requirements + with: + python-version: ${{ inputs.python-version }} + pip-install: ".[dev]" + + - name: Run tests + run: tox -e tests + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + name: ${{ inputs.python-version }}/${{ inputs.runs-on }} + files: cov.xml + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/_tox.yml b/.github/workflows/_tox.yml new file mode 100644 index 0000000..a13536d --- /dev/null +++ b/.github/workflows/_tox.yml @@ -0,0 +1,22 @@ +on: + workflow_call: + inputs: + tox: + type: string + description: What to run under tox + required: true + + +jobs: + run: + runs-on: "ubuntu-latest" + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install python packages + uses: ./.github/actions/install_requirements + + - name: Run tox + run: tox -e ${{ inputs.tox }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..93de608 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,54 @@ +name: CI + +on: + push: + pull_request: + +jobs: + check: + uses: ./.github/workflows/_check.yml + + lint: + needs: check + if: needs.check.outputs.branch-pr == '' + uses: ./.github/workflows/_tox.yml + with: + tox: pre-commit,type-checking + + test: + needs: check + if: needs.check.outputs.branch-pr == '' + strategy: + matrix: + runs-on: ["ubuntu-latest"] # can add windows-latest, macos-latest + python-version: ["3.8", "3.9", "3.10", "3.11"] + include: + # Include one that runs in the dev environment + - runs-on: "ubuntu-latest" + python-version: "dev" + fail-fast: false + uses: ./.github/workflows/_test.yml + with: + runs-on: ${{ matrix.runs-on }} + python-version: ${{ matrix.python-version }} + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + dist: + needs: check + if: needs.check.outputs.branch-pr == '' + uses: ./.github/workflows/_dist.yml + + pypi: + if: github.ref_type == 'tag' + needs: dist + uses: ./.github/workflows/_pypi.yml + permissions: + id-token: write + + release: + if: github.ref_type == 'tag' + needs: [dist] + uses: ./.github/workflows/_release.yml + permissions: + contents: write diff --git a/.github/workflows/code.yml b/.github/workflows/code.yml deleted file mode 100644 index 9cb02ef..0000000 --- a/.github/workflows/code.yml +++ /dev/null @@ -1,152 +0,0 @@ -name: Code CI - -on: - push: - pull_request: -env: - # The target python version, which must match the Dockerfile version - CONTAINER_PYTHON: "3.10" - -jobs: - lint: - # pull requests are a duplicate of a branch push if within the same repo. - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install python packages - uses: ./.github/actions/install_requirements - with: - requirements_file: requirements-dev-3.x.txt - install_options: -e .[dev] - - - name: Lint - run: tox -e pre-commit,mypy - - test: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository - strategy: - fail-fast: false - matrix: - os: ["ubuntu-latest"] # can add windows-latest, macos-latest - python: ["3.10", "3.11"] - install: ["-e .[dev]"] - # Make one version be non-editable to test both paths of version code - include: - - os: "ubuntu-latest" - python: "3.10" - install: ".[dev]" - - runs-on: ${{ matrix.os }} - env: - # https://github.com/pytest-dev/pytest/issues/2042 - PY_IGNORE_IMPORTMISMATCH: "1" - # enable QT tests with no X Display - QT_QPA_PLATFORM: "offscreen" - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - # Need this to get version number from last tag - fetch-depth: 0 - submodules: recursive - - - name: Install python packages - uses: ./.github/actions/install_requirements - with: - python_version: ${{ matrix.python }} - requirements_file: requirements-test-${{ matrix.os }}-${{ matrix.python }}.txt - install_options: ${{ matrix.install }} - - - name: List dependency tree - run: pipdeptree - - - name: Run tests - run: tox -e pytest - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 - with: - name: ${{ matrix.python }}/${{ matrix.os }} - files: cov.xml - - dist: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository - runs-on: "ubuntu-latest" - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - # Need this to get version number from last tag - fetch-depth: 0 - - - name: Build sdist and wheel - run: | - export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) && \ - pipx run build - - - name: Upload sdist and wheel as artifacts - uses: actions/upload-artifact@v3 - with: - name: dist - path: dist - - - name: Check for packaging errors - run: pipx run twine check --strict dist/* - - - name: Install python packages - uses: ./.github/actions/install_requirements - with: - python_version: ${{env.CONTAINER_PYTHON}} - requirements_file: requirements.txt - install_options: dist/*.whl - - - name: Test module --version works using the installed wheel - # If more than one module in src/ replace with module name to test - run: python -m $(ls src | head -1) --version - - release: - # upload to PyPI and make a release on every tag - needs: [lint, dist, test] - if: ${{ github.event_name == 'push' && github.ref_type == 'tag' }} - runs-on: ubuntu-latest - permissions: - # this permission is mandatory for trusted publishing To PyPI - id-token: write - contents: write - # Specify the GitHub Environment to publish to - environment: release - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - uses: actions/download-artifact@v3 - - - name: Fixup blank lockfiles - # Github release artifacts can't be blank - run: for f in lockfiles/*; do [ -s $f ] || echo '# No requirements' >> $f; done - - - name: Github Release - # We pin to the SHA, not the tag, for security reasons. - # https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15 - with: - prerelease: ${{ contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc') }} - # upload distribution files and lockfiles plus the support YAML schema - # note that the 'sample' has been checked to be current by the tests - files: | - dist/* - lockfiles/* - generate_release_notes: true - - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index 099a034..0000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Docs CI - -on: - push: - branches: - # Add more branches here to publish docs from other branches - - main - - main - tags: - - "*" - pull_request: - -jobs: - docs: - strategy: - fail-fast: false - matrix: - os: ["ubuntu-latest"] - python: ["3.10"] - - runs-on: ubuntu-latest - - steps: - - name: Avoid git conflicts when tag and branch pushed at same time - if: startsWith(github.ref, 'refs/tags') - run: sleep 60 - - - name: Install python version - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python }} - - - name: Install Packages - # Can delete this if you don't use graphviz in your docs - run: sudo apt-get install graphviz - - - name: checkout - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Install dependencies - run: | - touch requirements_dev.txt - pip install -r requirements_dev.txt -e .[dev] - - - name: Build docs - run: tox -e docs - - - name: Move to versioned directory - # e.g. main or 0.1.2 - run: mv build/html ".github/pages/${GITHUB_REF##*/}" - - - name: Write versions.txt - run: sphinx_rtd_theme_github_versions .github/pages - - - name: Publish Docs to gh-pages - if: github.event_name == 'push' - # We pin to the SHA, not the tag, for security reasons. - # https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions - uses: peaceiris/actions-gh-pages@068dc23d9710f1ba62e86896f84735d869951305 # v3.8.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: .github/pages - keep_files: true diff --git a/.gitignore b/.gitignore index e23a2b7..2593ec7 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ __pycache__/ # Distribution / packaging .Python env/ -.venv build/ develop-eggs/ dist/ @@ -60,8 +59,12 @@ docs/_build/ # PyBuilder target/ -# DLS build dir and virtual environment -/prefix/ -/venv/ -/lightweight-venv/ -/installed.files +# likely venv names +.venv* +venv* + +# further build artifacts +lockfiles/ + +# ruff cache +.ruff_cache/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5ef619e..5a4cbf7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,16 +8,16 @@ repos: - repo: local hooks: - - id: black - name: Run black - stages: [commit] + - id: ruff + name: lint with ruff language: system - entry: black --check --diff + entry: ruff check --force-exclude types: [python] + require_serial: true - - id: ruff - name: Run ruff - stages: [commit] + - id: ruff-format + name: format with ruff language: system - entry: ruff + entry: ruff format --force-exclude types: [python] + require_serial: true diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 734f215..66ad632 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,5 @@ { "recommendations": [ - "ms-python.vscode-pylance", - "ms-python.python", - "ryanluker.vscode-coverage-gutters" + "ms-vscode-remote.remote-containers", ] } \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index cffcf30..36d8f50 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,7 @@ "configurations": [ { "name": "Debug Unit Test", - "type": "python", + "type": "debugpy", "request": "launch", "justMyCode": false, "program": "${file}", @@ -15,59 +15,9 @@ ], "console": "integratedTerminal", "env": { - // The default config in setup.cfg's "[tool:pytest]" adds coverage. - // Cannot have coverage and debugging at the same time. - // https://github.com/microsoft/vscode-python/issues/693 - "PYTEST_ADDOPTS": "--no-cov" - }, - }, - { - "name": "Builder2ibek", - "type": "python", - "request": "launch", - "justMyCode": false, - "program": "/scratch/hgv27681/work/builder2ibek/src/builder2ibek/__main__.py", - "args": [ - "file", - "/dls_sw/work/R3.14.12.7/support/BL20J-BUILDER/etc/makeIocs/BL20J-DI-IOC-01.xml", - "--yaml", - "/scratch/hgv27681/work/bl20j/iocs/bl20j-di-ioc-01.yaml" - ], - "purpose": [ - "debug-test" - ], - "console": "integratedTerminal", - "env": { - // The default config in setup.cfg's "[tool:pytest]" adds coverage. - // Cannot have coverage and debugging at the same time. - // https://github.com/microsoft/vscode-python/issues/693 - "PYTEST_ADDOPTS": "--no-cov" - }, - }, - { - "name": "Builder2ibek-P46", - "type": "python", - "request": "launch", - "justMyCode": false, - "program": "/scratch/hgv27681/work/builder2ibek/src/builder2ibek/__main__.py", - "args": [ - "file", - "/scratch/wks59344/MXBridge/bl46p-builder/etc/makeIocs/BL46P-EA-IOC-01.xml", - "--yaml", - "/scratch/wks59344/MXBridge/bl46p/iocs/bl46p-ea-dcam-01/ioc.yaml", - "--schema", - "https://github.com/epics-containers/ioc-adaravis/releases/download/2023.11.4/ibek.ioc.schema.json" - ], - "purpose": [ - "debug-test" - ], - "console": "integratedTerminal", - "env": { - // The default config in setup.cfg's "[tool:pytest]" adds coverage. - // Cannot have coverage and debugging at the same time. - // https://github.com/microsoft/vscode-python/issues/693 - "PYTEST_ADDOPTS": "--no-cov" + // Enable break on exception when debugging tests (see: tests/conftest.py) + "PYTEST_RAISE": "1", }, } ] -} \ No newline at end of file +} diff --git a/.vscode/settings.json b/.vscode/settings.json index c142300..c129d99 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,15 +1,11 @@ { + "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit" + }, "[python]": { - "editor.codeActionsOnSave": { - "source.fixAll.ruff": "never", - "source.organizeImports.ruff": "explicit", - "source.black": "explicit" - } + "editor.defaultFormatter": "charliermarsh.ruff", }, - "cSpell.words": [ - "moduleinfos", - "PARENTPORT" - ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index ff78a11..946e69d 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -5,8 +5,8 @@ "tasks": [ { "type": "shell", - "label": "Tests with coverage", - "command": "pipenv run tests", + "label": "Tests, lint and docs", + "command": "tox -p", "options": { "cwd": "${workspaceRoot}" }, diff --git a/CHANGELOG.rst b/CHANGELOG.rst deleted file mode 100644 index b85bca4..0000000 --- a/CHANGELOG.rst +++ /dev/null @@ -1,17 +0,0 @@ -Changelog -========= - -All notable changes to this project will be documented in this file. - -The format is based on `Keep a Changelog `_, -and this project adheres to `Semantic Versioning `_. - - -Unreleased_ ------------ - -Nothing yet - - -.. _Unreleased: https://github.com/epics-containers/builder2ibek/compare/0.1...HEAD -.. _0.1: https://github.com/epics-containers/builder2ibek/releases/tag/0.1 diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index bf19962..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,159 +0,0 @@ -Contributing -============ - -Contributions and issues are most welcome! All issues and pull requests are -handled through GitHub_. Also, please check for any existing issues before -filing a new one. If you have a great idea but it involves big changes, please -file a ticket before making a pull request! We want to make sure you don't spend -your time coding something that might not fit the scope of the project. - -.. _GitHub: https://github.com/epics-containers/builder2ibek/issues - -Running the tests ------------------ - -To run in a container -~~~~~~~~~~~~~~~~~~~~~ - -Use vscode devcontainer as follows:: - - $ git clone git://github.com/epics-containers/builder2ibek.git - $ vscode builder2ibek - Click on 'Reopen in Container' when prompted - In a vscode Terminal: - $ tox -p - - -To run locally -~~~~~~~~~~~~~~ - -Get the source source code and run the unit tests directly -on your workstation as follows:: - - $ git clone git://github.com/epics-containers/builder2ibek.git - $ cd builder2ibek - $ virtualenv .venv - $ source .venv/bin/activate - $ pip install -e .[dev] - $ tox -p - -In both cases tox -p runs in parallel the following checks: - - - Build Spinx Documentation - - run pytest on all tests in ./tests - - run mypy linting on all files in ./src ./tests - - run pre-commit checks: - - - run flake8 style checks against all source - - run black formatting checks against all source - -While 100% code coverage does not make a library bug-free, it significantly -reduces the number of easily caught bugs! Please make sure coverage remains the -same or is improved by a pull request! - -Code Styling ------------- - -The code in this repository conforms to standards set by the following tools: - -- black_ for code formatting -- flake8_ for style checks -- isort_ for import ordering -- mypy_ for static type checking - -flake8 and black be run by pre-commit_. You can run the above checks on -all files with this command:: - - $ tox -e pre-commit,mypy - -Or you can install a pre-commit hook that will run each time you do a ``git -commit`` on just the files that have changed. Note that mypy is not in -the pre-commit because it is a little slow :: - - $ pre-commit install - -.. _black: https://github.com/psf/black -.. _flake8: https://flake8.pycqa.org/en/latest/ -.. _isort: https://github.com/PyCQA/isort -.. _mypy: https://github.com/python/mypy -.. _pre-commit: https://pre-commit.com/ - -Docstrings are pre-processed using the Sphinx Napoleon extension. As such, -google-style_ is considered as standard for this repository. Please use type -hints in the function signature for types. For example:: - - def func(arg1: str, arg2: int) -> bool: - """Summary line. - - Extended description of function. - - Args: - arg1: Description of arg1 - arg2: Description of arg2 - - Returns: - Description of return value - """ - return True - -.. _google-style: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/index.html#google-vs-numpy - -Documentation -------------- - -Documentation is contained in the ``docs`` directory and extracted from -docstrings of the API. - -Docs follow the underlining convention:: - - Headling 1 (page title) - ======================= - - Heading 2 - --------- - - Heading 3 - ~~~~~~~~~ - -You can build the docs from the project directory by running:: - - $ tox -e docs - $ firefox build/html/index.html - -Release Process ---------------- - -To make a new release, please follow this checklist: - -- Choose a new PEP440 compliant release number -- Git tag the version -- Push to GitHub and the actions will make a release on pypi -- Push to internal gitlab and do a dls-release.py of the tag -- Check and edit for clarity the autogenerated GitHub release_ - -.. _release: https://github.com/epics-containers/builder2ibek/releases - - -Checking Dependencies ---------------------- - -To see a graph of the python package dependency tree type:: - - pipdeptree - -Updating the tools ------------------- - -This module is merged with the dls-python3-skeleton_. This is a generic -Python project structure which provides a means to keep tools and -techniques in sync between multiple Python projects. To update to the -latest version of the skeleton, run:: - - $ git pull https://github.com/dls-controls/dls-python3-skeleton skeleton - -Any merge conflicts will indicate an area where something has changed that -conflicts with the setup of the current module. Check the `closed pull requests -`_ -of the skeleton module for more details. - -.. _dls-python3-skeleton: https://dls-controls.github.io/dls-python3-skeleton \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c4404ec --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +# The devcontainer should use the developer target and run as root with podman +# or docker with user namespaces. +ARG PYTHON_VERSION=3.11 +FROM python:${PYTHON_VERSION} as developer + +# Add any system dependencies for the developer/build environment here +RUN apt-get update && apt-get install -y --no-install-recommends \ + graphviz \ + && rm -rf /var/lib/apt/lists/* + +# Set up a virtual environment and put it in PATH +RUN python -m venv /venv +ENV PATH=/venv/bin:$PATH diff --git a/README.md b/README.md new file mode 100644 index 0000000..cf97681 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +[![CI](https://github.com/epics-containers/builder2ibek/actions/workflows/ci.yml/badge.svg)](https://github.com/epics-containers/builder2ibek/actions/workflows/ci.yml) +[![Coverage](https://codecov.io/gh/epics-containers/builder2ibek/branch/main/graph/badge.svg)](https://codecov.io/gh/epics-containers/builder2ibek) +[![PyPI](https://img.shields.io/pypi/v/builder2ibek.svg)](https://pypi.org/project/builder2ibek) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +# builder2ibek + +Conversion tool for DLS XML builder IOC instances to ibek ioc.yaml + +This is where you should write a short paragraph that describes what your module does, +how it does it, and why people should use it. + +Source | +:---: | :---: +PyPI | `pip install builder2ibek` +Releases | + +This is where you should put some images or code snippets that illustrate +some relevant examples. If it is a library then you might put some +introductory code here: + +```python +from builder2ibek import __version__ + +print(f"Hello builder2ibek {__version__}") +``` + +Or if it is a commandline tool then you might put some example commands here: + +``` +python -m builder2ibek --version +``` diff --git a/README.rst b/README.rst deleted file mode 100644 index c20d9a8..0000000 --- a/README.rst +++ /dev/null @@ -1,40 +0,0 @@ -builder2ibek -============ - -|code_ci| |docs_ci| |coverage| |pypi_version| |license| - -Tool for converting DLS builder IOCS to ibek containerized IOCS. - -============== ============================================================== -PyPI ``pip install builder2ibek`` -Source code https://github.com/epics-containers/builder2ibek -Documentation https://epics-containers.github.io/builder2ibek -Releases https://github.com/epics-containers/builder2ibek/releases -============== ============================================================== - - -.. |code_ci| image:: https://github.com/epics-containers/builder2ibek/workflows/Code%20CI/badge.svg?branch=main - :target: https://github.com/epics-containers/builder2ibek/actions?query=workflow%3A%22Code+CI%22 - :alt: Code CI - -.. |docs_ci| image:: https://github.com/epics-containers/builder2ibek/workflows/Docs%20CI/badge.svg?branch=main - :target: https://github.com/epics-containers/builder2ibek/actions?query=workflow%3A%22Docs+CI%22 - :alt: Docs CI - -.. |coverage| image:: https://codecov.io/gh/epics-containers/builder2ibek/branch/main/graph/badge.svg - :target: https://codecov.io/gh/epics-containers/builder2ibek - :alt: Test Coverage - -.. |pypi_version| image:: https://img.shields.io/pypi/v/builder2ibek.svg - :target: https://pypi.org/project/builder2ibek - :alt: Latest PyPI version - -.. |license| image:: https://img.shields.io/badge/License-Apache%202.0-blue.svg - :target: https://opensource.org/licenses/Apache-2.0 - :alt: Apache License - -.. - Anything below this line is used when viewing README.rst and will be replaced - when included in index.rst - -See https://epics-containers.github.io/builder2ibek for more detailed documentation. diff --git a/catalog-info.yaml b/catalog-info.yaml new file mode 100644 index 0000000..6ad5db7 --- /dev/null +++ b/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: builder2ibek + title: builder2ibek + description: Conversion tool for DLS XML builder IOC instances to ibek ioc.yaml +spec: + type: documentation + lifecycle: experimental + owner: group:default/sscc \ No newline at end of file diff --git a/docs/_static/theme_overrides.css b/docs/_static/theme_overrides.css deleted file mode 100644 index 5fd9b72..0000000 --- a/docs/_static/theme_overrides.css +++ /dev/null @@ -1,34 +0,0 @@ -/* override table width restrictions */ -@media screen and (min-width: 639px) { - .wy-table-responsive table td { - /* !important prevents the common CSS stylesheets from - overriding this as on RTD they are loaded after this stylesheet */ - white-space: normal !important; - } -} - -/* override table padding */ -.rst-content table.docutils th, .rst-content table.docutils td { - padding: 4px 6px; -} - -/* Add two-column option */ -@media only screen and (min-width: 1000px) { - .columns { - padding-left: 10px; - padding-right: 10px; - float: left; - width: 50%; - min-height: 145px; - } -} - -.endcolumns { - clear: both -} - -/* Hide toctrees within columns and captions from all toctrees. - This is what makes the include trick in index.rst work */ -.columns .toctree-wrapper, .toctree-wrapper .caption-text { - display: none; -} diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index c220926..0000000 --- a/docs/conf.py +++ /dev/null @@ -1,126 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/main/usage/configuration.html - -import builder2ibek - -# -- General configuration ------------------------------------------------ - -# General information about the project. -project = "builder2ibek" - -# The full version, including alpha/beta/rc tags. -release = builder2ibek.__version__ - -# The short X.Y version. -if "+" in release: - # Not on a tag - version = "main" -else: - version = release - -extensions = [ - # Use this for generating API docs - "sphinx.ext.autodoc", - # This can parse google style docstrings - "sphinx.ext.napoleon", - # For linking to external sphinx documentation - "sphinx.ext.intersphinx", - # Add links to source code in API docs - "sphinx.ext.viewcode", - # Adds the inheritance-diagram generation directive - "sphinx.ext.inheritance_diagram", -] - -# If true, Sphinx will warn about all references where the target cannot -# be found. -nitpicky = True - -# A list of (type, target) tuples (by default empty) that should be ignored when -# generating warnings in "nitpicky mode". Note that type should include the -# domain name if present. Example entries would be ('py:func', 'int') or -# ('envvar', 'LD_LIBRARY_PATH'). -nitpick_ignore = [ - ("py:class", "NoneType"), - ("py:class", "'str'"), - ("py:class", "'float'"), - ("py:class", "'int'"), - ("py:class", "'bool'"), - ("py:class", "'object'"), - ("py:class", "'id'"), - ("py:class", "typing_extensions.Literal"), -] - -# Both the class’ and the __init__ method’s docstring are concatenated and -# inserted into the main body of the autoclass directive -autoclass_content = "both" - -# Order the members by the order they appear in the source code -autodoc_member_order = "bysource" - -# Don't inherit docstrings from baseclasses -autodoc_inherit_docstrings = False - -# Output graphviz directive produced images in a scalable format -graphviz_output_format = "svg" - -# The name of a reST role (builtin or Sphinx extension) to use as the default -# role, that is, for text marked up `like this` -default_role = "any" - -# The suffix of source filenames. -source_suffix = ".rst" - -# The main toctree document. -main_doc = "index" - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# These patterns also affect html_static_path and html_extra_path -exclude_patterns = ["_build"] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = "sphinx" - -# This means you can link things like `str` and `asyncio` to the relevant -# docs in the python documentation. -intersphinx_mapping = dict(python=("https://docs.python.org/3/", None)) - -# A dictionary of graphviz graph attributes for inheritance diagrams. -inheritance_graph_attrs = dict(rankdir="TB") - -# Common links that should be available on every page -rst_epilog = """ -.. _Diamond Light Source: - http://www.diamond.ac.uk -""" - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = "sphinx_rtd_theme_github_versions" - -# Options for the sphinx rtd theme, use DLS blue -html_theme_options = dict(style_nav_header_background="rgb(7, 43, 93)") - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -html_show_sphinx = False - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -html_show_copyright = False - -# Add some CSS classes for columns and other tweaks in a custom css file -html_css_files = ["theme_overrides.css"] - -# Logo -html_logo = "images/builder2ibek-logo.svg" -html_favicon = "images/builder2ibek-favicon.ico" diff --git a/docs/explanations.rst b/docs/explanations.rst deleted file mode 100644 index 45a29b3..0000000 --- a/docs/explanations.rst +++ /dev/null @@ -1,11 +0,0 @@ -:orphan: - -Explanations -============ - -Explanation of how the library works and why it works that way. - -.. toctree:: - :caption: Explanations - - explanations/todo diff --git a/docs/explanations/todo.rst b/docs/explanations/todo.rst deleted file mode 100644 index 3300056..0000000 --- a/docs/explanations/todo.rst +++ /dev/null @@ -1,4 +0,0 @@ -Explanations -============ - -Todo diff --git a/docs/how-to.rst b/docs/how-to.rst deleted file mode 100644 index 4ade98a..0000000 --- a/docs/how-to.rst +++ /dev/null @@ -1,11 +0,0 @@ -:orphan: - -How-to Guides -============= - -Practical step-by-step guides for the more experienced user. - -.. toctree:: - :caption: How-to Guides - - how-to/todo diff --git a/docs/how-to/todo.rst b/docs/how-to/todo.rst deleted file mode 100644 index ad881e9..0000000 --- a/docs/how-to/todo.rst +++ /dev/null @@ -1,4 +0,0 @@ -How To -====== - -Todo \ No newline at end of file diff --git a/docs/images/builder2ibek-favicon.ico b/docs/images/builder2ibek-favicon.ico deleted file mode 100644 index 1c42a8e09f5f0cf30186880733673a958c7373a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14318 zcmc&*XK+;46_!I1l1br5CS@|2IGM>LnaNBtlQ?aX8NgK045Hf@@L+>mY!Fpc0TR7Q zs325V1*9zkQAF>e3nT&BT@V6kSH|r}Jc%6xDmUl5Z_n=Cx9_cXR~Ya-pZD(Gd*Aua zJ@>Tx6c_g#{nzg=arFOR#JT?(7x$yMxVYca)sL=s=|X!n{|fKl|CaSu>&Gh{HDc__ z;vQW?7G{aQbGFHA_>x@XxmJ~k#Dc>j|B_qSU0z{rY!#E%6^nj}Y5uXeUr=^b{*FEd z*F&4jn-C37v%Yp$+cd)8K55M^V}7HM$>`;Uehe?p-5xaGIKn;8a!goi?+BYSfN9f_ zE23{A$!xYJH^{F);YU9M+-h69!`U|63|FM>B>&p=2d{MYbnSWkfO#2y8H`$1AjXmW z5(^KD;_J3v|`<=&y^?WgMf_({*D z+^i(43fe0?R-qqPxjjGCV~gb3?(!s-)-^xE8pVRuXv_%O_x*e}0BdV?8uBd4Z?=f| z#gLVPpYBJm%n!k6_36!)qt}A$h9ZMARv~&tf?4fTajW&*x&xQHjBv!-HY_PeK!>rG z!=IonHZ-=~X}d(Ik;!TOh6zbmG1wu$Lm>|$f}Rbg{^v^_;S;&8Pk zso1)^w>CC@lg2-sO}02ztom`2*X;_j;|Z$@46&3o+!F)m2kZpPVBmrb(u@0sV<0!k zptSy;n7Y9#d44^8k0`2bl0Jlf{}TJTJKX#`+0MUV&R5o#KN0*`myyeN2CXUlSkC!d zA$Z=)KOkP5r|Ae|f01{Sma-X@q)r_w@O7p#2 zT-W?izlO0qPg%EHWSza?xBHB#KiTz3>q~+#6hXU&gGbh#6Mx zJ?~$)i791LCTOp0YWsUQ?8!oW&Eb6TNAkhd=_l*j6Ot`753bm3ApH7HpZxW446wnz z&n`SDmf23pYtp)s5d6@SDVujigq>vpUpkF+j`@Zj@1lK0{^E06qt{zn-+bQT{9vFe zi%M794@mFNZ8&sUOk7(Wq^laQX=1>Jx^#9KUP|9NR*)t+<0?rtk*{Fdu?KgRlUAC9@< zuh5Rz4RYgl?#C1|>o+G&>c<$`H*5A^k~W$7hFu>@Sh#m;*7&$fdca z`i;3pkp3g536)2h^zoTz8vL<5_T#Ixha<(T?>B~g9OIRJqeN^6}xet}I5*wQAPbnWCFM)TZiE*Se70%Y$;)ajD!}w2~5?^Dx<$@jlrQXhNl1K$Wcsprw?dE=o_zqX$I zuTfup8{4_~B|8LSM&yNR?SSp&WQxCdZJ5rt9HqXk{}Dnw$GDl=Ty3*T>h8uI`@KYU z4ryy(bLi6Z&CkP#ZzF!u2A{|MRLVAB)QVh@Sac{T7iPSA`tsUP{K%2e&+7i*H;kJp z`NTJS8v7PsZ<4-v`nC!K|Df$_-&#JfvP_931YlXaU zul}aqLtk<(aJ?*0BQ?WMbz6~aKWmD=;$|z=NIer7H&chZtv}}E96A>Kv-1y;ZS%;y zJF&1jxQ=BKtEgCw?h(f!rjI5Unwe2$h#xgQigCJZx4rRhb$|)rMn@ z<_ol0sIHq&u~#K2r(^tTb9=uci>k-wuW~-Rhdu!8&KeRi&U2kXaHwj+3p{s`HAHeCCKl~EuzgaDCZV}}gbQYoF;rl@bxgKgw{JWmgx=~JBCF=|< zd*%al5b-f?Wq6%kVMo5%(yGU+f5zD_okMj@p!zZEJLoXw3=8iZws@zq=Dha7bi*M! zkI}6uuo=bqLl@FBX!mde5Ubv#Ydsz@C$?q1LU= z8_oS3I#VobxG(E7vx^Q&f5H5N;tYf_no-odDSr`&(QqDtaj>O>=-!MM*m9b$tMYc+ zAI$I?wHIB#lcm<}2QSJteTUh*_3fxhAvZz&n(H_$1NaLg-01+UWkIvRQskU>}2%}jWa-lhv>MuC{fQ-%TydGos&lW9qAf6@vG&kZ$$VA1D zdOyAgO4)lsAZ|7K9wB~F4(VkeHW*4ZIGjN+4~uu761#7;kp1y?hV%QX9IRgNw~3Dr zRU18GX?Xj}?~8eqbL(--O`&8fVw9ZMBOj8!8O(8qJToqdFhv#CJyV^qoP1 z@7&I9@u^Qd;892UEz+A9Xv$871lqYm1K4c-;Et(UtBl3Rjtkv9i z8DZA9;Y<>8)XPEYmk+~4*cYc~v=L^t&EDAhJLuueEQiF7dEckATAb(NOj-Z#XrI+u z$4hj6676`i{*dFaB<))RtQq?k*crqNiz`mjxtHe!6|2!b&cf*|pl0jwT4`Hxu85eG z_Tv}nCmT9pQ_OgXq#bzz>wP5sqwSMgb-ruu{tNAIWICizd56vgv~LJJ$BgRUMl!HA z-v0^dfP=mx`I6{obfwvwAG~07djGriSY2mNYDBy)IG2eQTiE`zE_C+VMYirS>^J4I zui%`McyFL6{f}CK5uRw;5K~gF)=oNk)!O*r=h0y3X9 zm@YbZ=z4=?G&Z@?!b~##J zzsml!HvK5h+J)~(sh-?H=hGdC!)MZWSd&tBQLIb#Gg^D>0ocMZR7X{DqYu8>!WfLD zdTl#$QQBwLuiCahNx76ZHGLmGxWehNP~GVxT05EFP#xxx8UrED#t2EH?xk#2A2ZzT|$j##GEe(1L%^g-We!Q<0PBXRt9 z7v0g`r+wpmv{z4Qi*G(Ns^N<3qo*4FxaXO6X!G>tXMKPDGxzJ7j)A>}Ca^w26X^3o o$O-$B+s5xi#A*7&JW!g6y2%cGLB;7_l8A@0nP%|Oj_0ZU|C{>R$N&HU diff --git a/docs/images/builder2ibek-logo.svg b/docs/images/builder2ibek-logo.svg deleted file mode 100644 index 6343eb4..0000000 --- a/docs/images/builder2ibek-logo.svg +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 9bde8ad..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,48 +0,0 @@ -.. include:: ../README.rst - :end-before: when included in index.rst - - -How the documentation is structured ------------------------------------ - -Documentation is split into four categories, also accessible from links in the -side-bar. - -.. rst-class:: columns - -`tutorials` -~~~~~~~~~~~ - -.. include:: tutorials.rst - :start-after: ========= - -.. rst-class:: columns - -`how-to` -~~~~~~~~ - -.. include:: how-to.rst - :start-after: ============= - -.. rst-class:: columns - -`explanations` -~~~~~~~~~~~~~~ - -.. include:: explanations.rst - :start-after: ============ - -.. rst-class:: columns - -`reference` -~~~~~~~~~~~ - -.. include:: reference.rst - :start-after: ========= - -.. rst-class:: endcolumns - -About the documentation -~~~~~~~~~~~~~~~~~~~~~~~ - -`Why is the documentation structured this way? `_ diff --git a/docs/reference.rst b/docs/reference.rst deleted file mode 100644 index ab3ea14..0000000 --- a/docs/reference.rst +++ /dev/null @@ -1,18 +0,0 @@ -:orphan: - -Reference -========= - -Practical step-by-step guides for the more experienced user. - -.. toctree:: - :caption: Reference - - reference/api - reference/contributing - Releases - Index - -.. - Index link above is a hack to make genindex.html a relative link - https://stackoverflow.com/a/31820846 diff --git a/docs/reference/api.rst b/docs/reference/api.rst deleted file mode 100644 index 1a0c09d..0000000 --- a/docs/reference/api.rst +++ /dev/null @@ -1,17 +0,0 @@ -API -=== - -This is the internal API reference for ibek - - -.. automodule ibek - -``ibek`` -~~~~~~~~ - -.. data:: ibek.__version__ - :type: str - - Version number as calculated by setuptools_scm - - diff --git a/docs/reference/contributing.rst b/docs/reference/contributing.rst deleted file mode 100644 index ac7b6bc..0000000 --- a/docs/reference/contributing.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../CONTRIBUTING.rst diff --git a/docs/tutorials.rst b/docs/tutorials.rst deleted file mode 100644 index dfdef50..0000000 --- a/docs/tutorials.rst +++ /dev/null @@ -1,11 +0,0 @@ -:orphan: - -Tutorials -========= - -Tutorials for installation, library and commandline usage. New users start here. - -.. toctree:: - :caption: Tutorials - - tutorials/installation diff --git a/docs/tutorials/installation.rst b/docs/tutorials/installation.rst deleted file mode 100644 index 8c6cc26..0000000 --- a/docs/tutorials/installation.rst +++ /dev/null @@ -1,47 +0,0 @@ -Installation -============ - -.. note:: - - For installation inside DLS, please see the internal documentation on - ``dls-python3`` and ``pipenv``. Although these instructions will work - inside DLS, they are intended for external use. - - If you want to contribute to the library itself, please follow - the `../reference/contributing` instructions. - - -Check your version of python ----------------------------- - -You will need python 3.7 or later. You can check your version of python by -typing into a terminal:: - - python3 --version - -Create a virtual environment ----------------------------- - -It is recommended that you install into a “virtual environment” so this -installation will not interfere with any existing Python software:: - - python3 -m venv /path/to/venv - source /path/to/venv/bin/activate - - -Installing the library ----------------------- - -You can now use ``pip`` to install the library:: - - python3 -m pip install builder2ibek - -If you require a feature that is not currently released you can also install -from github:: - - python3 -m pip install git+git://github.com/epics-containers/builder2ibek.git - -The library should now be installed and the commandline interface on your path. -You can check the version that has been installed by typing:: - - builder2ibek --version diff --git a/pyproject.toml b/pyproject.toml index e23575d..54162fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=64", "setuptools_scm[toml]==7.1.0", "wheel"] +requires = ["setuptools>=64", "setuptools_scm[toml]>=6.2"] build-backend = "setuptools.build_meta" [project] @@ -7,36 +7,30 @@ name = "builder2ibek" classifiers = [ "Development Status :: 3 - Alpha", "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", ] -description = "Converter from IOC Builder to ibek" -dependencies = [ - "ibek", -] # Add project dependencies here, e.g. ["click", "numpy"] +description = "Conversion tool for DLS XML builder IOC instances to ibek ioc.yaml" +dependencies = ["ibek"] # Add project dependencies here, e.g. ["click", "numpy"] dynamic = ["version"] license.file = "LICENSE" -readme = "README.rst" +readme = "README.md" requires-python = ">=3.10" [project.optional-dependencies] dev = [ - "black", + "copier", "mypy", "pipdeptree", "pre-commit", - "pydata-sphinx-theme>=0.12", "pytest", "pytest-cov", - "pytest-mock", "ruff", - "Sphinx==6.2.1", - "sphinx-autobuild", - "sphinx-copybutton", - "sphinx-design", "tox-direct", "types-mock", - "sphinx-rtd-theme-github-versions", ] [project.scripts] @@ -46,8 +40,8 @@ builder2ibek = "builder2ibek.__main__:cli" GitHub = "https://github.com/epics-containers/builder2ibek" [[project.authors]] # Further authors may be added by duplicating this section -email = "tom.cobb@diamond.ac.uk" -name = "Tom Cobb" +email = "giles.knap@diamond.ac.uk" +name = "Giles Knap" [tool.setuptools_scm] @@ -59,11 +53,10 @@ ignore_missing_imports = true # Ignore missing stubs in imported modules [tool.pytest.ini_options] # Run pytest with all our checkers, and don't spam us with massive tracebacks on error addopts = """ - --tb=native -vv --doctest-modules --doctest-glob="*.rst" - --cov=builder2ibek --cov-report term --cov-report xml:cov.xml + --tb=native -vv """ # https://iscinumpy.gitlab.io/post/bound-version-constraints/#watch-for-warnings -filterwarnings = ["error", "ignore::pytest_cov.plugin.CovDisabledWarning"] +filterwarnings = "error" # Doctest python code in docs, python code in src docstrings, test functions in tests testpaths = "docs src tests" @@ -81,7 +74,7 @@ legacy_tox_ini = """ [tox] skipsdist=True -[testenv:{pre-commit,mypy,pytest,docs}] +[testenv:{pre-commit,type-checking,tests}] # Don't create a virtualenv for the command, requires tox-direct plugin direct = True passenv = * @@ -89,32 +82,26 @@ allowlist_externals = pytest pre-commit mypy - sphinx-build - sphinx-autobuild commands = - pytest: pytest --cov=builder2ibek --cov-report term --cov-report xml:cov.xml {posargs} - mypy: mypy src tests {posargs} - pre-commit: pre-commit run --all-files {posargs} - docs: sphinx-{posargs:build -EW --keep-going} -T docs build/html + pre-commit: pre-commit run --all-files --show-diff-on-failure {posargs} + type-checking: mypy src tests {posargs} + tests: pytest --cov=builder2ibek --cov-report term --cov-report xml:cov.xml {posargs} """ - [tool.ruff] src = ["src", "tests"] -ignore = [ - "C408", # Unnecessary collection call - e.g. list(...) instead of [...] - "E501", # Line too long, should be fixed by black. +lint.ignore = [ + "C408", # Unnecessary collection call - e.g. list(...) instead of [...] + "UP007", # Do not complain about Optional[] (TODO: remove once typer is patched) + "B008", # Do not perform function call `typer.Argument` in argument defaults; ] line-length = 88 -select = [ - "C4", # flake8-comprehensions - https://beta.ruff.rs/docs/rules/#flake8-comprehensions-c4 - "E", # pycodestyle errors - https://beta.ruff.rs/docs/rules/#error-e - "F", # pyflakes rules - https://beta.ruff.rs/docs/rules/#pyflakes-f - "W", # pycodestyle warnings - https://beta.ruff.rs/docs/rules/#warning-w - "I001", # isort +lint.select = [ + "B", # flake8-bugbear - https://docs.astral.sh/ruff/rules/#flake8-bugbear-b + "C4", # flake8-comprehensions - https://docs.astral.sh/ruff/rules/#flake8-comprehensions-c4 + "E", # pycodestyle errors - https://docs.astral.sh/ruff/rules/#error-e + "F", # pyflakes rules - https://docs.astral.sh/ruff/rules/#pyflakes-f + "W", # pycodestyle warnings - https://docs.astral.sh/ruff/rules/#warning-w + "I", # isort - https://docs.astral.sh/ruff/rules/#isort-i + "UP", # pyupgrade - https://docs.astral.sh/ruff/rules/#pyupgrade-up ] -[tool.ruff.per-file-ignores] - -[tool.setuptools.packages.find] -where = ["src"] - diff --git a/src/builder2ibek/__init__.py b/src/builder2ibek/__init__.py index 5875d99..26d23ba 100644 --- a/src/builder2ibek/__init__.py +++ b/src/builder2ibek/__init__.py @@ -1,14 +1,3 @@ -try: - # Use live version from git - from setuptools_scm import get_version - - # Warning: If the install is nested to the same depth, this will always succeed - tmp_version = get_version(root="../../", relative_to=__file__) - del get_version -except (ImportError, LookupError): - # Use installed version - from ._version import version as __version__ -else: - __version__ = tmp_version +from ._version import __version__ __all__ = ["__version__"] diff --git a/src/builder2ibek/__main__.py b/src/builder2ibek/__main__.py index 034d278..a2541ab 100644 --- a/src/builder2ibek/__main__.py +++ b/src/builder2ibek/__main__.py @@ -49,7 +49,7 @@ def tidy_up(yaml): "entities", " - type", ]: - yaml = re.sub(r"(\n%s)" % field, "\n\\g<1>", yaml) + yaml = re.sub(rf"(\n{field})", "\n\\g<1>", yaml) return yaml """Convert a single builder XML file into a single ibek YAML""" @@ -88,7 +88,6 @@ def beamline( raise typer.Exit(code=1) -# test with: -# pipenv run python -m builder2ibek +# test with: python -m builder2ibek if __name__ == "__main__": - cli() + main() diff --git a/src/builder2ibek/builder.py b/src/builder2ibek/builder.py index 3c11ffc..752b722 100644 --- a/src/builder2ibek/builder.py +++ b/src/builder2ibek/builder.py @@ -3,7 +3,6 @@ """ from pathlib import Path -from typing import List from xml.dom.minidom import Document, parse, parseString from xml.dom.minidom import Element as DomElement @@ -19,7 +18,7 @@ def __init__(self) -> None: self.file: Path = Path() self.name: str = "" self.arch: str = "" - self.elements: List[Element] = [] + self.elements: list[Element] = [] def load_string(self, xml_str: str): """ diff --git a/src/builder2ibek/convert.py b/src/builder2ibek/convert.py index eaae778..c85315f 100644 --- a/src/builder2ibek/convert.py +++ b/src/builder2ibek/convert.py @@ -2,7 +2,7 @@ Generic XML to YAML conversion functions """ -from typing import Any, Dict, List +from typing import Any from builder2ibek.builder import Builder, Element from builder2ibek.moduleinfos import module_infos @@ -32,7 +32,7 @@ def do_dispatch(builder: Builder, ioc: Generic_IOC): for element in builder.elements: do_one_element(element, ioc) - sorted_entities: List[Entity] = [] + sorted_entities: list[Entity] = [] for entity in ioc.entities: # type: ignore # sort the args by key entity = Entity(sorted(entity.items())) # type: ignore @@ -65,7 +65,7 @@ def do_one_element(element: Element, ioc: Generic_IOC): add_defaults(entity, info.defaults) -def add_defaults(entity: Dict[str, Any], defaults: Dict[str, Dict[str, Any]]): +def add_defaults(entity: dict[str, Any], defaults: dict[str, dict[str, Any]]): this_entity_defaults = defaults.get(entity["type"]) if this_entity_defaults: needed_defaults = { diff --git a/src/builder2ibek/moduleinfos.py b/src/builder2ibek/moduleinfos.py index d1c2490..f0870c5 100644 --- a/src/builder2ibek/moduleinfos.py +++ b/src/builder2ibek/moduleinfos.py @@ -1,7 +1,8 @@ +from collections.abc import Callable from dataclasses import dataclass from importlib import import_module from pathlib import Path -from typing import Any, Callable, Dict +from typing import Any converters_path = Path(__file__).parent / "converters" @@ -9,12 +10,12 @@ @dataclass class ModuleInfo: handler: Callable - defaults: Dict[str, Dict[str, Any]] + defaults: dict[str, dict[str, Any]] schema: str yaml_component: str -module_infos: Dict[str, ModuleInfo] = {} +module_infos: dict[str, ModuleInfo] = {} # automatically load all of the convert handlers in ./converters into the @@ -24,7 +25,7 @@ class ModuleInfo: if not converter.name.startswith("_"): module = import_module(f"builder2ibek.converters.{converter.stem}") if module is not None: - xml_component = getattr(module, "xml_component") + xml_component = module.xml_component info = ModuleInfo( getattr(module, "handler", lambda *args: None), getattr(module, "defaults", {}), diff --git a/src/builder2ibek/types.py b/src/builder2ibek/types.py index 312a0fb..ab6ca53 100644 --- a/src/builder2ibek/types.py +++ b/src/builder2ibek/types.py @@ -1,9 +1,10 @@ """ Dataclasses for representing XML and YAML in memory """ + from dataclasses import dataclass from pathlib import Path -from typing import Any, Dict, List +from typing import Any from pydantic import BaseModel, ConfigDict @@ -12,7 +13,7 @@ DELETE_ME = "__delete_me__" -class Entity(Dict[str, Any]): +class Entity(dict[str, Any]): """ Generic Entity has functions for using . notation which makes the code in the convertors package easier to type and read @@ -48,7 +49,7 @@ class Generic_IOC(BaseModel): ) ioc_name: str description: str - entities: List[Dict[str, Any]] + entities: list[dict[str, Any]] source_file: Path @@ -57,4 +58,4 @@ class Generic_IOC(BaseModel): class Element: name: str module: str - attributes: Dict[str, str] + attributes: dict[str, str] diff --git a/tests/conftest.py b/tests/conftest.py index 682d6fd..d5cdd5f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,21 +1,15 @@ -from pathlib import Path +import os -from ibek.support import Support -from pytest import fixture -from ruamel.yaml import YAML +import pytest +# Prevent pytest from catching exceptions when debugging in vscode so that break on +# exception works correctly (see: https://github.com/pytest-dev/pytest/issues/7409) +if os.getenv("PYTEST_RAISE", "0") == "1": -def get_support(samples: Path, yaml_file: str) -> Support: - """ - Get a support object from the sample YAML directory - """ - # load from file - d = YAML(typ="safe").load(samples / "yaml" / f"{yaml_file}") - # create a support object from that dict - support = Support.deserialize(d) - return support + @pytest.hookimpl(tryfirst=True) + def pytest_exception_interact(call): + raise call.excinfo.value - -@fixture -def samples(): - return Path(__file__).parent / "samples" + @pytest.hookimpl(tryfirst=True) + def pytest_internalerror(excinfo): + raise excinfo.value diff --git a/tests/test_cli.py b/tests/test_cli.py index 0bf783f..c8e58b8 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,40 +1,9 @@ -import filecmp import subprocess import sys -from pathlib import Path -from shutil import copy - -from typer.testing import CliRunner from builder2ibek import __version__ -from builder2ibek.__main__ import cli - -runner = CliRunner() def test_cli_version(): cmd = [sys.executable, "-m", "builder2ibek", "--version"] assert subprocess.check_output(cmd).decode().strip() == __version__ - - -def run_cli(*args): - result = runner.invoke(cli, [str(x) for x in args]) - if result.exception: - raise result.exception - assert result.exit_code == 0, result - - -def test_mo_01(tmp_path: Path, samples: Path): - """read and convert p45s 1st motion IOC""" - - ioc_xml_file = samples / "BL45P-MO-IOC-01.xml" - example_yaml_file = samples / "bl45p-mo-ioc-01.yaml" - yaml_file = tmp_path / "bl45p-mo-ioc-01.yaml" - run_cli("file", ioc_xml_file, "--yaml", yaml_file) - - example_out = Path("/tmp/bl45p-mo-ioc-01-example.yaml") - - assert filecmp.cmp(yaml_file, example_yaml_file) - - # TODO for the moment copy the result out of the ephemeral folder for debugging - copy(str(yaml_file.absolute()), example_out)