diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..03fe30b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,41 @@ +--- +name: Bug report ๐Ÿ› +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +## Describe the bug + +A clear and concise description of what the bug is. + +## To Reproduce + +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +## Expected behavior + +A clear and concise description of what you expected to happen. + +## Configuration + +```shell +# use `pip freeze` to list all deps +pip freeze +``` + +- Python version: +- OS version: +- deps version: +- ... + +## Additional context + +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..c0963ac --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,4 @@ +contact_links: + - name: I have a question ๐Ÿค” + url: https://github.com/WSH032/pyproject-template/discussions # EDIT + about: If you have any question that's not clearly a bug, please open a discussion first. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..dca4a5a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,32 @@ +--- +name: Feature request ๐Ÿ’ก +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +## Have you discussed it? + +- [ ] I have discussed this feature request in discussions, and developers ask me directly to create an issue here. + +## Describe your feature request + +A clear and concise description of what the feature is. + +## Is your feature request related to a problem? Please describe + +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +## Describe the solution you'd like + +A clear and concise description of what you want to happen. + +## Describe alternatives you've considered + +A clear and concise description of any alternative solutions or features you've considered. + +## Additional context + +Add any other context or screenshots about the feature request here. diff --git a/.github/actions/setup-envs/action.yml b/.github/actions/setup-envs/action.yml new file mode 100644 index 0000000..94fbd89 --- /dev/null +++ b/.github/actions/setup-envs/action.yml @@ -0,0 +1,95 @@ +# WARNING: Do not change the name of this folder, keep `setup-envs`. +# other workflows need the name of the action to work. + +# https://docs.github.com/actions/using-workflows/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache + +name: "Setup deps envs" +description: | + Setup and cache deps envs for hatch and pre-commit. + will: + `pip install -r requirements.txt -U` + cache hatch venv + cache pre-commit venv + NOTE: `setup-python` first. + +inputs: + python-version: + description: "steps.setup-python.outputs.python-version" + required: true + python-path: + description: "steps.setup-python.outputs.python-path" + required: true + cache: + description: "Whether to use cache; set `true` to use cache" + default: "false" + required: false + +outputs: + hatch-cache-hit: + description: "hatch venv cache hit" + value: ${{ steps.cache-hatch-venv.outputs.cache-hit }} + pre-commit-cache-hit: + description: "pre-commit venv cache hit" + value: ${{ steps.cache-pre-commit-venv.outputs.cache-hit }} + +runs: + using: composite + steps: + # pip install hatch and pre-commit + - name: Install dependencies + shell: bash + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements.txt -U + python -m pip freeze --local + + # cache hatch venv + - name: cache hatch venv + id: cache-hatch-venv + if: ${{ inputs.cache == 'true' }} + uses: actions/cache@v3 + env: + CACHE_VERSION: v1 + with: + # Don't cache `.venv-default`, re-creat it instead. + # Because we can't use `==` to constraint the version of deps, + # resulting in cache not being up-to-date + path: | + ./.venv-docs + ./.venv-fmt + key: + # `v1` is the version of this cache key + "\ + hatch-venv-\ + ${{ runner.os }}-\ + ${{ env.CACHE_VERSION }}-\ + python${{ inputs.python-version }}-\ + ${{ inputs.python-path }}-\ + ${{ hashFiles('pyproject.toml', 'requirements.txt') }}\ + " + restore-keys: + hatch-venv-${{ runner.os }}- + + # cache pre-commit venv + # ref: https://github.com/pre-commit/action/blob/c7d159c2092cbfaab7352e2d8211ab536aa2267c/action.yml + # https://pre-commit.com/#github-actions-example + - name: cache pre-commit venv + uses: actions/cache@v3 + id: cache-pre-commit-venv + if: ${{ inputs.cache == 'true' }} + env: + CACHE_VERSION: v1 + with: + path: ~/.cache/pre-commit + key: + # `v1` is the version of this cache key + "\ + pre-commit-3-\ + ${{ runner.os }}-\ + ${{ env.CACHE_VERSION }}-\ + python${{ inputs.python-version }}-\ + ${{ inputs.python-path }}-\ + ${{ hashFiles('.pre-commit-config.yaml') }}\ + " + restore-keys: + pre-commit-3-${{ runner.os }}- diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..645d4a5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,29 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + # GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + # https://docs.github.com/zh/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#groups + groups: + actions: + patterns: + - "*" + # Python + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "daily" + # groups: + # pip: + # patterns: + # - "*" + # update-types: + # - "minor" + # - "patch" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..f4640f6 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,13 @@ + + +# Summary + + + +# Checklist + +- [ ] I've read `CONTRIBUTING.md`. +- [ ] I understand that this PR may be closed in case there was no previous discussion. (This doesn't apply to typos!) +- [ ] I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change. +- [ ] I've updated the documentation accordingly. diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..848b0b2 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,71 @@ +# copy from: https://github.com/frankie567/httpx-ws/blob/main/.github/workflows/docs.yml + +# WARNING: Do not change the name of this file, keep `docs.yml`. +# markdown badges are hard-coded to point to this file. + +name: Deploy documentation + +# Since document updates may be frequent, +# we do not run tests when deploying documents, +# instead test during the PR stage. +on: + push: + branches: + - main + workflow_dispatch: + +# Allow one concurrent deployment +concurrency: + group: "pages" + cancel-in-progress: true + +# Default to bash +defaults: + run: + shell: bash + +jobs: + build-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + # https://github.com/timvink/mkdocs-git-revision-date-localized-plugin#note-when-using-build-environments + with: + fetch-depth: 0 + - name: Set up Python + uses: actions/setup-python@v5 + id: setup-python + with: + python-version: "3.10" + # Issue ref: https://github.com/actions/setup-python/issues/436 + cache: "pip" + # setup and cache envs + - name: setup and cache envs + id: setup-envs + uses: ./.github/actions/setup-envs + with: + python-version: ${{ steps.setup-python.outputs.python-version }} + python-path: ${{ steps.setup-python.outputs.python-path }} + cache: true + + - name: Build + run: hatch run docs:build + - name: Upload artifact + uses: actions/upload-pages-artifact@v2 + with: + path: ./site + + deploy-docs: + needs: build-docs + # Grant GITHUB_TOKEN the permissions required to make a Pages deployment + permissions: + pages: write # to deploy to Pages + id-token: write # to verify the deployment originates from an appropriate source + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v3 diff --git a/.github/workflows/lint-test.yml b/.github/workflows/lint-test.yml new file mode 100644 index 0000000..ada017e --- /dev/null +++ b/.github/workflows/lint-test.yml @@ -0,0 +1,96 @@ +# WARNING: Do not change the name of this file, keep `lint-test.yml`. +# `workflow_call` needs the name of the workflow file to work. + +name: Lint check and test + +# We only automatically run checks for PRs. +# It is best to avoid direct commits to the main branch, instead make a PR for checks. +# For the pushes to the main branch, the checks is done by `publish.yml` when publish. +on: + pull_request: + workflow_dispatch: + # NOTE: set `secrets: inherit` when call this workflow from other workflow. + workflow_call: + +jobs: + lint-check: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + id: setup-python + with: + python-version: ${{ matrix.python-version }} + # Issue ref: https://github.com/actions/setup-python/issues/436 + cache: "pip" + # setup and cache envs + - name: setup and cache envs + id: setup-envs + uses: ./.github/actions/setup-envs + with: + python-version: ${{ steps.setup-python.outputs.python-version }} + python-path: ${{ steps.setup-python.outputs.python-path }} + cache: true + + - name: Lint check and type check + # keep the hook name consistent with `ci.skip` in `.pre-commit-config.yaml` + run: | + pre-commit run type-check + pre-commit run fmt-check + + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + os: ["ubuntu-latest", "windows-latest"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + # Issue ref: https://github.com/actions/setup-python/issues/436 + cache: "pip" + # setup and cache envs + - name: setup and cache envs + id: setup-envs + uses: ./.github/actions/setup-envs + with: + python-version: ${{ steps.setup-python.outputs.python-version }} + # # https://github.com/actions/setup-python/blob/e9d6f990972a57673cdb72ec29e19d42ba28880f/docs/advanced-usage.md#environment-variables + python-path: ${{ steps.setup-python.outputs.python-path }} + cache: true + + - name: Test + # Prevent unknown errors from causing long-term blockage of ci during testing + # can be adjusted according to the actual test time + timeout-minutes: 5 + run: | + hatch run test + - name: Upload coverage reports to Codecov with GitHub Action + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true + fail_ci_if_error: true + + # https://github.com/marketplace/actions/alls-green#why + lint-test-all-green: # This job does nothing and is only used for the branch protection + if: always() # IMPORTANT: mandatory + needs: + - lint-check + - test + runs-on: ubuntu-latest + steps: + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 + with: + jobs: ${{ toJSON(needs) }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..f2b8354 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,93 @@ +# refer to: https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/ + +# WARNING: Do not change the name of this file, keep `publish.yml`. +# "trusted publishing" will check the name of the workflow file. + +name: Publish Python ๐Ÿ distribution ๐Ÿ“ฆ to PyPI + +on: + push: + tags: + - v* + +jobs: + lint-test: + name: Lint check and test ๐Ÿงช + uses: ./.github/workflows/lint-test.yml + secrets: inherit # IMPORTANT: sub-workflow needs secrets for uploading codecov + + build-dist: + needs: + - lint-test + name: Build distribution ๐Ÿ“ฆ + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + id: setup-python + uses: actions/setup-python@v5 + with: + # NOTE: Do not use cache, create a new environment is better. + python-version: "3.10" + # setup and cache envs + - name: setup and cache envs + id: setup-envs + uses: ./.github/actions/setup-envs + with: + python-version: ${{ steps.setup-python.outputs.python-version }} + python-path: ${{ steps.setup-python.outputs.python-path }} + # NOTE: Do not use cache, create a new environment is better. + cache: false + + - name: Build a binary wheel and a source tarball + run: | + hatch build + - name: Store the distribution packages + uses: actions/upload-artifact@v4 + with: + name: python-package-distributions + path: dist/ + if-no-files-found: error + + publish-to-pypi: + needs: + - build-dist + name: Publish Python ๐Ÿ distribution ๐Ÿ“ฆ to PyPI + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/ # EDIT + permissions: + id-token: write # IMPORTANT: mandatory for trusted publishing + steps: + - name: Download all the dists + uses: actions/download-artifact@v4 + with: + # https://github.com/actions/download-artifact/blob/f44cd7b40bfd40b6aa1cc1b9b5b7bf03d3c67110/docs/MIGRATION.md + pattern: python-package-distributions* + merge-multiple: true + path: dist/ + - name: Publish distribution ๐Ÿ“ฆ to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + github-release: + needs: + - publish-to-pypi + name: Create GitHub release ๐Ÿท๏ธ + runs-on: ubuntu-latest + permissions: + contents: write # IMPORTANT: mandatory for creating release + steps: + - name: Download all the dists + uses: actions/download-artifact@v4 + with: + # https://github.com/actions/download-artifact/blob/f44cd7b40bfd40b6aa1cc1b9b5b7bf03d3c67110/docs/MIGRATION.md + pattern: python-package-distributions* + merge-multiple: true + path: dist/ + - name: Create release + uses: ncipollo/release-action@v1 + with: + draft: true + body: ${{ github.event.head_commit.message }} + artifacts: dist/*.whl,dist/*.tar.gz diff --git a/.gitignore b/.gitignore index d9005f2..0bf9b46 100644 --- a/.gitignore +++ b/.gitignore @@ -150,3 +150,16 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +# only track the `extensions.json` +/.vscode/* +!/.vscode/extensions.json + +# ignore temporary files +Untitled*.ipynb +Untitled*.py + +# hatch venv +.venv-default/ +.venv-docs/ +.venv-fmt/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..2c2da04 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,48 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks + +# # set `default_language_version` need this version of Python existed on the computer +# default_language_version: +# python: python3.10 + +default_install_hook_types: [pre-commit, commit-msg] + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: no-commit-to-branch + - id: check-added-large-files + - id: check-toml + - id: check-json + - id: check-yaml + args: + - --unsafe + - id: end-of-file-fixer + - id: trailing-whitespace + - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook + rev: v9.10.0 + hooks: + - id: commitlint + stages: [commit-msg] + # NOTE: the dependencies must consistent with `commitlint.config.js` + additional_dependencies: ["@commitlint/config-conventional"] + - repo: local + hooks: + - id: fmt-check + stages: [pre-commit] + name: python format check + language: system + entry: hatch run fmt:fmt-check + types: [python] + - id: type-check + stages: [pre-commit] + name: python type check + language: system + entry: hatch run type-check + types: [python] + +ci: + # NOTE: skip all local system hooks + # NOTE: keep the name of hooks which be skipped consistent with `.github/workflows/lint-test.yml` + skip: [fmt-check, type-check] diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..96bd75c --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "njpwerner.autodocstring", + "ms-python.vscode-pylance", + "ms-python.python", + "charliermarsh.ruff" + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..872e432 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,27 @@ + + + + +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +- `Added` for new features. +- `Changed` for changes in existing functionality. +- `Deprecated` for soon-to-be removed features. +- `Removed` for now removed features. +- `Fixed` for any bug fixes. +- `Security` in case of vulnerabilities. +- `[YANKED]` for deprecated releases. + + + + +## [Unreleased] + + + + [unreleased]: https://github.com/WSH032/pyproject-template/tree/HEAD diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..89e4aea --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,212 @@ + + + + +# Contributing + +> The guide is modified from [mkdocstrings](https://mkdocstrings.github.io/contributing/#contributing) + +Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given. + +## Environment setup + +First, `fork` and `clone` the repository, then `cd` to the directory. + +We use [`hatch`](https://github.com/pypa/hatch) and [`pre-commit`](https://pre-commit.com/) to manage our project. + +You can install them with: + +```shell +# https://pypa.github.io/pipx/ +python3 -m pip install --user pipx + +pipx install hatch +pipx install pre-commit +``` + +!!! note + check `requirements.txt` to know the version of `hatch` and `pre-commit` we use. + +Then, initialize the env with: + +```shell +# Init pre-commit +# https://pre-commit.com/#3-install-the-git-hook-scripts +pre-commit install +pre-commit run --all-files + +# https://hatch.pypa.io/latest/environment/ +hatch shell +``` + +That's all! Now, you can start to develop. + +## Code style + +The source code is in `src/` + +We use [Ruff](https://github.com/astral-sh/ruff), [Pyright](https://github.com/Microsoft/pyright/) + and [Codespell](https://github.com/codespell-project/codespell) to format, lint our code and type check. + +Please check `pyproject.toml` to know our style. + +If you want to format your code, you can use the following command: + +```shell +hatch run fmt:fmt +hatch run fmt:spell-fix +``` + +or, dry run to check: + +```shell +hatch run fmt:fmt-check +``` + +If you want to perform type checking, you can use the following command: + +```shell +hatch run type-check +``` + +!!! tip + If you use `VSCode`, we strongly recommend you to install the extensions in `.vscode/extensions.json`.
+ Because our code style rules are quite strict.
+ These extensions can help you know where need to be fixed when coding. + +## Testing + +We use [pytest](https://docs.pytest.org/en/stable/) to test our code. + +The test source code is in `tests/` + +You can run the testing with: + +```shell +hatch run test +``` + +## Documentation + +We use [mkdocs](https://www.mkdocs.org), [mkdocs-material](https://squidfunk.github.io/mkdocs-material), [mkdocstrings](https://mkdocstrings.github.io) to build our documentation. + +The documentation source code is in `docs/`, `mkdocs.yml`, + may be there is also some source code in `scripts/` or somewhere (check `mkdocs.yml` to find that). + +Live-reloading docs: + +```shell +hatch run docs:mkdocs serve +``` + +Build docs: + +```shell +hatch run docs:build +``` + +### mkdocs reference + +!!! tip + + - [mkdocs/getting-started](https://www.mkdocs.org/getting-started/) + - [mkdocs-material/getting-started](https://squidfunk.github.io/mkdocs-material/getting-started/) + +### Code Docstring styles + +!!! warning + + We use `Google` style to write docstrings, please refer to + + - [mkdocstrings-python's documentation](https://mkdocstrings.github.io/python/usage/docstrings/google/) + - [Napoleon's documentation](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html) + - [Griffe's documentation](https://mkdocstrings.github.io/griffe/docstrings/) + +## PR + +- PRs should target the `main` branch. +- Keep branches up to date by `rebase` before merging. +- Do not add multiple unrelated things in same PR. +- Do not submit PRs where you just take existing lines and reformat them without changing what they do. +- Do not change other parts of the code that are not yours for formatting reasons. +- Do not use your clone's main branch to make a PR - create a branch and PR that. + +### Edit `CHANGELOG.md` + +If you have made the corresponding changes, please record them in `CHANGELOG.md`. + +### Commit message convention + +Commit messages must follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), +or, `pre-commit` may be reject your commit. + +!!! info + If you don't know how to finish these, it's okay, feel free to initiate a PR, I will help you continue. + +## More + +There may still be some useful commands in `pyproject.toml`, you can refer to [hatch/environment/scripts](https://hatch.pypa.io/latest/config/environment/overview/#scripts) to use them. + +!!! info + If you find that the commands given in the above examples are incorrect, please open an issue, we greatly appreciate it. + +--- + +## ๐Ÿ˜ข + +!!! warning + The following ๐Ÿ‘‡ content is for the maintainers of this project, may be you don't need to read it. + +--- + +## deploy-docs + +please refer to `.github/workflows/docs.yml` + +## CI: lint-test + +please refer to `.github/workflows/lint-test.yml` + +## Publish and Release ๐Ÿš€ + +**^^First, check-out to a new branch, edit `CHANGELOG.md` to record the changes.^^** + +Then, please refer to: + +- `.github/workflows/publish.yml` +- +- + +Update version in **^^new branch^^** with: + +```shell +git add . +hatch version {new_version} +``` + +It will create a commit and tag automatically. + +Then, push the **new branch** with **tag** to GitHub, and create a PR to `main` branch. + +!!! warning + The `bump version` PR must have **only one commit with the corresponding tag**; otherwise, it will be rejected. + +Review the PR, if it's ok, **rebase** it to `main` branch **^^in local^^** + +!!! warning + **DO NOT rebase with tag in GitHub**, refer to + +Check if everything is ok, for example: + +- **check if the tag is on the `main` branch**. +- check if the link in `CHANGELOG.md` is correct. + +If so, make a `approve` in environment `pypi` for the workflow. + +After that, the `publish.yml` workflow will build and publish the package to PyPI. + +Finally, edit the `draft release` created by `publish.yml` workflow, and publish the release. + +!!! warning + The creating of tag needs signature verification,
+ please refer to diff --git a/README.md b/README.md index 98905ca..dc2e977 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,88 @@ + + + + # pyproject-template - + +

+ Stubborn python project scaffold +
+ ๅ›บๆ‰งๅทฑ่ง็š„python้กน็›ฎๆ‰‹่„šๆžถ +

+ +## ็”จๆณ• + +1. ๆŒ‰็…ง `CONTRIBUTING.md` ๅˆๅง‹ๅŒ–้กน็›ฎ +2. ไฟฎๆ”นๆ‰€ๆœ‰ๅธฆๆœ‰ `EDIT` ๆณจ้‡Š็š„ๅœฐๆ–น +3. ๅฐ† `githubไป“ๅบ“่ฎพ็ฝฎ`๏ผŒ`็Žฏๅขƒๅ˜้‡ๆœบๅฏ†`๏ผŒ`ไฟๆŠค่ง„ๅˆ™` ่ฎพ็ฝฎๅพ—ๅ’Œๆœฌไป“ๅบ“๏ผˆ`pyproject-template`๏ผ‰ๅฎŒๅ…จไธ€่‡ด +4. ็”ณ่ฏท`codecov`ๅ’Œ`pre-commit.ci`็š„BOT APP +5. ๆŒ‰็…ง[pypa](https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/)็š„ๆŒ‡ๅ—ๅŽป `pypi` ็”ณ่ฏท `Trusted Publisher` +6. ๅŒๆญฅไธชไบบ็š„`VSCode`่ฎพ็ฝฎๅ’Œๆ‰ฉๅฑ• +7. ๅˆ ๆŽ‰ๆœฌ็”จๆณ•้ƒจๅˆ† +8. Python๏ผŒๅฏๅŠจ๏ผโœจ + +็บฏpythonๆ‰“ๅŒ…ๅ‚่€ƒ +ๅธฆๆœ‰ไธๅŒๅนณๅฐ็š„ไบŒ่ฟ›ๅˆถไพ่ต–ๆ‰“ๅŒ…ๅ‚่€ƒ + +--- + +| | | +| - | - | +| CI/CD | [![CI: lint-test]][CI: lint-test#link] [![pre-commit.ci status]][pre-commit.ci status#link]
[![CI: docs]][CI: docs#link] [![CI: publish]][CI: publish#link] | +| Code | [![codecov]][codecov#link] [![Code style: black]][Code style: black#link] [![Ruff]][Ruff#link] [![Checked with pyright]][Checked with pyright#link] | +| Package | [![PyPI - Version]][PyPI#link] [![PyPI - Downloads]][PyPI#link] [![PyPI - Python Version]][PyPI#link] | +| Meta | [![Hatch project]][Hatch project#link] [![GitHub License]][GitHub License#link] | + +--- + +Documentation: + +Source Code: + +--- + +## development + +- If you find any issues, please don't hesitate to [open an issue](https://github.com/WSH032/pyproject-template/issues). +- If you need assistance, feel free to [start a discussion](https://github.com/WSH032/pyproject-template/discussions). +- Follow our `CONTRIBUTING.md`, [PR Welcome!](https://github.com/WSH032/pyproject-template/pulls) +- Security ๐Ÿ˜ฐโ—: We value any security vulnerabilities, [please report to us privately](https://github.com/WSH032/pyproject-template/security), pretty appreciated for that. + +English is not the native language of the author (me), so if you find any areas for improvement in the documentation, your feedback is welcome. + +If you think this project helpful, consider giving it a star ![GitHub Repo stars](https://img.shields.io/github/stars/wsh032/pyproject-template?style=social), which makes me happy. :smile: + + + + + +[CI: lint-test]: https://github.com/WSH032/pyproject-template/actions/workflows/lint-test.yml/badge.svg +[CI: lint-test#link]: https://github.com/WSH032/pyproject-template/actions/workflows/lint-test.yml +[CI: docs]: https://github.com/WSH032/pyproject-template/actions/workflows/docs.yml/badge.svg +[CI: docs#link]: https://github.com/WSH032/pyproject-template/actions/workflows/docs.yml +[CI: publish]: https://github.com/WSH032/pyproject-template/actions/workflows/publish.yml/badge.svg +[CI: publish#link]: https://github.com/WSH032/pyproject-template/actions/workflows/publish.yml +[pre-commit.ci status]: https://results.pre-commit.ci/badge/github/WSH032/pyproject-template/main.svg +[pre-commit.ci status#link]: https://results.pre-commit.ci/latest/github/WSH032/pyproject-template/main + + +[Code style: black]: https://img.shields.io/badge/code%20style-black-000000.svg +[Code style: black#link]: https://github.com/psf/black + [GitHub License]: https://img.shields.io/github/license/WSH032/pyproject-template?color=9400d3 + [GitHub License#link]: https://github.com/WSH032/pyproject-template/blob/main/LICENSE +[Ruff]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json +[Ruff#link]: https://github.com/astral-sh/ruff +[Checked with pyright]: https://microsoft.github.io/pyright/img/pyright_badge.svg +[Checked with pyright#link]: https://microsoft.github.io/pyright + + +[PyPI - Version]: https://img.shields.io/pypi/v/?logo=pypi&label=PyPI&logoColor=gold +[PyPI - Downloads]: https://img.shields.io/pypi/dm/?color=blue&label=Downloads&logo=pypi&logoColor=gold +[PyPI - Python Version]: https://img.shields.io/pypi/pyversions/?logo=python&label=Python&logoColor=gold +[PyPI#link]: https://pypi.org/project/ + + +[Hatch project]: https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg +[Hatch project#link]: https://github.com/pypa/hatch + [codecov]: https://codecov.io/gh/WSH032/pyproject-template/graph/badge.svg?token=62QQU06E8X + [codecov#link]: https://codecov.io/gh/WSH032/pyproject-template diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000..2e6affe --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,6 @@ +// refer to: https://commitlint.js.org/#/reference-configuration?id=shareable-configuration +// Rule: https://karma-runner.github.io/6.4/dev/git-commit-msg.html +// Rule: https://github.com/conventional-changelog/commitlint/tree/master/@commitlint/config-conventional + +// NOTE: the extends must consistent with `.pre-commit-config.yaml` +module.exports = { extends: ['@commitlint/config-conventional'] }; diff --git a/docs/CHANGELOG/CHANGELOG.md b/docs/CHANGELOG/CHANGELOG.md new file mode 100644 index 0000000..786b75d --- /dev/null +++ b/docs/CHANGELOG/CHANGELOG.md @@ -0,0 +1 @@ +--8<-- "CHANGELOG.md" diff --git a/docs/CONTRIBUTING/CONTRIBUTING.md b/docs/CONTRIBUTING/CONTRIBUTING.md new file mode 100644 index 0000000..ea38c9b --- /dev/null +++ b/docs/CONTRIBUTING/CONTRIBUTING.md @@ -0,0 +1 @@ +--8<-- "CONTRIBUTING.md" diff --git a/docs/images/rocket-24.svg b/docs/images/rocket-24.svg new file mode 100644 index 0000000..8660bbf --- /dev/null +++ b/docs/images/rocket-24.svg @@ -0,0 +1 @@ + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..612c7a5 --- /dev/null +++ b/docs/index.md @@ -0,0 +1 @@ +--8<-- "README.md" diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..e33b409 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,152 @@ +# yaml-language-server: $schema=https://squidfunk.github.io/mkdocs-material/schema.json + +site_name: pyproject-template # EDIT +site_url: https://WSH032.github.io/pyproject-template/ # EDIT + +repo_url: https://github.com/WSH032/pyproject-template/ # EDIT +repo_name: WSH032/pyproject-template # EDIT + +edit_uri: edit/main/docs/ + +theme: + name: material + icon: + logo: octicons/rocket-24 # EDIT: or do nothing + favicon: images/rocket-24.svg # EDIT: or do nothing + features: + - content.code.copy + - content.code.annotate + - navigation.instant + - navigation.instant.progress + - navigation.tabs + - search.suggest + - search.highlight + - search.share + - navigation.footer + - content.action.edit + - content.action.view + - content.tabs.link + - content.tooltips + - navigation.top + # - navigation.expand + # - navigation.tracking + # https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/#system-preference + palette: + # Palette toggle for automatic mode + - media: "(prefers-color-scheme)" + toggle: + icon: material/brightness-auto + name: Switch to light mode + # Palette toggle for light mode + - media: "(prefers-color-scheme: light)" + scheme: default + toggle: + icon: material/brightness-7 + name: Switch to dark mode + # Palette toggle for dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + toggle: + icon: material/brightness-4 + name: Switch to system preference + +markdown_extensions: + # Python Markdown + - abbr + - admonition + - attr_list + - def_list + - footnotes + - md_in_html + - tables + - toc: + permalink: true + + # Python Markdown Extensions + - pymdownx.arithmatex: + generic: true + - pymdownx.betterem: + smart_enable: all + - pymdownx.critic + - pymdownx.caret + - pymdownx.details + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + - pymdownx.highlight: + anchor_linenums: true + line_spans: __span + pygments_lang_class: true + - pymdownx.snippets + - pymdownx.inlinehilite + - pymdownx.keys + - pymdownx.mark + - pymdownx.smartsymbols + - pymdownx.superfences + # - pymdownx.superfences: + # custom_fences: + # - name: mermaid + # class: mermaid + # format: !!python/name:pymdownx.superfences.fence_code_format + - pymdownx.tabbed: + alternate_style: true + slugify: !!python/object/apply:pymdownx.slugs.slugify + kwds: + case: lower + - pymdownx.tasklist: + custom_checkbox: true + - pymdownx.tilde + +plugins: + # - offline + - search + - gen-files: + scripts: + - scripts/gen_ref_pages.py + - literate-nav: + nav_file: SUMMARY.md + - section-index + - mkdocstrings: + default_handler: python + handlers: + python: + # https://mkdocstrings.github.io/python/usage/#import + import: [] # EDIT + options: + docstring_style: google + paths: [src] + # Remember: https://github.com/timvink/mkdocs-git-revision-date-localized-plugin#note-when-using-build-environments + - git-revision-date-localized: + fallback_to_build_date: true + enable_creation_date: true + type: timeago + - git-committers: + repository: WSH032/pyproject-template # EDIT + branch: main + +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/WSH032/ # EDIT + +watch: + - src/ + - README.md + - CONTRIBUTING.md + - CHANGELOG.md + +validation: + omitted_files: warn + absolute_links: warn + unrecognized_links: warn + +# Don't change the name "reference/" +# It's used in scripts/gen_ref_pages.py +nav: + - Home: index.md + - Usage: [] # EDIT + - API Reference: reference/ + - CONTRIBUTING: + - CONTRIBUTING/CONTRIBUTING.md + - CHANGELOG: + - CHANGELOG/CHANGELOG.md diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b81830c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,238 @@ +# https://hatch.pypa.io/latest/config/metadata/ +[project] +name = "pyproject-template" # EDIT +requires-python = ">=3.8" +readme = "README.md" +license = { file = "LICENSE" } +authors = [ + { name = "Sean Wang", email = "126865849+WSH032@users.noreply.github.com" }, # EDIT +] +description = "pyproject-template." # EDIT +keywords = ["pyproject-template"] # EDIT +# https://pypi.org/classifiers/ +classifiers = [ + "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 :: 3 :: Only", +] # EDIT + +dynamic = ["version"] + +# NOTE: version constraints +# https://iscinumpy.dev/post/bound-version-constraints/ + +dependencies = [] # EDIT + +[project.optional-dependencies] +# NOTE: Must use `==` to constrain version for github actions cache working properly +dev_fmt = [ + "ruff==0.1.9", + "codespell==2.2.6", + "tomli", # tomli needed for `codespell` +] +# NOTE: Must use `==` to constrain version for github actions cache working properly +dev_test = [ + "pyright == 1.1.338", + "pytest==7.4.3", + "pytest-cov== 4.1.0", + "pytest-timeout==2.2.0", +] +# NOTE: Must use `==` to constrain version for github actions cache working properly +dev_docs = [ + "mkdocs-material == 9.5.3", + "mkdocstrings[python] == 0.24.0", + "mkdocs-gen-files == 0.5.0", + "mkdocs-literate-nav == 0.6.1", + "mkdocs-section-index == 0.3.8", + "mkdocs-git-revision-date-localized-plugin == 1.2.1", + "mkdocs-git-committers-plugin-2 == 2.2.2", +] + + +[project.urls] +Documentation = "https://WSH032.github.io/pyproject-template/" # EDIT +"Source code" = "https://github.com/WSH032/pyproject-template/" # EDIT + + +# https://hatch.pypa.io/latest/config/metadata/#cli +# [project.scripts] +# EDIT: add or delete here + + +[build-system] +requires = ["hatch-regex-commit"] +build-backend = "hatchling.build" + + +[tool.hatch.build.targets.wheel] +# https://hatch.pypa.io/latest/plugins/builder/wheel/#default-file-selection +# https://hatch.pypa.io/latest/config/build/#packages + + +[tool.hatch.version] +# refer to: https://github.com/frankie567/hatch-regex-commit +source = "regex_commit" +commit_extra_args = ["-e"] +path = "src/pyproject_template/__init__.py" # EDIT: repo name +# NOTE: `chore` is required by commitlint +commit_message = "chore(version): ๐Ÿš€ bump version v{current_version} โ†’ v{new_version}" +tag_message = "๐Ÿš€ bump version v{current_version} โ†’ v{new_version}" +# NOTE: `v` prefix is required by github `publish.yml` action +tag_name = "v{new_version}" +check_dirty = false + + +[tool.hatch.envs.default] +path = ".venv-default" # NOTE: Do not change the path, it's used in github action cache +features = ["dev_test"] + +# NOTE: Do not change the scripts name, it's used in pre-commit local hook +[tool.hatch.envs.default.scripts] +# https://pytest-cov.readthedocs.io/en/latest/config.html +# xml for codecov, html for local review +test = "pytest tests/ --cov --cov-report=xml --cov-report=html" +type-check = [ + "pyright .", + "pyright --verifytypes pyproject_template --ignoreexternal", # EDIT: change `pyproject_template` to your package name +] + + +[tool.hatch.envs.fmt] +path = ".venv-fmt" # NOTE: Do not change the path, it's used in github action cache +features = ["dev_fmt"] +detached = true + +# NOTE: Do not change the scripts name, it's used in pre-commit local hook +[tool.hatch.envs.fmt.scripts] +# lint must before format +fmt = ["- ruff check . --fix", "- ruff format ."] +spell-fix = "codespell . -i 3 -w" +fmt-check = ["ruff check .", "ruff format --check .", "codespell ."] + + +[tool.hatch.envs.docs] +path = ".venv-docs" # NOTE: Do not change the path, it's used in github action cache +features = ["dev_docs"] +detached = true + +# NOTE: Do not change the scripts name, it's used in pre-commit local hook +[tool.hatch.envs.docs.scripts] +serve = "mkdocs serve" +build = "mkdocs build" + + +[tool.ruff.format] +docstring-code-format = true + +# https://docs.astral.sh/ruff/rules/ +[tool.ruff] +select = [ + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # pyflakes + "I", # isort + "C4", # flake8-comprehensions + "B", # flake8-bugbear + "N", # pep8-naming + "UP", # pyupgrade + "D", # pydocstyle + "SIM", # flake8-simplify + "RUF", # unused-noqa + "Q", # flake8-quotes + "C90", # McCabe complexity + "ANN001", # missing-type-function-argument + "ANN201", # missing-return-type-undocumented-public-function + "ASYNC", # flake8-async + "A", # flake8-builtins + "COM", # flake8-commas + "ISC", # flake8-implicit-str-concat + "ICN001", # unconventional-import-alias + "PIE", # flake8-pie + "PT", # flake8-pytest-style + "INT", # flake8-gettext + "ARG", # flake8-unused-arguments + "PGH004", # blanket-noqa + "TRY201", # Use raise without specifying exception name + "NPY", # NumPy-specific rules + "PD", # pandas-vet + "PERF", # Perflint + "PL", # Pylint + "TID252", # Relative imports from parent modules are banned +] +ignore = [ + "E501", # line too long, handled by black + "COM812", # missing-trailing-comma + "PERF203", # try-except within a loop incurs performance overhead + "PLR2004", # magic-value-comparison + "PLR5501", # collapsible-else-if + "PLW0120", # useless-else-on-loop + "PLR0911", # too-many-return-statements + "PLR0913", # too-many-arguments + "PLC0205", # single-string-slots + "PLW0603", # global-statement + "PLC1901", # compare-to-empty-string + "PLR0904", # too-many-public-methods + "RUF002", # ambiguous-unicode-character-docstring + "RUF003", # ambiguous-unicode-character-comment + "SIM105", # suppressible-exception # slower + "ISC001", + # "D418", # Function decorated with `@overload` shouldn't contain a docstring + # "SIM108", # if-else-block-instead-of-if-exp +] + +# https://docs.astral.sh/ruff/settings/#pydocstyle +[tool.ruff.pydocstyle] +convention = "google" + +# [tool.ruff.flake8-tidy-imports] +# ban-relative-imports = "all" + + +# https://microsoft.github.io/pyright/#/configuration +[tool.pyright] +typeCheckingMode = "strict" +pythonVersion = "3.8" +reportUnusedImport = "warning" +reportUnusedFunction = "warning" +reportUnusedExpression = "warning" +reportUnusedVariable = "warning" +reportUnnecessaryTypeIgnoreComment = true +reportPrivateUsage = "warning" +reportUnnecessaryIsInstance = "warning" +reportIncompatibleMethodOverride = "warning" +reportMissingTypeArgument = true +reportMissingParameterType = true + + +# https://coverage.readthedocs.io/en/7.3.2/config.html#run +[tool.coverage.run] +branch = true +source = ['pyproject_template'] # EDIT + +# https://coverage.readthedocs.io/en/7.3.2/config.html#report +[tool.coverage.report] +exclude_also = [ + "if __name__ == .__main__.:", + "if TYPE_CHECKING:", + "raise NotImplementedError", + "class .*\\bProtocol\\):", + "@(abc\\.)?abstractmethod", + # # deprecated code will not be tested + "@(typing_extensions\\.)?deprecated", + # `overload` just for type hint, will not be tested + "@(typing_extensions\\.)?overload", + "@(typing\\.)?overload", + "raise AssertionError", +] + + +[tool.codespell] +# https://github.com/codespell-project/codespell/issues/1887 +skip = "./htmlcov,./site" + + +[tool.pytest.ini_options] +timeout = 15 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b518cd9 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +# NOTE: Must use `==` to constrain version for github actions cache working properly + +hatch == 1.9.1 +pre-commit == 3.6.0 diff --git a/scripts/gen_ref_pages.py b/scripts/gen_ref_pages.py new file mode 100644 index 0000000..26da0e5 --- /dev/null +++ b/scripts/gen_ref_pages.py @@ -0,0 +1,55 @@ +# pyright: basic + +"""Generate the code reference pages and navigation. + +Copy form: https://mkdocstrings.github.io/recipes/ + +NOTE: Keep the following directory structure: + +๐Ÿ“ repo/ +โ”œโ”€โ”€ ๐Ÿ“ docs/ +โ”‚ โ””โ”€โ”€ ๐Ÿ“„ index.md +โ”œโ”€โ”€ ๐Ÿ“ scripts/ +โ”‚ โ””โ”€โ”€ ๐Ÿ“„ gen_ref_pages.py +โ”œโ”€โ”€ ๐Ÿ“ src/ +โ”‚ โ””โ”€โ”€ ๐Ÿ“ project/ +โ””โ”€โ”€ ๐Ÿ“„ mkdocs.yml +""" + +from pathlib import Path + +import mkdocs_gen_files # type: ignore + +nav = mkdocs_gen_files.Nav() + +SRC = Path(__file__).parent.parent / "src" +INDEX_MD_NAME = "index.md" + +for path in sorted(SRC.rglob("*.py")): + module_path = path.relative_to(SRC).with_suffix("") + doc_path = path.relative_to(SRC).with_suffix(".md") + # Don't change the name "reference" + # It's used in mkdocs.yml + full_doc_path = Path("reference", doc_path) + + parts = tuple(module_path.parts) + + if parts[-1] == "__init__": + parts = parts[:-1] + doc_path = doc_path.with_name(INDEX_MD_NAME) + full_doc_path = full_doc_path.with_name(INDEX_MD_NAME) + elif parts[-1].startswith("_"): + continue + + nav[parts] = doc_path.as_posix() + + with mkdocs_gen_files.open(full_doc_path, "w") as fd: + ident = ".".join(parts) + fd.writelines(f"::: {ident}") + + mkdocs_gen_files.set_edit_path(full_doc_path, Path("../") / path) + +# Don't change the name "reference/SUMMARY.md" +# It's used in mkdocs.yml +with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file: + nav_file.writelines(nav.build_literate_nav()) diff --git a/src/pyproject_template/__init__.py b/src/pyproject_template/__init__.py new file mode 100644 index 0000000..324e4ad --- /dev/null +++ b/src/pyproject_template/__init__.py @@ -0,0 +1,10 @@ +""".""" # EDIT + +# DO NOT EDIT THE `__version__` MANUALLY. +# Use `hatch version {new_version}` instead. +# Refer to `CONTRIBUTING.md` for more info. +__version__ = "0.0.1a0" + +__all__ = ("make_pyright_happy",) # EDIT: delete + +make_pyright_happy: str = "make_pyright_happy" # EDIT: delete diff --git a/src/pyproject_template/py.typed b/src/pyproject_template/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e32e54f --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +"""Tests for this project."""