-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add skeleton
govcookiecutter
package
Create a Python package with the minimum folders and files required to create a project from `govcookiecutter` using a CLI. By executing: ``` python setup.py build_package ``` a universal source and wheel distribution of this skeleton package is created. `pip` install the package, and then run `govcookiecutter` in your terminal. Should fix issue #23.
- Loading branch information
Showing
7 changed files
with
215 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
include README.md LICENSE | ||
graft src/govcookiecutter/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,3 +10,4 @@ pytest-mock | |
pytest-xdist | ||
Sphinx | ||
toml | ||
wheel |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
from pathlib import Path | ||
from setuptools import Command, find_packages, setup | ||
from shutil import copy, copytree, rmtree | ||
from src.govcookiecutter import __version__ | ||
import subprocess | ||
import sys | ||
|
||
# Define a description for this package | ||
PACKAGE_DESCRIPTION = ( | ||
"A cookiecutter template for analytical, Python-, or Python and R-based projects " | ||
"within Her Majesty's Government, and wider public sector." | ||
) | ||
|
||
# Define the path to the parent directory of this file | ||
dir_parent = Path(__file__).resolve().parent | ||
|
||
# Try to parse the `README.md` file to generate the long description of this package | ||
try: | ||
with open(dir_parent.joinpath("README.md"), encoding="utf-8") as f: | ||
long_description = f.read() | ||
except FileNotFoundError: | ||
long_description = PACKAGE_DESCRIPTION | ||
|
||
# Define paths to the template folder, and the `src` directories | ||
dir_template = dir_parent.joinpath("{{ cookiecutter.repo_name }}") | ||
dir_govcookiecutter = dir_parent.joinpath("src", "govcookiecutter", "govcookiecutter") | ||
dir_govcookiecutter_template = dir_govcookiecutter.joinpath( | ||
"{{ cookiecutter.repo_name }}" | ||
) | ||
|
||
# Define a dictionary of files and folders to copy to a skeleton `govcookiecutter` | ||
# Python package, where the keys are the current locations, and values are the | ||
# locations within the skeleton package | ||
copy_folders_and_files = { | ||
dir_parent.joinpath("hooks"): dir_govcookiecutter.joinpath("hooks"), | ||
dir_template: dir_govcookiecutter_template, | ||
dir_parent.joinpath("cookiecutter.json"): dir_govcookiecutter.joinpath( | ||
"cookiecutter.json" | ||
), | ||
} | ||
|
||
|
||
class BuildPackage(Command): | ||
"""Build a skeleton ``govcookiecutter`` package.""" | ||
|
||
description = "Build a skeleton `govcookiecutter` package." | ||
user_options = [] | ||
|
||
def initialize_options(self) -> None: | ||
pass | ||
|
||
def finalize_options(self) -> None: | ||
pass | ||
|
||
@staticmethod | ||
def run() -> None: | ||
"""Build a skeleton ``govcookiecutter`` package. | ||
The skeleton package contains only the necessary files and folders to generate | ||
a project template. It also contains a CLI interface, where invoking the | ||
``govcookiecutter`` command in your terminal creates the project. | ||
Returns: | ||
A universal source and wheel distribution of the skeleton `govcookiecutter` | ||
package. | ||
""" | ||
|
||
# If they already exist, delete certain folders related to the package build | ||
rmtree(dir_parent.joinpath("build"), ignore_errors=True) | ||
rmtree(dir_parent.joinpath("dist"), ignore_errors=True) | ||
rmtree(dir_govcookiecutter, ignore_errors=True) | ||
|
||
# Copy files and folders required by `cookiecutter` to create the project | ||
# templates | ||
for k, v in copy_folders_and_files.items(): | ||
if k.is_file(): | ||
copy(k, v) | ||
elif k.is_dir(): | ||
copytree(k, v) | ||
else: | ||
raise RuntimeError(f"Invalid file/folder to copy: {k}") | ||
|
||
# Create the universal source and wheel distributions | ||
subprocess.run( | ||
[sys.executable, "setup.py", "sdist", "bdist_wheel", "--universal"] | ||
) | ||
|
||
|
||
# Set up the package | ||
setup( | ||
name="govcookiecutter", | ||
version=__version__, | ||
description=PACKAGE_DESCRIPTION, | ||
long_description=long_description, | ||
long_description_content_type="text/markdown", | ||
author="ukgovdatascience", | ||
author_email="[email protected]", | ||
python_requires=">=3.6.1", | ||
url="https://github.com/ukgovdatascience/govcookiecutter", | ||
install_requires=["click", "cookiecutter"], | ||
package_dir={"": "src"}, | ||
packages=find_packages(where="src"), | ||
include_package_data=True, | ||
license="MIT", | ||
classifiers=[ | ||
"License :: OSI Approved :: MIT License", | ||
"Operating System :: OS Independent", | ||
"Programming Language :: Python", | ||
"Programming Language :: Python :: 3", | ||
"Programming Language :: Python :: 3.6", | ||
"Programming Language :: Python :: 3.7", | ||
"Programming Language :: Python :: 3.8", | ||
"Programming Language :: Python :: 3.9", | ||
"Programming Language :: Python :: Implementation :: CPython", | ||
"Programming Language :: Python :: Implementation :: PyPy", | ||
], | ||
entry_points={ | ||
"console_scripts": ["govcookiecutter=govcookiecutter.__main__:main"], | ||
}, | ||
cmdclass={ | ||
"build_package": BuildPackage, | ||
}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Define the version number of the package | ||
__version__ = "1.2.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from govcookiecutter.cli import main | ||
|
||
if __name__ == "__main__": | ||
main(prog_name="govcookiecutter") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
from pathlib import Path | ||
from cookiecutter.main import cookiecutter | ||
from govcookiecutter import __version__ | ||
import click | ||
|
||
# Define the file path to the project template | ||
dir_template = Path(__file__).resolve().parent.joinpath("govcookiecutter") | ||
|
||
|
||
# Relevant `click` options taken from `cookiecutter` version 1.7.3 | ||
@click.command(context_settings=dict(help_option_names=["-h", "--help"])) | ||
@click.version_option(__version__, u"-V", u"--version") | ||
@click.option( | ||
"--no-input", | ||
is_flag=True, | ||
help="Do not prompt for parameters and only use `cookiecutter.json` file content", | ||
) | ||
@click.option( | ||
"--replay", | ||
is_flag=True, | ||
help="Do not prompt for parameters and only use information entered previously", | ||
) | ||
@click.option( | ||
"-f", | ||
"--overwrite-if-exists", | ||
is_flag=True, | ||
help="Overwrite the contents of the output directory if it already exists", | ||
) | ||
@click.option( | ||
"-s", | ||
"--skip-if-file-exists", | ||
is_flag=True, | ||
help="Skip the files in the corresponding directories if they already exist", | ||
default=False, | ||
) | ||
@click.option( | ||
"-o", | ||
"--output-dir", | ||
default=".", | ||
type=click.Path(), | ||
help="Where to output the generated project dir into", | ||
) | ||
@click.option( | ||
"--config-file", type=click.Path(), default=None, help="User configuration file" | ||
) | ||
@click.option( | ||
"--default-config", | ||
is_flag=True, | ||
help="Do not load a config file. Use the defaults instead", | ||
) | ||
def main( | ||
no_input, | ||
replay, | ||
overwrite_if_exists, | ||
output_dir, | ||
config_file, | ||
default_config, | ||
skip_if_file_exists, | ||
) -> None: | ||
"""Generate a ``govcookiecutter`` template using ``cookiecutter``. | ||
Options are those available from ``cookiecutter`` v1.7.3 that are compatible with | ||
``govcookiecutter``. | ||
""" | ||
cookiecutter( | ||
template=str(dir_template), | ||
no_input=no_input, | ||
replay=replay, | ||
overwrite_if_exists=overwrite_if_exists, | ||
output_dir=output_dir, | ||
config_file=config_file, | ||
default_config=default_config, | ||
skip_if_file_exists=skip_if_file_exists, | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |