From 14aa05fbfa2481dade40251bb4aa3c86cbe8f659 Mon Sep 17 00:00:00 2001 From: Emmanuel Bengio Date: Thu, 24 Feb 2022 14:45:23 -0500 Subject: [PATCH] Initial commit --- README.md | 9 ++ cookiecutter.json | 10 ++ hooks/post_gen_project.py | 28 ++++ template-tests/.gitignore | 1 + template-tests/requirements.txt | 8 + template-tests/test.sh | 52 +++++++ template-tests/test_generate.py | 26 ++++ {{cookiecutter.repo_name}}/.gitignore | 129 ++++++++++++++++ {{cookiecutter.repo_name}}/.yapfignore | 4 + {{cookiecutter.repo_name}}/Dockerfile.test | 6 + {{cookiecutter.repo_name}}/MANIFEST.in | 0 {{cookiecutter.repo_name}}/README.md | 31 ++++ {{cookiecutter.repo_name}}/VERSION | 2 + .../conda.recipe/meta.yaml | 53 +++++++ .../requirements/dev.in | 23 +++ .../requirements/main.in | 9 ++ {{cookiecutter.repo_name}}/setup.cfg | 37 +++++ {{cookiecutter.repo_name}}/setup.py | 14 ++ {{cookiecutter.repo_name}}/tests/__init__.py | 0 {{cookiecutter.repo_name}}/tests/test_core.py | 5 + {{cookiecutter.repo_name}}/tox.ini | 38 +++++ .../{{cookiecutter.python_name}}/__init__.py | 0 .../{{cookiecutter.python_name}}/cli.py | 144 ++++++++++++++++++ .../{{cookiecutter.python_name}}/core.py | 19 +++ 24 files changed, 648 insertions(+) create mode 100644 README.md create mode 100644 cookiecutter.json create mode 100644 hooks/post_gen_project.py create mode 100644 template-tests/.gitignore create mode 100644 template-tests/requirements.txt create mode 100755 template-tests/test.sh create mode 100644 template-tests/test_generate.py create mode 100644 {{cookiecutter.repo_name}}/.gitignore create mode 100644 {{cookiecutter.repo_name}}/.yapfignore create mode 100644 {{cookiecutter.repo_name}}/Dockerfile.test create mode 100644 {{cookiecutter.repo_name}}/MANIFEST.in create mode 100644 {{cookiecutter.repo_name}}/README.md create mode 100644 {{cookiecutter.repo_name}}/VERSION create mode 100644 {{cookiecutter.repo_name}}/conda.recipe/meta.yaml create mode 100644 {{cookiecutter.repo_name}}/requirements/dev.in create mode 100644 {{cookiecutter.repo_name}}/requirements/main.in create mode 100644 {{cookiecutter.repo_name}}/setup.cfg create mode 100644 {{cookiecutter.repo_name}}/setup.py create mode 100644 {{cookiecutter.repo_name}}/tests/__init__.py create mode 100644 {{cookiecutter.repo_name}}/tests/test_core.py create mode 100644 {{cookiecutter.repo_name}}/tox.ini create mode 100644 {{cookiecutter.repo_name}}/{{cookiecutter.python_name}}/__init__.py create mode 100644 {{cookiecutter.repo_name}}/{{cookiecutter.python_name}}/cli.py create mode 100644 {{cookiecutter.repo_name}}/{{cookiecutter.python_name}}/core.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..e223849 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +**Note: Do not attempt to use this directly unless you +know what you are doing. The happy path is to let `roadie` interact with this +template for you.** + +This is a template repository. It will be used by `roadie` to instantiate +instances. We will make an initial commit on those repos with this boilerplate, +so there is traceability as to the version of this template the repo was created +with. This could be useful in figuring out later upgrades necessary to keep +a repo up-to-date with compliance standards. diff --git a/cookiecutter.json b/cookiecutter.json new file mode 100644 index 0000000..a255318 --- /dev/null +++ b/cookiecutter.json @@ -0,0 +1,10 @@ +{ + "repo_name": "Repository name (use hyphens)", + "description": "Project summary description", + "package": "package? (y/n)", + "type": "dash/package/service/task", + "yapf": "yapf configuration", + "flake8": "flake8 configuration", + "cli": "cli? (y/n)", + "python_name": "{{cookiecutter.repo_name|replace('-', '_')|lower}}" + } \ No newline at end of file diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py new file mode 100644 index 0000000..51331e1 --- /dev/null +++ b/hooks/post_gen_project.py @@ -0,0 +1,28 @@ +import os +import shutil + + +def move_files(files_to_move): + for f in files_to_move: + shutil.move(f['src'], f['dest']) + + +def main(): + have_cli = {{cookiecutter.cli == 'y'}} + python_name = '{{cookiecutter.python_name}}' + + + files_to_delete = set() + dirs_to_delete = set() + + if not have_cli: + files_to_delete = files_to_delete.union({f'{python_name}/cli.py'}) + + for f in files_to_delete: + os.remove(f) + + for d in dirs_to_delete: + shutil.rmtree(d) + + +main() diff --git a/template-tests/.gitignore b/template-tests/.gitignore new file mode 100644 index 0000000..90609aa --- /dev/null +++ b/template-tests/.gitignore @@ -0,0 +1 @@ +test-package/* \ No newline at end of file diff --git a/template-tests/requirements.txt b/template-tests/requirements.txt new file mode 100644 index 0000000..3fae1a5 --- /dev/null +++ b/template-tests/requirements.txt @@ -0,0 +1,8 @@ +--index-url https://${PYPI_DOWNLOAD_USERNAME}:${PYPI_DOWNLOAD_PASSWORD}@nexus.rxrx.io/repository/pypi-all/simple +bandit +cookiecutter +flake8 +mypy +roadie[cli]>=2.3.9 +safety +yapf diff --git a/template-tests/test.sh b/template-tests/test.sh new file mode 100755 index 0000000..c3a0ecc --- /dev/null +++ b/template-tests/test.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +set -e +set -x + +python3.9 -m pip install -r requirements.txt + +################################################################################ +#### Test Case: Package With CLI +rm -rf test-package || true +python3.9 test_generate.py y + +pushd test-package + +python3.9 -m roadie.cli.main yapf dump -o ./style.yapf +python3.9 -m roadie.cli.main lock -u ${PYPI_DOWNLOAD_USERNAME} -p ${PYPI_DOWNLOAD_PASSWORD} --all +python3.9 -m roadie.cli.main venv -u ${PYPI_DOWNLOAD_USERNAME} -p ${PYPI_DOWNLOAD_PASSWORD} --use-venv +source venv/bin/activate + +flake8 +yapf --style ./style.yapf --parallel --diff -r . +mypy +bandit -r . -x /tests/,/venv/ +safety check $(ls requirements/*.txt | xargs -i echo -n ' -r {}') +CONFIGOME_ENV=test pytest +pip install --upgrade tox +tox --parallel + +popd + +################################################################################ +#### Test Case: Package Without a CLI +rm -rf test-package || true +python3.9 test_generate.py n + +pushd test-package + +python3.9 -m roadie.cli.main yapf dump -o ./style.yapf +python3.9 -m roadie.cli.main lock -u ${PYPI_DOWNLOAD_USERNAME} -p ${PYPI_DOWNLOAD_PASSWORD} --all +python3.9 -m roadie.cli.main venv -u ${PYPI_DOWNLOAD_USERNAME} -p ${PYPI_DOWNLOAD_PASSWORD} --use-venv +source venv/bin/activate + +flake8 +yapf --style ./style.yapf --parallel --diff -r . +mypy +bandit -r . -x /tests/,/venv/ +safety check $(ls requirements/*.txt | xargs -i echo -n ' -r {}') +CONFIGOME_ENV=test pytest +pip install --upgrade tox +tox --parallel + +popd diff --git a/template-tests/test_generate.py b/template-tests/test_generate.py new file mode 100644 index 0000000..6564c45 --- /dev/null +++ b/template-tests/test_generate.py @@ -0,0 +1,26 @@ +from cookiecutter.main import cookiecutter +from roadie.constants import FLAKE8_STYLE, YAPF_STYLE +import sys + + +def main(): + + yapf_configuration = '' + for k, v in YAPF_STYLE.items(): + yapf_configuration += f'{k.lower()} = {str(v).lower()}\n' + flake8_configuration = '' + for k, v in FLAKE8_STYLE.items(): + flake8_configuration += f'{k.lower()} = {str(v).lower()}\n' + + cookiecutter_context = { + 'repo_name': "test-package", + 'description': "words go here", + 'type': 'package', + 'yapf': yapf_configuration, + 'flake8': flake8_configuration, + 'cli': sys.argv[1], + } + cookiecutter('..', no_input=True, extra_context=cookiecutter_context) + + +main() diff --git a/{{cookiecutter.repo_name}}/.gitignore b/{{cookiecutter.repo_name}}/.gitignore new file mode 100644 index 0000000..b6e4761 --- /dev/null +++ b/{{cookiecutter.repo_name}}/.gitignore @@ -0,0 +1,129 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/{{cookiecutter.repo_name}}/.yapfignore b/{{cookiecutter.repo_name}}/.yapfignore new file mode 100644 index 0000000..1e01d59 --- /dev/null +++ b/{{cookiecutter.repo_name}}/.yapfignore @@ -0,0 +1,4 @@ +venv*/ +build/ +dist/ +.tox diff --git a/{{cookiecutter.repo_name}}/Dockerfile.test b/{{cookiecutter.repo_name}}/Dockerfile.test new file mode 100644 index 0000000..67566f5 --- /dev/null +++ b/{{cookiecutter.repo_name}}/Dockerfile.test @@ -0,0 +1,6 @@ +FROM gcr.io/eng-infrastructure/rxrx-pyenv as test +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + +ENV CONFIGOME_ENV=test +ENTRYPOINT [ "tox", "--parallel" ] diff --git a/{{cookiecutter.repo_name}}/MANIFEST.in b/{{cookiecutter.repo_name}}/MANIFEST.in new file mode 100644 index 0000000..e69de29 diff --git a/{{cookiecutter.repo_name}}/README.md b/{{cookiecutter.repo_name}}/README.md new file mode 100644 index 0000000..f057bbe --- /dev/null +++ b/{{cookiecutter.repo_name}}/README.md @@ -0,0 +1,31 @@ +# {{cookiecutter.repo_name}} + +{{cookiecutter.description}} + +## Installation + +### PIP + +This package is installable via [Nexus](nexus.rxrx.io). You should configure your PIP using the instructions listed at +[roadie: PIP Configuration](https://github.com/recursionpharma/roadie#pip-configuration). Then, execute the following: + +```bash +pip install {{cookiecutter.python_name}} +``` + +### Conda + +You will need [anaconda cloud setup](https://github.com/recursionpharma/drug-discovery/wiki/Anaconda-Setup#setup-anaconda-cloud-locally) +in order to access the Recursion conda packages. Once that is setup you can install this library like so: + +``` +conda config --add channels conda-forge +conda config --add channels defaults +conda config --add channels recursion +conda install {{cookiecutter.python_name}} +``` + +## Developing + +Please refer to [Developing Python at Recursion](https://github.com/recursionpharma/roadie/blob/trunk/Developing.md) +for all tasks related to development of this codebase. diff --git a/{{cookiecutter.repo_name}}/VERSION b/{{cookiecutter.repo_name}}/VERSION new file mode 100644 index 0000000..bd263df --- /dev/null +++ b/{{cookiecutter.repo_name}}/VERSION @@ -0,0 +1,2 @@ +MAJOR="0" +MINOR="0" diff --git a/{{cookiecutter.repo_name}}/conda.recipe/meta.yaml b/{{cookiecutter.repo_name}}/conda.recipe/meta.yaml new file mode 100644 index 0000000..db8fa4e --- /dev/null +++ b/{{cookiecutter.repo_name}}/conda.recipe/meta.yaml @@ -0,0 +1,53 @@ +{# raw is for ignoring templating with cookiecutter, leaving it for use with conda-build #} +{% raw -%} +{% set data = load_setup_py_data() %} +{%- endraw %} + +package: + name: {{cookiecutter.python_name}} + {# raw is for ignoring templating with cookiecutter, leaving it for use with conda-build #} + {% raw -%} + version: {{ data['version'] }} + {%- endraw %} + +source: + path: .. + +build: + # If the installation is complex, or different between Unix and Windows, use + # separate bld.bat and build.sh files instead of this key. Add the line + # "skip: True # [py<35]" (for example) to limit to Python 3.5 and newer, or + # "skip: True # [not win]" to limit to Windows. + script: python setup.py install --single-version-externally-managed --record=record.txt + noarch: python + {%- if cookiecutter.cli == 'y' %} + entry_points: + - {{cookiecutter.python_name}} = {{cookiecutter.python_name}}.cli:cli + {%- endif %} + +requirements: + build: + - python>=3.6 + - setuptools + - roadie + run: + - python>=3.6 + {% raw -%} + # dependencies are defined in setup.py + {% for dep in data['install_requires'] %} + - {{ dep.lower() }} + {% endfor %} + {# raw is for ignoring templating with cookiecutter, leaving it for use with conda-build #} + {%- endraw %} + +test: + source_files: + - tests + requires: + - pytest + commands: + - pytest tests + +about: + home: https://github.com/recursionpharma/{{cookiecutter.repo_name}} + summary: {{cookiecutter.description}} diff --git a/{{cookiecutter.repo_name}}/requirements/dev.in b/{{cookiecutter.repo_name}}/requirements/dev.in new file mode 100644 index 0000000..fb0faf9 --- /dev/null +++ b/{{cookiecutter.repo_name}}/requirements/dev.in @@ -0,0 +1,23 @@ +# These are the minimum specifications required to set up a development +# environment and includes things like depedencies required for testing, tools +# for ensuring security, formatting, and static checking compliance. Feel free +# to add anything that improves your developer experience. +# +# Do you like to test things in a notebook? Then, add `notebook` here. Do you +# find yourself inspecting objects a lot in the REPL? May I suggest `pdir2`. Do +# you like lots of colors and formatting options in your REPL, then get `rich`. +# Remember, it doesn't pay to be too specific here, roadie can be used to +# resolve your environment and make it reproducible for others. + +-c main + +bandit +flake8<4; python_version<'3.8' +flake8; python_version>='3.8' +mypy +pytest +pytest-cov +roadie +safety +types-pkg_resources +yapf diff --git a/{{cookiecutter.repo_name}}/requirements/main.in b/{{cookiecutter.repo_name}}/requirements/main.in new file mode 100644 index 0000000..3f0209d --- /dev/null +++ b/{{cookiecutter.repo_name}}/requirements/main.in @@ -0,0 +1,9 @@ +# These are the minimum specifications your package will need to operate. If +# there are heavy things that only provide limited functionality consider adding +# an optional extra package by including those dependencies in a separate file +# in this directory with the .in extenion. Roadie will handle constructing your +# package appropriately. + +{%- if cookiecutter.cli == 'y' %} +click +{%- endif %} \ No newline at end of file diff --git a/{{cookiecutter.repo_name}}/setup.cfg b/{{cookiecutter.repo_name}}/setup.cfg new file mode 100644 index 0000000..6d75c62 --- /dev/null +++ b/{{cookiecutter.repo_name}}/setup.cfg @@ -0,0 +1,37 @@ +[metadata] +name = {{cookiecutter.python_name}} +description = {{cookiecutter.description}} +url = https://github.com/recursionpharma/roadie +version = set_version_placeholder +author = Recursion Pharmaceuticals +author_email = devs@recursionpharma.com +classifiers = + Operating System :: OS Independent + Programming Language :: Python + Programming Language :: Python :: 3 +keywords = '{{cookiecutter.python_name}}' + +[options] +python_requires > = 3.6 + +[flake8] +{{cookiecutter.flake8}} + +[yapf] +{{cookiecutter.yapf}} + +[bdist_wheel] +universal = True + +[tool:pytest] +addopts = + -v + -x + --color=yes + --cov-report term-missing + --cov={{cookiecutter.python_name}} +testpaths = + tests + +[mypy] +files = {{cookiecutter.python_name}} diff --git a/{{cookiecutter.repo_name}}/setup.py b/{{cookiecutter.repo_name}}/setup.py new file mode 100644 index 0000000..e749efc --- /dev/null +++ b/{{cookiecutter.repo_name}}/setup.py @@ -0,0 +1,14 @@ +from setuptools import find_packages, setup + +import roadie + +(install_requires, extras_require) = roadie.get_requirements() + +setup( + packages=find_packages(), + install_requires=install_requires, + extras_require=extras_require, + {%- if cookiecutter.cli == 'y' %} + entry_points={'console_scripts': ['{{cookiecutter.python_name}}={{cookiecutter.python_name}}.cli:cli']}, + {%- endif %} +) diff --git a/{{cookiecutter.repo_name}}/tests/__init__.py b/{{cookiecutter.repo_name}}/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/{{cookiecutter.repo_name}}/tests/test_core.py b/{{cookiecutter.repo_name}}/tests/test_core.py new file mode 100644 index 0000000..57732d5 --- /dev/null +++ b/{{cookiecutter.repo_name}}/tests/test_core.py @@ -0,0 +1,5 @@ +from {{cookiecutter.python_name}}.core import get_version + + +def test_get_version(): + assert get_version() == 'set_version_placeholder' diff --git a/{{cookiecutter.repo_name}}/tox.ini b/{{cookiecutter.repo_name}}/tox.ini new file mode 100644 index 0000000..1eb7099 --- /dev/null +++ b/{{cookiecutter.repo_name}}/tox.ini @@ -0,0 +1,38 @@ +[tox] +minversion = 3.2.0 +requires = roadie +envlist = py3{7,8,9}, report + +[testenv] +commands = pytest +passenv = * +skip_install=true +setenv = + PIP_INDEX_URL = https://{env:PYPI_DOWNLOAD_USERNAME}:{env:PYPI_DOWNLOAD_PASSWORD}@nexus.rxrx.io/repository/pypi-all/simple + CONFIGOME_ENV = test + py3{7,8,9}: COVERAGE_FILE = .coverage.{envname} + +depends = + report: py37,py38,py39 + +[testenv:py37] +deps = + -rrequirements/main_3.7.txt + -rrequirements/dev_3.7.txt + +[testenv:py38] +deps = + -rrequirements/main_3.8.txt + -rrequirements/dev_3.8.txt + +[testenv:py39] +deps = + -rrequirements/main_3.9.txt + -rrequirements/dev_3.9.txt + +[testenv:report] +deps = coverage +skip_install = true +commands = + coverage combine + coverage report --fail-under=0 diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.python_name}}/__init__.py b/{{cookiecutter.repo_name}}/{{cookiecutter.python_name}}/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.python_name}}/cli.py b/{{cookiecutter.repo_name}}/{{cookiecutter.python_name}}/cli.py new file mode 100644 index 0000000..dce7279 --- /dev/null +++ b/{{cookiecutter.repo_name}}/{{cookiecutter.python_name}}/cli.py @@ -0,0 +1,144 @@ +import base64 +import click + +import {{cookiecutter.python_name}}.core + + +def print_banner() -> None: + """Prints a Colorful Logo + """ + banner = "G1sxMDc7NDBtG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szOD" \ + "s1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20g" \ + "G1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20mG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szOD" \ + "s1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20g" \ + "G1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gChtbMzg7NTttIBtbMz" \ + "g7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTtt" \ + "IBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttKBtbMzg7NTttJRtbMzg7NTsyMjFtJR" \ + "tbMzg7NTsyMjFtJRtbMzg7NTsyMjFtJRtbMzg7NTsxODVtIxtbMzg7NTsxNzltIxtbMzg7NTsxNzltIxtbMzg7NTsxNzltIxtbMzg7" \ + "NTttJRtbMzg7NTttLBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIB" \ + "tbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIAobWzM4OzU7bSAbWzM4" \ + "OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bS" \ + "AbWzM4OzU7bSAbWzM4OzU7bSYbWzM4OzU7bSUbWzM4OzU7MjIxbSUbWzM4OzU7MjIxbSUbWzM4OzU7MjIxbSUbWzM4OzU7MjIxbSUb" \ + "WzM4OzU7MjIxbSUbWzM4OzU7MjIxbSUbWzM4OzU7MjIxbSUbWzM4OzU7MTg1bSMbWzM4OzU7MTc5bSMbWzM4OzU7MTc5bSMbWzM4Oz" \ + "U7MTc5bSMbWzM4OzU7MTc5bSMbWzM4OzU7MTc5bSMbWzM4OzU7MTc5bSMbWzM4OzU7MTc5bSMbWzM4OzU7bSMbWzM4OzU7bSobWzM4" \ + "OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bS" \ + "AbWzM4OzU7bSAKG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20sG1sz" \ + "ODs1O20jG1szODs1OzEwN20oG1szODs1OzEwN20oG1szODs1OzE0OW0jG1szODs1OzE4NW0jG1szODs1OzE4NW0jG1szODs1OzE4NW" \ + "0jG1szODs1OzIyMW0lG1szODs1OzIyMW0lG1szODs1OzIyMW0lG1szODs1OzIyMW0lG1szODs1OzIyMW0lG1szODs1OzIyMW0lG1sz" \ + "ODs1OzIyMW0jG1szODs1OzE3OW0jG1szODs1OzE3OW0jG1szODs1OzE3OW0jG1szODs1OzE3OW0jG1szODs1OzE3OW0jG1szODs1Oz" \ + "E3OW0jG1szODs1OzE3OW0jG1szODs1OzE3OW0jG1szODs1OzE3OW0jG1szODs1OzE3OW0jG1szODs1OzE3OW0jG1szODs1OzE3OW0j" \ + "G1szODs1O20jG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gChtbMzg7NTttIBtbMz" \ + "g7NTttIBtbMzg7NTttJRtbMzg7NTttKBtbMzg7NTsxMDdtKBtbMzg7NTsxMDdtKBtbMzg7NTsxMDdtKBtbMzg7NTsxMDdtKBtbMzg7" \ + "NTsxMDdtKBtbMzg7NTsxMDdtKBtbMzg7NTsxNDltIxtbMzg7NTsxODVtIxtbMzg7NTsxODVtIxtbMzg7NTsxODVtIxtbMzg7NTsxOD" \ + "VtIxtbMzg7NTsxODVtIxtbMzg7NTsxODVtIxtbMzg7NTsxODVtIxtbMzg7NTsyMjFtJRtbMzg7NTsyMjFtJRtbMzg7NTsyMjFtIxtb" \ + "Mzg7NTsxNzltIxtbMzg7NTsxNzltIxtbMzg7NTsxNzltIxtbMzg7NTsxNzltIxtbMzg7NTsxNzltIxtbMzg7NTsxNzltIxtbMzg7NT" \ + "sxNzltIxtbMzg7NTsxNzltIxtbMzg7NTsxNzltIxtbMzg7NTsxNzltIxtbMzg7NTsxNzltIxtbMzg7NTsxNzltIxtbMzg7NTsxNzlt" \ + "IxtbMzg7NTsxNzltIxtbMzg7NTsxNzltIxtbMzg7NTsxNzltIxtbMzg7NTttIxtbMzg7NTttIBtbMzg7NTttIAobWzM4OzU7MTA4bS" \ + "gbWzM4OzU7MDcxbS8bWzM4OzU7MDY1bS8bWzM4OzU7MDcxbS8bWzM4OzU7MDcxbS8bWzM4OzU7MDcxbS8bWzM4OzU7MDcxbS8bWzM4" \ + "OzU7MDcxbS8bWzM4OzU7MDcxbS8bWzM4OzU7MDcxbS8bWzM4OzU7MTA3bSgbWzM4OzU7MTQ5bSgbWzM4OzU7MTQ5bSgbWzM4OzU7MT" \ + "Q5bSgbWzM4OzU7MTQ5bSgbWzM4OzU7MTQ5bSgbWzM4OzU7MTQ5bSgbWzM4OzU7MTQ5bSgbWzM4OzU7bSMbWzM4OzU7bSAbWzM4OzU7" \ + "bSAbWzM4OzU7bSMbWzM4OzU7bSMbWzM4OzU7MTczbSgbWzM4OzU7MTczbSgbWzM4OzU7MTczbSgbWzM4OzU7MTczbSgbWzM4OzU7MT" \ + "czbSgbWzM4OzU7MTczbSgbWzM4OzU7MTczbSgbWzM4OzU7MTY3bS8bWzM4OzU7MTY3bS8bWzM4OzU7MTY3bS8bWzM4OzU7MTY3bS8b" \ + "WzM4OzU7MTY3bS8bWzM4OzU7MTY3bS8bWzM4OzU7MTY3bS8bWzM4OzU7MTY3bS8bWzM4OzU7MTY3bS8bWzM4OzU7MTMxbS8KG1szOD" \ + "s1OzEwOG0oG1szODs1OzA2Nm0vG1szODs1OzA2NW0vG1szODs1OzA3MW0vG1szODs1OzA3MW0vG1szODs1OzA3MW0vG1szODs1OzA3" \ + "MW0vG1szODs1OzA3MW0vG1szODs1OzA3MW0vG1szODs1OzA3MW0vG1szODs1OzEwN20oG1szODs1OzE0OW0oG1szODs1OzE0OW0oG1" \ + "szODs1O20jG1szODs1O20oG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1" \ + "O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20sG1szODs1O20lG1szODs1OzE3M20oG1szODs1OzE3M20oG1szOD" \ + "s1OzE3M20oG1szODs1OzE2N20vG1szODs1OzE2N20vG1szODs1OzE2N20vG1szODs1OzE2N20vG1szODs1OzE2N20vG1szODs1OzEz" \ + "MW0vG1szODs1OzEzMW0vG1szODs1OzEzMW0vG1szODs1OzEzMW0vG1szODs1OzEzMW0qChtbMzg7NTttKBtbMzg7NTswNjZtLxtbMz" \ + "g7NTswNjZtLxtbMzg7NTswNjZtLxtbMzg7NTswNzFtLxtbMzg7NTswNzFtLxtbMzg7NTswNzFtLxtbMzg7NTswNzFtLxtbMzg7NTsw" \ + "NzFtLxtbMzg7NTswNzFtLxtbMzg7NTttJhtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NT" \ + "ttIBtbMzg7NTttKBtbMzg7NTttIxtbMzg7NTsxNDltKBtbMzg7NTsxNzltIxtbMzg7NTsxNzltIxtbMzg7NTttIxtbMzg7NTttIxtb" \ + "Mzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttKBtbMzg7NTsxMzFtLxtbMz" \ + "g7NTsxMzFtLxtbMzg7NTsxMzFtLxtbMzg7NTsxMzFtLxtbMzg7NTsxMzFtLxtbMzg7NTsxMzFtLxtbMzg7NTsxMzFtKhtbMzg7NTsx" \ + "MzFtKhtbMzg7NTsxMzFtKgobWzM4OzU7bSgbWzM4OzU7MDY2bS8bWzM4OzU7MDY2bS8bWzM4OzU7MDY2bS8bWzM4OzU7MDY2bS8bWz" \ + "M4OzU7MDcybS8bWzM4OzU7MDczbSgbWzM4OzU7MDczbSgbWzM4OzU7MDczbSgbWzM4OzU7MDczbSgbWzM4OzU7bSYbWzM4OzU7bSAb" \ + "WzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSgbWzM4OzU7MTA3bSgbWzM4OzU7MTQ5bSMbWzM4OzU7MTQ5bSgbWzM4OzU7MTQ5bSgbWz" \ + "M4OzU7MTQ5bSgbWzM4OzU7MTc5bSMbWzM4OzU7MTc5bSMbWzM4OzU7MTc5bSMbWzM4OzU7MTc5bSMbWzM4OzU7MTc5bSMbWzM4OzU7" \ + "MTczbSgbWzM4OzU7bSgbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSgbWzM4OzU7MTY3bS8bWzM4OzU7MTY3bS8bWz" \ + "M4OzU7MTY3bS8bWzM4OzU7MTY3bS8bWzM4OzU7MTMxbS8bWzM4OzU7MTMxbSobWzM4OzU7MTMxbSobWzM4OzU7MTMxbSobWzM4OzU7" \ + "MTMxbSoKG1szODs1O20oG1szODs1OzA3M20oG1szODs1OzA3M20oG1szODs1OzA3M20oG1szODs1OzA3M20oG1szODs1OzA3M20oG1" \ + "szODs1OzA3M20oG1szODs1OzA3M20oG1szODs1OzA3M20oG1szODs1OzA3M20oG1szODs1O20mG1szODs1O20gG1szODs1O20gG1sz" \ + "ODs1O20gG1szODs1O20oG1szODs1OzAzMm0vG1szODs1OzAzMm0vG1szODs1OzAzMm0vG1szODs1OzAzMm0vG1szODs1OzA3Mm0oG1" \ + "szODs1OzE3OW0jG1szODs1OzE2N20vG1szODs1OzEzMW0qG1szODs1OzEzMW0qG1szODs1OzEzMW0qG1szODs1OzEzMW0qG1szODs1" \ + "O20oG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20oG1szODs1OzE2N20vG1szODs1OzE2N20vG1szODs1OzE2N20vG1" \ + "szODs1OzE2N20vG1szODs1OzE2N20vG1szODs1OzE2N20vG1szODs1OzE2N20vG1szODs1OzE2N20vG1szODs1OzEzMW0vChtbMzg7" \ + "NTttIxtbMzg7NTswMzhtKBtbMzg7NTswMzhtKBtbMzg7NTswNzRtKBtbMzg7NTswNzNtKBtbMzg7NTswNzNtKBtbMzg7NTswNzNtKB" \ + "tbMzg7NTswNzNtKBtbMzg7NTswNzNtKBtbMzg7NTswNzNtKBtbMzg7NTttJhtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7" \ + "NTttKBtbMzg7NTswMzJtLxtbMzg7NTswMzFtLxtbMzg7NTswMjRtKhtbMzg7NTswMjRtKhtbMzg7NTswMjRtKhtbMzg7NTswNjBtKh" \ + "tbMzg7NTswOTVtKhtbMzg7NTswOTVtKhtbMzg7NTswOTVtKhtbMzg7NTsxMzFtKhtbMzg7NTsxMzFtKhtbMzg7NTttKBtbMzg7NTtt" \ + "IBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttKBtbMzg7NTsxNjdtLxtbMzg7NTsxNjdtLxtbMzg7NTsxNjdtLxtbMzg7NTsxNjdtLx" \ + "tbMzg7NTsxNjdtLxtbMzg7NTsxNjdtLxtbMzg7NTsxMzFtLxtbMzg7NTsxMzJtLxtbMzg7NTsxMzFtLwobWzM4OzU7bSMbWzM4OzU7" \ + "MDMybS8bWzM4OzU7MDM4bS8bWzM4OzU7MDM4bSgbWzM4OzU7MDM4bSgbWzM4OzU7MDM4bSgbWzM4OzU7MDM4bSgbWzM4OzU7MDc0bS" \ + "gbWzM4OzU7MDczbSgbWzM4OzU7MDczbSgbWzM4OzU7bSYbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7" \ + "bS8bWzM4OzU7MDI0bSobWzM4OzU7MDI0bSobWzM4OzU7MDI0bSobWzM4OzU7MDI0bSobWzM4OzU7MDYwbSobWzM4OzU7MDk1bSobWz" \ + "M4OzU7MDk1bSobWzM4OzU7MDk1bSobWzM4OzU7bS8bWzM4OzU7bSgbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAb" \ + "WzM4OzU7bSgbWzM4OzU7MTY3bS8bWzM4OzU7MTMxbS8bWzM4OzU7MTMybS8bWzM4OzU7MTMybS8bWzM4OzU7MTMybS8bWzM4OzU7MT" \ + "MybS8bWzM4OzU7MTMybS8bWzM4OzU7MTY3bS8bWzM4OzU7MTY3bS8KG1szODs1OzA3NG0jG1szODs1OzAzMm0vG1szODs1OzAzMm0v" \ + "G1szODs1OzAzMm0vG1szODs1OzAzOG0oG1szODs1OzAzOG0oG1szODs1OzAzOG0oG1szODs1OzAzOG0oG1szODs1OzAzMW0vG1szOD" \ + "s1OzAzMW0vG1szODs1OzAyNG0qG1szODs1O20qG1szODs1O20jG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1sz" \ + "ODs1O20gG1szODs1O20gG1szODs1O20uG1szODs1O20vG1szODs1O20uG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O2" \ + "0gG1szODs1O20gG1szODs1O20gG1szODs1O20oG1szODs1OzA5Nm0vG1szODs1OzEzMW0vG1szODs1OzEzMW0vG1szODs1OzEzMW0v" \ + "G1szODs1OzEzMm0vG1szODs1OzEzMm0vG1szODs1OzEzMm0vG1szODs1OzE2N20vG1szODs1OzE2N20vG1szODs1OzE2N20vG1szOD" \ + "s1OzE2N20vChtbMzg7NTswNzRtIxtbMzg7NTswMzJtLxtbMzg7NTswMzJtLxtbMzg7NTswMzJtLxtbMzg7NTswNjdtLxtbMzg7NTsw" \ + "NjdtLxtbMzg7NTswMzFtLxtbMzg7NTswMzFtLxtbMzg7NTswMzFtLxtbMzg7NTswMzFtLxtbMzg7NTswMjRtKhtbMzg7NTswMjRtKh" \ + "tbMzg7NTswNjBtKhtbMzg7NTswNjBtKhtbMzg7NTswNjBtKhtbMzg7NTswNjBtKhtbMzg7NTttKBtbMzg7NTttIBtbMzg7NTttIBtb" \ + "Mzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttLhtbMzg7NTttKBtbMzg7NTswOTZtLxtbMzg7NTswOTZtLx" \ + "tbMzg7NTswOTZtLxtbMzg7NTsxMzFtLxtbMzg7NTsxMzFtLxtbMzg7NTsxMzFtLxtbMzg7NTsxMzFtLxtbMzg7NTsxMzFtLxtbMzg7" \ + "NTsxMzFtLxtbMzg7NTsxMzFtLxtbMzg7NTsxMzJtLxtbMzg7NTsxMzFtLxtbMzg7NTsxNjdtLxtbMzg7NTsxNjdtLxtbMzg7NTsxNj" \ + "dtLwobWzM4OzU7bSgbWzM4OzU7bSgbWzM4OzU7MDY3bS8bWzM4OzU7MDY3bS8bWzM4OzU7MDY3bS8bWzM4OzU7MDY3bS8bWzM4OzU7" \ + "MDY3bS8bWzM4OzU7MDMxbS8bWzM4OzU7MDMxbS8bWzM4OzU7MDMxbS8bWzM4OzU7MDI0bSobWzM4OzU7MDI0bSobWzM4OzU7MDI0bS" \ + "obWzM4OzU7MDI0bSobWzM4OzU7MDYwbSobWzM4OzU7MDYwbSobWzM4OzU7MDYwbSobWzM4OzU7MDYwbSobWzM4OzU7MDYwbSobWzM4" \ + "OzU7MDYwbSobWzM4OzU7bSobWzM4OzU7MDk2bS8bWzM4OzU7MDk2bS8bWzM4OzU7MDk2bS8bWzM4OzU7MDk2bS8bWzM4OzU7MDk2bS" \ + "8bWzM4OzU7MDk2bS8bWzM4OzU7MTMxbS8bWzM4OzU7MTMxbS8bWzM4OzU7MTMxbS8bWzM4OzU7MTMxbS8bWzM4OzU7MTMxbS8bWzM4" \ + "OzU7MTMxbS8bWzM4OzU7MTMxbS8bWzM4OzU7MTMybS8bWzM4OzU7MTMybS8bWzM4OzU7MTMybS8bWzM4OzU7MTMybS8bWzM4OzU7MT" \ + "MxbS8bWzM4OzU7bSMKG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20uG1szODs1O20jG1szODs1OzA2" \ + "N20vG1szODs1OzA2N20vG1szODs1OzA2N20vG1szODs1OzAzMW0vG1szODs1OzAyNG0qG1szODs1OzAyNG0qG1szODs1OzAyNG0qG1" \ + "szODs1OzAyNG0qG1szODs1OzAyNG0qG1szODs1OzA2MG0qG1szODs1OzA2MG0qG1szODs1OzA2MG0qG1szODs1OzA2MG0qG1szODs1" \ + "OzA2MG0qG1szODs1OzA2MG0qG1szODs1OzIzOW0qG1szODs1OzIzOW0qG1szODs1OzIzOW0qG1szODs1OzIzOW0qG1szODs1OzA5NW" \ + "0vG1szODs1OzEzMW0vG1szODs1OzEzMW0vG1szODs1OzEzMW0vG1szODs1OzEzMW0vG1szODs1OzEzMW0vG1szODs1OzEzMW0vG1sz" \ + "ODs1OzEzMm0vG1szODs1OzEzMm0vG1szODs1OzEzMm0vG1szODs1O20lG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O2" \ + "0gChtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtb" \ + "Mzg7NTttIBtbMzg7NTttJhtbMzg7NTswMjRtKhtbMzg7NTswMjRtKhtbMzg7NTswMjRtKhtbMzg7NTswMjRtKhtbMzg7NTswMjRtKh" \ + "tbMzg7NTswMjRtKhtbMzg7NTswMjRtKhtbMzg7NTswNjBtKhtbMzg7NTswNjBtKhtbMzg7NTswNjBtKhtbMzg7NTswNjBtKhtbMzg7" \ + "NTsyMzltKhtbMzg7NTsyMzltKhtbMzg7NTsyMzltKhtbMzg7NTswOTVtKhtbMzg7NTswOTVtKhtbMzg7NTswOTVtKhtbMzg7NTswOT" \ + "VtKhtbMzg7NTswOTVtKhtbMzg7NTswOTVtKhtbMzg7NTsxMzFtLxtbMzg7NTttQBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtb" \ + "Mzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIBtbMzg7NTttIAobWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4Oz" \ + "U7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAb" \ + "WzM4OzU7bSAbWzM4OzU7bSgbWzM4OzU7bSobWzM4OzU7MDI0bSobWzM4OzU7MDI0bSobWzM4OzU7MDI0bSobWzM4OzU7MDYwbSobWz" \ + "M4OzU7MDYwbSobWzM4OzU7MDYwbSobWzM4OzU7MjM5bSobWzM4OzU7MjQwbSobWzM4OzU7MDk1bSobWzM4OzU7MDk1bSobWzM4OzU7" \ + "MDk1bSobWzM4OzU7bS8bWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bS" \ + "AbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAbWzM4OzU7bSAKG1szODs1O20gG1szODs1O20gG1sz" \ + "ODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O2" \ + "0gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20uG1szODs1O20oG1sz" \ + "ODs1OzAyNG0qG1szODs1OzA2MG0qG1szODs1OzA5NW0qG1szODs1O20vG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O2" \ + "0gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1sz" \ + "ODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gG1szODs1O20gChtbMG0=" + + print(base64.b64decode(banner).decode("utf-8")) + + +def print_version() -> None: + """Prints this package's version number + """ + print(f'{{cookiecutter.python_name}} version: { {{cookiecutter.python_name}}.core.get_version()}\n') + + +@click.group() +def cli() -> None: + """{{cookiecutter.description}} + """ + print_banner() + + +@click.command() +def version() -> None: + """Print version and exit + """ + print_version() + + +cli.add_command(version) + +if __name__ == '__main__': + cli() diff --git a/{{cookiecutter.repo_name}}/{{cookiecutter.python_name}}/core.py b/{{cookiecutter.repo_name}}/{{cookiecutter.python_name}}/core.py new file mode 100644 index 0000000..1090d02 --- /dev/null +++ b/{{cookiecutter.repo_name}}/{{cookiecutter.python_name}}/core.py @@ -0,0 +1,19 @@ +def get_version() -> str: + """Returns a string representation of the version of {{cookiecutter.python_name}} currently in use + + Returns + ------- + str + the version number installed of this package + """ + try: + from importlib.metadata import version # type: ignore + return version('{{cookiecutter.python_name}}') + except ImportError: + try: + import pkg_resources + return pkg_resources.get_distribution('{{cookiecutter.python_name}}').version + except pkg_resources.DistributionNotFound: + return 'set_version_placeholder' + except ModuleNotFoundError: + return 'set_version_placeholder'