diff --git a/README.md b/README.md index 3a8c6db..d40fe5a 100644 --- a/README.md +++ b/README.md @@ -1,86 +1,24 @@ -# template-python -[![Coverage Status](https://coveralls.io/repos/github/TUM-Aries-Lab/template-python/badge.svg?branch=main)](https://coveralls.io/github/TUM-Aries-Lab/template-python?branch=main) -![Docker Image CI](https://github.com/TUM-Aries-Lab/template-python/actions/workflows/ci.yml/badge.svg) +# Template-Python -Simple README.md for a Python project template. +Do ***NOT*** clone this repository. Please use it as a template instead—this README is meant to help you get started quickly. -Do ***NOT*** clone this repository. Please use it as a template instead. This readme is just here to serve as a template for you to get started faster. - -## Install -To install the library run: -```bash -uv pip install change-me==latest -``` -OR -```bash -uv add git+https://github.com/TUM-Aries-Lab/change-me.git@ # need credentials -``` - -## Development -0. Install [uv](https://docs.astral.sh/uv/getting-started/installation/) from Astral. -1. `git clone git@github.com:TUM-Aries-Lab/change-me.git` -2. `make init` to create the virtual environment and install dependencies -3. `make format` to format the code and check for errors -4. `make test` to run the test suite -5. `make clean` to delete the temporary files and directories - - -## Publishing -It's super easy to publish your own packages on PyPI. To build and publish this package run: - -```bash -uv build -uv publish # make sure your version in pyproject.toml is updated -``` -The package can then be found at: https://pypi.org/project/change-me - -## Module Usage -```python -"""Basic docstring for my module.""" - -from loguru import logger - -from change_me import definitions - -def main() -> None: - """Run a simple demonstration.""" - logger.info("Hello World!") - -if __name__ == "__main__": - main() +The file cookiecutter.json has the following contents: ``` - -## Program Usage -```bash -uv run python -m change_me +{ + "repo_name": "temp-python", + "module_name": "new-repo", + "package_name": "new_repo", + "org_name": "TUM-Aries-Lab", + "description": "Basic description for the repo.", + "author_name": "Tony Smoragiewicz", + "author_email": "tony.smoragiewicz@tum.de", + "python_version": "3.12", + "version": "0.0.1" +} ``` -## Structure -The following tree shows the important permanent files. - -``` -├── src -│ └── change_me -│ ├── __init__.py -│ ├── __main__.py -│ ├── definitions.py -│ └── utils.py -├── tests -│ ├── __init__.py -│ ├── conftest.py -│ ├── main_test.py -│ └── utils_test.py -├── .dockerignore -├── .gitignore -├── .pre-commit-config.yaml -├── .python-version -├── CONTRIBUTING.md -├── Dockerfile -├── LICENSE -├── Makefile -├── README.md -├── pyproject.toml -├── repo_tree.py -└── uv.lock -``` - +## Steps +1. Make the necessary names changes in `cookiecutter.json` and then run: +2. ` cookiecutter . # This will create a new repo with the correct names in place.` +3. You can then delete everything but the code in your newly generated folder. +4. Commit your new changes. diff --git a/cookiecutter.json b/cookiecutter.json new file mode 100644 index 0000000..7f0c496 --- /dev/null +++ b/cookiecutter.json @@ -0,0 +1,11 @@ +{ + "repo_name": "temp-python", + "module_name": "new-repo", + "package_name": "new_repo", + "org_name": "TUM-Aries-Lab", + "description": "Basic description for the repo.", + "author_name": "Tony Smoragiewicz", + "author_email": "tony.smoragiewicz@tum.de", + "python_version": "3.12", + "version": "0.0.1" +} diff --git a/.dockerignore b/{{ cookiecutter.repo_name }}/.dockerignore similarity index 100% rename from .dockerignore rename to {{ cookiecutter.repo_name }}/.dockerignore diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/{{ cookiecutter.repo_name }}/.github/ISSUE_TEMPLATE/feature_request.md similarity index 100% rename from .github/ISSUE_TEMPLATE/feature_request.md rename to {{ cookiecutter.repo_name }}/.github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/{{ cookiecutter.repo_name }}/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE.md rename to {{ cookiecutter.repo_name }}/.github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/workflows/ci.yml b/{{ cookiecutter.repo_name }}/.github/workflows/ci.yml similarity index 99% rename from .github/workflows/ci.yml rename to {{ cookiecutter.repo_name }}/.github/workflows/ci.yml index d3cae79..334acc5 100644 --- a/.github/workflows/ci.yml +++ b/{{ cookiecutter.repo_name }}/.github/workflows/ci.yml @@ -1,3 +1,4 @@ +{% raw %} name: CI on: @@ -119,3 +120,4 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: ./coverage.xml +{% endraw %} diff --git a/.github/workflows/docker.yml b/{{ cookiecutter.repo_name }}/.github/workflows/docker.yml similarity index 72% rename from .github/workflows/docker.yml rename to {{ cookiecutter.repo_name }}/.github/workflows/docker.yml index dad113a..edf8dfe 100644 --- a/.github/workflows/docker.yml +++ b/{{ cookiecutter.repo_name }}/.github/workflows/docker.yml @@ -1,3 +1,4 @@ +{% raw %} name: Docker Build & Publish on: @@ -17,8 +18,7 @@ permissions: env: REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} # may include uppercase (we'll normalize) - # Flip this to "true" if you want multi-arch on all branches + IMAGE_NAME: ${{ github.repository }} MULTIARCH_ON_BRANCHES: "false" concurrency: @@ -45,7 +45,6 @@ jobs: - name: Set up Buildx uses: docker/setup-buildx-action@v3 - # Only set up QEMU when we actually need arm64 (main or tag builds) - name: Set up QEMU (for arm64) if: env.IS_MAIN == 'true' || env.IS_TAG == 'true' || env.MULTIARCH_ON_BRANCHES == 'true' uses: docker/setup-qemu-action@v3 @@ -69,7 +68,6 @@ jobs: echo "latest_tag=latest" >> "$GITHUB_OUTPUT" fi - # Fast path for branches: single-arch build, cache, don't push - name: Build (branch) — fast single-arch, no push if: env.IS_MAIN != 'true' && env.IS_TAG != 'true' && env.MULTIARCH_ON_BRANCHES != 'true' uses: docker/build-push-action@v6 @@ -77,7 +75,7 @@ jobs: context: . file: ./Dockerfile push: false - load: true # so we can run the smoke test + load: true platforms: linux/amd64 cache-from: type=gha cache-to: type=gha,mode=max @@ -85,7 +83,6 @@ jobs: tags: | ${{ env.REGISTRY }}/${{ steps.repo.outputs.image_name_lc }}:${{ steps.meta.outputs.sha_tag }} - # Publish path for main/tags: multi-arch build + push (with cache) - name: Build & push (multi-arch) if: env.IS_MAIN == 'true' || env.IS_TAG == 'true' || env.MULTIARCH_ON_BRANCHES == 'true' uses: docker/build-push-action@v6 @@ -99,21 +96,33 @@ jobs: provenance: false tags: | ${{ env.REGISTRY }}/${{ steps.repo.outputs.image_name_lc }}:${{ steps.meta.outputs.sha_tag }} - ${{ steps.meta.outputs.version_tag && format('{0}/{1}:{2}', env.REGISTRY, steps.repo.outputs.image_name_lc, steps.meta.outputs.version_tag) || '' }} - ${{ steps.meta.outputs.latest_tag && format('{0}/{1}:{2}', env.REGISTRY, steps.repo.outputs.image_name_lc, steps.meta.outputs.latest_tag) || '' }} +{% endraw %} + {% raw %}${{ steps.meta.outputs.version_tag }}{% endraw %}{{ "" if not cookiecutter.module_name else "" }} +{% raw %} + {% endraw %} + {% raw %}${{ steps.meta.outputs.latest_tag }}{% endraw %}{{ "" if not cookiecutter.module_name else "" }} +{% raw %} - # Smoke test: use the local image for branch builds, or pull the pushed one for main/tags - name: Smoke test (branch image) if: env.IS_MAIN != 'true' && env.IS_TAG != 'true' && env.MULTIARCH_ON_BRANCHES != 'true' run: | IMAGE="${{ env.REGISTRY }}/${{ steps.repo.outputs.image_name_lc }}:${{ steps.meta.outputs.sha_tag }}" - echo "Smoke testing local image ${IMAGE}" - docker run --rm "$IMAGE" python -c "import change_me, sys; print('✅ import ok:', getattr(change_me,'__version__','?'), 'on', sys.version)" +{% endraw %} + python - << 'EOF' +import {{ cookiecutter.module_name }}, sys +print("✅ import ok:", getattr({{ cookiecutter.module_name }}, "__version__", "?"), "on", sys.version) +EOF +{% raw %} - name: Smoke test (pushed image) if: env.IS_MAIN == 'true' || env.IS_TAG == 'true' || env.MULTIARCH_ON_BRANCHES == 'true' run: | IMAGE="${{ env.REGISTRY }}/${{ steps.repo.outputs.image_name_lc }}:${{ steps.meta.outputs.sha_tag }}" - echo "Smoke testing pushed image ${IMAGE}" docker pull "$IMAGE" - docker run --rm "$IMAGE" python -c "import change_me, sys; print('✅ import ok:', getattr(change_me,'__version__','?'), 'on', sys.version)" +{% endraw %} + python - << 'EOF' +import {{ cookiecutter.module_name }}, sys +print("✅ import ok:", getattr({{ cookiecutter.module_name }}, "__version__", "?"), "on", sys.version) +EOF +{% raw %} +{% endraw %} diff --git a/{{ cookiecutter.repo_name }}/.gitignore b/{{ cookiecutter.repo_name }}/.gitignore new file mode 100644 index 0000000..88760d5 --- /dev/null +++ b/{{ cookiecutter.repo_name }}/.gitignore @@ -0,0 +1,172 @@ +# 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 +.coveragerc +.coverage +coverage.xml +.cache +nosetests.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 + +# 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 +.idea? +.DS_Store +.DS_Store? + +# pixi environments +.pixi +*.egg-info + +/logs/log_* diff --git a/.pre-commit-config.yaml b/{{ cookiecutter.repo_name }}/.pre-commit-config.yaml similarity index 100% rename from .pre-commit-config.yaml rename to {{ cookiecutter.repo_name }}/.pre-commit-config.yaml diff --git a/.python-version b/{{ cookiecutter.repo_name }}/.python-version similarity index 100% rename from .python-version rename to {{ cookiecutter.repo_name }}/.python-version diff --git a/CONTRIBUTING.md b/{{ cookiecutter.repo_name }}/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to {{ cookiecutter.repo_name }}/CONTRIBUTING.md diff --git a/Dockerfile b/{{ cookiecutter.repo_name }}/Dockerfile similarity index 95% rename from Dockerfile rename to {{ cookiecutter.repo_name }}/Dockerfile index e8fc42d..e46753d 100644 --- a/Dockerfile +++ b/{{ cookiecutter.repo_name }}/Dockerfile @@ -6,7 +6,7 @@ ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 # Select the package and version at build time -ARG PKG=change_me +ARG PKG={{ cookiecutter.module_name }} ARG VER=latest ENV PKG=${PKG} VER=${VER} diff --git a/LICENSE b/{{ cookiecutter.repo_name }}/LICENSE similarity index 100% rename from LICENSE rename to {{ cookiecutter.repo_name }}/LICENSE diff --git a/Makefile b/{{ cookiecutter.repo_name }}/Makefile similarity index 82% rename from Makefile rename to {{ cookiecutter.repo_name }}/Makefile index 7db7421..bf5ce85 100644 --- a/Makefile +++ b/{{ cookiecutter.repo_name }}/Makefile @@ -41,11 +41,11 @@ update-deep: make update docker: - docker build --no-cache -f Dockerfile -t change_me-smoke . - docker run --rm change_me-smoke + docker build --no-cache -f Dockerfile -t {{ cookiecutter.module_name }}-smoke . + docker run --rm {{ cookiecutter.module_name }}-smoke app: - uv run python -m change_me + uv run python -m {{ cookiecutter.module_name }} tree: uv run python repo_tree.py --update-readme diff --git a/{{ cookiecutter.repo_name }}/README.md b/{{ cookiecutter.repo_name }}/README.md new file mode 100644 index 0000000..1712acb --- /dev/null +++ b/{{ cookiecutter.repo_name }}/README.md @@ -0,0 +1,97 @@ +# {{ cookiecutter.repo_name }} + +[![Coverage Status](https://coveralls.io/repos/github/TUM-Aries-Lab/{{ cookiecutter.repo_name }}/badge.svg?branch=main)](https://coveralls.io/github/TUM-Aries-Lab/{{ cookiecutter.repo_name }}?branch=main) +![Docker Image CI](https://github.com/TUM-Aries-Lab/{{ cookiecutter.repo_name }}/actions/workflows/ci.yml/badge.svg) + +Simple README.md for a Python project template. + +Do ***NOT*** clone this repository. +Please use it as a template instead—this README is meant to help you get started quickly. + +# Names Changes +After adjusting the names in `cookiecutter.json` move into the repo and run: +```bash +cookiecutter . +``` +--- + +## Install + +To install the library from PyPI: + +```bash +uv pip install {{ cookiecutter.repo_name | replace('-', '_') }}==latest +``` +OR +```bash +uv add git+https://github.com/TUM-Aries-Lab/{{ cookiecutter.repo_name }}.git@ # needs credentials +``` + +## Development +0. Install [uv](https://docs.astral.sh/uv/getting-started/installation/) from Astral. +1. `git clone git@github.com:TUM-Aries-Lab/change-me.git` +2. `make init` to create the virtual environment and install dependencies +3. `make format` to format the code and check for errors +4. `make test` to run the test suite +5. `make clean` to delete the temporary files and directories + + +## Publishing +It's super easy to publish your own packages on PyPI. To build and publish this package run: + +```bash +uv build +uv publish # make sure your version in pyproject.toml is updated +``` +The package can then be found at: https://pypi.org/project/change-me + +## Module Usage +```python +"""Basic docstring for my module.""" + +from loguru import logger + +from {{ cookiecutter.module_name }} import definitions + +def main() -> None: + """Run a simple demonstration.""" + logger.info("Hello World!") + +if __name__ == "__main__": + main() +``` + +## Program Usage +```bash +uv run python -m {{ cookiecutter.module_name }} +``` + +## Structure +The following tree shows the important permanent files. + +``` +├── src +│ └── {{ cookiecutter.module_name }} +│ ├── __init__.py +│ ├── __main__.py +│ ├── definitions.py +│ └── utils.py +├── tests +│ ├── __init__.py +│ ├── conftest.py +│ ├── main_test.py +│ └── utils_test.py +├── .dockerignore +├── .gitignore +├── .pre-commit-config.yaml +├── .python-version +├── CONTRIBUTING.md +├── Dockerfile +├── LICENSE +├── Makefile +├── README.md +├── pyproject.toml +├── repo_tree.py +└── uv.lock +``` + diff --git a/pyproject.toml b/{{ cookiecutter.repo_name }}/pyproject.toml similarity index 96% rename from pyproject.toml rename to {{ cookiecutter.repo_name }}/pyproject.toml index f7d5319..b36f60e 100644 --- a/pyproject.toml +++ b/{{ cookiecutter.repo_name }}/pyproject.toml @@ -21,7 +21,7 @@ dev = [ ] [project.urls] -homepage = "https://github.com/TUM-Aries-Lab/template-python" +homepage = "https://github.com/TUM-Aries-Lab/{{ cookiecutter.repo_name }}" [tool.ruff] line-length = 88 diff --git a/repo_tree.py b/{{ cookiecutter.repo_name }}/repo_tree.py similarity index 100% rename from repo_tree.py rename to {{ cookiecutter.repo_name }}/repo_tree.py diff --git a/src/change_me/__init__.py b/{{ cookiecutter.repo_name }}/src/{{ cookiecutter.module_name }}/__init__.py similarity index 100% rename from src/change_me/__init__.py rename to {{ cookiecutter.repo_name }}/src/{{ cookiecutter.module_name }}/__init__.py diff --git a/src/change_me/__main__.py b/{{ cookiecutter.repo_name }}/src/{{ cookiecutter.module_name }}/__main__.py similarity index 99% rename from src/change_me/__main__.py rename to {{ cookiecutter.repo_name }}/src/{{ cookiecutter.module_name }}/__main__.py index 35682d6..1ff6893 100644 --- a/src/change_me/__main__.py +++ b/{{ cookiecutter.repo_name }}/src/{{ cookiecutter.module_name }}/__main__.py @@ -2,10 +2,9 @@ import argparse -from loguru import logger - from change_me.definitions import DEFAULT_LOG_LEVEL, LogLevel from change_me.utils import setup_logger +from loguru import logger def main( diff --git a/src/change_me/definitions.py b/{{ cookiecutter.repo_name }}/src/{{ cookiecutter.module_name }}/definitions.py similarity index 100% rename from src/change_me/definitions.py rename to {{ cookiecutter.repo_name }}/src/{{ cookiecutter.module_name }}/definitions.py diff --git a/src/change_me/utils.py b/{{ cookiecutter.repo_name }}/src/{{ cookiecutter.module_name }}/utils.py similarity index 99% rename from src/change_me/utils.py rename to {{ cookiecutter.repo_name }}/src/{{ cookiecutter.module_name }}/utils.py index 9fd9e27..6b8c6fa 100644 --- a/src/change_me/utils.py +++ b/{{ cookiecutter.repo_name }}/src/{{ cookiecutter.module_name }}/utils.py @@ -4,8 +4,6 @@ from datetime import datetime from pathlib import Path -from loguru import logger - from change_me.definitions import ( DATE_FORMAT, DEFAULT_LOG_FILENAME, @@ -13,6 +11,7 @@ ENCODING, LOG_DIR, ) +from loguru import logger def create_timestamped_filepath(suffix: str, output_dir: Path, prefix: str) -> Path: diff --git a/tests/__init__.py b/{{ cookiecutter.repo_name }}/tests/__init__.py similarity index 100% rename from tests/__init__.py rename to {{ cookiecutter.repo_name }}/tests/__init__.py diff --git a/tests/conftest.py b/{{ cookiecutter.repo_name }}/tests/conftest.py similarity index 100% rename from tests/conftest.py rename to {{ cookiecutter.repo_name }}/tests/conftest.py diff --git a/tests/main_test.py b/{{ cookiecutter.repo_name }}/tests/main_test.py similarity index 65% rename from tests/main_test.py rename to {{ cookiecutter.repo_name }}/tests/main_test.py index 2984a22..1c57d35 100644 --- a/tests/main_test.py +++ b/{{ cookiecutter.repo_name }}/tests/main_test.py @@ -1,6 +1,6 @@ """Test the main program.""" -from change_me.__main__ import main +from {{ cookiecutter.module_name }}.__main__ import main def test_main(): diff --git a/tests/utils_test.py b/{{ cookiecutter.repo_name }}/tests/utils_test.py similarity index 81% rename from tests/utils_test.py rename to {{ cookiecutter.repo_name }}/tests/utils_test.py index 8da207f..5262015 100644 --- a/tests/utils_test.py +++ b/{{ cookiecutter.repo_name }}/tests/utils_test.py @@ -3,8 +3,8 @@ from pathlib import Path from tempfile import TemporaryDirectory -from change_me.definitions import LogLevel -from change_me.utils import setup_logger +from {{ cookiecutter.module_name }}.definitions import LogLevel +from {{ cookiecutter.module_name }}.utils import setup_logger def test_logger_init() -> None: diff --git a/uv.lock b/{{ cookiecutter.repo_name }}/uv.lock similarity index 100% rename from uv.lock rename to {{ cookiecutter.repo_name }}/uv.lock