Skip to content

Commit 6400565

Browse files
committed
[NEW] Add a CLI to you Python Package
2 parents 8e1dbe9 + e8580f4 commit 6400565

File tree

18 files changed

+266
-242
lines changed

18 files changed

+266
-242
lines changed

.github/biskotaki.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ default_context:
1010
github_username: boromir674
1111
project_short_description: Project generated from the https://github.com/boromir674/cookiecutter-python-package/tree/master/src/cookiecutter_python cookiecutter
1212
initialize_git_repo: no
13+
add_cli: no
1314
interpreters: {"supported-interpreters": ["3.6", "3.7", "3.8", "3.9", "3.10"]}

CHANGELOG.rst

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,43 @@
22
Changelog
33
=========
44

5+
1.4.0 (2022-06-06)
6+
==================
7+
8+
Add a CLI as an entrypoint to your Python Package
9+
-------------------------------------------------
10+
11+
This release enables the user to optionally provide their Python Package with
12+
a Command Line Interface (CLI) as an entrypoint.
13+
The *add_cli* Generator Variable has been added to behave as an enable/disable
14+
'switch'.
15+
16+
Changes
17+
^^^^^^^
18+
19+
feature
20+
"""""""
21+
- add 'dev' & 'dev-cov' envs, designed to run locally with 'python3' from PATH
22+
- allow user to scaffold a cli with an entrypoint when installing their package
23+
24+
fix
25+
"""
26+
- use a proper name for the test case
27+
- remove hardcoded values and add templated ones
28+
29+
test
30+
""""
31+
- verify that when add_cli = 'no', there are no cli related files generated
32+
33+
development
34+
"""""""""""
35+
- add 'dev' & 'dev-cov' envs, designed to run locally with 'python3' from PATH
36+
37+
refactor
38+
""""""""
39+
- use the 'get_object' fixture from the 'pytest-object-getter' (pypi) package ;-)
40+
41+
542
1.3.0 (2022-05-31)
643
==================
744

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,9 @@ For more complex use cases, you can modify the Template and also leverage all of
196196

197197
.. Github Releases & Tags
198198
199-
.. |commits_since_specific_tag_on_master| image:: https://img.shields.io/github/commits-since/boromir674/cookiecutter-python-package/v1.3.0/master?color=blue&logo=github
199+
.. |commits_since_specific_tag_on_master| image:: https://img.shields.io/github/commits-since/boromir674/cookiecutter-python-package/v1.4.0/master?color=blue&logo=github
200200
:alt: GitHub commits since tagged version (branch)
201-
:target: https://github.com/boromir674/cookiecutter-python-package/compare/v1.3.0..master
201+
:target: https://github.com/boromir674/cookiecutter-python-package/compare/v1.4.0..master
202202

203203
.. |commits_since_latest_github_release| image:: https://img.shields.io/github/commits-since/boromir674/cookiecutter-python-package/latest?color=blue&logo=semver&sort=semver
204204
:alt: GitHub commits since latest release (by SemVer)

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ build-backend = "poetry.core.masonry.api"
1010
## Also renders on pypi as 'subtitle'
1111
[tool.poetry]
1212
name = "cookiecutter_python"
13-
version = "1.3.0"
13+
version = "1.4.0"
1414
description = "Yet another modern Python Package (pypi) with emphasis in CI/CD and automation."
1515
authors = ["Konstantinos Lampridis <k.lampridis@hotmail.com>"]
1616
maintainers = ["Konstantinos Lampridis <k.lampridis@hotmail.com>"]
@@ -103,6 +103,7 @@ prompt-toolkit = "==1.0.14"
103103

104104
# Test: packages imported in test code and packages required for the "test runner"
105105
pytest = { version = ">= 6.2.4", optional = true }
106+
pytest-object-getter = { version = "^ 1.0.1", optional = true }
106107
pytest-click = { version = "~= 1.1.0", optional = true }
107108
pytest-cov = { version = ">= 2.12", optional = true }
108109
pytest-explicit = { version = "~= 1.0.1", optional = true }
@@ -126,6 +127,7 @@ test = [
126127
"pytest-cov",
127128
"pytest-explicit",
128129
"pytest-xdist",
130+
"pytest-object-getter",
129131
]
130132
docs = [
131133
"sphinx",

scripts/parse_version.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ def client_callback(file_path: str, regex: str) -> t.Tuple:
3434
if match:
3535
extracted_tuple = data[2](match)
3636
return extracted_tuple
37-
else:
38-
raise factory(file_path, regex, contents)
37+
raise factory(file_path, regex, contents)
3938

4039
return client_callback
4140

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.3.0'
1+
__version__ = '1.4.0'

src/cookiecutter_python/cookiecutter.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"year": "{% now 'utc', '%Y' %}",
1414
"version": "0.0.1",
1515
"initialize_git_repo": ["yes", "no"],
16+
"add_cli": ["no", "yes"],
1617
"interpreters": {
1718
"supported-interpreters": [
1819
"3.6",

src/cookiecutter_python/hooks/post_gen_project.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import subprocess
99
import sys
1010
from collections import OrderedDict
11+
from os import path
1112

1213
PROJECT_DIRECTORY = os.path.realpath(os.path.curdir)
1314

@@ -20,13 +21,16 @@ def get_request():
2021
AUTHOR = "{{ cookiecutter.author }}"
2122
AUTHOR_EMAIL = "{{ cookiecutter.author_email }}"
2223
INITIALIZE_GIT_REPO_FLAG = "{{ cookiecutter.initialize_git_repo|lower }}"
24+
ADD_CLI_FLAG = "{{ cookiecutter.add_cli|lower }}"
2325

2426
request = type('PostGenProjectRequest', (), {
2527
'cookiecutter': COOKIECUTTER,
2628
'project_dir': PROJECT_DIRECTORY,
29+
'module_name': COOKIECUTTER['pkg_name'],
2730
'author': AUTHOR,
2831
'author_email': AUTHOR_EMAIL,
2932
'initialize_git_repo': {'yes': True}.get(INITIALIZE_GIT_REPO_FLAG, False),
33+
'add_cli': {'yes': True}.get(ADD_CLI_FLAG, False),
3034
})
3135

3236
return request
@@ -141,11 +145,34 @@ def is_git_repo_clean(project_directory: str):
141145

142146
return False
143147

148+
class PostFileRemovalError(Exception):
149+
pass
150+
151+
def post_file_removal(request):
152+
files_to_remove = []
153+
if not request.add_cli:
154+
files_to_remove.extend([
155+
path.join(request.project_dir, 'src', request.module_name, 'cli.py'),
156+
path.join(request.project_dir, 'src', request.module_name, '__main__.py'),
157+
])
158+
for file in files_to_remove:
159+
print('FILE to remove:', file)
160+
os.remove(file)
161+
# try:
162+
# except Exception as error:
163+
# raise PostFileRemovalError from error
164+
144165

145166
def _post_hook():
146167
print('\n --- POST GEN SCRIPT')
147168
request = get_request()
148169
print('Computed Templated Vars for Post Script')
170+
# try:
171+
post_file_removal(request)
172+
# except PostFileRemovalError as error:
173+
# print(error)
174+
# print('ERROR in Post Script.\nExiting with 1')
175+
# return 1
149176
if request.initialize_git_repo:
150177
try:
151178
initialize_git_repo(request.project_dir)

src/cookiecutter_python/{{ cookiecutter.project_slug }}/.github/workflows/test.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ jobs:
5252
echo "DIST_DIR=dist" >> $GITHUB_ENV
5353
5454
mkdir "$DIST_DIR"
55-
mv ".tox/${DIST_DIR}/cookiecutter_python-${PKG_VERSION}.tar.gz" "${DIST_DIR}"
56-
mv ".tox/${DIST_DIR}/cookiecutter_python-${PKG_VERSION}-py3-none-any.whl" "${DIST_DIR}"
55+
mv ".tox/${DIST_DIR}/{{ cookiecutter.pkg_name }}-${PKG_VERSION}.tar.gz" "${DIST_DIR}"
56+
mv ".tox/${DIST_DIR}/{{ cookiecutter.pkg_name }}-${PKG_VERSION}-py3-none-any.whl" "${DIST_DIR}"
5757
tox -e check -vv -s false
5858
5959
- name: Upload Source & Wheel distributions as Artefacts
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# -*- coding: utf-8 -*-
2+
"""Run `python -m {{ cookiecutter.pkg_name }}`.
3+
4+
Allow running {{ cookiecutter.project_name }}, also by invoking
5+
the python module:
6+
7+
`python -m {{ cookiecutter.pkg_name }}`
8+
9+
This is an alternative to directly invoking the cli that uses python as the
10+
"entrypoint".
11+
"""
12+
from __future__ import absolute_import
13+
14+
from {{ cookiecutter.pkg_name }}.cli import main
15+
16+
if __name__ == "__main__": # pragma: no cover
17+
main(prog_name="{{ cookiecutter.pkg_name|replace('_', '-') }}")

0 commit comments

Comments
 (0)