Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
de723b7
fix: adjust path to .ruff.toml in .pre-commit-config.yaml
56kyle May 24, 2025
e12c92d
feat: update version of ruff used in pre-commit hooks
56kyle May 24, 2025
45c601f
fix: correct arg error in precommit hook and adjust max size of files…
56kyle May 24, 2025
624ecec
fix: ensure package metadata is passed correctly and fix syntax error…
56kyle May 24, 2025
f3fd808
feat: attempt at fixing syntax error for release-python.yml
56kyle May 24, 2025
9035534
feat: more changes hoping to get release-python.yml working
56kyle May 24, 2025
397e48e
feat: add target and .idea to .gitignore
56kyle May 24, 2025
f716c09
feat: attempt to fix jinja escaping
56kyle May 24, 2025
24b8f7f
Revert "feat: attempt to fix jinja escaping"
56kyle May 24, 2025
6efa88d
feat: yet another attempt at fixing jinja madness
56kyle May 24, 2025
d335917
feat: convert all manual uv executions in nox to just implicitly use …
56kyle May 24, 2025
8b72f9c
feat: convert leftover uv sync calls in noxfile.py to install normally
56kyle May 24, 2025
014cba9
feat: removes final uv sync calls
56kyle May 24, 2025
fcaf011
feat: remove non-existent installation group
56kyle May 24, 2025
9ec490a
feat: add pre-commit migration change
56kyle May 24, 2025
107564d
feat: remove .cruft.json from the .gitignore
56kyle May 24, 2025
613898b
feat: add hypermodern cookiecutter logic for installing pre-commit-hooks
56kyle May 24, 2025
5576572
feat: remove .cruft.json from .gitignore
56kyle May 24, 2025
d0d42c8
feat: add a DEBUG flag to pyrightconfig.json
56kyle May 24, 2025
c56f813
feat: remove execution environments from pyrightconfig.json to allow …
56kyle May 24, 2025
e57a9a8
fix: remove invalid kwarg from nox session security-python
56kyle May 24, 2025
cc004b8
feat: add commitizen pre-commit hook and edit settings
56kyle May 24, 2025
b5cdf7b
chore: add .idea to .gitignore
56kyle May 24, 2025
c95b15a
feat: update commitizen version in .pre-commit-config.yaml
56kyle May 24, 2025
3ce5bfd
build: update typer and commitizen dependencies
56kyle May 25, 2025
90a9a58
chore: fix grammar in README.md
56kyle May 25, 2025
fe597e3
chore: add exported .editorconfig settings from pycharm
56kyle May 25, 2025
76a5827
fix: adjust bandit.yml path in nox session security-python
56kyle May 25, 2025
6ed3b21
fix: remove faulty kwarg from nox session security-python
56kyle May 25, 2025
5624f06
fix: remove happenstance retrocookie insertion into nox version speci…
56kyle May 25, 2025
873a80e
feat: copy .editorconfig from the inner portion to the template
56kyle May 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 120
tab_width = 4
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = true
ij_smart_tabs = false
ij_visual_guides =
ij_wrap_on_typing = false

[*.toml]
indent_style = space
indent_size = 4

[*.yml,yaml,json]
indent_style = space
indent_size = 2

[{*.py,*.pyw,*.whl}]
indent_style = space
indent_size = 4
ij_continuation_indent_size = 4
ij_python_add_indent_inside_injections = false
ij_python_align_collections_and_comprehensions = true
ij_python_align_multiline_imports = true
ij_python_align_multiline_parameters = false
ij_python_align_multiline_parameters_in_calls = false
ij_python_blank_line_at_file_end = true
ij_python_blank_lines_after_imports = 2
ij_python_blank_lines_after_local_imports = 0
ij_python_blank_lines_around_class = 1
ij_python_blank_lines_around_method = 1
ij_python_blank_lines_around_top_level_classes_functions = 2
ij_python_blank_lines_before_first_method = 0
ij_python_call_parameters_new_line_after_left_paren = true
ij_python_call_parameters_right_paren_on_new_line = true
ij_python_call_parameters_wrap = on_every_item
ij_python_dict_alignment = 0
ij_python_dict_new_line_after_left_brace = true
ij_python_dict_new_line_before_right_brace = true
ij_python_dict_wrapping = on_every_item
ij_python_format_injected_fragments = true
ij_python_from_import_new_line_after_left_parenthesis = true
ij_python_from_import_new_line_before_right_parenthesis = true
ij_python_from_import_parentheses_force_if_multiline = true
ij_python_from_import_trailing_comma_if_multiline = false
ij_python_from_import_wrapping = on_every_item
ij_python_hang_closing_brackets = false
ij_python_keep_blank_lines_in_code = 1
ij_python_keep_blank_lines_in_declarations = 1
ij_python_keep_indents_on_empty_lines = false
ij_python_keep_line_breaks = true
ij_python_list_new_line_after_left_bracket = true
ij_python_list_new_line_before_right_bracket = true
ij_python_list_wrapping = on_every_item
ij_python_method_parameters_new_line_after_left_paren = true
ij_python_method_parameters_right_paren_on_new_line = true
ij_python_method_parameters_wrap = on_every_item
ij_python_new_line_after_colon = true
ij_python_new_line_after_colon_multi_clause = true
ij_python_optimize_imports_always_split_from_imports = true
ij_python_optimize_imports_case_insensitive_order = false
ij_python_optimize_imports_join_from_imports_with_same_source = false
ij_python_optimize_imports_sort_by_type_first = true
ij_python_optimize_imports_sort_imports = true
ij_python_optimize_imports_sort_names_in_from_imports = false
ij_python_set_new_line_after_left_brace = true
ij_python_set_new_line_before_right_brace = true
ij_python_set_wrapping = on_every_item
ij_python_space_after_comma = true
ij_python_space_after_number_sign = true
ij_python_space_after_py_colon = true
ij_python_space_before_backslash = true
ij_python_space_before_comma = false
ij_python_space_before_for_semicolon = false
ij_python_space_before_lbracket = false
ij_python_space_before_method_call_parentheses = false
ij_python_space_before_method_parentheses = false
ij_python_space_before_number_sign = true
ij_python_space_before_py_colon = false
ij_python_space_within_empty_method_call_parentheses = false
ij_python_space_within_empty_method_parentheses = false
ij_python_spaces_around_additive_operators = true
ij_python_spaces_around_assignment_operators = true
ij_python_spaces_around_bitwise_operators = true
ij_python_spaces_around_eq_in_keyword_argument = false
ij_python_spaces_around_eq_in_named_parameter = false
ij_python_spaces_around_equality_operators = true
ij_python_spaces_around_multiplicative_operators = true
ij_python_spaces_around_power_operator = true
ij_python_spaces_around_relational_operators = true
ij_python_spaces_around_shift_operators = true
ij_python_spaces_within_braces = false
ij_python_spaces_within_brackets = false
ij_python_spaces_within_method_call_parentheses = false
ij_python_spaces_within_method_parentheses = false
ij_python_tuple_new_line_after_left_parenthesis = true
ij_python_tuple_new_line_before_right_parenthesis = true
ij_python_tuple_wrapping = on_every_item
ij_python_use_continuation_indent_for_arguments = false
ij_python_use_continuation_indent_for_collection_and_comprehensions = false
ij_python_use_continuation_indent_for_parameters = true
ij_python_use_trailing_comma_in_arguments_list = false
ij_python_use_trailing_comma_in_collections = false
ij_python_use_trailing_comma_in_parameter_list = false
ij_python_wrap_long_lines = false
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,4 @@ Thumbs.db # Windows thumbnail cache
debug.log
nohup.out

# Cookiecutter/Cruft metadata (for template updates)
.cruft.json
/.idea/
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ Any and all advice, support, PR's, etc are welcome and would be greatly apprecia


# Why does this project exist?
Unfortunately the [Hypermodern Python Cookiecutter] is no longer maintained nor modern.
Unfortunately, the [Hypermodern Python Cookiecutter] is no longer maintained nor modern.
While 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.

For a whle I maintained [a personal fork](https://github.com/56kyle/cookiecutter-hypermodern-python) that I would update, however when it came time to switch
For 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
to new tooling such as [ruff], [uv], [maturin], etc, I found the process of updating the existing tooling to be extremly painful.

The [Hypermodern Python Cookiecutter] remains as a fantastic sendoff point for devs interested in building a 2021 style Python Package, but there were
Expand All @@ -34,7 +34,7 @@ The [Robust Python Cookiecutter] exists to solve a few main concerns
One of the main issues I encountered with [my personal fork] of the [Hypermodern Python Cookiecutter] was that any change
I made to my repos would mean a later conflict if I tried to rerun [cookiecutter] to sync a change from a different project.

Thankfully [cruft] exists specifically to help with this issue. It enables us to periodically create PR's to add in any fixes
Thankfully, [cruft] exists specifically to help with this issue. It enables us to periodically create PR's to add in any fixes
the [Robust Python Cookiecutter] may have added.

Additionally, extra care is put in to use tooling specific config files whenever possible to help reduce merge conflicts occurring
Expand Down Expand Up @@ -76,12 +76,12 @@ Overall it's rather rare that people debate over tooling for no reason. Most thi

## CI/CD Vendor Lock
Now don't get me wrong, I love [github-actions] and do pretty much everything in my power to avoid [bitbucket-pipelines].
However 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.
However, 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.

The [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
CI/CD options or at a minimum basic examples of what the translated CI/CD pipeline would look like.

Finally 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.
Finally, 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.
The local [noxfile] is designed to match up directly with the CI/CD each step of the way.

The [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.
Expand Down
8 changes: 4 additions & 4 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,10 @@ def docs(session: Session):

session.log(f"Cleaning template docs build directory: {docs_build_dir}")
docs_build_dir.parent.mkdir(parents=True, exist_ok=True)
session.run("uv", "run", "sphinx-build", "-b", "html", "docs", str(docs_build_dir), "-E", external=True)
session.run("sphinx-build", "-b", "html", "docs", str(docs_build_dir), "-E")

session.log("Building template documentation.")
session.run("uv", "run", "sphinx-build", "-b", "html", "docs", str(docs_build_dir), "-W", external=True)
session.run("sphinx-build", "-b", "html", "docs", str(docs_build_dir), "-W")

session.log(f"Template documentation built in {docs_build_dir.resolve()}.")

Expand Down Expand Up @@ -199,7 +199,7 @@ def test(session: Session) -> None:
session.install("-e", ".", external=True)

session.log("Running generated project's default checks...")
session.run("uv", "run", "nox", external=True)
session.run("nox")

session.log(f"Cleaning up temporary directory: {temp_dir}")
shutil.rmtree(temp_dir)
Expand All @@ -221,7 +221,7 @@ def release_template(session: Session):
session.skip("Git not available.")

session.log("Checking Commitizen availability via uvx.")
session.run("uvx", "cz", "--version", successcodes=[0], external=True)
session.run("cz", "--version", successcodes=[0])

increment = session.posargs[0] if session.posargs else None
session.log(
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ dependencies = [
"loguru>=0.7.3",
"platformdirs>=4.3.8",
"retrocookie>=0.4.3",
"typer>=0.15.3",
"typer>=0.15.4",
]

[dependency-groups]
dev = [
"commitizen>=4.7.0",
"commitizen>=4.8.2",
"nox>=2025.5.1",
"pre-commit>=4.2.0",
]
Expand Down
16 changes: 8 additions & 8 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions {{cookiecutter.project_name}}/.cz.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ write_version_files = [
"src/{{ cookiecutter.package_name }}/__init__.py:__version__",
]
commit_msg_file = ".git/COMMIT_EDITMSG"
retry_after_failure = true
update_changelog_on_bump = true

[tool.commitizen.github]
release = true
Expand Down
100 changes: 99 additions & 1 deletion {{cookiecutter.project_name}}/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,109 @@ charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 120
tab_width = 4
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = true
ij_smart_tabs = false
ij_visual_guides =
ij_wrap_on_typing = false

[*.{py,toml}]
[*.toml]
indent_style = space
indent_size = 4

[*.yml,yaml,json]
indent_style = space
indent_size = 2

[{*.py,*.pyw,*.whl}]
indent_style = space
indent_size = 4
ij_continuation_indent_size = 4
ij_python_add_indent_inside_injections = false
ij_python_align_collections_and_comprehensions = true
ij_python_align_multiline_imports = true
ij_python_align_multiline_parameters = false
ij_python_align_multiline_parameters_in_calls = false
ij_python_blank_line_at_file_end = true
ij_python_blank_lines_after_imports = 2
ij_python_blank_lines_after_local_imports = 0
ij_python_blank_lines_around_class = 1
ij_python_blank_lines_around_method = 1
ij_python_blank_lines_around_top_level_classes_functions = 2
ij_python_blank_lines_before_first_method = 0
ij_python_call_parameters_new_line_after_left_paren = true
ij_python_call_parameters_right_paren_on_new_line = true
ij_python_call_parameters_wrap = on_every_item
ij_python_dict_alignment = 0
ij_python_dict_new_line_after_left_brace = true
ij_python_dict_new_line_before_right_brace = true
ij_python_dict_wrapping = on_every_item
ij_python_format_injected_fragments = true
ij_python_from_import_new_line_after_left_parenthesis = true
ij_python_from_import_new_line_before_right_parenthesis = true
ij_python_from_import_parentheses_force_if_multiline = true
ij_python_from_import_trailing_comma_if_multiline = false
ij_python_from_import_wrapping = on_every_item
ij_python_hang_closing_brackets = false
ij_python_keep_blank_lines_in_code = 1
ij_python_keep_blank_lines_in_declarations = 1
ij_python_keep_indents_on_empty_lines = false
ij_python_keep_line_breaks = true
ij_python_list_new_line_after_left_bracket = true
ij_python_list_new_line_before_right_bracket = true
ij_python_list_wrapping = on_every_item
ij_python_method_parameters_new_line_after_left_paren = true
ij_python_method_parameters_right_paren_on_new_line = true
ij_python_method_parameters_wrap = on_every_item
ij_python_new_line_after_colon = true
ij_python_new_line_after_colon_multi_clause = true
ij_python_optimize_imports_always_split_from_imports = true
ij_python_optimize_imports_case_insensitive_order = false
ij_python_optimize_imports_join_from_imports_with_same_source = false
ij_python_optimize_imports_sort_by_type_first = true
ij_python_optimize_imports_sort_imports = true
ij_python_optimize_imports_sort_names_in_from_imports = false
ij_python_set_new_line_after_left_brace = true
ij_python_set_new_line_before_right_brace = true
ij_python_set_wrapping = on_every_item
ij_python_space_after_comma = true
ij_python_space_after_number_sign = true
ij_python_space_after_py_colon = true
ij_python_space_before_backslash = true
ij_python_space_before_comma = false
ij_python_space_before_for_semicolon = false
ij_python_space_before_lbracket = false
ij_python_space_before_method_call_parentheses = false
ij_python_space_before_method_parentheses = false
ij_python_space_before_number_sign = true
ij_python_space_before_py_colon = false
ij_python_space_within_empty_method_call_parentheses = false
ij_python_space_within_empty_method_parentheses = false
ij_python_spaces_around_additive_operators = true
ij_python_spaces_around_assignment_operators = true
ij_python_spaces_around_bitwise_operators = true
ij_python_spaces_around_eq_in_keyword_argument = false
ij_python_spaces_around_eq_in_named_parameter = false
ij_python_spaces_around_equality_operators = true
ij_python_spaces_around_multiplicative_operators = true
ij_python_spaces_around_power_operator = true
ij_python_spaces_around_relational_operators = true
ij_python_spaces_around_shift_operators = true
ij_python_spaces_within_braces = false
ij_python_spaces_within_brackets = false
ij_python_spaces_within_method_call_parentheses = false
ij_python_spaces_within_method_parentheses = false
ij_python_tuple_new_line_after_left_parenthesis = true
ij_python_tuple_new_line_before_right_parenthesis = true
ij_python_tuple_wrapping = on_every_item
ij_python_use_continuation_indent_for_arguments = false
ij_python_use_continuation_indent_for_collection_and_comprehensions = false
ij_python_use_continuation_indent_for_parameters = true
ij_python_use_trailing_comma_in_arguments_list = false
ij_python_use_trailing_comma_in_collections = false
ij_python_use_trailing_comma_in_parameter_list = false
ij_python_wrap_long_lines = false
Loading