main 06459b247e3a cached
14 files
14.5 KB
4.3k tokens
4 symbols
1 requests
Download .txt
Repository: FrancescoSaverioZuppichini/python-template
Branch: main
Commit: 06459b247e3a
Files: 14
Total size: 14.5 KB

Directory structure:
gitextract_ov64cyve/

├── .github/
│   └── workflows/
│       ├── build.yml
│       ├── publish.yml
│       └── test.yml
├── .gitignore
├── .python-version
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── examples/
│   └── main.py
├── pyproject.toml
├── src/
│   └── jokes/
│       ├── __init__.py
│       └── jokes.py
└── tests/
    └── test_jokes.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/build.yml
================================================
#
name: Create and publish a Docker image

# Configures this workflow to run every time a change is pushed to the branch called `release` or a new release is created.
on:
  release:
    types: [published]
  push:
    branches: ["release"]

# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.
jobs:
  build-and-push-image:
    runs-on: ubuntu-latest
    # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
    permissions:
      contents: read
      packages: write
      attestations: write
      id-token: write
      #
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
      - name: Log in to the Container registry
        uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
      # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
      # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository.
      # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.
      - name: Build and push Docker image
        id: push
        uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

      # This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see "[AUTOTITLE](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)."
      - name: Generate artifact attestation
        uses: actions/attest-build-provenance@v2
        with:
          subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
          subject-digest: ${{ steps.push.outputs.digest }}
          push-to-registry: true


================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish
on:
  push:
    branches:
      - main
jobs:
  build-format-and-publish-to-pypi:
    runs-on: ubuntu-latest
    # FROM https://github.com/pypa/gh-action-pypi-publish
    environment:
      name: pypi
      url: https://pypi.org/p/python-template-zuppif
    permissions:
      id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
    steps:
      - name: 🛎️ Checkout
        uses: actions/checkout@v4

      - name: 📦 Install uv
        uses: astral-sh/setup-uv@v4

      - name: 🐍 Set up Python
        uses: actions/setup-python@v5
        with:
          python-version-file: ".python-version"

      - name: 🦾 Install the project
        run: uv sync

      - name: 💅 Format
        run: uv run ruff format

      - name: 🦾 Build
        run: uv build

      - name: 🚀 Publish
        uses: pypa/gh-action-pypi-publish@release/v1


================================================
FILE: .github/workflows/test.yml
================================================
name: Test
on:
  pull_request:
    branches: [main, dev]

jobs:
  build-lint-format-and-test:
    runs-on: ubuntu-latest

    steps:
      - name: 🛎️ Checkout
        uses: actions/checkout@v4

      - name: 📦 Install uv
        uses: astral-sh/setup-uv@v4

      - name: 🐍 Set up Python
        uses: actions/setup-python@v5
        with:
          python-version-file: ".python-version"

      - name: 🦾 Install the project
        run: |
          uv sync --all-extras --dev
          uv pip install -e .

      - name: 💅 Link & Format Check
        run: make check_code_quality

      - name: 🧪 Test
        run: uv run pytest tests/


================================================
FILE: .gitignore
================================================
# ruff
.ruff_cache
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
#   For a library or package, you might want to ignore these files since the code is
#   intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
#   However, in case of collaboration, if having platform-specific dependencies or dependencies
#   having no cross-platform support, pipenv may install dependencies that don't work, or not
#   install all needed dependencies.
#Pipfile.lock

# UV
#   Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
#   This is especially recommended for binary packages to ensure reproducibility, and is more
#   commonly ignored for libraries.
#uv.lock

# poetry
#   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
#   This is especially recommended for binary packages to ensure reproducibility, and is more
#   commonly ignored for libraries.
#   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
#   in version control.
#   https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
#  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/

# PyPI configuration file
.pypirc


================================================
FILE: .python-version
================================================
3.12


================================================
FILE: Dockerfile
================================================
# Build stage
FROM python:3.12-slim AS builder

# Update image
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    && rm -rf /var/lib/apt/lists/*
# Install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# Set working directory
WORKDIR /app

# Install the project without the the source code (only dependencies)  
RUN --mount=type=cache,target=/root/.cache/uv \
    --mount=type=bind,source=uv.lock,target=uv.lock \
    --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
    uv sync --frozen --no-install-project --no-dev --compile-bytecode

# Install the project's source packages
ADD .python-version pyproject.toml uv.lock src/ /app/

RUN --mount=type=cache,target=/root/.cache/uv \
    uv pip install --compile-bytecode .

# Use alpine for the final image to reduce the total size
FROM python:3.12-alpine

# Copy the installed environment from builder
COPY --from=builder --chown=app:app /app /app

# Set working directory
WORKDIR /app

# Configure PATH for executables, packages are in the /app/.venv folder
ENV PATH="/app/.venv/bin:$PATH"

# Run command
CMD ["make_me_laugh"]

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2024 Francesco Saverio Zuppichini

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.


================================================
FILE: Makefile
================================================
.PHONY: style check_code_quality

export PYTHONPATH = .
check_dirs := src

style:
	uv run ruff format  $(check_dirs)
	uv run ruff check --select I --fix 

link:
	uv run ruff check --fix

check_code_quality:
	uv run ruff check $(check_dirs)
	# check sort
	uv run ruff check -e
	uv run ruff check --select I -e
	
publish:
	uv build
	uv publish --token $UV_PUBLISH_TOKEN

================================================
FILE: README.md
================================================
# Python Template 🐍
[![PyPI version](https://img.shields.io/pypi/v/python-template-zuppif)](https://pypi.org/project/python-template-zuppif/)

A template for a python project for 2025

Features:
- [x] 🛠️ configuration in a single file [`pyproject.toml`](pyproject.toml)
- [x] 📦 [`uv`](https://docs.astral.sh/uv/) as package manager
- [x] 💅 [`ruff`](https://docs.astral.sh/ruff/) for linting and formatting
- [x] 🧪 [`pytest`](https://docs.pytest.org/en/stable/) 
- [x] 🧹 [`Makefile`](Makefile) with code quality checks
- [ ] 📚 auto doc generation
- [x] 🐳 CI/CD Optimized Docker Image runs when a new *release* is created pushing to gh registry
- [x] 🦾 GitHub actions:
    - [x] auto publish to [`pypi`](https://pypi.org/) on push on `main`
    - [ ] auto creating a new tag on push on `main`, sync versions
    - [x] run `tests` and `lint` on `dev` and `main` when a PR is open

## Getting started

### Installation

To set it up and run

```bash
uv sync
```

Then

```bash
python main.py
```

Will output a random joke

```
Why did the cow in the pasture get promoted at work? ...  Because he is OUT-STANDING in his field!
```

You can now run, for example, a function defined as `scripts` in the [`pyproject.toml`](pyproject.toml)

```bash
make_me_laugh
```

### Linting

```
ruff check
```


### Formatting

```
ruff format
```

## CI/CD

### Tests
Tests inside `/tests` are run using [`pytest`](https://docs.pytest.org/en/stable/) on PR both on `dev` and `main`

### Publish Package
 In order to publish to [pypi](https://pypi.org/) you need to create a publisher on pypi.

This is explained [here](https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/) and [here](https://docs.pypi.org/trusted-publishers/) 

In practice go your pypi project -> Manage Project -> Publishing, scroll and "add a new publisher"


### Docker
[`Dockerfile`](Dockerfile) contains a multi stage build that uses `--compile-bytecode` to compite your package. For this example, the resulting image is just

```bash
docker build -t python-template .
```

```
REPOSITORY        TAG       IMAGE ID       CREATED          SIZE
python-template   latest    1ded7d260b1c   58 seconds ago   55.4MB
```

The image is build using the [`build`](.github/workflows/build.yml) workflow when a new *release* is created


================================================
FILE: examples/main.py
================================================
from jokes import make_me_laugh

make_me_laugh()


================================================
FILE: pyproject.toml
================================================
[project]
# https://docs.astral.sh/uv/concepts/projects/config/
name = "python-template-zuppif"
version = "0.1.3"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["requests>=2.32.3"]

[dependency-groups]
dev = ["pytest>=8.3.4", "ruff>=0.8.4"]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["src/jokes"]

[tool.ruff]
# https://docs.astral.sh/ruff/configuration/
target-version = "py312"


[project.scripts]
# will run the function by just typing `make_me_laugh` in the cli
make_me_laugh = "jokes:make_me_laugh"


================================================
FILE: src/jokes/__init__.py
================================================
from .jokes import get_joke


def make_me_laugh():
    joke = get_joke()
    print(f"{joke["preambula"]} ... {joke['punchline']}")


================================================
FILE: src/jokes/jokes.py
================================================
from random import choice
from typing import TypedDict

import requests

JOKES_FILE_URL = "https://gist.githubusercontent.com/FrancescoSaverioZuppichini/8e7614da3b156ccaa29d50211b790146/raw/79b00cdaa023903629052426b24cdee7212229c3/jokes.txt"


class Joke(TypedDict):
    preambula: str
    punchline: str


def get_joke() -> Joke:
    res = requests.get(JOKES_FILE_URL)
    content = res.text
    jokes = content.strip().split("\n")
    joke = choice(jokes)
    joke_splitted = joke.split("<>")
    return Joke(preambula=joke_splitted[0], punchline=joke_splitted[1])


================================================
FILE: tests/test_jokes.py
================================================
from jokes import get_joke


def test_jokes():
    joke = get_joke()
    assert "preambula" in joke
    assert "punchline" in joke
Download .txt
gitextract_ov64cyve/

├── .github/
│   └── workflows/
│       ├── build.yml
│       ├── publish.yml
│       └── test.yml
├── .gitignore
├── .python-version
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── examples/
│   └── main.py
├── pyproject.toml
├── src/
│   └── jokes/
│       ├── __init__.py
│       └── jokes.py
└── tests/
    └── test_jokes.py
Download .txt
SYMBOL INDEX (4 symbols across 3 files)

FILE: src/jokes/__init__.py
  function make_me_laugh (line 4) | def make_me_laugh():

FILE: src/jokes/jokes.py
  class Joke (line 9) | class Joke(TypedDict):
  function get_joke (line 14) | def get_joke() -> Joke:

FILE: tests/test_jokes.py
  function test_jokes (line 4) | def test_jokes():
Condensed preview — 14 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (16K chars).
[
  {
    "path": ".github/workflows/build.yml",
    "chars": 3379,
    "preview": "#\nname: Create and publish a Docker image\n\n# Configures this workflow to run every time a change is pushed to the branch"
  },
  {
    "path": ".github/workflows/publish.yml",
    "chars": 875,
    "preview": "name: Publish\non:\n  push:\n    branches:\n      - main\njobs:\n  build-format-and-publish-to-pypi:\n    runs-on: ubuntu-lates"
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 638,
    "preview": "name: Test\non:\n  pull_request:\n    branches: [main, dev]\n\njobs:\n  build-lint-format-and-test:\n    runs-on: ubuntu-latest"
  },
  {
    "path": ".gitignore",
    "chars": 3434,
    "preview": "# ruff\n.ruff_cache\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Dis"
  },
  {
    "path": ".python-version",
    "chars": 5,
    "preview": "3.12\n"
  },
  {
    "path": "Dockerfile",
    "chars": 1145,
    "preview": "# Build stage\nFROM python:3.12-slim AS builder\n\n# Update image\nRUN apt-get update && apt-get install -y --no-install-rec"
  },
  {
    "path": "LICENSE",
    "chars": 1085,
    "preview": "MIT License\n\nCopyright (c) 2024 Francesco Saverio Zuppichini\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "Makefile",
    "chars": 367,
    "preview": ".PHONY: style check_code_quality\n\nexport PYTHONPATH = .\ncheck_dirs := src\n\nstyle:\n\tuv run ruff format  $(check_dirs)\n\tuv"
  },
  {
    "path": "README.md",
    "chars": 2352,
    "preview": "# Python Template 🐍\n[![PyPI version](https://img.shields.io/pypi/v/python-template-zuppif)](https://pypi.org/project/pyt"
  },
  {
    "path": "examples/main.py",
    "chars": 49,
    "preview": "from jokes import make_me_laugh\n\nmake_me_laugh()\n"
  },
  {
    "path": "pyproject.toml",
    "chars": 641,
    "preview": "[project]\n# https://docs.astral.sh/uv/concepts/projects/config/\nname = \"python-template-zuppif\"\nversion = \"0.1.3\"\ndescri"
  },
  {
    "path": "src/jokes/__init__.py",
    "chars": 131,
    "preview": "from .jokes import get_joke\n\n\ndef make_me_laugh():\n    joke = get_joke()\n    print(f\"{joke[\"preambula\"]} ... {joke['punc"
  },
  {
    "path": "src/jokes/jokes.py",
    "chars": 567,
    "preview": "from random import choice\nfrom typing import TypedDict\n\nimport requests\n\nJOKES_FILE_URL = \"https://gist.githubuserconten"
  },
  {
    "path": "tests/test_jokes.py",
    "chars": 131,
    "preview": "from jokes import get_joke\n\n\ndef test_jokes():\n    joke = get_joke()\n    assert \"preambula\" in joke\n    assert \"punchlin"
  }
]

About this extraction

This page contains the full source code of the FrancescoSaverioZuppichini/python-template GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 14 files (14.5 KB), approximately 4.3k tokens, and a symbol index with 4 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!