{"id":28512385,"url":"https://github.com/56kyle/cookiecutter-robust-python","last_synced_at":"2025-07-22T07:33:35.117Z","repository":{"id":292055730,"uuid":"973543599","full_name":"56kyle/cookiecutter-robust-python","owner":"56kyle","description":"A Python project template designed to make best practices as simple and convenient as possible.","archived":false,"fork":false,"pushed_at":"2025-07-20T03:06:51.000Z","size":746,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-20T04:39:34.723Z","etag":null,"topics":["cookiecutter","cookiecutter-python","cookiecutter-uv","hypermodern-python","maturin","nox","python","ruff","rust","tox","uv"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/56kyle.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-27T08:04:35.000Z","updated_at":"2025-07-19T04:29:44.000Z","dependencies_parsed_at":"2025-06-17T06:25:49.508Z","dependency_job_id":"25a20253-5549-4f6f-ab43-cb14a7469130","html_url":"https://github.com/56kyle/cookiecutter-robust-python","commit_stats":null,"previous_names":["56kyle/cookiecutter-robust-python"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/56kyle/cookiecutter-robust-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/56kyle%2Fcookiecutter-robust-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/56kyle%2Fcookiecutter-robust-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/56kyle%2Fcookiecutter-robust-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/56kyle%2Fcookiecutter-robust-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/56kyle","download_url":"https://codeload.github.com/56kyle/cookiecutter-robust-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/56kyle%2Fcookiecutter-robust-python/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266448158,"owners_count":23930143,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cookiecutter","cookiecutter-python","cookiecutter-uv","hypermodern-python","maturin","nox","python","ruff","rust","tox","uv"],"created_at":"2025-06-09T00:37:50.311Z","updated_at":"2025-07-22T07:33:35.106Z","avatar_url":"https://github.com/56kyle.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cookiecutter-robust-python\n\nA Python project template robust enough to follow up [cookiecutter-hypermodern-python]\n\n# Caveat\n\nI really believe this idea has a lot of good ideas and best practices, however, creating it is a ton of work.\n\nIf you have any interest in this project, please don't hesitate to reach out!\nAny advice, support, PR's, etc. are welcome and would be greatly appreciated.\n\nAs it stands this project is getting rather close to being ready, but not quite yet. Mainly I want to ensure the github actions pipeline is steady, but once that is done it should be alright for use.\n\n# Why does this project exist?\n\nUnfortunately, the [Hypermodern Python Cookiecutter] is no longer maintained nor modern.\nWhile it will always have a place in my heart, there have been far too many improvements in Python tooling to keep using it as is.\n\nFor a while I maintained [a personal fork](https://github.com/56kyle/cookiecutter-hypermodern-python) that I would update, however, when it came time to switch\nto new tooling such as [ruff], [uv], [maturin], etc., I found the process of updating the existing tooling to be extremely painful.\n\nThe [Hypermodern Python Cookiecutter] remains as a fantastic sendoff point for devs interested in building a 2021-style Python Package. However, there were\na handful of issues with it that prevented it from being able to adapt to new Python developments over the years.\n\n# Okay, so what's different this time?\n\nThe [Robust Python Cookiecutter] exists to solve a few main concerns\n\n- [Template Update Propagation](#template-update-propagation)\n- [Project Domain Expansion](#project-domain-expansion)\n- [Documenting Tooling Decisions](#documenting-tooling-decisions)\n- [CI/CD Vendor Lock](#cicd-vendor-lock)\n- [Project Neglect](#project-neglect)\n\n## Template Update Propagation\n\nOne of the main issues I encountered with [my personal fork] of the [Hypermodern Python Cookiecutter] was that any change\nI made to my repos would mean a later conflict if I tried to rerun [cookiecutter] to sync a change from a different project.\n\nThankfully, [cruft] exists specifically to help with this issue. It enables us to periodically create PR's to add in any fixes\nthe [Robust Python Cookiecutter] may have added.\n\nAdditionally, extra care is put in to use tooling specific config files whenever possible to help reduce merge conflicts occurring\nin the pyproject.toml.\n\n## Project Domain Expansion\n\nNow, I'm not one to advocate for mixing languages in a project. However, there is a unique case that has arisen with the creation of [maturin].\n\nThere are a plethora of great projects such as [ruff], [uv], [polars], [just], etc. all making use of [maturin] to get the performance improvements of [rust] while\nsubmitting their package to both pypi and crates.io\n\nNow, this definitely is not required by any means to make a good Python package, however this pattern only seems to be picking up momentum and has honestly been a massive boon\nto Python's ecosystem overall.\n\nThat being said, it's generally good practice to avoid the complexity of this dual language system unless you actually need the performance bump for your use case. However knowing ahead of time if performance\nwill be an issue is rather tricky, and a much easier route is to just prepare as though you _might_ swap to it some day.\n\nThe [Robust Python Cookiecutter] includes a `include_rust_extensions` flag that not only toggles [maturin] vs a traditional Python package,\nbut that can be used in combination with [cruft] to swap to [maturin] at any time with just about no risk to CI/CD / etc.\n\nAdditionally, the [Robust Python Cookiecutter] is designed with both normal and [monorepos] in mind. So whether you need to just add\na quick [rust] module for performance or you are trying to publish a series of crates and packages, either case will be handled using a setup inspired by [polars].\n\n## Documenting Tooling Decisions\n\nOne of the really stand out features of the [Hypermodern Python Cookiecutter] was its incredibly detailed documentation.\nIt did a pretty great job of describing the tooling to use, but there was a distinct lack of **_why_** these decisions were made.\n\nIt may seem like a small detail, but detailing why a decision was made has an incredibly important effect on the maintainablity of the template.\n\n#### **It allows maintainers to check if a decision should change in one click.**\n\nRather than having to go through a mini crusade to determine whether we use [poetry] or [uv], we can just point to the\n[existing reasoning](https://cookiecutter-robust-python.readthedocs.io/en/latest/topics/02_dependency_management.md#option-2--term--poetry) to see if it still is true or not.\n\nOverall, it's rather rare that people debate over tooling for no reason. Most things have merit in some cases, and a large goal of this template is identifying the tools that have the most merit in almost all cases.\n\n## CI/CD Vendor Lock\n\nNow don't get me wrong, I love [github-actions] and do pretty much everything in my power to avoid [bitbucket-pipelines].\nHowever, not all jobs have the luxury of GitHub, and I would love to be able to just use the same template for both my personal and professional projects.\n\nThe [Robust Python Cookiecutter] focuses on being as modular as possible for areas that connect to the CI/CD pipeline. Additionally, there will always be either alternative\nCI/CD options or at a minimum basic examples of what the translated CI/CD pipeline would look like.\n\nFinally, the main reason that this task is even possible is that the [Robust Python Cookiecutter] mirrors all of the CI/CD steps in it's local dev tooling.\nThe local [noxfile] is designed to match up directly with the CI/CD each step of the way.\n\nThe [Hypermodern Python Cookiecutter] did this where it could afford to also, however the lack of [uv] meant it would significantly increase CI/CD times if done everywhere.\nThankfully now we can spin up a venv with a tiny fraction of the overhead that used to exist.\n\n## Project Neglect\n\nThis is most certainly not a knock against claudio. The work they did on [cookiecutter-hypermodern-python] laid the way for countless other devs to start\nimplementing best practices in their python packages.\n\nHowever, Open Source work is draining, and is especially so for a project template including metacode.\n\nI can guarantee that if the [Robust Python Cookiecutter] ever sees any number of users, I will immediately transfer it to an organization to enable at least a handful\nof trusted individuals to ensure the project is taken care of.\n\n[bitbucket-pipelines]: https://support.atlassian.com/bitbucket-cloud/docs/write-a-pipe-for-bitbucket-pipelines/\n[cookiecutter]: https://cookiecutter.readthedocs.io/en/stable/\n[cookiecutter-hypermodern-python]: https://github.com/cjolowicz/cookiecutter-hypermodern-python\n[cookiecutter-robust-python]: https://github.com/56kyle/cookiecutter-robust-python\n[cruft]: https://cruft.github.io/cruft/\n[github-actions]: https://docs.github.com/en/actions\n[hypermodern python cookiecutter]: https://github.com/cjolowicz/cookiecutter-hypermodern-python\n[just]: https://github.com/casey/just?tab=readme-ov-fil\n[maturin]: https://github.com/PyO3/maturin\n[noxfile]: https://github.com/56kyle/cookiecutter-robust-python/blob/main/%7B%7Bcookiecutter.project_name%7D%7D/noxfile.py\n[poetry]: https://python-poetry.org/docs/\n[polars]: https://github.com/pola-rs/polars\n[robust python cookiecutter]: https://github.com/56kyle/cookiecutter-robust-python\n[ruff]: https://docs.astral.sh/ruff/\n[rust]: https://www.rust-lang.org/learn\n[rye]: https://rye.astral.sh/\n[uv]: https://docs.astral.sh/uv/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F56kyle%2Fcookiecutter-robust-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F56kyle%2Fcookiecutter-robust-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F56kyle%2Fcookiecutter-robust-python/lists"}