pax_global_header00006660000000000000000000000064146504217060014517gustar00rootroot0000000000000052 comment=44d509d486ccf55692adc35e5bb599d6dfabc4b7 consolekit-1.7.1/000077500000000000000000000000001465042170600136775ustar00rootroot00000000000000consolekit-1.7.1/.bumpversion.cfg000066400000000000000000000011741465042170600170120ustar00rootroot00000000000000[bumpversion] current_version = 1.7.1 commit = True tag = True [bumpversion:file:repo_helper.yml] [bumpversion:file:README.rst] [bumpversion:file:doc-source/index.rst] [bumpversion:file:consolekit/__init__.py] search = : str = "{current_version}" replace = : str = "{new_version}" [bumpversion:file:consolekit/utils.py] search = current_version="{current_version}" replace = current_version="{new_version}" [bumpversion:file:pyproject.toml] search = version = "{current_version}" replace = version = "{new_version}" [bumpversion:file:.github/workflows/conda_ci.yml] search = ={current_version}=py_1 replace = ={new_version}=py_1 consolekit-1.7.1/.deepsource.toml000066400000000000000000000004751465042170600170160ustar00rootroot00000000000000version = 1 test_patterns = ["tests/**/test_*.py"] exclude_patterns = [ "doc-source/conf.py", ] [[analyzers]] name = "python" enabled = true [analyzers.meta] runtime_version = "3.x.x" max_line_length = 115 [[analyzers]] name = "test-coverage" enabled = true [[analyzers]] name = "secrets" enabled = true consolekit-1.7.1/.github/000077500000000000000000000000001465042170600152375ustar00rootroot00000000000000consolekit-1.7.1/.github/ISSUE_TEMPLATE/000077500000000000000000000000001465042170600174225ustar00rootroot00000000000000consolekit-1.7.1/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000022331465042170600221140ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve labels: bug assignees: domdfcoding --- ## Description ## Steps to Reproduce 1. 2. 3. ## Actual result: ## Expected result: ## Reproduces how often: ## Version * Operating System: * Python: * consolekit: ## Installation source ## Other Additional Information: consolekit-1.7.1/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000012161465042170600231470ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project labels: "enhancement" assignees: domdfcoding --- ## Description ## Version * Operating System: * Python: * consolekit: ## Other Additional Information: consolekit-1.7.1/.github/auto_assign.yml000066400000000000000000000003471465042170600203020ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. --- addReviewers: true addAssignees: true reviewers: - domdfcoding numberOfReviewers: 0 # more settings at https://github.com/marketplace/actions/auto-assign-action consolekit-1.7.1/.github/dependabot.yml000066400000000000000000000003351465042170600200700ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. --- version: 2 updates: - package-ecosystem: pip directory: / schedule: interval: weekly open-pull-requests-limit: 0 reviewers: - domdfcoding consolekit-1.7.1/.github/milestones.py000077500000000000000000000012401465042170600177730ustar00rootroot00000000000000#!/usr/bin/env python # stdlib import os import sys # 3rd party from github3 import GitHub from github3.repos import Repository from packaging.version import InvalidVersion, Version latest_tag = os.environ["GITHUB_REF_NAME"] try: current_version = Version(latest_tag) except InvalidVersion: sys.exit() gh: GitHub = GitHub(token=os.environ["GITHUB_TOKEN"]) repo: Repository = gh.repository(*os.environ["GITHUB_REPOSITORY"].split('/', 1)) for milestone in repo.milestones(state="open"): try: milestone_version = Version(milestone.title) except InvalidVersion: continue if milestone_version == current_version: sys.exit(not milestone.update(state="closed")) consolekit-1.7.1/.github/stale.yml000066400000000000000000000040211465042170600170670ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. # Configuration for probot-stale - https://github.com/probot/stale --- # Number of days of inactivity before an Issue or Pull Request becomes stale daysUntilStale: 180 # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. daysUntilClose: false # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) onlyLabels: [] # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable exemptLabels: - pinned - security - "[Status] Maybe Later" # Set to true to ignore issues in a project (defaults to false) exemptProjects: false # Set to true to ignore issues in a milestone (defaults to false) exemptMilestones: false # Set to true to ignore issues with an assignee (defaults to false) exemptAssignees: false # Label to use when marking as stale staleLabel: stale # Comment to post when marking as stale. Set to `false` to disable markComment: false # This issue has been automatically marked as stale because it has not had # recent activity. It will be closed if no further activity occurs. Thank you # for your contributions. # Comment to post when removing the stale label. # unmarkComment: > # Your comment here. # Comment to post when closing a stale Issue or Pull Request. # closeComment: > # Your comment here. # Limit the number of actions per hour, from 1-30. Default is 30 limitPerRun: 30 # Limit to only `issues` or `pulls` # only: issues # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': # pulls: # daysUntilStale: 30 # markComment: > # This pull request has been automatically marked as stale because it has not had # recent activity. It will be closed if no further activity occurs. Thank you # for your contributions. # issues: # exemptLabels: # - confirmed consolekit-1.7.1/.github/workflows/000077500000000000000000000000001465042170600172745ustar00rootroot00000000000000consolekit-1.7.1/.github/workflows/conda_ci.yml000066400000000000000000000037261465042170600215660ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. --- name: Conda Tests on: push: branches: ["master"] permissions: contents: read jobs: tests: name: "Conda" runs-on: ubuntu-22.04 defaults: run: shell: bash -l {0} steps: - name: Checkout 🛎️ uses: "actions/checkout@v4" - name: Setup Python 🐍 uses: "actions/setup-python@v5" with: python-version: "3.11" - name: Setup Conda uses: conda-incubator/setup-miniconda@v2.1.1 with: activate-environment: env conda-build-version: 3.28.4 miniconda-version: py311_24.1.2-0 python-version: "3.11" miniforge-variant: Mambaforge - name: Install dependencies 🔧 run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel python -m pip install --upgrade "whey-conda" "flit-core<4,>=3.2" # $CONDA is an environment variable pointing to the root of the miniconda directory $CONDA/bin/conda update -n base conda $CONDA/bin/conda config --add channels conda-forge $CONDA/bin/conda config --add channels domdfcoding - name: "Build and index channel" run: | python -m whey --builder whey_conda --out-dir conda-bld/noarch $CONDA/bin/conda index ./conda-bld || exit 1 - name: "Search for package" run: | $CONDA/bin/conda search -c file://$(pwd)/conda-bld consolekit $CONDA/bin/conda search -c file://$(pwd)/conda-bld --override-channels consolekit - name: "Install package" run: | $CONDA/bin/conda install -c file://$(pwd)/conda-bld consolekit=1.7.1=py_1 -y || exit 1 - name: "Run Tests" run: | rm -rf consolekit $CONDA/bin/conda install pytest coincidence || exit 1 pip install -r tests/requirements.txt pytest tests/ consolekit-1.7.1/.github/workflows/docs_test_action.yml000066400000000000000000000015501465042170600233440ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. --- name: "Docs Check" on: push: branches-ignore: - 'repo-helper-update' - 'pre-commit-ci-update-config' - 'imgbot' pull_request: permissions: contents: read jobs: docs: runs-on: ubuntu-latest steps: - name: Checkout 🛎️ uses: "actions/checkout@v4" - name: Check for changed files uses: dorny/paths-filter@v2 id: changes with: list-files: "json" filters: | code: - '!tests/**' - name: Install and Build 🔧 uses: sphinx-toolbox/sphinx-action@sphinx-3.3.1 if: steps.changes.outputs.code == 'true' with: pre-build-command: python -m pip install tox docs-folder: "doc-source/" build-command: "tox -e docs -- -W " consolekit-1.7.1/.github/workflows/flake8.yml000066400000000000000000000023361465042170600211750ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. --- name: Flake8 on: push: branches-ignore: - 'repo-helper-update' - 'pre-commit-ci-update-config' - 'imgbot' pull_request: permissions: contents: read jobs: Run: name: "Flake8" runs-on: "ubuntu-20.04" steps: - name: Checkout 🛎️ uses: "actions/checkout@v4" - name: Check for changed files uses: dorny/paths-filter@v2 id: changes with: list-files: "json" filters: | code: - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' - name: Setup Python 🐍 if: steps.changes.outputs.code == 'true' uses: "actions/setup-python@v5" with: python-version: "3.8" - name: Install dependencies 🔧 if: steps.changes.outputs.code == 'true' run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel python -m pip install tox~=3.0 - name: "Run Flake8" if: steps.changes.outputs.code == 'true' run: "python -m tox -e lint -s false -- --format github" consolekit-1.7.1/.github/workflows/mypy.yml000066400000000000000000000024501465042170600210160ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. --- name: mypy on: push: branches-ignore: - 'repo-helper-update' - 'pre-commit-ci-update-config' - 'imgbot' pull_request: permissions: contents: read jobs: Run: name: "mypy / ${{ matrix.os }}" runs-on: ${{ matrix.os }} strategy: matrix: os: ['ubuntu-20.04', 'windows-2019'] fail-fast: false steps: - name: Checkout 🛎️ uses: "actions/checkout@v4" - name: Check for changed files uses: dorny/paths-filter@v2 id: changes with: list-files: "json" filters: | code: - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' - name: Setup Python 🐍 if: steps.changes.outputs.code == 'true' uses: "actions/setup-python@v5" with: python-version: "3.8" - name: Install dependencies 🔧 run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel python -m pip install --upgrade tox~=3.0 virtualenv!=20.16.0 - name: "Run mypy" if: steps.changes.outputs.code == 'true' run: "python -m tox -e mypy -s false" consolekit-1.7.1/.github/workflows/octocheese.yml000066400000000000000000000006151465042170600221420ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. --- name: "GitHub Releases" on: schedule: - cron: 0 12 * * * jobs: Run: runs-on: ubuntu-latest steps: - uses: domdfcoding/octocheese@master with: pypi_name: "consolekit" env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} if: startsWith(github.ref, 'refs/tags/') != true consolekit-1.7.1/.github/workflows/python_ci.yml000066400000000000000000000063721465042170600220230ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. --- name: Windows on: push: branches-ignore: - 'repo-helper-update' - 'pre-commit-ci-update-config' - 'imgbot' pull_request: permissions: actions: write issues: write contents: read jobs: tests: name: "windows-2019 / Python ${{ matrix.config.python-version }}" runs-on: "windows-2019" continue-on-error: ${{ matrix.config.experimental }} env: USING_COVERAGE: '3.6,3.7,3.8,3.9,3.10,3.11,3.12,3.13.0-beta.3,pypy-3.6,pypy-3.7,pypy-3.8,pypy-3.9' strategy: fail-fast: False matrix: config: - {python-version: "3.6", testenvs: "py36-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.7", testenvs: "py37-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.8", testenvs: "py38-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.9", testenvs: "py39-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.10", testenvs: "py310-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.11", testenvs: "py311-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.12", testenvs: "py312-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.13.0-beta.3", testenvs: "py313-dev-click{7.1,8.0,8.1},build", experimental: True} - {python-version: "pypy-3.6", testenvs: "pypy36-click{7.1,8.0,8.1}", experimental: False} - {python-version: "pypy-3.7", testenvs: "pypy37-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "pypy-3.8", testenvs: "pypy38-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "pypy-3.9-v7.3.15", testenvs: "pypy39-click{7.1,8.0,8.1},build", experimental: True} steps: - name: Checkout 🛎️ uses: "actions/checkout@v4" - name: Check for changed files if: startsWith(github.ref, 'refs/tags/') != true uses: dorny/paths-filter@v2 id: changes with: list-files: "json" filters: | code: - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' - name: Setup Python 🐍 id: setup-python if: ${{ steps.changes.outputs.code == 'true' || steps.changes.outcome == 'skipped' }} uses: "actions/setup-python@v5" with: python-version: "${{ matrix.config.python-version }}" - name: Install dependencies 🔧 if: steps.setup-python.outcome == 'success' run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel python -m pip install --upgrade tox~=3.0 virtualenv!=20.16.0 - name: "Run Tests for Python ${{ matrix.config.python-version }}" if: steps.setup-python.outcome == 'success' run: python -m tox -e "${{ matrix.config.testenvs }}" -s false - name: "Upload Coverage 🚀" uses: actions/upload-artifact@v4 if: ${{ always() && steps.setup-python.outcome == 'success' }} with: name: "coverage-${{ matrix.config.python-version }}" path: .coverage consolekit-1.7.1/.github/workflows/python_ci_linux.yml000066400000000000000000000200411465042170600232270ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. --- name: Linux on: push: branches-ignore: - 'repo-helper-update' - 'pre-commit-ci-update-config' - 'imgbot' tags: - '*' pull_request: permissions: actions: write issues: write contents: read jobs: tests: name: "ubuntu-20.04 / Python ${{ matrix.config.python-version }}" runs-on: "ubuntu-20.04" continue-on-error: ${{ matrix.config.experimental }} env: USING_COVERAGE: '3.6,3.7,3.8,3.9,3.10,3.11,3.12,3.13.0-beta.3,pypy-3.6,pypy-3.7,pypy-3.8,pypy-3.9' strategy: fail-fast: False matrix: config: - {python-version: "3.6", testenvs: "py36-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.7", testenvs: "py37-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.8", testenvs: "py38-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.9", testenvs: "py39-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.10", testenvs: "py310-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.11", testenvs: "py311-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.12", testenvs: "py312-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.13.0-beta.3", testenvs: "py313-dev-click{7.1,8.0,8.1},build", experimental: True} - {python-version: "pypy-3.6", testenvs: "pypy36-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "pypy-3.7", testenvs: "pypy37-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "pypy-3.8", testenvs: "pypy38-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "pypy-3.9", testenvs: "pypy39-click{7.1,8.0,8.1},build", experimental: True} steps: - name: Checkout 🛎️ uses: "actions/checkout@v4" - name: Check for changed files if: startsWith(github.ref, 'refs/tags/') != true uses: dorny/paths-filter@v2 id: changes with: list-files: "json" filters: | code: - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' - name: Setup Python 🐍 id: setup-python if: ${{ steps.changes.outputs.code == 'true' || steps.changes.outcome == 'skipped' }} uses: "actions/setup-python@v5" with: python-version: "${{ matrix.config.python-version }}" - name: Install dependencies 🔧 if: steps.setup-python.outcome == 'success' run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel python -m pip install --upgrade tox~=3.0 virtualenv!=20.16.0 python -m pip install --upgrade coverage_pyver_pragma - name: "Run Tests for Python ${{ matrix.config.python-version }}" if: steps.setup-python.outcome == 'success' run: python -m tox -e "${{ matrix.config.testenvs }}" -s false - name: "Upload Coverage 🚀" uses: actions/upload-artifact@v4 if: ${{ always() && steps.setup-python.outcome == 'success' }} with: name: "coverage-${{ matrix.config.python-version }}" path: .coverage Coverage: needs: tests runs-on: "ubuntu-20.04" steps: - name: Checkout 🛎️ uses: "actions/checkout@v4" - name: Setup Python 🐍 uses: "actions/setup-python@v5" with: python-version: 3.8 - name: Install dependencies 🔧 run: | python -m pip install --upgrade pip setuptools wheel python -m pip install --upgrade "coveralls>=3.0.0" coverage_pyver_pragma - name: "Download Coverage 🪂" uses: actions/download-artifact@v4 with: path: coverage - name: Display structure of downloaded files id: show run: ls -R working-directory: coverage continue-on-error: true - name: Combine Coverage 👷 if: ${{ steps.show.outcome != 'failure' }} run: | shopt -s globstar python -m coverage combine coverage/**/.coverage - name: "Upload Combined Coverage Artefact 🚀" if: ${{ steps.show.outcome != 'failure' }} uses: actions/upload-artifact@v4 with: name: "combined-coverage" path: .coverage - name: "Upload Combined Coverage to Coveralls" if: ${{ steps.show.outcome != 'failure' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | coveralls --service=github Deploy: needs: tests runs-on: "ubuntu-20.04" steps: - name: Checkout 🛎️ uses: "actions/checkout@v4" if: startsWith(github.ref, 'refs/tags/') - name: Setup Python 🐍 uses: "actions/setup-python@v5" if: startsWith(github.ref, 'refs/tags/') with: python-version: 3.8 - name: Install dependencies 🔧 if: startsWith(github.ref, 'refs/tags/') run: | python -m pip install --upgrade pip setuptools wheel python -m pip install --upgrade tox~=3.0 - name: Build distributions 📦 if: startsWith(github.ref, 'refs/tags/') run: | tox -e build - name: Upload distribution to PyPI 🚀 if: startsWith(github.ref, 'refs/tags/') uses: pypa/gh-action-pypi-publish@v1.4.2 with: user: __token__ password: ${{ secrets.PYPI_TOKEN }} skip_existing: true - name: Close milestone 🚪 if: startsWith(github.ref, 'refs/tags/') run: | python -m pip install --upgrade github3.py packaging python .github/milestones.py env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} Conda: needs: deploy runs-on: ubuntu-22.04 if: startsWith(github.ref, 'refs/tags/') || (startsWith(github.event.head_commit.message, 'Bump version') != true) steps: - name: Checkout 🛎️ uses: "actions/checkout@v4" - name: Setup Python 🐍 uses: "actions/setup-python@v5" with: python-version: 3.11 - name: Setup Conda uses: conda-incubator/setup-miniconda@v2.1.1 with: activate-environment: env conda-build-version: 3.28.4 miniconda-version: py311_24.1.2-0 python-version: "3.11" miniforge-variant: Mambaforge - name: Install dependencies 🔧 run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel python -m pip install --upgrade "mkrecipe" "flit-core<4,>=3.2" # $CONDA is an environment variable pointing to the root of the miniconda directory $CONDA/bin/conda config --set always_yes yes --set changeps1 no $CONDA/bin/conda update -n base conda $CONDA/bin/conda info -a $CONDA/bin/conda config --add channels conda-forge $CONDA/bin/conda config --add channels domdfcoding $CONDA/bin/conda config --remove channels defaults - name: Build Conda Package 📦 run: | python -m mkrecipe --type wheel || exit 1 $CONDA/bin/conda build conda -c conda-forge -c domdfcoding --output-folder conda/dist - name: Deploy Conda Package 🚀 if: startsWith(github.ref, 'refs/tags/') run: | $CONDA/bin/conda config --set always_yes yes --set changeps1 no $CONDA/bin/conda install anaconda-client $CONDA/bin/conda info -a for f in conda/dist/noarch/consolekit-*.tar.bz2; do [ -e "$f" ] || continue echo "$f" conda install "$f" || exit 1 echo "Deploying to Anaconda.org..." $CONDA/bin/anaconda -t "$ANACONDA_TOKEN" upload "$f" || exit 1 echo "Successfully deployed to Anaconda.org." done env: ANACONDA_TOKEN: ${{ secrets.ANACONDA_TOKEN }} consolekit-1.7.1/.github/workflows/python_ci_macos.yml000066400000000000000000000061721465042170600232030ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. --- name: macOS on: push: branches-ignore: - 'repo-helper-update' - 'pre-commit-ci-update-config' - 'imgbot' pull_request: permissions: actions: write issues: write contents: read jobs: tests: name: "macos-13 / Python ${{ matrix.config.python-version }}" runs-on: "macos-13" continue-on-error: ${{ matrix.config.experimental }} env: USING_COVERAGE: '3.6,3.7,3.8,3.9,3.10,3.11,3.12,3.13.0-beta.3,pypy-3.7,pypy-3.8,pypy-3.9' strategy: fail-fast: False matrix: config: - {python-version: "3.6", testenvs: "py36-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.7", testenvs: "py37-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.8", testenvs: "py38-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.9", testenvs: "py39-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.10", testenvs: "py310-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.11", testenvs: "py311-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.12", testenvs: "py312-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "3.13.0-beta.3", testenvs: "py313-dev-click{7.1,8.0,8.1},build", experimental: True} - {python-version: "pypy-3.7", testenvs: "pypy37-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "pypy-3.8", testenvs: "pypy38-click{7.1,8.0,8.1},build", experimental: False} - {python-version: "pypy-3.9", testenvs: "pypy39-click{7.1,8.0,8.1},build", experimental: True} steps: - name: Checkout 🛎️ uses: "actions/checkout@v4" - name: Check for changed files if: startsWith(github.ref, 'refs/tags/') != true uses: dorny/paths-filter@v2 id: changes with: list-files: "json" filters: | code: - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' - name: Setup Python 🐍 id: setup-python if: ${{ steps.changes.outputs.code == 'true' || steps.changes.outcome == 'skipped' }} uses: "actions/setup-python@v5" with: python-version: "${{ matrix.config.python-version }}" - name: Install dependencies 🔧 if: steps.setup-python.outcome == 'success' run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel python -m pip install --upgrade tox~=3.0 virtualenv!=20.16.0 - name: "Run Tests for Python ${{ matrix.config.python-version }}" if: steps.setup-python.outcome == 'success' run: python -m tox -e "${{ matrix.config.testenvs }}" -s false - name: "Upload Coverage 🚀" uses: actions/upload-artifact@v4 if: ${{ always() && steps.setup-python.outcome == 'success' }} with: name: "coverage-${{ matrix.config.python-version }}" path: .coverage consolekit-1.7.1/.github/workflows/safety.yml000066400000000000000000000022511465042170600213120ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. --- name: Safety on: push: branches-ignore: - 'repo-helper-update' - 'pre-commit-ci-update-config' pull_request: permissions: contents: read jobs: Run: name: "Safety" runs-on: "ubuntu-22.04" steps: - name: Checkout 🛎️ uses: "actions/checkout@v2" - name: Check for changed files uses: dorny/paths-filter@v2 id: changes with: list-files: "json" filters: | code: - 'requirements.txt' - name: Setup Python 🐍 if: steps.changes.outputs.code == 'true' uses: "actions/setup-python@v2" with: python-version: "3.6" - name: Install dependencies 🔧 if: steps.changes.outputs.code == 'true' run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel python -m pip install git+https://github.com/domdfcoding/safety@lower - name: "Run Safety" if: steps.changes.outputs.code == 'true' run: "python -m safety check -r requirements.txt --full-report" consolekit-1.7.1/.gitignore000066400000000000000000000020321465042170600156640ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. __pycache__/ *.py[cod] *$py.class *.so .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg *.egg* *.manifest *.spec pip-log.txt pip-delete-this-directory.txt htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ .pytest_cache/ cover/ *.mo *.pot *.log local_settings.py db.sqlite3 instance/ .webassets-cache .scrapy docs/_build/ doc/build target/ .ipynb_checkpoints .python-version celerybeat-schedule celerybeat.pid *.sage.py .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ .spyderproject .spyproject .ropeproject /site .mypy_cache/ .dmypy.json dmypy.json *.iml *.ipr cmake-build-*/ .idea/**/mongoSettings.xml *.iws out/ atlassian-ide-plugin.xml com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties .idea build **/__pycache__ **/conda __pypackages__/ profile_default/ ipython_config.py Pipfile.lock .pyre/ _command.py consolekit-1.7.1/.imgbotconfig000066400000000000000000000001151465042170600163440ustar00rootroot00000000000000{ "schedule": "weekly", "ignoredFiles": [ "**/*.svg" ] } consolekit-1.7.1/.pre-commit-config.yaml000066400000000000000000000042461465042170600201660ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. --- exclude: ^$ ci: autoupdate_schedule: quarterly repos: - repo: https://github.com/repo-helper/pyproject-parser rev: v0.11.0 hooks: - id: reformat-pyproject - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.4.0 hooks: - id: check-added-large-files - id: check-ast - id: fix-byte-order-marker - id: check-byte-order-marker - id: check-case-conflict - id: check-executables-have-shebangs - id: check-json - id: check-toml - id: check-yaml - id: check-merge-conflict - id: check-symlinks - id: check-vcs-permalinks - id: detect-private-key - id: trailing-whitespace - id: mixed-line-ending - id: end-of-file-fixer - repo: https://github.com/domdfcoding/pre-commit-hooks rev: v0.4.0 hooks: - id: requirements-txt-sorter args: - --allow-git - id: check-docstring-first exclude: ^(doc-source/conf|__pkginfo__|setup|tests/.*)\.py$ - id: bind-requirements - repo: https://github.com/domdfcoding/flake8-dunder-all rev: v0.4.1 hooks: - id: ensure-dunder-all files: ^consolekit/.*\.py$ - repo: https://github.com/domdfcoding/flake2lint rev: v0.4.3 hooks: - id: flake2lint - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.10.0 hooks: - id: python-no-eval - id: rst-backticks - id: rst-directive-colons - id: rst-inline-touching-normal - repo: https://github.com/asottile/pyupgrade rev: v2.12.0 hooks: - id: pyupgrade args: - --py36-plus - --keep-runtime-typing - repo: https://github.com/Lucas-C/pre-commit-hooks rev: v1.5.1 hooks: - id: remove-crlf - id: forbid-crlf - repo: https://github.com/python-formate/snippet-fmt rev: v0.1.5 hooks: - id: snippet-fmt - repo: https://github.com/python-formate/formate rev: v0.7.0 hooks: - id: formate exclude: ^(doc-source/conf|__pkginfo__|setup)\.(_)?py$ - repo: https://github.com/domdfcoding/dep_checker rev: v0.8.0 hooks: - id: dep_checker args: - consolekit # Custom hooks can be added below this comment consolekit-1.7.1/.pylintrc000066400000000000000000000346201465042170600155510ustar00rootroot00000000000000[MASTER] # Specify a configuration file. #rcfile= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS # Add files or directories matching the regex patterns to the blacklist. The # regex matches against base names, not paths. ignore-patterns= # Pickle collected data for later comparisons. persistent=yes # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= # Use multiple processes to speed up Pylint. jobs=1 # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code extension-pkg-whitelist= # Allow optimization of some AST trees. This will activate a peephole AST # optimizer, which will apply various small optimizations. For instance, it can # be used to obtain the result of joining multiple strings with the addition # operator. Joining a lot of strings can lead to a maximum recursion error in # Pylint and this flag can prevent that. It has one side effect, the resulting # AST will be different than the one from reality. This option is deprecated # and it will be removed in Pylint 2.0. optimize-ast=no [MESSAGES CONTROL] # Only show warnings with the listed confidence levels. Leave empty to show # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED confidence= # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). See also the "--disable" option for examples. #enable= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once).You can also use "--disable=all" to # disable everything first and then reenable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" disable=all enable=assert-on-tuple,astroid-error,bad-except-order,bad-inline-option,bad-option-value,bad-reversed-sequence,bare-except,binary-op-exception,boolean-datetime,catching-non-exception,cell-var-from-loop,confusing-with-statement,consider-merging-isinstance,consider-using-enumerate,consider-using-ternary,continue-in-finally,deprecated-pragma,django-not-available,duplicate-except,duplicate-key,eval-used,exec-used,expression-not-assigned,fatal,file-ignored,fixme,global-at-module-level,global-statement,global-variable-not-assigned,global-variable-undefined,http-response-with-content-type-json,http-response-with-json-dumps,invalid-all-object,invalid-characters-in-docstring,len-as-condition,literal-comparison,locally-disabled,locally-enabled,lost-exception,lowercase-l-suffix,misplaced-bare-raise,missing-kwoa,mixed-line-endings,model-has-unicode,model-missing-unicode,model-no-explicit-unicode,model-unicode-not-callable,multiple-imports,new-db-field-with-default,non-ascii-bytes-literals,nonexistent-operator,not-in-loop,notimplemented-raised,overlapping-except,parse-error,pointless-statement,pointless-string-statement,raising-bad-type,raising-non-exception,raw-checker-failed,redefine-in-handler,redefined-argument-from-local,redefined-builtin,redundant-content-type-for-json-response,reimported,relative-import,return-outside-function,simplifiable-if-statement,singleton-comparison,syntax-error,trailing-comma-tuple,trailing-newlines,unbalanced-tuple-unpacking,undefined-all-variable,undefined-loop-variable,unexpected-line-ending-format,unidiomatic-typecheck,unnecessary-lambda,unnecessary-pass,unnecessary-semicolon,unneeded-not,unpacking-non-sequence,unreachable,unrecognized-inline-option,used-before-assignment,useless-else-on-loop,using-constant-test,wildcard-import,yield-outside-function,useless-return [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs # (visual studio) and html. You can also give a reporter class, eg # mypackage.mymodule.MyReporterClass. output-format=text # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be # written in a file name "pylint_global.[txt|html]". This option is deprecated # and it will be removed in Pylint 2.0. files-output=no # Tells whether to display a full report or only the messages reports=no # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details #msg-template= [BASIC] # Good variable names which should always be accepted, separated by a comma good-names=i,j,k,ex,Run,_ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata # Colon-delimited sets of names that determine each other's naming style when # the name regexes allow several styles. name-group= # Include a hint for the correct naming format with invalid-name include-naming-hint=no # List of decorators that produce properties, such as abc.abstractproperty. Add # to this list to register other decorators that produce valid properties. property-classes=abc.abstractproperty # Regular expression matching correct function names function-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for function names function-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct variable names variable-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for variable names variable-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct constant names const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Naming hint for constant names const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Regular expression matching correct attribute names attr-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for attribute names attr-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct argument names argument-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for argument names argument-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct class attribute names class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ # Naming hint for class attribute names class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ # Regular expression matching correct inline iteration names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Naming hint for inline iteration names inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ # Regular expression matching correct class names class-rgx=[A-Z_][a-zA-Z0-9]+$ # Naming hint for class names class-name-hint=[A-Z_][a-zA-Z0-9]+$ # Regular expression matching correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Naming hint for module names module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Regular expression matching correct method names method-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for method names method-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=^_ # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=-1 [ELIF] # Maximum number of nested blocks for function / method body max-nested-blocks=5 [FORMAT] # Maximum number of characters on a single line. max-line-length=159 # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=no # List of optional constructs for which whitespace checking is disabled. `dict- # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. # `trailing-comma` allows a space between comma and closing bracket: (a, ). # `empty-line` allows space-only lines. no-space-check=trailing-comma,dict-separator # Maximum number of lines in a module max-module-lines=1000 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' # Number of spaces of indent required inside a hanging or continued line. indent-after-paren=4 # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. expected-line-ending-format= [LOGGING] # Logging modules to check that the string format arguments are in logging # function parameter format logging-modules=logging [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME,XXX,TODO [SIMILARITIES] # Minimum lines number of a similarity. min-similarity-lines=4 # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no [SPELLING] # Spelling dictionary name. Available dictionaries: none. To make it working # install python-enchant package. spelling-dict= # List of comma separated words that should not be checked. spelling-ignore-words= # A path to a file that contains private dictionary; one word per line. spelling-private-dict-file= # Tells whether to store unknown words to indicated private dictionary in # --spelling-private-dict-file option instead of raising a message. spelling-store-unknown-words=no [TYPECHECK] # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis. It # supports qualified module names, as well as Unix pattern matching. ignored-modules= # List of class names for which member attributes should not be checked (useful # for classes with dynamically set attributes). This supports the use of # qualified names. ignored-classes=optparse.Values,thread._local,_thread._local # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. generated-members= # List of decorators that produce context managers, such as # contextlib.contextmanager. Add to this list to register other decorators that # produce valid context managers. contextmanager-decorators=contextlib.contextmanager [VARIABLES] # Tells whether we should check for unused import in __init__ files. init-import=no # A regular expression matching the name of dummy variables (i.e. expectedly # not used). dummy-variables-rgx=(_+[a-zA-Z0-9]*?$)|dummy # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins= # List of strings which can identify a callback function by name. A callback # name must start or end with one of those strings. callbacks=cb_,_cb # List of qualified module names which can have objects that can redefine # builtins. redefining-builtins-modules=six.moves,future.builtins [CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=mcs # List of member names, which should be excluded from the protected access # warning. exclude-protected=_asdict,_fields,_replace,_source,_make [DESIGN] # Maximum number of arguments for function / method max-args=5 # Argument names that match this expression will be ignored. Default to name # with leading underscore ignored-argument-names=_.* # Maximum number of locals for function / method body max-locals=15 # Maximum number of return / yield for function / method body max-returns=6 # Maximum number of branch for function / method body max-branches=12 # Maximum number of statements in function / method body max-statements=60 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of attributes for a class (see R0902). max-attributes=7 # Minimum number of public methods for a class (see R0903). min-public-methods=2 # Maximum number of public methods for a class (see R0904). max-public-methods=20 # Maximum number of boolean expressions in a if statement max-bool-expr=5 [IMPORTS] # Deprecated modules which should not be used, separated by a comma deprecated-modules=regsub,TERMIOS,Bastion,rexec # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled) import-graph= # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled) ext-import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled) int-import-graph= # Force import order to recognize a module as part of the standard # compatibility libraries. known-standard-library= # Force import order to recognize a module as part of a third party library. known-third-party=enchant # Analyse import fallback blocks. This can be used to support both Python 2 and # 3 compatible code, which means that the block might have code that exists # only in one or another interpreter, leading to false positives when analysed. analyse-fallback-blocks=no [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception" overgeneral-exceptions=Exception consolekit-1.7.1/.readthedocs.yml000066400000000000000000000012021465042170600167600ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. # Read the Docs configuration file --- version: 2 sphinx: builder: html configuration: doc-source/conf.py formats: - pdf - htmlzip python: install: - requirements: requirements.txt - requirements: doc-source/requirements.txt build: os: ubuntu-20.04 tools: python: '3.9' jobs: post_create_environment: - pip install . post_install: - pip install sphinxcontrib-applehelp==1.0.4 sphinxcontrib-devhelp==1.0.2 sphinxcontrib-htmlhelp==2.0.1 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.5 consolekit-1.7.1/.style.yapf000066400000000000000000000272001465042170600157770ustar00rootroot00000000000000[style] # Align closing bracket with visual indentation. align_closing_bracket_with_visual_indent=True # Allow dictionary keys to exist on multiple lines. For example: # # x = { # ('this is the first element of a tuple', # 'this is the second element of a tuple'): # value, # } allow_multiline_dictionary_keys=True # Allow lambdas to be formatted on more than one line. allow_multiline_lambdas=False # Allow splitting before a default / named assignment in an argument list. allow_split_before_default_or_named_assigns=True # Allow splits before the dictionary value. allow_split_before_dict_value=True # Let spacing indicate operator precedence. For example: # # a = 1 * 2 + 3 / 4 # b = 1 / 2 - 3 * 4 # c = (1 + 2) * (3 - 4) # d = (1 - 2) / (3 + 4) # e = 1 * 2 - 3 # f = 1 + 2 + 3 + 4 # # will be formatted as follows to indicate precedence: # # a = 1*2 + 3/4 # b = 1/2 - 3*4 # c = (1+2) * (3-4) # d = (1-2) / (3+4) # e = 1*2 - 3 # f = 1 + 2 + 3 + 4 # arithmetic_precedence_indication=False # Number of blank lines surrounding top-level function and class # definitions. blank_lines_around_top_level_definition=2 # Insert a blank line before a class-level docstring. blank_line_before_class_docstring=False # Insert a blank line before a module docstring. blank_line_before_module_docstring=False # Insert a blank line before a 'def' or 'class' immediately nested # within another 'def' or 'class'. For example: # # class Foo: # # <------ this blank line # def method(): # ... blank_line_before_nested_class_or_def=True # Do not split consecutive brackets. Only relevant when # dedent_closing_brackets is set. For example: # # call_func_that_takes_a_dict( # { # 'key1': 'value1', # 'key2': 'value2', # } # ) # # would reformat to: # # call_func_that_takes_a_dict({ # 'key1': 'value1', # 'key2': 'value2', # }) coalesce_brackets=True # The column limit. column_limit=115 # The style for continuation alignment. Possible values are: # # - SPACE: Use spaces for continuation alignment. This is default behavior. # - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns # (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs or # CONTINUATION_INDENT_WIDTH spaces) for continuation alignment. # - VALIGN-RIGHT: Vertically align continuation lines to multiple of # INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if # cannot vertically align continuation lines with indent characters. continuation_align_style=VALIGN-RIGHT # Indent width used for line continuations. continuation_indent_width=8 # Put closing brackets on a separate line, dedented, if the bracketed # expression can't fit in a single line. Applies to all kinds of brackets, # including function definitions and calls. For example: # # config = { # 'key1': 'value1', # 'key2': 'value2', # } # <--- this bracket is dedented and on a separate line # # time_series = self.remote_client.query_entity_counters( # entity='dev3246.region1', # key='dns.query_latency_tcp', # transform=Transformation.AVERAGE(window=timedelta(seconds=60)), # start_ts=now()-timedelta(days=3), # end_ts=now(), # ) # <--- this bracket is dedented and on a separate line dedent_closing_brackets=False # Disable the heuristic which places each list element on a separate line # if the list is comma-terminated. disable_ending_comma_heuristic=False # Place each dictionary entry onto its own line. each_dict_entry_on_separate_line=False # Require multiline dictionary even if it would normally fit on one line. # For example: # # config = { # 'key1': 'value1' # } force_multiline_dict=False # The regex for an i18n comment. The presence of this comment stops # reformatting of that line, because the comments are required to be # next to the string they translate. ;i18n_comment= # The i18n function call names. The presence of this function stops # reformattting on that line, because the string it has cannot be moved # away from the i18n comment. ;i18n_function_call= # Indent blank lines. indent_blank_lines=False # Put closing brackets on a separate line, indented, if the bracketed # expression can't fit in a single line. Applies to all kinds of brackets, # including function definitions and calls. For example: # # config = { # 'key1': 'value1', # 'key2': 'value2', # } # <--- this bracket is indented and on a separate line # # time_series = self.remote_client.query_entity_counters( # entity='dev3246.region1', # key='dns.query_latency_tcp', # transform=Transformation.AVERAGE(window=timedelta(seconds=60)), # start_ts=now()-timedelta(days=3), # end_ts=now(), # ) # <--- this bracket is indented and on a separate line indent_closing_brackets=True # Indent the dictionary value if it cannot fit on the same line as the # dictionary key. For example: # # config = { # 'key1': # 'value1', # 'key2': value1 + # value2, # } indent_dictionary_value=True # The number of columns to use for indentation. indent_width=4 # Join short lines into one line. E.g., single line 'if' statements. join_multiple_lines=False # Do not include spaces around selected binary operators. For example: # # 1 + 2 * 3 - 4 / 5 # # will be formatted as follows when configured with "*,/": # # 1 + 2*3 - 4/5 ;no_spaces_around_selected_binary_operators= # Use spaces around default or named assigns. spaces_around_default_or_named_assign=False # Adds a space after the opening '{' and before the ending '}' dict delimiters. # # {1: 2} # # will be formatted as: # # { 1: 2 } spaces_around_dict_delimiters=False # Adds a space after the opening '[' and before the ending ']' list delimiters. # # [1, 2] # # will be formatted as: # # [ 1, 2 ] spaces_around_list_delimiters=False # Use spaces around the power operator. spaces_around_power_operator=False # Use spaces around the subscript / slice operator. For example: # # my_list[1 : 10 : 2] spaces_around_subscript_colon=False # Adds a space after the opening '(' and before the ending ')' tuple delimiters. # # (1, 2, 3) # # will be formatted as: # # ( 1, 2, 3 ) spaces_around_tuple_delimiters=False # The number of spaces required before a trailing comment. # This can be a single value (representing the number of spaces # before each trailing comment) or list of values (representing # alignment column values; trailing comments within a block will # be aligned to the first column value that is greater than the maximum # line length within the block). For example: # # With spaces_before_comment=5: # # 1 + 1 # Adding values # # will be formatted as: # # 1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment # # With spaces_before_comment=15, 20: # # 1 + 1 # Adding values # two + two # More adding # # longer_statement # This is a longer statement # short # This is a shorter statement # # a_very_long_statement_that_extends_beyond_the_final_column # Comment # short # This is a shorter statement # # will be formatted as: # # 1 + 1 # Adding values <-- end of line comments in block aligned to col 15 # two + two # More adding # # longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20 # short # This is a shorter statement # # a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length # short # This is a shorter statement # spaces_before_comment=2 # Insert a space between the ending comma and closing bracket of a list, # etc. space_between_ending_comma_and_closing_bracket=True # Use spaces inside brackets, braces, and parentheses. For example: # # method_call( 1 ) # my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ] # my_set = { 1, 2, 3 } space_inside_brackets=False # Split before arguments split_all_comma_separated_values=False # Split before arguments, but do not split all subexpressions recursively # (unless needed). split_all_top_level_comma_separated_values=True # Split before arguments if the argument list is terminated by a # comma. split_arguments_when_comma_terminated=False # Set to True to prefer splitting before '+', '-', '*', '/', '//', or '@' # rather than after. split_before_arithmetic_operator=True # Set to True to prefer splitting before '&', '|' or '^' rather than # after. split_before_bitwise_operator=True # Split before the closing bracket if a list or dict literal doesn't fit on # a single line. split_before_closing_bracket=True # Split before a dictionary or set generator (comp_for). For example, note # the split before the 'for': # # foo = { # variable: 'Hello world, have a nice day!' # for variable in bar if variable != 42 # } split_before_dict_set_generator=True # Split before the '.' if we need to split a longer expression: # # foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d)) # # would reformat to something like: # # foo = ('This is a really long string: {}, {}, {}, {}' # .format(a, b, c, d)) split_before_dot=False # Split after the opening paren which surrounds an expression if it doesn't # fit on a single line. split_before_expression_after_opening_paren=True # If an argument / parameter list is going to be split, then split before # the first argument. split_before_first_argument=False # Set to True to prefer splitting before 'and' or 'or' rather than # after. split_before_logical_operator=True # Split named assignments onto individual lines. split_before_named_assigns=True # Set to True to split list comprehensions and generators that have # non-trivial expressions and multiple clauses before each of these # clauses. For example: # # result = [ # a_long_var + 100 for a_long_var in xrange(1000) # if a_long_var % 10] # # would reformat to something like: # # result = [ # a_long_var + 100 # for a_long_var in xrange(1000) # if a_long_var % 10] split_complex_comprehension=True # The penalty for splitting right after the opening bracket. split_penalty_after_opening_bracket=100 # The penalty for splitting the line after a unary operator. split_penalty_after_unary_operator=10000 # The penalty of splitting the line around the '+', '-', '*', '/', '//', # ``%``, and '@' operators. split_penalty_arithmetic_operator=300 # The penalty for splitting right before an if expression. split_penalty_before_if_expr=0 # The penalty of splitting the line around the '&', '|', and '^' # operators. split_penalty_bitwise_operator=300 # The penalty for splitting a list comprehension or generator # expression. split_penalty_comprehension=80 # The penalty for characters over the column limit. split_penalty_excess_character=7000 # The penalty incurred by adding a line split to the unwrapped line. The # more line splits added the higher the penalty. split_penalty_for_added_line_split=30 # The penalty of splitting a list of "import as" names. For example: # # from a_very_long_or_indented_module_name_yada_yad import (long_argument_1, # long_argument_2, # long_argument_3) # # would reformat to something like: # # from a_very_long_or_indented_module_name_yada_yad import ( # long_argument_1, long_argument_2, long_argument_3) split_penalty_import_names=0 # The penalty of splitting the line around the 'and' and 'or' # operators. split_penalty_logical_operator=300 # Use the Tab character for indentation. use_tabs=True consolekit-1.7.1/CONTRIBUTING.rst000066400000000000000000000025031465042170600163400ustar00rootroot00000000000000============== Contributing ============== .. This file based on https://github.com/PyGithub/PyGithub/blob/master/CONTRIBUTING.md ``consolekit`` uses `tox `_ to automate testing and packaging, and `pre-commit `_ to maintain code quality. Install ``pre-commit`` with ``pip`` and install the git hook: .. code-block:: bash $ python -m pip install pre-commit $ pre-commit install Coding style -------------- `formate `_ is used for code formatting. It can be run manually via ``pre-commit``: .. code-block:: bash $ pre-commit run formate -a Or, to run the complete autoformatting suite: .. code-block:: bash $ pre-commit run -a Automated tests ------------------- Tests are run with ``tox`` and ``pytest``. To run tests for a specific Python version, such as Python 3.6: .. code-block:: bash $ tox -e py36 To run tests for all Python versions, simply run: .. code-block:: bash $ tox Type Annotations ------------------- Type annotations are checked using ``mypy``. Run ``mypy`` using ``tox``: .. code-block:: bash $ tox -e mypy Build documentation locally ------------------------------ The documentation is powered by Sphinx. A local copy of the documentation can be built with ``tox``: .. code-block:: bash $ tox -e docs consolekit-1.7.1/LICENSE000066400000000000000000000020501465042170600147010ustar00rootroot00000000000000Copyright (c) 2020 Dominic Davis-Foster Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. consolekit-1.7.1/README.rst000066400000000000000000000125371465042170600153760ustar00rootroot00000000000000########### consolekit ########### .. start short_desc **Additional utilities for click.** .. end short_desc .. start shields .. list-table:: :stub-columns: 1 :widths: 10 90 * - Docs - |docs| |docs_check| * - Tests - |actions_linux| |actions_windows| |actions_macos| |coveralls| * - PyPI - |pypi-version| |supported-versions| |supported-implementations| |wheel| * - Anaconda - |conda-version| |conda-platform| * - Activity - |commits-latest| |commits-since| |maintained| |pypi-downloads| * - QA - |codefactor| |actions_flake8| |actions_mypy| * - Other - |license| |language| |requires| .. |docs| image:: https://img.shields.io/readthedocs/consolekit/latest?logo=read-the-docs :target: https://consolekit.readthedocs.io/en/latest :alt: Documentation Build Status .. |docs_check| image:: https://github.com/domdfcoding/consolekit/workflows/Docs%20Check/badge.svg :target: https://github.com/domdfcoding/consolekit/actions?query=workflow%3A%22Docs+Check%22 :alt: Docs Check Status .. |actions_linux| image:: https://github.com/domdfcoding/consolekit/workflows/Linux/badge.svg :target: https://github.com/domdfcoding/consolekit/actions?query=workflow%3A%22Linux%22 :alt: Linux Test Status .. |actions_windows| image:: https://github.com/domdfcoding/consolekit/workflows/Windows/badge.svg :target: https://github.com/domdfcoding/consolekit/actions?query=workflow%3A%22Windows%22 :alt: Windows Test Status .. |actions_macos| image:: https://github.com/domdfcoding/consolekit/workflows/macOS/badge.svg :target: https://github.com/domdfcoding/consolekit/actions?query=workflow%3A%22macOS%22 :alt: macOS Test Status .. |actions_flake8| image:: https://github.com/domdfcoding/consolekit/workflows/Flake8/badge.svg :target: https://github.com/domdfcoding/consolekit/actions?query=workflow%3A%22Flake8%22 :alt: Flake8 Status .. |actions_mypy| image:: https://github.com/domdfcoding/consolekit/workflows/mypy/badge.svg :target: https://github.com/domdfcoding/consolekit/actions?query=workflow%3A%22mypy%22 :alt: mypy status .. |requires| image:: https://dependency-dash.repo-helper.uk/github/domdfcoding/consolekit/badge.svg :target: https://dependency-dash.repo-helper.uk/github/domdfcoding/consolekit/ :alt: Requirements Status .. |coveralls| image:: https://img.shields.io/coveralls/github/domdfcoding/consolekit/master?logo=coveralls :target: https://coveralls.io/github/domdfcoding/consolekit?branch=master :alt: Coverage .. |codefactor| image:: https://img.shields.io/codefactor/grade/github/domdfcoding/consolekit?logo=codefactor :target: https://www.codefactor.io/repository/github/domdfcoding/consolekit :alt: CodeFactor Grade .. |pypi-version| image:: https://img.shields.io/pypi/v/consolekit :target: https://pypi.org/project/consolekit/ :alt: PyPI - Package Version .. |supported-versions| image:: https://img.shields.io/pypi/pyversions/consolekit?logo=python&logoColor=white :target: https://pypi.org/project/consolekit/ :alt: PyPI - Supported Python Versions .. |supported-implementations| image:: https://img.shields.io/pypi/implementation/consolekit :target: https://pypi.org/project/consolekit/ :alt: PyPI - Supported Implementations .. |wheel| image:: https://img.shields.io/pypi/wheel/consolekit :target: https://pypi.org/project/consolekit/ :alt: PyPI - Wheel .. |conda-version| image:: https://img.shields.io/conda/v/domdfcoding/consolekit?logo=anaconda :target: https://anaconda.org/domdfcoding/consolekit :alt: Conda - Package Version .. |conda-platform| image:: https://img.shields.io/conda/pn/domdfcoding/consolekit?label=conda%7Cplatform :target: https://anaconda.org/domdfcoding/consolekit :alt: Conda - Platform .. |license| image:: https://img.shields.io/github/license/domdfcoding/consolekit :target: https://github.com/domdfcoding/consolekit/blob/master/LICENSE :alt: License .. |language| image:: https://img.shields.io/github/languages/top/domdfcoding/consolekit :alt: GitHub top language .. |commits-since| image:: https://img.shields.io/github/commits-since/domdfcoding/consolekit/v1.7.1 :target: https://github.com/domdfcoding/consolekit/pulse :alt: GitHub commits since tagged version .. |commits-latest| image:: https://img.shields.io/github/last-commit/domdfcoding/consolekit :target: https://github.com/domdfcoding/consolekit/commit/master :alt: GitHub last commit .. |maintained| image:: https://img.shields.io/maintenance/yes/2024 :alt: Maintenance .. |pypi-downloads| image:: https://img.shields.io/pypi/dm/consolekit :target: https://pypi.org/project/consolekit/ :alt: PyPI - Downloads .. end shields Installation -------------- .. start installation ``consolekit`` can be installed from PyPI or Anaconda. To install with ``pip``: .. code-block:: bash $ python -m pip install consolekit To install with ``conda``: * First add the required channels .. code-block:: bash $ conda config --add channels https://conda.anaconda.org/conda-forge $ conda config --add channels https://conda.anaconda.org/domdfcoding * Then install .. code-block:: bash $ conda install consolekit .. end installation Additionally, for better support in terminals, install `psutil `_ by specifying the ``terminals`` extra: .. code-block:: bash $ python -m pip install consolekit[terminals] or, if you installed ``consolekit`` through conda: .. code-block:: bash $ conda install -c conda-forge psutil consolekit-1.7.1/__pkginfo__.py000066400000000000000000000005141465042170600165020ustar00rootroot00000000000000# This file is managed by 'repo_helper'. Don't edit it directly. __all__ = ["extras_require"] extras_require = { "terminals": ["psutil>=5.8.0"], "testing": ["coincidence>=0.1.0", "pytest>=6.0.0", "pytest-regressions>=2.0.2"], "all": ["coincidence>=0.1.0", "psutil>=5.8.0", "pytest>=6.0.0", "pytest-regressions>=2.0.2"] } consolekit-1.7.1/consolekit/000077500000000000000000000000001465042170600160515ustar00rootroot00000000000000consolekit-1.7.1/consolekit/__init__.py000066400000000000000000000107041465042170600201640ustar00rootroot00000000000000#!/usr/bin/env python3 # # __init__.py """ Additional utilities for `click `_. .. attention:: ``consolekit`` disables Python's readline history to prevent unrelated histories appearing for prompts. If the original behaviour is desired run: .. code-block:: python import readline readline.set_history_length(-1) readline.set_auto_history(True) """ # # Copyright © 2020 Dominic Davis-Foster # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE # OR OTHER DEALINGS IN THE SOFTWARE. # # pylint: disable=redefined-builtin # stdlib from typing import Any, Callable, Dict, Optional, Type, TypeVar, cast # 3rd party import click # this package from consolekit import _readline, commands, input, terminal_colours, tracebacks, utils # noqa: F401 from consolekit.commands import SuggestionGroup from consolekit.options import _Option # pylint: enable=redefined-builtin __author__: str = "Dominic Davis-Foster" __copyright__: str = "2020 Dominic Davis-Foster" __license__: str = "MIT License" __version__: str = "1.7.1" __email__: str = "dominic@davis-foster.co.uk" __all__ = ( "CONTEXT_SETTINGS", "click_command", "click_group", "option", "SuggestionGroup", ) _C = TypeVar("_C", bound=click.Command) _G = TypeVar("_G", bound=click.Group) CONTEXT_SETTINGS: Dict[str, Any] = dict(help_option_names=["-h", "--help"], max_content_width=120) def click_command( name: Optional[str] = None, cls: Optional[Type[_C]] = None, **attrs: Any, ) -> Callable[[Callable], _C]: r""" Shortcut to :func:`click.command`, with the ``-h``/``--help`` option enabled and a max width of ``120``. :param name: :param cls: :type cls: :class:`~typing.Type`\[:class:`~click.Command`\] :default type: :class:`click.Command` :param \*\*attrs: Additional keyword arguments passed to the :class:`~click.Command`. :rtype: :class:`~typing.Callable`\[[:class:`~typing.Callable`\], :class:`~click.Command`\] """ attrs.setdefault("context_settings", CONTEXT_SETTINGS) return cast(Callable[[Callable], _C], click.command(name, cls=cls, **attrs)) def click_group( name: Optional[str] = None, cls: Optional[Type[_G]] = None, **attrs: Any, ) -> Callable[[Callable], _G]: r""" Shortcut to :func:`click.group`, with the ``-h``/``--help`` option enabled and a max width of ``120``. :param name: :param cls: :type cls: :class:`~typing.Type`\[:class:`~click.Group`\] :default type: :class:`click.Group` :param \*\*attrs: Additional keyword arguments passed to the :class:`~click.Group`. :rtype: .. latex:clearpage:: """ if cls is None: cls = SuggestionGroup attrs.setdefault("context_settings", CONTEXT_SETTINGS) return click_command(name, cls=cls, **attrs) def option( *param_decls: str, **attrs: Any, ) -> Callable[[_C], _C]: r""" Shortcut to :func:`click.option`, but using :func:`consolekit.input.confirm` when prompting for a boolean flag. :param \*param_decls: :param \*\*attrs: Additional keyword arguments passed to :func:`click.command`. """ attrs.setdefault("cls", _Option) return cast(Callable[[_C], _C], click.option(*param_decls, **attrs)) # Fixes intersphinx links click.Command.__module__ = "click" click.Argument.__module__ = "click" click.Abort.__module__ = "click" click.Option.__module__ = "click" click.ParamType.__module__ = "click" click.Parameter.__module__ = "click" click.Context.__module__ = "click" click.HelpFormatter.__module__ = "click" click.Group.__module__ = "click" click.OptionParser.__module__ = "click" consolekit-1.7.1/consolekit/__init__.pyi000066400000000000000000000026461465042170600203430ustar00rootroot00000000000000# pylint: disable=redefined-builtin # stdlib from typing import Any, Callable, Dict, List, Optional, Type, TypeVar, overload # 3rd party import click # this package from consolekit import commands as commands # noqa: F401 from consolekit import input as input # noqa: F401 from consolekit import terminal_colours as terminal_colours # noqa: F401 from consolekit import tracebacks as tracebacks # noqa: F401 from consolekit import utils as utils # noqa: F401 from consolekit.commands import SuggestionGroup as SuggestionGroup # noqa: F401 from consolekit.options import _Option # noqa: F401 __author__: str __copyright__: str __license__: str __version__: str __email__: str __all__: List[str] _C = TypeVar("_C", bound=click.Command) _G = TypeVar("_G", bound=click.Group) CONTEXT_SETTINGS: Dict[str, Any] @overload def click_command( name: Optional[str] = ..., cls: None = ..., **attrs: Any, ) -> Callable[[Callable], click.Command]: ... @overload def click_command( name: Optional[str] = ..., cls: Type[_C] = ..., **attrs: Any, ) -> Callable[[Callable], _C]: ... @overload def click_group( name: Optional[str] = ..., cls: None = ..., **attrs: Any, ) -> Callable[[Callable], click.Group]: ... @overload def click_group( name: Optional[str] = ..., cls: Type[_G] = ..., **attrs: Any, ) -> Callable[[Callable], _G]: ... def option( *param_decls: str, **attrs: Any, ) -> Callable[[_C], _C]: ... consolekit-1.7.1/consolekit/_readline.py000066400000000000000000000006631465042170600203520ustar00rootroot00000000000000# pragma: no cover # stdlib import sys if not bool(getattr(sys, "ps1", sys.flags.interactive)): try: # stdlib import readline # typeshed thinks the module but not these functions are available on Windows. # In reality the whole module is unavailable. readline.set_history_length(0) readline.set_auto_history(False) except (ImportError, AttributeError): # Attribute error on PyPy, ImportError on Windows etc. pass consolekit-1.7.1/consolekit/_readline.pyi000066400000000000000000000000001465042170600205040ustar00rootroot00000000000000consolekit-1.7.1/consolekit/_types.py000066400000000000000000000027431465042170600177340ustar00rootroot00000000000000#!/usr/bin/env python3 # # _types.py # # Copyright © 2020 Dominic Davis-Foster # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE # OR OTHER DEALINGS IN THE SOFTWARE. # # stdlib from typing import Any, Callable, Optional, Tuple, Union # 3rd party from click import Context, Parameter, ParamType _ConvertibleType = Union[ type, ParamType, Tuple[Union[type, ParamType], ...], Callable[[str], Any], Callable[[Optional[str]], Any] ] Callback = Callable[[Context, Parameter, str], Any] consolekit-1.7.1/consolekit/commands.py000066400000000000000000000324021465042170600202250ustar00rootroot00000000000000#!/usr/bin/env python3 # # commands.py """ Customised click commands and command groups. .. versionadded:: 0.8.0 """ # # Copyright © 2020-2021 Dominic Davis-Foster # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE # OR OTHER DEALINGS IN THE SOFTWARE. # # MarkdownHelpCommand.parse_args and the docstrings of ContextInheritingGroup # based on https://github.com/pallets/click # Copyright 2014 Pallets # | Redistribution and use in source and binary forms, with or without modification, # | are permitted provided that the following conditions are met: # | # | * Redistributions of source code must retain the above copyright notice, # | this list of conditions and the following disclaimer. # | * Redistributions in binary form must reproduce the above copyright notice, # | this list of conditions and the following disclaimer in the documentation # | and/or other materials provided with the distribution. # | * Neither the name of the copyright holder nor the names of its contributors # | may be used to endorse or promote products derived from this software without # | specific prior written permission. # | # | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER # | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # stdlib import difflib import inspect from textwrap import indent from typing import TYPE_CHECKING, Any, Callable, List, Optional, Tuple # 3rd party import click from click.core import iter_params_for_processing from click.parser import split_opt from click.utils import make_str from domdf_python_tools.stringlist import DelimitedList from domdf_python_tools.words import Plural from mistletoe import block_token # type: ignore[import] # this package from consolekit.terminal_colours import ColourTrilean, resolve_color_default, strip_ansi from consolekit.utils import TerminalRenderer __all__ = ( "MarkdownHelpCommand", "MarkdownHelpGroup", "MarkdownHelpMixin", "RawHelpCommand", "RawHelpGroup", "RawHelpMixin", "SuggestionGroup", "ContextInheritingGroup", ) _argument = Plural("argument", "arguments") class RawHelpMixin: """ Mixin class for :class:`click.Command` and :class:`click.Group` which leaves the help text unformatted. .. seealso:: :class:`~.RawHelpCommand` and :class:`~.RawHelpGroup` .. tip:: This can be combined with groups such as :class:`~.SuggestionGroup`. .. versionadded:: 0.8.0 """ help: Optional[str] # noqa: A003 # pylint: disable=redefined-builtin def format_help_text(self, ctx: click.Context, formatter: click.formatting.HelpFormatter) -> None: """ Writes the help text to the formatter if it exists. :param ctx: :param formatter: """ if not self.help: return text = inspect.cleandoc(self.help or '').partition('\x0c')[0] if getattr(self, "deprecated", False): text = f"(Deprecated) {text}" formatter.write('\n') formatter.write(indent(text, " ")) formatter.write('\n') class RawHelpCommand(RawHelpMixin, click.Command): # lgtm [py/conflicting-attributes] """ Subclass of :class:`click.Command` which leaves the help text unformatted. .. versionadded:: 0.8.0 """ class RawHelpGroup(RawHelpMixin, click.Group): # lgtm [py/conflicting-attributes] """ Subclass of :class:`click.Group` which leaves the help text unformatted. .. versionadded:: 0.8.0 """ class MarkdownHelpMixin: """ Mixin class for :class:`click.Command` and :class:`click.Group` which treats the help text as markdown and prints a rendered representation. .. seealso:: :class:`~.MarkdownHelpCommand` and :class:`~.MarkdownHelpGroup` .. tip:: This can be combined with groups such as :class:`~.SuggestionGroup`. Tested in Gnome Terminal and Terminator (both libVTE-based), and PyCharm. libVTE has the best support. PyCharm's support for italics and strikethrough is poor. Support on Windows is, as expected, poor. Not tested on other terminals, but contributions are welcome to improve support. .. versionadded:: 0.8.0 """ # noqa: D400 help: Optional[str] # noqa: A003 # pylint: disable=redefined-builtin no_args_is_help: bool _colour: ColourTrilean = None if TYPE_CHECKING: def get_params(self, ctx: click.Context) -> List[click.Parameter]: """ Returns the list of parameters for this command in the order they should appear in the help page. :param ctx: """ raise NotImplementedError def make_parser(self, ctx: click.Context) -> click.OptionParser: """ Creates the underlying option parser for this command. :param ctx: """ raise NotImplementedError def format_help_text(self, ctx: click.Context, formatter: click.formatting.HelpFormatter) -> None: """ Writes the help text to the formatter if it exists. :param ctx: :param formatter: """ if not self.help: return text = inspect.cleandoc(self.help or '').partition('\x0c')[0] if getattr(self, "deprecated", False): text = f"(Deprecated) {text}" doc = block_token.Document(text) with TerminalRenderer() as renderer: rendered_doc = indent(renderer.render(doc).strip(), " ") if resolve_color_default(self._colour) is False: # Also remove 'COMBINING LONG STROKE OVERLAY', used for strikethrough. rendered_doc = strip_ansi(rendered_doc).replace('̶', '') formatter.write('\n') formatter.write(rendered_doc) formatter.write('\n') def parse_help_args(obj: MarkdownHelpMixin, ctx: click.Context, args: List[str]) -> List[str]: """ Helper function for markdown help classes to parse the given arguments and modify the context as necessary. .. versionadded:: 1.1.0 :param obj: :param ctx: :param args: """ # noqa: D400 # This is necessary to parse any --colour/--no-colour commands before generating the help, # to ensure the option is honoured. if not args and obj.no_args_is_help and not ctx.resilient_parsing: click.echo(ctx.get_help(), color=ctx.color) ctx.exit() parser = obj.make_parser(ctx) opts, args, param_order = parser.parse_args(args=args) obj._colour = opts.get("colour", ctx.color) for param in iter_params_for_processing(param_order, obj.get_params(ctx)): value, args = param.handle_parse_result(ctx, opts, args) if args and not ctx.allow_extra_args and not ctx.resilient_parsing: args_string = DelimitedList(map(make_str, args)) ctx.fail(f"Got unexpected extra {_argument(len(args))} ({args_string: })") ctx.args = args return args class MarkdownHelpCommand(MarkdownHelpMixin, click.Command): # lgtm [py/conflicting-attributes] """ Subclass of :class:`click.Command` which treats the help text as markdown and prints a rendered representation. Tested in Gnome Terminal and Terminator (both libVTE-based), and PyCharm. libVTE has the best support. PyCharm's support for italics and strikethrough is poor. Support on Windows is, as expected, poor. Not tested on other terminals, but contributions are welcome to improve support. .. versionadded:: 0.8.0 """ # noqa: D400 def parse_args(self, ctx: click.Context, args: List[str]) -> List[str]: """ Parse the given arguments and modify the context as necessary. :param ctx: :param args: """ return parse_help_args(self, ctx, args) class MarkdownHelpGroup(MarkdownHelpMixin, click.Group): # lgtm [py/conflicting-attributes] """ Subclass of :class:`click.Group` which treats the help text as markdown and prints a rendered representation. Tested in Gnome Terminal and Terminator (both libVTE-based), and PyCharm. libVTE has the best support. PyCharm's support for italics and strikethrough is poor. Support on Windows is, as expected, poor. Not tested on other terminals, but contributions are welcome to improve support. .. versionadded:: 0.8.0 """ # noqa: D400 def parse_args(self, ctx: click.Context, args: List[str]) -> List[str]: """ Parse the given arguments and modify the context as necessary. :param ctx: :param args: """ # This is necessary to parse any --colour/--no-colour commands before generating the help, # to ensure the option is honoured. if not args and self.no_args_is_help and not ctx.resilient_parsing: click.echo(ctx.get_help(), color=ctx.color) ctx.exit() rest = parse_help_args(self, ctx, args) if self.chain: ctx.protected_args = rest ctx.args = [] elif rest: ctx.protected_args, ctx.args = rest[:1], rest[1:] return ctx.args class ContextInheritingGroup(click.Group): """ Subclass of :class:`click.Group` whose children inherit its :attr:`~click.BaseCommand.context_settings`. The group's commands can be given different context settings by passing the ``context_settings`` keyword argument to :meth:`~.command` and :meth:`~.group` as normal. .. versionadded:: 1.1.0 .. autosummary-widths:: 5/16 """ def command(self, *args, **kwargs) -> Callable[[Callable[..., Any]], click.Command]: # type: ignore[override] """ A shortcut decorator for declaring and attaching a command to the group. This takes the same arguments as :func:`click.command` but immediately registers the created command with this instance by calling into :meth:`click.Group.add_command`. """ kwargs.setdefault("context_settings", self.context_settings) return super().command(*args, **kwargs) def group(self, *args, **kwargs) -> Callable[[Callable[..., Any]], click.Group]: # type: ignore[override] """ A shortcut decorator for declaring and attaching a group to the group. This takes the same arguments as :func:`click.group` but immediately registers the created group with this instance by calling into :meth:`click.Group.add_command`. """ kwargs.setdefault("context_settings", self.context_settings) return super().group(*args, **kwargs) class SuggestionGroup(ContextInheritingGroup): """ Subclass of :class:`click.Group` which suggests the most similar command if the command is not found. .. versionadded 0.2.0 .. versionchanged:: 0.8.0 Moved to :mod:`consolekit.commands`. .. versionchanged:: 1.1.0 Now inherits from :class:`~.ContextInheritingGroup` """ def resolve_command( self, ctx: click.Context, args: List[str], ) -> Tuple[str, click.Command, List[str]]: """ Resolve the requested command belonging to this group, and print a suggestion if it can't be found. :param ctx: :param args: :return: The name of the matching command, the :class:`click.Command` object itself, and any remaining arguments. """ cmd_name = make_str(args[0]) original_cmd_name = cmd_name # Get the command cmd = self.get_command(ctx, cmd_name) # If we can't find the command but there is a normalization # function available, we try with that one. if cmd is None and ctx.token_normalize_func is not None: cmd_name = ctx.token_normalize_func(cmd_name) cmd = self.get_command(ctx, cmd_name) # If we don't find the command we want to show an error message # to the user that it was not provided. # However, there is something else we should do: # if the first argument looks like an option we want to kick off parsing again # for arguments to resolve things like --help which now should go to the main place. if cmd is None and not ctx.resilient_parsing: if split_opt(cmd_name)[0]: self.parse_args(ctx, ctx.args) closest = difflib.get_close_matches(original_cmd_name, self.commands, n=1) message = [f"No such command '{original_cmd_name}'."] if closest: message.append(f"The most similar command is {closest[0]!r}.") ctx.fail('\n'.join(message)) # TODO: cmd here is Optional[click.Command], typeshed says it should be just click.Command # I think typeshed is wrong. # https://github.com/python/typeshed/blob/484c014665cdf071b292dd9630f207c03e111895/third_party/2and3/click/core.pyi#L171 return cmd_name, cmd, args[1:] # type: ignore[return-value] consolekit-1.7.1/consolekit/input.py000066400000000000000000000266311465042170600175720ustar00rootroot00000000000000#!/usr/bin/env python3 # # input.py """ Input functions (prompt, choice etc.). """ # # Copyright © 2020-2021 Dominic Davis-Foster # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE # OR OTHER DEALINGS IN THE SOFTWARE. # # prompt and confirm based on https://github.com/pallets/click # Copyright 2014 Pallets # | Redistribution and use in source and binary forms, with or without modification, # | are permitted provided that the following conditions are met: # | # | * Redistributions of source code must retain the above copyright notice, # | this list of conditions and the following disclaimer. # | * Redistributions in binary form must reproduce the above copyright notice, # | this list of conditions and the following disclaimer in the documentation # | and/or other materials provided with the distribution. # | * Neither the name of the copyright holder nor the names of its contributors # | may be used to endorse or promote products derived from this software without # | specific prior written permission. # | # | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER # | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # | # # stderr_input based on raw_input from https://foss.heptapod.net/pypy/pypy # PyPy Copyright holders 2003-2020 # MIT Licenced # # stdlib import sys from typing import IO, Any, Callable, List, Mapping, Optional, Union, overload # 3rd party import click from click.termui import _build_prompt, hidden_prompt_func from click.types import Path, convert_type # this package from consolekit import _readline # noqa: F401 from consolekit._types import _ConvertibleType __all__ = ( "prompt", "confirm", "stderr_input", "choice", ) def prompt( # noqa: MAN002 text: str, default: Optional[str] = None, hide_input: bool = False, confirmation_prompt: Union[bool, str] = False, type: Optional[_ConvertibleType] = None, # noqa: A002 # pylint: disable=redefined-builtin value_proc: Optional[Callable[[Optional[str]], Any]] = None, prompt_suffix: str = ": ", show_default: bool = True, err: bool = False, show_choices: bool = True, ): """ Prompts a user for input. If the user aborts the input by sending an interrupt signal, this function will catch it and raise a :exc:`click.Abort` exception. :param text: The text to show for the prompt. :param default: The default value to use if no input happens. If this is not given it will prompt until it is aborted. :param hide_input: If :py:obj:`True` then the input value will be hidden. :param confirmation_prompt: Asks for confirmation for the value. Can be set to a string instead of :py:obj:`True` to customize the message. :param type: The type to check the value against. :param value_proc: If this parameter is provided it must be a function that is invoked instead of the type conversion to convert a value. :param prompt_suffix: A suffix that should be added to the prompt. :param show_default: Shows or hides the default value in the prompt. :param err: If :py:obj:`True` the file defaults to ``stderr`` instead of ``stdout``, the same as with :func:`click.echo`. :param show_choices: Show or hide choices if the passed type is a :class:`click.Choice`. For example, if the choice is either ``day`` or ``week``, ``show_choices`` is :py:obj:`True` and ``text`` is ``'Group by'`` then the prompt will be ``'Group by (day, week): '``. """ result = None # noqa def prompt_func(text: Any) -> Any: try: return _prompt(text, err=err, hide_input=hide_input) except (KeyboardInterrupt, EOFError): if hide_input: click.echo(None, err=err) raise click.Abort() if value_proc is None: value_proc = convert_type(type, default) prompt = _build_prompt( text, prompt_suffix, show_default, default, show_choices, type, # type: ignore[arg-type] ) has_default = default is not None while True: while True: value = prompt_func(prompt) if value: break elif has_default: if isinstance(value_proc, Path): # pylint: disable=loop-invariant-statement # validate Path default value (exists, dir_okay etc.) value = default break return default try: # pylint: disable=loop-try-except-usage result = value_proc(value) except click.UsageError as e: click.echo(f"Error: {e.message}", err=err) # pylint: disable=loop-invariant-statement continue if not confirmation_prompt: return result if confirmation_prompt is True: confirmation_prompt = "Repeat for confirmation: " while True: value2 = prompt_func(confirmation_prompt) if value2: break if value == value2: # pylint: disable=loop-invariant-statement return result click.echo("Error: the two entered values do not match", err=err) def confirm( # noqa: MAN002 text: str, default: bool = False, abort: bool = False, prompt_suffix: str = ": ", show_default: bool = True, err: bool = False, ): """ Prompts for confirmation (yes/no question). If the user aborts the input by sending a interrupt signal this function will catch it and raise a :exc:`click.Abort` exception. .. latex:clearpage:: :param text: The question to ask. :param default: The default for the prompt. :param abort: If :py:obj:`True` a negative answer aborts the exception by raising :exc:`click.Abort`. :param prompt_suffix: A suffix that should be added to the prompt. :param show_default: Shows or hides the default value in the prompt. :param err: If :py:obj:`True` the file defaults to ``stderr`` instead of ``stdout``, the same as with echo. """ prompt = _build_prompt(text, prompt_suffix, show_default, "Y/n" if default else "y/N") while True: try: # pylint: disable=loop-try-except-usage value = _prompt(prompt, err=err, hide_input=False).lower().strip() except (KeyboardInterrupt, EOFError): raise click.Abort() if value in ('y', "yes"): rv = True elif value in ('n', "no"): rv = False elif value == '': rv = default else: click.echo("Error: invalid input", err=err) continue break if abort and not rv: raise click.Abort() return rv def stderr_input(prompt: str = '', file: IO = sys.stdout) -> str: # pragma: no cover """ Read a string from standard input, but prompt to standard error. The trailing newline is stripped. If the user hits EOF (Unix: :kbd:`Ctrl-D`, Windows: :kbd:`Ctrl-Z+Return`), raise :exc:`EOFError`. On Unix, GNU readline is used if enabled. The ``prompt`` string, if given, is printed to stderr without a trailing newline before reading. """ if file is sys.stdout: return input(prompt) try: stdin = sys.stdin except AttributeError: raise RuntimeError("stderr_input: lost sys.stdin") file.write(prompt) try: flush = file.flush except AttributeError: pass else: flush() try: file.softspace = 0 # type: ignore[attr-defined] except (AttributeError, TypeError): pass line = stdin.readline() if not line: # inputting an empty line gives line == '\n' raise EOFError elif line[-1] == '\n': return line[:-1] return line def _prompt(text: Any, err: bool, hide_input: bool): # noqa: MAN002 if sys.platform != "linux": # Write the prompt separately so that we get nice # coloring through colorama on Windows click.echo(text, nl=False, err=err) text = '' if hide_input: return hidden_prompt_func(text) elif err: return stderr_input(text, file=sys.stderr) else: return click.termui.visible_prompt_func(text) @overload def choice( options: List[str], text: str = ..., default: Optional[str] = ..., prompt_suffix: str = ..., show_default: bool = ..., err: bool = ..., start_index: int = ... ) -> int: ... @overload def choice( options: Mapping[str, str], text: str = ..., default: Optional[str] = ..., prompt_suffix: str = ..., show_default: bool = ..., err: bool = ..., start_index: int = ... ) -> str: ... def choice( options: Union[List[str], Mapping[str, str]], text: str = '', default: Optional[str] = None, prompt_suffix: str = ": ", show_default: bool = True, err: bool = False, start_index: int = 0 ) -> Union[str, int]: """ Prompts a user for input. If the user aborts the input by sending an interrupt signal, this function will catch it and raise a :exc:`click.Abort` exception. :param options: :param text: The text to show for the prompt. :param default: The index of the default value to use if the user does not enter anything. If this is not given it will prompt the user until aborted. :param prompt_suffix: A suffix that should be added to the prompt. :param show_default: Shows or hides the default value in the prompt. :param err: If :py:obj:`True` the file defaults to ``stderr`` instead of ``stdout``, the same as with echo. :param start_index: If ``options`` is a list of values, sets the start index. """ # TODO: completer for numbers? type_: click.ParamType if isinstance(options, Mapping): # (Y/I/N/O/D/Z) [default=N] text = f"{text} ({'/'.join(options.keys())})" type_ = click.STRING for choice, descripton in options.items(): click.echo(f" {choice} : {descripton}") else: type_ = click.IntRange(start_index, len(options) + 1 - start_index) for idx, descripton in enumerate(options): idx += start_index click.echo(f" [{idx}] {descripton}") if default is not None and show_default: text += f" [default={default}]" while True: selection = prompt( text=text, default=default, type=type_, prompt_suffix=prompt_suffix, show_default=False, err=err, ) # pylint: disable=loop-invariant-statement if isinstance(options, Mapping): selection = selection.strip().upper() if selection not in options: click.echo("Please enter a valid option.") else: return selection else: return selection - start_index # pylint: enable=loop-invariant-statement consolekit-1.7.1/consolekit/options.py000066400000000000000000000372501465042170600201250ustar00rootroot00000000000000#!/usr/bin/env python3 # # options.py """ Command line options. .. versionadded:: 0.4.0 """ # # Copyright © 2020-2021 Dominic Davis-Foster # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE # OR OTHER DEALINGS IN THE SOFTWARE. # # MultiValueOption based on https://stackoverflow.com/a/48394004 # Copyright (c) 2018 Stephen Rauch # CC BY-SA 3.0 # # MultiValueOption and auto_default_option based on https://github.com/pallets/click # Copyright 2014 Pallets # | Redistribution and use in source and binary forms, with or without modification, # | are permitted provided that the following conditions are met: # | # | * Redistributions of source code must retain the above copyright notice, # | this list of conditions and the following disclaimer. # | * Redistributions in binary form must reproduce the above copyright notice, # | this list of conditions and the following disclaimer in the documentation # | and/or other materials provided with the distribution. # | * Neither the name of the copyright holder nor the names of its contributors # | may be used to endorse or promote products derived from this software without # | specific prior written permission. # | # | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER # | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # stdlib import inspect from typing import Any, Callable, Iterable, List, Optional, Tuple, TypeVar, cast # 3rd party import click from click.decorators import _param_memo # this package import consolekit.input from consolekit._types import Callback, _ConvertibleType __all__ = ( "verbose_option", "version_option", "colour_option", "force_option", "no_pager_option", "MultiValueOption", "flag_option", "auto_default_option", "auto_default_argument", "DescribedArgument", "_A", "_C", ) _A = TypeVar("_A", bound=click.Argument) _C = TypeVar("_C", bound=click.Command) class VerboseVersionCountType(click.IntRange): """ Subclass of :class:`click.IntRange` which doesn't show the range of valid values. .. versionadded:: 0.8.1 """ def __init__(self): super().__init__(min=0) @staticmethod def _describe_range() -> str: # pragma: no cover """ Describe the range for use in help text. """ return '' def verbose_option(help_text: str = "Show verbose output.") -> Callable[[_C], _C]: """ Adds an option (via the parameter ``verbose``: :class:`int`) to enable verbose output. The option can be provided multiple times by the user. .. versionadded:: 0.4.0 :param help_text: The help text for the option. """ return click.option( "-v", "--verbose", count=True, help=help_text, type=VerboseVersionCountType(), ) def version_option(callback: Callable[[click.Context, click.Option, int], Any]) -> Callable[[_C], _C]: """ Adds an option to show the version and exit. The option can be provided multiple times by the user. The count is stored as an integer and passed as the third parameter to the callback function. .. versionadded:: 0.4.0 :param callback: The callback to invoke when the option is provided. The callback function might look like: .. code-block:: python def version_callback(ctx: click.Context, param: click.Option, value: int): if not value or ctx.resilient_parsing: return if value > 1: click.echo(f"consolekit version {__version__}, Python {sys.version}") else: click.echo(f"consolekit version {__version__}") ctx.exit() """ return click.option( "--version", count=True, expose_value=False, is_eager=True, help="Show the version and exit.", type=VerboseVersionCountType(), callback=cast(Callback, callback), ) def colour_option(help_text: str = "Whether to use coloured output.") -> Callable[[_C], _C]: """ Adds an option (via the parameter ``colour``: :class:`bool`) to enable verbose output. .. versionadded:: 0.4.0 :param help_text: The help text for the option. """ return flag_option( "--colour/--no-colour", default=None, help=help_text, ) def force_option(help_text: str) -> Callable[[_C], _C]: """ Decorator to add the ``-f / --force`` option to a click command. The value is exposed via the parameter ``force``: :class:`bool`. .. versionadded:: 0.5.0 :param help_text: The help text for the option. """ return flag_option("-f", "--force", help=help_text) def no_pager_option(help_text: str = "Disable the output pager.") -> Callable[[_C], _C]: """ Decorator to add the ``--no-pager`` option to a click command. The value is exposed via the parameter ``no_pager``: :class:`bool`. .. versionadded:: 0.5.0 :param help_text: The help text for the option. """ return flag_option("--no-pager", help=help_text) def flag_option(*args, default: Optional[bool] = False, **kwargs) -> Callable[[_C], _C]: r""" Decorator to a flag option to a click command. .. versionadded:: 0.7.0 :param \*args: Positional arguments passed to :func:`click.option`. :param default: The default state of the flag. :param \*\*kwargs: Keyword arguments passed to :func:`click.option`. """ return click.option( *args, is_flag=True, default=default, **kwargs, ) def auto_default_option(*param_decls, **attrs) -> Callable[[_C], _C]: """ Attaches an option to the command, with a default value determined from the decorated function's signature. All positional arguments are passed as parameter declarations to :class:`click.Option`; all keyword arguments are forwarded unchanged (except ``cls``). This is equivalent to creating an :class:`click.Option` instance manually and attaching it to the :attr:`click.Command.params` list. .. versionadded:: 0.7.0 :param cls: the option class to instantiate. This defaults to :class:`click.Option`. """ def decorator(f: _C) -> _C: option_attrs = attrs.copy() if "help" in option_attrs: option_attrs["help"] = inspect.cleandoc(option_attrs["help"]) OptionClass = option_attrs.pop("cls", click.Option) option = OptionClass(param_decls, **option_attrs) _param_memo(f, option) _get_default_from_callback_and_set(f, option) return f return decorator def _get_default_from_callback_and_set(command: click.Command, param: click.Parameter) -> None: if command.callback is not None: # The callback *can* be None, for a no-op if param.name is None: # pragma: no cover raise ValueError("The parameter name cannot be None") signature: inspect.Signature = inspect.signature(command.callback) param_default = signature.parameters[param.name].default if param_default is not inspect.Signature.empty: param.default = param_default param.required = False def auto_default_argument(*param_decls, **attrs) -> Callable[[_C], _C]: """ Attaches an argument to the command, with a default value determined from the decorated function's signature. All positional arguments are passed as parameter declarations to :class:`click.Argument`; all keyword arguments are forwarded unchanged (except ``cls``). This is equivalent to creating an :class:`click.Argument` instance manually and attaching it to the :attr:`click.Command.params` list. .. versionadded:: 0.8.0 :param cls: the option class to instantiate. This defaults to :class:`click.Argument`. """ def decorator(f: _C) -> _C: ArgumentClass = attrs.pop("cls", click.Argument) argument = ArgumentClass(param_decls, **attrs) _param_memo(f, argument) _get_default_from_callback_and_set(f, argument) return f return decorator class MultiValueOption(click.Option): """ Subclass of :class:`click.Option` that behaves like argparse's ``nargs='+'``. .. versionadded:: 0.6.0 :param param_decls: The parameter declarations for this option or argument. This is a list of flags or argument names. :param show_default: Controls whether the default value should be shown on the help page. Normally, defaults are not shown. If this value is a string, it shows the string instead of the value. This is particularly useful for dynamic options. :param help: The help string. :param hidden: Hide this option from help outputs. :param type: The type that should be used. Either a :class:`click.ParamType` or a Python type. The later is converted into the former automatically if supported. :param required: Controls whether this is optional. :param default: The default value if omitted. This can also be a callable, in which case it is invoked when the default is needed without any arguments. :param callback: A callback that should be executed after the parameter was matched. This is called as ``fn(ctx, param, value)`` and needs to return the value. :param metavar: How the value is represented in the help page. :param expose_value: If :py:obj:`True` then the value is passed onwards to the command callback and stored on the context, otherwise it is skipped. :param is_eager: Eager values are processed before non eager ones. Example usage: .. code-block:: python @click.option( "--select", type=click.STRING, help="The checks to enable", cls=MultiValueOption, ) @click_command() def main(select: Iterable[str]): select = list(select) """ def __init__( self, param_decls: Optional[List[str]] = None, show_default: bool = False, help: Optional[str] = None, # noqa: A002 # pylint: disable=redefined-builtin hidden: bool = False, type: Optional[_ConvertibleType] = None, # noqa: A002 # pylint: disable=redefined-builtin required: bool = False, default: Optional[Any] = (), callback: Optional[Callback] = None, metavar: Optional[str] = None, expose_value: bool = True, is_eager: bool = False, ): super().__init__( show_default=show_default, help=help, hidden=hidden, param_decls=param_decls, type=type, required=required, default=default, callback=callback, metavar=metavar, expose_value=expose_value, is_eager=is_eager, ) self._previous_parser_process: Optional[Callable] = None self._eat_all_parser: Optional[click.parser.Option] = None def add_to_parser(self, parser: click.OptionParser, ctx: click.Context) -> Any: """ Add the :class:`~.MultiValueOption` to the given parser. :param parser: :param ctx: """ def parser_process(value, state) -> None: # noqa: MAN001 # method to hook to the parser.process done = False value = [value] # grab everything up to the next option assert self._eat_all_parser is not None # skipcq while state.rargs and not done: for prefix in self._eat_all_parser.prefixes: if state.rargs[0].startswith(prefix): done = True if not done: value.append(state.rargs.pop(0)) # pylint: disable=loop-invariant-statement value = tuple(value) # call the actual process assert self._previous_parser_process is not None # skipcq self._previous_parser_process(value, state) retval = super().add_to_parser(parser, ctx) for name in self.opts: # pylint: disable=loop-invariant-statement our_parser: Optional[click.parser.Option] = parser._long_opt.get(name) or parser._short_opt.get(name) if our_parser is not None: # pylint: enable=loop-invariant-statement self._eat_all_parser = our_parser self._previous_parser_process = our_parser.process our_parser.process = parser_process # type: ignore[assignment] break return retval def process_value(self, ctx: click.Context, value: Any) -> Optional[Tuple]: """ Given a value and context, converts the value as necessary. :param ctx: :param value: """ # If the value we were given is None we do nothing. # This way code that calls this can easily figure out if something was not provided. # Otherwise, it would be converted into an empty tuple for multiple invocations, # which is inconvenient. # assert isinstance(value, tuple), type(value) if value is not None: if isinstance(value, Iterable) and not isinstance(value, str): return tuple(self.type_cast_value(ctx, v) for v in value) elif value in ("()", str(self.default)) or not value: return self.default # type: ignore[return-value] else: return self.type_cast_value(ctx, value) else: return None if int(click.__version__.split('.')[0]) == 7: # pragma: nocover def get_default(self, ctx): # noqa: MAN001,MAN002,D102 if callable(self.default): rv = self.default() else: rv = self.default ret = tuple(self.type(x or (), self, ctx) for x in rv or ()) return ret class _Option(click.Option): def prompt_for_value(self, ctx: click.Context): # noqa: MAN002 """ This is an alternative flow that can be activated in the full value processing if a value does not exist. It will prompt the user until a valid value exists and then returns the processed value as result. """ # Calculate the default before prompting anything to be stable. default = self.get_default(ctx) prompt_string = cast(str, self.prompt) # If this is a prompt for a flag we need to handle this differently. if self.is_bool_flag: return consolekit.input.confirm( prompt_string, default, # type: ignore[arg-type] ) return consolekit.input.prompt( prompt_string, default=default, type=self.type, hide_input=self.hide_input, show_choices=self.show_choices, confirmation_prompt=self.confirmation_prompt, value_proc=lambda x: self.process_value(ctx, x), ) class DescribedArgument(click.Argument): r""" :class:`click.Argument` with an additional keyword argument and attribute giving a short description. This is not shown in the help text, but may be useful for manpages or HTML documentation where additional information can be provided. .. versionadded:: 1.2.0 :param description: See :class:`click.Argument` and :class:`click.Parameter` for descriptions of the other keyword argu ments. .. attribute:: description **Type:** |nbsp| |nbsp| |nbsp| |nbsp| :py:obj:`~typing.Optional`\[:py:class:`str`\] A short description of the argument. """ def __init__(self, *args, description: Optional[str] = None, **kwargs): super().__init__(*args, **kwargs) self.description: Optional[str] = description consolekit-1.7.1/consolekit/py.typed000066400000000000000000000000001465042170600175360ustar00rootroot00000000000000consolekit-1.7.1/consolekit/terminal_colours.py000066400000000000000000000405251465042170600220120ustar00rootroot00000000000000#!/usr/bin/env python # # terminal_colours.py """ Functions for adding ANSI character codes to terminal print statements. .. seealso:: http://en.wikipedia.org/wiki/ANSI_escape_code """ # # Copyright © 2020-2021 Dominic Davis-Foster # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE # OR OTHER DEALINGS IN THE SOFTWARE. # # Based on colorama # https://github.com/tartley/colorama # Copyright Jonathan Hartley 2013 # Distributed under the BSD 3-Clause license. # | Redistribution and use in source and binary forms, with or without # | modification, are permitted provided that the following conditions are met: # | # | * Redistributions of source code must retain the above copyright notice, this # | list of conditions and the following disclaimer. # | # | * Redistributions in binary form must reproduce the above copyright notice, # | this list of conditions and the following disclaimer in the documentation # | and/or other materials provided with the distribution. # | # | * Neither the name of the copyright holders, nor those of its contributors # | may be used to endorse or promote products derived from this software without # | specific prior written permission. # | # | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE # | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Includes modifications to colorama made by Bram Geelen in # https://github.com/tartley/colorama/pull/141/files # # resolve_color_default, _ansi_re and strip_ansi based on # https://github.com/pallets/click # Copyright 2014 Pallets # Distributed under the BSD 3-Clause license. # # stdlib import os import re from abc import ABC from collections import deque from functools import partial from typing import Deque, Iterable, List, Optional, Pattern, Type, TypeVar, Union # 3rd party import click from typing_extensions import Final __all__ = ( "AnsiFore", "AnsiBack", "AnsiStyle", "AnsiCursor", "Fore", "Back", "Style", "Cursor", "AnsiCodes", "Colour", "ColourTrilean", "clear_line", "code_to_chars", "resolve_color_default", "set_title", "strip_ansi", "CSI", "OSC", "BEL", ) try: # 3rd party import colorama # type: ignore[import] colorama.init() except ImportError: pass _C = TypeVar("_C", bound="Colour") _AC = TypeVar("_AC", bound="AnsiCodes") ColourTrilean = Optional[bool] """ Represents the :py:obj:`True`/:py:obj:`False`/:py:obj:`None` state of colour options. .. versionadded:: 0.8.0 """ CSI: Final[str] = "\u001b[" OSC: Final[str] = "\u001b]" BEL: Final[str] = '\x07' fore_stack: Deque[str] = deque() back_stack: Deque[str] = deque() style_stack: Deque[str] = deque() def resolve_color_default(color: ColourTrilean = None) -> ColourTrilean: """ Helper to get the default value of the color flag. If a value is passed it is returned unchanged, otherwise it's looked up from the current context. If the environment variable ``PYCHARM_HOSTED`` is ``1`` (which is the case if running in PyCharm) the output will be coloured by default. If the environment variable ``NO_COLOR`` is ``1`` the output will not be coloured by default. See https://no-color.org/ for more details. This variable takes precedence over ``PYCHARM_HOSTED``. If no value is passed in, there is no context, and neither environment variable is set, :py:obj:`None` is returned. .. versionchanged:: 1.3.0 * Added support for the ``NO_COLOR`` environment variable. * Only uses a value from the click context (:attr:`Context.color `) if it is not :py:obj:`None`. Otherwise falls back to checking the environment variables. :param color: """ if color is not None: return color ctx = click.get_current_context(silent=True) if ctx is not None and ctx.color is not None: return ctx.color if int(os.environ.get("NO_COLOR", 0)): return False if int(os.environ.get("PYCHARM_HOSTED", 0)): return True return None def code_to_chars(code: Union[str, int]) -> str: # noqa: D103 return CSI + str(code) + 'm' def set_title(title: str) -> str: # noqa: D103 return OSC + "2;" + title + BEL # def clear_screen(mode: int = 2) -> str: # return CSI + str(mode) + 'J' def clear_line(mode: int = 2) -> str: # noqa: D103 return CSI + str(mode) + 'K' _ansi_re: Pattern[str] = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") def strip_ansi(value: str) -> str: """ Strip ANSI colour codes from the given string to return a plaintext output. :param value: """ return _ansi_re.sub('', value) class Colour(str): r""" An ANSI escape sequence representing a colour. The colour can be used as a context manager, a string, or a function. :param style: Escape sequence representing the style. :type style: :class:`str` :param stack: The stack to place the escape sequence on. :type stack: :class:`~typing.List`\[:class:`str`\] :param reset: The escape sequence to reset the style. :type reset: :class:`str` .. autosummary-widths:: 7/16 """ __slots__ = ("style", "reset", "stack") style: str reset: str stack: Union[Deque[str], List[str]] def __new__(cls, style: str, stack: Union[Deque[str], List[str]], reset: str) -> "Colour": # noqa: D102 self = super().__new__(cls, style) # type: ignore[import] self.style = style self.stack = stack self.reset = reset return self def __enter__(self) -> None: print(self.style, end='') self.stack.append(self.style) def __exit__(self, exc_type, exc_val, exc_tb) -> None: if self.style == self.stack[-1]: self.stack.pop() print(self.stack[-1], end='') def __call__(self, text) -> str: # noqa: MAN001 """ Returns the given text in this colour. """ return f"{self}{text}{self.reset}" @classmethod def from_code(cls: Type[_C], code: Union[str, int], background: bool = False) -> _C: """ Returns a :class:`~.Colour` to create coloured text. The colour can be reset using :py:obj:`.Fore.RESET` or :py:obj:`.Back.RESET`. .. versionadded:: 0.9.0 :param code: A 3- or 4- bit ANSI colour code. :param background: Whether to set the colour for the background. :rtype: :class:`~.Colour` .. note:: The ``background`` option only influences the reset value and the stack used. It will not handle conversion of foreground codes to background codes. .. latex:clearpage:: """ if background: stack = back_stack reset = AnsiBack._reset else: stack = fore_stack reset = AnsiFore._reset return cls(code_to_chars(code), stack=stack, reset=reset) @classmethod def from_256_code(cls: Type[_C], code: Union[str, int], background: bool = False) -> _C: """ Returns a :class:`~.Colour` to create 256-colour text. The colour can be reset using :py:obj:`.Fore.RESET` or :py:obj:`.Back.RESET`. .. versionadded:: 0.9.0 .. note:: Not all terminals support 256-colour mode. :param code: A 256-colour ANSI code. :param background: Whether to set the colour for the background. :rtype: :class:`~.Colour` .. note:: The ``background`` option only influences the reset value and the stack used. It will not handle conversion of foreground codes to background codes. """ if background: stack = back_stack reset = AnsiBack._reset template = CSI + "48;5;{}m" else: stack = fore_stack reset = AnsiFore._reset template = CSI + "38;5;{}m" return cls(template.format(code), stack=stack, reset=reset) @classmethod def from_rgb( cls: Type[_C], r: Union[str, int], g: Union[str, int], b: Union[str, int], background: bool = False ) -> _C: """ Returns a :class:`~.Colour` to create 24-bit coloured text. The colour can be reset using :py:obj:`.Fore.RESET` or :py:obj:`.Back.RESET`. .. versionadded:: 0.9.0 .. note:: Not all terminals support 24-bit colours. :param r: :param g: :param b: :param background: Whether to set the colour for the background. :rtype: :class:`~.Colour` .. note:: The ``background`` option only influences the reset value and the stack used. It will not handle conversion of foreground codes to background codes. .. latex:clearpage:: """ if background: template = CSI + "48;2;{r};{g};{b}m" stack = back_stack reset = AnsiBack._reset else: template = CSI + "38;2;{r};{g};{b}m" stack = fore_stack reset = AnsiFore._reset return cls(template.format(r=r, g=g, b=b), stack=stack, reset=reset) @classmethod def from_hex(cls: Type[_C], hex_colour: str, background: bool = False) -> _C: """ Returns a :class:`~.Colour` to create 24-bit coloured text. The colour can be reset using :py:obj:`.Fore.RESET` or :py:obj:`.Back.RESET`. .. versionadded:: 0.9.0 .. note:: Not all terminals support 24-bit colours. :param hex_colour: The hex colour code. :param background: Whether to set the colour for the background. :rtype: :class:`~.Colour` .. note:: The ``background`` option only influences the reset value and the stack used. It will not handle conversion of foreground codes to background codes. """ # From https://stackoverflow.com/q/29643352 # https://stackoverflow.com/users/3924370/julian-white # CC BY-SA 3.0 value = hex_colour.lstrip('#') lv = len(value) r, g, b = tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3)) return cls.from_rgb(r, g, b, background=background) def print_256_colour_testpattern() -> None: """ Print a 256-colour test pattern to the terminal. .. versionadded:: 0.9.0 .. note:: Not all terminals support 24-bit colours. """ # 3rd party from domdf_python_tools.iterative import chunks def print_heading(text: str, block_size: int = 3, n_blocks: int = 36) -> None: click.echo() click.echo(str(text).center(((block_size + 1) * n_blocks) - 1, '-')) def print_line(values: Iterable[int], block_size: int = 3) -> None: values = list(values) mid = len(values) // 2 colour: Optional[bool] = resolve_color_default() echo = partial(click.echo, nl=False, color=colour) for code in values[:mid]: echo(Colour.from_256_code(code, background=True)(str(code).center(block_size)) + ' ') with Fore.BLACK: for code in values[mid:-1]: echo(Colour.from_256_code(code, background=True)(str(code).center(block_size)) + ' ') click.echo( Colour.from_256_code(values[-1], background=True)(str(values[-1]).center(block_size).rstrip()), color=colour ) print_heading( "Standard Colours".center((9 * 8) - 1, '-') + ' ' + "High-Intensity Colours".center((9 * 8) - 1, '-'), block_size=8, n_blocks=16 ) print_line(range(16), block_size=8) print_heading("216 Colours") for row in chunks(range(16, 232), 36): # pylint: disable=loop-invariant-statement print_line(row) print_heading("Greyscale Colours", block_size=5, n_blocks=24) print_line(range(232, 256), block_size=5) click.echo('\n') class AnsiCodes(ABC): """ Abstract base class for ANSI Codes. """ _stack: Union[Deque[str], List[str]] _reset: str def __init_subclass__(cls, **kwargs) -> None: """ The subclasses declare class attributes which are numbers. Upon instantiation we define instance attributes, which are the same as the class attributes but wrapped with the ANSI escape sequence. """ for name in dir(cls): if not name.startswith('_'): value = getattr(cls, name) setattr(cls, name, Colour(code_to_chars(value), cls._stack, cls._reset)) def __new__(cls: Type[_AC], *args, **kwargs) -> Type[_AC]: # noqa: D102 return cls class AnsiCursor: """ Provides methods to control the cursor. """ def UP(self, n: int = 1) -> str: """ Moves the cursor up ``n`` lines. :param n: """ return f"{CSI}{str(n)}A" def DOWN(self, n: int = 1) -> str: """ Moves the cursor down ``n`` lines. :param n: """ return f"{CSI}{str(n)}B" def FORWARD(self, n: int = 1) -> str: """ Moves the cursor forward (right) ``n`` lines. :param n: """ return f"{CSI}{str(n)}C" def BACK(self, n: int = 1) -> str: """ Moves the cursor backward (left) ``n`` lines. :param n: """ return f"{CSI}{str(n)}D" def POS(self, x: int = 1, y: int = 1) -> str: """ Moves the cursor to the given position. :param x: :param y: """ return f"{CSI}{str(y)};{str(x)}H" def HIDE(self) -> str: """ Hides the cursor. .. versionadded:: 0.7.0 """ return f"{CSI}?25l" def SHOW(self) -> str: """ Shows the cursor. .. versionadded:: 0.7.0 """ return f"{CSI}?25h" class AnsiFore(AnsiCodes): r""" ANSI Colour Codes for foreground colour. The colours can be used as a context manager, a string, or a function. Valid values are: .. raw:: latex \vspace{-5px} \begin{multicols}{3} * BLACK * RED * GREEN * YELLOW * BLUE * MAGENTA * CYAN * WHITE * RESET * LIGHTBLACK_EX * LIGHTRED_EX * LIGHTGREEN_EX * LIGHTYELLOW_EX * LIGHTBLUE_EX * LIGHTMAGENTA_EX * LIGHTCYAN_EX * LIGHTWHITE_EX .. raw:: latex \end{multicols} \vspace{-5px} This class is also available under the shorter alias :py:obj:`Fore`. """ _stack = fore_stack _reset = f"{CSI}39m" BLACK = 30 RED = 31 GREEN = 32 YELLOW = 33 BLUE = 34 MAGENTA = 35 CYAN = 36 WHITE = 37 RESET = 39 # These are fairly well supported, but not part of the standard. LIGHTBLACK_EX = 90 LIGHTRED_EX = 91 LIGHTGREEN_EX = 92 LIGHTYELLOW_EX = 93 LIGHTBLUE_EX = 94 LIGHTMAGENTA_EX = 95 LIGHTCYAN_EX = 96 LIGHTWHITE_EX = 97 class AnsiBack(AnsiCodes): r""" ANSI Colour Codes for background colour. The colours can be used as a context manager, a string, or a function. Valid values are: .. raw:: latex \vspace{-5px} \begin{multicols}{3} * BLACK * RED * GREEN * YELLOW * BLUE * MAGENTA * CYAN * WHITE * RESET * LIGHTBLACK_EX * LIGHTRED_EX * LIGHTGREEN_EX * LIGHTYELLOW_EX * LIGHTBLUE_EX * LIGHTMAGENTA_EX * LIGHTCYAN_EX * LIGHTWHITE_EX .. raw:: latex \end{multicols} \vspace{-5px} This class is also available under the shorter alias :py:obj:`Back`. """ _stack = back_stack _reset = f"{CSI}49m" BLACK = 40 RED = 41 GREEN = 42 YELLOW = 43 BLUE = 44 MAGENTA = 45 CYAN = 46 WHITE = 47 RESET = 49 # These are fairly well supported, but not part of the standard. LIGHTBLACK_EX = 100 LIGHTRED_EX = 101 LIGHTGREEN_EX = 102 LIGHTYELLOW_EX = 103 LIGHTBLUE_EX = 104 LIGHTMAGENTA_EX = 105 LIGHTCYAN_EX = 106 LIGHTWHITE_EX = 107 class AnsiStyle(AnsiCodes): """ ANSI Colour Codes for text style. Valid values are: * BRIGHT * DIM * NORMAL Additionally, ``AnsiStyle.RESET_ALL`` can be used to reset the foreground and background colours as well as the text style. This class is also available under the shorter alias :py:obj:`Style`. """ _stack = style_stack _reset = f"{CSI}22m" BRIGHT = 1 DIM = 2 NORMAL = 22 RESET_ALL = 0 Fore = AnsiFore Back = AnsiBack Style = AnsiStyle Cursor = AnsiCursor() fore_stack.append(Fore.RESET) back_stack.append(Back.RESET) style_stack.append(Style.NORMAL) if __name__ == "__main__": print_256_colour_testpattern() consolekit-1.7.1/consolekit/terminal_colours.pyi000066400000000000000000000137041465042170600221620ustar00rootroot00000000000000#!/usr/bin/env python # # terminal_colours.py """ Functions for adding colours to terminal print statements. This module generates ANSI character codes to printing colors to terminals. See: http://en.wikipedia.org/wiki/ANSI_escape_code """ # # Copyright © 2020 Dominic Davis-Foster # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. # # Based on colorama # https://github.com/tartley/colorama # Copyright Jonathan Hartley 2013 # Distributed under the BSD 3-Clause license. # | Redistribution and use in source and binary forms, with or without # | modification, are permitted provided that the following conditions are met: # | # | * Redistributions of source code must retain the above copyright notice, this # | list of conditions and the following disclaimer. # | # | * Redistributions in binary form must reproduce the above copyright notice, # | this list of conditions and the following disclaimer in the documentation # | and/or other materials provided with the distribution. # | # | * Neither the name of the copyright holders, nor those of its contributors # | may be used to endorse or promote products derived from this software without # | specific prior written permission. # | # | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE # | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Includes modifications to colorama made by Bram Geelen in # https://github.com/tartley/colorama/pull/141/files # # resolve_color_default, _ansi_re and strip_ansi based on # https://github.com/pallets/click # Copyright 2014 Pallets # Distributed under the BSD 3-Clause license. # # stdlib from abc import ABC from typing import Deque, List, Optional, Type, TypeVar, Union # 3rd party from typing_extensions import Final ColourTrilean = Optional[bool] CSI: Final[str] OSC: Final[str] BEL: Final[str] fore_stack: Deque[str] back_stack: Deque[str] style_stack: Deque[str] def resolve_color_default(color: Optional[bool] = ...) -> Optional[bool]: ... def code_to_chars(code: Union[str, int]) -> str: ... def set_title(title: str) -> str: ... # def clear_screen(mode: int = ...) -> str: ... def clear_line(mode: int = ...) -> str: ... def strip_ansi(value: str) -> str: ... _C = TypeVar("_C", bound="Colour") _AC = TypeVar("_AC", bound="AnsiCodes") class Colour(str): style: str reset: str stack: Union[Deque[str], List[str]] def __new__(cls, style: str, stack: Union[Deque[str], List[str]], reset: str) -> "Colour": ... def __enter__(self) -> None: ... def __exit__(self, exc_type, exc_val, exc_tb) -> None: ... def __call__(self, text) -> str: ... # noqa: MAN001 @classmethod def from_code(cls: Type[_C], code: Union[str, int], background: bool = ...) -> _C: ... @classmethod def from_256_code(cls: Type[_C], code: Union[str, int], background: bool = ...) -> _C: ... @classmethod def from_rgb( cls: Type[_C], r: Union[str, int], g: Union[str, int], b: Union[str, int], background: bool = ... ) -> _C: ... @classmethod def from_hex(cls: Type[_C], hex_colour: str, background: bool = ...) -> _C: ... def print_256_colour_testpattern() -> None: ... class AnsiCodes(ABC): _stack: Union[Deque[str], List[str]] _reset: str def __new__(cls: Type[_AC], *args, **kwargs) -> Type[_AC]: ... # type: ignore[misc] class AnsiCursor: def UP(self, n: int = ...) -> str: ... def DOWN(self, n: int = ...) -> str: ... def FORWARD(self, n: int = ...) -> str: ... def BACK(self, n: int = ...) -> str: ... def POS(self, x: int = ..., y: int = ...) -> str: ... def HIDE(self) -> str: ... def SHOW(self) -> str: ... class AnsiFore(AnsiCodes): BLACK: Colour RED: Colour GREEN: Colour YELLOW: Colour BLUE: Colour MAGENTA: Colour CYAN: Colour WHITE: Colour RESET: Colour # These are fairly well supported, but not part of the standard. LIGHTBLACK_EX: Colour LIGHTRED_EX: Colour LIGHTGREEN_EX: Colour LIGHTYELLOW_EX: Colour LIGHTBLUE_EX: Colour LIGHTMAGENTA_EX: Colour LIGHTCYAN_EX: Colour LIGHTWHITE_EX: Colour class AnsiBack(AnsiCodes): _stack: List[str] _reset: str BLACK: Colour RED: Colour GREEN: Colour YELLOW: Colour BLUE: Colour MAGENTA: Colour CYAN: Colour WHITE: Colour RESET: Colour # These are fairly well supported, but not part of the standard. LIGHTBLACK_EX: Colour LIGHTRED_EX: Colour LIGHTGREEN_EX: Colour LIGHTYELLOW_EX: Colour LIGHTBLUE_EX: Colour LIGHTMAGENTA_EX: Colour LIGHTCYAN_EX: Colour LIGHTWHITE_EX: Colour class AnsiStyle(AnsiCodes): _stack: List[str] _reset: str BRIGHT: Colour DIM: Colour NORMAL: Colour RESET_ALL: Colour Fore = AnsiFore Back = AnsiBack Style = AnsiStyle Cursor = AnsiCursor() consolekit-1.7.1/consolekit/testing.py000066400000000000000000000210741465042170600201040ustar00rootroot00000000000000#!/usr/bin/env python3 # # testing.py """ Test helpers. .. versionadded:: 0.9.0 .. extras-require:: testing :pyproject: """ # # Copyright © 2020-2021 Dominic Davis-Foster # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE # OR OTHER DEALINGS IN THE SOFTWARE. # # Result and CliRunner based on https://github.com/pallets/click # Copyright 2014 Pallets # | Redistribution and use in source and binary forms, with or without modification, # | are permitted provided that the following conditions are met: # | # | * Redistributions of source code must retain the above copyright notice, # | this list of conditions and the following disclaimer. # | * Redistributions in binary form must reproduce the above copyright notice, # | this list of conditions and the following disclaimer in the documentation # | and/or other materials provided with the distribution. # | * Neither the name of the copyright holder nor the names of its contributors # | may be used to endorse or promote products derived from this software without # | specific prior written permission. # | # | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER # | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # stdlib from types import TracebackType from typing import IO, Any, Iterable, Mapping, Optional, Tuple, Type, Union # 3rd party import click.testing import pytest # nodep from coincidence.regressions import check_file_regression # nodep from pytest_regressions.file_regression import FileRegressionFixture # nodep from typing_extensions import Literal __all__ = ("CliRunner", "Result", "cli_runner") _click_major = int(click.__version__.split('.')[0]) class Result(click.testing.Result): """ Holds the captured result of an invoked CLI script. :param runner: The runner that created the result. :param stdout_bytes: The standard output as bytes. :param stderr_bytes: The standard error as bytes, or :py:obj:`None` if not available. :param exit_code: The command's exit code. :param exception: The exception that occurred, if any. :param exc_info: The traceback, if an exception occurred. """ runner: click.testing.CliRunner exit_code: int exception: Optional[BaseException] exc_info: Optional[Any] stdout_bytes: bytes stderr_bytes: Optional[bytes] return_value: Optional[Tuple[Type[BaseException], BaseException, TracebackType]] def __init__( self, runner: click.testing.CliRunner, stdout_bytes: bytes, stderr_bytes: Optional[bytes], exit_code: int, exception: Optional[BaseException], exc_info: Optional[Tuple[Type[BaseException], BaseException, TracebackType]] = None, ) -> None: if _click_major >= 8: super().__init__( runner=runner, stdout_bytes=stdout_bytes, stderr_bytes=stderr_bytes, exit_code=exit_code, exception=exception, exc_info=exc_info, return_value=None, ) else: super().__init__( # type: ignore[call-arg] runner=runner, stdout_bytes=stdout_bytes, stderr_bytes=stderr_bytes, exit_code=exit_code, exception=exception, exc_info=exc_info, ) @property def output(self) -> str: """ The (standard) output as a string. """ return super().output @property def stdout(self) -> str: """ The standard output as a string. """ return super().stdout @property def stderr(self) -> str: """ The standard error as a string. """ return super().stderr @classmethod def _from_click_result(cls, result: click.testing.Result) -> "Result": return cls( runner=result.runner, stdout_bytes=result.stdout_bytes, stderr_bytes=result.stderr_bytes, exit_code=result.exit_code, exception=result.exception, exc_info=result.exc_info, ) def check_stdout( self, file_regression: FileRegressionFixture, extension: str = ".txt", **kwargs, ) -> Literal[True]: r""" Perform a regression check on the standard output from the command. :param file_regression: :param extension: The extension of the reference file. :param \*\*kwargs: Additional keyword arguments passed to :meth:`.FileRegressionFixture.check`. """ __tracebackhide__ = True check_file_regression(self.stdout.rstrip(), file_regression, extension=extension, **kwargs) return True class CliRunner(click.testing.CliRunner): """ Provides functionality to invoke and test a Click script in an isolated environment. This only works in single-threaded systems without any concurrency as it changes the global interpreter state. :param charset: The character set for the input and output data. :param env: A dictionary with environment variables to override. :param echo_stdin: If :py:obj:`True`, then reading from stdin writes to stdout. This is useful for showing examples in some circumstances. Note that regular prompts will automatically echo the input. :param mix_stderr: If :py:obj:`False`, then stdout and stderr are preserved as independent streams. This is useful for Unix-philosophy apps that have predictable stdout and noisy stderr, such that each may be measured independently. .. autoclasssumm:: CliRunner :autosummary-sections: ;; """ def __init__( self, charset: str = "UTF-8", env: Optional[Mapping[str, str]] = None, *, echo_stdin: bool = False, mix_stderr: bool = True, ) -> None: super().__init__(charset, env, echo_stdin, mix_stderr) def invoke( # type: ignore[override] self, cli: click.BaseCommand, args: Optional[Union[str, Iterable[str]]] = None, input: Optional[Union[bytes, str, IO]] = None, # noqa: A002 # pylint: disable=redefined-builtin env: Optional[Mapping[str, str]] = None, *, catch_exceptions: bool = False, color: bool = False, **extra, ) -> Result: r""" Invokes a command in an isolated environment. The arguments are forwarded directly to the command line script, the ``extra`` keyword arguments are passed to the :meth:`~click.Command.main` function of the command. :param cli: The command to invoke. :param args: The arguments to invoke. It may be given as an iterable or a string. When given as string it will be interpreted as a Unix shell command. More details at :func:`shlex.split`. :param input: The input data for ``sys.stdin``. :param env: The environment overrides. :param catch_exceptions: Whether to catch any other exceptions than :exc:`SystemExit`. :param color: whether the output should contain color codes. The application can still override this explicitly. :param \*\*extra: The keyword arguments to pass to :meth:`click.Command.main`. """ if args is not None and not isinstance(args, str): args = list(args) result = super().invoke( cli, args=args, input=input, env=env, catch_exceptions=catch_exceptions, color=color, **extra, ) return Result._from_click_result(result) @pytest.fixture() def cli_runner() -> CliRunner: """ Returns a click runner for this test function. """ return CliRunner() consolekit-1.7.1/consolekit/tracebacks.py000066400000000000000000000152211465042170600205260ustar00rootroot00000000000000#!/usr/bin/env python3 # # tracebacks.py """ Functions for handling exceptions and their tracebacks. .. versionadded:: 1.0.0 .. latex:vspace:: -10px """ # # Copyright © 2020-2021 Dominic Davis-Foster # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE # OR OTHER DEALINGS IN THE SOFTWARE. # # stdlib import contextlib import sys from typing import TYPE_CHECKING, Callable, ContextManager, List, Type, TypeVar, Union # 3rd party import click from domdf_python_tools.compat import nullcontext if sys.version_info >= (3, 7) or TYPE_CHECKING: # stdlib from typing import NoReturn __all__ = ("TracebackHandler", "handle_tracebacks", "traceback_handler", "traceback_option") _C = TypeVar("_C", bound=click.Command) class TracebackHandler: """ Context manager to abort execution with a short error message on the following exception types: * :exc:`FileNotFoundError` * :exc:`FileExistsError` Other custom exception classes inheriting from :exc:`Exception` are also handled, but with a generic message. The following exception classes are ignored: * :exc:`EOFError` * :exc:`KeyboardInterrupt` * :exc:`click.ClickException` * :exc:`SystemExit` (new in version 1.1.2) How these exceptions are handled can be changed, and supported can be added for further exception classes by subclassing this class. Each method is named in the form :file:`handle_{}`, where ``exception`` is the name of the exception class to handle. .. versionadded:: 1.0.0 :param exception: The exception to raise after handling the traceback. If not running within a click command or group you'll likely want to set this to :exc:`SystemExit(1) `. :default exception: :class:`click.Abort() ` .. versionchanged:: 1.4.0 Added the ``exception`` argument. .. seealso:: :func:`~.handle_tracebacks`. .. latex:clearpage:: """ # noqa: D400 exception: Exception """ The exception to raise after handling the traceback. .. versionadded:: 1.4.0 """ def __init__(self, exception: BaseException = click.Abort()): self.exception: BaseException = exception # type: ignore[assignment] def abort(self, msg: Union[str, List[str]]) -> "NoReturn": """ Abort the current process by calling ``self.exception``. .. versionadded:: 1.4.0 :param msg: The message to write to stderr before raising the exception. If a list of strings the strings are concatenated (i.e. ``''.join(msg)``). """ if not isinstance(msg, str): msg = ''.join(msg) if msg: click.echo(msg, err=True, color=False) raise self.exception def handle_EOFError(self, e: EOFError) -> "NoReturn": # noqa: D102 raise e def handle_KeyboardInterrupt(self, e: KeyboardInterrupt) -> "NoReturn": # noqa: D102 raise e def handle_ClickException(self, e: click.ClickException) -> "NoReturn": # noqa: D102 raise e def handle_Abort(self, e: click.Abort) -> "NoReturn": # noqa: D102 raise e def handle_SystemExit(self, e: SystemExit) -> "NoReturn": # noqa: D102 raise e def handle_FileNotFoundError(self, e: FileNotFoundError) -> "NoReturn": # noqa: D102 self.abort(f"File Not Found: {e}") def handle_FileExistsError(self, e: FileExistsError) -> "NoReturn": # noqa: D102 self.abort(f"File Exists: {e}") def handle(self, e: BaseException) -> bool: """ Handle the given exception. :param e: """ exception_name = e.__class__.__name__ if hasattr(self, f"handle_{exception_name}"): return getattr(self, f"handle_{exception_name}")(e) for base in e.__class__.__mro__: if hasattr(self, f"handle_{base.__name__}"): return getattr(self, f"handle_{base.__name__}")(e) self.abort(f"An error occurred: {e}") @contextlib.contextmanager def __call__(self): # noqa: MAN002 """ Use the :class:`~.TracebackHandler` with a :keyword:`with` block, and handle any exceptions raised within. """ try: yield except BaseException as e: self.handle(e) @contextlib.contextmanager def traceback_handler(): # noqa: MAN002 """ Context manager to abort execution with a short error message on the following exception types: * :exc:`FileNotFoundError` * :exc:`FileExistsError` Other custom exception classes inheriting from :exc:`Exception` are also handled, but with a generic message. The following exception classes are ignored: * :exc:`EOFError` * :exc:`KeyboardInterrupt` * :exc:`click.ClickException` .. versionadded:: 0.8.0 .. seealso:: :func:`~.handle_tracebacks` and :class:`~.TracebackHandler` """ # noqa: D400 with TracebackHandler()(): yield def handle_tracebacks( show_traceback: bool = False, cls: Type[TracebackHandler] = TracebackHandler, ) -> ContextManager: """ Context manager to conditionally handle tracebacks, usually based on the value of a command line flag. .. versionadded:: 0.8.0 :param show_traceback: If :py:obj:`True`, the full Python traceback will be shown on errors. If :py:obj:`False`, only the summary of the traceback will be shown. In either case the program execution will stop on error. :param cls: The class to use to handle the tracebacks. :rtype: .. versionchanged:: 1.0.0 Added the ``cls`` parameter. .. seealso:: :func:`~.traceback_handler` and :class:`~.TracebackHandler` """ if show_traceback: return nullcontext() else: return cls()() def traceback_option(help_text: str = "Show the complete traceback on error.") -> Callable[[_C], _C]: """ Decorator to add the ``-T / --traceback`` option to a click command. The value is exposed via the parameter ``show_traceback``: :class:`bool`. .. versionadded:: 1.0.0 :param help_text: The help text for the option. """ # this package from consolekit.options import flag_option return flag_option("-T", "--traceback", "show_traceback", help=help_text) consolekit-1.7.1/consolekit/utils.py000066400000000000000000000330431465042170600175660ustar00rootroot00000000000000#!/usr/bin/env python3 # # utils.py """ Utility functions. .. versionchanged:: 1.0.0 :func:`~.tracebacks.traceback_handler` and :func:`~.tracebacks.handle_tracebacks` moved to :mod:`consolekit.tracebacks`. They will still be importable from here until v2.0.0 .. automodulesumm:: consolekit.utils .. latex:clearpage:: """ # # Copyright © 2020-2021 Dominic Davis-Foster # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE # OR OTHER DEALINGS IN THE SOFTWARE. # # stdlib import contextlib import difflib import os import shutil import sys from functools import lru_cache from itertools import cycle from types import ModuleType from typing import IO, Any, Iterable, Iterator, List, Optional, Sequence, Union # 3rd party import click import deprecation_alias from domdf_python_tools.stringlist import StringList from domdf_python_tools.words import SANS_SERIF_ITALIC_LETTERS from mistletoe import block_token, span_token # type: ignore[import] from mistletoe.base_renderer import BaseRenderer # type: ignore[import] from typing_extensions import TypeGuard # this package from consolekit import terminal_colours, tracebacks from consolekit.terminal_colours import ColourTrilean, resolve_color_default __all__ = ( "get_env_vars", "is_command", "import_commands", "abort", "overtype", "coloured_diff", "solidus_spinner", "braille_spinner", "snake_spinner", "hide_cursor", "show_cursor", "TerminalRenderer", "hidden_cursor", "long_echo", ) _deprecator = deprecation_alias.deprecated( deprecated_in="1.0.0", removed_in="2.0.0", current_version="1.7.1", details="Import from consolekit.tracebacks instead." ) handle_tracebacks = _deprecator(tracebacks.handle_tracebacks) traceback_handler = _deprecator(tracebacks.traceback_handler) def get_env_vars(ctx, args, incomplete) -> List[str]: # noqa: D103,MAN001 return [k for k in os.environ.keys() if incomplete in k] def is_command(obj: Any) -> TypeGuard[click.Command]: """ Return whether ``obj`` is a click command. :param obj: """ return isinstance(obj, click.Command) def import_commands(source: Optional[ModuleType] = None, entry_point: Optional[str] = None) -> List[click.Command]: """ Returns a list of all commands. Commands can be defined locally in the module given in ``source``, or by third party extensions who define an entry point in the following format: :: = : :param source: :param entry_point: """ # 3rd party from domdf_python_tools.import_tools import discover, discover_entry_points all_commands = [] if source is not None: all_commands.extend(discover(source, is_command, exclude_side_effects=False)) if entry_point is not None: all_commands.extend(discover_entry_points(entry_point, is_command)) return all_commands # TODO: Turn this into a class so the message is only printed when raised. def abort(message: str, colour: ColourTrilean = None) -> Exception: """ Aborts the program execution. :param message: :param colour: Whether to use coloured output. Default auto-detect. :no-default colour: .. versionchanged:: 1.0.1 Added the ``colour`` option. """ click.echo(terminal_colours.Fore.RED(message), err=True, color=resolve_color_default(colour)) return click.Abort() def overtype( *objects, sep: str = ' ', end: str = '', file: Optional[IO] = None, flush: bool = False, ) -> None: r""" Print ``objects`` to the text stream ``file``, starting with ``"\r"``, separated by ``sep`` and followed by ``end``. ``sep``, ``end``, ``file`` and ``flush``, if present, must be given as keyword arguments All non-keyword arguments are converted to strings like :class:`str` does and written to the stream, separated by `sep` and followed by `end`. If no such arguments are given, :func:`~consolekit.utils.overtype` will just write ``"\r"``. .. TODO:: This does not currently work in the PyCharm console, at least on Windows :param objects: A list of strings or string-like objects to write to the terminal. :param sep: String to separate the objects with. :param end: String to end with. :param file: An object with a ``write(string)`` method. :default file: ``sys.stdout`` :param flush: If :py:obj:`True`, the stream is forcibly flushed. """ # noqa: D400 object0 = f"\r{objects[0]}" objects = (object0, *objects[1:]) print(*objects, sep=sep, end=end, file=file, flush=flush) def coloured_diff( a: Sequence[str], b: Sequence[str], fromfile: str = '', tofile: str = '', fromfiledate: str = '', tofiledate: str = '', n: int = 3, lineterm: str = '\n', removed_colour: terminal_colours.Colour = terminal_colours.Fore.RED, added_colour: terminal_colours.Colour = terminal_colours.Fore.GREEN, ) -> str: r""" Compare two sequences of lines; generate the delta as a unified diff. Unified diffs are a compact way of showing line changes and a few lines of context. The number of context lines is set by ``n`` which defaults to three. By default, the diff control lines (those with ``---``, ``+++``, or ``@@``) are created with a trailing newline. This is helpful so that inputs created from ``file.readlines()`` result in diffs that are suitable for ``file.writelines()`` since both the inputs and outputs have trailing newlines. For inputs that do not have trailing newlines, set the lineterm argument to ``''`` so that the output will be uniformly newline free. The unidiff format normally has a header for filenames and modification times. Any or all of these may be specified using strings for ``fromfile``, ``tofile``, ``fromfiledate``, and ``tofiledate``. The modification times are normally expressed in the ISO 8601 format. .. versionadded:: 0.3.0 :bold-title:`Example:` >>> for line in coloured_diff( ... 'one two three four'.split(), ... 'zero one tree four'.split(), 'Original', 'Current', ... '2005-01-26 23:30:50', '2010-04-02 10:20:52', ... lineterm='', ... ): ... print(line) # doctest: +NORMALIZE_WHITESPACE --- Original 2005-01-26 23:30:50 +++ Current 2010-04-02 10:20:52 @@ -1,4 +1,4 @@ +zero one -two -three +tree four :param a: :param b: :param fromfile: :param tofile: :param fromfiledate: :param tofiledate: :param n: :param lineterm: :param removed_colour: The :class:`~consolekit.terminal_colours.Colour` to use for lines that were removed. :param added_colour: The :class:`~consolekit.terminal_colours.Colour` to use for lines that were added. """ buf = StringList() diff = difflib.unified_diff(a, b, fromfile, tofile, fromfiledate, tofiledate, n, lineterm) for line in diff: if line.startswith('+'): buf.append(added_colour(line)) elif line.startswith('-'): buf.append(removed_colour(line)) else: buf.append(line) buf.blankline(ensure_single=True) return str(buf) solidus_spinner = cycle("|/-\\") """ :func:`itertools.cycle` of characters to use as a loading spinner. .. versionadded:: 0.7.0 """ braille_spinner = cycle(['⢿', '⣻', '⣽', '⣾', '⣷', '⣯', '⣟', '⡿']) """ :func:`itertools.cycle` of braille characters to use as a loading spinner. .. versionadded:: 0.7.0 """ snake_spinner = cycle(['⠋', '⠙', '⠸', '⠴', '⠦', '⠇']) """ :func:`itertools.cycle` of braille characters to use as a loading spinner which looks like a snake. .. versionadded:: 1.1.0 """ def hide_cursor() -> None: """ Hide the cursor. To show it again use :func:`~.show_cursor`, or use the :func:`~.hidden_cursor` context manager. .. versionadded:: 0.7.0 """ click.echo( terminal_colours.Cursor.HIDE(), nl=False, color=terminal_colours.resolve_color_default(), ) def show_cursor() -> None: """ Show the cursor. .. seealso:: The :func:`~.hidden_cursor` context manager. .. versionadded:: 0.7.0 """ click.echo( terminal_colours.Cursor.SHOW(), nl=False, color=terminal_colours.resolve_color_default(), ) @contextlib.contextmanager def hidden_cursor() -> Iterator: """ Context manager to hide the cursor for the scope of the ``with`` block. .. versionadded:: 0.7.0 .. versionchanged:: 0.9.0 Moved to :mod:`consolekit.utils`. """ try: hide_cursor() yield finally: show_cursor() @lru_cache(1) def _pycharm_terminal() -> bool: try: # 3rd party import psutil # type: ignore[import] # nodep parent_process = psutil.Process(os.getppid()) grandparent_process = psutil.Process(parent_process.ppid()) great_grandparent_process = psutil.Process(grandparent_process.ppid()) great_grandparent_name = great_grandparent_process.name() #: TODO: pycharm on Windows and macOS return great_grandparent_name == "pycharm.sh" except Exception: # pragma: no cover return False class TerminalRenderer(BaseRenderer): """ Mistletoe markdown renderer for terminals. Tested in Gnome Terminal and Terminator (both libVTE-based), and PyCharm. libVTE has the best support. PyCharm's support for italics and strikethrough is poor. Support on Windows is, as expected, poor. Not tested on other terminals, but contributions are welcome to improve support. .. versionadded:: 0.8.0 """ def render_strong(self, token: span_token.Strong) -> str: """ Render strong (``**strong**``). :param token: The token to render. """ return terminal_colours.Style.BRIGHT(self.render_inner(token)) def render_emphasis(self, token: span_token.Emphasis) -> str: """ Render emphasis (``*emphasis*``). :param token: The token to render. """ if int(os.environ.get("PYCHARM_HOSTED", 0)): # Pycharm terminal doesn't support italic escape return SANS_SERIF_ITALIC_LETTERS(self.render_inner(token)) return ''.join([ terminal_colours.code_to_chars(3), self.render_inner(token), terminal_colours.code_to_chars(23), ]) def render_inline_code(self, token: span_token.InlineCode) -> str: r""" Render inline code (:inline-code:`code`). :param token: The token to render. """ # TODO: A better implementation return f"{self.render_inner(token)!r}" def render_strikethrough(self, token: span_token.Strikethrough) -> str: """ Render strikethrough (``~~strikethrough~~``). :param token: The token to render. """ if int(os.environ.get("PYCHARM_HOSTED", 0)) or _pycharm_terminal(): # Pycharm terminal doesn't support strikethrough return self.render_inner(token) return ''.join([f'{char}\u0336' for char in self.render_inner(token)]) def render_paragraph(self, token: block_token.Paragraph) -> str: """ Render a paragraph. :param token: The token to render. """ return f'\n{self.render_inner(token)}\n' _in_ordered_list: bool = False _ol_number: int = 0 def render_list(self, token: block_token.List) -> str: """ Render a markdown list. :param token: The token to render. """ self._in_ordered_list = token.start is not None if self._in_ordered_list: self._ol_number = 0 return self.render_inner(token) + '\n' def render_list_item(self, token: block_token.ListItem) -> str: """ Render a markdown list item. :param token: """ if self._in_ordered_list: self._ol_number += 1 return f" {self._ol_number}. {self.render_inner(token).lstrip()}" else: return f" * {self.render_inner(token).lstrip()}" @staticmethod def render_line_break(token) -> str: # noqa: MAN001 """ Render a line break in a multiline paragraph. :param token: """ return ' ' def render(self, token) -> str: # noqa: MAN001 """ Render the given token for display in a terminal. :param token: """ return super().render(token).replace("\n\n\n", "\n\n") def long_echo( text: Union[str, StringList, Iterable[str]], use_pager: Optional[bool] = None, colour: ColourTrilean = None ) -> None: """ Echo ``text`` to the terminal, optionally via a pager. .. versionadded:: 1.2.0 :param text: :param use_pager: If :py:obj:`True`, forces the use of the pager. If :py:obj:`False` the pager is never used. If :py:obj:`None` the pager is used if `sys.stdout`` is a TTY and the number of lines is less than the terminal height. :param colour: Whether to use coloured output. Default auto-detect. :no-default colour: .. tip:: Allow the user to control the value of ``use_pager`` with the :func:`no_pager_option` decorator. .. latex:clearpage:: """ if isinstance(text, str): text = StringList(text.split('\n')) elif not isinstance(text, StringList): text = StringList(text) if use_pager is None: use_pager = True if shutil.get_terminal_size().lines >= len(text): # Don't use pager if fewer lines than terminal height use_pager = False if not sys.stdout.isatty(): use_pager = False if use_pager: return click.echo_via_pager(str(text), color=colour) else: return click.echo(str(text), color=colour) consolekit-1.7.1/consolekit/versions.py000066400000000000000000000074751465042170600203100ustar00rootroot00000000000000#!/usr/bin/env python3 # # versions.py """ Tool to get software versions. .. versionadded:: 1.6.0 """ # # Copyright © 2023 Dominic Davis-Foster # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE # OR OTHER DEALINGS IN THE SOFTWARE. # # stdlib import platform import sys import textwrap from typing import Any, Callable, Iterable, Mapping, Union # 3rd party import click from domdf_python_tools.compat import importlib_metadata from domdf_python_tools.stringlist import StringList from domdf_python_tools.words import LF __all__ = ("get_formatted_versions", "get_version_callback") def get_formatted_versions( dependencies: Union[Iterable[str], Mapping[str, str]] = (), show_python: bool = True, show_platform: bool = True, ) -> StringList: """ Return the versions of software dependencies, one per line. :param dependencies: Either a list of dependency names, or a mapping of dependency name to a more human-readable form. :param show_python: :param show_platform: """ versions = StringList() if not isinstance(dependencies, Mapping): dependencies = {d: d for d in dependencies} for dependency_name, display_name in dependencies.items(): dep_version = importlib_metadata.version(dependency_name) versions.append(f"{display_name}: {dep_version}") if show_python: versions.append(f"Python: {sys.version.replace(LF, ' ')}") if show_platform: versions.append(' '.join(platform.system_alias(platform.system(), platform.release(), platform.version()))) return versions def get_version_callback( tool_version: str, tool_name: str, dependencies: Union[Iterable[str], Mapping[str, str]] = (), ) -> Callable[[click.Context, click.Option, int], Any]: """ Creates a callback for :class:`~.version_option`. With each ``--version`` argument the callback displays the package version, then adds the python version, and finally adds dependency versions. :param tool_version: The version of the tool to show the version of. :param tool_name: The name of the tool to show the version of. :param dependencies: Either a list of dependency names, or a mapping of dependency name to a more human-readable form. """ def version_callback(ctx: click.Context, param: click.Option, value: int) -> None: """ Callback for displaying the package version (and optionally the Python runtime). """ if not value or ctx.resilient_parsing: return if value > 2: versions = textwrap.indent( get_formatted_versions(dependencies), # type: ignore[arg-type] " ", ) click.echo(tool_name) click.echo(f" Version: {tool_version}") click.echo(versions.rstrip()) elif value > 1: python_version = sys.version.replace('\n', ' ') click.echo(f"{tool_name} version {tool_version}, Python {python_version}") else: click.echo(f"{tool_name} version {tool_version}") ctx.exit() return version_callback consolekit-1.7.1/doc-source/000077500000000000000000000000001465042170600157425ustar00rootroot00000000000000consolekit-1.7.1/doc-source/404.rst000066400000000000000000000003271465042170600170050ustar00rootroot00000000000000:orphan: =============== 404 =============== We looked everywhere but we couldn't find that page! .. image:: not-found.png :align: center Try using the links in the sidebar to find what you are looking for. consolekit-1.7.1/doc-source/Source.rst000066400000000000000000000025551465042170600177430ustar00rootroot00000000000000========================= Downloading source code ========================= The ``consolekit`` source code is available on GitHub, and can be accessed from the following URL: https://github.com/domdfcoding/consolekit If you have ``git`` installed, you can clone the repository with the following command: .. prompt:: bash git clone https://github.com/domdfcoding/consolekit .. parsed-literal:: Cloning into 'consolekit'... remote: Enumerating objects: 47, done. remote: Counting objects: 100% (47/47), done. remote: Compressing objects: 100% (41/41), done. remote: Total 173 (delta 16), reused 17 (delta 6), pack-reused 126 Receiving objects: 100% (173/173), 126.56 KiB | 678.00 KiB/s, done. Resolving deltas: 100% (66/66), done. | Alternatively, the code can be downloaded in a 'zip' file by clicking: | :guilabel:`Clone or download` --> :guilabel:`Download Zip` .. figure:: git_download.png :alt: Downloading a 'zip' file of the source code. Downloading a 'zip' file of the source code Building from source ----------------------- The recommended way to build ``consolekit`` is to use `tox `_: .. prompt:: bash tox -e build The source and wheel distributions will be in the directory ``dist``. If you wish, you may also use `pep517.build `_ or another :pep:`517`-compatible build tool. consolekit-1.7.1/doc-source/_static/000077500000000000000000000000001465042170600173705ustar00rootroot00000000000000consolekit-1.7.1/doc-source/_static/style.css000066400000000000000000000001571465042170600212450ustar00rootroot00000000000000/* This file is managed by 'repo_helper'. Don't edit it directly. */ .longtable.autosummary { width: 100%; } consolekit-1.7.1/doc-source/_templates/000077500000000000000000000000001465042170600200775ustar00rootroot00000000000000consolekit-1.7.1/doc-source/_templates/layout.html000066400000000000000000000003441465042170600223030ustar00rootroot00000000000000 {% extends "!layout.html" %} {% block extrahead %} {% endblock %} consolekit-1.7.1/doc-source/api/000077500000000000000000000000001465042170600165135ustar00rootroot00000000000000consolekit-1.7.1/doc-source/api/commands.rst000066400000000000000000000024371465042170600210540ustar00rootroot00000000000000============================= :mod:`consolekit.commands` ============================= .. autosummary-widths:: 49/100 .. automodule:: consolekit.commands :no-members: :autosummary-members: .. currentmodule:: consolekit.commands .. latex:vspace:: -10px .. autoclass:: ContextInheritingGroup .. class:: MarkdownHelpCommand MarkdownHelpGroup Bases: :class:`~.MarkdownHelpMixin` Subclasses of :class:`click.Command` and :class:`click.Group` which treat the help text as markdown and print a rendered representation. Tested in Gnome Terminal and Terminator (both libVTE-based), and PyCharm. libVTE has the best support. PyCharm's support for italics and strikethrough is poor. Support on Windows is, as expected, poor. Not tested on other terminals, but contributions are welcome to improve support. .. versionadded:: 0.8.0 .. automethod:: MarkdownHelpCommand.parse_args .. autoclass:: consolekit.commands.MarkdownHelpMixin :no-autosummary: .. class:: RawHelpCommand RawHelpGroup Bases: :class:`~.RawHelpMixin` Subclasses of :class:`click.Command` and :class:`click.Group` which leave the help text unformatted. .. versionadded:: 0.8.0 .. autoclass:: consolekit.commands.RawHelpMixin :no-autosummary: .. autoclass:: consolekit.commands.SuggestionGroup :no-autosummary: consolekit-1.7.1/doc-source/api/consolekit.rst000066400000000000000000000002411465042170600214140ustar00rootroot00000000000000======================== :mod:`consolekit` ======================== .. autosummary-widths:: 5/16 .. automodule:: consolekit :exclude-members: SuggestionGroup consolekit-1.7.1/doc-source/api/input.rst000066400000000000000000000002111465042170600203760ustar00rootroot00000000000000======================== :mod:`consolekit.input` ======================== .. autosummary-widths:: 7/16 .. automodule:: consolekit.input consolekit-1.7.1/doc-source/api/options.rst000066400000000000000000000001641465042170600207410ustar00rootroot00000000000000========================== :mod:`consolekit.options` ========================== .. automodule:: consolekit.options consolekit-1.7.1/doc-source/api/terminal_colours.rst000066400000000000000000000003211465042170600226220ustar00rootroot00000000000000==================================== :mod:`consolekit.terminal_colours` ==================================== .. autosummary-widths:: 6/16 .. automodule:: consolekit.terminal_colours :member-order: bysource consolekit-1.7.1/doc-source/api/testing.rst000066400000000000000000000001641465042170600207230ustar00rootroot00000000000000========================== :mod:`consolekit.testing` ========================== .. automodule:: consolekit.testing consolekit-1.7.1/doc-source/api/tracebacks.rst000066400000000000000000000002341465042170600213460ustar00rootroot00000000000000=============================== :mod:`consolekit.tracebacks` =============================== .. latex:vspace:: -10px .. automodule:: consolekit.tracebacks consolekit-1.7.1/doc-source/api/utils.rst000066400000000000000000000001541465042170600204050ustar00rootroot00000000000000======================== :mod:`consolekit.utils` ======================== .. automodule:: consolekit.utils consolekit-1.7.1/doc-source/api/versions.rst000066400000000000000000000001741465042170600211170ustar00rootroot00000000000000============================= :mod:`consolekit.versions` ============================= .. automodule:: consolekit.versions consolekit-1.7.1/doc-source/conf.py000066400000000000000000000055461465042170600172530ustar00rootroot00000000000000#!/usr/bin/env python3 # This file is managed by 'repo_helper'. Don't edit it directly. # stdlib import os import re import sys # 3rd party from sphinx_pyproject import SphinxConfig sys.path.append('.') config = SphinxConfig(globalns=globals()) project = config["project"] author = config["author"] documentation_summary = config.description github_url = "https://github.com/{github_username}/{github_repository}".format_map(config) rst_prolog = f""".. |pkgname| replace:: consolekit .. |pkgname2| replace:: ``consolekit`` .. |browse_github| replace:: `Browse the GitHub Repository <{github_url}>`__ """ slug = re.sub(r'\W+', '-', project.lower()) release = version = config.version sphinx_builder = os.environ.get("SPHINX_BUILDER", "html").lower() todo_include_todos = int(os.environ.get("SHOW_TODOS", 0)) and sphinx_builder != "latex" intersphinx_mapping = { "python": ("https://docs.python.org/3/", None), "sphinx": ("https://www.sphinx-doc.org/en/stable/", None), } html_theme_options = {"logo_only": False} html_context = { "display_github": True, "github_user": "domdfcoding", "github_repo": "consolekit", "github_version": "master", "conf_py_path": "/doc-source/", } htmlhelp_basename = slug latex_documents = [("index", f'{slug}.tex', project, author, "manual")] man_pages = [("index", slug, project, [author], 1)] texinfo_documents = [("index", slug, project, author, slug, project, "Miscellaneous")] toctree_plus_types = set(config["toctree_plus_types"]) autodoc_default_options = { "members": None, # Include all members (methods). "special-members": None, "autosummary": None, "show-inheritance": None, "exclude-members": ','.join(config["autodoc_exclude_members"]), } latex_elements = { "printindex": "\\begin{flushleft}\n\\printindex\n\\end{flushleft}", "tableofcontents": "\\pdfbookmark[0]{\\contentsname}{toc}\\sphinxtableofcontents", } # Fix for pathlib issue with sphinxemoji on Python 3.9 and Sphinx 4.x def copy_asset_files(app, exc): # 3rd party from domdf_python_tools.compat import importlib_resources from sphinx.util.fileutil import copy_asset if exc: return asset_files = ["twemoji.js", "twemoji.css"] for path in asset_files: path_str = os.fspath(importlib_resources.files("sphinxemoji") / path) copy_asset(path_str, os.path.join(app.outdir, "_static")) def setup(app): # 3rd party from sphinx_toolbox.latex import better_header_layout from sphinxemoji import sphinxemoji app.connect("config-inited", lambda app, config: better_header_layout(config)) app.connect("build-finished", copy_asset_files) app.add_js_file("https://unpkg.com/twemoji@latest/dist/twemoji.min.js") app.add_js_file("twemoji.js") app.add_css_file("twemoji.css") app.add_transform(sphinxemoji.EmojiSubstitutions) toctree_plus_types.add("fixture") latex_elements["preamble"] = "\\usepackage{multicol}" needspace_amount = r"5\baselineskip" consolekit-1.7.1/doc-source/contributing.rst000066400000000000000000000023771465042170600212140ustar00rootroot00000000000000Overview --------- .. This file based on https://github.com/PyGithub/PyGithub/blob/master/CONTRIBUTING.md ``consolekit`` uses `tox `_ to automate testing and packaging, and `pre-commit `_ to maintain code quality. Install ``pre-commit`` with ``pip`` and install the git hook: .. prompt:: bash python -m pip install pre-commit pre-commit install Coding style -------------- `formate `_ is used for code formatting. It can be run manually via ``pre-commit``: .. prompt:: bash pre-commit run formate -a Or, to run the complete autoformatting suite: .. prompt:: bash pre-commit run -a Automated tests ------------------- Tests are run with ``tox`` and ``pytest``. To run tests for a specific Python version, such as Python 3.6: .. prompt:: bash tox -e py36 To run tests for all Python versions, simply run: .. prompt:: bash tox Type Annotations ------------------- Type annotations are checked using ``mypy``. Run ``mypy`` using ``tox``: .. prompt:: bash tox -e mypy Build documentation locally ------------------------------ The documentation is powered by Sphinx. A local copy of the documentation can be built with ``tox``: .. prompt:: bash tox -e docs consolekit-1.7.1/doc-source/docs_needspace.py000066400000000000000000000024471465042170600212620ustar00rootroot00000000000000# 3rd party from domdf_python_tools.stringlist import StringList from sphinx import addnodes from sphinx.application import Sphinx # nodep from sphinx.config import Config # nodep from sphinx.writers.latex import LaTeXTranslator from sphinxcontrib import toctree_plus def visit_desc(translator: LaTeXTranslator, node: addnodes.desc) -> None: """ Visit an :class:`addnodes.desc` node and add a custom table of contents label for the item, if required. .. versionadded:: 0.3.0 :param translator: :param node: """ translator.body.append(r"\needspace{5\baselineskip}") toctree_plus.visit_desc(translator, node) def configure(app: Sphinx, config: Config): """ Configure Sphinx Extension. :param app: The Sphinx application. :param config: """ latex_elements = getattr(config, "latex_elements", {}) latex_extrapackages = StringList(latex_elements.get("extrapackages", '')) latex_extrapackages.append(r"\usepackage{needspace}") latex_elements["extrapackages"] = str(latex_extrapackages) config.latex_elements = latex_elements def setup(app: Sphinx): """ Setup Sphinx Extension. :param app: The Sphinx application. """ app.connect("config-inited", configure) app.add_node(addnodes.desc, latex=(visit_desc, toctree_plus.depart_desc), override=True) return {"parallel_read_safe": True} consolekit-1.7.1/doc-source/docutils.conf000066400000000000000000000000501465042170600204320ustar00rootroot00000000000000[restructuredtext parser] tab_width = 4 consolekit-1.7.1/doc-source/git_download.png000066400000000000000000000642761465042170600211410ustar00rootroot00000000000000PNG  IHDRnvgAMA a cHRMz&u0`:pQ<bKGDgIDATx]T^~v%kR~"EC[)j#TxXxVJRZ`- ɀ_L2OU__4u񏘪6=am+ vlc#Vrv2& ܭ>O.ݿkC֜")6 YZ ۭ9ʌ\e[}`kNB 愥??G69rW!kOyb¦Xst##еC y]~;Q/$ ׽Z?$oE9~_}8o' xWv鍳z"' ۾\*]EOn3%H溷=AK(OOҼ{N_/ݨ8u~ ަ2"f)Y󭫕4zYUc4k ,EQ|cX+,4O.VV/. x벟*n ;Kt=s')tSZ{e񯇮kCfvtOx򛯿[nnu/"+qޟN|+D~b?u{M٘1 \BBG.̴xbղ]o~_eeE)zkxޥd?ziQ|.TSEQvn]lifguV/bM(dtwǺ'*"&gz$orRRu+'ԍ\7~xMm?:%[2 OO@NyEV=_Qp0KOkw.]yg@zoн :?igEWB7 g 㱴l x1u*=~{´7ُVOeXi{tڄQZbD}:D]䌁9iҟ4D+#6e{ M%E9oSyM-KZ?o g wsC髶V 濖ytx39Tzyk}AșD#g253Zkm/N˛gn660K"}cǪj#li}at۾*GN*p@Wj>vƥL :͉7w[}z}_U` i"nݥ>!7m2|Oj(J~k<"B0X>mԣ]/춡ܥ^*ݕw~rf7S/9t=wǫwg R}wrFzT3yWכ*&Ш׷v.Ҷ~Ӯ*+;i1_f i1a\%:ު5` NN9?O@19lNmu^bꅿN~Yݵ8b2(Ae1J1}啭~D4i]SyT/g6/x=YvT6ҿ[ëL<%\CSw=NSM$4\R{Obl74LQ悌'.L4|IwӍj7KM蠝0]{>{M_TuyƠf#r8܅43FYvKBwZċ>s`՜wkstvɐd gSBotXUdGma|LaazD!4imnScVWy'ʻI2]*]lOiת3%쀗e8s7ZEG 䵼<7< Yt?2[/8(̇Je9?Ȭi9mО3W&8G7qߺҿ՟ZM'+ ץטLlu#29qu6+g\DmT~*h]_]<ۧ 7wX: d}8e)Y(7RcGB=ق0]M2w|54Z,iWIcSl ώ;7[|uYNK$쭎a41t;Vai}x~K_7 EQ}'k_.o_.rֿf6Fa KNjR۹dm1B:?}ڥ%ES{!}k G> 7ߝ5S`_d^u]uo1}hRƨy &}VJŵ]uA:^]&/P>/7KykADYgwD]w%aoFg51SM=q].ctf&#r:9g+*ys0EQcU~RS5v"tIS@-OjCܙqĩVN'I G~2uG$[-@/6~(=(]>9ͺ^~$ z~J a깎8rͽ'˭KCdx翑kۅg8a깇N5M7:ԥm/Կ}znIKkSzŬu""4i]rrSz^c?79-BDjFOrb7z}޲}e;OcUIH'(6O>x5E+Sʆ(W%Ej.~rO\_Ǎ^ww+KN n 2,nr{q^)sKw['Nu;3p9zy9,w-=fVn *NRR\QFD'^ ucͱQAyw>F6Ͻ[uͩq5dRs1ܓ]o1"Vf\k"VB?G<|{rƈXqbߢfoV'X59c@̸|V'X6 Vf\kLXN wӭ۰hÚ!kO=PHbסkO=Dڢ km?п'ol51m@hlLXN wG@Cv? #.XӨbtrkmXSl?Z'~Z!km /H~A]#}#~w]u߬dcY{"dW@,RK}D!kmO߬His?_Q];w:?)K|xiiyb¦_s"d࿦՟y]=-wiS/!M˝^ߟה%ׯ9b^`_"vm͉5G6w[v o!|Hסe\\w(~'$IrxxX$vTT(:IWF;w,YrvH@IrC3-S6R}#0Xw!~:hdJfhhHz&V!WtCC-)`t٦7D`%177C=z-hh8j4@CzPT!dC~899ipp:/~d X MNz{pi@hhRwɾ~m1 X&MMMMM9q,/;=пvl,?A_oѳ'GơH:=1/X? {+Yz@?x[V:[೩ wU|igsGO{ĵUˏ3rF?\:UJZ)<ݞ(M:F.+Q쒫WMO1nLH\Su{UjN|6Ub-f?AN++^,ƝmMʙ˩=WFIk{0$ݸӵWʊ a`@d8I,bGx{ӧGzVu'ݛh3 C)uۖ*%N㤡HbU|D9OQ?O?wdu6OHO9r2)͑i;AwR)Ț=vuYb˵]jGwZ%g-kD~aa|V @su( mNQd5lYӧ)g EJ;\]V^Ϙ2LRT^QVg~Ͳ:[Nr?X:ז%ږ+My2JKOV6x_v']Ǿ*Y{,8uhG4RUJU^{DQm7&vjC%}N{ÎL2U;Z<4u͠1ˌlBƓ:ҿFbiA(JRz_L1X?pcnz@R*LIXum afN2| xk5w:1j'6 .eVꪹe_@DgUjťC ,bvԩrU|dƧ6)u\Cj~ق?Yg ?6m=zF`ȑJ특f~sxz6Ul?U:XړnUX}ϪTnLZZI?sdr“͠v蘻Yt`QR^FubK辺QΣ(lg%(2"6@*sk п&*eG8ȞBqLHO@u5?[BZn9[4z1<WjC%Ug׎. Z*_֓jqbUj'`#%뤊U]]3h'^!_ڵP#[(u5g`תT]qzAqOd-3;z^<؟q0f?ܿg[;С:5mTRuɶ^y0Pj]cw2<PA2>]9܉c?o~/DS5#5;-+LӃ6hP5CEQds~b١3uWjeE߱Yhu_YM?Tjyq?j-pmT3,+έ# {祬5?܊K=jRP} =yHz g]:؏Y.6CVUsGiiuW;֛kTgtV-Q@dlTdŹ{|N(bU2;ܜ]|Ԩ3{l&/w/+f~SL˧:tܛjTTX(*7ב ItLOc3FS9#G&c3CjԀFp]`r0jn@?FU#CC?h+ ?jO'Rq8.:_G&ħiW8M"-q%q?Xw,(u?"<.Y_ݪ3U^ayL^ $xr-EQd' %ye7ߚ?E 'yZOr!qp@UiMhM+f" ^Ƹ©r<=--& #E0$*Q't#?# td#6U5MX9)DZ蟢TE1""N)Ga+ga*SDVYH㋙)?8׿W[a' "eL+ܼ(JK CYRb?&)ic2OK"HveMa@Ϻd]Ւ ' )$kr4f&O?e0zЕ%ֺ$,e$[DTc"kQdֿv`R}H{{T{2]@j䍕yh?#X íGOm<g.\))t7]L'"^( bNZ 0/В-qg|?~Yer޿Rf=*9TqM$k*y"LRT^QƎbI0O@0}l!WS,@pE~f=2eBv&x61Um3%qB1vbg#StEDP^V,Sju=0M.#H<5Y=ű6#gTISo6I!jxNP YWlsE$ eWsԩJ<ׄvR6! O4gX'@CK;TFV%e37XmiJCFq8=|- {$ aBfYO~HEQ-AtC[( eWHZL猛]档ZW{AP9KX 2iE棨blG韢t !-h{ʱms]hv_hI^hit?nCJ+?c/+O H}RIYz,LҠ]6a^TUR/wNg= s5ɭQD?zoC~bŀgHQLzt78EmV&K-8ۈ]@_yVLd>ONlwԈMKѿ]޺SA.=M;J_uk{}{PZ4/?y_ϡh'0W /O@DfY,3ZއjZjn^Ճ}Kճi10$ߍ]v鷹 ¥LY_?P# 7U1 qt?@)7ĩw%Hr *>^B?CO$k…b9}H]+ Ngf"&A^q~+tyIED%J\,?+>2O( ɒC:&=[^MB-}, *:sΪx7os.@^KߧqRwG vvjci@$t[wږr]pDDO:{'uS33zX83333=Za0=O;: `4I$Y@xtEj0 R?cR{Hsss,9u{CסW I?`=z4;;,77oB+PYsssn~ܺ8~< ?xGnn%g~BeѣG?\7og~`%$gOʪʪ??9𨩽 < 5|[&r@-<^ P{B}[&ZyQ@isv.,b-vڦ>O@${kT 2?5˓>/BLz$3!_\R.a%&2Ev4)8\ jז% am=5I!|I>sAQU Ł:km-K  ĬVtIBARycIJ' N)JңVBR/"yr#(=nEO9%x>C6x"qT6xtR~er{+O~]cB/ bNxV~8OT/r?]+?YRZ( $xR.8_^!qqEY9ʳmc%g:SVZMTdk~4 ٘{|ՙ|^`R{%A~bƛme"%=YYUQ$M?K5\]V^QV~&;F(\\ O%dW1)O@VW2E.V\sׂY( A|怼0'H پ7L@K,u[A0O^d:VX( Z)U' DdaZpd,'εMďg@ӱLTR,fz.AYtVDdae~eDV2EDX~<7\ЖEMg= Z~ֿb /}۔9}~J+"WvZ]zMOq, 4j7ׂmYji͏ x!f랙M!]mӔšר Z(Q/\CѶ"%V Uz}r[e̳2r vWS/HcMS/>ʾПN||r4$uV4a}`A/CjSme5*YD.ݏW}v\w>j(do?i#SG3յ)=ՁH}_'e̓2V{c ^^9A7FSn'߼3c = dwq *eҿb&տkT63Кd'אVKj %q~aHûF:^(c cz͕@k}Fڲ?e}qϮі% ,mtUb'7Mֳiյ /筪jX\<$=\xP]_ˡ:^(ң63ˏ+1<2'/뿩Zqt\}|uu5F՞٫dC7pxSY1b^>UסDUҿMEi 48[*GyjM0H6M@gEH'R=WUoKZ8+q{Qzswwq-K% fA'MR6ik?]fhd7ތK'ɿ?w'߾xؒnvMzԌA7M'F'cCCMҿs>vsK˃ݣ(Hu ئP4 fϹj'6@sIkʫ:L֤Źvw-ok$RX\}gZ_w-/'J6X-N 7zE/C} }}ohlW[{6J`y gd|dMUx)3f.VHC7 t ^qS.ZDY/$ yV[scJrNy(/ Y"F L5*FW/7/z-XnX<$= ?2rFqxs du@ѿFIJC'ȤqS[nGJמ:# !xgM%dWTԞ8 ㉢;hx_y2JhUQmC*D ^H|~,@akyk֓/o?(F@ce5-JEkMaRLr|q.KR+|(81@HM(3U ő"B![ZP1+ qkyz8}ér)c<~gFD/~|Uo .rgJOzq$x)=٭u::U쿺 Oz}^9$<_,)U\ncZ ɋ4vpNR~008F,jw<6̹r؆pM aHTz,Ѫ*oK䏻kA*ke+der@B(DZunUy!|/,ARir~MjFGi[Keļ6On9_ M'\Rk+Sp?[$9S9x)ܮ=`O 7DX>;wu?)uAUQ+X!xU=*RoOYno ttv+ ni/1؄r^)I׉l:zQ9O >*朗8o\s_lOOwCb@vyEՕIa"B{@y;l,?B;_o=I:=Y˝dq:_'x+?/CT*F)'JtPx|P9*1&@RX jofI3_48MTk᱘ C= `?yK:%l( yK:Cѣhݞ%z[қo{z,&A?aǵ[?w6,?Vͷ& K??7IVG'877ߡct ™[ns!?>Wt tݎn@K]E&&$977˜3[K9n~?lOty ̗?<~=%IHFQLOO릦&u RRcdt@6CC?@?C?@?C?@?CCC?GC?@?9l|m(to[ W*Ԯ>2iSL3k-oڿAڄs-EQoLi >+%]Ob@??K99ZI;Qv+sz9IV-FK?GwCgMt*t<ݤXX/J/~V8i8Uc"#;akydzr 󃝫]/*lD7~Ӟg%gv;ܿvRgIr/֒ RbvRETSkuFŪ$i]mfwicTJVתCz(Vu>+U۷r+ZG4jIbIo?<*aTo=?EQ#|s{(f=RMQZsi'ۺٓIӇ%9+>sx0f!ff¥(J;isڵYV_.WKz94ܖJS}joFELc_C^vl鯝I(#|Ư#ꘃ=lSx}eS~OmL:|_~`J0U*Ul*SX;sM5_]i٬x0;n1x/t;[tiLFsV%/Cyk)jY9&7ČHFNXV}*Uo/nօI':-{MiPx-ƸjJ3joMwgO?[0Q3}SR;߾GoBˬEQQ*eB߃hnn50gl־h摏 v?5IZ˔v{_r@?FȾS]OcKjk _V(jfTyh=I'Mnۅϖ̰v?y;{6(p}rX|`r<(ʰug;s+;2ފ7`o3oOSWlxBu􏢆[%xwfO-;L;|;C,9cŵn,?5lCRcGOF6[tvs$KUtJ?OՒ.uӽ0_ʼW`)v 2 sJ+9mzӺ3'oT/)_S+l:zmgHkS{?CT_3:cD;NCCCF=420azA>uo߀AOo}僛Q?C|o0O u:ӿN/T?eI,;OaCno~%Ǐ'tSS-]Y+]?{@755  J@ H~wꡡ!VK]qu<@ VՎjZV;0pd@ ݙ[t9#JhhGGZ-- ~lیCpYnZ.@ _JN-O^4eLw~ пc+lv\>֧Bgff]=YJ׿+\6+E{⶧\%X-~{z}?9 -f}#078fDu߾C*ޞ]v0?.ܿvx?z\jc?~kzϛ?:Nd}HCt_YPq̑l#cg2l33:a?@,j Ѝn 8h bbb|О۲7o۳㣃+ر#{/׸p7voޖy[ݛeoؗy'rٛwaҡݛEdw_:mٛ~Ҝ=eo9Q/g6qr{?{t죏SkDк3J]Ǐts} yfiLMM׆TS>عy7F6>J8?)ssp޹?;;}_ۧ;7肒}⏿ͼpOvn޶s#0mܜul݇?}yNg[oyy[e~߃y3 n0vSM\?@LMwa!ϻwkMξiw殔>AihwJ`rvecb({'w;HƓ>ع#jwn ?M#V{S$NvJ%eo0wv\`7vSWZ/|][l8>ؕZxeJ`oܓkeJ}uJ3%}+>-gLσؙu.ٛuCgzBY$zz]w-qvSA]n%_4ɮTɮTɮ4k|Cs8U+T#K|R"huobffff׏$Rصd9-J7{ەџfffffz`W?+wv,adV}^Gwp{i0#5z䃆/reiꇟ_wtܬIii:DDaiR%Rx '$vz?OH?oB}LDvݷ{wJ]z}累$R?*o#hX'Jb+p?~ `o[6kklPL>Vپ;1g(߾}/Gl0p[+p#M;voUޝpvhVVKrͷZvJHԏC閝ޙ=-i/CVBah\ϡF@_@ lc8dϨ拷o߳cἏҷŕ9[oe時l߽l߱{[>*>T6gwo4.Z^d|U?͍v69vc?uUୟ+|Yt~^M񉪫j/?vqƿ2Nܝeu>쳌=-Y>:qt7V;T5לh8k X67ʖmsNn˗mvSc3qV8SOLп- `1}쿷fUÝ>mmY2ǵM?-g+=?0׿ݠ67,=F/ߟ[5Suk>ys癙>x!c8[f,7&>(`yjf10=x unuMx~C߅Ѡ?9P?Zd?峁,j??_:/| %tEXtdate:create2020-05-24T20:00:42+00:00v%tEXtdate:modify2020-05-24T20:00:42+00:00TtEXtSoftwareShutterc IENDB`consolekit-1.7.1/doc-source/index.rst000066400000000000000000000102501465042170600176010ustar00rootroot00000000000000########### consolekit ########### .. start short_desc .. documentation-summary:: :meta: .. end short_desc .. start shields .. only:: html .. list-table:: :stub-columns: 1 :widths: 10 90 * - Docs - |docs| |docs_check| * - Tests - |actions_linux| |actions_windows| |actions_macos| |coveralls| * - PyPI - |pypi-version| |supported-versions| |supported-implementations| |wheel| * - Anaconda - |conda-version| |conda-platform| * - Activity - |commits-latest| |commits-since| |maintained| |pypi-downloads| * - QA - |codefactor| |actions_flake8| |actions_mypy| * - Other - |license| |language| |requires| .. |docs| rtfd-shield:: :project: consolekit :alt: Documentation Build Status .. |docs_check| actions-shield:: :workflow: Docs Check :alt: Docs Check Status .. |actions_linux| actions-shield:: :workflow: Linux :alt: Linux Test Status .. |actions_windows| actions-shield:: :workflow: Windows :alt: Windows Test Status .. |actions_macos| actions-shield:: :workflow: macOS :alt: macOS Test Status .. |actions_flake8| actions-shield:: :workflow: Flake8 :alt: Flake8 Status .. |actions_mypy| actions-shield:: :workflow: mypy :alt: mypy status .. |requires| image:: https://dependency-dash.repo-helper.uk/github/domdfcoding/consolekit/badge.svg :target: https://dependency-dash.repo-helper.uk/github/domdfcoding/consolekit/ :alt: Requirements Status .. |coveralls| coveralls-shield:: :alt: Coverage .. |codefactor| codefactor-shield:: :alt: CodeFactor Grade .. |pypi-version| pypi-shield:: :project: consolekit :version: :alt: PyPI - Package Version .. |supported-versions| pypi-shield:: :project: consolekit :py-versions: :alt: PyPI - Supported Python Versions .. |supported-implementations| pypi-shield:: :project: consolekit :implementations: :alt: PyPI - Supported Implementations .. |wheel| pypi-shield:: :project: consolekit :wheel: :alt: PyPI - Wheel .. |conda-version| image:: https://img.shields.io/conda/v/domdfcoding/consolekit?logo=anaconda :target: https://anaconda.org/domdfcoding/consolekit :alt: Conda - Package Version .. |conda-platform| image:: https://img.shields.io/conda/pn/domdfcoding/consolekit?label=conda%7Cplatform :target: https://anaconda.org/domdfcoding/consolekit :alt: Conda - Platform .. |license| github-shield:: :license: :alt: License .. |language| github-shield:: :top-language: :alt: GitHub top language .. |commits-since| github-shield:: :commits-since: v1.7.1 :alt: GitHub commits since tagged version .. |commits-latest| github-shield:: :last-commit: :alt: GitHub last commit .. |maintained| maintained-shield:: 2024 :alt: Maintenance .. |pypi-downloads| pypi-shield:: :project: consolekit :downloads: month :alt: PyPI - Downloads .. end shields Installation --------------- .. start installation .. installation:: consolekit :pypi: :github: :anaconda: :conda-channels: conda-forge, domdfcoding .. end installation .. only:: latex .. transition:: Additionally, for better support in terminals, install `psutil `_ by specifying the ``terminals`` extra: .. prompt:: bash python -m pip install consolekit[terminals] or, if you installed ``consolekit`` through conda: .. prompt:: bash conda install -c conda-forge psutil Highlights --------------- .. latex:vspace:: -20px .. api-highlights:: :module: consolekit :colours: blue,green,red,orange .commands.MarkdownHelpCommand .commands.SuggestionGroup .input.choice .options.auto_default_option .. .options.flag_option .. .tracebacks.TracebackHandler .. .utils.coloured_diff .. .utils.hidden_cursor Contents ------------ .. html-section:: .. toctree:: :hidden: Home .. toctree:: :maxdepth: 3 :glob: api/consolekit api/* .. only:: html .. toctree:: :maxdepth: 3 :caption: Contributing contributing Source license .. sidebar-links:: :caption: Links :github: :pypi: consolekit .. start links .. only:: html View the :ref:`Function Index ` or browse the `Source Code <_modules/index.html>`__. :github:repo:`Browse the GitHub Repository ` .. end links consolekit-1.7.1/doc-source/latex_transition.py000066400000000000000000000064061465042170600217110ustar00rootroot00000000000000# 3rd party from docutils import nodes from docutils.transforms.misc import Transitions from sphinx import addnodes from sphinx.application import Sphinx from sphinx.config import Config from sphinx.util.docutils import SphinxDirective, SphinxRole from sphinx.util.nodes import process_only_nodes from sphinx.writers.latex import LaTeXTranslator class TransitionTransform(Transitions): default_priority = Transitions.default_priority - 10 def visit_transition(self, node): index = node.parent.index(node) error = None if ( index == 0 or isinstance(node.parent[0], nodes.title) and (index == 1 or isinstance(node.parent[1], nodes.subtitle) and index == 2) ): if isinstance(node.parent, (nodes.document, nodes.section)): error = self.document.reporter.error( "Document or section may not begin with a transition.", source=node.source, line=node.line, ) elif isinstance(node.parent[index - 1], nodes.transition): error = self.document.reporter.error( 'At least one body element must separate transitions; ' 'adjacent transitions are not allowed.', source=node.source, line=node.line ) if error: # Insert before node and update index. node.parent.insert(index, error) index += 1 assert index < len(node.parent) # skipcq if index != len(node.parent) - 1: # No need to move the node. return # Node behind which the transition is to be moved. sibling = node # While sibling is the last node of its parent. while index == len(sibling.parent) - 1: sibling = sibling.parent # If sibling is the whole document (i.e. it has no parent). if sibling.parent is None: # Transition at the end of document. Do not move the # transition up, and place an error behind. error = self.document.reporter.error("Document may not end with a transition.", line=node.line) node.parent.insert(node.parent.index(node) + 1, error) return index = sibling.parent.index(sibling) # Remove the original transition node. node.parent.remove(node) # Insert the transition after the sibling. sibling.parent.insert(index + 1, node) class TransitionTransform(Transitions): default_priority = Transitions.default_priority - 10 def visit_transition(self, node): if isinstance(node.parent, addnodes.only): process_only_nodes( node.parent.parent, tags=self.document.settings.env.app.builder.tags, ) class TransitionDirective(SphinxDirective): def run(self): return [nodes.transition()] def depart_desc_annotation(translator: LaTeXTranslator, node: addnodes.desc_annotation) -> None: translator.body.append("}}") parent = node.parent grandparent = parent.parent if len(grandparent) > 1: aunt = grandparent[grandparent.index(parent) + 1] if isinstance(parent, addnodes.desc_signature) and isinstance(aunt, addnodes.desc_signature): translator.body.append(r"\vspace{5px}") class InlineRole(SphinxRole): def run(self): return [nodes.literal('', f"`{self.text}`")], [] def setup(app: Sphinx): app.add_directive("transition", TransitionDirective) app.add_transform(TransitionTransform) app.add_node( addnodes.desc_annotation, latex=(LaTeXTranslator.visit_desc_annotation, depart_desc_annotation), override=True ) app.add_role("inline-code", InlineRole()) consolekit-1.7.1/doc-source/license.rst000066400000000000000000000002161465042170600201150ustar00rootroot00000000000000========= License ========= ``consolekit`` is licensed under the :choosealicense:`MIT` .. license-info:: MIT .. license:: :py: consolekit consolekit-1.7.1/doc-source/not-found.png000066400000000000000000001352371465042170600203740ustar00rootroot00000000000000PNG  IHDR\rf'zTXtRaw profile type exifxڭi7sp`?C)J͈M*3wÃ__S4Kk{q3_Ow>?h]?3}$ׅ}>9"~|? K~\ꌟo)_S{~7rcvU)ƓBYA.u|KH ?nO7ui~^oQ?A(??|pv;_vȕ_=exd{[Ww2?"8/?B\rab9",{\D(Wv2"q.}-}n;X-_ޥ- ޾\O^E@[y?6ٸ?r+8'^W[g5c }44XyL9N"JEƜREJ=-kԷ&QRM4V΅iȡQRɥZZ1Wz5\KUhVZmYmXlŪ536z ,֭>Ft\kwfiYfms,gUV]mk&vm{Hq)v3.vͷz۵׿ZZ|]ڷKIQ̈X́7EsT3ߣ,Ȣظ1BO#r7W9D'Q"BOT??6\!Ru\[ 5pmv[]`c-[s%YeS@E"t_n1˗YX:@[ -a39rA ;Ni|Ș8)v n;+ẳZXeOn mݕܜNf< +Zxeo m7͋ mQZllbvPՕMrpɝvG;7xa<˧0oUAkSl7wbiu?qu8 I];^$N7-4uǽ~lM'"g;jxcz\Rq7sʙmkMccCڷⵉerW$My5lv<~iqJ?^Ch G"ms3;';+}%|✠?˗:UQqsYi`߈wA/&u)KD>@髺`8 ,-4"X՗I kZ wQQ"apR=i&( D uM %+][ `CvZn(&_p91tC D45[Ko0JJA:KArHkl]]K,`0J5 #ut!50Ie3¨o2jj@yAeM̍<]=8C#',ԔͲ39KjS9~7~pB8Mfz441*'3$:D*\Ҥ[m98eAP}*DDgPX@wqEE6D!%>ˁaPFzHd--CZd^|R!1}^$@u@c5G ;UlR4ãS`w(}ϭ"+7&zdGRr&uo&㣜LqIAL CwLM5$JSm~k2R"Z\Ky~-6 Qx'-aO ޥ>dl=wL $,9w}ٮ$D< cP hضc"o +8fPb6PGQT.D|(p;W*F-`vC^0$s(r=H(uX mr{U+`z+,{?X|! FFvE<,*Ȧb:L>|: |0::]asS!%Z`6И cW!K=yj% Hp]U =@hAסÅ-~UEGU95qCM.79]dna%2uYяcb@B2+,~U)C7!rgNs :"P@Xw4Rs< ϋIO‚앛)^8>APGJ݀x\9$¬F(Ķ`Xz8P(dVJRcB3K=)9/ J !mEq`U$1-W?:`i"蜉nMBHjJy ѽpAmpQ :OnLn@hlɦB] tL@f#P#؆@7ʹRD cXjq“Zы?/u`{SCg(l|s5Q^M蓪C *;e t>0?zF=u; I5^6|퍩zvhrd+ω]'Q3rI3q@|JX+Pe&u.7XIdK@2]`A[vȳB^aM?IDw w`YXUVRsd4a+,Y2j6'Rұs(^Q})V PKKBS͘ig>`>^ LF6LH,!)ܒ`RVTJĤ#cG1H,. d4 0Mr1L`&0j  (b~wc&O!SPS'SʞUe!J/ցCpC#t[ 7` Xe.Pˡp#+ 1N+j(U&D}?إP1#@ub_)&|/A&I@ wP@HVսE ƞ &@,Sj2B x Ԑ;.wQp d̚>2kx03Fm ߻!>f5F T VhsRx\c].VP Ջp}o?hP ` "\hlU>|C+a>^[D(Nl-=9y1~?6BRїμ nCe\Ed@e}o)6$ N]#R0cJ5v4Dx;=& $n+-J2)oNnIOjsQV*O پFe颣?l @A%2o7 _OOj9CbP@U}kgx?t5חP dƀ#WlT %)le@41{:mAR W9Bj#dދ;Ż'{z:V$|TP ]HqEꟍ 8<6 oH8.`Ȫv3aQHq؏0u!Dē;! $Ux+LT(a|($[诮sSN'6 utGCOI|*q.G # ZÖe@ XiE2o8p.`$ɱP$}%8W'ǵErqYL7 {Ar~>RujR=|Xod ^'o]햬ViLI!/L|%١N+x.f(= nC'zJ0|()l.0:V'Vχ-@Kݬu@Eg[u0V AYƈR5jՌb)yg&ubFH-x%$7K (HM{Rk5 vV 9AFR`Yt$jաKӔH1'/7rCF6?BA0rXæ1K)D~՝@$x`~b$u4 ,r-Td"z؀a/#Qi;o ^w\S.|8VPg7BѸl}^ CVCl!`KL±ItSE^Q4{{HcSk6hӴ,摽TX3!,,f%h8H]é> @ WJIp7%})ʄq'H ZhS ~b-#SPV*b:#ʝ(p;~FԆ w.OڄijFv B^u%fE|5ƜΦ6u"1^Pf-JIƨ)c՝O"t#+j06+@U{!H@$2[}%nT~O' ̡̹ut,; P5V$lל¶wO /ҔJuXܭWC|bB!9`C}32_1Xċ یEJpB[BNXuu2jDkAIXu-OI:V )|mMЬemHu#܅FvM)#Ө0,S u^h*:>P 9fk`hI ٗF6VMhס,+,WǓ[PT-0]w{uЗ5=;n跇bGٯI/piR4XM~Ъ|QVm͈4r}ZY^OEv }#-`܏,jٽ^z+0!L># 4u*͉إFxSfkB5#([-bW#Vק{6\-$IsL۷KI9NQ) /Xːx'SZY*!Nt`n҉N0̐cw>%2pXt DJ(V$ORpvH%Z$b$χbׇp`MA]ojF2KT΄ѼS٣o8RY0+g`~&I1,P`eQiXt:SjLguIy؂z&*t+%BɢTnFj#X-kZP6V6:IKD>z5u]<w)gB>Az7#}H:ʒ`P H^I:-z cjj-G=j(D `*-cUY:$Ϙ !0buDsDP{F+`~o󕭓&Pp ]Bra_`C 1HkZ8iv7!4}ʾRE-]6 WEgic7R%DNs:$AՁ+HT y" HS=P&p> ojabȠN(J@ڡMġcj{#~ mEG@/ULP2']vqjlaLrP/'v;X< jq q#(%Xs",V1pT^0zN*ȼ :1E畝@LuA.[L!rC3=@] n,ʕ@>#ܪEӃ [k1X1 Ⰻ}4|S䁘,N7W;JUи%&?pdl Z}ǬB" k|9_AX|e`=%n¶8(b܃1^qh:u2UQ&=:6tB8( R騤hX^#U5U0`:Sf}G(F&&k hQD;9p;?utUa/BNf^М zaM,HL6LA]V\}d2N)n,d,`\UxE%VQEѠ2F>W֢8*s@Gױi2 RU(advAQPax8 i"8AԮDlR!5WCkhbjx"gf$8:gdDvқ(6I\ ,Y̽5e 404TƣŖ'ٽC+sWHHD6J뱌DjۓSQ7I@ PaCyw՛:#5% ԯHBSXu5_PAʛ|5 \WOد]˧ϟp*[uj_XG2u>,g0(rOHI{еqޠ$8˵@4XQFHex{seМK}@I(a@Q󱲋겷4=lF3mמ3)uNg_T=z5x14VHrbYK33՗@8;:7pnGXj j+鎻 s(֐I[7 C7ҥ0Xwi*1H۔m_sE: )G@U ۘIOćmL`FN *Sj|7Zlb/Au|ޱ[a'**a7|'lhYPzNO}lDL~=^IH< Kܱ.Uk1u^b)P!l v6k^{ &Ltҿyb㓵w"{zQTBPtH'TMՉc4]uՈ;ꑰ <6i\R )WVɖUJȦHagu { ͋ă\n\N8Jx V XI]'yA0#P2MB'H6u z 0gD"Y ,hFk иyoP^,BU ܗb6Fjv_̦Uy`>zJQchbXt`*TV$?Q6o*T2QhV+38s;2c«Џ8FӥIMBa~.,0v}}l53d+ny>0"ŘX^w")@37cm(PzL-Ws]r[_մAe=d!бՃLW9AƹD=+eZk"A _yHAŅHEI!UzUc oBGɡNy`&^ +ojԳ SU^N DZP=Y׮ 6ŷ{:?8:CE;]j: =IigHNt{[J3S-CB+ >s]|a:_4x`[3zhr)~򃇬ppp`|K&Y zpU!kӱq*@#er4&GIg֍@ЂHpMBWHgE9#,K0JqF:F $f] Z,"h:ܞE旦,EFtXk _^~ |<)5gVA SQњ5 E˦ sZ71{}d꣒P؇'ǕsOކ$B1YI 0EWw^I"NE$z< ٸ;"`p&35Xdz^(X[q>- yN"-Wt V9xؿy+, YH0=daXА2u?sV٨`9.c}}Xid6VuڟœeQ'ٺPQ͂&@=!`&^_9Q'ҧ56kȅt.a!fAHҹ2Im'5/LP?zI?lR lZ]0@|h ^g-z/W#thIf!lZFm@!V6U #B]1$xԤ ?2]qeef&=O ;X)$qLtkҺ'{a$,3fI,b "Ȩ liIUBTAr`[01%E@q>.Ь;4O3p0IzŎm⺭{0dHJA\7[g뭵 C]nC`H>3~r}bKGDۗ$ pHYs  tIME#? IDATxwy6ٽ}z9G& Hjۤ&_nt/ݐ/$`'Nϗc\0QDPC]{/k?YFBسў=̼g9Yr,g9Yr,g9Yr,g9Yr,g9Yr,g9YESpף> <"h(H0MH~wNp9W`UʣWj 8$cSJ|8WYp%\{j8E/S?s(@WG?_{Ʉ! # vIFRj5T*J%eeEE4gR?𯄐o޽\yG̮GyMo(uvݍv!##hB~J):j 2 $R,$iC(%kk>`BbXbzzzގD"uI?JJtӘ з|)g?pDQ? &xraժUX|9z{{/ߦL㘞iCؽ{ZtOw /֯[Wƒ%Kz?PhX,"cbb8 ޽戌>~@he,]>4 ?(FFF@)]gO3GtX>1@G}}>JlذD'kjFJIIrEMPñ1>}lv1_rQտlX,۷cڵ D\\FZERAvqѲBF)4 r9R)LMMԩS^0?vQ#l"Hի/g\.T*T*R" "rA)"Ncff'NBvG\'np8n k֬Y342X,.o~ߖ$IZbRfggqQ.t~mppp)G_-lex셾2ÈD":RT*L&)bN._qkY~=n&E|tzy<-Cq1AV<Ν;#G,u188qQu=Wx 3"F83á9+bV?uёBObĂAP JE^oܼ:k7c@#zhoooHcH&~r9ݏcpp#vx7 -o0}݇ަ7<2 #YzdOG 7v`;z<[JoV3`mGsA[oWW^DѦVffBzñ+80^|'b)x.yIp:~CN]Rwu_RT`\ U c]=bÊ]Ov@ ݧZbrrZ 'Ncvp!pbUV;c!J!J-ju7M㉗&0^Gt,OCt8HB$I lJB)ϗB)ɕZrJB@܋U;u/^$ $ [h`rrJcccx78∠ޕoݺ7|m*/OR-f5 N/]b["<ՒL9uIzNsTs6.WKumǢs~?:;;mCRLOOX,b~~/)HeG   Em߾7p%*˘Ztӣi|y0N/NYRW[t=>.+f;+gfS}sپrX1;Kq\.l Bffffo>nD鈢xU,~7x#mf+\s&eF|;5=9U^$M<;Rkز7,Yp@^}饗ڇwgy睟ܮhpۆXs;UW6ilZhp! W︲kx_ ֝(]QDpV_L1}m/Qu !x]`|yg(.1VU5# zZk/WcSU9=-M j*BE H@ \.P(@ `w]v}kϞ=+kV.Ԟ Yǎa,[%֯}c`ew@垫z֯./${Y].TkdS_ FW"@ xݒ%[VkbHCIh[[l2fS|ero$K rd"H4!V衐uڼP( Z"7^޹s=sNOxG"h7w}m-*B:WxYn4 &}uj9gA`= hs^˽=zjR_9 :ccLR& {ck^J"4Ai߳gӎ*n4o߾}mIږzl$ ٴa٫^G%B>u'[tV_u3 h LJ vEojsA۷3p1VVqk]J \ex{!tz{㚖[tmz~Hg<ѧtJO9B4:Pz#}]qpBn `ݕxݾ`PX,<{rs|3XW 7UHUǞEB!0D/Ϟ=O8Sv7vܹK.3==ݬ$f㯼 /IiWb2^~ T"dք3O4?! DR&"gGU :3;5 $nt`T(FB\2˘qe$q8aqUJ)ժP|>mZkk+ECw֞={N:"VCCC7\f :anncDŽ}.4%6#:6w?qݒݭ6j4(,'~=z<gC(w8,N@HkdP@0/#QOpV|2ZIa]V ۵k޳g *!7`J B;;jAjc83_^ni c6Bވl ѡ(z\f#{NeĨ 0HeW`g ˽Ii@GKtbWəE Fؾ n&#rPA\,!33@#ݒ.g}&۷1cffƶ1k{NdQ@`m\U;߾dsp5U=w.ט "LL*7@0`zc7 ?r%^£KB,̑sƶzkFN+WkCCC){ؼ֭CT߿s()|mͲmmqaْ/p϶M~gb5Faԥ(_YBKH41}E[1Si_\oBЎuK@[[|rͲמ>ċ3+mG[[nNtA=r@޾};|>пYt}qw遞==b=yuʼQ6tSS1{fPA7#Mk1X3ݴ <AoumE4i^*l7?}Uo*eQj7(eo_B8??o Ӡ{-#>{.6׿uGz? 7k-[v[Bдw^Ɖ9k2[ɯ[:5%r=kB=g6`1(D_WtӅ[{nQS(F g _[~Ԯ;cmK" inϣYQp_7q,ky,2]{U$L;ƈ.'@Xg:_Ż0"Z.+O$Jo?"z?{j0ri(ۇw:"|*G}[Xb)Mvx`'? u\ٶ̄/ܺ ju̬FCwЕ:'L`Qx S1`*nU2 )`܅@*[q: Xr.NW[M AQw,PAG/S4L=CV^ I, Oe7DHc޷D=sKJD\~ zk|N} l( ZjQGtd 0l^>l8j2!lͪ%oIX.⿼0dV\h4(vkۍ5kֈ544L<^ݼ}Uح_:/ʹtI`( <ՉxVns=gFH8Aa5bc((S4--d%3`Yi0SW]S(jhhBs -(J((Ȩ?gE`П_6g?8NRj1 200`71cc 1>ǃ+W;?>ǷZv}|_8-/a: pf)H@G_ =5 ?@w2`d󙢣8*LxrPS FF'CW,L73G2wz(*ۢzZCD3g]F.oZ+Bn^%I Є۰i&@_J iATW}y9yuHBU!` # ;N #}PyT6j}WM%ЕK^{Q2+Db>eVח.5d\.2cy|XZDڕ F:[B '̌Ti>@ P.o{U~`ә|B gLJ4)*>8!lN0'Pb^IⓉN6CV A-b c~Gq2A)29vGoeGٺ<%@qKSԢ(SFBƬ Egg`Q!NVm#HcU’1ɗ%@E/n-FϿir v-r#>G~m4vSc1)CV߿5#fkCxV'I2ƤfLa%KϛS0P. =vU9h<]A(_J(OSE`< 2>7@\9H9Gˡ+dRP>DžX,2Yz=s88ӳX,^[`P&ۅYH r~FookSۮIm nRX źSFqa0]42[Sr ӂ̼/3!@Cv؉_m=yLxv.)ro$ "+:aS %0 V-ف>OHd9ꓟ%G/l{ ëhU <57G?Jz,JTWFD~IVD"P{D-!L;J IDAT:os6u'x(| DQ0<ݽ?>pPpr_8GT{ObLeF(+j֡w LBE܊#sѰ?͗ |cf DQZ@oo/NnJu9b> ~7oXzZMi:>Dl }<ɚyeDq9M(D?3sB 4BP)Gy'PfE(R=Hx΂ġ)X*Wx ^(7z8q.eKVUR>zooo7?=d5^n3/\q J|Yx%@p)Stg _׳~1:"r$98yy^[8kƵi|]1sR( u RQ51s#p@O&_֚y%ф$I;f(2c)hTd9&̱ڃD L!ڈj9P6i 0z+ėmK]E%j{ߟʍ z'RIM</$IQK]H* @ NѡV;b(,B%F O o΄mqyok0{%`I=fHeڿ)W$ /QYc0*=tHxac%4׊~dB#'b#Y w[I>%cR1 x2W4botu sN\]Vh4, ' 2]X_b044`i&l!jX#|7р {CS6)/.Oc<93Fޗj@J؏h? `@5.0u L+43 uAu+س{^4}t zc{bjORboUpk~~("xB]R ?x@@Ju;cko}`k5kP~aai b!5 ,6X.Q=7@&U2F,!Dy?r^8x2n6{*j`|ɰ񻨮 s Z+eBO(iH@Gk߼t6|I|/."o8IB{vtGqXh)1[02kM}pg"c|ʘ0&_W_;co|7Yp9 e*5K`)a\E`ugL `O~hoe!Be6ͤIjo%"`vTm1K c #Y[7@t(Eth !d#ڗVl7ohmmՒ7̍?*N G<] )!>3ՔeY{(b~<_ (S(E9IEKJt 6Lyxܾ}]~:!839!'fOs!DB[%3>B=xAԃvYOMnP[кEg1>LМ ^koPj&I1j(t2bP -ԲjQH1#G &T`h\Nw+v..` ~_Ek81k Bv5כkȡ ;5xNM)'[%)W<' SstO)+KWNjuoqi5Hv" 5sӅi!8, \a,\Ssed U[` UؼJG/ UD55' Ev yJ,;z0cBb!uxxNuP!}~9+'Q!:a0t֕IC&`{X\q\Rs=GR`-3p Jtfa6>IJb2]ȵ!BX!K,K< liwx\j0ۆ.?8ϸt?%Le u@1LЄkD +:Q <aeZl)IGR{"ZO<ג#VbˆF$OyT)EMǙc건 gJY).v0/x.K伸(LQMJRD `E0a!WI@/^ Po~>M4_PƈgV4&hdѳ`R"?}cy絓pO!Zhur-|<7DS)yL1 2@$Y=?T1T)?TO }kzzz"B`N&3?ØYt{B Η #le2*Ԋ A\Z)8GV۫|8u&/Ky'ڨ7LuPCrgCDBT'C+Pd'EC' ̏XniHdUFn̸p#Hɣ[b|+/Đ)Tl9#347OUovX|>m [rQׇɲHjGm؏<ћk:?~ͳrs4YUK5뮽=mDG#Q`k~p|ߡw?C-xQc8L'ƀtifd1d镣e Q$n;"#:}B_,*s$_6@}x_|`/-(=`~vLE\Z/~`J{ku|kjqr"}4:>:__=+{k[g>ty##zOn#dO4ʹ;M#\rnI‘/\NMNNNB`;ov#1UFn֊ȪZL6~&5HAYؕAN E\&xӏ}>OY xT+g ot{:Vg@,rD"DT#Hdʒ(eAv]TDvr,s6_WS$]B)9ԯ 7/䢱Mu\Z7s#!G>h`%G/aZ2x Bէ7=iA9-N<O.Y?osDѧp03])FfLZxkQ߱sŞw^V)0 ӭn:3 \Z$|2d,7 eO,d ^"دfQC<^jVj)[}3#OX/*(v<'^Tozh t$9k?7ڟrnkqz_zŊ~6n\a xBң`ܘQ  q+O>i,K\4PC3N$iՓs8_,Yw췰BGhkw~}9Kg&7l^9zҌYZ% vvĿ>Uo;n:)G00C(cgˍj݆saN nIH{x.3:QG/)vm !t6]AL/}ĝ©3b p;w~k'yCo}΅wݰ1~xOgޯ=O<ݞVfׯ_=7Η J5 ={D7ՙ o%$E څ,0R V4 `'!m6bP(D7nWJպ"xfߑij/?kfs-xYZ@+o?{j\2y?QiBf<Oh'l\hva L(T5P0F(QL!b`&P(X[GvpsϿ}R2gw<ܛmnq8;5\[MFvrE?jg]{~#{r Z VȽpt3 :U(IO(kbP1y'Qsx8 JÖY<|D]jFfˍS[06S"b|g Fp>8' W>vgnڱg'~Fu*?þ~Z]gojO[}$f;o9G7uJ͢P{I"I na!Qn~9P5?:2}OQ/s[$ Pں9t x@c1k!4XSAޠ\5GrA0O(|f$/Cyoe{5O=\3.o]1K%Y EOl{+^+\rh2f Ѓz^::s0SW`E-p_JBl=RjiA J^%4auXz쬿r^A-RΌ2f' lUcDU%;Ou.o`ūGGlfU/}d܉b_ؿ,]Xwxv5Ƅ( Ћ V}SjAf#HPY[ Aוچn,**`iUE^kF `b ygLctLëLfߋ\,Gc#=g'ܳc/~obj}R/"Os'p%QhmZ[r--AAk=x~TPa?QĸoǟmFHIk\p/(]sf zç2@P--i ugT`51GcZ"UQ {I[r,®ܺirS/Zߗ|~LY{>d(\_[6-yE=`E$+ot$ZchKk;kYZk({dZZyhi:UYmކE,h}J νTRܠg1.^X-NĐGɽDcеF"`P s\k]}ՖyacOO ϥS~hir<(D_J`8r לS{}guz2_7˗ϿEUSJ\?OOsx OFp$:fhKl0)Rpu LP)U ,`cs_\`iV/l@K2HTb]偖j!7="MVT2m$*0JK4hoo[?+_׏%NK^>uzJVH\n-[ggf <O>MљH,>EsHAL XT X۔7#4])JG/S*L3Wq|:`YgmJJ`*]f2 6OI#b!ƹF+ Bna#l劥sO?}_l,Ͻ|;o]t-QKt:OF+Ei{]sssṹ91vKXl.Ecp<1$ñxA.f eQ[ h3~9"~cl DM&6, _of6+ l:S)Vu\Z[Mq]vە'|z1Grߎ#oHZYd43 m$֞p zER\O>=b;wk{}5 o*JR]~oz,KGcT4Hct$d KBUGI|^Hu"+ݻwW&Yr J<خ\zTk \ ΗݭZ܌1BTOLTM#rN%%1`Di; \#U:1&a۷zΉd~܁jrHPzsr;t6ux.P+*f'IZ;Z;gCegz2dO!r]\\q~AݩT-JaXW =kUYlVN;}98+ ܬyCW&dm~oMj9Wj~t +V?&1yZ1T Tu7'ݞzkgTkg$ԕI͵eS|6ݙˤ;l{.kk4,IƼHD|B_P(F#ޗFdz]HnaUQ|ucd1)tָCG抹KrAfL~0F2Crw~IC~2!( BddF> IL!`#_S׾~|I[ݒ'oOYCW-3AT9U2A^TC2bge2-\-δj&n VU᧔=RW IDATG/hT*ek&"?@R  H02k0F'KP+q{BwNR$* Kᗉ=IATT*N˕gg^Yߠy\_纷7>owſ>haNx`ƭo*U5Ӂ2)(K`2(]Љ!q$nyz*c\8+0`X , lM2l*ٞfZRtV%_2έb"E3ov{~PJx_p'B$uKV+ ݡP@gzfj D=g8#rMNH>0Fԣ#w*@ΈxG߽fd&nvoC;Z5 ֞x*7]55zo^kU 3 բ SG8Bh>;z&)ӧF:76!9YjsyHǓY{K熆Fbj4Fj@$ ?:3`߯:/=ۛp, ]r}; ta+<$9j@K&S'{Ӵh=,;_q54(+f3s)F]zc\cg9zGW߲RUB(M%bH_JXAJ/-]DtgW YlWU$I1#ڗ~fR)DQTU6+n]Ed b }9ӭсcM bN$;P, .!@\1Be)eQFo+k?"[&ܵc˱?̱|Re0clڍG9tTT6LhKH [#MI>5_ * ~ِOhP ~xDyP&/R`#ڗV㆛wnZ>|>XyGֈXm(el,Y*%K9xn' z~#IZ8=Qs__W{=̦[>Hkgϴ>OY8GvLGݽ( <|:|zO%b_hzXi_b.Hn1o%l\!᲼7"ORJR+e}߼abbBrY+V>Oqml3-/Ii47^g5h7ߛ?yc͖J !0GmGxf6_ŝۥ-ar6 9QgMWaSW6ShMJmmCPL$x^=bg@Ξ=kҧi>)o9+J I5-]cM'^l9~ݔڧBk?|_l/C.aD`:À9 I$j<{||.6N$*eTbmh/B#fnnLF`J bAmEUVePHn V=nPǠcyB|^7;*֭{r}Ӟ+΂D-V10P9*g>f$2#Mj$w`9;rn9KΡ3!v}t+̦{xu =?1?22""h\.۶ [&BM(̢[1oq뇾-7?| {\73*߃sfbHr.mzr=!H݄(_X?PWɜ"ZGf.Wj0kN:%_>WqDUO@5WmbȢD!X$Y&c6UO&Jk i;[HhZwwsn7u?[ړ &t&rBt̊r6%+JΞ\yD]YgÊ:t{+?*Y`I&=s_,b ' Z ottJł#<Mq9rG)x^ۈ7 >7!fɡ]ʚ >1˖7~v-ۻ뾟k72[MO:fnuǕA^ tZ!>yne2FLn1Ģ*n4ѨrDj,˖tcǎYRzX,wG gϞX|>ob(۲nYc}-WO̭2߉k0]7х X"C;v~T!6n1q]EbP d`0xTn+AȳM.+pU%0Q^gv٘/U-AWǰ|zOsDfff077g)w4c+ mPrj |\nZ*}UJ5 aNBΚl όBeEzY,+UJ *JI޾g_R:;$.:FEg1|jWajMFoBPT,#GDYJ/2o?sF ?j ̱zzO.ax&|qJAAύ(@EDLw rՋ.d9Q(ǒɐ?HG"<|Eb s-d<ö[$nW"uR) * _B0oԺVUab%o۶akl00111Y<J6|M<z`mP{/QTO9MnA,.Aop C~еVSs||f|h)xp۵}jj 9r":r2S Q|0<o<5zO2KG'ieZFQaܿT*YDOc8"|y L(s6hEH]ص\ նF'bJ(L@0 3j^O2Zj,(@ro飇?ƻχMґ)*\fBHOߕ/U-3n|br;(tc~hffgΜ%|_rUw.kˍ{:%KA{{0E83~\n6"M ln] Is$b s&?,[5Ek&rkD(p.r Ο:="u oBZZZ?~0ꫯ{X(o`!N)ɓ'9 9,h ]=32{lo^ӛ !X]&170(B"ްz?oE!胑3[33g}_˶O$(߿/p2WK{Yb307'H$pر""NJvBO̤ @HRP!|u]!BI֝ŢͿ5n8w^dF%D,$usz~&n\׋c^X̂Tw/VxE_8@`YwޛGqw_]]} IQlEEEm|g;y;;M}|T*( jaoocT@ >1 % Oq| KxO[y:H;hA x3YNSnY,7e vIs"|1ɏ;9>1|qŗJ7( N-cMwIs\gggRaXXXp,E==Cv> yyͼn'7%XWYBH# 9WտIlsEs \4m(D"tul9ga_(NM)A? A695MkJpq' +خ:t7>0d2-뎙a$A0F{ MNT~4Nzddtkj)lM88_ސh l2 (YlEL\@ pn恻I ;6s6np{4rž.kUN?]H$X7??4 n>77':dpQСC|z^8sWU9Vz^TUG-+,cGdu*&;~y,2ڦ|| i!o6w*H>>p=?tS~FRk>ޜ4,,O;\,Ft^ٳg*~o|;݄YB]vX/,,`֭&*^odB|>JRS(Ah{T HR!|6-uFÑh>G+9$NB9gY9ɛF% $D3N'f?ᷯ1^79S|I'<_*ہ&%cǎСCo`kGf}vsT*M?Cv-$YKe" L/xYF@sHٟ@HjO`?{5ZZ'3\L=vo79cyG__ݯ:^@䊢G\vNoֳjMH)>t0M#k!F}Aty& |łxW[εEıJ՜:8Z3T@ooيOձh GH[DP+'/~d.]݉>ܓ8lٲ5;77˗]eJ;u]|Ϳ<~xf#x^}vSF9u ,7ُL׋f;(Mv|ҜwiRnka-r@Z8(Ik=inwHs1gF́7.n8 ?<[nB}}}$(MLL^pu/~'w^@xѣGu'I VNAQx ˇۆCx\TMs4E!Hp fצ ?k1z'F3 G&-:>w)aM1ǟ|7npcwk*Pӟ.~>'oFo':MC \=t= TUE u\$IAK@$]1\!YTMbu`>IIYCez1;c~13{JesVSdNlyco=VRd2t~aa;v}{n #8dYh~i{9|) ^_"qSZHݻvjl2R49| u 2'^O"Яw o}NЭ9l<1z഍nNA#!5>vs z]&.w5U-޷/?Gp~{A" ϟNj/d2J;xJ؉l˿0Aq֭[Kn݃kfggFH:;>y T='\eg9Bf%@o&a#%㑍}3EU"5+Wo29> yV><ϷtUUBus[woVTp Mvod2m۶+bk+,j>vqXsE\ͻ4ݛWvLϦo+$=:p 4z34UZJ}]$/^t޳s}m>GvqNJ>&hx19nO]r9\rGP0Wz+b1yhf>o$]?2::H$~Ձ& - _týl}LƬacʼn'N4&qܟ>|X@}A^tvw;lZchK:Е,*73gQVھ_s9Ep`nQݷD ?FS e@)H.[زΏfr݅rmY9|>sVdk}>qҘf`t p52N8sΙ^x<>p@LES077T*e&99ÇW:p`&T[Ӄ6@0t8t5T$_WPזW(|1\ o*ϊPw89a@(|=_ \uJ<[9k pb6JnmzJc166HٳիW+E y op0H 7 IDAT]M@e2+T*6r/J_E_1鑄#$QKXD |:љj+\WU^W55\]WT-߭/;q}K|>]4(fB>ǫj߾bttpؑvw0sop0H!?tF"u]M뚐bS:٥h8}!~3.n Tw[zqHgd]]]-+b\ũ&[߮ /0;;3g L"}3Ž=zuVU̠!M)EP,FqT% PǵZ1 Rǝwo"ҹ2y:wnơwlC_gX x5}ϙLM(:D"|>=!LME S(>M$So` | : xX^ `&UĹY|6W&y85!m~c,l v߻8%t]ɤzi\t$V|"FFFL"bVĉHRCťң>!M@M7044亢%eXQ0,bb*SWxJeZ:!5@+.4DУTRҥKx;ѤuPǙ@|cΝy/PVc~~ I8V;In,wEW0I=hO:cǎaffU;n?ў|C?A ,XX059}3(4M31&lpδЍ.Cč0==mR[.fQ.͛^+uεlTJB:u:Ekx155J7͓zu]fjj 0my||d,=9E5^k}}G,LXT@q&\0_ӑgxo~: sKUU3Zٳgq%U{}Q{Jk>B)߿Ї*.^AT*arr\`Yx fՎ,N8|>T*F?CH}Q> /`k>&lhOX,brrϟ7k]׏Op\}=8x >1әi'Zf]Mn\(i{ 0a.38?>u`siO Js>b1Ȳn,D똜D\n[ϱt았 `ll ,OkoUUqi$ɥZ lByHZ}7eM3 ۮ[ Q|LT ssszK_R~//>OȔҧ)w8A޽p `ff\nI39jBعs'@&~J)Ν;iR)!.xln`; l]QVP@ CVM6j5eL9ɘ7y QJWG?nJ3=N+c;w4oNy/5[`كcddhԑ˸p9E><>>L6|+_u]?>}t\IAYӠ(YºTHox\RJ/YYGu9]G $I9If5C!FLc `x  s|f||{xh27 *^?t]c[lPSX0!3===l 2gY#~i!__p?kKRJ)G/u=<uf@ @,Ν;͜}6„&+)& BqMV*p  ͵(ˑ#Gxʗe/6,& 3U]ߠR,G}tz?=W0;v "aB;pg z[\ibΝ/„,EI;1;m0ŴՔeL& П~Cξ{? ࿹iJn>a¥r[`0q$&LRKEN`1B0!SJ؂* @bs+1(*rƖ0''r>xI3Nq BŦ0bvvldv҇[ ?d2\i,&u:&<0vaXoA 5>ܮV:ŚHXP(MP'6wnM-dlmDvtt{ORՐfqc1!~(6+_óx9Մt,evH$χBIPTH@D"J:]m/% !EA:6w*:Չ%Wr""ǹ\ 4 ہ@Hl,uott4{;wvj:[O0s&&&tY McX@ EQP*FWm655͍Zu^J(J؛PJ!2fxPV ޥ ' C[C#h$$I$Oرc>baa$ydYsp}upbѱjω>jz-Iz{{ I {{ttDC ֠ߌ[011q|ddeBؓA٬.,, uypjuj0BYnAMZ>(f|httt,t# c%YӃt: j\[vD"Q;A %FPJK8{7 .i*1`,LvVej\i Qۋ|>Q[E<8::D"Q|[?kpPM.tPkVTP׸d֌Fo<ϣ:K$ɷ !pnm$F$ŋn(oRJP(d Yq;#HÀMfh^B0a^$InSFD"qq=x@,㵫}Zg9\ȉ1A%,Y DE"oٕVQZzQUUiVZVUeRD ’Sm\] q=Hۜ^166QcqjB=y㭺/phhȱ9'\ u͹+>2>>Bk\Ju |>qŸ. `0>Hy<NE!v . S]M4]4i(( #ZrY+JZX2Nt:҅ GJWb1n g7u1kJ\boGuuuapp in`,xR/_w]ih@! \OBh8W3:??(333ޢMz$[p7z^p MGDi._Zvqq۰o߾jB)r˗/ss\_f`b懆[]]]B(`_$IEQ`Es^8y8 !moی(v" `)T~JF^UUU5@VjVSZ*|>r95J)W^UIZҵ^oY8!chh7tX,u"lݍO}>+ PJQ.H$կ~)ؓO>yuzkM(k.~xxXܲeńp8,]/ h^`8N ƪ/X4g7͠[4A" {Fz]JZeD %ͪ 299\rET*t-W|u]`1Ff]vvmXl:dn?Tav<444brlT‹/|;NOm||VY7" `sN_# %'ʲ,z<A$Q$QPEA7< c`gP+[Y7 U]7H@뚪(jVSժba(LFWfff/333mkD op__w!w9ݼ^{AooO&l!hMD###pm5Bo8~B^xꩧ m"x'+<^g뚒Q0曥={x=}}}h4D"@ |,˒,Y=$MEQe<{x8qyly={ly,dDDB;f`h&¢> Á<Ϣ( i|>" wH$y<GE(A< x K x83q'<1^2q^c p{-g{+!y !^dBq!Hv6LSnXL7ܢ0y Xc lV|۷i5MѨ=(8ՄK giۯMuaV<==YB"AY6 _ -A cccАX,&AƊ/J$(ƾ$qg9DIybbbv7:zz^"I'"KibՒ>go@)q'''q%TUY<ݻw7[ ^~e;H$ ,بvP$ Fn8j r쪿U7q ہot]iV4W5M^a$`j㺪UMjuUUcEQ^QE늢(JVSj TTrYj.S3JYujjJfW~ţCCCUޅtj"^R44eYF hh:uV`D&n"J鋆l7e^tVVi\FZkD"^zN}>(.IxtM4EQ4Q5ATUUUU#P8NyL%-R!:8x,鿌p㱙kS`b K6@T*JT2٬2??\zUVRcǎ}7)IcN'Ob׮]ۑjB]r`ƻc\xtMqpYNtl rqTfggi6/,,h-[n- jPH|Q^j$),VRy ୩he,c@VJ@VR-6?Ͱj՟J.S:??_UtMӮؗzsό.Z={ĩS{nȲl$Iرc&''V#Ny pi)J䤾}vu۶mJOOեa@@eYx<%IbuA(T.v0Rk-ޡh]b $:/.T3`vY~6l}C5j*RɤL&zN7oϾ|]w/ ~^ɓ'{n~l< Iy8%1brxc+y<m۶M|4eB}>o$ F "/q~1cv$ة'q"k Q[WE\l o}EQ4z} JT*f2,x->o0c߾}4 ;w4XzzzuVs`jWVl\.~Wl^L zzzh4*B!F 2xAXW s32lBl 4QԒ@% = V[\6 9L&+k UΝ;op~'Pʲ@4 7U ۴ӫ~'_7 韏wR&l9^ YkYbbMLLh cp8|>>$x< oh 9!,DlGkTŒ:\ YP]UU/(ވj^3@^6ղ٬^,)?r?8x|<OCK5rL`y1 0`}aPUU4FZ+^.RB@ ^ըÍzkM:@ .2G @$0AΝ;@2nZ[ /.3<^O/?:A1~Θy<NeN$b4%FyG,(pmf[pRP0-˨NM>RBؐdq}$I&C<,عs'D4VPef?3dYSѪjysa  8HR EQ(N6׾ skLkNs>{͒s4M328 &u|K/dرcp߿Vne{k܊7BnwM7݄[nŵJD4G?O~' Gyt5dz Rl[^Zj P(~VBv?P*fc}?T>)m5_6g 8o;/lfNȫW4MXlOj59I x <pRJȑ#?X @HcӁR_ze&,{{EQX/GetMضm 2Ģd2s̙3KEh =r+uy6|z~΀_oR(~`q,و}i'=zzV֓jE_n;@Z۾[Z8 ˗/u]n4-BPJg[k ֪BX+e`#]|D *2SU˖$5z@ e v^w-לW.W{RJ(?>Ses_ߌF[obM=mXtꄐ, TX< /{*F]ѯo`3+ZZh MKk뵚_o uz]l+ `~NLzZ#v"` X)RF ѻ:8. -I.]:Fz6FaWݍ,YLakEJXkaS~3ZV Xo\׮ oCo bXk]Z'-vh nƱ;&iVrfp-4t`S}dk ,zvG:6VБt#HG:ґt#HG:ґt#HG:ґt#HG:ґt#HG:ґt#i-?_=0.6.5 default-values>=0.6.0 domdf-sphinx-theme>=0.3.0 extras-require>=0.5.0 html-section>=0.3.0 seed-intersphinx-mapping>=1.2.2 sphinx>=3.0.3 sphinx-autofixture>=0.2.1 sphinx-copybutton>=0.5.2 sphinx-debuginfo>=0.2.2 sphinx-highlights>=0.4.0 sphinx-licenseinfo>=0.3.1 sphinx-notfound-page>=0.7.1 sphinx-prompt>=1.1.0 sphinx-pyproject>=0.1.0 sphinx-tabs>=1.1.13 sphinx-toolbox>=3.5.0 sphinxcontrib-applehelp==1.0.4 sphinxcontrib-devhelp==1.0.2 sphinxcontrib-htmlhelp==2.0.1 sphinxcontrib-httpdomain>=1.7.0 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.5 sphinxemoji>=0.1.6 toctree-plus>=0.6.1 consolekit-1.7.1/formate.toml000066400000000000000000000022271465042170600162340ustar00rootroot00000000000000[hooks] dynamic_quotes = 10 collections-import-rewrite = 20 reformat-generics = 40 noqa-reformat = 60 ellipsis-reformat = 70 squish_stubs = 80 [hooks.yapf] priority = 30 [hooks.yapf.kwargs] yapf_style = ".style.yapf" [hooks.isort] priority = 50 [hooks.isort.kwargs] indent = " " multi_line_output = 8 import_heading_stdlib = "stdlib" import_heading_thirdparty = "3rd party" import_heading_firstparty = "this package" import_heading_localfolder = "this package" balanced_wrapping = false lines_between_types = 0 use_parentheses = true remove_redundant_aliases = true default_section = "THIRDPARTY" known_third_party = [ "backports_entry_points_selectable", "click", "coincidence", "colorama", "coverage", "coverage_pyver_pragma", "deprecation_alias", "domdf_python_tools", "github", "importlib_metadata", "mistletoe", "mypy", "psutil", "pytest", "pytest_cov", "pytest_mypy_plugins", "pytest_mypy_plugins_shim", "pytest_randomly", "pytest_regressions", "pytest_timeout", "requests", "typing_extensions", ] known_first_party = [ "consolekit",] [config] indent = " " line_length = 115 consolekit-1.7.1/justfile000066400000000000000000000005731465042170600154540ustar00rootroot00000000000000default: lint pdf-docs: latex-docs make -C doc-source/build/latex/ latex-docs: SPHINX_BUILDER=latex tox -e docs unused-imports: tox -e lint -- --select F401 incomplete-defs: tox -e lint -- --select MAN vdiff: git diff $(repo-helper show version -q)..HEAD bare-ignore: greppy '# type:? *ignore(?!\[|\w)' -s lint: unused-imports incomplete-defs bare-ignore tox -n qa consolekit-1.7.1/pyproject.toml000066400000000000000000000121361465042170600166160ustar00rootroot00000000000000[build-system] requires = [ "flit-core<4,>=3.2",] build-backend = "flit_core.buildapi" [project] name = "consolekit" version = "1.7.1" description = "Additional utilities for click." readme = "README.rst" requires-python = ">=3.6.1" keywords = [ "click", "terminal",] classifiers = [ "Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.6", "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", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed", ] dependencies = [ "click>=7.1.2", 'colorama>=0.4.3; python_version < "3.10" and platform_system == "Windows"', "deprecation-alias>=0.1.1", "domdf-python-tools>=3.8.0", "mistletoe>=0.7.2", "typing-extensions!=3.10.0.1,>=3.10.0.0", ] dynamic = [] [project.license] file = "LICENSE" [[project.authors]] name = "Dominic Davis-Foster" email = "dominic@davis-foster.co.uk" [project.urls] Homepage = "https://github.com/domdfcoding/consolekit" "Issue Tracker" = "https://github.com/domdfcoding/consolekit/issues" "Source Code" = "https://github.com/domdfcoding/consolekit" Documentation = "https://consolekit.readthedocs.io/en/latest" [project.optional-dependencies] terminals = [ "psutil>=5.8.0",] testing = [ "coincidence>=0.1.0", "pytest>=6.0.0", "pytest-regressions>=2.0.2",] all = [ "coincidence>=0.1.0", "psutil>=5.8.0", "pytest>=6.0.0", "pytest-regressions>=2.0.2",] [tool.mkrecipe] conda-channels = [ "conda-forge", "domdfcoding",] extras = [] license-key = "MIT" [tool.sphinx-pyproject] github_username = "domdfcoding" github_repository = "consolekit" author = "Dominic Davis-Foster" project = "consolekit" copyright = "2020-2021 Dominic Davis-Foster" language = "en" package_root = "consolekit" extensions = [ "sphinx_toolbox", "sphinx_toolbox.more_autodoc", "sphinx_toolbox.more_autosummary", "sphinx_toolbox.documentation_summary", "sphinx_toolbox.tweaks.param_dash", "sphinxcontrib.toctree_plus", "sphinx_toolbox.tweaks.latex_layout", "sphinx_toolbox.tweaks.latex_toc", "sphinx.ext.intersphinx", "sphinx.ext.mathjax", "sphinxcontrib.extras_require", "sphinx.ext.todo", "notfound.extension", "sphinx_copybutton", "sphinxcontrib.default_values", "sphinx_debuginfo", "sphinx_licenseinfo", "seed_intersphinx_mapping", "html_section", "sphinx_autofixture", "sphinx_highlights", "latex_transition", "sphinx_toolbox.more_autosummary.column_widths", "sphinx_toolbox.latex.succinct_seealso", ] gitstamp_fmt = "%d %b %Y" templates_path = [ "_templates",] html_static_path = [ "_static",] source_suffix = ".rst" master_doc = "index" suppress_warnings = [ "image.nonlocal_uri",] pygments_style = "default" html_theme = "domdf_sphinx_theme" html_theme_path = [ "../..",] html_show_sourcelink = true toctree_plus_types = [ "class", "confval", "data", "directive", "enum", "exception", "flag", "function", "namedtuple", "protocol", "role", "typeddict", ] add_module_names = false hide_none_rtype = true all_typevars = true overloads_location = "bottom" html_codeblock_linenos_style = "table" autodoc_exclude_members = [ "__dict__", "__class__", "__dir__", "__weakref__", "__module__", "__annotations__", "__orig_bases__", "__parameters__", "__subclasshook__", "__init_subclass__", "__attrs_attrs__", "__init__", "__new__", "__getnewargs__", "__abstractmethods__", "__hash__", ] [tool.whey] base-classifiers = [ "Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed", ] python-versions = [ "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12",] python-implementations = [ "CPython", "PyPy",] platforms = [ "Windows", "macOS", "Linux",] license-key = "MIT" [tool.mypy] python_version = "3.8" namespace_packages = true check_untyped_defs = true warn_unused_ignores = true no_implicit_optional = true show_error_codes = true [tool.snippet-fmt] directives = [ "code-block",] [tool.snippet-fmt.languages.python] reformat = true [tool.snippet-fmt.languages.TOML] reformat = true [tool.snippet-fmt.languages.ini] [tool.snippet-fmt.languages.json] [tool.dep_checker] allowed_unused = [ "colorama",] [tool.dependency-dash."requirements.txt"] order = 10 [tool.dependency-dash."doc-source/requirements.txt"] order = 30 include = false [tool.dependency-dash."tests/requirements.txt"] order = 20 include = false consolekit-1.7.1/repo_helper.yml000066400000000000000000000026511465042170600167320ustar00rootroot00000000000000# Configuration for 'repo_helper' (https://github.com/domdfcoding/repo_helper) --- modname: 'consolekit' copyright_years: '2020-2021' author: 'Dominic Davis-Foster' email: 'dominic@davis-foster.co.uk' username: 'domdfcoding' version: '1.7.1' license: 'MIT' short_desc: 'Additional utilities for click.' use_flit: true min_coverage: 90 docs_fail_on_warning: true mypy_version: "0.971" python_deploy_version: 3.8 conda_extras: - none python_versions: - 3.6 - 3.7 - 3.8 - 3.9 - "3.10" - "3.11" - "3.12" - 3.13-dev - pypy36 - pypy37 - pypy38 - pypy39 classifiers: - 'Development Status :: 5 - Production/Stable' - 'Environment :: Console' - 'Intended Audience :: Developers' - 'Topic :: Software Development :: Libraries :: Python Modules' conda_channels: - conda-forge additional_ignore: - _command.py keywords: - click - terminal extras_require: terminals: - psutil>=5.8.0 testing: - pytest>=6.0.0 - pytest-regressions>=2.0.2 - coincidence>=0.1.0 third_party_version_matrix: click: - 7.1 - 8.0 - 8.1 extra_sphinx_extensions: - sphinx_autofixture - sphinx_highlights - latex_transition # - docs_needspace - sphinx_toolbox.more_autosummary.column_widths - sphinx_toolbox.latex.succinct_seealso sphinx_conf_epilogue: - toctree_plus_types.add("fixture") - latex_elements["preamble"] = "\\usepackage{multicol}" - needspace_amount = r"5\baselineskip" tox_unmanaged: - pytest - testenv consolekit-1.7.1/requirements.txt000066400000000000000000000003021465042170600171560ustar00rootroot00000000000000click>=7.1.2 colorama>=0.4.3; python_version < "3.10" and platform_system == "Windows" deprecation-alias>=0.1.1 domdf-python-tools>=3.8.0 mistletoe>=0.7.2 typing-extensions!=3.10.0.1,>=3.10.0.0 consolekit-1.7.1/spinner_demo.py000066400000000000000000000007501465042170600167350ustar00rootroot00000000000000# Demo of consolekit's spinners # stdlib import time # this package from consolekit.utils import braille_spinner, hidden_cursor, snake_spinner, solidus_spinner REPEATS = 50 SLEEP = 0.5 with hidden_cursor(): for _ in range(REPEATS): print(f"\r{next(braille_spinner)}", end='') time.sleep(SLEEP) for _ in range(REPEATS): print(f"\r{next(solidus_spinner)}", end='') time.sleep(SLEEP) for _ in range(REPEATS): print(f"\r{next(snake_spinner)}", end='') time.sleep(SLEEP) consolekit-1.7.1/tests/000077500000000000000000000000001465042170600150415ustar00rootroot00000000000000consolekit-1.7.1/tests/__init__.py000066400000000000000000000000001465042170600171400ustar00rootroot00000000000000consolekit-1.7.1/tests/conftest.py000066400000000000000000000007431465042170600172440ustar00rootroot00000000000000# stdlib from typing import Optional pytest_plugins = ("coincidence", "consolekit.testing") try: # 3rd party from pytest_mypy_plugins.collect import YamlTestFile, pytest_addoption # noqa: F401 def pytest_collect_file(file_path, parent) -> Optional[YamlTestFile]: # noqa: MAN001 if file_path.suffix == ".yaml" and file_path.name.startswith(("test-", "test_")): return YamlTestFile.from_parent(parent, path=file_path, fspath=None) return None except ImportError: pass consolekit-1.7.1/tests/import_commands_demo/000077500000000000000000000000001465042170600212405ustar00rootroot00000000000000consolekit-1.7.1/tests/import_commands_demo/__init__.py000066400000000000000000000003211465042170600233450ustar00rootroot00000000000000# this package from consolekit import click_command, click_group # this package from . import submodule # noqa: F401 # skipcq @click_group() def commando(): pass @click_command() def command1(): pass consolekit-1.7.1/tests/import_commands_demo/submodule.py000066400000000000000000000002171465042170600236110ustar00rootroot00000000000000# this package from consolekit import click_command, click_group @click_command() def command2(): pass @click_group() def group2(): pass consolekit-1.7.1/tests/requirements.txt000066400000000000000000000015101465042170600203220ustar00rootroot00000000000000backports-entry-points-selectable>=1.0.2 coincidence>=0.2.0 colorama>=0.4.4; python_version >= "3.10" and platform_system != "Windows" coverage>=5.1 coverage-pyver-pragma>=0.2.1 domdf-python-tools[testing]>=2.0.1 importlib-metadata>=3.6.0 iniconfig!=1.1.0,>=1.0.1 mypy==0.971; platform_python_implementation == "CPython" psutil>=5.9.6; platform_python_implementation == "PyPy" and platform_system != "Windows" psutil>=5.9.6; platform_python_implementation != "PyPy" and platform_system == "Windows" psutil>=5.9.6; platform_python_implementation != "PyPy" and platform_system != "Windows" pytest>=6.0.0 pytest-cov>=2.8.1 pytest-mypy-plugins>=1.9.1; platform_python_implementation == "CPython" pytest-mypy-plugins-shim>=0.1.0; platform_python_implementation != "CPython" pytest-randomly>=3.7.0 pytest-regressions>=2.0.1 pytest-timeout>=1.4.2 consolekit-1.7.1/tests/test_commands.py000066400000000000000000000226451465042170600202640ustar00rootroot00000000000000# stdlib import inspect from textwrap import dedent from typing import Tuple # 3rd party import click import pytest from coincidence.regressions import AdvancedFileRegressionFixture from coincidence.selectors import not_windows # this package import consolekit.commands from consolekit import CONTEXT_SETTINGS, click_command, click_group from consolekit.options import colour_option from consolekit.terminal_colours import ColourTrilean from consolekit.testing import CliRunner @pytest.fixture() def force_not_pycharm(monkeypatch) -> None: # Pretend we aren't running in PyCharm, even if we are. monkeypatch.setenv("PYCHARM_HOSTED", '0') monkeypatch.setattr(consolekit.utils, "_pycharm_terminal", lambda: False) @pytest.fixture() def markdown_demo_command() -> click.Command: @click_command(cls=consolekit.commands.MarkdownHelpCommand) def demo() -> None: """ This is the summary line. This **program** does *the* ``following``: * This * That * ~~The other~~ (deprecated) A multiline paragraph """ return demo @pytest.fixture() def markdown_demo_command_numbered() -> click.Command: @colour_option() @click_command(cls=consolekit.commands.MarkdownHelpCommand, no_args_is_help=True) def demo(colour: ColourTrilean = None) -> None: """ This is the summary line. This **program** does *the* ``following``: 1. This 2. That 3. ~~The other~~ (deprecated) """ return demo @pytest.fixture() def markdown_demo_group() -> Tuple[click.Command, click.Command]: @click_group(cls=consolekit.commands.MarkdownHelpGroup) def demo() -> None: """ This is the summary line. This **program** does *the* ``following``: * This * That * ~~The other~~ (deprecated) """ @demo.command(cls=consolekit.commands.MarkdownHelpCommand) def foo() -> None: """ This is the summary line. This **program** does *the* ``following``: * This * That * ~~The other~~ (deprecated) """ return demo, foo def test_raw_help_command( advanced_file_regression: AdvancedFileRegressionFixture, cli_runner: CliRunner, ): @click_command(cls=consolekit.commands.RawHelpCommand) def demo() -> None: """ This is the summary line. This **program** does *the* ``following``: * This * That * ~~The other~~ (deprecated) """ @click_command(cls=consolekit.commands.RawHelpCommand) def helpless_demo() -> None: pass result = cli_runner.invoke(demo, args=["--help"]) result.check_stdout(advanced_file_regression, extension=".md") assert demo.callback.__doc__ is not None expected = inspect.cleandoc(demo.callback.__doc__) assert dedent('\n'.join(result.stdout.splitlines()[2:-3])) == expected result = cli_runner.invoke(helpless_demo, args=["--help"]) result.check_stdout(advanced_file_regression, extension=".helpless.md") assert helpless_demo.callback.__doc__ is None assert dedent('\n'.join(result.stdout.splitlines()[2:-3])) == '' def test_raw_help_group( advanced_file_regression: AdvancedFileRegressionFixture, cli_runner: CliRunner, ): @click_group(cls=consolekit.commands.RawHelpGroup) def demo() -> None: """ This is the summary line. This **program** does *the* ``following``: * This * That * ~~The other~~ (deprecated) """ @demo.command(cls=consolekit.commands.RawHelpCommand) def foo() -> None: """ This is the summary line. This **program** does *the* ``following``: * This * That * ~~The other~~ (deprecated) """ result = cli_runner.invoke(demo, args=["--help"]) result.check_stdout(advanced_file_regression, extension="_group.md") result = cli_runner.invoke(foo, args=["--help"]) result.check_stdout(advanced_file_regression, extension="_command.md") @pytest.mark.usefixtures("force_not_pycharm") @not_windows("Windows support for bold and italics is non-existent.") def test_markdown_help_command( advanced_file_regression: AdvancedFileRegressionFixture, markdown_demo_command: click.Command, cli_runner: CliRunner, ): result = cli_runner.invoke(markdown_demo_command, args=["--help"], color=True) result.check_stdout(advanced_file_regression, extension=".md") @pytest.mark.usefixtures("force_not_pycharm") def test_markdown_help_command_no_help( advanced_file_regression: AdvancedFileRegressionFixture, cli_runner: CliRunner, ): @click_command(cls=consolekit.commands.MarkdownHelpCommand) def helpless_demo() -> None: pass result = cli_runner.invoke(helpless_demo, args=["--help"], color=True) result.check_stdout(advanced_file_regression, extension=".md") @pytest.mark.usefixtures("force_not_pycharm") @not_windows("Windows support for bold and italics is non-existent.") def test_markdown_help_group( advanced_file_regression: AdvancedFileRegressionFixture, markdown_demo_group: Tuple[click.Command, click.Command], cli_runner: CliRunner, ): demo_group, demo_command = markdown_demo_group result = cli_runner.invoke(demo_group, args=["--help"], color=True) result.check_stdout(advanced_file_regression, extension="_group.md") result = cli_runner.invoke(demo_command, args=["--help"], color=True) result.check_stdout(advanced_file_regression, extension="_command.md") @pytest.mark.usefixtures("force_not_pycharm") @not_windows("Windows support for bold and italics is non-existent.") def test_markdown_help_command_ordered_list( advanced_file_regression: AdvancedFileRegressionFixture, cli_runner: CliRunner, ): @click_command(cls=consolekit.commands.MarkdownHelpCommand) def demo() -> None: """ This is the summary line. This **program** does *the* ``following``: 1. This 2. That 3. ~~The other~~ (deprecated) """ result = cli_runner.invoke(demo, args=["--help"], color=True) result.check_stdout(advanced_file_regression, extension=".md") @not_windows("Windows support for bold and italics is non-existent.") def test_markdown_help_command_pycharm( advanced_file_regression: AdvancedFileRegressionFixture, monkeypatch, markdown_demo_command: click.Command, cli_runner: CliRunner, ): monkeypatch.setenv("PYCHARM_HOSTED", '1') monkeypatch.setattr(consolekit.utils, "_pycharm_terminal", lambda: False) result = cli_runner.invoke(markdown_demo_command, args=["--help"], color=True) result.check_stdout(advanced_file_regression, extension=".md") def test_private_helper(monkeypatch): monkeypatch.setenv("PYCHARM_HOSTED", '1') assert not consolekit.utils._pycharm_terminal() @pytest.mark.usefixtures("force_not_pycharm") def test_markdown_help_command_no_colour( advanced_file_regression: AdvancedFileRegressionFixture, markdown_demo_command_numbered: click.Command, cli_runner: CliRunner, monkeypatch, ): result = cli_runner.invoke(markdown_demo_command_numbered, args=["--help", "--no-colour"], color=True) result.check_stdout(advanced_file_regression, extension=".md") # Again with envvar monkeypatch.setenv("NO_COLOR", '1') result = cli_runner.invoke(markdown_demo_command_numbered, args=["--help"], color=True) result.check_stdout(advanced_file_regression, extension=".md") @pytest.mark.usefixtures("force_not_pycharm") def test_markdown_help_no_args_is_help( advanced_file_regression: AdvancedFileRegressionFixture, markdown_demo_command_numbered: click.Command, cli_runner: CliRunner, ): result = cli_runner.invoke(markdown_demo_command_numbered) result.check_stdout(advanced_file_regression, extension=".md") assert result.exit_code == 0 @pytest.mark.usefixtures("force_not_pycharm") def test_markdown_help_group_no_args_is_help( advanced_file_regression: AdvancedFileRegressionFixture, markdown_demo_group: Tuple[click.Command, click.Command], cli_runner: CliRunner, ): result = cli_runner.invoke(markdown_demo_group[0]) result.check_stdout(advanced_file_regression, extension=".md") assert result.exit_code == 0 def test_suggestion_group( advanced_file_regression: AdvancedFileRegressionFixture, cli_runner: CliRunner, ): @click_group(context_settings={**CONTEXT_SETTINGS, "token_normalize_func": lambda x: x.lower()}) def demo() -> None: """ A program. """ @demo.command() # skipcq def search() -> None: """ Conduct a search. """ result = cli_runner.invoke(demo, args=["searh"]) result.check_stdout(advanced_file_regression, extension="_success.md") assert result.exit_code == 2 result = cli_runner.invoke(demo, args=["list"]) result.check_stdout(advanced_file_regression, extension="_failure.md") assert result.exit_code == 2 result = cli_runner.invoke(demo, args=["SEARCH"]) assert not result.stdout.rstrip() assert result.exit_code == 0 def test_context_inheriting_group( advanced_file_regression: AdvancedFileRegressionFixture, cli_runner: CliRunner, ): @click_group(cls=consolekit.commands.ContextInheritingGroup) def demo() -> None: """ A program. """ @demo.command() def search() -> None: """ Conduct a search. """ @demo.group() def foo() -> None: """ Does bar. """ result = cli_runner.invoke(demo, args=["--help"]) assert result.exit_code == 0 result = cli_runner.invoke(demo, args=["-h"]) assert result.exit_code == 0 result.check_stdout(advanced_file_regression, extension=".md") result = cli_runner.invoke(foo, args=["--help"]) assert result.exit_code == 0 result = cli_runner.invoke(foo, args=["-h"]) assert result.exit_code == 0 result.check_stdout(advanced_file_regression, extension="_foo.md") result = cli_runner.invoke(search, args=["--help"]) assert result.exit_code == 0 result = cli_runner.invoke(search, args=["-h"]) assert result.exit_code == 0 result.check_stdout(advanced_file_regression, extension="_search.md") consolekit-1.7.1/tests/test_commands_/000077500000000000000000000000001465042170600200405ustar00rootroot00000000000000consolekit-1.7.1/tests/test_commands_/test_context_inheriting_group.md000066400000000000000000000002451465042170600265420ustar00rootroot00000000000000Usage: demo [OPTIONS] COMMAND [ARGS]... A program. Options: -h, --help Show this message and exit. Commands: foo Does bar. search Conduct a search. consolekit-1.7.1/tests/test_commands_/test_context_inheriting_group_foo.md000066400000000000000000000001501465042170600274000ustar00rootroot00000000000000Usage: foo [OPTIONS] COMMAND [ARGS]... Does bar. Options: -h, --help Show this message and exit. consolekit-1.7.1/tests/test_commands_/test_context_inheriting_group_search.md000066400000000000000000000001411465042170600300620ustar00rootroot00000000000000Usage: search [OPTIONS] Conduct a search. Options: -h, --help Show this message and exit. consolekit-1.7.1/tests/test_commands_/test_markdown_help_command.md000066400000000000000000000003721465042170600257530ustar00rootroot00000000000000Usage: demo [OPTIONS] This is the summary line. This program does the 'following': * This * That * T̶h̶e̶ ̶o̶t̶h̶e̶r̶ (deprecated) A multiline paragraph Options: -h, --help Show this message and exit. consolekit-1.7.1/tests/test_commands_/test_markdown_help_command_no_colour.md000066400000000000000000000004061465042170600300300ustar00rootroot00000000000000Usage: demo [OPTIONS] This is the summary line. This program does the 'following': 1. This 2. That 3. The other (deprecated) Options: --colour / --no-colour Whether to use coloured output. -h, --help Show this message and exit. consolekit-1.7.1/tests/test_commands_/test_markdown_help_command_no_help.md000066400000000000000000000001231465042170600274510ustar00rootroot00000000000000Usage: helpless-demo [OPTIONS] Options: -h, --help Show this message and exit. consolekit-1.7.1/tests/test_commands_/test_markdown_help_command_ordered_list.md000066400000000000000000000003441465042170600305110ustar00rootroot00000000000000Usage: demo [OPTIONS] This is the summary line. This program does the 'following': 1. This 2. That 3. T̶h̶e̶ ̶o̶t̶h̶e̶r̶ (deprecated) Options: -h, --help Show this message and exit. consolekit-1.7.1/tests/test_commands_/test_markdown_help_command_pycharm.md000066400000000000000000000003501465042170600274720ustar00rootroot00000000000000Usage: demo [OPTIONS] This is the summary line. This program does 𝘵𝘩𝘦 'following': * This * That * The other (deprecated) A multiline paragraph Options: -h, --help Show this message and exit. consolekit-1.7.1/tests/test_commands_/test_markdown_help_group_command.md000066400000000000000000000003341465042170600271650ustar00rootroot00000000000000Usage: foo [OPTIONS] This is the summary line. This program does the 'following': * This * That * T̶h̶e̶ ̶o̶t̶h̶e̶r̶ (deprecated) Options: --help Show this message and exit. consolekit-1.7.1/tests/test_commands_/test_markdown_help_group_group.md000066400000000000000000000004371465042170600267070ustar00rootroot00000000000000Usage: demo [OPTIONS] COMMAND [ARGS]... This is the summary line. This program does the 'following': * This * That * T̶h̶e̶ ̶o̶t̶h̶e̶r̶ (deprecated) Options: -h, --help Show this message and exit. Commands: foo This is the summary line. consolekit-1.7.1/tests/test_commands_/test_markdown_help_group_no_args_is_help.md000066400000000000000000000004151465042170600307020ustar00rootroot00000000000000Usage: demo [OPTIONS] COMMAND [ARGS]... This is the summary line. This program does the 'following': * This * That * T̶h̶e̶ ̶o̶t̶h̶e̶r̶ (deprecated) Options: -h, --help Show this message and exit. Commands: foo This is the summary line. consolekit-1.7.1/tests/test_commands_/test_markdown_help_no_args_is_help.md000066400000000000000000000004301465042170600274630ustar00rootroot00000000000000Usage: demo [OPTIONS] This is the summary line. This program does the 'following': 1. This 2. That 3. T̶h̶e̶ ̶o̶t̶h̶e̶r̶ (deprecated) Options: --colour / --no-colour Whether to use coloured output. -h, --help Show this message and exit. consolekit-1.7.1/tests/test_commands_/test_raw_help_command.helpless.md000066400000000000000000000001231465042170600265320ustar00rootroot00000000000000Usage: helpless-demo [OPTIONS] Options: -h, --help Show this message and exit. consolekit-1.7.1/tests/test_commands_/test_raw_help_command.md000066400000000000000000000003071465042170600247200ustar00rootroot00000000000000Usage: demo [OPTIONS] This is the summary line. This **program** does *the* ``following``: * This * That * ~~The other~~ (deprecated) Options: -h, --help Show this message and exit. consolekit-1.7.1/tests/test_commands_/test_raw_help_group_command.md000066400000000000000000000003021465042170600261270ustar00rootroot00000000000000Usage: foo [OPTIONS] This is the summary line. This **program** does *the* ``following``: * This * That * ~~The other~~ (deprecated) Options: --help Show this message and exit. consolekit-1.7.1/tests/test_commands_/test_raw_help_group_group.md000066400000000000000000000004051465042170600256510ustar00rootroot00000000000000Usage: demo [OPTIONS] COMMAND [ARGS]... This is the summary line. This **program** does *the* ``following``: * This * That * ~~The other~~ (deprecated) Options: -h, --help Show this message and exit. Commands: foo This is the summary line. consolekit-1.7.1/tests/test_commands_/test_suggestion_group_caps.md000066400000000000000000000001421465042170600260270ustar00rootroot00000000000000Usage: demo [OPTIONS] COMMAND [ARGS]... Try 'demo -h' for help. Error: No such command 'SEARCH'. consolekit-1.7.1/tests/test_commands_/test_suggestion_group_failure.md000066400000000000000000000001401465042170600265260ustar00rootroot00000000000000Usage: demo [OPTIONS] COMMAND [ARGS]... Try 'demo -h' for help. Error: No such command 'list'. consolekit-1.7.1/tests/test_commands_/test_suggestion_group_success.md000066400000000000000000000002071465042170600265530ustar00rootroot00000000000000Usage: demo [OPTIONS] COMMAND [ARGS]... Try 'demo -h' for help. Error: No such command 'searh'. The most similar command is 'search'. consolekit-1.7.1/tests/test_diff_/000077500000000000000000000000001465042170600171475ustar00rootroot00000000000000consolekit-1.7.1/tests/test_diff_/modified000066400000000000000000000005101465042170600206460ustar00rootroot00000000000000Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat, lectus et interdum feugiat, magna enim vestibulum diam, a ultrices urna odio at magna. Quisque ut ullamcorper justo. Integer lobortis eros eget diam varius eleifend. Donec ornare nisi vel purus aliquet consequat. Ut quis ipsum et nunc sodales tristique. consolekit-1.7.1/tests/test_diff_/original000066400000000000000000000006521465042170600207010ustar00rootroot00000000000000Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat, lectus et interdum feugiat, magna enim vestibulum diam, a ultrices urna odio at magna. Quisque ut ullamcorper justo. Suspendisse ac tincidunt velit. Integer lobortis eros eget diam varius eleifend. Donec ornare nisi vel purus aliquet consequat. Ut quis ipsum et nunc sodales tristique. Maecenas justo libero, semper eget feugiat et, aliquam et mauris. consolekit-1.7.1/tests/test_input.py000066400000000000000000000125511465042170600176150ustar00rootroot00000000000000# stdlib from typing import Type # 3rd party import click import pytest from click import echo from coincidence.regressions import AdvancedDataRegressionFixture from domdf_python_tools.stringlist import StringList # this package from consolekit.input import choice, confirm, prompt from consolekit.testing import _click_major def test_choice_letters( capsys, monkeypatch, advanced_data_regression: AdvancedDataRegressionFixture, ): inputs = iter(['F', 'G', 'D']) def fake_input(prompt: str) -> str: value = next(inputs) print(f"{prompt}{value}".rstrip()) return value monkeypatch.setattr(click.termui, "visible_prompt_func", fake_input) echo("Configuration file '/etc/sudoers'") echo("==> Modified (by you or by a script) since installation.") echo("==> Package distributor has shipped an updated version.") echo("What would you like to do about it ? Your options are:") options = { 'Y': "install the package maintainer's version", 'N': "keep your currently-installed version", 'D': "show the differences between the versions", 'Z': "start a shell to examine the situation" } assert choice(text="*** sudoers", options=options, default='N') == 'D' advanced_data_regression.check(list(StringList(capsys.readouterr().out.splitlines()))) @pytest.mark.parametrize( "click_version", [ pytest.param( '7', marks=pytest.mark.skipif(_click_major == 8, reason="Output differs on click 8"), ), pytest.param( '8', marks=pytest.mark.skipif(_click_major != 8, reason="Output differs on click 8"), ), ] ) def test_choice_numbers( capsys, monkeypatch, advanced_data_regression: AdvancedDataRegressionFixture, click_version: str, ): inputs = iter(["20", '0', '5']) def fake_input(prompt: str) -> str: value = next(inputs) print(f"{prompt}{value}".rstrip()) return value monkeypatch.setattr(click.termui, "visible_prompt_func", fake_input) echo("What is the Development Status of this project?") options = [ "Planning", "Pre-Alpha", "Alpha", "Beta", "Production/Stable", "Mature", "Inactive", ] assert choice(text='', options=options, start_index=1) == 4 advanced_data_regression.check(list(StringList(capsys.readouterr().out.splitlines()))) def test_confirm( capsys, monkeypatch, advanced_data_regression: AdvancedDataRegressionFixture, ): inputs = iter(['Y', 'N', '', '', "yEs", "No", "gkjhkhjv", '']) def fake_input(prompt: str) -> str: value = next(inputs) print(f"{prompt}{value}".rstrip()) return value monkeypatch.setattr(click.termui, "visible_prompt_func", fake_input) assert confirm(text="Do you wish to delete all files in '/' ?", default=False) is True assert confirm(text="Do you wish to delete all files in '/' ?", default=False) is False assert confirm(text="Do you wish to delete all files in '/' ?", default=False) is False assert confirm(text="Do you wish to delete all files in '/' ?", default=True) is True assert confirm(text="Do you wish to delete all files in '/' ?", default=False) is True assert confirm(text="Do you wish to delete all files in '/' ?", default=True) is False assert confirm(text="Do you wish to delete all files in '/' ?", default=True) is True advanced_data_regression.check(list(StringList(capsys.readouterr().out.splitlines()))) def test_prompt( capsys, monkeypatch, advanced_data_regression: AdvancedDataRegressionFixture, ): inputs = iter([ '', '', '', '', "24", "Bond007", "badpassword", "baspassword", "badpassword", "badpassword", "badpassword", "badpassword", ]) def fake_input(prompt: str) -> str: value = next(inputs) print(f"{prompt}{value}".rstrip()) return value monkeypatch.setattr(click.termui, "visible_prompt_func", fake_input) assert prompt(text="What is your age", prompt_suffix="? ", type=click.INT) == 24 assert prompt(text="Username", type=click.STRING) == "Bond007" assert prompt(text="Password", type=click.STRING, confirmation_prompt=True) == "badpassword" assert prompt( text="Password", type=click.STRING, confirmation_prompt="Are you sure about that? ", ) == "badpassword" advanced_data_regression.check(list(StringList(capsys.readouterr().out.splitlines()))) @pytest.mark.parametrize("exception", [KeyboardInterrupt, EOFError]) def test_prompt_abort( capsys, monkeypatch, advanced_data_regression: AdvancedDataRegressionFixture, exception: Type[Exception], ): def fake_input(prompt: str) -> str: print(f"{prompt}", end='') raise exception monkeypatch.setattr(click.termui, "visible_prompt_func", fake_input) with pytest.raises(click.Abort, match="^$"): prompt(text="Password", type=click.STRING, confirmation_prompt=True) assert list(StringList(capsys.readouterr().out.splitlines())) == ["Password:"] @pytest.mark.parametrize("exception", [KeyboardInterrupt, EOFError]) def test_confirm_abort( capsys, monkeypatch, advanced_data_regression: AdvancedDataRegressionFixture, exception: Type[Exception], ): def fake_input(prompt: str) -> str: print(f"{prompt}", end='') raise exception monkeypatch.setattr(click.termui, "visible_prompt_func", fake_input) with pytest.raises(click.Abort, match="^$"): confirm(text="Do you wish to delete all files in '/' ?", default=False) expected = ["Do you wish to delete all files in '/' ? [y/N]:"] assert list(StringList(capsys.readouterr().out.splitlines())) == expected consolekit-1.7.1/tests/test_input_/000077500000000000000000000000001465042170600173765ustar00rootroot00000000000000consolekit-1.7.1/tests/test_input_/test_choice_letters.yml000066400000000000000000000011231465042170600241510ustar00rootroot00000000000000- Configuration file '/etc/sudoers' - ==> Modified (by you or by a script) since installation. - ==> Package distributor has shipped an updated version. - 'What would you like to do about it ? Your options are:' - ' Y : install the package maintainer''s version' - ' N : keep your currently-installed version' - ' D : show the differences between the versions' - ' Z : start a shell to examine the situation' - '*** sudoers (Y/N/D/Z) [default=N]: F' - Please enter a valid option. - '*** sudoers (Y/N/D/Z) [default=N]: G' - Please enter a valid option. - '*** sudoers (Y/N/D/Z) [default=N]: D' consolekit-1.7.1/tests/test_input_/test_choice_numbers_7_.yml000066400000000000000000000004571465042170600245400ustar00rootroot00000000000000- What is the Development Status of this project? - ' [1] Planning' - ' [2] Pre-Alpha' - ' [3] Alpha' - ' [4] Beta' - ' [5] Production/Stable' - ' [6] Mature' - ' [7] Inactive' - ': 20' - 'Error: 20 is not in the valid range of 1 to 7.' - ': 0' - 'Error: 0 is not in the valid range of 1 to 7.' - ': 5' consolekit-1.7.1/tests/test_input_/test_choice_numbers_8_.yml000066400000000000000000000004371465042170600245370ustar00rootroot00000000000000- What is the Development Status of this project? - ' [1] Planning' - ' [2] Pre-Alpha' - ' [3] Alpha' - ' [4] Beta' - ' [5] Production/Stable' - ' [6] Mature' - ' [7] Inactive' - ': 20' - 'Error: 20 is not in the range 1<=x<=7.' - ': 0' - 'Error: 0 is not in the range 1<=x<=7.' - ': 5' consolekit-1.7.1/tests/test_input_/test_confirm.yml000066400000000000000000000007351465042170600226220ustar00rootroot00000000000000- 'Do you wish to delete all files in ''/'' ? [y/N]: Y' - 'Do you wish to delete all files in ''/'' ? [y/N]: N' - 'Do you wish to delete all files in ''/'' ? [y/N]:' - 'Do you wish to delete all files in ''/'' ? [Y/n]:' - 'Do you wish to delete all files in ''/'' ? [y/N]: yEs' - 'Do you wish to delete all files in ''/'' ? [Y/n]: No' - 'Do you wish to delete all files in ''/'' ? [Y/n]: gkjhkhjv' - 'Error: invalid input' - 'Do you wish to delete all files in ''/'' ? [Y/n]:' consolekit-1.7.1/tests/test_input_/test_prompt.yml000066400000000000000000000005631465042170600225050ustar00rootroot00000000000000- What is your age? - What is your age? - What is your age? - What is your age? - What is your age? 24 - 'Username: Bond007' - 'Password: badpassword' - 'Repeat for confirmation: baspassword' - 'Error: the two entered values do not match' - 'Password: badpassword' - 'Repeat for confirmation: badpassword' - 'Password: badpassword' - Are you sure about that? badpassword consolekit-1.7.1/tests/test_options.py000066400000000000000000000202271465042170600201500ustar00rootroot00000000000000# stdlib import sys from typing import Iterable # 3rd party import click from pytest_regressions.file_regression import FileRegressionFixture # this package from consolekit import click_command from consolekit.options import ( DescribedArgument, MultiValueOption, auto_default_argument, auto_default_option, colour_option, flag_option, force_option, no_pager_option, verbose_option, version_option ) from consolekit.terminal_colours import ColourTrilean from consolekit.testing import CliRunner, Result def test_described_argument( file_regression: FileRegressionFixture, cli_runner: CliRunner, ): @click.argument( "dest", cls=DescribedArgument, type=click.STRING, description="The destination directory.", ) @click_command() def main(dest: str) -> None: print(dest) result = cli_runner.invoke(main, args="--help") result.check_stdout(file_regression, extension=".md") assert result.exit_code == 0 result = cli_runner.invoke(main, catch_exceptions=False, args="./staging") assert result.stdout.rstrip() == "./staging" assert result.exit_code == 0 ctx = click.Context(main, info_name="main", parent=None) argument = ctx.command.params[0] assert isinstance(argument, DescribedArgument) assert argument.description == "The destination directory." def test_auto_default_option( file_regression: FileRegressionFixture, cli_runner: CliRunner, ): @auto_default_option( "--width", type=click.INT, help="The max width to display.", show_default=True, ) @click_command() def main(width: int = 80) -> None: print(width) argument = main.params[0] assert argument.default == 80 assert not argument.required assert argument.show_default # type: ignore[attr-defined] result = cli_runner.invoke(main, args="--help") result.check_stdout(file_regression, extension=".md") assert result.exit_code == 0 result = cli_runner.invoke(main, catch_exceptions=False) assert result.stdout.rstrip() == "80" assert result.exit_code == 0 for width in [0, 8, 36, 48, 130]: result = cli_runner.invoke(main, args=["--width", str(width)]) assert result.stdout.rstrip() == str(width) assert result.exit_code == 0 def test_flag_option(cli_runner: CliRunner): @flag_option("--no-colour") @click_command() def main(no_colour: bool) -> None: print(no_colour) result = cli_runner.invoke(main, catch_exceptions=False) assert result.stdout.rstrip() == "False" assert result.exit_code == 0 result = cli_runner.invoke(main, args="--no-colour") assert result.stdout.rstrip() == "True" assert result.exit_code == 0 def test_no_pager_option(file_regression: FileRegressionFixture, cli_runner: CliRunner): @no_pager_option() @click_command() def main(no_pager: bool) -> None: print(no_pager) result = cli_runner.invoke(main, catch_exceptions=False) assert result.stdout.rstrip() == "False" assert result.exit_code == 0 result = cli_runner.invoke(main, args="--no-pager") assert result.stdout.rstrip() == "True" assert result.exit_code == 0 result = cli_runner.invoke(main, args="-h") result.check_stdout(file_regression) assert result.exit_code == 0 def test_force_option(file_regression: FileRegressionFixture, cli_runner: CliRunner): @force_option("Force the operation") @click_command() def main(force: bool) -> None: print(force) result = cli_runner.invoke(main, catch_exceptions=False) assert result.stdout.rstrip() == "False" assert result.exit_code == 0 result = cli_runner.invoke(main, args="--force") assert result.stdout.rstrip() == "True" assert result.exit_code == 0 result = cli_runner.invoke(main, args="-f") assert result.stdout.rstrip() == "True" assert result.exit_code == 0 result = cli_runner.invoke(main, args="-h") result.check_stdout(file_regression) assert result.exit_code == 0 def test_verbose_option(file_regression: FileRegressionFixture, cli_runner: CliRunner): @verbose_option("Show verbose output.") @click_command() def main(verbose: int) -> None: print(verbose) result = cli_runner.invoke(main) assert result.stdout.rstrip() == '0' assert result.exit_code == 0 result = cli_runner.invoke(main, args="--verbose") assert result.stdout.rstrip() == '1' assert result.exit_code == 0 result = cli_runner.invoke(main, args="-v") assert result.stdout.rstrip() == '1' assert result.exit_code == 0 result = cli_runner.invoke(main, args=["--verbose", "--verbose"]) assert result.stdout.rstrip() == '2' assert result.exit_code == 0 result = cli_runner.invoke(main, args="-vv") assert result.stdout.rstrip() == '2' assert result.exit_code == 0 result = cli_runner.invoke(main, args="-vvv") assert result.stdout.rstrip() == '3' assert result.exit_code == 0 result = cli_runner.invoke(main, args="-h") result.check_stdout(file_regression) assert result.exit_code == 0 def test_colour_option(file_regression: FileRegressionFixture, cli_runner: CliRunner): @colour_option() @click_command() def main(colour: ColourTrilean) -> None: print(colour) result = cli_runner.invoke(main, catch_exceptions=False) assert result.stdout.rstrip() == "None" assert result.exit_code == 0 result = cli_runner.invoke(main, args="--no-colour") assert result.stdout.rstrip() == "False" assert result.exit_code == 0 result = cli_runner.invoke(main, args="--colour") assert result.stdout.rstrip() == "True" assert result.exit_code == 0 result = cli_runner.invoke(main, args="-h") result.check_stdout(file_regression) assert result.exit_code == 0 def test_version_option(file_regression: FileRegressionFixture, cli_runner: CliRunner): def version_callback(ctx: click.Context, param: click.Option, value: int) -> None: if not value or ctx.resilient_parsing: return if value > 1: click.echo("consolekit version 1.2.3, Python 3.8.5") else: click.echo("consolekit version 1.2.3") ctx.exit() @version_option(version_callback) @click_command() def main() -> None: sys.exit(1) result = cli_runner.invoke(main, args="--version") assert result.stdout.rstrip() == "consolekit version 1.2.3" assert result.exit_code == 0 result = cli_runner.invoke(main, args=["--version", "--version"]) assert result.stdout.rstrip() == "consolekit version 1.2.3, Python 3.8.5" assert result.exit_code == 0 def test_multi_value_option(cli_runner: CliRunner): @click.option( "--select", type=click.STRING, help="The checks to enable", cls=MultiValueOption, ) @colour_option() @click_command() def main(select: Iterable[str], colour: bool) -> None: select = list(select) print(*select) print(", ".join(select)) result: Result = cli_runner.invoke(main, catch_exceptions=False) assert result.stdout.rstrip() == '' assert result.exit_code == 0 result = cli_runner.invoke(main, args=["--select", "E102", "F223"]) assert result.stdout.rstrip() == "E102 F223\nE102, F223" assert result.exit_code == 0 result = cli_runner.invoke(main, args=["--select", "E102", "F223", "--colour"]) assert result.stdout.rstrip() == "E102 F223\nE102, F223" assert result.exit_code == 0 result = cli_runner.invoke(main, args=["--select", "E102"]) assert result.stdout.rstrip() == "E102\nE102" assert result.exit_code == 0 def test_multi_value_option_int(cli_runner: CliRunner): @click.option("--value", help="Some values", cls=MultiValueOption, type=int, default=(1, 2, 3)) @colour_option() @click_command() def main(value: Iterable[int], colour: bool) -> None: print(value) result: Result = cli_runner.invoke(main, catch_exceptions=False) assert result.stdout.rstrip() == "(1, 2, 3)" assert result.exit_code == 0 result = cli_runner.invoke(main, args=["--value", '4', '5', '6']) assert result.stdout.rstrip() == "(4, 5, 6)" assert result.exit_code == 0 def test_auto_default_argument(cli_runner: CliRunner): @auto_default_argument( "greeting", type=click.STRING, ) @click_command() def main(greeting: str = "Hello") -> None: print(f"{greeting} User!") argument = main.params[0] assert argument.default == "Hello" assert not argument.required result = cli_runner.invoke(main) assert result.stdout.rstrip() == "Hello User!" assert result.exit_code == 0 result = cli_runner.invoke(main, args=["Good Morning"]) assert result.stdout.rstrip() == "Good Morning User!" assert result.exit_code == 0 consolekit-1.7.1/tests/test_options_/000077500000000000000000000000001465042170600177325ustar00rootroot00000000000000consolekit-1.7.1/tests/test_options_/test_auto_default_option.md000066400000000000000000000002131465042170600253530ustar00rootroot00000000000000Usage: main [OPTIONS] Options: --width INTEGER The max width to display. [default: 80] -h, --help Show this message and exit. consolekit-1.7.1/tests/test_options_/test_colour_option.txt000066400000000000000000000002201465042170600244170ustar00rootroot00000000000000Usage: main [OPTIONS] Options: --colour / --no-colour Whether to use coloured output. -h, --help Show this message and exit. consolekit-1.7.1/tests/test_options_/test_described_argument.md000066400000000000000000000001171465042170600251400ustar00rootroot00000000000000Usage: main [OPTIONS] DEST Options: -h, --help Show this message and exit. consolekit-1.7.1/tests/test_options_/test_force_option.txt000066400000000000000000000001561465042170600242220ustar00rootroot00000000000000Usage: main [OPTIONS] Options: -f, --force Force the operation -h, --help Show this message and exit. consolekit-1.7.1/tests/test_options_/test_no_pager_option.txt000066400000000000000000000001621465042170600247130ustar00rootroot00000000000000Usage: main [OPTIONS] Options: --no-pager Disable the output pager. -h, --help Show this message and exit. consolekit-1.7.1/tests/test_options_/test_verbose_option.txt000066400000000000000000000001631465042170600245670ustar00rootroot00000000000000Usage: main [OPTIONS] Options: -v, --verbose Show verbose output. -h, --help Show this message and exit. consolekit-1.7.1/tests/test_terminal_colours.py000066400000000000000000000100661465042170600220360ustar00rootroot00000000000000# stdlib from collections import deque # 3rd party from coincidence.regressions import AdvancedFileRegressionFixture, check_file_regression # this package from consolekit import terminal_colours from consolekit.terminal_colours import Colour, print_256_colour_testpattern, strip_ansi def test_terminal_colours_constants(): assert terminal_colours.CSI == "\u001b[" assert terminal_colours.OSC == "\u001b]" assert terminal_colours.BEL == '\x07' def test_terminal_colours_stacks(): assert terminal_colours.fore_stack == deque([terminal_colours.Fore.RESET]) assert terminal_colours.back_stack == deque([terminal_colours.Back.RESET]) assert terminal_colours.style_stack == deque([terminal_colours.Style.NORMAL]) def test_terminal_colours_functions(): assert terminal_colours.set_title("Foo") == "\u001b]2;Foo\u0007" # assert terminal_colours.clear_screen() == "\033[2J" # assert terminal_colours.clear_screen(1) == "\033[1J" assert terminal_colours.clear_line() == "\u001b[2K" assert terminal_colours.clear_line(1) == "\u001b[1K" def test_ansi_cursor(): assert terminal_colours.Cursor.UP() == "\u001b[1A" assert terminal_colours.Cursor.UP(1) == "\u001b[1A" assert terminal_colours.Cursor.UP(2) == "\u001b[2A" assert terminal_colours.Cursor.UP(3) == "\u001b[3A" assert terminal_colours.Cursor.DOWN() == "\u001b[1B" assert terminal_colours.Cursor.DOWN(1) == "\u001b[1B" assert terminal_colours.Cursor.DOWN(2) == "\u001b[2B" assert terminal_colours.Cursor.DOWN(3) == "\u001b[3B" assert terminal_colours.Cursor.FORWARD() == "\u001b[1C" assert terminal_colours.Cursor.FORWARD(1) == "\u001b[1C" assert terminal_colours.Cursor.FORWARD(2) == "\u001b[2C" assert terminal_colours.Cursor.FORWARD(3) == "\u001b[3C" assert terminal_colours.Cursor.BACK() == "\u001b[1D" assert terminal_colours.Cursor.BACK(1) == "\u001b[1D" assert terminal_colours.Cursor.BACK(2) == "\u001b[2D" assert terminal_colours.Cursor.BACK(3) == "\u001b[3D" assert terminal_colours.Cursor.POS() == "\u001b[1;1H" assert terminal_colours.Cursor.POS(1) == "\u001b[1;1H" assert terminal_colours.Cursor.POS(2) == "\u001b[1;2H" assert terminal_colours.Cursor.POS(3) == "\u001b[1;3H" assert terminal_colours.Cursor.POS(y=1) == "\u001b[1;1H" assert terminal_colours.Cursor.POS(y=2) == "\u001b[2;1H" assert terminal_colours.Cursor.POS(y=3) == "\u001b[3;1H" assert terminal_colours.Cursor.POS(x=1) == "\u001b[1;1H" assert terminal_colours.Cursor.POS(x=2) == "\u001b[1;2H" assert terminal_colours.Cursor.POS(x=3) == "\u001b[1;3H" assert terminal_colours.Cursor.POS(1, 1) == "\u001b[1;1H" assert terminal_colours.Cursor.POS(2, 2) == "\u001b[2;2H" assert terminal_colours.Cursor.POS(3, 3) == "\u001b[3;3H" assert terminal_colours.Cursor.POS(x=2, y=3) == "\u001b[3;2H" class TestColour: def test_from_code(self): black = Colour.from_code(30) assert black == "\u001b[30m" assert black("Hello") == "\u001b[30mHello\u001b[39m" black = Colour.from_code(40, background=True) assert black == "\u001b[40m" assert black("Hello") == "\u001b[40mHello\u001b[49m" def test_from_rgb(self): yellow = Colour.from_rgb(252, 186, 3) assert yellow == "\u001b[38;2;252;186;3m" assert yellow("Hello") == "\u001b[38;2;252;186;3mHello\u001b[39m" yellow = Colour.from_rgb(252, 186, 3, background=True) assert yellow == "\u001b[48;2;252;186;3m" assert yellow("Hello") == "\u001b[48;2;252;186;3mHello\u001b[49m" def test_from_hex(self): yellow = Colour.from_hex("#fcba03") assert yellow == "\u001b[38;2;252;186;3m" assert yellow("Hello") == "\u001b[38;2;252;186;3mHello\u001b[39m" yellow = Colour.from_hex("#fcba03", background=True) assert yellow == "\u001b[48;2;252;186;3m" assert yellow("Hello") == "\u001b[48;2;252;186;3mHello\u001b[49m" def test_print_256_colour_testpattern( monkeypatch, advanced_file_regression: AdvancedFileRegressionFixture, capsys, ): monkeypatch.setattr(terminal_colours, "resolve_color_default", lambda *args: False) # Checks only the structure, not the colours print_256_colour_testpattern() check_file_regression(strip_ansi(capsys.readouterr().out.strip()), advanced_file_regression) consolekit-1.7.1/tests/test_terminal_colours_/000077500000000000000000000000001465042170600216205ustar00rootroot00000000000000consolekit-1.7.1/tests/test_terminal_colours_/test_print_256_colour_testpattern.txt000066400000000000000000000030561465042170600311740ustar00rootroot00000000000000----------------------------Standard Colours--------------------------- -------------------------High-Intensity Colours------------------------ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ------------------------------------------------------------------216 Colours------------------------------------------------------------------ 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 ---------------------------------------------------------------Greyscale Colours--------------------------------------------------------------- 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 consolekit-1.7.1/tests/test_terminal_colours_colorama.py000066400000000000000000000123661465042170600237200ustar00rootroot00000000000000# From https://github.com/tartley/colorama # Copyright Jonathan Hartley 2013 # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # * Neither the name of the copyright holders, nor those of its contributors # may be used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # stdlib import sys # 3rd party import pytest # this package from consolekit.terminal_colours import Back, Colour, Fore, Style stdout_orig = sys.stdout stderr_orig = sys.stderr colorama = pytest.importorskip("colorama") AnsiToWin32 = colorama.ansitowin32.AnsiToWin32 def setup_module() -> None: # sanity check: stdout should be a file or StringIO object. # It will only be AnsiToWin32 if init() has previously wrapped it assert not isinstance(sys.stdout, AnsiToWin32) assert not isinstance(sys.stderr, AnsiToWin32) def teardown_module() -> None: sys.stdout = stdout_orig sys.stderr = stderr_orig @pytest.mark.parametrize( "obj, expects", [ (Fore.BLACK, "\u001b[30m"), (Fore.RED, "\u001b[31m"), (Fore.GREEN, "\u001b[32m"), (Fore.YELLOW, "\u001b[33m"), (Fore.BLUE, "\u001b[34m"), (Fore.MAGENTA, "\u001b[35m"), (Fore.CYAN, "\u001b[36m"), (Fore.WHITE, "\u001b[37m"), (Fore.RESET, "\u001b[39m"), # Check the light, extended versions. (Fore.LIGHTBLACK_EX, "\u001b[90m"), (Fore.LIGHTRED_EX, "\u001b[91m"), (Fore.LIGHTGREEN_EX, "\u001b[92m"), (Fore.LIGHTYELLOW_EX, "\u001b[93m"), (Fore.LIGHTBLUE_EX, "\u001b[94m"), (Fore.LIGHTMAGENTA_EX, "\u001b[95m"), (Fore.LIGHTCYAN_EX, "\u001b[96m"), (Fore.LIGHTWHITE_EX, "\u001b[97m"), ], ) def test_fore_attributes(obj: Colour, expects: str, capsys): assert obj == expects assert obj("Hello World") == f"{obj}Hello World\033[39m" with obj: print("Hello World!") with Fore.RESET: print("Reset!") print("Coloured Again!") print("Reset Again!") captured = capsys.readouterr() stdout = captured.out.split('\n') assert stdout[0] == f"{obj}Hello World!" assert stdout[1] == f"\033[39mReset!" assert stdout[2] == f"{obj}Coloured Again!" assert stdout[3] == f"\033[39mReset Again!" assert stdout[4] == '' @pytest.mark.parametrize( "obj, expects", [ (Back.BLACK, "\u001b[40m"), (Back.RED, "\u001b[41m"), (Back.GREEN, "\u001b[42m"), (Back.YELLOW, "\u001b[43m"), (Back.BLUE, "\u001b[44m"), (Back.MAGENTA, "\u001b[45m"), (Back.CYAN, "\u001b[46m"), (Back.WHITE, "\u001b[47m"), (Back.RESET, "\u001b[49m"), # Check the light, extended versions. (Back.LIGHTBLACK_EX, "\u001b[100m"), (Back.LIGHTRED_EX, "\u001b[101m"), (Back.LIGHTGREEN_EX, "\u001b[102m"), (Back.LIGHTYELLOW_EX, "\u001b[103m"), (Back.LIGHTBLUE_EX, "\u001b[104m"), (Back.LIGHTMAGENTA_EX, "\u001b[105m"), (Back.LIGHTCYAN_EX, "\u001b[106m"), (Back.LIGHTWHITE_EX, "\u001b[107m"), ], ) def test_back_attributes(obj: Colour, expects: str, capsys): assert obj == expects assert obj("Hello World") == f"{obj}Hello World\033[49m" with obj: print("Hello World!") with Back.RESET: print("Reset!") print("Coloured Again!") print("Reset Again!") captured = capsys.readouterr() stdout = captured.out.split('\n') assert stdout[0] == f"{obj}Hello World!" assert stdout[1] == f"\033[49mReset!" assert stdout[2] == f"{obj}Coloured Again!" assert stdout[3] == f"\033[49mReset Again!" assert stdout[4] == '' @pytest.mark.parametrize( "obj, expects", [ (Style.DIM, "\u001b[2m"), (Style.NORMAL, "\u001b[22m"), (Style.BRIGHT, "\u001b[1m"), ], ) def test_style_attributes(obj: Colour, expects: str, capsys): assert obj == expects assert obj("Hello World") == f"{obj}Hello World\033[22m" with obj: print("Hello World!") with Style.NORMAL: print("Reset!") print("Coloured Again!") print("Reset Again!") captured = capsys.readouterr() stdout = captured.out.split('\n') assert stdout[0] == f"{obj}Hello World!" assert stdout[1] == f"\033[22mReset!" assert stdout[2] == f"{obj}Coloured Again!" assert stdout[3] == f"\033[22mReset Again!" assert stdout[4] == '' consolekit-1.7.1/tests/test_testing.py000066400000000000000000000021061465042170600201260ustar00rootroot00000000000000# 3rd party import click # this package from consolekit import click_command from consolekit.options import DescribedArgument from consolekit.testing import CliRunner def test_result(cli_runner: CliRunner): @click.argument( "dest", cls=DescribedArgument, type=click.STRING, description="The destination directory.", ) @click_command() def main(dest: str) -> None: print(dest) result = cli_runner.invoke(main, catch_exceptions=False, args="./staging") assert result.stdout.rstrip() == "./staging" assert result.output.rstrip() == "./staging" assert result.exit_code == 0 def test_result_no_mix_stderr(): cli_runner = CliRunner(mix_stderr=False) @click.argument( "dest", cls=DescribedArgument, type=click.STRING, description="The destination directory.", ) @click_command() def main(dest: str) -> None: print(dest) result = cli_runner.invoke(main, catch_exceptions=False, args="./staging") assert result.stdout.rstrip() == "./staging" assert result.stderr == '' assert result.output.rstrip() == "./staging" assert result.exit_code == 0 consolekit-1.7.1/tests/test_tracebacks.py000066400000000000000000000131441465042170600205570ustar00rootroot00000000000000# stdlib import re from typing import Callable, ContextManager, Type # 3rd party import click import pytest from coincidence.regressions import AdvancedFileRegressionFixture from pytest_regressions.file_regression import FileRegressionFixture # this package from consolekit import click_command from consolekit.testing import CliRunner, Result, _click_major from consolekit.tracebacks import TracebackHandler, handle_tracebacks, traceback_handler, traceback_option exceptions = pytest.mark.parametrize( "exception", [ pytest.param(FileNotFoundError("foo.txt"), id="FileNotFoundError"), pytest.param(FileExistsError("foo.txt"), id="FileExistsError"), pytest.param(Exception("Something's awry!"), id="Exception"), pytest.param(ValueError("'age' must be >= 0"), id="ValueError"), pytest.param(TypeError("Expected type int, got type str"), id="TypeError"), pytest.param(NameError("name 'hello' is not defined"), id="NameError"), pytest.param(SyntaxError("invalid syntax"), id="SyntaxError"), ] ) contextmanagers = pytest.mark.parametrize( "contextmanager, exit_code", [ pytest.param(handle_tracebacks, 1, id="handle_tracebacks"), pytest.param(traceback_handler, 1, id="traceback_handler"), pytest.param(TracebackHandler(), 1, id="TracebackHandler"), pytest.param(TracebackHandler(SystemExit(1)), 1, id="TracebackHandler_SystemExit"), pytest.param(TracebackHandler(SystemExit(2)), 2, id="TracebackHandler_SystemExit_2"), ] ) @exceptions @contextmanagers def test_handle_tracebacks( exception: BaseException, contextmanager: Callable[..., ContextManager], exit_code: int, advanced_file_regression: AdvancedFileRegressionFixture, cli_runner: CliRunner, ): @click.command() def demo() -> None: with contextmanager(): raise exception result: Result = cli_runner.invoke(demo, catch_exceptions=False) result.check_stdout(advanced_file_regression) assert result.exit_code == exit_code @exceptions def test_handle_tracebacks_show_traceback(exception: Exception, cli_runner: CliRunner): @click.command() def demo() -> None: with handle_tracebacks(show_traceback=True): raise exception with pytest.raises(type(exception), match=re.escape(str(exception))): cli_runner.invoke(demo, catch_exceptions=False) @pytest.mark.parametrize("exception", [EOFError(), KeyboardInterrupt(), click.Abort()]) @contextmanagers def test_handle_tracebacks_ignored_exceptions_click( exception: Exception, contextmanager: Callable[..., ContextManager], cli_runner: CliRunner, exit_code: int, ): @click.command() def demo() -> None: with contextmanager(): raise exception result: Result = cli_runner.invoke(demo, catch_exceptions=False) assert result.stdout.strip() == "Aborted!" assert result.exit_code == 1 @pytest.mark.parametrize("exception", [EOFError, KeyboardInterrupt, click.Abort, SystemExit]) @contextmanagers def test_handle_tracebacks_ignored_exceptions( exception: Type[Exception], contextmanager: Callable[..., ContextManager], exit_code: int, ): with pytest.raises(exception): # noqa: PT012 # skipcq with contextmanager(): raise exception @pytest.mark.parametrize( "exception, code", [ pytest.param(click.UsageError("Message"), 2, id="click.UsageError"), pytest.param(click.BadParameter("Message"), 2, id="click.BadParameter"), pytest.param( click.FileError("Message"), 1, id="click.FileError", marks=pytest.mark.skipif(_click_major == 8, reason="Output differs on Click 8") ), pytest.param( click.FileError("Message"), 1, id="click.FileError_8", marks=pytest.mark.skipif(_click_major != 8, reason="Output differs on Click 8") ), pytest.param(click.ClickException("Message"), 1, id="click.ClickException"), ] ) @contextmanagers @pytest.mark.parametrize( "click_version", [ pytest.param( '7', marks=pytest.mark.skipif(_click_major == 8, reason="Output differs on click 8"), ), pytest.param( '8', marks=pytest.mark.skipif(_click_major != 8, reason="Output differs on click 8"), ), ] ) def test_handle_tracebacks_ignored_click( exception: Exception, contextmanager: Callable[..., ContextManager], advanced_file_regression: AdvancedFileRegressionFixture, code: int, cli_runner: CliRunner, click_version: str, exit_code: int, ): @click.command() def demo() -> None: with contextmanager(): raise exception result = cli_runner.invoke(demo, catch_exceptions=False) result.check_stdout(advanced_file_regression) # if code == 1 and exit_code == 2: # code = 2 assert result.exit_code == code def test_traceback_option(file_regression: FileRegressionFixture, cli_runner: CliRunner): @traceback_option() @click_command() def main(show_traceback: bool) -> None: print(show_traceback) result = cli_runner.invoke(main, catch_exceptions=False) assert result.stdout.rstrip() == "False" assert result.exit_code == 0 result = cli_runner.invoke(main, args="--traceback") assert result.stdout.rstrip() == "True" assert result.exit_code == 0 result = cli_runner.invoke(main, args="-T") assert result.stdout.rstrip() == "True" assert result.exit_code == 0 result = cli_runner.invoke(main, args="-h") result.check_stdout(file_regression) assert result.exit_code == 0 def test_traceback_handler_abort(capsys): TH = TracebackHandler(ValueError("foo")) with pytest.raises(ValueError, match="foo$"): TH.abort("Hello World") assert capsys.readouterr().err == "Hello World\n" with pytest.raises(ValueError, match="foo$"): TH.abort(["Hello", "Everybody"]) assert capsys.readouterr().err == "HelloEverybody\n" consolekit-1.7.1/tests/test_tracebacks_/000077500000000000000000000000001465042170600203415ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_TracebackHandler_Exception_.txt000066400000000000000000000000561465042170600331710ustar00rootroot00000000000000An error occurred: Something's awry! Aborted! consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_TracebackHandler_FileExistsError_.txt000066400000000000000000000000361465042170600343220ustar00rootroot00000000000000File Exists: foo.txt Aborted! test_handle_tracebacks_TracebackHandler_FileNotFoundError_.txt000066400000000000000000000000411465042170600345140ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_File Not Found: foo.txt Aborted! consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_TracebackHandler_NameError_.txt000066400000000000000000000000701465042170600331210ustar00rootroot00000000000000An error occurred: name 'hello' is not defined Aborted! consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_TracebackHandler_SyntaxError_.txt000066400000000000000000000000531465042170600335300ustar00rootroot00000000000000An error occurred: invalid syntax Aborted! test_handle_tracebacks_TracebackHandler_SystemExit_2_Exception_.txt000066400000000000000000000000451465042170600355270ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_An error occurred: Something's awry! test_handle_tracebacks_TracebackHandler_SystemExit_2_FileExistsError_.txt000066400000000000000000000000251465042170600366600ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_File Exists: foo.txt test_handle_tracebacks_TracebackHandler_SystemExit_2_FileNotFoundError_.txt000066400000000000000000000000301465042170600371310ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_File Not Found: foo.txt test_handle_tracebacks_TracebackHandler_SystemExit_2_NameError_.txt000066400000000000000000000000571465042170600354660ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_An error occurred: name 'hello' is not defined test_handle_tracebacks_TracebackHandler_SystemExit_2_SyntaxError_.txt000066400000000000000000000000421465042170600360660ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_An error occurred: invalid syntax test_handle_tracebacks_TracebackHandler_SystemExit_2_TypeError_.txt000066400000000000000000000000631465042170600355240ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_An error occurred: Expected type int, got type str test_handle_tracebacks_TracebackHandler_SystemExit_2_ValueError_.txt000066400000000000000000000000461465042170600356600ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_An error occurred: 'age' must be >= 0 test_handle_tracebacks_TracebackHandler_SystemExit_Exception_.txt000066400000000000000000000000451465042170600353060ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_An error occurred: Something's awry! test_handle_tracebacks_TracebackHandler_SystemExit_FileExistsError_.txt000066400000000000000000000000251465042170600364370ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_File Exists: foo.txt test_handle_tracebacks_TracebackHandler_SystemExit_FileNotFoundError_.txt000066400000000000000000000000301465042170600367100ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_File Not Found: foo.txt test_handle_tracebacks_TracebackHandler_SystemExit_NameError_.txt000066400000000000000000000000571465042170600352450ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_An error occurred: name 'hello' is not defined test_handle_tracebacks_TracebackHandler_SystemExit_SyntaxError_.txt000066400000000000000000000000421465042170600356450ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_An error occurred: invalid syntax test_handle_tracebacks_TracebackHandler_SystemExit_TypeError_.txt000066400000000000000000000000631465042170600353030ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_An error occurred: Expected type int, got type str test_handle_tracebacks_TracebackHandler_SystemExit_ValueError_.txt000066400000000000000000000000461465042170600354370ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_An error occurred: 'age' must be >= 0 consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_TracebackHandler_TypeError_.txt000066400000000000000000000000741465042170600331660ustar00rootroot00000000000000An error occurred: Expected type int, got type str Aborted! consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_TracebackHandler_ValueError_.txt000066400000000000000000000000571465042170600333220ustar00rootroot00000000000000An error occurred: 'age' must be >= 0 Aborted! consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_handle_tracebacks_Exception_.txt000066400000000000000000000000561465042170600334310ustar00rootroot00000000000000An error occurred: Something's awry! Aborted! test_handle_tracebacks_handle_tracebacks_FileExistsError_.txt000066400000000000000000000000361465042170600345030ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_File Exists: foo.txt Aborted! test_handle_tracebacks_handle_tracebacks_FileNotFoundError_.txt000066400000000000000000000000411465042170600347540ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_File Not Found: foo.txt Aborted! consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_handle_tracebacks_NameError_.txt000066400000000000000000000000701465042170600333610ustar00rootroot00000000000000An error occurred: name 'hello' is not defined Aborted! consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_handle_tracebacks_SyntaxError_.txt000066400000000000000000000000531465042170600337700ustar00rootroot00000000000000An error occurred: invalid syntax Aborted! consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_handle_tracebacks_TypeError_.txt000066400000000000000000000000741465042170600334260ustar00rootroot00000000000000An error occurred: Expected type int, got type str Aborted! consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_handle_tracebacks_ValueError_.txt000066400000000000000000000000571465042170600335620ustar00rootroot00000000000000An error occurred: 'age' must be >= 0 Aborted! test_handle_tracebacks_ignored_click_7_TracebackHandler_SystemExit_2_click_BadParameter_.txt000066400000000000000000000000651465042170600423710ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Error: Invalid value: Message test_handle_tracebacks_ignored_click_7_TracebackHandler_SystemExit_2_click_ClickException_.txt000066400000000000000000000000171465042170600427430ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Message test_handle_tracebacks_ignored_click_7_TracebackHandler_SystemExit_2_click_FileError_.txt000066400000000000000000000000621465042170600417300ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Could not open file Message: unknown error test_handle_tracebacks_ignored_click_7_TracebackHandler_SystemExit_2_click_UsageError_.txt000066400000000000000000000000461465042170600421170ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Error: Message test_handle_tracebacks_ignored_click_7_TracebackHandler_SystemExit_click_BadParameter_.txt000066400000000000000000000000651465042170600421500ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Error: Invalid value: Message test_handle_tracebacks_ignored_click_7_TracebackHandler_SystemExit_click_ClickException_.txt000066400000000000000000000000171465042170600425220ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Message test_handle_tracebacks_ignored_click_7_TracebackHandler_SystemExit_click_FileError_.txt000066400000000000000000000000621465042170600415070ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Could not open file Message: unknown error test_handle_tracebacks_ignored_click_7_TracebackHandler_SystemExit_click_UsageError_.txt000066400000000000000000000000461465042170600416760ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Error: Message test_handle_tracebacks_ignored_click_7_TracebackHandler_click_BadParameter_.txt000066400000000000000000000000651465042170600377520ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Error: Invalid value: Message test_handle_tracebacks_ignored_click_7_TracebackHandler_click_ClickException_.txt000066400000000000000000000000171465042170600403240ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Message test_handle_tracebacks_ignored_click_7_TracebackHandler_click_FileError_.txt000066400000000000000000000000621465042170600373110ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Could not open file Message: unknown error test_handle_tracebacks_ignored_click_7_TracebackHandler_click_UsageError_.txt000066400000000000000000000000461465042170600375000ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Error: Message test_handle_tracebacks_ignored_click_7_handle_tracebacks_click_BadParameter_.txt000066400000000000000000000000651465042170600402120ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Error: Invalid value: Message test_handle_tracebacks_ignored_click_7_handle_tracebacks_click_ClickException_.txt000066400000000000000000000000171465042170600405640ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Message test_handle_tracebacks_ignored_click_7_handle_tracebacks_click_FileError_.txt000066400000000000000000000000621465042170600375510ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Could not open file Message: unknown error test_handle_tracebacks_ignored_click_7_handle_tracebacks_click_UsageError_.txt000066400000000000000000000000461465042170600377400ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Error: Message test_handle_tracebacks_ignored_click_7_traceback_handler_click_BadParameter_.txt000066400000000000000000000000651465042170600402110ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Error: Invalid value: Message test_handle_tracebacks_ignored_click_7_traceback_handler_click_ClickException_.txt000066400000000000000000000000171465042170600405630ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Message test_handle_tracebacks_ignored_click_7_traceback_handler_click_FileError_.txt000066400000000000000000000000621465042170600375500ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Could not open file Message: unknown error test_handle_tracebacks_ignored_click_7_traceback_handler_click_UsageError_.txt000066400000000000000000000000461465042170600377370ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Error: Message test_handle_tracebacks_ignored_click_8_TracebackHandler_SystemExit_2_click_BadParameter_.txt000066400000000000000000000001211465042170600423630ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Try 'demo --help' for help. Error: Invalid value: Message test_handle_tracebacks_ignored_click_8_TracebackHandler_SystemExit_2_click_ClickException_.txt000066400000000000000000000000171465042170600427440ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Message test_handle_tracebacks_ignored_click_8_TracebackHandler_SystemExit_2_click_FileError_8_.txt000066400000000000000000000000641465042170600421620ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Could not open file 'Message': unknown error test_handle_tracebacks_ignored_click_8_TracebackHandler_SystemExit_2_click_UsageError_.txt000066400000000000000000000001021465042170600421110ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Try 'demo --help' for help. Error: Message test_handle_tracebacks_ignored_click_8_TracebackHandler_SystemExit_click_BadParameter_.txt000066400000000000000000000001211465042170600421420ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Try 'demo --help' for help. Error: Invalid value: Message test_handle_tracebacks_ignored_click_8_TracebackHandler_SystemExit_click_ClickException_.txt000066400000000000000000000000171465042170600425230ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Message test_handle_tracebacks_ignored_click_8_TracebackHandler_SystemExit_click_FileError_8_.txt000066400000000000000000000000641465042170600417410ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Could not open file 'Message': unknown error test_handle_tracebacks_ignored_click_8_TracebackHandler_SystemExit_click_UsageError_.txt000066400000000000000000000001021465042170600416700ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Try 'demo --help' for help. Error: Message test_handle_tracebacks_ignored_click_8_TracebackHandler_click_BadParameter_.txt000066400000000000000000000001211465042170600377440ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Try 'demo --help' for help. Error: Invalid value: Message test_handle_tracebacks_ignored_click_8_TracebackHandler_click_ClickException_.txt000066400000000000000000000000171465042170600403250ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Message test_handle_tracebacks_ignored_click_8_TracebackHandler_click_FileError_8_.txt000066400000000000000000000000641465042170600375430ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Could not open file 'Message': unknown error test_handle_tracebacks_ignored_click_8_TracebackHandler_click_UsageError_.txt000066400000000000000000000001021465042170600374720ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Try 'demo --help' for help. Error: Message test_handle_tracebacks_ignored_click_8_handle_tracebacks_click_BadParameter_.txt000066400000000000000000000001211465042170600402040ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Try 'demo --help' for help. Error: Invalid value: Message test_handle_tracebacks_ignored_click_8_handle_tracebacks_click_ClickException_.txt000066400000000000000000000000171465042170600405650ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Message test_handle_tracebacks_ignored_click_8_handle_tracebacks_click_FileError_8_.txt000066400000000000000000000000641465042170600400030ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Could not open file 'Message': unknown error test_handle_tracebacks_ignored_click_8_handle_tracebacks_click_UsageError_.txt000066400000000000000000000001021465042170600377320ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Try 'demo --help' for help. Error: Message test_handle_tracebacks_ignored_click_8_traceback_handler_click_BadParameter_.txt000066400000000000000000000001211465042170600402030ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Try 'demo --help' for help. Error: Invalid value: Message test_handle_tracebacks_ignored_click_8_traceback_handler_click_ClickException_.txt000066400000000000000000000000171465042170600405640ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Message test_handle_tracebacks_ignored_click_8_traceback_handler_click_FileError_8_.txt000066400000000000000000000000641465042170600400020ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Error: Could not open file 'Message': unknown error test_handle_tracebacks_ignored_click_8_traceback_handler_click_UsageError_.txt000066400000000000000000000001021465042170600377310ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_Usage: demo [OPTIONS] Try 'demo --help' for help. Error: Message consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_traceback_handler_Exception_.txt000066400000000000000000000000561465042170600334300ustar00rootroot00000000000000An error occurred: Something's awry! Aborted! test_handle_tracebacks_traceback_handler_FileExistsError_.txt000066400000000000000000000000361465042170600345020ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_File Exists: foo.txt Aborted! test_handle_tracebacks_traceback_handler_FileNotFoundError_.txt000066400000000000000000000000411465042170600347530ustar00rootroot00000000000000consolekit-1.7.1/tests/test_tracebacks_File Not Found: foo.txt Aborted! consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_traceback_handler_NameError_.txt000066400000000000000000000000701465042170600333600ustar00rootroot00000000000000An error occurred: name 'hello' is not defined Aborted! consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_traceback_handler_SyntaxError_.txt000066400000000000000000000000531465042170600337670ustar00rootroot00000000000000An error occurred: invalid syntax Aborted! consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_traceback_handler_TypeError_.txt000066400000000000000000000000741465042170600334250ustar00rootroot00000000000000An error occurred: Expected type int, got type str Aborted! consolekit-1.7.1/tests/test_tracebacks_/test_handle_tracebacks_traceback_handler_ValueError_.txt000066400000000000000000000000571465042170600335610ustar00rootroot00000000000000An error occurred: 'age' must be >= 0 Aborted! consolekit-1.7.1/tests/test_tracebacks_/test_traceback_option.txt000066400000000000000000000002101465042170600254410ustar00rootroot00000000000000Usage: main [OPTIONS] Options: -T, --traceback Show the complete traceback on error. -h, --help Show this message and exit. consolekit-1.7.1/tests/test_type_hints_init.yaml000066400000000000000000000024311465042170600221750ustar00rootroot00000000000000- case: mypy_path_from_env mypy_config: | ignore_missing_imports = True no_silence_site_packages = False follow_imports = silent main: | import click from consolekit import click_command, click_group from consolekit.commands import MarkdownHelpGroup class MyCommand(click.Command): pass @click_command() def command(): pass @click_group() def group(): pass reveal_type(click_command()) # N: Revealed type is "def (def (*Any, **Any) -> Any) -> click.core.Command" reveal_type(click_command(cls=MyCommand)) # N: Revealed type is "def (def (*Any, **Any) -> Any) -> main.MyCommand" reveal_type(click_command(cls=click.Command)) # N: Revealed type is "def (def (*Any, **Any) -> Any) -> click.core.Command" reveal_type(command) # N: Revealed type is "click.core.Command" reveal_type(click_group()) # N: Revealed type is "def (def (*Any, **Any) -> Any) -> click.core.Group" reveal_type(click_group(cls=MarkdownHelpGroup)) # N: Revealed type is "def (def (*Any, **Any) -> Any) -> consolekit.commands.MarkdownHelpGroup" reveal_type(click_group(cls=click.Group)) # N: Revealed type is "def (def (*Any, **Any) -> Any) -> click.core.Group" reveal_type(group) # N: Revealed type is "click.core.Group" consolekit-1.7.1/tests/test_utils.py000066400000000000000000000106141465042170600176140ustar00rootroot00000000000000# stdlib import math import os import shutil import sys from typing import Tuple # 3rd party import click from coincidence.regressions import AdvancedDataRegressionFixture, check_file_regression from coincidence.selectors import not_windows from domdf_python_tools.paths import PathPlus from domdf_python_tools.utils import redirect_output from pytest_regressions.file_regression import FileRegressionFixture # this package import consolekit from consolekit import click_command from consolekit.terminal_colours import ColourTrilean from consolekit.utils import ( abort, coloured_diff, hidden_cursor, hide_cursor, import_commands, is_command, long_echo, overtype, show_cursor, solidus_spinner ) def test_overtype(capsys): print("Waiting...", end='') overtype("foo", "bar") sys.stdout.flush() captured = capsys.readouterr() stdout = captured.out.split('\n') assert stdout == ["Waiting...\rfoo bar"] print("Waiting...", end='') overtype("foo", "bar", sep='') sys.stdout.flush() captured = capsys.readouterr() stdout = captured.out.split('\n') assert stdout == ["Waiting...\rfoobar"] print("Waiting...", end='') overtype("foo", "bar", sep='-', end='\n') sys.stdout.flush() captured = capsys.readouterr() stdout = captured.out.split('\n') assert stdout == ["Waiting...\rfoo-bar", ''] sys.stderr.write("Waiting...") overtype("foo", "bar", file=sys.stderr) sys.stdout.flush() captured = capsys.readouterr() stderr = captured.err.split('\n') assert stderr == ["Waiting...\rfoo bar"] def test_coloured_diff(file_regression: FileRegressionFixture): data_dir = PathPlus(__file__).parent / "test_diff_" original = data_dir / "original" modified = data_dir / "modified" diff = coloured_diff( original.read_lines(), modified.read_lines(), fromfile="original_file.txt", tofile="modified_file.txt", fromfiledate="(original)", tofiledate="(modified)", lineterm='', ) check_file_regression(diff, file_regression) def test_is_command(): @click_command() def main() -> None: ... assert is_command(main) assert not is_command(int) assert not is_command(lambda: True) assert not is_command(math.ceil) def test_hidden_cursor(monkeypatch, capsys, advanced_data_regression: AdvancedDataRegressionFixture): monkeypatch.setattr(consolekit.terminal_colours, "resolve_color_default", lambda *args: True) hide_cursor() show_cursor() with hidden_cursor(): click.echo(f"\r{next(solidus_spinner)}", nl=False) click.echo(f"\r{next(solidus_spinner)}", nl=False) click.echo(f"\r{next(solidus_spinner)}", nl=False) advanced_data_regression.check(tuple(capsys.readouterr())) def test_import_commands(): # this package from tests import import_commands_demo commands = import_commands(import_commands_demo) assert commands == [ import_commands_demo.command1, import_commands_demo.commando, import_commands_demo.submodule.command2, import_commands_demo.submodule.group2, ] def test_long_echo(monkeypatch): def get_terminal_size(fallback: Tuple[int, int] = (80, 24)) -> Tuple[int, int]: return os.terminal_size((80, 5)) def echo_via_pager(text_or_generator, color: ColourTrilean = None) -> None: # noqa: MAN001 click.echo('\n'.join(f"|{line}" for line in text_or_generator.splitlines())) monkeypatch.setattr(shutil, "get_terminal_size", get_terminal_size) monkeypatch.setattr(click, "echo_via_pager", echo_via_pager) with redirect_output() as (stdout, stderr): stdout.isatty = lambda *args: True # type: ignore[assignment] assert stdout.isatty() assert sys.stdout.isatty() long_echo([ "Line 1", "Line 2", "Line 3", "Line 4", "Line 5", "Line 6", ]) assert stdout.getvalue() == "|Line 1\n|Line 2\n|Line 3\n|Line 4\n|Line 5\n|Line 6\n" with redirect_output() as (stdout, stderr): stdout.isatty = lambda *args: True # type: ignore[assignment] assert stdout.isatty() assert sys.stdout.isatty() long_echo('\n'.join([ "Line 1", "Line 2", "Line 3", "Line 4", "Line 5", ])) assert stdout.getvalue() == "Line 1\nLine 2\nLine 3\nLine 4\nLine 5\n" @not_windows(reason="Output differs on Windows") def test_abort(capsys): abort("The program will now abort.", colour=True) assert capsys.readouterr().err == "\x1b[31mThe program will now abort.\x1b[39m\n" def test_abort_no_colour(capsys): abort("The program will now abort.", colour=False) assert capsys.readouterr().err == "The program will now abort.\n" consolekit-1.7.1/tests/test_utils_/000077500000000000000000000000001465042170600173775ustar00rootroot00000000000000consolekit-1.7.1/tests/test_utils_/test_coloured_diff.txt000066400000000000000000000015451465042170600240100ustar00rootroot00000000000000--- original_file.txt (original) +++ modified_file.txt (modified) @@ -1,9 +1,8 @@ -Lorem ipsum dolor sit amet, consectetur adipiscing elit. -Quisque feugiat, lectus et interdum feugiat, magna enim -vestibulum diam, a ultrices urna odio at magna. Quisque -ut ullamcorper justo. Suspendisse ac tincidunt velit. +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque feugiat, +lectus et interdum feugiat, magna enim vestibulum diam, a ultrices urna +odio at magna. Quisque +ut ullamcorper justo. Integer lobortis eros eget diam varius eleifend. Donec ornare nisi vel purus aliquet consequat. Ut quis ipsum -et nunc sodales tristique. Maecenas justo libero, semper -eget feugiat et, aliquam et mauris. +et nunc sodales tristique. consolekit-1.7.1/tests/test_utils_/test_hidden_cursor.yml000066400000000000000000000000571465042170600240130ustar00rootroot00000000000000- "\e[?25l\e[?25h\e[?25l\r|\r/\r-\e[?25h" - '' consolekit-1.7.1/tests/test_versions.py000066400000000000000000000040261465042170600203240ustar00rootroot00000000000000# stdlib import sys # this package from consolekit import click_command from consolekit.options import version_option from consolekit.testing import CliRunner from consolekit.versions import get_formatted_versions, get_version_callback def test_get_formatted_versions(): dependencies = ["click", "deprecation-alias", "domdf-python-tools", "mistletoe", "typing-extensions"] sl = get_formatted_versions(dependencies) for line, dep in zip(sl, dependencies): assert line.startswith(f"{dep}:") assert sl[-2].startswith("Python: 3.") sl = get_formatted_versions(dependencies, show_platform=False) for line, dep in zip(sl, [*dependencies]): assert line.startswith(f"{dep}:") assert sl[-1].startswith("Python: 3.") sl = get_formatted_versions(dependencies, show_python=False) assert len(sl) == len(dependencies) + 1 sl = get_formatted_versions(dependencies, show_python=False, show_platform=False) assert len(sl) == len(dependencies) sl = get_formatted_versions({ "click": "pkg1", "deprecation-alias": "pkg2", "domdf-python-tools": "pkg3", "mistletoe": "pkg4", "typing-extensions": "pkg5" }) for line, name in zip(sl, ["pkg1", "pkg2", "pkg3", "pkg4", "pkg5"]): assert line.startswith(f"{name}:") assert sl[-2].startswith("Python: 3.") def test_version_callback(cli_runner: CliRunner): @version_option( get_version_callback( "1.2.3", "my-tool", ["click", "deprecation-alias", "domdf-python-tools", "mistletoe", "typing-extensions"] ) ) @click_command() def main() -> None: sys.exit(1) result = cli_runner.invoke(main, args="--version") assert result.stdout.rstrip() == "my-tool version 1.2.3" assert result.exit_code == 0 result = cli_runner.invoke(main, args=["--version", "--version"]) assert result.stdout.startswith("my-tool version 1.2.3, Python 3.") assert result.exit_code == 0 result = cli_runner.invoke(main, args=["--version", "--version", "--version"]) print(result.stdout) assert result.stdout.startswith("my-tool\n Version: 1.2.3\n click: ") assert result.exit_code == 0 consolekit-1.7.1/tox.ini000066400000000000000000000213471465042170600152210ustar00rootroot00000000000000# This file is managed by 'repo_helper'. # You may add new sections, but any changes made to the following sections will be lost: # * tox # * envlists # * testenv:.package # * testenv:py313-dev # * testenv:py312-dev # * testenv:py312 # * testenv:docs # * testenv:build # * testenv:lint # * testenv:perflint # * testenv:mypy # * testenv:pyup # * testenv:coverage # * flake8 # * coverage:run # * coverage:report # * check-wheel-contents [tox] envlist = py36-click{7.1,8.0,8.1} py37-click{7.1,8.0,8.1} py38-click{7.1,8.0,8.1} py39-click{7.1,8.0,8.1} py310-click{7.1,8.0,8.1} py311-click{7.1,8.0,8.1} py312-click{7.1,8.0,8.1} py313-dev-click{7.1,8.0,8.1} pypy36-click{7.1,8.0,8.1} pypy37-click{7.1,8.0,8.1} pypy38-click{7.1,8.0,8.1} pypy39-click{7.1,8.0,8.1} mypy build skip_missing_interpreters = True isolated_build = True requires = pip>=21,!=22.2 tox-envlist>=0.2.1 tox~=3.0 virtualenv!=20.16.0 [envlists] test = py36-click{7.1,8.0,8.1} py37-click{7.1,8.0,8.1} py38-click{7.1,8.0,8.1} py39-click{7.1,8.0,8.1} py310-click{7.1,8.0,8.1} py311-click{7.1,8.0,8.1} py312-click{7.1,8.0,8.1} py313-dev-click{7.1,8.0,8.1} pypy36-click{7.1,8.0,8.1} pypy37-click{7.1,8.0,8.1} pypy38-click{7.1,8.0,8.1} pypy39-click{7.1,8.0,8.1} qa = mypy, lint cov = py38-click7.1, coverage [testenv:.package] setenv = PYTHONDEVMODE=1 PIP_DISABLE_PIP_VERSION_CHECK=1 [testenv:py313-dev] setenv = PYTHONDEVMODE=1 PIP_DISABLE_PIP_VERSION_CHECK=1 UNSAFE_PYO3_SKIP_VERSION_CHECK=1 [testenv:py312] setenv = PYTHONDEVMODE=1 PIP_DISABLE_PIP_VERSION_CHECK=1 [testenv:docs] setenv = SHOW_TODOS = 1 passenv = SPHINX_BUILDER basepython = python3.8 changedir = {toxinidir}/doc-source deps = -r{toxinidir}/doc-source/requirements.txt commands = sphinx-build -M {env:SPHINX_BUILDER:html} . ./build {posargs} [testenv:build] setenv = PYTHONDEVMODE=1 PIP_DISABLE_PIP_VERSION_CHECK=1 PIP_PREFER_BINARY=1 UNSAFE_PYO3_SKIP_VERSION_CHECK=1 skip_install = True changedir = {toxinidir} deps = build[virtualenv]>=0.3.1 check-wheel-contents>=0.1.0 twine>=3.2.0 cryptography<40; implementation_name == "pypy" and python_version <= "3.7" commands = python -m build --sdist --wheel "{toxinidir}" twine check dist/*.tar.gz dist/*.whl check-wheel-contents dist/ [testenv:lint] basepython = python3.8 changedir = {toxinidir} ignore_errors = True skip_install = False deps = flake8>=3.8.2,<5 flake8-2020>=1.6.0 flake8-builtins>=1.5.3 flake8-docstrings>=1.5.0 flake8-dunder-all>=0.1.1 flake8-encodings>=0.1.0 flake8-github-actions>=0.1.0 flake8-noqa>=1.1.0,<=1.2.2 flake8-pyi>=20.10.0,<=22.8.0 flake8-pytest-style>=1.3.0,<2 flake8-quotes>=3.3.0 flake8-slots>=0.1.0 flake8-sphinx-links>=0.0.4 flake8-strftime>=0.1.1 flake8-typing-imports>=1.10.0 git+https://github.com/domdfcoding/flake8-rst-docstrings-sphinx.git git+https://github.com/domdfcoding/flake8-rst-docstrings.git git+https://github.com/python-formate/flake8-unused-arguments.git@magic-methods git+https://github.com/python-formate/flake8-missing-annotations.git pydocstyle>=6.0.0 pygments>=2.7.1 importlib_metadata<4.5.0; python_version<'3.8' commands = python3 -m flake8_rst_docstrings_sphinx consolekit tests --allow-toolbox {posargs} [testenv:perflint] basepython = python3.8 changedir = {toxinidir} ignore_errors = True skip_install = True deps = perflint commands = python3 -m perflint consolekit {posargs} [testenv:mypy] basepython = python3.8 ignore_errors = True changedir = {toxinidir} deps = mypy==0.971 -r{toxinidir}/tests/requirements.txt commands = mypy consolekit tests {posargs} [testenv:pyup] basepython = python3.8 skip_install = True ignore_errors = True changedir = {toxinidir} deps = pyupgrade-directories commands = pyup_dirs consolekit tests --py36-plus --recursive [testenv:coverage] basepython = python3.8 skip_install = True ignore_errors = True whitelist_externals = /bin/bash passenv = COV_PYTHON_VERSION COV_PLATFORM COV_PYTHON_IMPLEMENTATION * changedir = {toxinidir} deps = coverage>=5 coverage_pyver_pragma>=0.2.1 commands = /bin/bash -c "rm -rf htmlcov" coverage html /bin/bash -c "DISPLAY=:0 firefox 'htmlcov/index.html'" [flake8] max-line-length = 120 select = E111 E112 E113 E121 E122 E125 E127 E128 E129 E131 E133 E201 E202 E203 E211 E222 E223 E224 E225 E225 E226 E227 E228 E231 E241 E242 E251 E261 E262 E265 E271 E272 E303 E304 E306 E402 E502 E703 E711 E712 E713 E714 E721 W291 W292 W293 W391 W504 YTT101 YTT102 YTT103 YTT201 YTT202 YTT203 YTT204 YTT301 YTT302 YTT303 STRFTIME001 STRFTIME002 SXL001 PT001 PT002 PT003 PT006 PT007 PT008 PT009 PT010 PT011 PT012 PT013 PT014 PT015 PT016 PT017 PT018 PT019 PT020 PT021 RST201 RST202 RST203 RST204 RST205 RST206 RST207 RST208 RST210 RST211 RST212 RST213 RST214 RST215 RST216 RST217 RST218 RST219 RST299 RST301 RST302 RST303 RST304 RST305 RST306 RST399 RST401 RST499 RST900 RST901 RST902 RST903 Q001 Q002 Q003 A001 A002 TYP001 TYP002 TYP003 TYP004 TYP005 TYP006 ENC001 ENC002 ENC003 ENC004 ENC011 ENC012 ENC021 ENC022 ENC023 ENC024 ENC025 ENC026 Y001,Y002 Y003 Y004 Y005 Y006 Y007 Y008 Y009 Y010 Y011 Y012 Y013 Y014 Y015 Y090 Y091 NQA001 NQA002 NQA003 NQA004 NQA005 NQA102 NQA103 E301 E302 E305 D100 D101 D102 D103 D104 D106 D201 D204 D207 D208 D209 D210 D211 D212 D213 D214 D215 D300 D301 D400 D402 D403 D404 D415 D417 DALL000 SLOT000 SLOT001 SLOT002 extend-exclude = doc-source,old,build,dist,__pkginfo__.py,setup.py,venv rst-directives = TODO autosummary-widths envvar extras-require license license-info rst-roles = choosealicense inline-code per-file-ignores = tests/*: D100 D101 D102 D103 D104 D106 D201 D204 D207 D208 D209 D210 D211 D212 D213 D214 D215 D300 D301 D400 D402 D403 D404 D415 D417 DALL000 SLOT000 SLOT001 SLOT002 */*.pyi: E301 E302 E305 D100 D101 D102 D103 D104 D106 D201 D204 D207 D208 D209 D210 D211 D212 D213 D214 D215 D300 D301 D400 D402 D403 D404 D415 D417 DALL000 SLOT000 SLOT001 SLOT002 tests/import_commands_demo/*: MAN002,D100,D103,D104,DALL000 tests/type_hints_test_code.py: MAN002,D100,D101,D103,D104,DALL000 pytest-parametrize-names-type = csv inline-quotes = " multiline-quotes = """ docstring-quotes = """ count = True min_python_version = 3.6.1 unused-arguments-ignore-abstract-functions = True unused-arguments-ignore-overload-functions = True unused-arguments-ignore-magic-methods = True unused-arguments-ignore-variadic-names = True [coverage:run] plugins = coverage_pyver_pragma [coverage:report] fail_under = 90 show_missing = True exclude_lines = raise AssertionError raise NotImplementedError if 0: if False: if TYPE_CHECKING if typing.TYPE_CHECKING if __name__ == .__main__.: [check-wheel-contents] ignore = W002 toplevel = consolekit package = consolekit [testenv:py312-click{7.1,8.0,8.1}] setenv = PYTHONDEVMODE=1 PIP_DISABLE_PIP_VERSION_CHECK=1 [testenv:py313-dev-click{7.1,8.0,8.1}] setenv = PYTHONDEVMODE=1 PIP_DISABLE_PIP_VERSION_CHECK=1 UNSAFE_PYO3_SKIP_VERSION_CHECK=1 [testenv:py312-dev-click{7.1,8.0,8.1}] setenv = PYTHONDEVMODE=1 PIP_DISABLE_PIP_VERSION_CHECK=1 [testenv] setenv = PYTHONDEVMODE=1 PIP_DISABLE_PIP_VERSION_CHECK=1 SETUPTOOLS_USE_DISTUTILS=stdlib deps = -r{toxinidir}/tests/requirements.txt click7.1: click~=7.1.0 click7.1: types-click==7.1.8 click8.0: click~=8.0.0 commands = python --version python -m pytest --cov=consolekit -r aR tests/ {posargs} [pytest] addopts = --color yes --durations 25 -p no:pytest-mypy-plugins timeout = 300 filterwarnings = error ignore:can't resolve package from __spec__ or __package__, falling back on __name__ and __path__:ImportWarning always:The \(fspath.*\) argument to YamlTestFile is deprecated:DeprecationWarning always:module 'sre_constants' is deprecated:DeprecationWarning always:pkg_resources is deprecated as an API:DeprecationWarning always:ast.Ellipsis is deprecated and will be removed in Python 3.14; use ast.Constant instead:DeprecationWarning:mypy.fastparse always:ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead:DeprecationWarning:mypy.fastparse always:ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead:DeprecationWarning:mypy.fastparse always:ast.Bytes is deprecated and will be removed in Python 3.14; use ast.Constant instead:DeprecationWarning:mypy.fastparse always:ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead:DeprecationWarning:mypy.fastparse [doc8] ignore-path = doc-source/build max-line-length = 110 ignore = D003