Commit

Improvements and lessons-learned

Lessons learned (from hookmeup):
1. Use a Makefile for as many commands as possible
2. Force all dependency management through Pipenv
3. On that note, always use Pipenv
4. Add support for Tox, Travis CI, and Coveralls
Daniel Moch committed 5 years ago (Tree)

Diffstat

 cookiecutter.json | 1 
 hooks/post_gen_project.py | 18 ++++++----
 hooks/pre_gen_project.py | 7 ++-
 {{cookiecutter.project_slug}}/.travis.yml | 41 +++++++++++++++++++++++++
 {{cookiecutter.project_slug}}/Makefile | 40 ++++++++++++-----------
 {{cookiecutter.project_slug}}/Pipfile | 8 +---
 {{cookiecutter.project_slug}}/tox.ini | 29 +++++++++++++++++

cookiecutter.json

8 8 "project_short_description": "Flit Boilerplate contains all the boilerplate you need to create a Python Flit package.",
9 9 "pypi_username": "{{ cookiecutter.github_username }}",
10 10 "version": "0.1.0",
11 - "use_pipenv": "y",
12 11 "script_entrypoint": "y",
13 12 "open_source_license": ["MIT license", "BSD license", "ISC license", "Apache Software License 2.0", "GNU General Public License v3", "Not open source"]
14 13 }

hooks/post_gen_project.py

1 -#!/usr/bin/env python3
1 +# -*- encoding: utf-8 *-*
2 +"""Hook to run after template is created"""
2 3 import os
3 4 import subprocess
5 +from subprocess import CalledProcessError
4 6
5 7 PROJECT_DIRECTORY = os.path.realpath(os.path.curdir)
6 -
7 8
8 9 def remove_file(filepath):
10 + """Remove a file from the generated template"""
9 11 os.remove(os.path.join(PROJECT_DIRECTORY, filepath))
10 -
11 12
12 13 if __name__ == '__main__':
13 -
14 14 if 'Not open source' == '{{ cookiecutter.open_source_license }}':
15 15 remove_file('LICENSE')
16 16
17 - if '{{ cookiecutter.use_pipenv }}' == 'n':
18 - remove_file('Pipfile')
19 - else:
17 + try:
18 + subprocess.run(
19 + ['which',
20 + 'pipenv'],
21 + stdout=subprocess.DEVNULL).check_returncode()
20 22 subprocess.run(['pipenv', 'lock', '--dev'])
21 23 subprocess.run(['pipenv', 'sync', '--dev'])
24 + except CalledProcessError:
25 + print('pipenv not installed, or not available on PATH')

hooks/pre_gen_project.py

1 +# -*- encoding: utf-8 -*-
2 +"""Hook to run before the template is generated"""
1 3 import re
2 4 import sys
3 5
4 -
5 6 MODULE_REGEX = r'^[_a-zA-Z][_a-zA-Z0-9]+$'
6 7
7 -module_name = '{{ cookiecutter.project_slug}}'
8 +module_name = '{{ cookiecutter.project_slug }}'
8 9
9 10 if not re.match(MODULE_REGEX, module_name):
10 11 print('ERROR: The project slug (%s) is not a valid Python module name. Please do not use a - and use _ instead' % module_name)
11 12
12 13 #Exit to cancel project
13 - sys.exit(1)
14 + sys.exit(1)

{{cookiecutter.project_slug}}/.travis.yml (created)

1 +# https://travis-ci.org/djmoch/{{ cookiecutter.project_slug }}
2 +language: python
3 +
4 +matrix:
5 + fast_finish: true
6 +
7 +.mixins:
8 +- &xenial-mixin
9 + dist: xenial
10 + sudo: true
11 + addons:
12 + apt:
13 + packages:
14 + - libgnutls-dev
15 +
16 +env:
17 + - PIPENV_HIDE_EMOJIS=1 PIPENV_NO_INHERIT=1
18 +
19 +install:
20 + - pip install pipenv python-coveralls
21 + - make test-install
22 +
23 +jobs:
24 + include:
25 + - stage: test
26 + script: make test
27 + python: 3.5
28 + - stage: test
29 + script: make test
30 + python: 3.6
31 + - stage: test
32 + script: make test
33 + <<: *xenial-mixin
34 + python: 3.7
35 + - stage: lint
36 + script: make lint
37 + python: 3.6
38 + - stage: coverage
39 + script: make coverage
40 + after_success: coveralls
41 + python: 3.5

{{cookiecutter.project_slug}}/Makefile

1 -.PHONY: clean clean-test clean-pyc clean-build help
1 +.PHONY: clean clean-test clean-pyc clean-build help lint coverage coverage-html release dist install run debug
2 2 .DEFAULT_GOAL := help
3 3
4 4 define BROWSER_PYSCRIPT
. . .
26 26
27 27 BROWSER := python -c "$$BROWSER_PYSCRIPT"
28 28
29 -# Comment out the following line to run outside of Pipenv
30 -{%- if cookiecutter.use_pipenv == 'y' %}
31 -PIPENV := pipenv run
32 -{%- else %}
33 -# PIPENV := pipenv run
34 -{%- endif %}
35 -
36 29 help:
37 30 @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST)
38 31
. . .
55 48 rm -f .coverage
56 49 rm -fr htmlcov/
57 50 rm -fr .pytest_cache
51 + rm -fr .tox
58 52
59 53 lint: ## check style with pylint
60 - $(PIPENV) pylint --rcfile tests/pylintrc {{ cookiecutter.project_slug }} tests
54 + pipenv run pylint --rcfile tests/pylintrc {{ cookiecutter.project_slug }} tests --disable=parse-error
61 55
62 56 test: ## run tests quickly with the default Python
63 - $(PIPENV) python -m pytest
57 + pipenv run python -m pytest
58 +
59 +test-install: ## install dependenices from Pipfile (for tox / CI builds)
60 + pipenv --bare install --dev --skip-lock
64 61
65 62 coverage: ## check code coverage quickly with the default Python
66 - $(PIPENV) python -m pytest
67 - $(PIPENV) coverage report -m
68 - $(PIPENV) coverage html
63 + pipenv run python -m pytest --cov={{ cookiecutter.project_slug }} --cov-config tests/coveragerc
64 + pipenv run coverage report -m
65 +
66 +coverage-html: coverage ## generate an HTML report and open in browser
67 + pipenv run coverage html
69 68 $(BROWSER) htmlcov/index.html
70 69
71 70 release: dist ## package and upload a release
72 - $(PIPENV) flit publish
71 + pipenv run flit publish
73 72
74 -dist: clean ## builds source and wheel package
75 - $(PIPENV) flit build
73 +dist: ## builds source and wheel package
74 + pipenv run flit build
76 75 ls -l dist
77 76
78 -install: clean ## install the package to the active Python's site-packages
79 - $(PIPENV) flit install
77 +install: ## install the package to the active Python's site-packages
78 + pipenv run flit install
79 +
80 +run: install ## run the package from site-packages
81 + pipenv run {{ cookiecutter.project_slug }}
80 82
81 83 debug: install ## debug the package from site packages
82 - $(PIPENV) pudb3 `$(PIPENV) which {{ cookiecutter.project_slug }}` install
84 + pipenv run pudb3 `pipenv run which {{ cookiecutter.project_slug }}`

{{cookiecutter.project_slug}}/Pipfile

4 4 name = "pypi"
5 5
6 6 [packages]
7 +flit = "*"
7 8
8 9 [dev-packages]
9 -pytest = "<3.7.0"
10 +pytest = "*"
10 11 pytest-cov = "*"
11 -pytest-pylint = "*"
12 +pylint = "*"
12 13 pudb = "*"
13 -
14 -[requires]
15 -python_version = "3.7"

{{cookiecutter.project_slug}}/tox.ini (created)

1 +[tox]
2 +envlist = py35, py36, py37, pylint, coverage
3 +skipsdist = True
4 +
5 +[testenv:pylint]
6 +deps = pylint
7 +whitelist_externals = make
8 +commands = make lint
9 +
10 +[testenv:coverage]
11 +deps = pipenv
12 +setenv =
13 + PIPENV_NO_INHERIT = 1
14 + PIPENV_HIDE_EMOJIS = 1
15 +whitelist_externals = make
16 +commands =
17 + make test-install
18 + make coverage
19 +
20 +[testenv]
21 +deps = pipenv
22 +setenv =
23 + PIPENV_NO_INHERIT = 1
24 + PIPENV_HIDE_EMOJIS = 1
25 +whitelist_externals = make
26 +commands =
27 + make test-install
28 + make install
29 + make test