Skip to content

Commit 9223d51

Browse files
authored
Merge pull request #10 from 56kyle/develop
General Project Lifecycle Fixes
2 parents 4ea8aea + 873a80e commit 9223d51

File tree

14 files changed

+380
-82
lines changed

14 files changed

+380
-82
lines changed

.editorconfig

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
end_of_line = lf
6+
insert_final_newline = true
7+
trim_trailing_whitespace = true
8+
max_line_length = 120
9+
tab_width = 4
10+
ij_continuation_indent_size = 8
11+
ij_formatter_off_tag = @formatter:off
12+
ij_formatter_on_tag = @formatter:on
13+
ij_formatter_tags_enabled = true
14+
ij_smart_tabs = false
15+
ij_visual_guides =
16+
ij_wrap_on_typing = false
17+
18+
[*.toml]
19+
indent_style = space
20+
indent_size = 4
21+
22+
[*.yml,yaml,json]
23+
indent_style = space
24+
indent_size = 2
25+
26+
[{*.py,*.pyw,*.whl}]
27+
indent_style = space
28+
indent_size = 4
29+
ij_continuation_indent_size = 4
30+
ij_python_add_indent_inside_injections = false
31+
ij_python_align_collections_and_comprehensions = true
32+
ij_python_align_multiline_imports = true
33+
ij_python_align_multiline_parameters = false
34+
ij_python_align_multiline_parameters_in_calls = false
35+
ij_python_blank_line_at_file_end = true
36+
ij_python_blank_lines_after_imports = 2
37+
ij_python_blank_lines_after_local_imports = 0
38+
ij_python_blank_lines_around_class = 1
39+
ij_python_blank_lines_around_method = 1
40+
ij_python_blank_lines_around_top_level_classes_functions = 2
41+
ij_python_blank_lines_before_first_method = 0
42+
ij_python_call_parameters_new_line_after_left_paren = true
43+
ij_python_call_parameters_right_paren_on_new_line = true
44+
ij_python_call_parameters_wrap = on_every_item
45+
ij_python_dict_alignment = 0
46+
ij_python_dict_new_line_after_left_brace = true
47+
ij_python_dict_new_line_before_right_brace = true
48+
ij_python_dict_wrapping = on_every_item
49+
ij_python_format_injected_fragments = true
50+
ij_python_from_import_new_line_after_left_parenthesis = true
51+
ij_python_from_import_new_line_before_right_parenthesis = true
52+
ij_python_from_import_parentheses_force_if_multiline = true
53+
ij_python_from_import_trailing_comma_if_multiline = false
54+
ij_python_from_import_wrapping = on_every_item
55+
ij_python_hang_closing_brackets = false
56+
ij_python_keep_blank_lines_in_code = 1
57+
ij_python_keep_blank_lines_in_declarations = 1
58+
ij_python_keep_indents_on_empty_lines = false
59+
ij_python_keep_line_breaks = true
60+
ij_python_list_new_line_after_left_bracket = true
61+
ij_python_list_new_line_before_right_bracket = true
62+
ij_python_list_wrapping = on_every_item
63+
ij_python_method_parameters_new_line_after_left_paren = true
64+
ij_python_method_parameters_right_paren_on_new_line = true
65+
ij_python_method_parameters_wrap = on_every_item
66+
ij_python_new_line_after_colon = true
67+
ij_python_new_line_after_colon_multi_clause = true
68+
ij_python_optimize_imports_always_split_from_imports = true
69+
ij_python_optimize_imports_case_insensitive_order = false
70+
ij_python_optimize_imports_join_from_imports_with_same_source = false
71+
ij_python_optimize_imports_sort_by_type_first = true
72+
ij_python_optimize_imports_sort_imports = true
73+
ij_python_optimize_imports_sort_names_in_from_imports = false
74+
ij_python_set_new_line_after_left_brace = true
75+
ij_python_set_new_line_before_right_brace = true
76+
ij_python_set_wrapping = on_every_item
77+
ij_python_space_after_comma = true
78+
ij_python_space_after_number_sign = true
79+
ij_python_space_after_py_colon = true
80+
ij_python_space_before_backslash = true
81+
ij_python_space_before_comma = false
82+
ij_python_space_before_for_semicolon = false
83+
ij_python_space_before_lbracket = false
84+
ij_python_space_before_method_call_parentheses = false
85+
ij_python_space_before_method_parentheses = false
86+
ij_python_space_before_number_sign = true
87+
ij_python_space_before_py_colon = false
88+
ij_python_space_within_empty_method_call_parentheses = false
89+
ij_python_space_within_empty_method_parentheses = false
90+
ij_python_spaces_around_additive_operators = true
91+
ij_python_spaces_around_assignment_operators = true
92+
ij_python_spaces_around_bitwise_operators = true
93+
ij_python_spaces_around_eq_in_keyword_argument = false
94+
ij_python_spaces_around_eq_in_named_parameter = false
95+
ij_python_spaces_around_equality_operators = true
96+
ij_python_spaces_around_multiplicative_operators = true
97+
ij_python_spaces_around_power_operator = true
98+
ij_python_spaces_around_relational_operators = true
99+
ij_python_spaces_around_shift_operators = true
100+
ij_python_spaces_within_braces = false
101+
ij_python_spaces_within_brackets = false
102+
ij_python_spaces_within_method_call_parentheses = false
103+
ij_python_spaces_within_method_parentheses = false
104+
ij_python_tuple_new_line_after_left_parenthesis = true
105+
ij_python_tuple_new_line_before_right_parenthesis = true
106+
ij_python_tuple_wrapping = on_every_item
107+
ij_python_use_continuation_indent_for_arguments = false
108+
ij_python_use_continuation_indent_for_collection_and_comprehensions = false
109+
ij_python_use_continuation_indent_for_parameters = true
110+
ij_python_use_trailing_comma_in_arguments_list = false
111+
ij_python_use_trailing_comma_in_collections = false
112+
ij_python_use_trailing_comma_in_parameter_list = false
113+
ij_python_wrap_long_lines = false

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,4 @@ Thumbs.db # Windows thumbnail cache
6161
debug.log
6262
nohup.out
6363

64-
# Cookiecutter/Cruft metadata (for template updates)
65-
.cruft.json
64+
/.idea/

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ Any and all advice, support, PR's, etc are welcome and would be greatly apprecia
1212

1313

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

18-
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
18+
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
1919
to new tooling such as [ruff], [uv], [maturin], etc, I found the process of updating the existing tooling to be extremly painful.
2020

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

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

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

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

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

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

8787
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.

noxfile.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,10 @@ def docs(session: Session):
155155

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

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

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

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

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

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

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

226226
increment = session.posargs[0] if session.posargs else None
227227
session.log(

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ dependencies = [
1010
"loguru>=0.7.3",
1111
"platformdirs>=4.3.8",
1212
"retrocookie>=0.4.3",
13-
"typer>=0.15.3",
13+
"typer>=0.15.4",
1414
]
1515

1616
[dependency-groups]
1717
dev = [
18-
"commitizen>=4.7.0",
18+
"commitizen>=4.8.2",
1919
"nox>=2025.5.1",
2020
"pre-commit>=4.2.0",
2121
]

uv.lock

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

{{cookiecutter.project_name}}/.cz.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ write_version_files = [
1111
"src/{{ cookiecutter.package_name }}/__init__.py:__version__",
1212
]
1313
commit_msg_file = ".git/COMMIT_EDITMSG"
14+
retry_after_failure = true
15+
update_changelog_on_bump = true
1416

1517
[tool.commitizen.github]
1618
release = true

{{cookiecutter.project_name}}/.editorconfig

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,109 @@ charset = utf-8
55
end_of_line = lf
66
insert_final_newline = true
77
trim_trailing_whitespace = true
8+
max_line_length = 120
9+
tab_width = 4
10+
ij_continuation_indent_size = 8
11+
ij_formatter_off_tag = @formatter:off
12+
ij_formatter_on_tag = @formatter:on
13+
ij_formatter_tags_enabled = true
14+
ij_smart_tabs = false
15+
ij_visual_guides =
16+
ij_wrap_on_typing = false
817

9-
[*.{py,toml}]
18+
[*.toml]
1019
indent_style = space
1120
indent_size = 4
1221

1322
[*.yml,yaml,json]
1423
indent_style = space
1524
indent_size = 2
25+
26+
[{*.py,*.pyw,*.whl}]
27+
indent_style = space
28+
indent_size = 4
29+
ij_continuation_indent_size = 4
30+
ij_python_add_indent_inside_injections = false
31+
ij_python_align_collections_and_comprehensions = true
32+
ij_python_align_multiline_imports = true
33+
ij_python_align_multiline_parameters = false
34+
ij_python_align_multiline_parameters_in_calls = false
35+
ij_python_blank_line_at_file_end = true
36+
ij_python_blank_lines_after_imports = 2
37+
ij_python_blank_lines_after_local_imports = 0
38+
ij_python_blank_lines_around_class = 1
39+
ij_python_blank_lines_around_method = 1
40+
ij_python_blank_lines_around_top_level_classes_functions = 2
41+
ij_python_blank_lines_before_first_method = 0
42+
ij_python_call_parameters_new_line_after_left_paren = true
43+
ij_python_call_parameters_right_paren_on_new_line = true
44+
ij_python_call_parameters_wrap = on_every_item
45+
ij_python_dict_alignment = 0
46+
ij_python_dict_new_line_after_left_brace = true
47+
ij_python_dict_new_line_before_right_brace = true
48+
ij_python_dict_wrapping = on_every_item
49+
ij_python_format_injected_fragments = true
50+
ij_python_from_import_new_line_after_left_parenthesis = true
51+
ij_python_from_import_new_line_before_right_parenthesis = true
52+
ij_python_from_import_parentheses_force_if_multiline = true
53+
ij_python_from_import_trailing_comma_if_multiline = false
54+
ij_python_from_import_wrapping = on_every_item
55+
ij_python_hang_closing_brackets = false
56+
ij_python_keep_blank_lines_in_code = 1
57+
ij_python_keep_blank_lines_in_declarations = 1
58+
ij_python_keep_indents_on_empty_lines = false
59+
ij_python_keep_line_breaks = true
60+
ij_python_list_new_line_after_left_bracket = true
61+
ij_python_list_new_line_before_right_bracket = true
62+
ij_python_list_wrapping = on_every_item
63+
ij_python_method_parameters_new_line_after_left_paren = true
64+
ij_python_method_parameters_right_paren_on_new_line = true
65+
ij_python_method_parameters_wrap = on_every_item
66+
ij_python_new_line_after_colon = true
67+
ij_python_new_line_after_colon_multi_clause = true
68+
ij_python_optimize_imports_always_split_from_imports = true
69+
ij_python_optimize_imports_case_insensitive_order = false
70+
ij_python_optimize_imports_join_from_imports_with_same_source = false
71+
ij_python_optimize_imports_sort_by_type_first = true
72+
ij_python_optimize_imports_sort_imports = true
73+
ij_python_optimize_imports_sort_names_in_from_imports = false
74+
ij_python_set_new_line_after_left_brace = true
75+
ij_python_set_new_line_before_right_brace = true
76+
ij_python_set_wrapping = on_every_item
77+
ij_python_space_after_comma = true
78+
ij_python_space_after_number_sign = true
79+
ij_python_space_after_py_colon = true
80+
ij_python_space_before_backslash = true
81+
ij_python_space_before_comma = false
82+
ij_python_space_before_for_semicolon = false
83+
ij_python_space_before_lbracket = false
84+
ij_python_space_before_method_call_parentheses = false
85+
ij_python_space_before_method_parentheses = false
86+
ij_python_space_before_number_sign = true
87+
ij_python_space_before_py_colon = false
88+
ij_python_space_within_empty_method_call_parentheses = false
89+
ij_python_space_within_empty_method_parentheses = false
90+
ij_python_spaces_around_additive_operators = true
91+
ij_python_spaces_around_assignment_operators = true
92+
ij_python_spaces_around_bitwise_operators = true
93+
ij_python_spaces_around_eq_in_keyword_argument = false
94+
ij_python_spaces_around_eq_in_named_parameter = false
95+
ij_python_spaces_around_equality_operators = true
96+
ij_python_spaces_around_multiplicative_operators = true
97+
ij_python_spaces_around_power_operator = true
98+
ij_python_spaces_around_relational_operators = true
99+
ij_python_spaces_around_shift_operators = true
100+
ij_python_spaces_within_braces = false
101+
ij_python_spaces_within_brackets = false
102+
ij_python_spaces_within_method_call_parentheses = false
103+
ij_python_spaces_within_method_parentheses = false
104+
ij_python_tuple_new_line_after_left_parenthesis = true
105+
ij_python_tuple_new_line_before_right_parenthesis = true
106+
ij_python_tuple_wrapping = on_every_item
107+
ij_python_use_continuation_indent_for_arguments = false
108+
ij_python_use_continuation_indent_for_collection_and_comprehensions = false
109+
ij_python_use_continuation_indent_for_parameters = true
110+
ij_python_use_trailing_comma_in_arguments_list = false
111+
ij_python_use_trailing_comma_in_collections = false
112+
ij_python_use_trailing_comma_in_parameter_list = false
113+
ij_python_wrap_long_lines = false

0 commit comments

Comments
 (0)