Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* text=auto
.githooks/* text eol=lf
93 changes: 93 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/usr/bin/env bash

abort() {
printf '%s\n' "$@" >&2
exit 1
}

tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/morepath-ruff.XXXXXX") ||
abort 'Ruff pre-commit check: could not create a temporary directory.'
trap 'rm -rf "$tmpdir"' EXIT

list_file=$tmpdir/staged-files
staged_file=$tmpdir/staged
formatted_file=$tmpdir/formatted

# Write the list to a file first so a git failure is not silently ignored.
git diff --cached --name-only --diff-filter=ACMR -z -- '*.py' '*.pyi' \
>"$list_file" ||
abort 'Ruff pre-commit check: could not list the staged files.'

python_files=()
while IFS= read -r -d '' path; do
python_files+=("$path")
done <"$list_file"

if (( ${#python_files[@]} == 0 )); then
exit 0
fi

if [[ -x .venv/bin/ruff ]]; then
ruff_cmd=.venv/bin/ruff
elif [[ -f .venv/Scripts/ruff.exe ]]; then
ruff_cmd=.venv/Scripts/ruff.exe
elif command -v ruff >/dev/null 2>&1; then
ruff_cmd=$(command -v ruff)
elif command -v ruff.exe >/dev/null 2>&1; then
ruff_cmd=$(command -v ruff.exe)
else
abort 'Ruff not found in .venv or PATH.' \
"Install it with pip install -e '.[lint]'"
fi

# report <label> <fix label> <fix command> <files...>
report() {
local label=$1 fixlabel=$2 fix=$3
shift 3
printf '\n%s (%d):' "$label" "$#"
printf ' %q' "$@"
printf '\n%s: %s' "$fixlabel" "$fix"
printf ' %q' "$@"
printf '\n'
}

format_files=()
lint_files=()

for path in "${python_files[@]}"; do
git show ":$path" >"$staged_file" ||
abort "Could not read the staged content of $path."

# Format the staged content; a non-zero exit is a real failure here
# (for example a syntax error or a broken config).
# --force-exclude makes ruff honor its exclude settings for stdin input.
errors=$("$ruff_cmd" format --force-exclude --stdin-filename "$path" - \
<"$staged_file" 2>&1 >"$formatted_file") ||
abort "Ruff format failed on $path:" "$errors"

if ! cmp -s "$staged_file" "$formatted_file"; then
format_files+=("$path")
fi

# Lint the formatted content, so that violations the formatter
# fixes anyway (e.g. trailing whitespace) are not reported twice.
output=$("$ruff_cmd" check --force-exclude --no-fix \
--stdin-filename "$path" - <"$formatted_file" 2>&1)
case $? in
0) ;;
1) lint_files+=("$path") ;;
*) abort "Ruff check failed on $path:" "$output" ;;
esac
done

if (( ${#format_files[@]} || ${#lint_files[@]} )); then
printf '%s\n' 'Ruff checks failed - no files were changed.'
if (( ${#format_files[@]} )); then
report 'Needs formatting' 'Fix with' 'ruff format' "${format_files[@]}"
fi
if (( ${#lint_files[@]} )); then
report 'Lint errors' 'Try' 'ruff check --fix' "${lint_files[@]}"
fi
printf '\n%s\n' 'Review and stage the fixes, then retry the commit.'
exit 1
fi
26 changes: 12 additions & 14 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,33 @@ on:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

permissions: {}

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
tests:
name: "Python ${{ matrix.python-version }}"
runs-on: "ubuntu-latest"
permissions:
contents: read

strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "pypy3.11"]
python-version: ["3.11", "3.12", "3.13", "3.14", "3.15", "pypy-3.12"]

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: "actions/checkout@v6"
- uses: "actions/setup-python@v6"
- uses: "actions/checkout@v7"
with:
persist-credentials: false
- uses: "actions/setup-python@v7"
with:
python-version: "${{ matrix.python-version }}"
allow-prereleases: true
check-latest: true
- name: "Install dependencies"
run: python -m pip install --upgrade pip tox tox-gh
- name: "Run tox targets for ${{ matrix.python-version }}"
run: "python -m tox"

- name: "Report to coveralls"
# coverage is only created in the py314 environment
# --service=github is a workaround for bug
# https://github.com/coveralls-clients/coveralls-python/issues/251
if: "matrix.python-version == '3.14'"
run: |
pip install coveralls
coveralls --service=github
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
41 changes: 41 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Release

on:
push:
tags: ["v[0-9]*"]

permissions: {}

jobs:
build:
name: Build
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: actions/setup-python@v7
with:
python-version: "3.14"
- run: python -m pip install build
- run: python -m build
- uses: actions/upload-artifact@v7
with:
name: dist
path: dist/

publish:
name: Publish
needs: build
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v8
with:
name: dist
path: dist/
- uses: pypa/gh-action-pypi-publish@release/v1
15 changes: 0 additions & 15 deletions .pre-commit-config.yaml

This file was deleted.

34 changes: 34 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Read the Docs configuration file for Sphinx projects
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the OS, Python version and other tools you might need
build:
os: ubuntu-lts-latest
tools:
python: "3.14"

# Build documentation in the "doc/" directory with Sphinx
sphinx:
configuration: doc/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
# fail_on_warning: true

# Optionally build your docs in additional formats such as PDF and ePub
# formats:
# - pdf
# - epub

# Optional but recommended, declare the Python requirements required
# to build your documentation
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- method: pip
path: .
extra_requirements:
- docs
40 changes: 35 additions & 5 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,49 @@ CHANGES

- Skip importing packages in scan() since they're already imported in walk_packages().

- Add type annotations.
- Add type annotations and integrate ``mypy`` and ``pyright``.

- Add support for Python 3.10 - 3.14.
- Switch to ``pyproject.toml`` based project setup.

- Drop support for Python 3.9 and below.
- Add support for Python 3.11 - 3.15.

- Fix Flake8 errors.
- Drop support for Python 3.10 and below.

- Support Pypy 3.12.

- Fix linting errors.

- Use GitHub Actions for CI.

- Add tests for 100% coverage.

- Update docs.
- Update docs and adjust sphinx config.

- Make an overall cleanup.

- Fix readthedocs integration.

- Replace flake8, black, isort, pyupgrade and pre-commit with Ruff_.

.. _Ruff: https://docs.astral.sh/ruff

- Add a tracked Git pre-commit hook for Ruff checks on staged Python files.

- Remove coveralls integration.

- Adjust the deployment strategy:

* Move the Pypi upload from ``zest.release`` to ``gh-actions``.

* Use ``v`` + version as release tags like ``v1.0.0``.

* So we still use ``zest.release`` but without publishing to Pypi.
The Pypi upload is triggered by pushing the new release tag to GitHub.
This happens in the Release workflow in ``.github/workflows/release.yml``.
With this workflow we get Trusted Publishing with short-lived OIDC tokens
that PyPI issues to one specific repository, workflow file and environment (``pypi``).
We also get PEP 740 provenance and can set required reviewers for the environment
and a ruleset who can create release tags and trigger releases.


0.2 (2020-01-29)
Expand Down
3 changes: 0 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
:target: https://github.com/morepath/importscan/actions?workflow=CI
:alt: CI Status

.. image:: https://coveralls.io/repos/github/morepath/importscan/badge.svg?branch=master
:target: https://coveralls.io/github/morepath/importscan?branch=master

.. image:: https://img.shields.io/pypi/v/importscan.svg
:target: https://pypi.org/project/importscan/

Expand Down
1 change: 0 additions & 1 deletion develop_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# development
-e '.[test,coverage,lint,docs,mypy,pyright]'
pre-commit
tox >= 4

# releaser
Expand Down
Loading
Loading